def test_prepare_address_list(self): with set_qrl_dir('no_data'): with State() as state: block = Block.create(block_number=10, prev_headerhash=b'', prev_timestamp=10, transactions=[], miner_address=get_some_address(1)) # Test Case: without any transactions of block self.assertEqual(state.prepare_address_list(block), {config.dev.coinbase_address, get_some_address(1)}) alice_xmss = get_alice_xmss() block = Block.create(block_number=10, prev_headerhash=b'', prev_timestamp=10, transactions=[TransferTransaction.create(addrs_to=[get_some_address(2), get_some_address(3)], amounts=[100, 100], fee=0, xmss_pk=alice_xmss.pk)], miner_address=get_some_address(1)) # Test Case, with one Transaction self.assertEqual(state.prepare_address_list(block), {config.dev.coinbase_address, get_some_address(1), get_some_address(2), get_some_address(3), alice_xmss.address})
def create_block(self, last_block, mining_nonce, tx_pool: TransactionPool, miner_address) -> Optional[Block]: # TODO: Persistence will move to rocksdb # FIXME: Difference between this and create block????????????? dummy_block = Block.create(block_number=last_block.block_number + 1, prevblock_headerhash=last_block.headerhash, transactions=[], miner_address=miner_address) dummy_block.set_nonces(mining_nonce, 0) t_pool2 = tx_pool.transactions addresses_set = set() for tx_set in t_pool2: tx = tx_set[1] tx.set_effected_address(addresses_set) addresses_state = dict() for address in addresses_set: addresses_state[address] = self.state.get_address(address) block_size = dummy_block.size block_size_limit = self.state.get_block_size_limit(last_block) transactions = [] for tx_set in t_pool2: tx = tx_set[1] # Skip Transactions for later, which doesn't fit into block if block_size + tx.size + config.dev.tx_extra_overhead > block_size_limit: continue addr_from_pk_state = addresses_state[tx.addr_from] addr_from_pk = Transaction.get_slave(tx) if addr_from_pk: addr_from_pk_state = addresses_state[addr_from_pk] if not tx.validate_extended(addresses_state[tx.addr_from], addr_from_pk_state): logger.warning('Txn validation failed for tx in tx_pool') tx_pool.remove_tx_from_pool(tx) continue tx.apply_on_state(addresses_state) tx._data.nonce = addr_from_pk_state.nonce block_size += tx.size + config.dev.tx_extra_overhead transactions.append(tx) block = Block.create(block_number=last_block.block_number + 1, prevblock_headerhash=last_block.headerhash, transactions=transactions, miner_address=miner_address) return block
def create_block(self, last_block, mining_nonce, tx_pool: TransactionPool, miner_address) -> Optional[Block]: dummy_block = Block.create(block_number=last_block.block_number + 1, prev_headerhash=last_block.headerhash, prev_timestamp=last_block.timestamp, transactions=[], miner_address=miner_address) dummy_block.set_nonces(mining_nonce, 0) t_pool2 = tx_pool.transactions addresses_set = set() for tx_set in t_pool2: tx = tx_set[1].transaction tx.set_affected_address(addresses_set) addresses_state = dict() for address in addresses_set: addresses_state[address] = self._chain_manager.get_address_state( address) block_size = dummy_block.size block_size_limit = self._chain_manager.get_block_size_limit(last_block) transactions = [] for tx_set in t_pool2: tx = tx_set[1].transaction # Skip Transactions for later, which doesn't fit into block if block_size + tx.size + config.dev.tx_extra_overhead > block_size_limit: continue addr_from_pk_state = addresses_state[tx.addr_from] addr_from_pk = Transaction.get_slave(tx) if addr_from_pk: addr_from_pk_state = addresses_state[addr_from_pk] if not tx.validate_extended(addresses_state[tx.addr_from], addr_from_pk_state): logger.warning('Txn validation failed for tx in tx_pool') tx_pool.remove_tx_from_pool(tx) continue tx.apply_state_changes(addresses_state) tx._data.nonce = addr_from_pk_state.nonce block_size += tx.size + config.dev.tx_extra_overhead transactions.append(tx) block = Block.create(block_number=last_block.block_number + 1, prev_headerhash=last_block.headerhash, prev_timestamp=last_block.timestamp, transactions=transactions, miner_address=miner_address) return block
def test_rollback_tx_metadata(self): alice_xmss = get_alice_xmss() tx1 = TransferTransaction.create( addrs_to=[get_some_address(1), get_some_address(2)], amounts=[1, 2], message_data=None, fee=0, xmss_pk=alice_xmss.pk) block = Block.create(dev_config=config.dev, block_number=5, prev_headerhash=b'', prev_timestamp=10, transactions=[tx1], miner_address=b'', seed_height=0, seed_hash=None) TransactionMetadata.update_tx_metadata(self.state, block=block, batch=None) tx_metadata = TransactionMetadata.get_tx_metadata( self.state, tx1.txhash) self.assertEqual(tx_metadata[0].to_json(), tx1.to_json()) TransactionMetadata.rollback_tx_metadata(self.state, block, None) self.assertIsNone( TransactionMetadata.get_tx_metadata(self.state, tx1.txhash))
def test_getBlock(self): with set_qrl_dir('no_data'): db_state = State() p2p_factory = Mock(spec=P2PFactory) p2p_factory.pow = Mock(spec=POW) chain_manager = ChainManager(db_state) qrlnode = QRLNode(mining_address=b'') qrlnode.set_chain_manager(chain_manager) qrlnode._p2pfactory = p2p_factory qrlnode._pow = p2p_factory.pow qrlnode._peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(qrlnode) alice_xmss = get_alice_xmss() b = Block.create(dev_config=config.dev, block_number=1, prev_headerhash=sha256(b'reveal'), prev_timestamp=10, transactions=[], miner_address=alice_xmss.address, seed_height=0, seed_hash=None) Block.put_block(db_state, b, None) db_state.get_block = MagicMock(return_value=b) context = Mock(spec=ServicerContext) request = qrl_pb2.GetBlockReq(header_hash=b.headerhash) response = service.GetBlock(request=request, context=context) context.set_code.assert_not_called() self.assertEqual(1, response.block.header.block_number)
def test_mining_blob(self): alice_xmss = get_alice_xmss() block = Block.create(block_number=5, prevblock_headerhash=bytes(sha2_256(b'test')), transactions=[], miner_address=alice_xmss.address) block.set_nonces(mining_nonce=5, extra_nonce=4) mining_blob = block.mining_blob self.assertEqual(len(mining_blob), config.dev.mining_blob_size) mining_nonce_bytes = mining_blob[config.dev.mining_nonce_offset:config. dev.mining_nonce_offset + 4] extra_nonce_bytes = mining_blob[config.dev.extra_nonce_offset:config. dev.extra_nonce_offset + 8] mining_nonce = int.from_bytes(mining_nonce_bytes, byteorder='big', signed=False) extra_nonce = int.from_bytes(extra_nonce_bytes, byteorder='big', signed=False) self.assertEqual(mining_nonce, 5) self.assertEqual(extra_nonce, 4)
def test_bad_nonce_or_ots_reused(self, m_TransferTransaction_validate, m_TransferTransaction_validate_extended, m_TransferTransaction_apply_state_changes, m_CoinBase_apply_state_changes): # If a TX was signed by a Slave XMSS, apply_state_changes() should check against the Slave's AddressState.nonce. # In this case, tx.nonce = 3 but slave addrstate.nonce = 0 self.slave_addrstate_attrs.pbdata.nonce = 0 get_optimized_address_state = MockFunction() get_optimized_address_state.put(self.coinbase_addrstate_attrs.address, self.coinbase_addrstate_attrs) get_optimized_address_state.put(self.bob_addrstate_attrs.address, self.bob_addrstate_attrs) get_optimized_address_state.put(self.alice_addrstate_attrs.address, self.alice_addrstate_attrs) get_optimized_address_state.put(self.slave_addrstate_attrs.address, self.slave_addrstate_attrs) block = Block.create(**self.block_attrs) result = self.chain_manager._apply_state_changes(block, None) self.assertFalse(result) self.slave_addrstate_attrs.pbdata.nonce = 5 # Now we pretend that Alice's OTS key has been reused. result = self.chain_manager._apply_state_changes(block, None) self.assertFalse(result) # Now we pretend that Slave's OTS key has been reused. result = self.chain_manager._apply_state_changes(block, None) self.assertFalse(result)
def test_bad_nonce_or_ots_reused(self, m_TransferTransaction_validate, m_TransferTransaction_validate_extended, m_TransferTransaction_apply_state_changes, m_CoinBase_apply_state_changes): # If a TX was signed by a Slave XMSS, apply_state_changes() should check against the Slave's AddressState.nonce. # In this case, tx.nonce = 3 but slave addrstate.nonce = 0 self.slave_addrstate_attrs['nonce'] = 0 address_states = self.generate_address_states( self.alice_addrstate_attrs, {}, self.slave_addrstate_attrs) block = Block.create(**self.block_attrs) result = block.apply_state_changes(address_states) self.assertFalse(result) self.slave_addrstate_attrs['nonce'] = 5 # Now we pretend that Alice's OTS key has been reused. self.alice_addrstate_attrs['ots_key_reuse.return_value'] = True address_states = self.generate_address_states( self.alice_addrstate_attrs, {}, self.slave_addrstate_attrs) result = block.apply_state_changes(address_states) self.assertFalse(result) self.alice_addrstate_attrs['ots_key_reuse.return_value'] = False # Now we pretend that Slave's OTS key has been reused. self.slave_addrstate_attrs['ots_key_reuse.return_value'] = True address_states = self.generate_address_states( self.alice_addrstate_attrs, {}, self.slave_addrstate_attrs) result = block.apply_state_changes(address_states) self.assertFalse(result)
def test_tx_validation_fails(self, m_TransferTransaction_validate, m_TransferTransaction_validate_extended, m_TransferTransaction_apply_state_changes, m_CoinBase_apply_state_changes): get_optimized_address_state = MockFunction() get_optimized_address_state.put(self.coinbase_addrstate_attrs.address, self.coinbase_addrstate_attrs) get_optimized_address_state.put(self.bob_addrstate_attrs.address, self.bob_addrstate_attrs) get_optimized_address_state.put(self.alice_addrstate_attrs.address, self.alice_addrstate_attrs) get_optimized_address_state.put(self.slave_addrstate_attrs.address, self.slave_addrstate_attrs) block = Block.create(**self.block_attrs) m_TransferTransaction_validate.return_value = False result = self.chain_manager._apply_state_changes(block, None) self.assertFalse(result) m_TransferTransaction_validate.return_value = True m_TransferTransaction_validate_extended.return_value = False result = self.chain_manager._apply_state_changes(block, None) self.assertFalse(result) m_TransferTransaction_validate_extended.return_value = True with patch('qrl.core.txs.CoinBase.CoinBase._validate_extended') as m_validate_extended: m_validate_extended.return_value = False result = self.chain_manager._apply_state_changes(block, None) self.assertFalse(result)
def create_block(self, prev_hash, mining_address=None): if not mining_address: mining_address = self.alice_xmss.address 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] time_offset = 60 if block_idx % 2 == 0: time_offset += 2 self.time_mock.return_value = self.time_mock.return_value + time_offset self.ntp_mock.return_value = self.ntp_mock.return_value + time_offset block_new = Block.create(block_number=block_idx, prev_headerhash=block_prev.headerhash, prev_timestamp=block_prev.timestamp, transactions=transactions, miner_address=mining_address) while not self.qrlnode._chain_manager.validate_mining_nonce(blockheader=block_new.blockheader): block_new.set_nonces(block_new.mining_nonce + 1, 0) return block_new
def main(): if len(sys.argv) > 2: print("Unexpected arguments") sys.exit(0) elif len(sys.argv) == 1: print("Missing Filename") sys.exit(0) filename = sys.argv[1] if sys.version_info.major > 2: seed = bytes(hstr2bin(input('Enter extended hexseed: '))) else: seed = bytes(hstr2bin(raw_input('Enter extended hexseed: '))) # noqa dist_xmss = XMSS.from_extended_seed(seed) transactions = get_migration_transactions(signing_xmss=dist_xmss, filename=filename) block = Block.create(dev_config=config.dev, block_number=0, prev_headerhash=config.user.genesis_prev_headerhash, prev_timestamp=config.user.genesis_timestamp, transactions=transactions, miner_address=dist_xmss.address, seed_height=None, seed_hash=None) block.set_nonces(config.dev, 0, 0) block._data.genesis_balance.extend([qrl_pb2.GenesisBalance(address=config.dev.coinbase_address, balance=105000000000000000)]) with open('genesis.yml', 'w') as f: yaml.dump(json.loads(block.to_json()), f)
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 test_simple_add_block(self, time_mock): # Simply test that adding a block on top of the genesis block works. self.chain_manager._difficulty_tracker.get.return_value = ask_difficulty_tracker( '2') self.chain_manager.load(self.genesis_block) time_mock.return_value = 1615270948 # Very high to get an easy difficulty block_1 = Block.create(block_number=1, prev_headerhash=self.genesis_block.headerhash, prev_timestamp=self.genesis_block.timestamp, transactions=[], miner_address=alice.address) block_1.set_nonces(201, 0) # Uncomment only to determine the correct mining_nonce of above blocks # from qrl.core.PoWValidator import PoWValidator # while not PoWValidator().validate_mining_nonce(self.state, block_1.blockheader, False): # block_1.set_nonces(block_1.mining_nonce + 1) # print(block_1.mining_nonce) self.assertTrue(block_1.validate(self.chain_manager, {})) result = self.chain_manager.add_block(block_1) self.assertTrue(result) self.assertEqual(self.chain_manager.last_block, block_1)
def test_last_block(self): with set_wallet_dir("test_wallet"): with State() as state: self.assertIsNotNone(state) chain = Chain(state) alice_xmss = get_alice_xmss() staking_address = bytes(alice_xmss.get_address().encode()) address_state_dict = dict() address_state_dict[staking_address] = AddressState.create(address=staking_address, nonce=0, balance=100, pubhashes=[]) tmp_block1 = Block.create(staking_address=staking_address, block_number=0, reveal_hash=bytes(), prevblock_headerhash=bytes(), transactions=[], duplicate_transactions=OrderedDict(), vote=VoteMetadata(), signing_xmss=alice_xmss, nonce=address_state_dict[staking_address].nonce + 1) res = chain.add_block(tmp_block1, address_state_dict, None) address_state_dict[staking_address].increase_nonce() address_state_dict[staking_address].balance += tmp_block1.block_reward self.assertTrue(res) self.assertEqual(0, chain.height) # FIXME: wrong name, it is not height but max_index last_block = chain.get_last_block() self.assertEqual(tmp_block1, last_block)
def test_getBlockByNumber(self): db_state = Mock(spec=State) db_state.get_tx_metadata = MagicMock(return_value=None) db_state.get_block = MagicMock(return_value=None) p2p_factory = Mock(spec=P2PFactory) p2p_factory.pow = Mock(spec=POW) chain_manager = ChainManager(db_state) qrlnode = QRLNode(mining_address=b'') qrlnode.set_chain_manager(chain_manager) qrlnode._p2pfactory = p2p_factory qrlnode._pow = p2p_factory.pow qrlnode._peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(qrlnode) alice_xmss = get_alice_xmss() b = Block.create(block_number=1, prev_headerhash=sha256(b'reveal'), prev_timestamp=10, transactions=[], miner_address=alice_xmss.address) db_state.get_block_by_number = MagicMock(return_value=b) context = Mock(spec=ServicerContext) request = qrl_pb2.GetBlockByNumberReq(block_number=b.block_number) response = service.GetBlockByNumber(request=request, context=context) context.set_code.assert_not_called() self.assertEqual(1, response.block.header.block_number)
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 test_verify_blob(self): alice_xmss = get_alice_xmss() block = Block.create(block_number=5, prevblock_headerhash=bytes(sha2_256(b'test')), transactions=[], miner_address=alice_xmss.address) mining_blob = block.mining_blob self.assertTrue(block.blockheader.verify_blob(mining_blob))
def setUp(self): self.block = Block.create(dev_config=config.dev, block_number=5, prev_headerhash=bytes(sha2_256(b'test')), prev_timestamp=10, transactions=[], miner_address=alice.address, seed_height=0, seed_hash=None)
def test_all_ok(self, m_TransferTransaction_validate, m_TransferTransaction_validate_extended, m_TransferTransaction_apply_state_changes, m_CoinBase_apply_state_changes): address_states = self.generate_address_states( self.alice_addrstate_attrs, {}, self.slave_addrstate_attrs) block = Block.create(**self.block_attrs) result = block.apply_state_changes(address_states) self.assertTrue(result)
def test_all_ok(self, m_TransferTransaction_validate, m_TransferTransaction_validate_extended, m_TransferTransaction_apply_state_changes, m_CoinBase_apply_state_changes): get_optimized_address_state = MockFunction() get_optimized_address_state.put(self.coinbase_addrstate_attrs.address, self.coinbase_addrstate_attrs) get_optimized_address_state.put(self.bob_addrstate_attrs.address, self.bob_addrstate_attrs) get_optimized_address_state.put(self.alice_addrstate_attrs.address, self.alice_addrstate_attrs) get_optimized_address_state.put(self.slave_addrstate_attrs.address, self.slave_addrstate_attrs) self.chain_manager.get_optimized_address_state = get_optimized_address_state.get block = Block.create(**self.block_attrs) result = self.chain_manager._apply_state_changes(block, None) self.assertTrue(result)
def test_write_batch(self): batch = self.state.batch block = Block.create(block_number=10, prev_headerhash=b'aa', prev_timestamp=10, transactions=[], miner_address=b'aa') self.state.put_block(block, batch) self.assertIsNone(self.state.get_block(block.headerhash)) self.state.write_batch(batch) block2 = self.state.get_block(block.headerhash) self.assertEqual(block.headerhash, block2.headerhash)
def test_write_batch(self): with set_qrl_dir('no_data'): with State() as state: batch = state.get_batch() block = Block.create(block_number=10, prevblock_headerhash=b'aa', transactions=[], miner_address=b'aa') state.put_block(block, batch) self.assertIsNone(state.get_block(block.headerhash)) state.write_batch(batch) block2 = state.get_block(block.headerhash) self.assertEqual(block.headerhash, block2.headerhash)
def test_set_mining_nonce_from_blob(self): alice_xmss = get_alice_xmss() block = Block.create(block_number=5, prevblock_headerhash=bytes(sha2_256(b'test')), transactions=[], miner_address=alice_xmss.address) current_mining_nonce = block.mining_nonce current_headerhash = block.headerhash mining_blob = block.mining_blob block.blockheader.set_mining_nonce_from_blob(mining_blob) self.assertEqual(block.blockheader.mining_nonce, current_mining_nonce) self.assertEqual(block.headerhash, current_headerhash) self.assertEqual(block.blockheader.mining_blob, mining_blob)
def test_extra_coinbase_tx(self, m_TransferTransaction_validate, m_TransferTransaction_validate_extended, m_TransferTransaction_apply_state_changes, m_CoinBase_apply_state_changes): address_states = self.generate_address_states( self.alice_addrstate_attrs, {}, self.slave_addrstate_attrs) coinbase_extra = CoinBase.create(500, self.alice.address, 5) self.block_attrs["transactions"] = [self.tx1, coinbase_extra, self.tx2] block = Block.create(**self.block_attrs) result = block.apply_state_changes(address_states) self.assertFalse(result)
def setUp(self): self.blockheader = Mock(name='mock BlockHeader', autospec=BlockHeader, block_number=5, headerhash=bytes(sha2_256(b'mock headerhash')), prev_headerhash=bytes(sha2_256(b'test'))) self.block = Block.create(block_number=5, prev_headerhash=bytes(sha2_256(b'test')), prev_timestamp=10, transactions=[], miner_address=alice.address) self.block.blockheader = self.blockheader
def test_multi_output_transaction_add_block(self, time_mock): # Test that adding block with a multi-output Transaction updates everybody's balances correctly. self.chain_manager.load(self.genesis_block) extended_seed = "010300cebc4e25553afa0aab899f7838e59e18a48852fa9dfd5" \ "ae78278c371902aa9e6e9c1fa8a196d2dba0cbfd2f2d212d16c" random_xmss = XMSS.from_extended_seed(hstr2bin(extended_seed)) transfer_transaction = TransferTransaction.create( addrs_to=[alice.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.pk) transfer_transaction._data.nonce = 1 transfer_transaction.sign(bob) time_mock.return_value = 1615270948 # Very high to get an easy difficulty block_1 = Block.create(block_number=1, prev_headerhash=self.genesis_block.headerhash, prev_timestamp=self.genesis_block.timestamp, transactions=[transfer_transaction], miner_address=alice.address) block_1.set_nonces(129, 0) # Uncomment only to determine the correct mining_nonce of above blocks # from qrl.core.PoWValidator import PoWValidator # while not PoWValidator().validate_mining_nonce(self.state, block_1.blockheader, False): # block_1.set_nonces(block_1.mining_nonce + 1) # print(block_1.mining_nonce) self.assertTrue(block_1.validate(self.chain_manager, {})) result = self.chain_manager.add_block(block_1) self.assertTrue(result) self.assertEqual(self.chain_manager.last_block, block_1) bob_addr_state = self.state.get_address_state(bob.address) alice_addr_state = self.state.get_address_state(alice.address) random_addr_state = self.state.get_address_state(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_write_batch(self): batch = self.state.batch block = Block.create(dev_config=config.dev, block_number=10, prev_headerhash=b'aa', prev_timestamp=10, transactions=[], miner_address=b'aa', seed_height=0, seed_hash=None) Block.put_block(self.state, block, batch) self.assertIsNone(Block.get_block(self.state, block.headerhash)) self.state.write_batch(batch) block2 = Block.get_block(self.state, block.headerhash) self.assertEqual(block.headerhash, block2.headerhash)
def test_add_many_and_save(self): with set_wallet_dir("test_wallet"): with State() as state: self.assertIsNotNone(state) chain = Chain(state) alice_xmss = get_alice_xmss() staking_address = bytes(alice_xmss.get_address().encode()) with patch('qrl.core.config.dev.disk_writes_after_x_blocks'): qrl.core.config.dev.disk_writes_after_x_blocks = 4 prev = bytes() address_state_dict = dict() address_state_dict[staking_address] = AddressState.create( address=staking_address, nonce=0, balance=100, pubhashes=[]) for i in range(10): tmp_block1 = Block.create( staking_address=staking_address, block_number=i, reveal_hash=bytes(), prevblock_headerhash=prev, transactions=[], duplicate_transactions=OrderedDict(), vote=VoteMetadata(), signing_xmss=alice_xmss, nonce=address_state_dict[staking_address].nonce + 1) prev = tmp_block1.headerhash res = chain.add_block(tmp_block1, address_state_dict, StakeValidatorsTracker(), b'1001', alice_xmss) address_state_dict[staking_address].increase_nonce() address_state_dict[ staking_address].balance += tmp_block1.block_reward self.assertEqual( i, chain.height ) # FIXME: wrong name, it is not height but max_index self.assertTrue(res) print(qrl.core.config.dev.disk_writes_after_x_blocks)
def test_update_mining_address(self): alice_xmss = get_alice_xmss() bob_xmss = get_bob_xmss() block = Block.create(block_number=5, prev_headerhash=bytes(sha2_256(b'test')), prev_timestamp=10, transactions=[], miner_address=alice_xmss.address) block.update_mining_address(mining_address=bob_xmss.address) coinbase_tx = Transaction.from_pbdata(block.transactions[0]) self.assertTrue(isinstance(coinbase_tx, CoinBase)) self.assertEqual(coinbase_tx.addr_to, bob_xmss.address) hashedtransactions = [] for tx in block.transactions: hashedtransactions.append(tx.transaction_hash) self.assertEqual(block.blockheader.tx_merkle_root, merkle_tx_hash(hashedtransactions))
def test_extra_coinbase_tx(self, m_TransferTransaction_validate, m_TransferTransaction_validate_extended, m_TransferTransaction_apply_state_changes, m_CoinBase_apply_state_changes): get_optimized_address_state = MockFunction() get_optimized_address_state.put(self.coinbase_addrstate_attrs.address, self.coinbase_addrstate_attrs) get_optimized_address_state.put(self.bob_addrstate_attrs.address, self.bob_addrstate_attrs) get_optimized_address_state.put(self.alice_addrstate_attrs.address, self.alice_addrstate_attrs) get_optimized_address_state.put(self.slave_addrstate_attrs.address, self.slave_addrstate_attrs) coinbase_extra = CoinBase.create(config.dev, 500, self.alice.address, 5) self.block_attrs["transactions"] = [self.tx1, coinbase_extra, self.tx2] block = Block.create(**self.block_attrs) result = self.chain_manager._apply_state_changes(block, None) self.assertFalse(result)
def test_add_block(self): """ 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) chain_manager.load(genesis_block) chain_manager._difficulty_tracker = Mock() dt = DifficultyTracker() tmp_difficulty = StringToUInt256('2') tmp_boundary = dt.get_boundary(tmp_difficulty) chain_manager._difficulty_tracker.get = MagicMock(return_value=(tmp_difficulty, tmp_boundary)) block = state.get_block(genesis_block.headerhash) self.assertIsNotNone(block) slave_tx = SlaveTransaction.create(addr_from=alice_xmss.get_address(), slave_pks=[bob_xmss.pk()], access_types=[0], fee=0, xmss_pk=alice_xmss.pk(), xmss_ots_index=alice_xmss.get_index()) 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(mining_nonce=10, block_number=1, prevblock_headerhash=genesis_block.headerhash, transactions=[slave_tx], signing_xmss=alice_xmss, master_address=alice_xmss.get_address(), nonce=1) while not chain_manager.validate_mining_nonce(block_1, 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.get_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(mining_nonce=15, block_number=1, prevblock_headerhash=genesis_block.headerhash, transactions=[], signing_xmss=bob_xmss, master_address=bob_xmss.get_address(), nonce=1) while not chain_manager.validate_mining_nonce(block, 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(mining_nonce=15, block_number=2, prevblock_headerhash=block.headerhash, transactions=[], signing_xmss=bob_xmss, master_address=bob_xmss.get_address(), nonce=2) while not chain_manager.validate_mining_nonce(block_2, 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())
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_boundary(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 = 1615270948 # Very high to get an easy difficulty block_1 = Block.create(mining_nonce=10, block_number=1, prevblock_headerhash=genesis_block.headerhash, transactions=[], signing_xmss=alice_xmss, master_address=alice_xmss.get_address(), nonce=1) block_1.set_mining_nonce(10) while not chain_manager.validate_mining_nonce(block_1, 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 = 1615270948 + devconfig.minimum_minting_delay * 2 block = Block.create(mining_nonce=18, block_number=1, prevblock_headerhash=genesis_block.headerhash, transactions=[], signing_xmss=bob_xmss, master_address=bob_xmss.get_address(), nonce=1) block.set_mining_nonce(18) while not chain_manager.validate_mining_nonce(block, False): block.set_mining_nonce(block.mining_nonce + 1) with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 + devconfig.minimum_minting_delay * 3 block_2 = Block.create(mining_nonce=17, block_number=2, prevblock_headerhash=block.headerhash, transactions=[], signing_xmss=bob_xmss, master_address=bob_xmss.get_address(), nonce=2) block_2.set_mining_nonce(17) 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_1.block_number) self.assertEqual(chain_manager.last_block.headerhash, block_1.headerhash)
def create_block(self, last_block, mining_nonce, tx_pool, signing_xmss, master_address) -> Optional[Block]: # TODO: Persistence will move to rocksdb # FIXME: Difference between this and create block????????????? # FIXME: Break encapsulation dummy_block = Block.create(mining_nonce=mining_nonce, block_number=last_block.block_number + 1, prevblock_headerhash=last_block.headerhash, transactions=[], signing_xmss=signing_xmss, master_address=master_address, nonce=0) dummy_block.set_mining_nonce(mining_nonce) signing_xmss.set_index(signing_xmss.get_index() - 1) t_pool2 = copy.deepcopy(tx_pool.transaction_pool) del tx_pool.transaction_pool[:] ###### # recreate the transaction pool as in the tx_hash_list, ordered by txhash.. total_txn = len(t_pool2) txnum = 0 addresses_set = set() while txnum < total_txn: tx = t_pool2[txnum] tx.set_effected_address(addresses_set) txnum += 1 addresses_state = dict() for address in addresses_set: addresses_state[address] = self.state.get_address(address) block_size = dummy_block.size block_size_limit = self.state.get_block_size_limit(last_block) txnum = 0 while txnum < total_txn: tx = t_pool2[txnum] # Skip Transactions for later, which doesn't fit into block if block_size + tx.size + config.dev.tx_extra_overhead > block_size_limit: txnum += 1 continue addr_from_pk_state = addresses_state[tx.txfrom] addr_from_pk = Transaction.get_slave(tx) if addr_from_pk: addr_from_pk_state = addresses_state[addr_from_pk] if tx.ots_key_reuse(addr_from_pk_state, tx.ots_key): del t_pool2[txnum] total_txn -= 1 continue if tx.subtype == qrl_pb2.Transaction.TRANSFER: if addresses_state[tx.txfrom].balance < tx.amount + tx.fee: logger.warning('%s %s exceeds balance, invalid tx', tx, tx.txfrom) logger.warning('subtype: %s', tx.subtype) logger.warning('Buffer State Balance: %s Transfer Amount %s', addresses_state[tx.txfrom].balance, tx.amount) del t_pool2[txnum] total_txn -= 1 continue if tx.subtype == qrl_pb2.Transaction.MESSAGE: if addresses_state[tx.txfrom].balance < tx.fee: logger.warning('%s %s exceeds balance, invalid message tx', tx, tx.txfrom) logger.warning('subtype: %s', tx.subtype) logger.warning('Buffer State Balance: %s Free %s', addresses_state[tx.txfrom].balance, tx.fee) total_txn -= 1 continue if tx.subtype == qrl_pb2.Transaction.TOKEN: if addresses_state[tx.txfrom].balance < tx.fee: logger.warning('%s %s exceeds balance, invalid tx', tx, tx.txfrom) logger.warning('subtype: %s', tx.subtype) logger.warning('Buffer State Balance: %s Fee %s', addresses_state[tx.txfrom].balance, tx.fee) del t_pool2[txnum] total_txn -= 1 continue if tx.subtype == qrl_pb2.Transaction.TRANSFERTOKEN: if addresses_state[tx.txfrom].balance < tx.fee: logger.warning('%s %s exceeds balance, invalid tx', tx, tx.txfrom) logger.warning('subtype: %s', tx.subtype) logger.warning('Buffer State Balance: %s Transfer Amount %s', addresses_state[tx.txfrom].balance, tx.fee) del t_pool2[txnum] total_txn -= 1 continue if bin2hstr(tx.token_txhash).encode() not in addresses_state[tx.txfrom].tokens: logger.warning('%s doesnt own any token with token_txnhash %s', tx.txfrom, bin2hstr(tx.token_txhash).encode()) del t_pool2[txnum] total_txn -= 1 continue if addresses_state[tx.txfrom].tokens[bin2hstr(tx.token_txhash).encode()] < tx.amount: logger.warning('Token Transfer amount exceeds available token') logger.warning('Token Txhash %s', bin2hstr(tx.token_txhash).encode()) logger.warning('Available Token Amount %s', addresses_state[tx.txfrom].tokens[bin2hstr(tx.token_txhash).encode()]) logger.warning('Transaction Amount %s', tx.amount) del t_pool2[txnum] total_txn -= 1 continue if tx.subtype == qrl_pb2.Transaction.LATTICE: if addresses_state[tx.txfrom].balance < tx.fee: logger.warning('Lattice TXN %s %s exceeds balance, invalid tx', tx, tx.txfrom) logger.warning('subtype: %s', tx.subtype) logger.warning('Buffer State Balance: %s Transfer Amount %s', addresses_state[tx.txfrom].balance, tx.fee) del t_pool2[txnum] total_txn -= 1 continue if tx.subtype == qrl_pb2.Transaction.SLAVE: if addresses_state[tx.txfrom].balance < tx.fee: logger.warning('Slave TXN %s %s exceeds balance, invalid tx', tx, tx.txfrom) logger.warning('subtype: %s', tx.subtype) logger.warning('Buffer State Balance: %s Transfer Amount %s', addresses_state[tx.txfrom].balance, tx.fee) del t_pool2[txnum] total_txn -= 1 continue tx.apply_on_state(addresses_state) tx_pool.add_tx_to_pool(tx) tx._data.nonce = addresses_state[tx.txfrom].nonce txnum += 1 block_size += tx.size + config.dev.tx_extra_overhead coinbase_nonce = self.state.get_address(signing_xmss.get_address()).nonce if signing_xmss.get_address() in addresses_state: coinbase_nonce = addresses_state[signing_xmss.get_address()].nonce + 1 block = Block.create(mining_nonce=mining_nonce, block_number=last_block.block_number + 1, prevblock_headerhash=last_block.headerhash, transactions=t_pool2, signing_xmss=signing_xmss, master_address=master_address, nonce=coinbase_nonce) return block