Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/configs/feature.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ monad:
# --suppress-no-test-exit-code works around a problem where multi-phase fill
# (triggered by tarball output) fails to proceed on no tests processed
# in 1st phase (exit code 5)
fill-params: --suppress-no-test-exit-code -m blockchain_test --from=MONAD_EIGHT --until=MONAD_NEXT --chain-id=143 -k "not invalid_header"
fill-params: --suppress-no-test-exit-code -m blockchain_test --from=MONAD_EIGHT --until=MONAD_TEN --chain-id=143 -k "not invalid_header"

monad_runloop:
evm-type: eels
# Like `monad`, but `--monad-runloop` and eestnet chain id `30143`
fill-params: --suppress-no-test-exit-code -m blockchain_test --from=MONAD_EIGHT --until=MONAD_NEXT --chain-id=30143 --monad-runloop -k "not invalid_header"
fill-params: --suppress-no-test-exit-code -m blockchain_test --from=MONAD_EIGHT --until=MONAD_TEN --chain-id=30143 --monad-runloop -k "not invalid_header"
1 change: 1 addition & 0 deletions .github/scripts/generate_build_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
# to sort after the canonical forks.
"MONAD_EIGHT",
"MONAD_NINE",
"MONAD_TEN",
"MONAD_NEXT",
]

Expand Down
10 changes: 5 additions & 5 deletions MONAD_RUNLOOP_TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ uv run consume direct --input ../fixtures_eestnet \

## Fork-transition flow (MIP-8 dual-db)

MONAD_NINE storage is slot-encoded; MONAD_NEXT (MIP-8) is
MONAD_NINE storage is slot-encoded; MONAD_TEN (MIP-8) is
page-encoded. A transition fixture (e.g.
`MONAD_NINEToMONAD_NEXTAtTime15k`) crosses that boundary mid-run, so
`MONAD_NINEToMONAD_TENAtTime15k`) crosses that boundary mid-run, so
the run keeps both encodings live in one triedb: a slot-encoded
primary timeline and a page-encoded secondary timeline.

Expand All @@ -97,10 +97,10 @@ primary timeline and a page-encoded secondary timeline.
and writes `output.json`.
- **Execution** (`runloop_monad`): reads each block from the ledger
dir and dispatches on `get_monad_revision(timestamp)` via
`SWITCH_MONAD_TRAITS` — block 1 runs MONAD_NINE, block 2 MONAD_NEXT.
`SWITCH_MONAD_TRAITS` — block 1 runs MONAD_NINE, block 2 MONAD_TEN.
- **Dual-write** (`commit_block`): both timelines get the same
`StateDeltas` every block. Slot is canonical before the fork, page
after; the canonical root flips to page at the first MONAD_NEXT
after; the canonical root flips to page at the first MONAD_TEN
block, matching the fixture's final `blockHeader.stateRoot`.
- **Assertions**: `state_root` and every `postState` account
(balance, nonce, code, per-slot storage) match `output`, with no
Expand Down Expand Up @@ -129,4 +129,4 @@ The production fork migration uses the same dual-db mechanism: an operator
runs `monad-mpt --activate-secondary --state-machine monad` on the live
slot-encoded db before the fork, the node opens the secondary timeline and
dual-writes both encodings across the boundary, and the authoritative root
flips from slot to page at the first MONAD_NEXT block.
flips from slot to page at the first MONAD_TEN block.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ It mainly serves as an alternative implementation of https://github.com/category
3. Fill all monadized spec tests as of writing this (see below for explanation of flags):

```bash
uv run fill --clean -m "blockchain_test or transaction_test" --from MONAD_EIGHT --until MONAD_NINE --chain-id 143 -n auto tests
uv run fill --clean -m "blockchain_test or transaction_test" --from MONAD_EIGHT --until MONAD_TEN --chain-id 143 -n auto tests
```

4. The test fixtures to be found in `fixtures/` directory under repo root.
Expand All @@ -52,7 +52,7 @@ Filling tests is the process of running Python generators of spec tests [like on
- **`-m blockchain_test or transaction_test`**: causes these two flavors of fixtures to be generated
- `blockchain_test` is the currently supported by `monad` flavor of a spec test checking correctness of the state transition. Note this includes `blockchain_test_from_state_test`, meaning that all `state_test(...)` fillers are included
- `transaction_test` is also supported, tests only correctness of static transaction checks
- **`--from MONAD_EIGHT --until MONAD_NINE`**: hardforks for which to generate fixtures. Must match with those defined in `monad`, inclusive
- **`--from MONAD_EIGHT --until MONAD_TEN`**: hardforks for which to generate fixtures. Must match with those defined in `monad`, inclusive
- **`--chain-id 143`**: must be specified for signatures and EIP-7702 to work correctly
- **`-n auto`**: from `pytest`, parallel execution of tests
- **`tests`**: root directory to traverse to discover tests
Expand All @@ -65,7 +65,7 @@ Filling tests is the process of running Python generators of spec tests [like on

- not all Ethereum-only features have been switched off, e.g. eth-specific system contracts and tx types are available in the monadized `execution-specs` implementation. We're skipping their respective spec tests, and we don't have tests testing lack of these features in Monad.
- we're going to be keeping up with upstream changes (currently `forks/amsterdam` branch). This should work by opening a PR with the upstream changes to be commit-merged into our default branch (currently `forks/monad_nine`).
- when adding a new Monad-hardfork we should use the [`ethereum-spec-new-fork` tool](./CONTRIBUTING.md#new-fork-tool) provided to clone the parent hardfork into the new hardfork. If that new Monad-hardfork also adopts upstream (Ethereum) hardfork improvements, you will need to apply these yourself.
- when adding a new Monad-hardfork we should use the [`ethereum-spec-new-fork` tool](./docs/specs/writing_specs.md#new-fork-tool) provided to clone the parent hardfork into the new hardfork. If that new Monad-hardfork also adopts upstream (Ethereum) hardfork improvements, you will need to apply these yourself.

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@
FORK_REVISION_SCHEDULES = {
"MONAD_EIGHT": [(8, 0)],
"MONAD_NINE": [(9, 0)],
"MONAD_NEXT": [(10, 0)],
"MONAD_TEN": [(10, 0)],
"MONAD_NEXT": [(11, 0)],
"MONAD_EIGHTToMONAD_NINEAtTime15k": [(8, 0), (9, 15_000)],
"MONAD_NINEToMONAD_NEXTAtTime15k": [(9, 0), (10, 15_000)],
"MONAD_NINEToMONAD_TENAtTime15k": [(9, 0), (10, 15_000)],
"MONAD_TENToMONAD_NEXTAtTime15k": [(10, 0), (11, 15_000)],
Comment thread
pdobacz marked this conversation as resolved.
}


Expand Down Expand Up @@ -184,9 +186,9 @@ def _init_triedb(
Create and format a fresh triedb file via `monad-mpt`.

The storage encoding depends on the fixture's revision schedule.
MIP-8 (MONAD_NEXT, revision >= 10) uses a page-encoded triedb; older
MIP-8 (MONAD_TEN, revision >= 10) uses a page-encoded triedb; older
revisions use slot encoding. A fixture that crosses the boundary
(e.g. a MONAD_NINE->MONAD_NEXT transition) needs both: a slot-encoded
(e.g. a MONAD_NINE->MONAD_TEN transition) needs both: a slot-encoded
primary plus an activated page-encoded secondary timeline, so the
runloop can dual-write across the fork.
"""
Expand Down
8 changes: 6 additions & 2 deletions packages/testing/src/execution_testing/forks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
MONAD_EIGHT,
MONAD_NEXT,
MONAD_NINE,
MONAD_TEN,
Amsterdam,
ArrowGlacier,
Berlin,
Expand Down Expand Up @@ -38,7 +39,8 @@
BPO3ToBPO4AtTime15k,
CancunToPragueAtTime15k,
MONAD_EIGHTToMONAD_NINEAtTime15k,
MONAD_NINEToMONAD_NEXTAtTime15k,
MONAD_NINEToMONAD_TENAtTime15k,
MONAD_TENToMONAD_NEXTAtTime15k,
OsakaToBPO1AtTime15k,
ParisToShanghaiAtTime15k,
PragueToOsakaAtTime15k,
Expand Down Expand Up @@ -124,7 +126,9 @@
"MONAD_EIGHT",
"MONAD_EIGHTToMONAD_NINEAtTime15k",
"MONAD_NINE",
"MONAD_NINEToMONAD_NEXTAtTime15k",
"MONAD_NINEToMONAD_TENAtTime15k",
"MONAD_TEN",
"MONAD_TENToMONAD_NEXTAtTime15k",
"MONAD_NEXT",
"BPO1",
"BPO1ToBPO2AtTime15k",
Expand Down
10 changes: 8 additions & 2 deletions packages/testing/src/execution_testing/forks/forks/forks.py
Original file line number Diff line number Diff line change
Expand Up @@ -1666,8 +1666,8 @@ def c(w: int) -> int:
return fn


class MONAD_NEXT(MONAD_NINE, solc_name="cancun"): # noqa: N801
"""MONAD_NEXT fork."""
class MONAD_TEN(MONAD_NINE, solc_name="cancun"): # noqa: N801
"""MONAD_TEN fork."""

@classmethod
def gas_costs(cls) -> GasCosts:
Expand Down Expand Up @@ -1754,6 +1754,12 @@ def _calculate_sstore_gas_mip8(
return gas_cost


class MONAD_NEXT(MONAD_TEN, solc_name="cancun"): # noqa: N801
"""MONAD_NEXT fork, a placeholder identical to MONAD_TEN."""

pass


class BPO1(
Osaka,
bpo_fork=True,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
MONAD_EIGHT,
MONAD_NEXT,
MONAD_NINE,
MONAD_TEN,
Amsterdam,
Berlin,
Cancun,
Expand Down Expand Up @@ -65,9 +66,16 @@ class MONAD_EIGHTToMONAD_NINEAtTime15k(TransitionBaseClass): # noqa: N801
pass


@transition_fork(to_fork=MONAD_NEXT, from_fork=MONAD_NINE, at_timestamp=15_000)
class MONAD_NINEToMONAD_NEXTAtTime15k(TransitionBaseClass): # noqa: N801
"""MONAD_NINE to MONAD_NEXT transition at Timestamp 15k."""
@transition_fork(to_fork=MONAD_TEN, from_fork=MONAD_NINE, at_timestamp=15_000)
class MONAD_NINEToMONAD_TENAtTime15k(TransitionBaseClass): # noqa: N801
"""MONAD_NINE to MONAD_TEN transition at Timestamp 15k."""

pass


@transition_fork(to_fork=MONAD_NEXT, from_fork=MONAD_TEN, at_timestamp=15_000)
class MONAD_TENToMONAD_NEXTAtTime15k(TransitionBaseClass): # noqa: N801
"""MONAD_TEN to MONAD_NEXT transition at Timestamp 15k."""

pass

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from execution_testing.vm import Bytecode, Op

from ..forks.forks import MONAD_NEXT, Homestead, Osaka
from ..forks.forks import MONAD_TEN, Homestead, Osaka
from ..helpers import Fork


Expand Down Expand Up @@ -611,9 +611,9 @@ def test_sstore_gas_costs(fork: Fork, opcode: Op, expected_cost: int) -> None:
assert opcode.gas_cost(fork) == expected_cost


# --- MIP-8 page-based storage gas tests (MONAD_NEXT) ---
# --- MIP-8 page-based storage gas tests (MONAD_TEN) ---

_gc = MONAD_NEXT.gas_costs()
_gc = MONAD_TEN.gas_costs()


@pytest.mark.parametrize(
Expand All @@ -633,7 +633,7 @@ def test_sstore_gas_costs(fork: Fork, opcode: Op, expected_cost: int) -> None:
)
def test_mip8_sload_gas(opcode: Op, expected_cost: int) -> None:
"""Test MIP-8 page-level SLOAD gas."""
assert opcode.gas_cost(MONAD_NEXT) == expected_cost
assert opcode.gas_cost(MONAD_TEN) == expected_cost


@pytest.mark.parametrize(
Expand Down Expand Up @@ -734,7 +734,7 @@ def test_mip8_sload_gas(opcode: Op, expected_cost: int) -> None:
)
def test_mip8_sstore_gas(opcode: Op, expected_cost: int) -> None:
"""Test MIP-8 page-level SSTORE gas."""
assert opcode.gas_cost(MONAD_NEXT) == expected_cost
assert opcode.gas_cost(MONAD_TEN) == expected_cost


def test_mip8_sstore_no_refunds() -> None:
Expand All @@ -745,4 +745,4 @@ def test_mip8_sstore_no_refunds() -> None:
current_value=5,
new_value=0,
)
assert clear_op.refund(MONAD_NEXT) == 0
assert clear_op.refund(MONAD_TEN) == 0
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def _resolve_state_module(fork: Any) -> Tuple[Any, Any, Any, Any, Any]:
"""
Pick the (State, set_account, set_storage, state_root, Account) tuple
matching ``fork``'s storage-hashing scheme. Defaults to the local
Frontier slot-based impl. MONAD_NEXT and any later fork switch to the
Frontier slot-based impl. MONAD_TEN and any later fork switch to the
MIP-8 paged storage impl.

For transition forks the genesis pre-state uses the FROM fork's
Expand All @@ -115,7 +115,7 @@ def _resolve_state_module(fork: Any) -> Tuple[Any, Any, Any, Any, Any]:
if fork is None:
return (State, set_account, set_storage, state_root, FrontierAccount)

from execution_testing.forks.forks.forks import MONAD_NEXT
from execution_testing.forks.forks.forks import MONAD_TEN
from execution_testing.forks.transition_base_fork import (
TransitionBaseClass,
)
Expand All @@ -126,7 +126,7 @@ def _resolve_state_module(fork: Any) -> Tuple[Any, Any, Any, Any, Any]:
else fork
)

if isinstance(resolved, type) and issubclass(resolved, MONAD_NEXT):
if isinstance(resolved, type) and issubclass(resolved, MONAD_TEN):
return (
State,
set_account,
Expand Down Expand Up @@ -386,7 +386,7 @@ def state_root(self, fork: Any = None) -> Hash:

``fork`` selects the storage-hashing scheme. ``None`` keeps the
legacy slot-based MPT (used by every fork up to MONAD_NINE). When
``fork.name() == "MONAD_NEXT"`` the per-fork MIP-8 paged storage
``fork.name() == "MONAD_TEN"`` the per-fork MIP-8 paged storage
root impl is used so the genesis state_root matches what the C++
runtime computes for that fork.
"""
Expand Down
6 changes: 3 additions & 3 deletions packages/testing/src/execution_testing/vm/opcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2595,11 +2595,11 @@ class Opcodes(Opcode, Enum):

Gas
----
NOTE: MIP-8 (MONAD_NEXT) changes the gas cost, see spec.
NOTE: MIP-8 (MONAD_TEN) changes the gas cost, see spec.
- static_gas = 0
- dynamic_gas = 100 if warm_address, 2600 if cold_address

MIP-8 (MONAD_NEXT) replaces per-key warming with per-page
MIP-8 (MONAD_TEN) replaces per-key warming with per-page
warming: `GAS_PAGE_BASE_COST` when the page is already in
`read_accessed_pages`, else `GAS_PAGE_LOAD_COST +
GAS_PAGE_BASE_COST`.
Expand Down Expand Up @@ -2656,7 +2656,7 @@ class Opcodes(Opcode, Enum):

Gas
----
NOTE: MIP-8 (MONAD_NEXT) changes the gas cost, see spec.
NOTE: MIP-8 (MONAD_TEN) changes the gas cost, see spec.
```
static_gas = 0

Expand Down
7 changes: 4 additions & 3 deletions src/ethereum/forks/monad_next/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""
MONAD_TEN fork introduces Monad specific changes to the Ethereum protocol.
MONAD_NEXT fork is a placeholder for upcoming Monad changes and is
currently identical to MONAD_TEN.
"""

from ethereum.fork_criteria import ByTimestamp, ForkCriteria

# TODO: just a bit after MONAD_NINE
FORK_CRITERIA: ForkCriteria = ByTimestamp(1774898552)
# TODO: just a bit after MONAD_TEN
FORK_CRITERIA: ForkCriteria = ByTimestamp(1774898553)
2 changes: 1 addition & 1 deletion src/ethereum/forks/monad_next/utils/address.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
Introduction
------------

Address specific functions used in this MONAD_NINE version of
Address specific functions used in this MONAD_NEXT version of
specification.
"""

Expand Down
2 changes: 1 addition & 1 deletion src/ethereum/forks/monad_next/utils/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
Introduction
------------

Message specific functions used in this MONAD_NINE version of
Message specific functions used in this MONAD_NEXT version of
specification.
"""

Expand Down
2 changes: 1 addition & 1 deletion src/ethereum/forks/monad_nine/utils/hexadecimal.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
------------

Hexadecimal utility functions used in this specification, specific to
Monad Next types.
Monad Nine types.
"""

from ethereum_types.bytes import Bytes
Expand Down
8 changes: 8 additions & 0 deletions src/ethereum/forks/monad_ten/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
MONAD_TEN fork introduces Monad specific changes to the Ethereum protocol.
"""

from ethereum.fork_criteria import ByTimestamp, ForkCriteria

# TODO: just a bit after MONAD_NINE
FORK_CRITERIA: ForkCriteria = ByTimestamp(1774898552)
Loading