def token_list(ctx, owner): """ Fetch the list of tokens owned by an address. """ try: owner_address = parse_qaddress(owner) except Exception as e: click.echo("Error validating arguments: {}".format(e)) quit(1) try: stub = ctx.obj.get_stub_public_api() address_state_req = qrl_pb2.GetAddressStateReq(address=owner_address) address_state_resp = stub.GetAddressState(address_state_req, timeout=CONNECTION_TIMEOUT) for token_hash in address_state_resp.state.tokens: get_object_req = qrl_pb2.GetObjectReq( query=bytes(hstr2bin(token_hash))) get_object_resp = stub.GetObject(get_object_req, timeout=CONNECTION_TIMEOUT) click.echo('Hash: %s' % (token_hash, )) click.echo( 'Symbol: %s' % (get_object_resp.transaction.tx.token.symbol.decode(), )) click.echo('Name: %s' % (get_object_resp.transaction.tx.token.name.decode(), )) click.echo('Balance: %s' % (address_state_resp.state.tokens[token_hash], )) except Exception as e: print("Error {}".format(str(e)))
def query_txn(qrl_client, txn): #request = qrl_pb2.GetTransactionReq(tx_hash=bytes.fromhex(txn)) #response = qrl_client.GetTransaction(request) request = qrl_pb2.GetObjectReq(query=bytes.fromhex(txn)) response = qrl_client.GetObject(request) log_msg('', response) if response.found and response.transaction.tx.HasField('multi_sig_spend'): vote_req = qrl_pb2.GetVoteStatsReq( multi_sig_spend_tx_hash=response.transaction.tx.transaction_hash) vote_resp = qrl_client.GetVoteStats(vote_req) log_msg('', vote_resp)
def query_addr(qrl_client, addr): request = qrl_pb2.GetObjectReq(query=bytes.fromhex(addr[1:])) response = qrl_client.GetObject(request) log_msg('', response) if addr.startswith('Q1'): request = qrl_pb2.GetMultiSigAddressStateReq( address=bytes.fromhex(addr[1:])) response = qrl_client.GetMultiSigAddressState(request) log_msg('', response) request = qrl_pb2.GetMultiSigSpendTxsByAddressReq( address=bytes.fromhex(addr[1:]), item_per_page=8, page_number=1, filter_type=qrl_pb2.GetMultiSigSpendTxsByAddressReq.NONE) response = qrl_client.GetMultiSigSpendTxsByAddress(request) log_msg('', response) else: request = qrl_pb2.GetAddressStateReq(address=bytes.fromhex(addr[1:])) response = qrl_client.GetAddressState(request) log_msg('', response)
def audit_regular_addr(qrl_client, addr): """ Validate the provided regular address """ balance = 0 tx_count = 0 bad_tx_count = 0 request_addr = qrl_pb2.GetAddressStateReq(address=bytes.fromhex(addr[1:])) response_addr = qrl_client.GetAddressState(request_addr) if not response_addr.HasField('state'): logging.error('could not find address {}'.format(addr)) return balance, tx_count, bad_tx_count balance = response_addr.state.balance tx_count = len(response_addr.state.transaction_hashes) for txhash in response_addr.state.transaction_hashes: request_tx = qrl_pb2.GetObjectReq(query=bytes.fromhex(txhash.hex())) response_tx = qrl_client.GetObject(request_tx) if not response_tx.HasField('transaction'): bad_tx_count += 1 logging.error('txhash {} for addr {} does not exist'.format( txhash, addr)) continue tx = response_tx.transaction.tx if tx.HasField('transfer') or tx.HasField('multi_sig_spend'): tmptxhash = (tx.master_addr + to_bytes(tx.fee)) if tx.HasField('transfer'): tmptxhash += (tx.transfer.message_data + get_tx_hash(tx.transfer)) if tx.HasField('multi_sig_spend'): tmptxhash += ( tx.multi_sig_spend.multi_sig_address + to_bytes(tx.multi_sig_spend.expiry_block_number) + get_tx_hash(tx.multi_sig_spend)) data_hash = sha256(tmptxhash) signature = tx.signature public_key = tx.public_key if not XmssFast.verify(data_hash, signature, public_key): logging.info( 'txhash {} for addr {} failed XmssFast verification'. format(txhash, addr)) return balance, tx_count, bad_tx_count
def test_getObject(self): SOME_ODD_HASH = sha256(b'this should not be found') SOME_ADDR1 = b'Q' + sha256(b'address1') SOME_ADDR2 = b'Q' + sha256(b'address2') db_state = Mock(spec=State) p2p_factory = Mock(spec=P2PFactory) buffered_chain = Mock(spec=BufferedChain) buffered_chain.tx_pool = Mock() buffered_chain.tx_pool.transaction_pool = [] qrlnode = QRLNode(db_state) qrlnode.set_p2pfactory(p2p_factory) qrlnode.set_chain(buffered_chain) qrlnode._peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(qrlnode) 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) # Find an address db_state.get_address = MagicMock(return_value=AddressState.create( address=SOME_ADDR1, nonce=25, balance=10, pubhashes=[sha256(b'a'), sha256(b'b')], tokens=dict())) db_state.get_address_tx_hashes = MagicMock( return_value=[sha256(b'0'), sha256(b'1')]) 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) context = Mock(spec=ServicerContext) request = qrl_pb2.GetObjectReq() request.query = SOME_ADDR1 response = service.GetObject(request=request, context=context) context.set_code.assert_not_called() self.assertTrue(response.found) self.assertIsNotNone(response.address_state) self.assertEqual(SOME_ADDR1, response.address_state.address) self.assertEqual(25, response.address_state.nonce) self.assertEqual(10, response.address_state.balance) self.assertEqual([sha256(b'a'), sha256(b'b')], response.address_state.pubhashes) self.assertEqual([sha256(b'0'), sha256(b'1')], response.address_state.transaction_hashes) # Find a transaction db_state.address_used = MagicMock(return_value=False) tx1 = TransferTransaction.create(addr_from=SOME_ADDR1, addr_to=SOME_ADDR2, amount=125, fee=19, xmss_pk=sha256(b'pk'), xmss_ots_index=13) buffered_chain.tx_pool.transaction_pool = [tx1] 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(qrl_pb2.Transaction.TRANSFER, response.transaction.type) self.assertEqual(SOME_ADDR1, response.transaction.addr_from) self.assertEqual(sha256(b'pk'), response.transaction.public_key) self.assertEqual(tx1.txhash, response.transaction.transaction_hash) self.assertEqual(13, response.transaction.ots_key) self.assertEqual(b'', response.transaction.signature) self.assertEqual(SOME_ADDR2, response.transaction.transfer.addr_to) self.assertEqual(125, response.transaction.transfer.amount) self.assertEqual(19, response.transaction.transfer.fee) # Find a block buffered_chain.get_block = MagicMock(return_value=Block.create( staking_address=qrladdress('staking_addr'), block_number=1, reveal_hash=sha256(b'reveal'), prevblock_headerhash=sha256(b'reveal'), transactions=[], duplicate_transactions=OrderedDict(), vote=VoteMetadata(), signing_xmss=get_alice_xmss(), nonce=1)) 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) self.assertEqual(1, response.block.header.block_number)
def test_getObject(self): SOME_ODD_HASH = sha256(b'this should not be found') 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) # 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 = AddressState.create(address=bob_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) addr1_state.transaction_hashes.append(sha256(b'0')) addr1_state.transaction_hashes.append(sha256(b'1')) db_state.get_address_state = MagicMock(return_value=addr1_state) 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) self.assertEqual([sha256(b'0'), sha256(b'1')], response.address_state.transaction_hashes) # 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], 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 db_state.get_block_by_number = MagicMock( return_value=Block.create(block_number=1, prev_headerhash=sha256(b'reveal'), prev_timestamp=10, transactions=[], miner_address=alice_xmss.address)) 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)
def audit_chain(qrl_client, dbg_addr): """ Request and store each blockself. Iterate thru each block, replaying each transaction to recreate address balances. Query each address comparing the reported vs calculated balances. """ total_blocks = 0 block_store = dict() balances_store = dict() transaction_store = dict() if dbg_addr is not None: dbg_addr = bytes.fromhex(dbg_addr[1:]).hex() # load the blocks while True: request = qrl_pb2.GetObjectReq(query=str(total_blocks).encode( encoding='ascii')) response = qrl_client.GetObject(request) if not response.HasField('block_extended'): # we reached the end of the chain break # get and store block block = response.block_extended block_store[total_blocks] = block total_blocks += 1 logging.info('loaded up to block number {}'.format(total_blocks)) # re-create balances by replaying each block for block_num in range(0, total_blocks): block = block_store[block_num] # store transactions in each block for txn in range(0, len(block.extended_transactions)): txhash = block.extended_transactions[txn].tx.transaction_hash.hex() transaction_store[txhash] = block.extended_transactions[txn] # handle coinbase address = block.extended_transactions[0].tx.coinbase.addr_to.hex() amount = block.extended_transactions[0].tx.coinbase.amount if not address in balances_store: balances_store[address] = 0 balances_store[address] += amount if dbg_addr in [address]: print('coinbase amnt {} -> Q{} via blk {}'.format( amount, address, block_num)) # handle all other transactions outside of coinbase for txn in range(1, len(block.extended_transactions)): tx = block.extended_transactions[txn].tx addr_from = block.extended_transactions[txn].addr_from.hex() tx_hash = tx.transaction_hash.hex() if tx.fee > 0: balances_store[addr_from] -= tx.fee if dbg_addr in [addr_from]: print('fee amnt {} Q{} -> Q{} via tx {}'.format( tx.fee, addr_from, address, tx_hash)) if tx.HasField('transfer'): update_balances(balances_store, addr_from, tx.transfer, dbg_addr, tx_hash) if tx.HasField('multi_sig_spend'): if has_multi_sig_spend_executed(qrl_client, tx.transaction_hash): addr_from = tx.multi_sig_spend.multi_sig_address.hex() update_balances(balances_store, addr_from, tx.multi_sig_spend, dbg_addr, tx_hash) logging.info('loaded {} addresses and {} transactions'.format( len(balances_store), len(transaction_store))) # audit each block, checking the block header and building a list for block_num in range(0, total_blocks): block = block_store[block_num] if block_num > 0: blockPrev = block_store[block_num - 1] if block.header.hash_header_prev != blockPrev.header.hash_header: logging.error('prev block error at {}'.format(block_num)) if block.header.timestamp_seconds < blockPrev.header.timestamp_seconds: logging.error('timestamp error at {}'.format(block_num)) if block.header.block_number != block_num: logging.error('block num error at {}'.format(block_num)) hashedtransactions = [ block.extended_transactions[0].tx.transaction_hash ] reward = block.header.reward_block for txn in range(1, len(block.extended_transactions)): reward += block.extended_transactions[txn].tx.fee hashedtransactions.append( block.extended_transactions[txn].tx.transaction_hash) if block.extended_transactions[0].tx.coinbase.amount != reward: logging.error('coinbase error at {}'.format(block_num)) if block.header.reward_fee + block.header.reward_block != reward: logging.error('reward error at {}'.format(block_num)) merkle_root = merkle_tx_hash(hashedtransactions) if block.header.merkle_root != merkle_root: logging.error('merkle_root error at {}'.format(block_num)) for addr in balances_store: try: balance = audit_address(qrl_client, 'Q' + addr, False) if balance != balances_store[addr]: logging.error('balance for {} does not match'.format('Q' + addr)) logging.error('node-reported balance: {}'.format(balance)) logging.error('calculated balance: {}'.format( balances_store[addr])) except: logging.error('could not query addr {}'.format('Q' + addr)) raise
def query_block(qrl_client, block): #request = qrl_pb2.GetBlockByNumberReq(block_number=block) #response = qrl_client.GetBlockByNumber(request) request = qrl_pb2.GetObjectReq(query=str(block).encode(encoding='ascii')) response = qrl_client.GetObject(request) log_msg('', response)
args = parser.parse_args() addressA = '{}:{}'.format(args.hostA, args.portA) channelA = grpc.insecure_channel(addressA) qrlClientA = qrl_pb2_grpc.PublicAPIStub(channelA) logging.info('Connected to {}'.format(addressA)) addressB = '{}:{}'.format(args.hostB, args.portB) channelB = grpc.insecure_channel(addressB) qrlClientB = qrl_pb2_grpc.PublicAPIStub(channelB) logging.info('Connected to {}'.format(addressB)) # load the blocks for addressA & addressB start = time.monotonic() for blockNum in range(int(args.startBlock), int(args.endBlock) + 1): request = qrl_pb2.GetObjectReq(query=str(blockNum).encode( encoding='ascii')) responseA = qrlClientA.GetObject(request) responseB = qrlClientB.GetObject(request) if not responseA.HasField('block_extended') or not responseB.HasField( 'block_extended'): # we reached the end of the chain on either A or B break # update status if blockNum > 0 and blockNum % 10000 == 0: logging.info('loaded up to {}'.format(blockNum)) # compare the blocks blockA = responseA.block_extended blockB = responseB.block_extended
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)