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('xrd.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 test_getBlock(self): with set_xrd_dir('no_data'): db_state = State() p2p_factory = Mock(spec=P2PFactory) p2p_factory.pow = Mock(spec=POW) chain_manager = ChainManager(db_state) xrdnode = xrdNode(mining_address=b'') xrdnode.set_chain_manager(chain_manager) xrdnode._p2pfactory = p2p_factory xrdnode._pow = p2p_factory.pow xrdnode._peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(xrdnode) 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 = xrd_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_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_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 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_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 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(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) self.block.blockheader = self.blockheader
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_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 create_block(self, prev_hash, mining_address=None): if not mining_address: mining_address = self.alice_xmss.address transactions = [] block_prev = self.xrdnode.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(dev_config=config.dev, block_number=block_idx, prev_headerhash=block_prev.headerhash, prev_timestamp=block_prev.timestamp, transactions=transactions, miner_address=mining_address, seed_height=0, seed_hash=None) dev_config = self.xrdnode._chain_manager.get_config_by_block_number( block_new.block_number) while not self.xrdnode._chain_manager.validate_mining_nonce( blockheader=block_new.blockheader, dev_config=dev_config): block_new.set_nonces(config.dev, 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([ xrd_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 gen_blocks(block_count, state, miner_address): blocks = [] block = None with mock.patch('xrd.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 addresses_state = dict() for i in range(0, block_count): if i == 0: block = GenesisBlock() for genesis_balance in GenesisBlock().genesis_balance: bytes_addr = genesis_balance.address addresses_state[ bytes_addr] = OptimizedAddressState.get_default( bytes_addr) addresses_state[ bytes_addr]._data.balance = genesis_balance.balance else: block = Block.create(dev_config=config.dev, block_number=i, prev_headerhash=block.headerhash, prev_timestamp=block.timestamp, transactions=[], miner_address=miner_address, seed_height=None, seed_hash=None) addresses_set = ChainManager.set_affected_address(block) coin_base_tx = Transaction.from_pbdata(block.transactions[0]) coin_base_tx.set_affected_address(addresses_set) chain_manager = ChainManager(state) state_container = chain_manager.new_state_container( addresses_set, block.block_number, False, None) coin_base_tx.apply(state, state_container) for tx_idx in range(1, len(block.transactions)): tx = Transaction.from_pbdata(block.transactions[tx_idx]) if not chain_manager.update_state_container( tx, state_container): return False tx.apply(state, state_container) block.set_nonces(dev_config=config.dev, mining_nonce=10, extra_nonce=0) blocks.append(block) metadata = BlockMetadata() metadata.set_block_difficulty(StringToUInt256('256')) BlockMetadata.put_block_metadata(state, block.headerhash, metadata, None) Block.put_block(state, block, None) bm = xrd_pb2.BlockNumberMapping( headerhash=block.headerhash, prev_headerhash=block.prev_headerhash) Block.put_block_number_mapping(state, block.block_number, bm, None) state.update_mainchain_height(block.block_number, None) OptimizedAddressState.put_optimized_addresses_state( state, addresses_state) return blocks
def test_getMiniTransactionsByAddress(self, mock_dev_config): mock_dev_config.data_per_page = 5 with set_xrd_dir('no_data'): db_state = State() p2p_factory = Mock(spec=P2PFactory) p2p_factory.pow = Mock(spec=POW) chain_manager = ChainManager(db_state) xrdnode = xrdNode(mining_address=b'') xrdnode.set_chain_manager(chain_manager) xrdnode._p2pfactory = p2p_factory xrdnode._pow = p2p_factory.pow xrdnode._peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(xrdnode) # Find a transaction alice_xmss = get_alice_xmss(8) context = Mock(spec=ServicerContext) bob_xmss = get_bob_xmss(4) txs = [] for i in range(0, 100): tx = TransferTransaction.create(addrs_to=[bob_xmss.address], amounts=[10], message_data=None, fee=0, xmss_pk=alice_xmss.pk) tx.sign(alice_xmss) txs.append(tx) addresses_set = {bob_xmss.address, alice_xmss.address} block = Block.create(config.dev, 10, b'', 100000000, txs, alice_xmss.address, seed_height=0, seed_hash=None) state_container = chain_manager.new_state_container(addresses_set, 5, True, None) for tx in txs: chain_manager.update_state_container(tx, state_container) address_state = state_container.addresses_state[tx.addr_from] state_container.paginated_tx_hash.insert(address_state, tx.txhash) address_state = state_container.addresses_state[tx.addrs_to[0]] state_container.paginated_tx_hash.insert(address_state, tx.txhash) state_container.paginated_tx_hash.put_paginated_data(None) OptimizedAddressState.put_optimized_addresses_state(db_state, state_container.addresses_state) TransactionMetadata.update_tx_metadata(db_state, block, None) request = xrd_pb2.GetMiniTransactionsByAddressReq(address=alice_xmss.address, item_per_page=10, page_number=1) response = service.GetMiniTransactionsByAddress(request=request, context=context) context.set_code.assert_not_called() self.assertEqual(len(response.mini_transactions), 10) for i in range(0, 10): self.assertEqual(bin2hstr(txs[len(txs) - i - 1].txhash), response.mini_transactions[i].transaction_hash) self.assertEqual(response.balance, 0) TransactionMetadata.update_tx_metadata(db_state, block, None) request = xrd_pb2.GetMiniTransactionsByAddressReq(address=alice_xmss.address, item_per_page=8, page_number=3) response = service.GetMiniTransactionsByAddress(request=request, context=context) context.set_code.assert_not_called() self.assertEqual(len(response.mini_transactions), 8) for i in range(0, 8): self.assertEqual(bin2hstr(txs[len(txs) - i - 17].txhash), response.mini_transactions[i].transaction_hash) self.assertEqual(response.balance, 0)
def test_getLatestData(self): with set_xrd_dir('no_data'): db_state = State() chain_manager = ChainManager(db_state) blocks = [] txs = [] alice_xmss = get_alice_xmss() bob_xmss = get_bob_xmss() for i in range(0, 4): for j in range(1, 3): txs.append(TransferTransaction.create(addrs_to=[bob_xmss.address], amounts=[i * 100 + j], message_data=None, fee=j, xmss_pk=alice_xmss.pk)) blocks.append(Block.create(dev_config=config.dev, block_number=i, prev_headerhash=sha256(b'reveal'), prev_timestamp=10, transactions=txs, miner_address=alice_xmss.address, seed_height=10, seed_hash=None)) block = blocks[i] Block.put_block(db_state, block, None) Block.put_block_number_mapping(db_state, block.block_number, xrd_pb2.BlockNumberMapping(headerhash=block.headerhash), None) TransactionMetadata.update_tx_metadata(db_state, block, None) chain_manager._last_block = blocks[-1] txpool = [] txs = [] for j in range(10, 15): tx = TransferTransaction.create(addrs_to=[bob_xmss.address], amounts=[1000 + j], message_data=None, fee=j, xmss_pk=get_alice_xmss().pk) txpool.append((tx.fee, TransactionInfo(tx, 0))) txs.append(tx) p2p_factory = Mock(spec=P2PFactory) p2p_factory.pow = Mock(spec=POW) chain_manager.tx_pool = Mock() chain_manager.tx_pool.transactions = heapq.nlargest(len(txpool), txpool) chain_manager.tx_pool.transaction_pool = txpool xrdnode = xrdNode(mining_address=b'') xrdnode.set_chain_manager(chain_manager) xrdnode.get_block_from_index = MagicMock(return_value=None) xrdnode._p2pfactory = p2p_factory xrdnode._pow = p2p_factory.pow service = PublicAPIService(xrdnode) context = Mock(spec=ServicerContext) request = xrd_pb2.GetLatestDataReq(filter=xrd_pb2.GetLatestDataReq.ALL, offset=0, quantity=3) response = service.GetLatestData(request=request, context=context) context.set_code.assert_not_called() context.set_details.assert_not_called() # Verify blockheaders self.assertEqual(3, len(response.blockheaders)) self.assertEqual(1, response.blockheaders[0].header.block_number) self.assertEqual(2, response.blockheaders[1].header.block_number) self.assertEqual(3, response.blockheaders[2].header.block_number) # Verify transactions_unconfirmed self.assertEqual(3, len(response.transactions_unconfirmed)) # TODO: Verify expected order self.assertEqual(1014, response.transactions_unconfirmed[0].tx.transfer.amounts[0]) self.assertEqual(1013, response.transactions_unconfirmed[1].tx.transfer.amounts[0]) self.assertEqual(1012, response.transactions_unconfirmed[2].tx.transfer.amounts[0]) # Verify transactions self.assertEqual(3, len(response.transactions)) self.assertEqual(2, response.transactions[0].tx.fee) self.assertEqual(1, response.transactions[1].tx.fee) self.assertEqual(2, response.transactions[2].tx.fee) self.assertEqual(302, response.transactions[0].tx.transfer.amounts[0]) self.assertEqual(301, response.transactions[1].tx.transfer.amounts[0]) self.assertEqual(202, response.transactions[2].tx.transfer.amounts[0])
def test_getObject(self): SOME_ODD_HASH = sha256(b'this should not be found') with set_xrd_dir('no_data'): db_state = State() p2p_factory = Mock(spec=P2PFactory) p2p_factory.pow = Mock(spec=POW) chain_manager = ChainManager(db_state) xrdnode = xrdNode(mining_address=b'') xrdnode.set_chain_manager(chain_manager) xrdnode._p2pfactory = p2p_factory xrdnode._pow = p2p_factory.pow xrdnode._peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(xrdnode) # First try an empty request context = Mock(spec=ServicerContext) request = xrd_pb2.GetObjectReq() response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() context.set_details.assert_not_called() self.assertFalse(response.found) # Some odd address context = Mock(spec=ServicerContext) request = xrd_pb2.GetObjectReq() request.query = SOME_ODD_HASH response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() self.assertFalse(response.found) # Find an address bob_xmss = get_bob_xmss() addr1_state = OptimizedAddressState.create(address=bob_xmss.address, nonce=25, balance=10, ots_bitfield_used_page=0, transaction_hash_count=0, tokens_count=0, lattice_pk_count=0, slaves_count=0, multi_sig_address_count=0) AddressState.put_address_state(db_state, addr1_state, None) context = Mock(spec=ServicerContext) request = xrd_pb2.GetObjectReq() request.query = bob_xmss.address response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() self.assertTrue(response.found) self.assertIsNotNone(response.address_state) self.assertEqual(bob_xmss.address, response.address_state.address) self.assertEqual(25, response.address_state.nonce) self.assertEqual(10, response.address_state.balance) # Find a transaction alice_xmss = get_alice_xmss() db_state.address_used = MagicMock(return_value=False) tx1 = TransferTransaction.create( addrs_to=[bob_xmss.address], amounts=[125], message_data=None, fee=19, xmss_pk=bob_xmss.pk, master_addr=alice_xmss.address) chain_manager.tx_pool.transaction_pool = [(0, TransactionInfo(tx1, 0))] context = Mock(spec=ServicerContext) request = xrd_pb2.GetObjectReq() request.query = tx1.txhash response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() self.assertTrue(response.found) self.assertIsNotNone(response.transaction) self.assertEqual('transfer', response.transaction.tx.WhichOneof('transactionType')) self.assertEqual(alice_xmss.address, response.transaction.tx.master_addr) self.assertEqual(bob_xmss.pk, response.transaction.tx.public_key) self.assertEqual(tx1.txhash, response.transaction.tx.transaction_hash) self.assertEqual(b'', response.transaction.tx.signature) self.assertEqual(bob_xmss.address, response.transaction.tx.transfer.addrs_to[0]) self.assertEqual(125, response.transaction.tx.transfer.amounts[0]) self.assertEqual(19, response.transaction.tx.fee) alice_xmss = get_alice_xmss() # Find a block block = 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, block, None) Block.put_block_number_mapping(db_state, block.block_number, xrd_pb2.BlockNumberMapping(headerhash=block.headerhash), None) context = Mock(spec=ServicerContext) request = xrd_pb2.GetObjectReq() request.query = bytes(str2bin('1')) response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() self.assertTrue(response.found) self.assertIsNotNone(response.block_extended) self.assertEqual(1, response.block_extended.header.block_number)
def create_block(self, last_block, mining_nonce, tx_pool: TransactionPool, miner_address) -> Optional[Block]: seed_block = self._chain_manager.get_block_by_number( self._qn.get_seed_height(last_block.block_number + 1)) dev_config = self._chain_manager.get_config_by_block_number( block_number=last_block.block_number + 1) dummy_block = Block.create(dev_config=dev_config, block_number=last_block.block_number + 1, prev_headerhash=last_block.headerhash, prev_timestamp=last_block.timestamp, transactions=[], miner_address=miner_address, seed_height=seed_block.block_number, seed_hash=seed_block.headerhash) dummy_block.set_nonces(dev_config, mining_nonce, 0) t_pool2 = tx_pool.transactions block_size = dummy_block.size block_size_limit = self._chain_manager.get_block_size_limit( last_block, dev_config) transactions = [] state_container = self._chain_manager.new_state_container( set(), last_block.block_number, True, None) 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 + dev_config.tx_extra_overhead > block_size_limit: continue if not self._chain_manager.update_state_container( tx, state_container): logger.error("[create_block] Error updating state_container") return None if not tx.validate_all(state_container, check_nonce=False): if not state_container.revert_update(): return None tx_pool.remove_tx_from_pool(tx) continue if not self._chain_manager.apply_txn(tx, state_container): logger.error("[create_block] Failed to apply txn") if not state_container.revert_update(): return None continue addr_from_pk_state = state_container.addresses_state[tx.addr_from] addr_from_pk = Transaction.get_slave(tx) if addr_from_pk: addr_from_pk_state = state_container.addresses_state[ addr_from_pk] tx._data.nonce = addr_from_pk_state.nonce block_size += tx.size + dev_config.tx_extra_overhead transactions.append(tx) block = Block.create(dev_config=dev_config, block_number=last_block.block_number + 1, prev_headerhash=last_block.headerhash, prev_timestamp=last_block.timestamp, transactions=transactions, miner_address=miner_address, seed_height=seed_block.block_number, seed_hash=seed_block.headerhash) return block