示例#1
0
    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 test_tx_decode(evm_transaction_decoder, database):
    dbethtx = DBEthTx(database)
    addr1 = '0x2B888954421b424C5D3D9Ce9bB67c9bD47537d12'
    approve_tx_hash = deserialize_evm_tx_hash('0x5cc0e6e62753551313412492296d5e57bea0a9d1ce507cc96aa4aa076c5bde7a')  # noqa: E501
    transactions = dbethtx.get_ethereum_transactions(
        filter_=ETHTransactionsFilterQuery.make(
            addresses=[addr1],
            tx_hash=approve_tx_hash,
        ),
        has_premium=True,
    )
    decoder = evm_transaction_decoder
    with patch.object(decoder, 'decode_transaction', wraps=decoder.decode_transaction) as decode_mock:  # noqa: E501
        for tx in transactions:
            receipt = dbethtx.get_receipt(tx.tx_hash)
            assert receipt is not None, 'all receipts should be queried in the test DB'
            events = decoder.get_or_decode_transaction_events(tx, receipt, ignore_cache=False)
            if tx.tx_hash == approve_tx_hash:
                assert len(events) == 2
                assert_events_equal(events[0], HistoryBaseEntry(
                    # The no-member is due to https://github.com/PyCQA/pylint/issues/3162
                    event_identifier=approve_tx_hash.hex(),  # pylint: disable=no-member
                    sequence_index=0,
                    timestamp=1569924574000,
                    location=Location.BLOCKCHAIN,
                    location_label=addr1,
                    asset=A_ETH,
                    balance=Balance(amount=FVal('0.000030921')),
                    # The no-member is due to https://github.com/PyCQA/pylint/issues/3162
                    notes=f'Burned 0.000030921 ETH in gas from {addr1}',
                    event_type=HistoryEventType.SPEND,
                    event_subtype=HistoryEventSubType.FEE,
                    counterparty=CPT_GAS,
                ))
                assert_events_equal(events[1], HistoryBaseEntry(
                    # The no-member is due to https://github.com/PyCQA/pylint/issues/3162
                    event_identifier=approve_tx_hash.hex(),  # pylint: disable=no-member
                    sequence_index=163,
                    timestamp=1569924574000,
                    location=Location.BLOCKCHAIN,
                    location_label=addr1,
                    asset=A_SAI,
                    balance=Balance(amount=1),
                    notes=f'Approve 1 SAI of {addr1} for spending by 0xdf869FAD6dB91f437B59F1EdEFab319493D4C4cE',  # noqa: E501
                    event_type=HistoryEventType.INFORMATIONAL,
                    event_subtype=HistoryEventSubType.APPROVE,
                    counterparty='0xdf869FAD6dB91f437B59F1EdEFab319493D4C4cE',
                ))

        assert decode_mock.call_count == len(transactions)
        # now go again, and see that no more decoding happens as it's all pulled from the DB
        for tx in transactions:
            receipt = dbethtx.get_receipt(tx.tx_hash)
            assert receipt is not None, 'all receipts should be queried in the test DB'
            events = decoder.get_or_decode_transaction_events(tx, receipt, ignore_cache=False)
        assert decode_mock.call_count == len(transactions)
示例#3
0
    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
示例#4
0
def test_maybe_schedule_ethereum_txreceipts(
    task_manager,
    ethereum_manager,
    eth_transactions,
    database,
    one_receipt_in_db,
):
    task_manager.potential_tasks = [
        task_manager._maybe_schedule_ethereum_txreceipts
    ]  # pylint: disable=protected-member  # noqa: E501
    _, receipts = setup_ethereum_transactions_test(
        database=database,
        transaction_already_queried=True,
        one_receipt_in_db=one_receipt_in_db,
    )

    dbethtx = DBEthTx(database)
    timeout = 10
    tx_hash_1 = hexstring_to_bytes(
        '0x692f9a6083e905bdeca4f0293f3473d7a287260547f8cbccc38c5cb01591fcda'
    )  # noqa: E501
    tx_hash_2 = hexstring_to_bytes(
        '0x6beab9409a8f3bd11f82081e99e856466a7daf5f04cca173192f79e78ed53a77'
    )  # noqa: E501
    receipt_get_patch = patch.object(
        ethereum_manager,
        'get_transaction_receipt',
        wraps=ethereum_manager.get_transaction_receipt)  # pylint: disable=protected-member  # noqa: E501
    queried_receipts = set()
    try:
        with gevent.Timeout(timeout):
            with receipt_get_patch as receipt_task_mock:
                task_manager.schedule()
                while True:
                    if len(queried_receipts) == 2:
                        break

                    for txhash in (tx_hash_1, tx_hash_2):
                        if dbethtx.get_receipt(txhash) is not None:
                            queried_receipts.add(txhash)

                    gevent.sleep(.3)

                task_manager.schedule()
                gevent.sleep(.5)
                assert receipt_task_mock.call_count == 1 if one_receipt_in_db else 2, '2nd schedule should do nothing'  # noqa: E501

    except gevent.Timeout as e:
        raise AssertionError(
            f'receipts query was not completed within {timeout} seconds'
        ) from e  # noqa: E501

    receipt1 = eth_transactions.get_or_query_transaction_receipt(tx_hash_1)
    assert receipt1 == receipts[0]
    receipt2 = eth_transactions.get_or_query_transaction_receipt(tx_hash_2)
    assert receipt2 == receipts[1]
示例#5
0
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
            ),
        ])