Skip to content

feat(tests): RESERVE_BALANCE precompile with tests#14

Open
pdobacz wants to merge 9 commits intoforks/monad_ninefrom
mip4
Open

feat(tests): RESERVE_BALANCE precompile with tests#14
pdobacz wants to merge 9 commits intoforks/monad_ninefrom
mip4

Conversation

@pdobacz
Copy link
Collaborator

@pdobacz pdobacz commented Mar 6, 2026

No description provided.

pdobacz added 8 commits March 6, 2026 09:25
Co-Authored-By: Claude <claude-opus-4-5-20251101>
Co-Authored-By: Claude claude-opus-4-5-20251101

Squashed from:

Gas-dependent error message for `method not supported`
Tidy spec.py
Fix check order to match post PR 2109 spec
Appease mypy
refactor _is_call in reserve_balance.py
remove early version of test_check_order test
Add check-order tests and refactor precompile test helpers
Generic precompile tests aware of Monad precompiles
Test essential usecase of containing reserve balance violation
Enusre revert returns are independent of gas
Spec update: add error messages to reserve balance precompile
Appease mypy
Add SHORT_CALLDATA to CallScenario
Refactor and expand precompile call tests
Spec update: precompile gas cost GAS_BASE -> GAS_WARM_ACCESS (100)
Spec update: reject nonzero value in reserve balance precompile
Add test_contract_unrestricted_with_selfdestruct
wip claude 16: mip4 test_many_accounts_balance_change optimizations
wip claude 14: MIP-4 spec update - strict calldata and CALL-only
wip claude 13 (squashed): tests: 2step, uint256max, regression
wip claude 10: simplify RefillFactory to return callable directly
wip claude 08: convert CHECKRESERVEBALANCE opcode to precompile
wip claude 03 (squashed): adding tests
wip claude 03: add MIP-4 CHECKRESERVEBALANCE opcode tests (preliminary)
wip claude 02: add CHECKRESERVEBALANCE opcode (MIP-4)
@pdobacz pdobacz requested review from QEDK and mijovic March 6, 2026 14:22
@greptile-apps
Copy link

greptile-apps bot commented Mar 6, 2026

Greptile Summary

This PR implements the RESERVE_BALANCE precompile (dippedIntoReserve()) at address 0x1001 for the MONAD_NINE fork (MIP-4), accompanied by an extensive test suite. The core change extracts the reserve-balance violation check into a standalone is_reserve_balance_violated() helper, adds a new RevertInMonadPrecompile exception type, and adds a delegation-revert guard so that delegating EOAs pointing to Monad-specific precompile addresses cannot execute them as empty code.

Key changes:

  • New reserve_balance.py precompile: Implements dippedIntoReserve() with strict call-type enforcement (CALL only), selector/size/value validation, and GAS_WARM_ACCESS cost.
  • Refactored is_reserve_balance_violated(): Extracted from the inline process_message body into a named function shared by both the end-of-transaction check and the new precompile.
  • MONAD_PRECOMPILE_ADDRESSES guard: Added to both monad_eight and monad_nine interpreters to revert when a delegating EOA's code address is a Monad precompile.
  • Comprehensive test suite: Covers fork transition, call opcodes, input validation, gas, revert data, multi-block delegation scenarios, value-transfer violations, and interaction with the existing tx-revert mechanism.
  • Prague EIP-7702 test updates: Correctly adjusts test_set_code_to_precompile and test_pointer_to_precompile for the new Monad precompile revert behavior.

Issues found:

  • Logic bug: STAKING_ADDRESS (0x1000) is included in MONAD_PRECOMPILE_ADDRESSES (both forks) but is absent from PRE_COMPILED_CONTRACTS. Because the delegation-revert guard is nested inside if code_address in PRE_COMPILED_CONTRACTS:, the elif branch for STAKING_ADDRESS is unreachable — a delegating EOA pointing to 0x1000 silently executes empty code instead of reverting.
  • Debug artifact: A stray print() call was left in test_transfers.py::test_credit_same_tx and will pollute test output.

Confidence Score: 3/5

  • The PR has a logic bug where the delegation-revert guard for Monad precompiles does not fire for STAKING_ADDRESS, and contains a debug print statement.
  • The RESERVE_BALANCE precompile implementation itself is correct and well-tested. However, the MONAD_PRECOMPILE_ADDRESSES guard has a critical flaw: STAKING_ADDRESS is listed in the guard set but is not in PRE_COMPILED_CONTRACTS, making the elif branch unreachable for it. This means a delegating EOA pointing to 0x1000 will silently execute empty code rather than reverting, contradicting the stated invariant. This guard logic issue affects both monad_eight and monad_nine. Additionally, there is a leftover debug print() statement in test_transfers.py that should be removed before merge.
  • src/ethereum/forks/monad_nine/vm/precompiled_contracts/init.py and src/ethereum/forks/monad_eight/vm/interpreter.py (STAKING_ADDRESS guard logic) and tests/monad_nine/mip4_checkreservebalance/test_transfers.py (debug print)

Sequence Diagram

sequenceDiagram
    participant Caller as Caller Contract
    participant Interp as process_message()
    participant RB as reserve_balance()
    participant Helper as is_reserve_balance_violated()

    Caller->>Interp: CALL 0x1001 (normal path)
    Note over Interp: code_address in PRE_COMPILED_CONTRACTS AND NOT disable_precompiles
    Interp->>RB: reserve_balance(evm)
    RB->>RB: _is_call() check (NOT_CALL → raise InvalidParameter)
    RB->>RB: charge_gas(GAS_WARM_ACCESS)
    RB->>RB: selector / value / size checks
    RB->>Helper: is_reserve_balance_violated(state, tx_env)
    Helper-->>RB: bool
    RB-->>Interp: evm.output = U256(violation).to_be_bytes32()
    Interp-->>Caller: return data (32 bytes)

    Caller->>Interp: CALL delegating_EOA → points to 0x1001
    Note over Interp: disable_precompiles = True, code_address in PRE_COMPILED_CONTRACTS
    Interp->>Interp: elif code_address in MONAD_PRECOMPILE_ADDRESSES → True
    Interp->>Interp: raise RevertInMonadPrecompile
    Note over Interp: gas_left = 0, evm.output preserved
    Interp-->>Caller: revert (0 return, all gas consumed)

    Caller->>Interp: CALL delegating_EOA → points to 0x1000 (STAKING)
    Note over Interp: disable_precompiles = True, code_address NOT in PRE_COMPILED_CONTRACTS
    Note over Interp: ⚠ elif never reached — executes empty code instead
    Interp-->>Caller: success (empty return)
Loading

Last reviewed commit: 2b9d255

good bot

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant