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 test_delete(self): block = Block() self.state.put_block(block, None) block1 = self.state.get_block(block.headerhash) self.assertEqual(block.serialize(), block1.serialize()) self.state._delete(block.headerhash, None) self.assertIsNone(self.state.get_block(block.headerhash))
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 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) seed_block = self.get_seed_block(mining_block.block_number) self._dev_config = dev_config self._mining_block = mining_block work_seq_id = self.start(mainHeight=mining_block.block_number, seedHeight=seed_block.block_number, seedHash=seed_block.headerhash, 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 pre_block_logic(self, block: Block): logger.debug('Checking miner lock') with self._miner_lock: if not block.validate(self.chain_manager.state, self.future_blocks): logger.warning('Block Validation failed for #%s %s', block.block_number, bin2hstr(block.headerhash)) return if block.is_future_block(): delay = abs(block.timestamp - ntp.getTime()) + 1 reactor.callLater(delay, self.process_future_blocks) self.add_future_block(block) return 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: self.mine_next(self.chain_manager.last_block) if not result: logger.debug('Block Rejected %s %s', block.block_number, bin2hstr(block.headerhash)) return reactor.callLater(0, self.broadcast_block, block)
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_get_block_by_number(self, m_TransferTransaction_validate, m_TransferTransaction_validate_extended, m_TransferTransaction_apply_state_changes, m_CoinBase_apply_state_changes): bm = qrl_pb2.BlockNumberMapping() Block.put_block_number_mapping(self.state, 0, bm, None) self.assertIsNone(Block.get_block_by_number(self.state, 4))
def test_delete(self): with set_qrl_dir('no_data'): with State() as state: block = Block() state.put_block(block, None) block1 = state.get_block(block.headerhash) self.assertEqual(block.serialize(), block1.serialize()) state._delete(block.headerhash, None) self.assertIsNone(state.get_block(block.headerhash))
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_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('qrl.core.Block.Block.get_block', return_value=None): self.assertIsNone( Block.get_block_size_limit(self.state, blocks[-1], config.dev))
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 = qrl_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_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_GetBlockMiningCompatible(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.get_last_block = MagicMock(return_value=Block()) qrlnode = QRLNode(mining_address=b'') qrlnode.set_chain_manager(chain_manager) qrlnode._p2pfactory = p2p_factory qrlnode._pow = p2p_factory.pow block_header = BlockHeader.create(blocknumber=10, prev_headerhash=sha256(b'prevblock'), prev_timestamp=1234567890, hashedtransactions=sha256(b'tx1'), fee_reward=1) qrlnode.get_blockheader_and_metadata = MagicMock( return_value=[block_header, BlockMetadata()]) service = MiningAPIService(qrlnode) req = qrlmining_pb2.GetBlockMiningCompatibleReq(height=10) answer = service.GetBlockMiningCompatible(request=req, context=None) self.assertEqual(10, answer.blockheader.block_number) self.assertEqual(1, answer.blockheader.reward_fee)
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 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_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_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_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_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_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 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 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.qrlnode = QRLNode(mining_address=b'') self.qrlnode.set_chain_manager(self.chain_manager) self.qrlnode._p2pfactory = p2p_factory self.qrlnode._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.qrlnode)
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 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_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() qrlnode = QRLNode(mining_address=b'') qrlnode.set_chain_manager(chain_manager) qrlnode._p2pfactory = p2p_factory qrlnode._pow = p2p_factory.pow qrlnode.peer_manager = Mock() qrlnode.peer_manager.known_peer_addresses = [ '127.0.0.1', '192.168.1.1' ] service = PublicAPIService(qrlnode) response = service.GetKnownPeers(request=qrl_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 __init__(self, state): self.state = state self.tx_pool = TransactionPool() # TODO: Move to some pool manager self.last_block = Block.from_json(GenesisBlock().to_json()) self.current_difficulty = StringToUInt256(str(config.dev.genesis_difficulty)) self.trigger_miner = False
def handle_block(self, source, message: qrllegacy_pb2.LegacyMessage): # block received """ Block This function processes any new block received. :return: """ P2PBaseObserver._validate_message(message, qrllegacy_pb2.LegacyMessage.BK) try: block = Block(message.block) except Exception as e: logger.error( 'block rejected - unable to decode serialised data %s', source.addr_remote) logger.exception(e) return logger.info('>>>Received block from %s %s %s', source.addr_remote, 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(qrllegacy_pb2.LegacyMessage.BK, block.headerhash, message.block)
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 __init__(self, state): self.state = state self.tx_pool = TransactionPool() # TODO: Move to some pool manager self.last_block = Block.from_json(GenesisBlock().to_json()) self.current_difficulty = StringToUInt256(str(config.dev.genesis_difficulty)) self._difficulty_tracker = DifficultyTracker() self.trigger_miner = False
def get_block(self, header_hash: bytes) -> Optional[Block]: try: json_data = self._db.get_raw(bin2hstr(header_hash).encode()) return Block.from_json(json_data) except KeyError: logger.debug('[get_block] Block header_hash %s not found', bin2hstr(header_hash).encode()) except Exception as e: logger.error('[get_block] %s', e) return None
def __init__(self, state_code, db: db.DB): self._db = db self.state_code = state_code if state_code != b'current_': json_data = self._db.get_raw(self.state_code) self._block_number = Block.from_json(json_data).block_number self._data = qrl_pb2.StateLoader() try: json_data = self._db.get_raw(b'state' + self.state_code) if json_data: Parse(json_data, self._data) except KeyError: pass
def main(): args = parse_arguments() config.create_path(config.user.wallet_dir) slaves = mining_wallet_checks(args) logger.debug("=====================================================================================") logger.info("Data Path: %s", args.data_dir) config.user.data_dir = args.data_dir config.create_path(config.user.data_dir) ntp.setDrift() logger.info('Initializing chain..') persistent_state = State() chain_manager = ChainManager(state=persistent_state) chain_manager.load(Block.from_json(GenesisBlock().to_json())) qrlnode = QRLNode(db_state=persistent_state, slaves=slaves) qrlnode.set_chain(chain_manager) set_logger(args, qrlnode.sync_state) ####### # NOTE: Keep assigned to a variable or might get collected admin_service, grpc_service = start_services(qrlnode) qrlnode.start_listening() qrlnode.connect_peers() qrlnode.start_pow() logger.info('QRL blockchain ledger %s', config.dev.version) logger.info('mining/staking address %s', slaves[0]) # FIXME: This will be removed once we move away from Twisted reactor.run()
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
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)