Skip to content
Open
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
11 changes: 7 additions & 4 deletions EVM.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ Implemented in this workspace:
lists passed through to `revm` for Prague execution.
- [EIP-4788][eip-4788] beacon roots predeploy and pre-block system-call update.
Casper stores the parent Casper block hash as the root value.
- [EIP-2935][eip-2935] block-hash history predeploy and pre-block
system-call update. Casper stores parent Casper block hashes in the
8191-slot history ring buffer.

Implemented in the sidecar workspace for validation:

Expand Down Expand Up @@ -102,7 +105,7 @@ Ethereum JSON-RPC method names below refer to the Ethereum
| --- | --- | --- |
| `EvmSpec::Prague` / `revm::SpecId::PRAGUE` | Implemented. | Execution behavior is delegated to `revm`; Casper does not maintain its own EVM interpreter. |
| [EIP-2537][eip-2537] BLS12-381 precompiles | Delegated to `revm`. | Expected at `0x0b` through `0x11`, but Casper-owned conformance tests are still needed for gas costs, malformed input, subgroup checks, and failure behavior. |
| [EIP-2935][eip-2935] block-hash history contract | Missing. | Current `BLOCKHASH` uses a recent Casper block-hash provider only. Full compatibility needs the history contract at `0x0000F90827F1C53a10cb7A02335B175320002935`, a pre-block system call, and the 8191-entry ring buffer. |
| [EIP-2935][eip-2935] block-hash history contract | Implemented. | Standard address, bytecode, interface, and system-call update path are present. Casper stores parent Casper block hashes; `BLOCKHASH` opcode semantics remain unchanged. |
| [EIP-4788][eip-4788] beacon roots contract | Implemented. | Standard address, bytecode, interface, and system-call update path are present, but `parentBeaconBlockRoot := parent Casper block hash`, not an Ethereum beacon block root. |
| [EIP-6110][eip-6110] validator deposit requests | Missing / decision needed. | Ethereum-specific deposit-log-to-request flow. Full support requires [EIP-7685][eip-7685] request construction and commitment. |
| [EIP-7002][eip-7002] withdrawal request predeploy | Missing / decision needed. | Contract-visible predeploy at `0x00000961Ef480Eb55e80D19ad83579A64c007002` is absent. Full support requires queue/fee state, post-block extraction, and [EIP-7685][eip-7685] request output. |
Expand All @@ -128,7 +131,7 @@ Ethereum JSON-RPC method names below refer to the Ethereum
| EVM bytecode storage | Implemented. | Runtime bytecode is stored as `ByteCodeKind::EvmPrague`; future bytecode-affecting forks should add new bytecode kinds. |
| EVM storage slots | Implemented. | Slots are Casper `U256` values under `Key::Evm(EvmAddr::Storage(..))`; zero writes prune state. |
| Logs and receipts | Implemented. | Node stores EVM receipts/logs; sidecar computes Ethereum-style blooms and receipt roots from stored EVM receipts. Blob receipts are absent. |
| `BLOCKHASH` opcode | Partial. | Recent Casper block hashes are available through a node-supplied provider. This is not [EIP-2935][eip-2935] history-contract state. |
| `BLOCKHASH` opcode | Implemented with Casper semantics. | Recent Casper block hashes are available through a node-supplied provider. This remains separate from [EIP-2935][eip-2935] history-contract state. |
| `NUMBER`, `TIMESTAMP`, `GASLIMIT`, `BASEFEE` | Implemented. | Timestamp is Casper block time in seconds. Base fee is chainspec-configured and wei-denominated through `wei_per_mote`, not Ethereum's dynamic base-fee adjustment. |
| `COINBASE` | Implemented with Casper semantics. | The address is derived from the Casper block proposer public key. |
| `CHAINID` | Implemented. | Transaction chain ID is enforced against chainspec `[evm].chain_id`. |
Expand Down Expand Up @@ -187,8 +190,8 @@ This gives contracts a deterministic consensus-root oracle for Casper. It is
not strict Ethereum beacon-chain semantics. The detailed, audited compatibility
matrix is in [Current Status](#current-status).

The highest-priority smart-contract-visible gaps after EIP-4788 are
[EIP-2935][eip-2935], request predeploy decisions for [EIP-7002][eip-7002] and
The highest-priority smart-contract-visible gaps after EIP-4788 and
EIP-2935 are request predeploy decisions for [EIP-7002][eip-7002] and
[EIP-7251][eip-7251], and explicit Prague conformance coverage for
[EIP-2537][eip-2537], [EIP-7623][eip-7623], and [EIP-7702][eip-7702].

Expand Down
111 changes: 111 additions & 0 deletions executor/evm/tests/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,117 @@ fn user_call_does_not_update_eip4788_beacon_roots() {
assert_eq!(query.output, system_root);
}

#[test]
fn system_call_updates_eip2935_block_hash_history() {
let executor = executor(EvmSpec::Prague);
let (mut tracking_copy, _tempdir) = tracking_copy();
let parent_hash = [0xab; evm::HASH_LENGTH];

seed_evm_code(
&mut tracking_copy,
evm::BLOCK_HASH_HISTORY_ADDRESS,
evm::BLOCK_HASH_HISTORY_CODE.to_vec(),
);

let outcome = executor
.execute_system_call(
&mut tracking_copy,
SystemCallRequest {
block: block(),
target: evm::BLOCK_HASH_HISTORY_ADDRESS,
input: parent_hash.to_vec(),
},
)
.expect("EVM system call should execute");

assert_eq!(outcome.status, ExecutionStatus::Success);
let query = execute_call(
&executor,
&mut tracking_copy,
evm::Address::ZERO,
Some(evm::BLOCK_HASH_HISTORY_ADDRESS),
word(0).to_vec(),
);
assert_eq!(query.output, parent_hash);
}

#[test]
fn eip2935_current_or_future_block_reverts() {
let executor = executor(EvmSpec::Prague);
let (mut tracking_copy, _tempdir) = tracking_copy();

seed_evm_code(
&mut tracking_copy,
evm::BLOCK_HASH_HISTORY_ADDRESS,
evm::BLOCK_HASH_HISTORY_CODE.to_vec(),
);

let outcome = executor
.execute(
&mut tracking_copy,
call_request(
evm::Address::ZERO,
Some(evm::BLOCK_HASH_HISTORY_ADDRESS),
word(block().number).to_vec(),
CasperU256::zero(),
),
)
.expect("EVM call should execute");

assert_eq!(outcome.status, ExecutionStatus::Revert);
}

#[test]
fn eip2935_too_old_block_reverts() {
let executor = executor(EvmSpec::Prague);
let (mut tracking_copy, _tempdir) = tracking_copy();

seed_evm_code(
&mut tracking_copy,
evm::BLOCK_HASH_HISTORY_ADDRESS,
evm::BLOCK_HASH_HISTORY_CODE.to_vec(),
);

let mut request = call_request(
evm::Address::ZERO,
Some(evm::BLOCK_HASH_HISTORY_ADDRESS),
word(0).to_vec(),
CasperU256::zero(),
);
request.block.number = 8_192;
let outcome = executor
.execute(&mut tracking_copy, request)
.expect("EVM call should execute");

assert_eq!(outcome.status, ExecutionStatus::Revert);
}

#[test]
fn eip2935_invalid_calldata_length_reverts() {
let executor = executor(EvmSpec::Prague);
let (mut tracking_copy, _tempdir) = tracking_copy();

seed_evm_code(
&mut tracking_copy,
evm::BLOCK_HASH_HISTORY_ADDRESS,
evm::BLOCK_HASH_HISTORY_CODE.to_vec(),
);

let outcome = executor
.execute(
&mut tracking_copy,
call_request(
evm::Address::ZERO,
Some(evm::BLOCK_HASH_HISTORY_ADDRESS),
vec![0; evm::HASH_LENGTH - 1],
CasperU256::zero(),
),
)
.expect("EVM call should execute");

assert_eq!(outcome.status, ExecutionStatus::Revert);
}

#[test]
fn blockhash_uses_supplied_provider() {
let executor = executor(EvmSpec::Prague);
Expand Down
Loading
Loading