def _validate_custom(self): if self.fee <= 0: raise ValueError('TransferTokenTransaction [%s] Invalid Fee = %d', bin2hstr(self.txhash), self.fee) if (len(self.addrs_to) > config.dev.transaction_multi_output_limit or len(self.amounts) > config.dev.transaction_multi_output_limit): logger.warning('[TransferTokenTransaction] Number of addresses or amounts exceeds max limit') logger.warning('Number of addresses %s', len(self.addrs_to)) logger.warning('Number of amounts %s', len(self.amounts)) return False if len(self.addrs_to) != len(self.amounts): logger.warning('[TransferTokenTransaction] Mismatch number of addresses to & amounts') logger.warning('>> Length of addresses_to %s', len(self.addrs_to)) logger.warning('>> Length of amounts %s', len(self.amounts)) return False if not AddressState.address_is_valid(self.addr_from): logger.warning('[TransferTokenTransaction] Invalid address addr_from: %s', self.addr_from) return False for addr_to in self.addrs_to: if not AddressState.address_is_valid(addr_to): logger.warning('[TransferTokenTransaction] Invalid address addr_to: %s', addr_to) return False return True
def validate_extended(self, addr_from_state, addr_from_pk_state): if not self.validate_slave(addr_from_state, addr_from_pk_state): return False tx_balance = addr_from_state.balance if not AddressState.address_is_valid(self.addr_from): logger.warning('Invalid address addr_from: %s', self.addr_from) return False if not AddressState.address_is_valid(self.owner): logger.warning('Invalid address owner_addr: %s', self.owner) return False for address_balance in self.initial_balances: if not AddressState.address_is_valid(address_balance.address): logger.warning('Invalid address address in initial_balances: %s', address_balance.address) return False if tx_balance < self.fee: logger.info('TokenTxn State validation failed for %s because: Insufficient funds', self.txhash) logger.info('balance: %s, Fee: %s', tx_balance, self.fee) return False if addr_from_pk_state.ots_key_reuse(self.ots_key): logger.info('TokenTxn State validation failed for %s because: OTS Public key re-use detected', self.txhash) return False return True
def validate_extended(self, addr_from_state, addr_from_pk_state, transaction_pool): if not self.validate_slave(addr_from_state, addr_from_pk_state): return False tx_balance = addr_from_state.balance if self.fee < 0: logger.info('State validation failed for %s because: Negative send', self.txhash) return False if not AddressState.address_is_valid(self.addr_from): logger.warning('Invalid address addr_from: %s', self.addr_from) return False if not AddressState.address_is_valid(self.owner): logger.warning('Invalid address owner_addr: %s', self.owner) return False for address_balance in self.initial_balances: if not AddressState.address_is_valid(address_balance.address): logger.warning('Invalid address address in initial_balances: %s', address_balance.address) return False if tx_balance < self.fee: logger.info('TokenTxn State validation failed for %s because: Insufficient funds', self.txhash) logger.info('balance: %s, Fee: %s', tx_balance, self.fee) return False if self.ots_key_reuse(addr_from_pk_state, self.ots_key): logger.info('TokenTxn State validation failed for %s because: OTS Public key re-use detected', self.txhash) return False return True
def test_put_multi_sig_addresses_state(self): alice_xmss = get_alice_xmss() bob_xmss = get_bob_xmss() random_xmss = get_random_xmss() signatories = [alice_xmss.address, bob_xmss.address] weights = [20, 20] threshold = 21 multi_sig_tx = MultiSigCreate.create(signatories, weights, threshold, 0, random_xmss.pk) multi_sig_tx.sign(random_xmss) multi_sig_address_state = MultiSigAddressState.get_default( multi_sig_tx.txhash, signatories, weights, threshold) multi_sig_addresses_state = { multi_sig_address_state.address: multi_sig_address_state } AddressState.put_addresses_state(self.state, multi_sig_addresses_state) multi_sig_address_state2 = MultiSigAddressState.get_multi_sig_address_state_by_address( self.state._db, MultiSigAddressState.generate_multi_sig_address( multi_sig_tx.txhash)) self.assertEqual(multi_sig_address_state.pbdata, multi_sig_address_state2.pbdata)
def test_getHeight(self): with set_qrl_dir('no_data'): db_state = State() alice_xmss = get_alice_xmss() optimized_address_state = OptimizedAddressState.create(address=alice_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) addresses_state = {optimized_address_state.address: optimized_address_state} AddressState.put_addresses_state(db_state, addresses_state) p2p_factory = Mock(spec=P2PFactory) chain_manager = ChainManager(db_state) chain_manager._last_block = Mock() chain_manager._last_block.block_number = 100 qrlnode = QRLNode(mining_address=b'') qrlnode.set_chain_manager(chain_manager) qrlnode._p2pfactory = p2p_factory qrlnode._peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(qrlnode) context = Mock(spec=ServicerContext) request = qrl_pb2.GetHeightReq() response = service.GetHeight(request=request, context=context) self.assertEqual(response.height, 100)
def test_getTotalBalance(self): db_state = Mock(spec=State) xmss1 = get_alice_xmss() xmss2 = get_alice_xmss(4) xmss3 = get_bob_xmss(4) address_state1 = AddressState.create(address=xmss1.address, nonce=25, balance=1000, ots_bitfield=[b'\x00'] * config.dev.ots_bitfield_size, tokens=dict(), slave_pks_access_type=dict(), ots_counter=0) address_state2 = AddressState.create(address=xmss2.address, nonce=25, balance=2000, ots_bitfield=[b'\x00'] * config.dev.ots_bitfield_size, tokens=dict(), slave_pks_access_type=dict(), ots_counter=0) address_state3 = AddressState.create(address=xmss3.address, nonce=25, balance=3000, ots_bitfield=[b'\x00'] * config.dev.ots_bitfield_size, tokens=dict(), slave_pks_access_type=dict(), ots_counter=0) m = MockFunction() m.put(xmss1.address, address_state1) m.put(xmss2.address, address_state2) m.put(xmss3.address, address_state3) db_state.get_address_state = m.get p2p_factory = Mock(spec=P2PFactory) chain_manager = ChainManager(db_state) qrlnode = QRLNode(mining_address=b'') qrlnode.set_chain_manager(chain_manager) qrlnode._p2pfactory = p2p_factory qrlnode._peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(qrlnode) context = Mock(spec=ServicerContext) request = qrl_pb2.GetAddressStateReq() service.GetAddressState(request=request, context=context) context.set_code.assert_called() context.set_details.assert_called() context = Mock(spec=ServicerContext) request = qrl_pb2.GetTotalBalanceReq() request.addresses.extend([xmss1.address, xmss2.address, xmss3.address]) response = service.GetTotalBalance(request=request, context=context) context.set_code.assert_not_called() self.assertEqual(6000, response.balance)
def _validate_custom(self): if self.fee <= 0: raise ValueError('TransferTokenTransaction [%s] Invalid Fee = %d', bin2hstr(self.txhash), self.fee) if not (AddressState.address_is_valid(self.addr_from) and AddressState.address_is_valid(self.txto)): logger.warning('Invalid address addr_from: %s addr_to: %s', self.addr_from, self.txto) return False return True
def get_address_state(self, address: bytes) -> AddressState: try: data = self._db.get_raw(address) pbdata = qrl_pb2.AddressState() pbdata.ParseFromString(bytes(data)) address_state = AddressState(pbdata) return address_state except KeyError: return AddressState.get_default(address)
def validate_extended(self): if self.master_addr != config.dev.coinbase_address: return False if not (AddressState.address_is_valid(self.master_addr) and AddressState.address_is_valid(self.addr_to)): logger.warning('Invalid address addr_from: %s addr_to: %s', self.master_addr, self.addr_to) return False return self._validate_custom()
def _validate_custom(self): if self.amount <= 0: raise ValueError('[%s] Invalid amount = %d', bin2hstr(self.txhash), self.amount) if not (AddressState.address_is_valid(self.addr_from) and AddressState.address_is_valid(self.txto)): logger.warning('Invalid address addr_from: %s addr_to: %s', self.addr_from, self.txto) return False return True
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_state(self, header_hash: bytes, addresses_set: set): tmp_header_hash = header_hash parent_headerhash = None addresses_state = dict() for address in addresses_set: addresses_state[address] = None while True: if self.state_objects.contains(header_hash): parent_headerhash = header_hash self.set_addresses_state(addresses_state, header_hash) break block = self.get_block(header_hash) if not block: logger.warning('[get_state] No Block Found %s', header_hash) break if block.block_number == 0: break header_hash = block.prev_headerhash for genesis_balance in GenesisBlock().genesis_balance: bytes_addr = genesis_balance.address if not addresses_state[bytes_addr]: addresses_state[bytes_addr] = AddressState.get_default( bytes_addr) addresses_state[ bytes_addr]._data.balance = genesis_balance.balance for address in addresses_state: if not addresses_state[address]: addresses_state[address] = AddressState.get_default(address) header_hash = tmp_header_hash hash_path = [] while True: if parent_headerhash == header_hash: break block = self.get_block(header_hash) if not block: break hash_path.append(header_hash) header_hash = block.prev_headerhash if block.block_number == 0: break for header_hash in hash_path[-1::-1]: block = self.get_block(header_hash) for tx_pbdata in block.transactions: tx = Transaction.from_pbdata(tx_pbdata) tx.apply_on_state(addresses_state) return addresses_state
def validate_extended(self, addr_from_state, addr_from_pk_state, transaction_pool): if not self.validate_slave(addr_from_state, addr_from_pk_state): return False if self.addr_from != config.dev.coinbase_address: return False if not (AddressState.address_is_valid(self.addr_from) and AddressState.address_is_valid(self.txto)): logger.warning('Invalid address addr_from: %s addr_to: %s', self.addr_from, self.txto) return False return self.validate()
def get_state(self, header_hash, addresses_set): tmp_header_hash = header_hash parent_headerhash = None addresses_state = dict() for address in addresses_set: addresses_state[address] = None while True: if self.state_objects.contains(header_hash): parent_headerhash = header_hash self.set_addresses_state(addresses_state, header_hash) break block = self.get_block(header_hash) if not block: logger.warning('[get_state] No Block Found %s', header_hash) break if block.block_number == 0: break header_hash = block.prev_headerhash for genesis_balance in GenesisBlock().genesis_balance: bytes_addr = genesis_balance.address.encode() if not addresses_state[bytes_addr]: addresses_state[bytes_addr] = AddressState.get_default(bytes_addr) addresses_state[bytes_addr]._data.balance = genesis_balance.balance for address in addresses_state: if not addresses_state[address]: addresses_state[address] = AddressState.get_default(address) header_hash = tmp_header_hash hash_path = [] while True: if parent_headerhash == header_hash: break block = self.get_block(header_hash) if not block: break hash_path.append(header_hash) header_hash = block.prev_headerhash if block.block_number == 0: break for header_hash in hash_path[-1::-1]: block = self.get_block(header_hash) for tx_pbdata in block.transactions: tx = Transaction.from_pbdata(tx_pbdata) tx.apply_on_state(addresses_state) return addresses_state
def test_put_addresses_state(self): alice_xmss = get_alice_xmss() alice_state = AddressState.get_default(alice_xmss.address) addresses_state = { alice_state.address: alice_state, b'test1': AddressState.get_default(b'test1') } self.state.put_addresses_state(addresses_state, None) alice_state2 = self.state.get_address_state(alice_xmss.address) self.assertEqual(alice_state.serialize(), alice_state2.serialize()) test_state = self.state.get_address_state(b'test1') self.assertEqual(test_state.serialize(), AddressState.get_default(b'test1').serialize())
def test_put_addresses_state(self): with set_qrl_dir('no_data'): with State() as state: alice_xmss = get_alice_xmss() alice_state = AddressState.get_default(alice_xmss.address) addresses_state = { alice_state.address: alice_state, b'test1': AddressState.get_default(b'test1') } state.put_addresses_state(addresses_state, None) alice_state2 = state.get_address_state(alice_xmss.address) self.assertEqual(alice_state.serialize(), alice_state2.serialize()) test_state = state.get_address_state(b'test1') self.assertEqual(test_state.serialize(), AddressState.get_default(b'test1').serialize())
def test_sync_state_change_synced(self): chain_manager = Mock() chain_manager.height = 0 chain_manager.get_block = MagicMock(return_value=GenesisBlock()) chain_manager.last_block = GenesisBlock() chain_manager.tx_pool = Mock() chain_manager.tx_pool.transaction_pool = [] chain_manager.tx_pool.transactions = chain_manager.tx_pool.transaction_pool get_block_metadata_response = Mock() get_block_metadata_response.block_difficulty = StringToUInt256('2') chain_manager.state.get_block_metadata = MagicMock( return_value=get_block_metadata_response) alice_xmss = get_alice_xmss() chain_manager.state.get_address = MagicMock( return_value=AddressState.get_default(alice_xmss.address)) chain_manager.state.get_measurement = MagicMock(return_value=60) p2p_factory = Mock() sync_state = Mock() time_provider = Mock() # Setting mining enabled False, when update_note_state set to synced, # starts miner which is not exited properly by unit test with set_mining_enabled(False): node = POW(chain_manager=chain_manager, p2p_factory=p2p_factory, sync_state=sync_state, time_provider=time_provider, mining_credit_wallet=get_random_xmss().address, mining_thread_count=0) self.assertIsNotNone(node) node.update_node_state(ESyncState.synced)
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, _ = self._difficulty_tracker.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.encode() 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 get_block_to_mine(self, wallet_address, tx_pool, last_block, last_block_difficulty) -> list: try: mining_address = bytes(hstr2bin(wallet_address[1:].decode())) if not AddressState.address_is_valid(mining_address): raise ValueError( "[get_block_to_mine] Invalid Wallet Address %s", wallet_address) except Exception as e: raise ValueError("Error while decoding wallet address %s", e) if self._mining_block: if last_block.headerhash == self._mining_block.prev_headerhash: if self._mining_block.transactions[ 0].coinbase.addr_to == mining_address: return [ bin2hstr(self._mining_block.mining_blob), int(bin2hstr(self._current_difficulty), 16) ] else: self._mining_block.update_mining_address( mining_address) # Updates only Miner Address self.prepare_next_unmined_block_template(mining_address, tx_pool, last_block, last_block_difficulty) return [ bin2hstr(self._mining_block.mining_blob), int(bin2hstr(self._current_difficulty), 16) ]
def test_relaySlaveTxn(self): with set_qrl_dir("wallet_ver1"): walletd = WalletD() service = WalletAPIService(walletd) resp = service.AddNewAddress(qrlwallet_pb2.AddNewAddressReq(), context=None) qaddress = resp.address addr_state = AddressState.get_default(walletd.qaddress_to_address(qaddress)) walletd._public_stub.GetAddressState = Mock( return_value=qrl_pb2.GetAddressStateResp(state=addr_state.pbdata)) walletd._public_stub.IsSlave = Mock( return_value=qrl_pb2.IsSlaveResp(result=True)) walletd._public_stub.GetOTS = Mock( return_value=qrl_pb2.GetOTSResp(next_unused_ots_index=0, unused_ots_index_found=True)) alice_xmss = get_alice_xmss(4) slave_pks = [alice_xmss.pk] access_types = [0] walletd._public_stub.PushTransaction = Mock( return_value=qrl_pb2.PushTransactionResp(error_code=qrl_pb2.PushTransactionResp.SUBMITTED)) resp = service.RelaySlaveTxn(qrlwallet_pb2.RelaySlaveTxnReq(slave_pks=slave_pks, access_types=access_types, fee=100000000, master_address=None, signer_address=qaddress, ots_index=0), context=None) self.assertEqual(resp.code, 0) self.assertIsNotNone(resp.tx)
def validate_extended(self, addr_from_state, addr_from_pk_state): if not self.validate_slave(addr_from_state, addr_from_pk_state): return False if self.addr_from != config.dev.coinbase_address: return False if not (AddressState.address_is_valid(self.addr_from) and AddressState.address_is_valid(self.addr_to)): logger.warning('Invalid address addr_from: %s addr_to: %s', self.addr_from, self.addr_to) return False if addr_from_pk_state.ots_key_reuse(self.ots_key): logger.warning('CoinBase Txn: OTS Public key re-use detected %s', self.txhash) return False return True
def test_relayMessageTxn(self): with set_qrl_dir("wallet_ver1"): walletd = WalletD() walletd._public_stub.PushTransaction = Mock( return_value=qrl_pb2.PushTransactionResp(error_code=qrl_pb2.PushTransactionResp.SUBMITTED)) service = WalletAPIService(walletd) resp = service.AddNewAddress(qrlwallet_pb2.AddNewAddressReq(), context=None) qaddress = resp.address addr_state = AddressState.get_default(walletd.qaddress_to_address(qaddress)) walletd._public_stub.GetAddressState = Mock( return_value=qrl_pb2.GetAddressStateResp(state=addr_state.pbdata)) walletd._public_stub.GetOTS = Mock( return_value=qrl_pb2.GetOTSResp(next_unused_ots_index=0, unused_ots_index_found=True)) resp = service.RelayMessageTxn(qrlwallet_pb2.RelayMessageTxnReq(message=b'Hello QRL!', fee=100000000, master_address=None, signer_address=qaddress, ots_index=0), context=None) self.assertEqual(0, resp.code) self.assertIsNotNone(resp.tx)
def test_sync_state_change_synced(self): chain_manager = Mock() chain_manager.height = 0 chain_manager.get_block = MagicMock(return_value=GenesisBlock()) chain_manager.last_block = GenesisBlock() chain_manager.tx_pool = Mock() chain_manager.tx_pool.transaction_pool = [] get_block_metadata_response = Mock() get_block_metadata_response.block_difficulty = StringToUInt256('2') chain_manager.state.get_block_metadata = MagicMock(return_value=get_block_metadata_response) alice_xmss = get_alice_xmss() chain_manager.state.get_address = MagicMock(return_value=AddressState.get_default(alice_xmss.address)) chain_manager.state.get_measurement = MagicMock(return_value=60) p2p_factory = Mock() sync_state = Mock() time_provider = Mock() node = POW(chain_manager=chain_manager, p2p_factory=p2p_factory, sync_state=sync_state, time_provider=time_provider, slaves=get_random_master(), mining_thread_count=0) self.assertIsNotNone(node) node.update_node_state(ESyncState.synced)
def get_address_state(self, address: bytes) -> qrl_pb2.AddressState: if not AddressState.address_is_valid(address): raise ValueError("Invalid Address") address_state = self.db_state.get_address(address) return address_state
def test_relayTransferTokenTxn(self): with set_qrl_dir("wallet_ver1"): walletd = WalletD() service = WalletAPIService(walletd) resp = service.AddNewAddress(qrlwallet_pb2.AddNewAddressReq(), context=None) qaddress = resp.address addr_state = AddressState.get_default(walletd.qaddress_to_address(qaddress)) walletd._public_stub.GetAddressState = Mock( return_value=qrl_pb2.GetAddressStateResp(state=addr_state.pbdata)) alice_xmss = get_alice_xmss(4) bob_xmss = get_bob_xmss(4) qaddresses_to = [alice_xmss.qaddress, bob_xmss.qaddress] amounts = [1000000000, 1000000000] walletd._public_stub.PushTransaction = Mock( return_value=qrl_pb2.PushTransactionResp(error_code=qrl_pb2.PushTransactionResp.SUBMITTED)) resp = service.RelayTransferTokenTxn(qrlwallet_pb2.RelayTransferTokenTxnReq(addresses_to=qaddresses_to, amounts=amounts, token_txhash='', fee=100000000, master_address=None, signer_address=qaddress, ots_index=0), context=None) self.assertEqual(resp.code, 0) self.assertIsNotNone(resp.tx)
def test_relaySlaveTxnBySlave(self): with set_qrl_dir("wallet_ver1"): walletd = WalletD() walletd._public_stub.PushTransaction = Mock( return_value=qrl_pb2.PushTransactionResp(error_code=qrl_pb2.PushTransactionResp.SUBMITTED)) service = WalletAPIService(walletd) resp = service.AddNewAddressWithSlaves(qrlwallet_pb2.AddNewAddressWithSlavesReq(), context=None) qaddress = resp.address addr_state = AddressState.get_default(walletd.qaddress_to_address(qaddress)) slaves = walletd.get_slave_list(qaddress) addr_state.add_slave_pks_access_type(bytes(hstr2bin(slaves[0][0].pk)), 0) walletd._public_stub.GetAddressState = Mock( return_value=qrl_pb2.GetAddressStateResp(state=addr_state.pbdata)) alice_xmss = get_alice_xmss(4) slave_pks = [alice_xmss.pk] access_types = [0] resp = service.RelaySlaveTxnBySlave( qrlwallet_pb2.RelaySlaveTxnBySlaveReq(slave_pks=slave_pks, access_types=access_types, fee=100000000, master_address=qaddress), context=None) self.assertEqual(resp.code, 0) self.assertIsNotNone(resp.tx)
def test_sync_state_change_synced(self): chain_manager = Mock() chain_manager.height = 0 chain_manager.get_block = MagicMock(return_value=GenesisBlock()) chain_manager.last_block = GenesisBlock() chain_manager.tx_pool = Mock() chain_manager.tx_pool.transaction_pool = [] get_block_metadata_response = Mock() get_block_metadata_response.block_difficulty = StringToUInt256('2') chain_manager.state.get_block_metadata = MagicMock(return_value=get_block_metadata_response) alice_xmss = get_alice_xmss() chain_manager.state.get_address = MagicMock(return_value=AddressState.get_default(alice_xmss.get_address())) chain_manager.state.get_measurement = MagicMock(return_value=60) p2p_factory = Mock() sync_state = Mock() time_provider = Mock() node = POW(chain_manager=chain_manager, p2p_factory=p2p_factory, sync_state=sync_state, time_provider=time_provider, slaves=get_random_master()) self.assertIsNotNone(node) node.update_node_state(ESyncState.synced)
def get_address_state(self, address: bytes) -> qrl_pb2.AddressState: if not AddressState.address_is_valid(address): raise ValueError("Invalid Address") address_state = self.db_state.get_address_state(address) return address_state
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_unused_ots_index2(self): old_value = config.dev.max_ots_tracking_index config.dev.max_ots_tracking_index = 128 try: random_xmss = get_random_xmss(xmss_height=8) addr_state = AddressState.get_default(random_xmss.address) self.assertEqual(addr_state.get_unused_ots_index(), 0) addr_state.set_ots_key(0) self.assertEqual(addr_state.get_unused_ots_index(), 1) addr_state.set_ots_key(2) self.assertEqual(addr_state.get_unused_ots_index(), 1) addr_state.set_ots_key(1) self.assertEqual(addr_state.get_unused_ots_index(), 3) for i in range( 3, min(2**addr_state.height, config.dev.max_ots_tracking_index)): addr_state.set_ots_key(i) self.assertEqual(addr_state.get_unused_ots_index(), i + 1) self.assertEqual(addr_state.get_unused_ots_index(), config.dev.max_ots_tracking_index) for i in range(config.dev.max_ots_tracking_index, 2**addr_state.height): addr_state.set_ots_key(i) self.assertIsNone(addr_state.get_unused_ots_index()) finally: config.dev.max_ots_tracking_index = old_value
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_relayTokenTxnBySlave(self): with set_qrl_dir("wallet_ver1"): walletd = WalletD() walletd._public_stub.PushTransaction = Mock( return_value=qrl_pb2.PushTransactionResp(error_code=qrl_pb2.PushTransactionResp.SUBMITTED)) service = WalletAPIService(walletd) resp = service.AddNewAddressWithSlaves(qrlwallet_pb2.AddNewAddressWithSlavesReq(), context=None) qaddress = resp.address addr_state = AddressState.get_default(walletd.qaddress_to_address(qaddress)) slaves = walletd.get_slave_list(qaddress) addr_state.add_slave_pks_access_type(bytes(hstr2bin(slaves[0][0].pk)), 0) walletd._public_stub.GetAddressState = Mock( return_value=qrl_pb2.GetAddressStateResp(state=addr_state.pbdata)) alice_xmss = get_alice_xmss(4) bob_xmss = get_bob_xmss(4) qaddresses = [alice_xmss.qaddress, bob_xmss.qaddress] amounts = [1000000000, 1000000000] resp = service.RelayTokenTxnBySlave( qrlwallet_pb2.RelayTokenTxnBySlaveReq(symbol=b'QRL', name=b'Quantum Resistant Ledger', owner=alice_xmss.qaddress, decimals=5, addresses=qaddresses, amounts=amounts, fee=100000000, master_address=qaddress), context=None) self.assertEqual(resp.code, 0) self.assertIsNotNone(resp.tx)
def validate_extended(self, addr_from_state: AddressState, addr_from_pk_state: AddressState) -> bool: if not self.validate_slave(addr_from_state, addr_from_pk_state): return False tx_balance = addr_from_state.balance if self.fee < 0: logger.info( 'Slave: State validation failed for %s because: Negative send', bin2hstr(self.txhash)) return False if tx_balance < self.fee: logger.info( 'Slave: State validation failed for %s because: Insufficient funds', bin2hstr(self.txhash)) logger.info('balance: %s, amount: %s', tx_balance, self.fee) return False if addr_from_pk_state.ots_key_reuse(self.ots_key): logger.info( 'Slave: State validation failed for %s because: OTS Public key re-use detected', bin2hstr(self.txhash)) return False return True
def test_get_default_coinbase(self): # Make sure that Coinbase AddressState gets all the coins supply by default coinbase_addr_state = AddressState.get_default( config.dev.coinbase_address) self.assertEqual( coinbase_addr_state.balance, int(config.dev.max_coin_supply * config.dev.shor_per_quanta))
def test_getHeight(self): db_state = Mock(spec=State) alice_xmss = get_alice_xmss() address_state = AddressState.create(address=alice_xmss.address, nonce=25, balance=10, ots_bitfield=[b'\x00'] * config.dev.ots_bitfield_size, tokens=dict(), slave_pks_access_type=dict(), ots_counter=0) db_state.get_address_state = MagicMock(return_value=address_state) p2p_factory = Mock(spec=P2PFactory) chain_manager = ChainManager(db_state) chain_manager._last_block = Mock() chain_manager._last_block.block_number = 100 qrlnode = QRLNode(mining_address=b'') qrlnode.set_chain_manager(chain_manager) qrlnode._p2pfactory = p2p_factory qrlnode._peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(qrlnode) context = Mock(spec=ServicerContext) request = qrl_pb2.GetHeightReq() response = service.GetHeight(request=request, context=context) self.assertEqual(response.height, 100)
def test_getTransactionsByAddress(self): db_state = Mock(spec=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) # Find a transaction alice_xmss = get_alice_xmss() db_state.get_address_state = MagicMock( return_value=AddressState.get_default(alice_xmss.address)) db_state.address_used = MagicMock(return_value=False) context = Mock(spec=ServicerContext) request = qrl_pb2.GetTransactionsByAddressReq( address=alice_xmss.address) response = service.GetTransactionsByAddress(request=request, context=context) context.set_code.assert_not_called() self.assertEqual(len(response.mini_transactions), 0) self.assertEqual(response.balance, 0)
def validate_extended(self, addr_from_state: AddressState, addr_from_pk_state: AddressState): if not self.validate_slave(addr_from_state, addr_from_pk_state): return False tx_balance = addr_from_state.balance if self.fee < 0: logger.info( 'Lattice Txn: State validation failed %s : Negative fee %s', bin2hstr(self.txhash), self.fee) return False if tx_balance < self.fee: logger.info( 'Lattice Txn: State validation failed %s : Insufficient funds', bin2hstr(self.txhash)) logger.info('balance: %s, fee: %s', tx_balance, self.fee) return False if addr_from_pk_state.ots_key_reuse(self.ots_key): logger.info('Lattice Txn: OTS Public key re-use detected %s', bin2hstr(self.txhash)) return False return True
def validate_extended(self, addr_from_state: AddressState, addr_from_pk_state: AddressState): if not self.validate_slave(addr_from_state, addr_from_pk_state): return False tx_balance = addr_from_state.balance total_amount = self.total_amount if self.fee < 0 or total_amount < 0: logger.info( 'TransferTokenTransaction State validation failed for %s because: ', bin2hstr(self.txhash)) logger.info('Txn amount: %s, Fee: %s', total_amount, self.fee) return False if tx_balance < self.fee: logger.info( 'TransferTokenTransaction State validation failed for %s because: Insufficient funds', bin2hstr(self.txhash)) logger.info('balance: %s, Fee: %s', tx_balance, self.fee) return False if addr_from_pk_state.ots_key_reuse(self.ots_key): logger.info( 'TransferTokenTransaction State validation failed for %s because: OTS Public key re-use detected', bin2hstr(self.txhash)) return False return True
def _get_address_state(self, address: bytes) -> AddressState: try: data = self._db.get_raw(address) pbdata = qrl_pb2.AddressState() pbdata.ParseFromString(bytes(data)) address_state = AddressState(pbdata) return address_state except KeyError: return AddressState.get_default(address)
def GetObject(self, request: qrl_pb2.GetObjectReq, context) -> qrl_pb2.GetObjectResp: logger.debug("[PublicAPI] GetObject") answer = qrl_pb2.GetObjectResp() answer.found = False # FIXME: We need a unified way to access and validate data. query = bytes(request.query) # query will be as a string, if Q is detected convert, etc. if AddressState.address_is_valid(query): if self.qrlnode.get_address_is_used(query): address_state = self.qrlnode.get_address_state(query) if address_state is not None: answer.found = True answer.address_state.CopyFrom(address_state) return answer transaction, block_number = self.qrlnode.get_transaction(query) if transaction is not None: answer.found = True blockheader = None if block_number is not None: block = self.qrlnode.get_block_from_index(block_number) blockheader = block.blockheader.pbdata txextended = qrl_pb2.TransactionExtended(header=blockheader, tx=transaction.pbdata) answer.transaction.CopyFrom(txextended) return answer block = self.qrlnode.get_block_from_hash(query) if block is not None: answer.found = True answer.block.CopyFrom(block.pbdata) return answer # NOTE: This is temporary, indexes are accepted for blocks try: query_str = query.decode() query_index = int(query_str) block = self.qrlnode.get_block_from_index(query_index) if block is not None: answer.found = True answer.block.CopyFrom(block.pbdata) return answer except Exception: pass return answer
def get_address_is_used(self, address: bytes) -> bool: if not AddressState.address_is_valid(address): raise ValueError("Invalid Address") return self.db_state.address_used(address)