diff --git a/newsfragments/2265.feature.rst b/newsfragments/2265.feature.rst new file mode 100644 index 0000000000..b61e66f36a --- /dev/null +++ b/newsfragments/2265.feature.rst @@ -0,0 +1 @@ +Add async ``eth.get_transaction_receipt`` and ``eth.wait_for_transaction_receipt`` methods \ No newline at end of file diff --git a/web3/_utils/module_testing/eth_module.py b/web3/_utils/module_testing/eth_module.py index 9859dabc8e..17634912a0 100644 --- a/web3/_utils/module_testing/eth_module.py +++ b/web3/_utils/module_testing/eth_module.py @@ -47,6 +47,7 @@ InvalidAddress, InvalidTransaction, NameNotFound, + TimeExhausted, TransactionNotFound, TransactionTypeMismatch, ) @@ -799,8 +800,8 @@ async def test_async_eth_wait_for_transaction_receipt_unmined( 'maxFeePerGas': async_w3.toWei(3, 'gwei'), 'maxPriorityFeePerGas': async_w3.toWei(1, 'gwei') }) - with pytest.raises(TransactionNotFound): - await async_w3.eth.wait_for_transaction_receipt(txn_hash) + with pytest.raises(TimeExhausted): + await async_w3.eth.wait_for_transaction_receipt(txn_hash, timeout=2) @pytest.mark.asyncio async def test_async_eth_get_transaction_receipt_with_log_entry( @@ -827,6 +828,7 @@ async def test_async_eth_get_transaction_receipt_with_log_entry( assert log_entry['transactionIndex'] == 0 assert log_entry['transactionHash'] == HexBytes(txn_hash_with_log) + class EthModuleTest: def test_eth_protocol_version(self, web3: "Web3") -> None: with pytest.warns(DeprecationWarning, diff --git a/web3/_utils/transactions.py b/web3/_utils/transactions.py index d63ea51d42..374740eee9 100644 --- a/web3/_utils/transactions.py +++ b/web3/_utils/transactions.py @@ -125,26 +125,6 @@ def fill_transaction_defaults(web3: "Web3", transaction: TxParams) -> TxParams: defaults[key] = default_val return merge(defaults, transaction) - -def wait_for_transaction_receipt( - web3: "Web3", txn_hash: _Hash32, timeout: float, poll_latency: float -) -> TxReceipt: - with Timeout(timeout) as _timeout: - while True: - try: - txn_receipt = web3.eth.get_transaction_receipt(txn_hash) - except TransactionNotFound: - txn_receipt = None - # FIXME: The check for a null `blockHash` is due to parity's - # non-standard implementation of the JSON-RPC API and should - # be removed once the formal spec for the JSON-RPC endpoints - # has been finalized. - if txn_receipt is not None and txn_receipt['blockHash'] is not None: - break - _timeout.sleep(poll_latency) - return txn_receipt - - def get_block_gas_limit(web3: "Web3", block_identifier: Optional[BlockIdentifier] = None) -> Wei: if block_identifier is None: block_identifier = web3.eth.block_number diff --git a/web3/eth.py b/web3/eth.py index 636805798d..487091abcc 100644 --- a/web3/eth.py +++ b/web3/eth.py @@ -62,7 +62,6 @@ extract_valid_transaction_params, get_required_transaction, replace_transaction, - wait_for_transaction_receipt as utils_wait_for_transaction_receipt, ) from web3.contract import ( ConciseContract, @@ -71,6 +70,7 @@ ) from web3.exceptions import ( TimeExhausted, + TransactionNotFound, ) from web3.iban import ( Iban, @@ -417,7 +417,22 @@ async def wait_for_transaction_receipt( self, transaction_hash: _Hash32, timeout: float = 120, poll_latency: float = 0.1 ) -> TxReceipt: try: - return await utils_wait_for_transaction_receipt(self.web3, transaction_hash, timeout, poll_latency) + with Timeout(timeout) as _timeout: + while True: + try: + txn_receipt = await self._get_transaction_receipt(transaction_hash) + except TransactionNotFound: + txn_receipt = None + # FIXME: The check for a null `blockHash` is due to parity's + # non-standard implementation of the JSON-RPC API and should + # be removed once the formal spec for the JSON-RPC endpoints + # has been finalized. + # if txn_receipt is not None and txn_receipt['blockHash'] is not None: + if txn_receipt is not None: + break + _timeout.sleep(poll_latency) + return txn_receipt + except Timeout: raise TimeExhausted( "Transaction {!r} is not in the chain, after {} seconds".format( @@ -706,7 +721,22 @@ def wait_for_transaction_receipt( self, transaction_hash: _Hash32, timeout: float = 120, poll_latency: float = 0.1 ) -> TxReceipt: try: - return utils_wait_for_transaction_receipt(self.web3, transaction_hash, timeout, poll_latency) + with Timeout(timeout) as _timeout: + while True: + try: + txn_receipt = self._get_transaction_receipt(transaction_hash) + except TransactionNotFound: + txn_receipt = None + # FIXME: The check for a null `blockHash` is due to parity's + # non-standard implementation of the JSON-RPC API and should + # be removed once the formal spec for the JSON-RPC endpoints + # has been finalized. + # if txn_receipt is not None and txn_receipt['blockHash'] is not None: + if txn_receipt is not None: + break + _timeout.sleep(poll_latency) + return txn_receipt + except Timeout: raise TimeExhausted( "Transaction {!r} is not in the chain, after {} seconds".format( @@ -720,11 +750,6 @@ def get_transaction_receipt( ) -> TxReceipt: return self._get_transaction_receipt(transaction_hash) - # get_transaction_receipt: Method[Callable[[_Hash32], TxReceipt]] = Method( - # RPC.eth_getTransactionReceipt, - # mungers=[default_root_munger] - # ) - get_transaction_count: Method[Callable[..., Nonce]] = Method( RPC.eth_getTransactionCount, mungers=[BaseEth.block_id_munger],