def get_or_query_transaction_receipt( self, tx_hash: str, ) -> Optional['EthereumTxReceipt']: """ Gets the receipt from the DB if it exist. If not queries the chain for it, saves it in the DB and then returns it. Also if the actual transaction does not exist in the DB it queries it and saves it there. May raise: - DeserializationError - RemoteError """ tx_hash_b = hexstring_to_bytes(tx_hash) dbethtx = DBEthTx(self.database) # If the transaction is not in the DB then query it and add it result, _ = dbethtx.get_ethereum_transactions(ETHTransactionsFilterQuery.make(tx_hash=tx_hash_b)) # noqa: E501 if len(result) == 0: transaction = self.ethereum.get_transaction_by_hash(tx_hash) if transaction is None: return None # hash does not correspond to a transaction dbethtx.add_ethereum_transactions([transaction]) tx_receipt = dbethtx.get_receipt(tx_hash_b) if tx_receipt is not None: return tx_receipt # not in the DB, so we need to query the chain for it tx_receipt_data = self.ethereum.get_transaction_receipt(tx_hash=tx_hash) dbethtx.add_receipt_data(tx_receipt_data) tx_receipt = dbethtx.get_receipt(tx_hash_b) return tx_receipt
def get_or_query_transaction_receipt( self, tx_hash: EVMTxHash, ) -> 'EthereumTxReceipt': """ Gets the receipt from the DB if it exists. If not queries the chain for it, saves it in the DB and then returns it. Also if the actual transaction does not exist in the DB it queries it and saves it there. May raise: - DeserializationError - RemoteError if the transaction hash can't be found in any of the connected nodes """ dbethtx = DBEthTx(self.database) # If the transaction is not in the DB then query it and add it result = dbethtx.get_ethereum_transactions( filter_=ETHTransactionsFilterQuery.make(tx_hash=tx_hash), has_premium=True, # we don't need any limiting here ) if len(result) == 0: transaction = self.ethereum.get_transaction_by_hash(tx_hash) dbethtx.add_ethereum_transactions([transaction], relevant_address=None) self._get_internal_transactions_for_ranges( address=transaction.from_address, start_ts=transaction.timestamp, end_ts=transaction.timestamp, ) self._get_erc20_transfers_for_ranges( address=transaction.from_address, start_ts=transaction.timestamp, end_ts=transaction.timestamp, ) tx_receipt = dbethtx.get_receipt(tx_hash) if tx_receipt is not None: return tx_receipt # not in the DB, so we need to query the chain for it tx_receipt_data = self.ethereum.get_transaction_receipt( tx_hash=tx_hash) dbethtx.add_receipt_data(tx_receipt_data) tx_receipt = dbethtx.get_receipt(tx_hash) return tx_receipt # type: ignore # tx_receipt was just added in the DB so should be there # noqa: E501
def get_receipts_for_transactions_missing_them(self, limit: Optional[int] = None ) -> None: """ Searches the database for up to `limit` transactions that have no corresponding receipt and for each one of them queries the receipt and saves it in the DB. It's protected by a lock to not enter the same code twice (i.e. from periodic tasks and from pnl report history events gathering) """ with self.missing_receipts_lock: dbethtx = DBEthTx(self.database) hash_results = dbethtx.get_transaction_hashes_no_receipt( tx_filter_query=None, limit=limit, ) if len(hash_results) == 0: return # nothing to do for entry in hash_results: tx_receipt_data = self.ethereum.get_transaction_receipt( tx_hash=entry) dbethtx.add_receipt_data(tx_receipt_data)
def test_get_transaction_receipt( ethereum_manager, call_order, ethereum_manager_connect_at_start, database, ): wait_until_all_nodes_connected( ethereum_manager_connect_at_start=ethereum_manager_connect_at_start, ethereum=ethereum_manager, ) tx_hash = deserialize_evm_tx_hash( '0x12d474b6cbba04fd1a14e55ef45b1eb175985612244631b4b70450c888962a89' ) # noqa: E501 result = ethereum_manager.get_transaction_receipt(tx_hash, call_order=call_order) block_hash = '0x6f3a7838a8788c3371b88df170c3643d19bad896c915a7368681292882b6ad61' assert result['blockHash'] == block_hash assert len(result['logs']) == 2 assert result['gasUsed'] == 144046 assert result['blockNumber'] == 10840714 assert result['logs'][0]['blockNumber'] == 10840714 assert result['logs'][1]['blockNumber'] == 10840714 assert result['status'] == 1 assert result['transactionIndex'] == 110 assert result['logs'][0]['transactionIndex'] == 110 assert result['logs'][1]['transactionIndex'] == 110 assert result['logs'][0]['logIndex'] == 235 assert result['logs'][1]['logIndex'] == 236 from_addy = make_ethereum_address() to_addy = make_ethereum_address() database.add_blockchain_accounts( blockchain=SupportedBlockchain.ETHEREUM, account_data=[ BlockchainAccountData(address=from_addy), BlockchainAccountData(address=to_addy), ], ) db = DBEthTx(database) db.add_ethereum_transactions( [ EthereumTransaction( # need to add the tx first tx_hash=tx_hash, timestamp=1, # all other fields don't matter for this test block_number=1, from_address=from_addy, to_address=to_addy, value=1, gas=1, gas_price=1, gas_used=1, input_data=b'', nonce=1, ) ], relevant_address=from_addy, ) # also test receipt can be stored and retrieved from the DB. # This tests that all node types (say openethereum) are processed properly db.add_receipt_data(result) receipt = db.get_receipt(tx_hash) assert receipt == EthereumTxReceipt( tx_hash=tx_hash, contract_address=None, status=True, type=0, logs=[ EthereumTxReceiptLog( log_index=235, data= b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02T\x0b\xe4\x00', # noqa: E501 address='0x5bEaBAEBB3146685Dd74176f68a0721F91297D37', removed=False, topics=[ b'\xdd\xf2R\xad\x1b\xe2\xc8\x9bi\xc2\xb0h\xfc7\x8d\xaa\x95+\xa7\xf1c\xc4\xa1\x16(\xf5ZM\xf5#\xb3\xef', # noqa: E501 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s(*c\xf0\xe3\xd7\xe9`EuB\x0fwsa\xec\xa3\xc8j', # noqa: E501 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6 \xf1\x93ME\x84\xdd\xa6\x99\x9e\xdc\xad\xd3)\x81)dj\xa5', # noqa: E501 ]), EthereumTxReceiptLog( log_index=236, data= b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6 \xf1\x93ME\x84\xdd\xa6\x99\x9e\xdc\xad\xd3)\x81)dj\xa5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6 \xf1\x93ME\x84\xdd\xa6\x99\x9e\xdc\xad\xd3)\x81)dj\xa5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[\xea\xba\xeb\xb3\x14f\x85\xddt\x17oh\xa0r\x1f\x91)}7\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02T\x0b\xe4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r\xe0\xb6\xb3\xa7d\x00\x00', # noqa: E501 address='0x73282A63F0e3D7e9604575420F777361ecA3C86A', removed=False, topics=[ b'\xd6\xd4\xf5h\x1c$l\x9fB\xc2\x03\xe2\x87\x97Z\xf1`\x1f\x8d\xf8\x03Z\x92Q\xf7\x9a\xab\\\x8f\t\xe2\xf8' ], # noqa: E501 ), ])
def setup_ethereum_transactions_test( database: DBHandler, transaction_already_queried: bool, one_receipt_in_db: bool = False, ) -> Tuple[List[EthereumTransaction], List[EthereumTxReceipt]]: dbethtx = DBEthTx(database) tx_hash1 = '0x692f9a6083e905bdeca4f0293f3473d7a287260547f8cbccc38c5cb01591fcda' tx_hash1_b = hexstring_to_bytes(tx_hash1) transaction1 = EthereumTransaction( tx_hash=tx_hash1_b, timestamp=Timestamp(1630532276), block_number=13142218, from_address=string_to_ethereum_address( '0x443E1f9b1c866E54e914822B7d3d7165EdB6e9Ea'), to_address=string_to_ethereum_address( '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'), value=int(10 * 10**18), gas=194928, gas_price=int(0.000000204 * 10**18), gas_used=136675, input_data=hexstring_to_bytes( '0x7ff36ab5000000000000000000000000000000000000000000000367469995d0723279510000000000000000000000000000000000000000000000000000000000000080000000000000000000000000443e1f9b1c866e54e914822b7d3d7165edb6e9ea00000000000000000000000000000000000000000000000000000000612ff9b50000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000002a3bff78b79a009976eea096a51a948a3dc00e34' ), # noqa: E501 nonce=13, ) tx_hash2 = '0x6beab9409a8f3bd11f82081e99e856466a7daf5f04cca173192f79e78ed53a77' tx_hash2_b = hexstring_to_bytes(tx_hash2) transaction2 = EthereumTransaction( tx_hash=tx_hash2_b, timestamp=Timestamp(1631013757), block_number=13178342, from_address=string_to_ethereum_address( '0x442068F934BE670aDAb81242C87144a851d56d16'), to_address=string_to_ethereum_address( '0xEaDD9B69F96140283F9fF75DA5FD33bcF54E6296'), value=0, gas=77373, gas_price=int(0.000000100314697497 * 10**18), gas_used=46782, input_data=hexstring_to_bytes( '0xa9059cbb00000000000000000000000020c8032d4f7d4a380385f87aeadf05bed84504cb000000000000000000000000000000000000000000000000000000003b9deec6' ), # noqa: E501 nonce=3, ) transactions = [transaction1, transaction2] if transaction_already_queried is True: dbethtx.add_ethereum_transactions(ethereum_transactions=transactions) result, _ = dbethtx.get_ethereum_transactions( ETHTransactionsFilterQuery.make()) assert result == transactions expected_receipt1 = EthereumTxReceipt( tx_hash=tx_hash1_b, contract_address=None, status=True, type=0, logs=[ EthereumTxReceiptLog( log_index=295, data=hexstring_to_bytes( '0x0000000000000000000000000000000000000000000000008ac7230489e80000' ), # noqa: E501 address=string_to_ethereum_address( '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'), removed=False, topics=[ hexstring_to_bytes( '0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c' ), # noqa: E501 hexstring_to_bytes( '0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d' ), # noqa: E501 ], ), EthereumTxReceiptLog( log_index=296, data=hexstring_to_bytes( '0x0000000000000000000000000000000000000000000000008ac7230489e80000' ), # noqa: E501 address=string_to_ethereum_address( '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'), removed=False, topics=[ hexstring_to_bytes( '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' ), # noqa: E501 hexstring_to_bytes( '0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d' ), # noqa: E501 hexstring_to_bytes( '0x000000000000000000000000caa004418eb42cdf00cb057b7c9e28f0ffd840a5' ), # noqa: E501 ], ), EthereumTxReceiptLog( log_index=297, data=hexstring_to_bytes( '0x00000000000000000000000000000000000000000000036ba1d53baeeda5ed20' ), # noqa: E501 address=string_to_ethereum_address( '0x2a3bFF78B79A009976EeA096a51A948a3dC00e34'), removed=False, topics=[ hexstring_to_bytes( '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' ), # noqa: E501 hexstring_to_bytes( '0x000000000000000000000000caa004418eb42cdf00cb057b7c9e28f0ffd840a5' ), # noqa: E501 hexstring_to_bytes( '0x000000000000000000000000443e1f9b1c866e54e914822b7d3d7165edb6e9ea' ), # noqa: E501 ], ), EthereumTxReceiptLog( log_index=298, data=hexstring_to_bytes( '0x000000000000000000000000000000000000000000007b6ea033189ba7d047e30000000000000000000000000000000000000000000000140bc8194dd0f5e4be' ), # noqa: E501 address=string_to_ethereum_address( '0xcaA004418eB42cdf00cB057b7C9E28f0FfD840a5'), removed=False, topics=[ hexstring_to_bytes( '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1' ) ], # noqa: E501 ), EthereumTxReceiptLog( log_index=299, data=hexstring_to_bytes( '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000036ba1d53baeeda5ed200000000000000000000000000000000000000000000000000000000000000000' ), # noqa: E501 address=string_to_ethereum_address( '0xcaA004418eB42cdf00cB057b7C9E28f0FfD840a5'), removed=False, topics=[ hexstring_to_bytes( '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822' ), # noqa: E501 hexstring_to_bytes( '0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d' ), # noqa: E501 hexstring_to_bytes( '0x000000000000000000000000443e1f9b1c866e54e914822b7d3d7165edb6e9ea' ), # noqa: E501 ], ), ], ) expected_receipt2 = EthereumTxReceipt( tx_hash=tx_hash2_b, contract_address=None, status=True, type=2, logs=[ EthereumTxReceiptLog( log_index=438, data=hexstring_to_bytes( '0x000000000000000000000000000000000000000000000000000000003b9deec6' ), # noqa: E501 address=string_to_ethereum_address( '0xEaDD9B69F96140283F9fF75DA5FD33bcF54E6296'), removed=False, topics=[ hexstring_to_bytes( '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' ), # noqa: E501 hexstring_to_bytes( '0x000000000000000000000000442068f934be670adab81242c87144a851d56d16' ), # noqa: E501 hexstring_to_bytes( '0x00000000000000000000000020c8032d4f7d4a380385f87aeadf05bed84504cb' ), # noqa: E501 ], ), ], ) if one_receipt_in_db: dbethtx.add_receipt_data(txreceipt_to_data(expected_receipt1)) return transactions, [expected_receipt1, expected_receipt2]
def _run_ethereum_txreceipts_query(self, hash_results: List[Tuple]) -> None: dbethtx = DBEthTx(self.database) for entry in hash_results: tx_hash = '0x' + entry[0].hex() tx_receipt_data = self.chain_manager.ethereum.get_transaction_receipt(tx_hash=tx_hash) dbethtx.add_receipt_data(tx_receipt_data)