Skip to content

Commit

Permalink
Merge branch 'main' into fix/receipt-transaction-hash
Browse files Browse the repository at this point in the history
  • Loading branch information
antazoey authored Dec 23, 2024
2 parents abb380f + 0686379 commit efd471f
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 21 deletions.
13 changes: 12 additions & 1 deletion src/ape/api/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from ape.exceptions import (
AccountsError,
AliasAlreadyInUseError,
ConversionError,
MethodNonPayableError,
MissingDeploymentBytecodeError,
SignatureError,
Expand Down Expand Up @@ -220,8 +221,18 @@ def transfer(
Returns:
:class:`~ape.api.transactions.ReceiptAPI`
"""
if isinstance(account, int):
raise AccountsError(
"Cannot use integer-type for the `receiver` argument in the "
"`.transfer()` method (this protects against accidentally passing "
"the `value` as the `receiver`)."
)

try:
receiver = self.conversion_manager.convert(account, AddressType)
except ConversionError as err:
raise AccountsError(f"Invalid `receiver` value: '{account}'.") from err

receiver = self.conversion_manager.convert(account, AddressType)
txn = self.provider.network.ecosystem.create_transaction(
sender=self.address, receiver=receiver, **kwargs
)
Expand Down
5 changes: 3 additions & 2 deletions src/ape/managers/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand Down
31 changes: 18 additions & 13 deletions src/ape_test/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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 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
)
Expand All @@ -360,9 +368,6 @@ def send_transaction(self, txn: "TransactionAPI") -> "ReceiptAPI":
self.chain_manager.history.append(receipt)

if receipt.failed:
# NOTE: Using JSON mode since used as request data.
txn_dict = txn_dict or txn.model_dump(mode="json")

txn_dict["nonce"] += 1
txn_params = cast(TxParams, txn_dict)
txn_dict.pop("signature", None)
Expand Down
21 changes: 21 additions & 0 deletions tests/functional/test_accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,27 @@ def test_transfer_value_of_0(sender, receiver):
assert receiver.balance == initial_balance


def test_transfer_mixed_up_sender_and_value(sender, receiver):
"""
Testing the case where the user mixes up the argument order,
it should show a nicer error than it was previously, as this is
a common and easy mistake.
"""
expected = (
r"Cannot use integer-type for the `receiver` "
r"argument in the `\.transfer\(\)` method \(this "
r"protects against accidentally passing the "
r"`value` as the `receiver`\)."
)
with pytest.raises(AccountsError, match=expected):
sender.transfer(123, receiver)

# Similarly show using currency-str (may fail for different error).
expected = r"Invalid `receiver` value: '123 wei'\."
with pytest.raises(AccountsError, match=expected):
sender.transfer("123 wei", receiver)


def test_deploy(owner, contract_container, clean_contract_caches):
contract = owner.deploy(contract_container, 0)
assert contract.address
Expand Down
25 changes: 20 additions & 5 deletions tests/functional/test_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit efd471f

Please sign in to comment.