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_get_block_by_number(self, m_TransferTransaction_validate, m_TransferTransaction_validate_extended, m_TransferTransaction_apply_state_changes, m_CoinBase_apply_state_changes): bm = xrd_pb2.BlockNumberMapping() Block.put_block_number_mapping(self.state, 0, bm, None) self.assertIsNone(Block.get_block_by_number(self.state, 4))
def start_mining(self, mining_block: Block, current_target: bytes, dev_config: DevConfig): try: logger.debug('start_mining - TRY LOCK') with self.lock: logger.debug('start_mining - LOCKED') self.cancel() mining_blob = mining_block.mining_blob(dev_config) nonce_offset = mining_block.mining_nonce_offset(dev_config) self._dev_config = dev_config self._mining_block = mining_block work_seq_id = self.start(input=mining_blob, nonceOffset=nonce_offset, target=current_target, thread_count=self._mining_thread_count) logger.debug("MINING START [{}]".format(work_seq_id)) except Exception as e: logger.warning("Exception in start_mining") logger.exception(e) logger.debug('start_mining - UNLOCKED')
def test_get_block_number_mapping( self, m_TransferTransaction_validate, m_TransferTransaction_validate_extended, m_TransferTransaction_apply_state_changes, m_CoinBase_apply_state_changes): self.assertIsNone(Block.get_block_number_mapping(self.state, 0)) bm = xrd_pb2.BlockNumberMapping() Block.put_block_number_mapping(self.state, 0, bm, None) read_bm = Block.get_block_number_mapping(self.state, 0) self.assertEqual(bm.SerializeToString(), read_bm.SerializeToString())
def test_get_block_size_limit(self): alice_xmss = get_alice_xmss() blocks = gen_blocks(20, self.state, alice_xmss.address) self.assertEqual( Block.get_block_size_limit(self.state, blocks[-1], config.dev), 1048576) # get_block_size_limit() should return None if it couldn't get any blocks from db with patch('xrd.core.Block.Block.get_block', return_value=None): self.assertIsNone( Block.get_block_size_limit(self.state, blocks[-1], config.dev))
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_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_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 handle_block(self, source, message: xrdlegacy_pb2.LegacyMessage): # block received """ Block This function processes any new block received. :return: """ P2PBaseObserver._validate_message(message, xrdlegacy_pb2.LegacyMessage.BK) try: block = Block(message.block) except Exception as e: logger.error( 'block rejected - unable to decode serialised data %s', source.peer) logger.exception(e) return logger.info('>>>Received block from %s %s %s', source.peer.full_address, block.block_number, bin2hstr(block.headerhash)) if not source.factory.master_mr.isRequested(block.headerhash, source, block): return source.factory.pow.pre_block_logic( block) # FIXME: Ignores return value source.factory.master_mr.register(xrdlegacy_pb2.LegacyMessage.BK, block.headerhash, message.block)
def test_getKnownPeers(self): p2p_factory = Mock(spec=P2PFactory) p2p_factory.sync_state = SyncState() p2p_factory.num_connections = 23 p2p_factory.pow = Mock() chain_manager = Mock(spec=ChainManager) chain_manager.height = 0 chain_manager.last_block = Block() xrdnode = xrdNode(mining_address=b'') xrdnode.set_chain_manager(chain_manager) xrdnode._p2pfactory = p2p_factory xrdnode._pow = p2p_factory.pow xrdnode.peer_manager = Mock() xrdnode.peer_manager.known_peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(xrdnode) response = service.GetKnownPeers(request=xrd_pb2.GetKnownPeersReq, context=None) self.assertEqual(2, len(response.known_peers)) self.assertEqual('127.0.0.1', response.known_peers[0].ip) self.assertEqual('192.168.1.1', response.known_peers[1].ip) logger.info(response)
def setUp(self): p2p_factory = Mock(spec=P2PFactory) p2p_factory.sync_state = SyncState() p2p_factory.num_connections = 23 p2p_factory.pow = Mock() b = Block() self.chain_manager = Mock(spec=ChainManager) self.chain_manager.height = 0 self.chain_manager.get_last_block = MagicMock(return_value=b) self.chain_manager.get_block_header_hash_by_number = MagicMock( return_value=b.headerhash) self.xrdnode = xrdNode(mining_address=b'') self.xrdnode.set_chain_manager(self.chain_manager) self.xrdnode._p2pfactory = p2p_factory self.xrdnode._pow = p2p_factory.pow self.block_header_params = { "dev_config": config.dev, "blocknumber": 10, "prev_headerhash": sha256(b'prevblock'), "prev_timestamp": 1234567890, "hashedtransactions": sha256(b'tx1'), "fee_reward": 1, "seed_height": 0, "seed_hash": None, } self.service = MiningAPIService(self.xrdnode)
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_update_last_tx(self): alice_xmss = get_alice_xmss() # Test Case: When there is no last txns self.assertEqual(LastTransactions.get_last_txs(self.state), []) block = Block() 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._data.transactions.extend([tx1.pbdata]) LastTransactions._update_last_tx(self.state, block, None) last_txns = LastTransactions.get_last_txs(self.state) # Test Case: When there is only 1 last txns self.assertEqual(len(last_txns), 1) self.assertEqual(last_txns[0].to_json(), tx1.to_json()) block = Block() tx2 = TransferTransaction.create( addrs_to=[get_some_address(2), get_some_address(3)], amounts=[1, 2], message_data=None, fee=0, xmss_pk=alice_xmss.pk) tx3 = TransferTransaction.create( addrs_to=[get_some_address(4), get_some_address(5)], amounts=[1, 2], message_data=None, fee=0, xmss_pk=alice_xmss.pk) block._data.transactions.extend([tx2.pbdata, tx3.pbdata]) LastTransactions._update_last_tx(self.state, block, None) last_txns = LastTransactions.get_last_txs(self.state) # Test Case: When there are 3 last txns self.assertEqual(len(last_txns), 3) self.assertEqual(last_txns[0].to_json(), tx3.to_json()) self.assertEqual(last_txns[1].to_json(), tx2.to_json()) self.assertEqual(last_txns[2].to_json(), tx1.to_json())
def test_delete(self): block = Block() Block.put_block(self.state, block, None) block1 = Block.get_block(self.state, block.headerhash) self.assertEqual(block.serialize(), block1.serialize()) self.state._delete(block.headerhash, None) self.assertIsNone(Block.get_block(self.state, block.headerhash))
def test_last_block(self, m_TransferTransaction_validate, m_TransferTransaction_validate_extended, m_TransferTransaction_apply_state_changes, m_CoinBase_apply_state_changes): def get_block_by_number(state, block_number): block = Block() block.blockheader._data.block_number = block_number return block self.assertIsNone(Block.last_block(self.state)) with patch("xrd.core.Block.Block.get_block_by_number" ) as mock_get_block_by_number: mock_get_block_by_number.side_effect = get_block_by_number self.state.update_mainchain_height(10, None) self.assertEqual(Block.last_block(self.state).block_number, 10) self.state.update_mainchain_height(1, None) self.assertEqual(Block.last_block(self.state).block_number, 1)
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_peer_fetch_block_we_are_synced(self, m_reactor, m_logger): """ If is_syncing_finished() is True, then let's not ask for more blocks. """ with patch.object(Block, 'get_block', return_value=Block()): self.factory.is_syncing_finished.return_value = True self.factory.peer_fetch_block() self.channel_1.send_fetch_block.assert_not_called()
def block_received(self, source, block: Block): self.pow.last_pb_time = ntp.getTime() logger.info('>>> Received Block #%d %s', block.block_number, bin2hstr(block.headerhash)) if source != self._target_channel: if self._target_channel is None: logger.warning('Received block and target channel is None') else: logger.warning('Received block from unexpected peer') logger.warning('Expected peer: %s', self._target_channel.peer) logger.warning('Found peer: %s', source.peer) return if block.block_number != self._last_requested_block_number: logger.warning('Did not match %s', self._last_requested_block_number) self._xrd_node.peer_manager.ban_channel(source) return target_start_blocknumber = self._target_node_header_hash.block_number expected_headerhash = self._target_node_header_hash.headerhashes[ block.block_number - target_start_blocknumber] if block.headerhash != expected_headerhash: logger.warning('Did not match headerhash') logger.warning('Expected headerhash %s', expected_headerhash) logger.warning('Found headerhash %s', block.headerhash) self._xrd_node.peer_manager.ban_channel(source) return if not block.validate(self._chain_manager, self.pow.future_blocks): logger.warning('Syncing Failed: Block Validation Failed') self._xrd_node.peer_manager.ban_channel(source) return if self._chain_manager.add_block(block, check_stale=False): if self._chain_manager.last_block.headerhash == block.headerhash: self.pow.suspend_mining_timestamp = ntp.getTime( ) + config.dev.sync_delay_mining else: logger.warning('Failed to Add Block') self._xrd_node.peer_manager.ban_channel(source) return try: reactor.download_monitor.cancel() except Exception as e: logger.warning("PB: %s", e) if self.is_syncing_finished(): return self._last_requested_block_number += 1 self.peer_fetch_block()
def test_peer_fetch_block_we_already_have_the_block(self, m_reactor, m_logger): """ If peer_fetch_block() finds a corresponding block in the node's chain, then it keeps asking the node's local chain for newer blocks until 1. the node doesn't have any newer blocks OR 2. we've reached the end of the peer's NodeHeaderHash. Then it will ask the peer for the next block after that. """ with patch.object(Block, 'get_block', return_value=Block()): self.factory.peer_fetch_block() self.assertEqual(Block.get_block.call_count, 3) self.channel_1.send_fetch_block.assert_called_once_with(3)
def pre_block_logic(self, block: Block): logger.debug('LOCK - TRY - pre_block_logic') with self.miner.lock: logger.debug('LOCK - LOCKED - pre_block_logic') if not block.validate(self.chain_manager, self.future_blocks): logger.warning('Block Validation failed for #%s %s', block.block_number, bin2hstr(block.headerhash)) return False dev_config = self.chain_manager.get_config_by_block_number( block.block_number) if block.is_future_block(dev_config): delay = abs(block.timestamp - ntp.getTime()) + 1 reactor.callLater(delay, self.process_future_blocks) self.add_future_block(block) return True logger.debug('Inside add_block') result = self.chain_manager.add_block(block) logger.debug('trigger_miner %s', self.chain_manager.trigger_miner) if self.chain_manager.trigger_miner: logger.debug('try last block') last_block = self.chain_manager.last_block logger.debug('got last block') self._mine_next(last_block) if not result: logger.debug('Block Rejected %s %s', block.block_number, bin2hstr(block.headerhash)) return False reactor.callLater(0, self.broadcast_block, block) logger.debug('LOCK - RELEASE - pre_block_logic') return result
def test_start_mining_works(self, m_getTime, m_logger): m_getTime.return_value = self.time # Do prepare_next_unmined_block_template()'s job self.miner._mining_block = Block() # From sample run of test_prepare_next_unmined_block_template_works() self.miner._measurement = 60 self.miner._current_difficulty = StringToUInt256('0') self.miner._current_target = \ StringToUInt256('115792089237316195423570985008687907853269984665640564039457584007913129639807') # start() is from Qryptominer, let's not actually mine in a test with patch('xrd.core.miners.qryptonight7.CNv1Miner.CNv1Miner.start', spec=True) as m_start: self.miner.start_mining(self.parent_block, self.parent_difficulty, config.dev) m_start.assert_called_once()
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 test_getNodeState(self): p2p_factory = Mock(spec=P2PFactory) p2p_factory.sync_state = SyncState() p2p_factory.num_connections = 23 p2p_factory.pow = Mock() chain_manager = Mock(spec=ChainManager) chain_manager.height = 0 chain_manager.last_block = Block() xrdnode = xrdNode(mining_address=b'') xrdnode.set_chain_manager(chain_manager) xrdnode._p2pfactory = p2p_factory xrdnode._pow = p2p_factory.pow service = PublicAPIService(xrdnode) node_state = service.GetNodeState(request=xrd_pb2.GetNodeStateReq, context=None) # self.assertEqual(__version__, node_state.info.version) # FIXME self.assertEqual(xrd_pb2.NodeInfo.UNSYNCED, node_state.info.state) self.assertEqual(23, node_state.info.num_connections)
def setUp(self): self.time = 1526830525 self.m_mining_qaddress = alice.qaddress self.m_mining_address = parse_qaddress(self.m_mining_qaddress) self.chain_manager = Mock(spec=ChainManager) self.chain_manager.get_block_size_limit.return_value = 500 self.chain_manager.get_config_by_block_number.return_value = config.dev self.parent_block = Block() self.parent_difficulty = StringToUInt256('0') # tuple (0,0,0,0,0...) length 32 self.m_pre_block_logic = Mock(spec=POW.pre_block_logic, name='hello') mining_thread_count = 1 self.miner = Miner(self.chain_manager, self.m_pre_block_logic, self.m_mining_address, mining_thread_count) self.txpool = Mock(spec=TransactionPool) self.txpool.transactions = []
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 setUp(self): self.m_mining_qaddress = alice.qaddress self.m_mining_address = parse_qaddress(self.m_mining_qaddress) self.alice_address_state = Mock(autospec=OptimizedAddressState, name='mock alice OptimizedAddressState') self.chain_manager = Mock(spec=ChainManager) self.chain_manager.get_block_size_limit.return_value = 500 self.chain_manager.get_address_state.return_value = self.alice_address_state self.chain_manager.get_config_by_block_number.return_value = config.dev self.parent_block = Block() self.parent_difficulty = StringToUInt256('0') # tuple (0,0,0,0,0...) length 32 self.m_pre_block_logic = Mock(spec=POW.pre_block_logic, name='hello') mining_thread_count = 1 self.miner = Miner(self.chain_manager, self.m_pre_block_logic, self.m_mining_address, mining_thread_count) self.txpool = TransactionPool(None) def replacement_set_affected_address(addresses_set): return addresses_set.add(alice.address) self.m_tx_args = {"addr_from": alice.address, "addrs_to": [bob.address], "amounts": [10], "fee": 1, "PK": alice.pk, "master_addr": None, "size": 150, "validate_extended.return_value": True, "set_affected_address": replacement_set_affected_address }
def test_remove_last_tx(self): # Test Case: When there is no last txns self.assertEqual(LastTransactions.get_last_txs(self.state), []) alice_xmss = get_alice_xmss() block = Block() 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._data.transactions.extend([tx1.pbdata]) LastTransactions._update_last_tx(self.state, block, None) last_txns = LastTransactions.get_last_txs(self.state) self.assertEqual(last_txns[0].to_json(), tx1.to_json()) LastTransactions._remove_last_tx(self.state, block, None) last_txns = LastTransactions.get_last_txs(self.state) self.assertEqual(last_txns, [])