Skip to content

Commit 22a4057

Browse files
committed
Added system_call logic
1 parent 3af9dd3 commit 22a4057

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

evm/src/executor/stack/executor.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,46 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet>
835835
}
836836
}
837837

838+
/// Execute a system-level call as defined by EIP-4788, EIP-2935, EIP-7002, EIP-7251,
839+
/// and future EIPs.
840+
///
841+
/// System calls are made by the protocol itself at the start of each block, before any user
842+
/// transactions are processed. They follow the call semantics of a regular `CALL` with these
843+
/// specific properties:
844+
/// - `caller` is the protocol-defined `SYSTEM_ADDRESS` (`0xfffffffffffffffffffffffffffffffffffffffe`).
845+
/// - `value` is always zero — no ETH is transferred.
846+
/// - `address` — the system contract to call (e.g. the `beacon_root` or `blockhash` contract).
847+
/// - `data` — ABI-encoded call data passed to the system contract.
848+
/// - **Gas limit** is implicitly inherited from the executor's `metadata`. According to EIPs,
849+
/// the host must initialize the executor with exactly `30_000_000` gas prior to this call.
850+
///
851+
/// Additional behavioral overrides:
852+
/// - No `Transfer` is performed: balance checks on the caller are skipped entirely.
853+
/// - The caller's nonce is not incremented, and no base transaction cost is recorded.
854+
/// - The call is not static, meaning the callee can freely modify the state.
855+
pub fn system_call(
856+
&mut self,
857+
caller: H160,
858+
address: H160,
859+
data: Vec<u8>,
860+
) -> (ExitReason, Vec<u8>) {
861+
let context = Context {
862+
caller,
863+
address,
864+
apparent_value: U256::zero(),
865+
};
866+
867+
match self.call_inner(address, None, data, None, false, false, false, context) {
868+
Capture::Exit((s, v)) => emit_exit!(s, v),
869+
Capture::Trap(rt) => {
870+
let mut cs: SmallVec<[TaggedRuntime<'_>; DEFAULT_CALL_STACK_CAPACITY]> =
871+
smallvec!(rt.0);
872+
let (s, _, v) = self.execute_with_call_stack(&mut cs);
873+
emit_exit!(s, v)
874+
}
875+
}
876+
}
877+
838878
/// Get used gas for the current executor, given the price.
839879
pub fn used_gas(&self) -> u64 {
840880
// Avoid uncontrolled `u64` casting

0 commit comments

Comments
 (0)