From 68d0df8ce5c1db62578bbbd715d4d125308c8429 Mon Sep 17 00:00:00 2001 From: antazoey Date: Tue, 24 Dec 2024 03:48:31 +0700 Subject: [PATCH] fix(ape-test): issue where couldn't transact when `auto_mine=False` (#2443) --- src/ape/managers/chain.py | 5 +++-- src/ape_test/provider.py | 28 ++++++++++++++++++---------- tests/functional/test_provider.py | 25 ++++++++++++++++++++----- 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/ape/managers/chain.py b/src/ape/managers/chain.py index c459b29e26..0a1866a4b6 100644 --- a/src/ape/managers/chain.py +++ b/src/ape/managers/chain.py @@ -32,7 +32,7 @@ from ape.managers.base import BaseManager from ape.types.address import AddressType from ape.utils.basemodel import BaseInterfaceModel -from ape.utils.misc import is_evm_precompile, is_zero_hex, log_instead_of_fail +from ape.utils.misc import ZERO_ADDRESS, is_evm_precompile, is_zero_hex, log_instead_of_fail if TYPE_CHECKING: from rich.console import Console as RichConsole @@ -591,7 +591,8 @@ def append(self, txn_receipt: ReceiptAPI): """ self._hash_to_receipt_map[txn_receipt.txn_hash] = txn_receipt - address = self.conversion_manager.convert(txn_receipt.sender, AddressType) + key = txn_receipt.sender or ZERO_ADDRESS + address = self.conversion_manager.convert(key, AddressType) if address not in self._account_history_cache: self._account_history_cache[address] = AccountHistory(address=address) diff --git a/src/ape_test/provider.py b/src/ape_test/provider.py index 26aec6f169..f4994fc20e 100644 --- a/src/ape_test/provider.py +++ b/src/ape_test/provider.py @@ -35,6 +35,7 @@ from ape.utils.testing import DEFAULT_TEST_HD_PATH from ape_ethereum.provider import Web3Provider from ape_ethereum.trace import TraceApproach, TransactionTrace +from ape_ethereum.transactions import TransactionStatusEnum from ape_test.config import EthTesterProviderConfig if TYPE_CHECKING: @@ -341,17 +342,24 @@ def send_transaction(self, txn: "TransactionAPI") -> "ReceiptAPI": txn_hash = to_hex(txn.txn_hash) required_confirmations = txn.required_confirmations or 0 - if vm_err: - receipt = self._create_receipt( - required_confirmations=required_confirmations, error=vm_err, txn_hash=txn_hash - ) + txn_dict = txn_dict or txn.model_dump(mode="json") + + # Signature is typically excluded from the model fields, + # so we have to include it manually. + txn_dict["signature"] = txn.signature + + if vm_err or not self.auto_mine: + receipt_data = { + **txn_dict, + "block_number": -1, # Not yet confirmed, + "error": vm_err, + "provider": self, + "required_confirmations": required_confirmations, + "status": TransactionStatusEnum.NO_ERROR, + "txn_hash": txn_hash, + } + receipt = self.network.ecosystem.decode_receipt(receipt_data) else: - txn_dict = txn_dict or txn.model_dump(mode="json") - - # Signature is typically excluded from the model fields, - # so we have to include it manually. - txn_dict["signature"] = txn.signature - receipt = self.get_receipt( txn_hash, required_confirmations=required_confirmations, transaction=txn_dict ) diff --git a/tests/functional/test_provider.py b/tests/functional/test_provider.py index 8dca463fc1..57b6b6d5e1 100644 --- a/tests/functional/test_provider.py +++ b/tests/functional/test_provider.py @@ -514,15 +514,30 @@ def test_create_access_list(eth_tester_provider, vyper_contract_instance, owner) eth_tester_provider.create_access_list(tx) -def test_auto_mine(eth_tester_provider): +def test_auto_mine(eth_tester_provider, owner): eth_tester_provider.auto_mine = False assert not eth_tester_provider.auto_mine - # Ensure can still manually mine. - block = eth_tester_provider.get_block("latest").number + block_before = eth_tester_provider.get_block("latest").number + nonce_before = owner.nonce + + # NOTE: Before, this would wait until it timed out, because + # when auto mine is off, `ape-test` provider still waited + # for the receipt during send_transaction(). It should + # instead return early. + tx = owner.transfer(owner, 123) + assert not tx.confirmed + assert tx.sender == owner.address + assert tx.txn_hash is not None + + nonce_after_tx = owner.nonce + block_after_tx = eth_tester_provider.get_block("latest").number + assert nonce_before == nonce_after_tx, "Transaction should not have been mined." + assert block_before == block_after_tx, "Block height should not have increased." + eth_tester_provider.mine() - next_block = eth_tester_provider.get_block("latest").number - assert next_block > block + block_after_mine = eth_tester_provider.get_block("latest").number + assert block_after_mine > block_after_tx eth_tester_provider.auto_mine = True assert eth_tester_provider.auto_mine