def load(self, genesis_block): height = self.state.get_mainchain_height() if height == -1: self.state.put_block(genesis_block, None) block_number_mapping = qrl_pb2.BlockNumberMapping(headerhash=genesis_block.headerhash, prev_headerhash=genesis_block.prev_headerhash) self.state.put_block_number_mapping(genesis_block.block_number, block_number_mapping, None) parent_difficulty = StringToUInt256(str(config.dev.genesis_difficulty)) self.current_difficulty, _ = DifficultyTracker.get( measurement=config.dev.mining_setpoint_blocktime, parent_difficulty=parent_difficulty) block_metadata = BlockMetadata.create() block_metadata.set_orphan(False) block_metadata.set_block_difficulty(self.current_difficulty) block_metadata.set_cumulative_difficulty(self.current_difficulty) self.state.put_block_metadata(genesis_block.headerhash, block_metadata, None) addresses_state = dict() for genesis_balance in GenesisBlock().genesis_balance: bytes_addr = genesis_balance.address addresses_state[bytes_addr] = AddressState.get_default(bytes_addr) addresses_state[bytes_addr]._data.balance = genesis_balance.balance self.state.state_objects.update_current_state(addresses_state) self.state.state_objects.push(genesis_block.headerhash) else: self.last_block = self.get_block_by_number(height) self.current_difficulty = self.state.get_block_metadata(self.last_block.headerhash).block_difficulty
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 _update_mainchain(self, block, batch): block_number_mapping = None while block_number_mapping is None or block.headerhash != block_number_mapping.headerhash: block_number_mapping = qrl_pb2.BlockNumberMapping(headerhash=block.headerhash, prev_headerhash=block.prev_headerhash) self.state.put_block_number_mapping(block.block_number, block_number_mapping, batch) block = self.state.get_block(block.prev_headerhash) block_number_mapping = self.state.get_block_number_mapping(block.block_number)
def test_state_block_map(self): with set_data_dir('no_data'): with State() as state: bm = qrl_pb2.BlockNumberMapping() state.put_block_number_mapping(b"0", bm, None) read_bm = state.get_block_number_mapping(b"0") self.assertEqual(type(bm), type(read_bm)) self.assertIsNone(state.get_block_by_number(b"4"))
def test_get_block_number_mapping(self): with set_qrl_dir('no_data'): with State() as state: self.assertIsNone(state.get_block_number_mapping(0)) bm = qrl_pb2.BlockNumberMapping() state.put_block_number_mapping(0, bm, None) read_bm = state.get_block_number_mapping(0) self.assertEqual(bm.SerializeToString(), read_bm.SerializeToString())
def load(self, genesis_block): height = self.state.get_mainchain_height() if height == -1: self.state.put_block(genesis_block, None) block_number_mapping = qrl_pb2.BlockNumberMapping(headerhash=genesis_block.headerhash, prev_headerhash=genesis_block.prev_headerhash) self.state.put_block_number_mapping(genesis_block.block_number, block_number_mapping, None) parent_difficulty = StringToUInt256(str(config.dev.genesis_difficulty)) self.current_difficulty, _ = DifficultyTracker.get( measurement=config.dev.mining_setpoint_blocktime, parent_difficulty=parent_difficulty) block_metadata = BlockMetadata.create() block_metadata.set_orphan(False) block_metadata.set_block_difficulty(self.current_difficulty) block_metadata.set_cumulative_difficulty(self.current_difficulty) self.state.put_block_metadata(genesis_block.headerhash, block_metadata, None) addresses_state = dict() for genesis_balance in GenesisBlock().genesis_balance: bytes_addr = genesis_balance.address addresses_state[bytes_addr] = AddressState.get_default(bytes_addr) addresses_state[bytes_addr]._data.balance = genesis_balance.balance for tx_idx in range(1, len(genesis_block.transactions)): tx = Transaction.from_pbdata(genesis_block.transactions[tx_idx]) for addr in tx.addrs_to: addresses_state[addr] = AddressState.get_default(addr) coinbase_tx = Transaction.from_pbdata(genesis_block.transactions[0]) if not isinstance(coinbase_tx, CoinBase): return False addresses_state[coinbase_tx.addr_to] = AddressState.get_default(coinbase_tx.addr_to) if not coinbase_tx.validate_extended(): return False coinbase_tx.apply_on_state(addresses_state) for tx_idx in range(1, len(genesis_block.transactions)): tx = Transaction.from_pbdata(genesis_block.transactions[tx_idx]) tx.apply_on_state(addresses_state) self.state.state_objects.update_current_state(addresses_state) self.state.state_objects.update_tx_metadata(genesis_block, None) self.state.state_objects.push(genesis_block.headerhash) else: self.last_block = self.get_block_by_number(height) self.current_difficulty = self.state.get_block_metadata(self.last_block.headerhash).block_difficulty
def get_block_number_mapping(state: State, block_number: int): try: data = state._db.get_raw(str(block_number).encode()) block_number_mapping = qrl_pb2.BlockNumberMapping() return Parse(data, block_number_mapping) except KeyError: logger.debug('[get_block_number_mapping] Block #%s not found', block_number) except Exception as e: logger.error('[get_block_number_mapping] %s', e) return None
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 get_block_number_mapping(self, block_number: int) -> Optional[qrl_pb2.BlockNumberMapping]: try: json_data = self._db.get_raw(str(block_number).encode()) block_number_mapping = qrl_pb2.BlockNumberMapping() return Parse(json_data, block_number_mapping) except KeyError: logger.debug('[get_block_number_mapping] Block #%s not found', block_number) except Exception as e: logger.error('[get_block_number_mapping] %s', e) return None
def gen_blocks(block_count, state, miner_address): blocks = [] block = None with mock.patch('qrl.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] = AddressState.get_default( bytes_addr) addresses_state[ bytes_addr]._data.balance = genesis_balance.balance else: block = Block.create(block_number=i, prev_headerhash=block.headerhash, prev_timestamp=block.timestamp, transactions=[], miner_address=miner_address) addresses_set = state.prepare_address_list(block) for address in addresses_set: addresses_state[address] = state.get_address_state(address) for tx_protobuf in block.transactions: tx = Transaction.from_pbdata(tx_protobuf) tx.apply_state_changes(addresses_state) block.set_nonces(10, 0) blocks.append(block) metadata = BlockMetadata() metadata.set_block_difficulty(StringToUInt256('256')) state.put_block_metadata(block.headerhash, metadata, None) state.put_block(block, None) bm = qrl_pb2.BlockNumberMapping( headerhash=block.headerhash, prev_headerhash=block.prev_headerhash) state.put_block_number_mapping(block.block_number, bm, None) state.update_mainchain_height(block.block_number, None) state.put_addresses_state(addresses_state) return blocks
def test_getBlockByNumber(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) Block.put_block_number_mapping(db_state, b.block_number, qrl_pb2.BlockNumberMapping(headerhash=b.headerhash), None) 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 load(self, genesis_block): # load() has the following tasks: # Write Genesis Block into State immediately # Register block_number <-> blockhash mapping # Calculate difficulty Metadata for Genesis Block # Generate AddressStates from Genesis Block balances # Apply Genesis Block's transactions to the state # Detect if we are forked from genesis block and if so initiate recovery. height = self._state.get_mainchain_height() if height == -1: self._state.put_block(genesis_block, None) block_number_mapping = qrl_pb2.BlockNumberMapping( headerhash=genesis_block.headerhash, prev_headerhash=genesis_block.prev_headerhash) self._state.put_block_number_mapping(genesis_block.block_number, block_number_mapping, None) parent_difficulty = StringToUInt256( str(config.user.genesis_difficulty)) self.current_difficulty, _ = DifficultyTracker.get( measurement=config.dev.mining_setpoint_blocktime, parent_difficulty=parent_difficulty) block_metadata = BlockMetadata.create() block_metadata.set_block_difficulty(self.current_difficulty) block_metadata.set_cumulative_difficulty(self.current_difficulty) self._state.put_block_metadata(genesis_block.headerhash, block_metadata, None) addresses_state = dict() for genesis_balance in GenesisBlock().genesis_balance: bytes_addr = genesis_balance.address addresses_state[bytes_addr] = AddressState.get_default( bytes_addr) addresses_state[ bytes_addr]._data.balance = genesis_balance.balance for tx_idx in range(1, len(genesis_block.transactions)): tx = Transaction.from_pbdata( genesis_block.transactions[tx_idx]) for addr in tx.addrs_to: addresses_state[addr] = AddressState.get_default(addr) coinbase_tx = Transaction.from_pbdata( genesis_block.transactions[0]) if not isinstance(coinbase_tx, CoinBase): return False addresses_state[coinbase_tx.addr_to] = AddressState.get_default( coinbase_tx.addr_to) if not coinbase_tx.validate_extended(genesis_block.block_number): return False coinbase_tx.apply_state_changes(addresses_state) for tx_idx in range(1, len(genesis_block.transactions)): tx = Transaction.from_pbdata( genesis_block.transactions[tx_idx]) tx.apply_state_changes(addresses_state) self._state.put_addresses_state(addresses_state) self._state.update_tx_metadata(genesis_block, None) self._state.update_mainchain_height(0, None) else: self._last_block = self.get_block_by_number(height) self.current_difficulty = self._state.get_block_metadata( self._last_block.headerhash).block_difficulty fork_state = self._state.get_fork_state() if fork_state: block = self._state.get_block(fork_state.initiator_headerhash) self._fork_recovery(block, fork_state)
def test_get_block_by_number(self): with set_qrl_dir('no_data'): with State() as state: bm = qrl_pb2.BlockNumberMapping() state.put_block_number_mapping(0, bm, None) self.assertIsNone(state.get_block_by_number(4))
def gen_blocks(block_count, state, miner_address): blocks = [] block = None with mock.patch('qrl.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 = qrl_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 _update_block_number_mapping(self, block, batch): block_number_mapping = qrl_pb2.BlockNumberMapping( headerhash=block.headerhash, prev_headerhash=block.prev_headerhash) self._state.put_block_number_mapping(block.block_number, block_number_mapping, batch)
def test_getLatestData(self): with set_qrl_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, qrl_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 qrlnode = QRLNode(mining_address=b'') qrlnode.set_chain_manager(chain_manager) qrlnode.get_block_from_index = MagicMock(return_value=None) qrlnode._p2pfactory = p2p_factory qrlnode._pow = p2p_factory.pow service = PublicAPIService(qrlnode) context = Mock(spec=ServicerContext) request = qrl_pb2.GetLatestDataReq(filter=qrl_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_get_block_by_number(self): bm = qrl_pb2.BlockNumberMapping() self.state.put_block_number_mapping(0, bm, None) self.assertIsNone(self.state.get_block_by_number(4))
def test_get_block_number_mapping(self): self.assertIsNone(self.state.get_block_number_mapping(0)) bm = qrl_pb2.BlockNumberMapping() self.state.put_block_number_mapping(0, bm, None) read_bm = self.state.get_block_number_mapping(0) self.assertEqual(bm.SerializeToString(), read_bm.SerializeToString())
def test_getObject(self): SOME_ODD_HASH = sha256(b'this should not be found') 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) # First try an empty request context = Mock(spec=ServicerContext) request = qrl_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 = qrl_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 = qrl_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 = qrl_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, qrl_pb2.BlockNumberMapping(headerhash=block.headerhash), None) context = Mock(spec=ServicerContext) request = qrl_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)