def test_revert_coinbase_txn(self, m_logger): """ Alice earned some coins. Undo this. """ tx = CoinBase.create(config.dev, self.amount, self.alice.address, self.mock_blockheader.block_number) addresses_state = { config.dev.coinbase_address: OptimizedAddressState.get_default(config.dev.coinbase_address), self.alice.address: OptimizedAddressState.get_default(self.alice.address), } addresses_state[config.dev.coinbase_address].pbdata.balance = 1000000 state_container = StateContainer(addresses_state=addresses_state, tokens=Indexer(b'token', None), slaves=Indexer(b'slave', None), lattice_pk=Indexer(b'lattice_pk', None), multi_sig_spend_txs=dict(), votes_stats=dict(), block_number=self.mock_blockheader.block_number, total_coin_supply=100, current_dev_config=config.dev, write_access=True, my_db=self.state._db, batch=None) tx.apply(self.state, state_container) tx.revert(self.state, state_container) self.assertEqual(1000000, addresses_state[config.dev.coinbase_address].balance) storage_key = state_container.paginated_tx_hash.generate_key(config.dev.coinbase_address, 1) self.assertEqual([], state_container.paginated_tx_hash.key_value[storage_key]) self.assertEqual(0, addresses_state[self.alice.address].balance) storage_key = state_container.paginated_tx_hash.generate_key(config.dev.coinbase_address, 1) self.assertEqual([], state_container.paginated_tx_hash.key_value[storage_key])
def test_revert_state_changes(self, m_logger): """ Alice earned some coins. Undo this. """ tx = CoinBase.create(self.amount, self.alice.address, self.mock_blockheader.block_number) addresses_state = { config.dev.coinbase_address: Mock(autospec=AddressState, name='CoinBase AddressState', transaction_hashes=[tx.txhash], balance=1000000 - self.amount), self.alice.address: Mock(autospec=AddressState, name='alice AddressState', transaction_hashes=[tx.txhash], balance=self.amount), } unused_chain_manager_mock = Mock(autospec=ChainManager, name='unused ChainManager') tx.revert_state_changes(addresses_state, unused_chain_manager_mock) self.assertEqual(1000000, addresses_state[config.dev.coinbase_address].balance) self.assertEqual([], addresses_state[config.dev.coinbase_address].transaction_hashes) self.assertEqual(0, addresses_state[self.alice.address].balance) self.assertEqual([], addresses_state[self.alice.address].transaction_hashes) # A blank addresses_state doesn't get modified at all (but in practice, every node should have an AddressState # for the CoinBase addr addresses_state_empty = {} tx.revert_state_changes(addresses_state_empty, unused_chain_manager_mock) self.assertEqual({}, addresses_state_empty)
def test_affected_address(self, m_logger): # This transaction can only involve 2 addresses. affected_addresses = set() tx = CoinBase.create(config.dev, self.amount, self.alice.address, self.mock_blockheader.block_number) tx.set_affected_address(affected_addresses) self.assertEqual(2, len(affected_addresses))
def test_get_mini_transactions_by_address(self, mock_get_tx_metadata, mock_get_optimized_address_state, mock_get_paginated_data): """ QRLNode.get_transactions_by_address() returns all the changes in balance caused by a transaction. """ get_tx_metadata = GetTXMetadata() xmss = get_alice_xmss() xmss2 = get_random_xmss() addr_state = OptimizedAddressState.get_default(xmss.address) addr_state.pbdata.balance = 100 addr_state.pbdata.transaction_hash_count = 3 mock_get_optimized_address_state.return_value = addr_state tx1 = CoinBase.create(config.dev, 100, xmss.address, 5) get_tx_metadata.register_tx_metadata(tx1, 1) tx2 = TransferTransaction.create(addrs_to=[xmss2.address], amounts=[10], message_data=None, fee=1, xmss_pk=xmss.pk) tx2.sign(xmss) get_tx_metadata.register_tx_metadata(tx2, 1) tx3 = TransferTransaction.create(addrs_to=[xmss.address], amounts=[100], message_data=None, fee=1, xmss_pk=xmss2.pk) tx3.sign(xmss) get_tx_metadata.register_tx_metadata(tx3, 2) mock_get_paginated_data.return_value = [ tx1.txhash, tx2.txhash, tx3.txhash ] mock_get_tx_metadata.side_effect = get_tx_metadata.get_tx_metadata response = self.qrlnode.get_mini_transactions_by_address( alice.address, 3, 1) result, balance = response.mini_transactions, response.balance self.assertEqual(len(result), 3) self.assertEqual(result[0].amount, 100) self.assertEqual(result[0].out, False) self.assertEqual(result[1].amount, 11) self.assertEqual(result[1].out, True) self.assertEqual(result[2].amount, 100) self.assertEqual(result[2].out, False) self.assertEqual(balance, 100)
def test_validate_custom(self, m_logger): """ CoinBase _validate_custom() only checks if fee == 0 """ tx = CoinBase.create(self.amount, self.alice.address, self.mock_blockheader.block_number) tx._data.fee = 1 result = tx._validate_custom() self.assertFalse(result) tx._data.fee = 0 result = tx._validate_custom() self.assertTrue(result)
def test_from_txdict(self, m_logger): amount = self.mock_blockheader.block_reward + self.mock_blockheader.fee_reward tx = CoinBase.create(amount, self.alice.address, self.mock_blockheader.block_number) self.assertIsInstance(tx, CoinBase) # Test that common Transaction components were copied over. self.assertEqual(self.mock_blockheader.block_number + 1, tx.nonce) self.assertEqual('010300a1da274e68c88b0ccf448e0b1916fa789b01eb2ed4e9ad565ce264c9390782a9c61ac02f', bin2hstr(tx.addr_to)) self.assertEqual('222460cc57ab8683b46f1831fe6cf1832c7e3134baf74d33bfaf91741e19cba2', bin2hstr(tx.txhash)) self.assertEqual(tx.amount, 90)
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 test_get_transactions_by_address(self): """ QRLNode.get_transactions_by_address() returns all the changes in balance caused by a transaction. """ mock_get_tx_metadata = GetTXMetadata() xmss = get_alice_xmss() xmss2 = get_random_xmss() addr_state = AddressState.get_default(xmss.address) addr_state.pbdata.balance = 100 tx1 = CoinBase.create(100, xmss.address, 5) mock_get_tx_metadata.register_tx_metadata(tx1, 5) addr_state.transaction_hashes.append(tx1.txhash) tx2 = TransferTransaction.create(addrs_to=[xmss2.address], amounts=[10], fee=1, xmss_pk=xmss.pk) tx2.sign(xmss) mock_get_tx_metadata.register_tx_metadata(tx2, 99) addr_state.transaction_hashes.append(tx2.txhash) tx3 = TransferTransaction.create(addrs_to=[xmss.address], amounts=[100], fee=1, xmss_pk=xmss2.pk) tx3.sign(xmss) mock_get_tx_metadata.register_tx_metadata(tx3, 101) addr_state.transaction_hashes.append(tx3.txhash) self.db_state.get_address_state.return_value = addr_state self.db_state.get_tx_metadata = mock_get_tx_metadata.get_tx_metadata result, balance = self.qrlnode.get_transactions_by_address( alice.address) self.assertEqual(len(result), 3) self.assertEqual(result[0].amount, 100) self.assertEqual(result[0].out, False) self.assertEqual(result[1].amount, 11) self.assertEqual(result[1].out, True) self.assertEqual(result[2].amount, 100) self.assertEqual(result[2].out, False) self.assertEqual(balance, 189)
def create(dev_config: DevConfig, block_number: int, prev_headerhash: bytes, prev_timestamp: int, transactions: list, miner_address: bytes, seed_height: Optional[int], seed_hash: Optional[bytes]): block = Block() # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: fee_reward += tx.fee # Prepare coinbase tx total_reward_amount = BlockHeader.block_reward_calc( block_number, dev_config) + fee_reward coinbase_tx = CoinBase.create(dev_config, total_reward_amount, miner_address, block_number) hashedtransactions.append(coinbase_tx.txhash) Block._copy_tx_pbdata_into_block( block, coinbase_tx) # copy memory rather than sym link for tx in transactions: hashedtransactions.append(tx.txhash) Block._copy_tx_pbdata_into_block( block, tx) # copy memory rather than sym link txs_hash = merkle_tx_hash( hashedtransactions) # FIXME: Find a better name, type changes tmp_blockheader = BlockHeader.create(dev_config=dev_config, blocknumber=block_number, prev_headerhash=prev_headerhash, prev_timestamp=prev_timestamp, hashedtransactions=txs_hash, fee_reward=fee_reward, seed_height=seed_height, seed_hash=seed_hash) block.blockheader = tmp_blockheader block._data.header.MergeFrom(tmp_blockheader.pbdata) block.set_nonces(dev_config, 0, 0) return block
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_validate_extended(self, m_logger): """ CoinBase validate_extended() checks for 1. valid coinbase address (the coinbase address must be config.dev.coinbase_address) 2. valid addr_to then calls _validate_custom() """ tx = CoinBase.create(config.dev, self.amount, self.alice.address, self.mock_blockheader.block_number) tx._data.master_addr = self.alice.address addresses_state = { config.dev.coinbase_address: OptimizedAddressState.get_default(config.dev.coinbase_address), self.alice.address: OptimizedAddressState.get_default(self.alice.address), } addresses_state[config.dev.coinbase_address].pbdata.balance = 1000000 state_container = StateContainer( addresses_state=addresses_state, tokens=Indexer(b'token', None), slaves=Indexer(b'slave', None), lattice_pk=Indexer(b'lattice_pk', None), multi_sig_spend_txs=dict(), votes_stats=dict(), block_number=self.mock_blockheader.block_number, total_coin_supply=100, current_dev_config=config.dev, write_access=True, my_db=self.state._db, batch=None) result = tx._validate_extended(state_container) self.assertFalse(result) tx._data.master_addr = config.dev.coinbase_address with patch('qrl.core.txs.CoinBase.CoinBase.addr_to', new_callable=PropertyMock) as m_addr_to: m_addr_to.return_value = b'Fake Address' result = tx._validate_extended(state_container) self.assertFalse(result) result = tx._validate_extended(state_container) self.assertTrue(result)
def create(block_number: int, prev_headerhash: bytes, prev_timestamp: int, transactions: list, miner_address: bytes): block = Block() # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: fee_reward += tx.fee # Prepare coinbase tx total_reward_amount = BlockHeader.block_reward_calc( block_number) + fee_reward coinbase_tx = CoinBase.create(total_reward_amount, miner_address, block_number) hashedtransactions.append(coinbase_tx.txhash) block._data.transactions.extend([coinbase_tx.pbdata ]) # copy memory rather than sym link for tx in transactions: hashedtransactions.append(tx.txhash) block._data.transactions.extend( [tx.pbdata]) # copy memory rather than sym link txs_hash = merkle_tx_hash( hashedtransactions) # FIXME: Find a better name, type changes tmp_blockheader = BlockHeader.create(blocknumber=block_number, prev_headerhash=prev_headerhash, prev_timestamp=prev_timestamp, hashedtransactions=txs_hash, fee_reward=fee_reward) block.blockheader = tmp_blockheader block._data.header.MergeFrom(tmp_blockheader.pbdata) block.set_nonces(0, 0) return block
def test_validate_extended(self, m_logger): """ CoinBase validate_extended() checks for 1. valid coinbase address (the coinbase address must be config.dev.coinbase_address) 2. valid addr_to then calls _validate_custom() """ tx = CoinBase.create(self.amount, self.alice.address, self.mock_blockheader.block_number) tx._data.master_addr = self.alice.address result = tx.validate_extended(self.mock_blockheader.block_number) self.assertFalse(result) tx._data.master_addr = config.dev.coinbase_address with patch('qrl.core.txs.CoinBase.CoinBase.addr_to', new_callable=PropertyMock) as m_addr_to: m_addr_to.return_value = b'Fake Address' result = tx.validate_extended(self.mock_blockheader.block_number) self.assertFalse(result) result = tx.validate_extended(self.mock_blockheader.block_number) self.assertTrue(result)
def test_apply_state_changes(self, m_logger): """ Alice earned some coins. """ addresses_state = { config.dev.coinbase_address: Mock(autospec=AddressState, name='CoinBase AddressState', transaction_hashes=[], balance=1000000), self.alice.address: Mock(autospec=AddressState, name='alice AddressState', transaction_hashes=[], balance=0), } tx = CoinBase.create(self.amount, self.alice.address, self.mock_blockheader.block_number) tx.apply_state_changes(addresses_state) self.assertEqual(1000000 - tx.amount, addresses_state[config.dev.coinbase_address].balance) self.assertEqual([tx.txhash], addresses_state[config.dev.coinbase_address].transaction_hashes) self.assertEqual(tx.amount, addresses_state[self.alice.address].balance) self.assertEqual([tx.txhash], addresses_state[self.alice.address].transaction_hashes) # A blank addresses_state doesn't get modified at all (but in practice, every node should have an AddressState # for the CoinBase addr addresses_state_empty = {} tx.apply_state_changes(addresses_state_empty) self.assertEqual({}, addresses_state_empty)
def test_to_json(self, m_logger): amount = self.mock_blockheader.block_reward + self.mock_blockheader.fee_reward tx = CoinBase.create(amount, self.alice.address, self.mock_blockheader.block_number) txjson = tx.to_json() self.assertEqual(json.loads(test_json_CoinBase), json.loads(txjson))
def test_create(self, m_logger): tx = CoinBase.create(self.amount, self.alice.address, self.mock_blockheader.block_number) self.assertIsInstance(tx, CoinBase)