ethereum / py-evm

A Python implementation of the Ethereum Virtual Machine
https://py-evm.readthedocs.io/en/latest/
MIT License
2.27k stars 654 forks source link

aa/bug: Cannot have >1 pending transaction from same sender #2182

Open Anish-Agnihotri opened 4 months ago

Anish-Agnihotri commented 4 months ago

What happened?

Using eth-tester=0.11.0b2 w/ py-evm=0.10.1b1 and auto_mine_transactions=False (not sending one transaction per block as is usually the case with automine enabled).

py-evm seems to apply transaction against last block head StateAPI rather than pending state, resulting in transactions with sequential nonces from the same sender, within a single block, being invalid (think, (sender=A, nonce=1, block=1) being valid but (sender=A, nonce=2, block=1) being invalid.

Root cause seems to be the validate_frontier_transaction(StateAPI, SignedTransactionAPI) function checking for current sender_nonce against finalized state, not pending (returning the last included tx nonce and not the last applied against pending state).

Code that produced the error

def validate_frontier_transaction(
    state: StateAPI, transaction: SignedTransactionAPI
) -> None:
    max_gas_cost = transaction.gas * state.get_gas_price(transaction)
    sender_balance = state.get_balance(transaction.sender)

    if sender_balance < max_gas_cost:
        raise ValidationError(
            f"Sender {transaction.sender!r} cannot afford txn gas "
            f"{max_gas_cost} with account balance {sender_balance}"
        )

    total_cost = transaction.value + max_gas_cost

    if sender_balance < total_cost:
        raise ValidationError(
            f"Sender does not have enough balance to cover transaction value and gas "
            f" (has {sender_balance}, needs {total_cost})"
        )

    sender_nonce = state.get_nonce(transaction.sender)
    if sender_nonce != transaction.nonce:
        raise ValidationError(
            f"Invalid transaction nonce: Expected {sender_nonce}, "
            f"but got {transaction.nonce}"
        )

Full error output

File "/Users/anishagnihotri/project-name/env/lib/python3.10/site-packages/eth/vm/forks/frontier/validation.py", line 35, in validate_frontier_transaction
    raise ValidationError(
eth_utils.exceptions.ValidationError: Invalid transaction nonce: Expected 1, but got 2

Fill this section in if you know how this could or should be fixed

At some point during Chain.apply_transaction(self, SignedTransactionAPI), the correct new_block is being generated with the pending tx applied, but isn't being bubbled up back to eth-tester. Could be here or upstream.

py-evm Version

0.10.1b1

Python Version

3.10.14

Operating System

macOS 13.3.1

Output from pip-freeze

No response