def validate(self, state) -> bool: if not PoWValidator().validate_mining_nonce(state, self.blockheader): logger.warning('Failed PoW Validation') return False fee_reward = 0 for index in range(1, len(self.transactions)): fee_reward += self.transactions[index].fee if len(self.transactions) == 0: return False try: coinbase_txn = Transaction.from_pbdata(self.transactions[0]) coinbase_amount = coinbase_txn.amount if not coinbase_txn.validate_extended(): return False except Exception as e: logger.warning('Exception %s', e) return False if not self.blockheader.validate(fee_reward, coinbase_amount): return False parent_block = state.get_block(self.prev_headerhash) if not self.validate_parent_child_relation(parent_block): logger.warning('Failed to validate blocks parent child relation') return False return True
def create_block(self, prev_hash): transactions = [] block_prev = self.qrlnode.get_block_from_hash(prev_hash) block_idx = block_prev.block_number + 1 if block_idx == 1: slave_tx = SlaveTransaction.create(slave_pks=[self.bob_xmss.pk], access_types=[0], fee=0, xmss_pk=self.alice_xmss.pk) slave_tx.sign(self.alice_xmss) slave_tx._data.nonce = 1 transactions = [slave_tx] self.time_mock.return_value = self.time_mock.return_value + 60 self.ntp_mock.return_value = self.ntp_mock.return_value + 60 block_new = Block.create(block_number=block_idx, prevblock_headerhash=block_prev.headerhash, transactions=transactions, miner_address=self.alice_xmss.address) while not PoWValidator().validate_mining_nonce(state=self.qrlnode._chain_manager.state, blockheader=block_new.blockheader, enable_logging=False): block_new.set_mining_nonce(block_new.mining_nonce + 1) return block_new
def validate_block(self, block, address_txn) -> bool: len_transactions = len(block.transactions) if len_transactions < 1: return False coinbase_tx = Transaction.from_pbdata(block.transactions[0]) if not isinstance(coinbase_tx, CoinBase): return False if not coinbase_tx.validate_extended(): return False if not PoWValidator().validate_mining_nonce(self.state, block.blockheader): return False coinbase_tx.apply_on_state(address_txn) # TODO: check block reward must be equal to coinbase amount for tx_idx in range(1, len_transactions): tx = Transaction.from_pbdata(block.transactions[tx_idx]) if isinstance(tx, CoinBase): return False if not tx.validate( ): # TODO: Move this validation, before adding txn to pool return False addr_from_pk_state = address_txn[tx.addr_from] addr_from_pk = Transaction.get_slave(tx) if addr_from_pk: addr_from_pk_state = address_txn[addr_from_pk] if not tx.validate_extended(address_txn[tx.addr_from], addr_from_pk_state): return False expected_nonce = addr_from_pk_state.nonce + 1 if tx.nonce != expected_nonce: logger.warning('nonce incorrect, invalid tx') logger.warning('subtype: %s', tx.type) logger.warning('%s actual: %s expected: %s', tx.addr_from, tx.nonce, expected_nonce) return False if addr_from_pk_state.ots_key_reuse(tx.ots_key): logger.warning('pubkey reuse detected: invalid tx %s', tx.txhash) logger.warning('subtype: %s', tx.type) return False tx.apply_on_state(address_txn) return True
def qrlnode_with_mock_blockchain(num_blocks): start_time = time.time() with mock.patch('qrl.core.misc.ntp.getTime') as ntp_mock, \ set_data_dir('no_data'), \ State() as state, \ mock.patch('time.time') as time_mock: # noqa time_mock.return_value = start_time ntp_mock.return_value = start_time state.get_measurement = MagicMock(return_value=10000000) required_height = ceil(log(num_blocks, 2)) required_height = int(required_height + required_height % 2) alice_xmss = get_alice_xmss(xmss_height=required_height) bob_xmss = get_bob_xmss() genesis_block = GenesisBlock() chain_manager = ChainManager(state) chain_manager.load(genesis_block) chain_manager._difficulty_tracker = Mock() dt = DifficultyTracker() tmp_difficulty = StringToUInt256('2') tmp_target = dt.get_target(tmp_difficulty) chain_manager._difficulty_tracker.get = MagicMock(return_value=(tmp_difficulty, tmp_target)) block_prev = state.get_block(genesis_block.headerhash) for block_idx in range(1, num_blocks): transactions = [] if block_idx == 1: slave_tx = SlaveTransaction.create(slave_pks=[bob_xmss.pk], access_types=[0], fee=0, xmss_pk=alice_xmss.pk) slave_tx.sign(alice_xmss) slave_tx._data.nonce = 2 transactions = [slave_tx] time_mock.return_value = time_mock.return_value + 60 ntp_mock.return_value = ntp_mock.return_value + 60 block_new = Block.create(block_number=block_idx, prevblock_headerhash=block_prev.headerhash, transactions=transactions, miner_address=alice_xmss.address) while not PoWValidator().validate_mining_nonce(state, block_new.blockheader, False): block_new.set_nonces(block_new.mining_nonce + 1, 0) chain_manager.add_block(block_new) block_prev = block_new qrlnode = QRLNode(state, mining_credit_wallet=alice_xmss.address) qrlnode.set_chain_manager(chain_manager) yield qrlnode
def submit_mined_block(self, blob) -> bool: if not self._mining_block.verify_blob(blob): return False blockheader = copy.deepcopy(self._mining_block.blockheader) blockheader.set_mining_nonce_from_blob(blob) if not PoWValidator().validate_mining_nonce(self.state, blockheader=blockheader): return False self._mining_block.set_nonces(blockheader.mining_nonce, blockheader.extra_nonce) cloned_block = copy.deepcopy(self._mining_block) self.pre_block_logic(cloned_block) return True
def validate(self, state, future_blocks: OrderedDict) -> bool: if self.is_duplicate(state): logger.warning('Duplicate Block #%s %s', self.block_number, bin2hstr(self.headerhash)) return False parent_block = state.get_block(self.prev_headerhash) # If parent block not found in state, then check if its in the future block list if not parent_block: try: parent_block = future_blocks[self.prev_headerhash] except KeyError: logger.warning('Parent block not found') logger.warning('Parent block headerhash %s', bin2hstr(self.prev_headerhash)) return False if not self.validate_parent_child_relation(parent_block): logger.warning('Failed to validate blocks parent child relation') return False if not PoWValidator().validate_mining_nonce(state, self.blockheader): logger.warning('Failed PoW Validation') return False fee_reward = 0 for index in range(1, len(self.transactions)): fee_reward += self.transactions[index].fee if len(self.transactions) == 0: return False try: coinbase_txn = Transaction.from_pbdata(self.transactions[0]) coinbase_amount = coinbase_txn.amount if not coinbase_txn.validate_extended(): return False except Exception as e: logger.warning('Exception %s', e) return False if not self.blockheader.validate(fee_reward, coinbase_amount): return False return True
def validate_mining_nonce(self, blockheader: BlockHeader, enable_logging=True): with self.lock: parent_metadata = self.get_block_metadata( blockheader.prev_headerhash) parent_block = self._state.get_block(blockheader.prev_headerhash) measurement = self.get_measurement(blockheader.timestamp, blockheader.prev_headerhash, parent_metadata) diff, target = DifficultyTracker.get( measurement=measurement, parent_difficulty=parent_metadata.block_difficulty) if enable_logging: logger.debug('-----------------START--------------------') logger.debug('Validate #%s', blockheader.block_number) logger.debug('block.timestamp %s', blockheader.timestamp) logger.debug('parent_block.timestamp %s', parent_block.timestamp) logger.debug('parent_block.difficulty %s', UInt256ToString(parent_metadata.block_difficulty)) logger.debug('diff %s', UInt256ToString(diff)) logger.debug('target %s', bin2hstr(target)) logger.debug('-------------------END--------------------') if not PoWValidator().verify_input(blockheader.mining_blob, target): if enable_logging: logger.warning("PoW verification failed") qn = Qryptonight() tmp_hash = qn.hash(blockheader.mining_blob) logger.warning("{}".format(bin2hstr(tmp_hash))) logger.debug('%s', blockheader.to_json()) return False return True
def test_simple_add_block(self): with set_data_dir('no_data'): with State() as state: state.get_measurement = MagicMock(return_value=10000000) alice_xmss = get_alice_xmss() genesis_block = GenesisBlock() chain_manager = ChainManager(state) chain_manager.load(genesis_block) chain_manager._difficulty_tracker = Mock() dt = DifficultyTracker() tmp_difficulty = StringToUInt256('2') tmp_boundary = dt.get_target(tmp_difficulty) chain_manager._difficulty_tracker.get = MagicMock( return_value=(tmp_difficulty, tmp_boundary)) block = state.get_block(genesis_block.headerhash) self.assertIsNotNone(block) with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 # Very high to get an easy difficulty block_1 = Block.create( block_number=1, prevblock_headerhash=genesis_block.headerhash, transactions=[], signing_xmss=alice_xmss, master_address=alice_xmss.address, nonce=1) while not PoWValidator().validate_mining_nonce( state, block_1.blockheader, False): block_1.set_mining_nonce(block_1.mining_nonce + 1) result = chain_manager.add_block(block_1) self.assertTrue(result) self.assertEqual(chain_manager.last_block, block_1)
def test_orphan_block(self): """ Testing add_block logic in case of orphan_blocks. This test is expected to shift the mainchain towards block_2. :return: """ with mock.patch('qrl.core.config.DevConfig') as devconfig: devconfig.genesis_difficulty = 2 devconfig.minimum_minting_delay = 10 with set_data_dir('no_data'): with State( ) as state: # FIXME: Move state to temporary directory state.get_measurement = MagicMock(return_value=10000000) genesis_block = GenesisBlock() chain_manager = ChainManager(state) chain_manager.load(genesis_block) chain_manager._difficulty_tracker = Mock() dt = DifficultyTracker() tmp_difficulty = StringToUInt256('2') tmp_target = dt.get_target(tmp_difficulty) chain_manager._difficulty_tracker.get = MagicMock( return_value=(tmp_difficulty, tmp_target)) block = state.get_block(genesis_block.headerhash) self.assertIsNotNone(block) alice_xmss = get_alice_xmss() with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1521889325 # Very high to get an easy difficulty block_1 = Block.create( block_number=1, prevblock_headerhash=genesis_block.headerhash, transactions=[], miner_address=alice_xmss.address) block_1.set_nonces(29, 0) # Uncomment only to determine the correct mining_nonce of above blocks # from qrl.core.PoWValidator import PoWValidator # while not PoWValidator().validate_mining_nonce(state, block_1.blockheader, False): # block_1.set_nonces(block_1.mining_nonce + 1) # print(block_1.mining_nonce) result = chain_manager.add_block(block_1) self.assertTrue(result) self.assertEqual(chain_manager.last_block, block_1) bob_xmss = get_bob_xmss() with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1521889326 + devconfig.minimum_minting_delay * 2 block = Block.create( block_number=1, prevblock_headerhash=genesis_block.headerhash, transactions=[], miner_address=bob_xmss.address) block.set_nonces(246, 0) # Uncomment only to determine the correct mining_nonce of above blocks from qrl.core.PoWValidator import PoWValidator while not PoWValidator().validate_mining_nonce( state, block.blockheader, False): block.set_nonces(block.mining_nonce + 1) print(block.mining_nonce) with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1521889327 + devconfig.minimum_minting_delay * 3 block_2 = Block.create( block_number=2, prevblock_headerhash=block.headerhash, transactions=[], miner_address=bob_xmss.address) block_2.set_nonces(31, 0) # Uncomment only to determine the correct mining_nonce of above blocks # from qrl.core.PoWValidator import PoWValidator # while not PoWValidator().validate_mining_nonce(state, block_2.blockheader, False): # block_2.set_nonces(block_2.mining_nonce + 1) # print(block_2.mining_nonce) result = chain_manager.add_block(block_2) self.assertTrue(result) result = chain_manager.add_block(block) self.assertTrue(result) block = state.get_block(block.headerhash) self.assertIsNotNone(block) self.assertEqual(chain_manager.last_block.block_number, block_2.block_number) self.assertEqual(chain_manager.last_block.headerhash, block_2.headerhash)
def test_add_4(self, mock_difficulty_tracker_get): with set_qrl_dir('wallet_ver1'): with State() as state: with mocked_genesis() as custom_genesis: chain_manager = ChainManager(state) chain_manager._difficulty_tracker = Mock() tmp_difficulty = StringToUInt256('2') tmp_target = DifficultyTracker.get_target(tmp_difficulty) mock_difficulty_tracker_get.return_value = [ tmp_difficulty, tmp_target ] alice_xmss = get_alice_xmss() slave_xmss = XMSS( XmssFast(alice_xmss.seed, alice_xmss.height)) random_xmss1 = get_random_xmss() random_kyber1 = Kyber() random_dilithium1 = Dilithium() random_xmss2 = get_random_xmss() random_kyber2 = Kyber() random_dilithium2 = Dilithium() message = b'Hello World How are you?' prf512_seed = b'10192' custom_genesis.genesis_balance.extend([ qrl_pb2.GenesisBalance(address=random_xmss1.address, balance=65000000000000000) ]) custom_genesis.genesis_balance.extend([ qrl_pb2.GenesisBalance(address=random_xmss2.address, balance=65000000000000000) ]) chain_manager.load(custom_genesis) with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 lattice_public_key_txn = LatticePublicKey.create( fee=1, kyber_pk=random_kyber1.getPK(), dilithium_pk=random_dilithium1.getPK(), xmss_pk=random_xmss1.pk) lattice_public_key_txn._data.nonce = 1 lattice_public_key_txn.sign(random_xmss1) genesis_block = GenesisBlock() tmp_block1 = Block.create( block_number=1, prev_block_headerhash=genesis_block.headerhash, prev_block_timestamp=genesis_block.timestamp, transactions=[lattice_public_key_txn], miner_address=slave_xmss.address) # Mine the nonce while not PoWValidator().validate_mining_nonce( state, tmp_block1.blockheader, False): tmp_block1.set_nonces(tmp_block1.mining_nonce + 1, 0) res = chain_manager.add_block(block=tmp_block1) self.assertTrue(res) # Need to move forward the time to align with block times time_mock.return_value += config.dev.minimum_minting_delay * 2 encrypted_eph_message = create_ephemeral_channel( msg_id=lattice_public_key_txn.txhash, ttl=time_mock.return_value, ttr=0, addr_from=random_xmss2.address, kyber_pk=random_kyber2.getPK(), kyber_sk=random_kyber2.getSK(), receiver_kyber_pk=random_kyber1.getPK(), dilithium_pk=random_dilithium2.getPK(), dilithium_sk=random_dilithium2.getSK(), prf512_seed=prf512_seed, data=message, nonce=1) chain_manager.state.update_ephemeral( encrypted_eph_message) eph_metadata = chain_manager.state.get_ephemeral_metadata( lattice_public_key_txn.txhash) # Decrypting Payload encrypted_eph_message = eph_metadata.encrypted_ephemeral_message_list[ 0] encrypted_payload = encrypted_eph_message.payload random_kyber1.kem_decode( encrypted_eph_message.channel.enc_aes256_symkey) aes_key = bytes(random_kyber1.getMyKey()) myAES = AES(aes_key) decrypted_payload = myAES.decrypt(encrypted_payload) ephemeral_channel_payload = EphemeralChannelPayload.from_json( decrypted_payload) self.assertEqual(ephemeral_channel_payload.prf512_seed, b'10192') self.assertEqual(ephemeral_channel_payload.data, b'Hello World How are you?') # TODO (cyyber): Add Ephemeral Testing code using Naive RNG tmp_block2 = Block.create( block_number=2, prev_block_headerhash=tmp_block1.headerhash, prev_block_timestamp=tmp_block1.timestamp, transactions=[], miner_address=slave_xmss.address) # Mine the nonce while not PoWValidator().validate_mining_nonce( state, tmp_block2.blockheader, False): tmp_block2.set_nonces(tmp_block2.mining_nonce + 1, 0) res = chain_manager.add_block(block=tmp_block2) self.assertTrue(res) # Need to move forward the time to align with block times time_mock.return_value += config.dev.minimum_minting_delay * 2 tmp_block3 = Block.create( block_number=3, prev_block_headerhash=tmp_block2.headerhash, prev_block_timestamp=tmp_block1.timestamp, transactions=[], miner_address=slave_xmss.address) # Mine the nonce while not PoWValidator().validate_mining_nonce( state, tmp_block3.blockheader, False): tmp_block3.set_nonces(tmp_block3.mining_nonce + 1, 0) res = chain_manager.add_block(block=tmp_block3) self.assertTrue(res) time_mock.return_value += config.dev.minimum_minting_delay tmp_block4 = Block.create( block_number=4, prev_block_headerhash=tmp_block3.headerhash, prev_block_timestamp=tmp_block1.timestamp, transactions=[], miner_address=slave_xmss.address) # Mine the nonce while not PoWValidator().validate_mining_nonce( state, tmp_block4.blockheader, False): tmp_block4.set_nonces(tmp_block4.mining_nonce + 1, 0) res = chain_manager.add_block(block=tmp_block4) self.assertTrue(res) address_state = chain_manager.get_address( random_xmss1.address) self.assertEqual( address_state.latticePK_list[0].kyber_pk, lattice_public_key_txn.kyber_pk) self.assertEqual( address_state.latticePK_list[0].dilithium_pk, lattice_public_key_txn.dilithium_pk) self.assertEqual(address_state.address, lattice_public_key_txn.addr_from) random_xmss1_state = chain_manager.get_address( random_xmss1.address) self.assertEqual(64999999999999999, random_xmss1_state.balance)
def test_multi_output_transaction_add_block(self): with set_data_dir('no_data'): with State() as state: state.get_measurement = MagicMock(return_value=10000000) alice_xmss = get_alice_xmss() bob_xmss = get_bob_xmss() random_xmss = get_random_xmss() transfer_transaction = TransferTransaction.create( addr_from=bob_xmss.address, addrs_to=[alice_xmss.address, random_xmss.address], amounts=[ 40 * int(config.dev.shor_per_quanta), 59 * int(config.dev.shor_per_quanta) ], fee=1 * config.dev.shor_per_quanta, xmss_pk=bob_xmss.pk) transfer_transaction._data.nonce = 1 transfer_transaction.sign(bob_xmss) genesis_block = GenesisBlock() chain_manager = ChainManager(state) chain_manager.load(genesis_block) chain_manager._difficulty_tracker = Mock() dt = DifficultyTracker() tmp_difficulty = StringToUInt256('2') tmp_boundary = dt.get_target(tmp_difficulty) chain_manager._difficulty_tracker.get = MagicMock( return_value=(tmp_difficulty, tmp_boundary)) block = state.get_block(genesis_block.headerhash) self.assertIsNotNone(block) with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 # Very high to get an easy difficulty block_1 = Block.create( block_number=1, prevblock_headerhash=genesis_block.headerhash, transactions=[transfer_transaction], signing_xmss=alice_xmss, master_address=alice_xmss.address, nonce=1) while not PoWValidator().validate_mining_nonce( state, block_1.blockheader, False): block_1.set_mining_nonce(block_1.mining_nonce + 1) result = chain_manager.add_block(block_1) self.assertTrue(result) self.assertEqual(chain_manager.last_block, block_1) bob_addr_state = state.get_address(bob_xmss.address) alice_addr_state = state.get_address(alice_xmss.address) random_addr_state = state.get_address(random_xmss.address) self.assertEqual(bob_addr_state.balance, 0) self.assertEqual( alice_addr_state.balance, 140 * int(config.dev.shor_per_quanta) + block_1.block_reward + block_1.fee_reward) self.assertEqual(random_addr_state.balance, 159 * int(config.dev.shor_per_quanta))
def test_orphan_block(self): """ Testing add_block logic in case of orphan_blocks :return: """ with mock.patch('qrl.core.config.DevConfig') as devconfig: devconfig.genesis_difficulty = 2 devconfig.minimum_minting_delay = 10 with set_data_dir('no_data'): with State( ) as state: # FIXME: Move state to temporary directory state.get_measurement = MagicMock(return_value=10000000) genesis_block = GenesisBlock() chain_manager = ChainManager(state) chain_manager.load(genesis_block) chain_manager._difficulty_tracker = Mock() dt = DifficultyTracker() tmp_difficulty = StringToUInt256('2') tmp_boundary = dt.get_target(tmp_difficulty) chain_manager._difficulty_tracker.get = MagicMock( return_value=(tmp_difficulty, tmp_boundary)) block = state.get_block(genesis_block.headerhash) self.assertIsNotNone(block) alice_xmss = get_alice_xmss() with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1519601174 # Very high to get an easy difficulty block_1 = Block.create( block_number=1, prevblock_headerhash=genesis_block.headerhash, transactions=[], signing_xmss=alice_xmss, master_address=alice_xmss.address, nonce=1) block_1.set_mining_nonce(10) while not PoWValidator().validate_mining_nonce( state, block_1.blockheader, False): block_1.set_mining_nonce(block_1.mining_nonce + 1) result = chain_manager.add_block(block_1) self.assertTrue(result) self.assertEqual(chain_manager.last_block, block_1) bob_xmss = get_bob_xmss() with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1519601174 + devconfig.minimum_minting_delay * 2 block = Block.create( block_number=1, prevblock_headerhash=genesis_block.headerhash, transactions=[], signing_xmss=bob_xmss, master_address=bob_xmss.address, nonce=1) block.set_mining_nonce(18) while not PoWValidator().validate_mining_nonce( state, block.blockheader, False): block.set_mining_nonce(block.mining_nonce + 1) with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1519601174 + devconfig.minimum_minting_delay * 3 block_2 = Block.create( block_number=2, prevblock_headerhash=block.headerhash, transactions=[], signing_xmss=bob_xmss, master_address=bob_xmss.address, nonce=2) block_2.set_mining_nonce(10) result = chain_manager.add_block(block_2) self.assertTrue(result) result = chain_manager.add_block(block) self.assertTrue(result) block = state.get_block(block.headerhash) self.assertIsNotNone(block) self.assertEqual(chain_manager.last_block.block_number, block_2.block_number) self.assertEqual(chain_manager.last_block.headerhash, block_2.headerhash)
def test_add_block(self, mock_difficulty_tracker_get): """ Testing add_block, with fork logic :return: """ with set_data_dir('no_data'): with State() as state: state.get_measurement = MagicMock(return_value=10000000) alice_xmss = get_alice_xmss() bob_xmss = get_bob_xmss() genesis_block = GenesisBlock() chain_manager = ChainManager(state) mock_difficulty_tracker_get.return_value = [ config.dev.mining_setpoint_blocktime, 2 ] chain_manager.load(genesis_block) chain_manager._difficulty_tracker = Mock() tmp_difficulty = StringToUInt256('2') tmp_boundary = DifficultyTracker.get_target(tmp_difficulty) mock_difficulty_tracker_get.return_value = [ tmp_difficulty, tmp_boundary ] block = state.get_block(genesis_block.headerhash) self.assertIsNotNone(block) slave_tx = SlaveTransaction.create( addr_from=alice_xmss.address, slave_pks=[bob_xmss.pk], access_types=[0], fee=0, xmss_pk=alice_xmss.pk) slave_tx.sign(alice_xmss) slave_tx._data.nonce = 2 self.assertTrue(slave_tx.validate()) with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 # Very high to get an easy difficulty block_1 = Block.create( block_number=1, prevblock_headerhash=genesis_block.headerhash, transactions=[slave_tx], signing_xmss=alice_xmss, master_address=alice_xmss.address, nonce=1) while not PoWValidator().validate_mining_nonce( state, block_1.blockheader, False): block_1.set_mining_nonce(block_1.mining_nonce + 1) result = chain_manager.add_block(block_1) self.assertTrue(result) self.assertEqual(chain_manager.last_block, block_1) alice_state = chain_manager.get_address(alice_xmss.address) self.assertEqual(len(alice_state.slave_pks_access_type), 1) self.assertTrue( str(bob_xmss.pk) in alice_state.slave_pks_access_type) with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1715270948 # Very high to get an easy difficulty block = Block.create( block_number=1, prevblock_headerhash=genesis_block.headerhash, transactions=[], signing_xmss=bob_xmss, master_address=bob_xmss.address, nonce=1) while not PoWValidator().validate_mining_nonce( state, block.blockheader, False): block.set_mining_nonce(block.mining_nonce + 1) result = chain_manager.add_block(block) self.assertTrue(result) self.assertEqual(chain_manager.last_block, block_1) block = state.get_block(block.headerhash) self.assertIsNotNone(block) with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1815270948 # Very high to get an easy difficulty block_2 = Block.create( block_number=2, prevblock_headerhash=block.headerhash, transactions=[], signing_xmss=bob_xmss, master_address=bob_xmss.address, nonce=2) while not PoWValidator().validate_mining_nonce( state, block_2.blockheader, False): block_2.set_mining_nonce(block_2.mining_nonce + 1) result = chain_manager.add_block(block_2) self.assertTrue(result) self.assertEqual(chain_manager.last_block.block_number, block_2.block_number) self.assertEqual(chain_manager.last_block.to_json(), block_2.to_json())