Skip to content

Commit cf4533f

Browse files
committed
Merge remote-tracking branch 'origin/main' into devnet3
2 parents 0abb42b + 99c74f2 commit cf4533f

12 files changed

Lines changed: 125 additions & 45 deletions

File tree

crates/context/interface/src/local.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,28 @@ impl<T> Default for FrameStack<T> {
1818
}
1919
}
2020

21-
impl<T: Default> FrameStack<T> {
22-
/// Creates a new stack with preallocated items by calling `T::default()` `len` times.
23-
/// Index will still be `None` until `end_init` is called.
24-
pub fn new_prealloc(len: usize) -> Self {
25-
let mut stack = Vec::with_capacity(len);
26-
for _ in 0..len {
27-
stack.push(T::default());
28-
}
29-
Self { stack, index: None }
30-
}
31-
}
32-
3321
impl<T> FrameStack<T> {
3422
/// Creates a new, empty stack. It must be initialized with init before use.
3523
pub fn new() -> Self {
36-
// Init N amount of frames to allocate the stack.
24+
// p99.9 of call frame depth is 8,
25+
// per: https://ethresear.ch/t/evm-stack-and-memory-usage-statistics-report/24209
3726
Self {
3827
stack: Vec::with_capacity(8),
3928
index: None,
4029
}
4130
}
4231

32+
/// Creates a new stack with preallocated items by calling `T::default()` `len` times.
33+
/// Index will still be `None` until `end_init` is called.
34+
pub fn new_prealloc(len: usize) -> Self
35+
where
36+
T: Default,
37+
{
38+
let mut stack = Vec::with_capacity(len);
39+
stack.resize_with(len, T::default);
40+
Self { stack, index: None }
41+
}
42+
4343
/// Initializes the stack with a single item.
4444
#[inline]
4545
pub fn start_init(&mut self) -> OutFrame<'_, T> {

crates/inspector/src/handler.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,14 @@ where
173173
/// Handles the start of a frame by calling the appropriate inspector method.
174174
pub fn frame_start<CTX, INTR: InterpreterTypes>(
175175
context: &mut CTX,
176-
inspector: &mut impl Inspector<CTX, INTR>,
176+
inspector: &mut impl Inspector<CTX, INTR, FrameInput, FrameResult>,
177177
frame_input: &mut FrameInput,
178178
) -> Option<FrameResult> {
179+
// Generic hook before variant dispatch
180+
if let Some(result) = inspector.frame_start(context, frame_input) {
181+
return Some(result);
182+
}
183+
// Variant-specific dispatch
179184
match frame_input {
180185
FrameInput::Call(i) => {
181186
if let Some(output) = inspector.call(context, i) {
@@ -195,10 +200,11 @@ pub fn frame_start<CTX, INTR: InterpreterTypes>(
195200
/// Handles the end of a frame by calling the appropriate inspector method.
196201
pub fn frame_end<CTX, INTR: InterpreterTypes>(
197202
context: &mut CTX,
198-
inspector: &mut impl Inspector<CTX, INTR>,
203+
inspector: &mut impl Inspector<CTX, INTR, FrameInput, FrameResult>,
199204
frame_input: &FrameInput,
200205
frame_output: &mut FrameResult,
201206
) {
207+
// Variant-specific dispatch first
202208
match frame_output {
203209
FrameResult::Call(outcome) => {
204210
let FrameInput::Call(i) = frame_input else {
@@ -213,6 +219,8 @@ pub fn frame_end<CTX, INTR: InterpreterTypes>(
213219
inspector.create_end(context, i, outcome);
214220
}
215221
}
222+
// Generic hook after variant dispatch
223+
inspector.frame_end(context, frame_input, frame_output);
216224
}
217225

218226
/// Run Interpreter loop with inspection support.

crates/inspector/src/inspector.rs

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use auto_impl::auto_impl;
22
use context::{Database, Journal, JournalEntry};
3+
use handler::FrameResult;
34
use interpreter::{
4-
interpreter::EthInterpreter, CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter,
5-
InterpreterTypes,
5+
interpreter::EthInterpreter, CallInputs, CallOutcome, CreateInputs, CreateOutcome, FrameInput,
6+
Interpreter, InterpreterTypes,
67
};
78
use primitives::{Address, Log, U256};
89
use state::EvmState;
@@ -14,7 +15,8 @@ use state::EvmState;
1415
/// Object that is implemented this trait is used in `InspectorHandler` to trace the EVM execution.
1516
/// And API that allow calling the inspector can be found in [`crate::InspectEvm`] and [`crate::InspectCommitEvm`].
1617
#[auto_impl(&mut, Box)]
17-
pub trait Inspector<CTX, INTR: InterpreterTypes = EthInterpreter> {
18+
pub trait Inspector<CTX, INTR: InterpreterTypes = EthInterpreter, FI = FrameInput, FR = FrameResult>
19+
{
1820
/// Called before the interpreter is initialized.
1921
///
2022
/// If `interp.bytecode.set_action` is set the execution of the interpreter is skipped.
@@ -64,6 +66,29 @@ pub trait Inspector<CTX, INTR: InterpreterTypes = EthInterpreter> {
6466
self.log(context, log);
6567
}
6668

69+
/// Called before call/create dispatch. Called with a mutable reference to
70+
/// the frame input, allowing mutations of the input before the variant-specific
71+
/// hooks (`call`/`create`) are called.
72+
///
73+
/// Returning `Some(FrameResult)` will skip execution of the frame entirely,
74+
/// and also skips calling `call()`/`create()`. `frame_end` will still be called.
75+
#[inline]
76+
fn frame_start(&mut self, context: &mut CTX, frame_input: &mut FI) -> Option<FR> {
77+
let _ = context;
78+
let _ = frame_input;
79+
None
80+
}
81+
82+
/// Called after `call_end()`/`create_end()` variant-specific hooks complete.
83+
///
84+
/// Allows transformation of the final result regardless of frame kind.
85+
#[inline]
86+
fn frame_end(&mut self, context: &mut CTX, frame_input: &FI, frame_result: &mut FR) {
87+
let _ = context;
88+
let _ = frame_input;
89+
let _ = frame_result;
90+
}
91+
6792
/// Called whenever a call to a contract is about to start.
6893
///
6994
/// Returning `CallOutcome` will override the result of the call.
@@ -122,10 +147,10 @@ pub trait Inspector<CTX, INTR: InterpreterTypes = EthInterpreter> {
122147
}
123148
}
124149

125-
impl<CTX, INTR: InterpreterTypes, L, R> Inspector<CTX, INTR> for (L, R)
150+
impl<CTX, INTR: InterpreterTypes, FI, FR, L, R> Inspector<CTX, INTR, FI, FR> for (L, R)
126151
where
127-
L: Inspector<CTX, INTR>,
128-
R: Inspector<CTX, INTR>,
152+
L: Inspector<CTX, INTR, FI, FR>,
153+
R: Inspector<CTX, INTR, FI, FR>,
129154
{
130155
fn initialize_interp(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX) {
131156
self.0.initialize_interp(interp, context);
@@ -152,6 +177,17 @@ where
152177
self.1.log_full(interp, context, log);
153178
}
154179

180+
fn frame_start(&mut self, context: &mut CTX, frame_input: &mut FI) -> Option<FR> {
181+
let first = self.0.frame_start(context, frame_input);
182+
let second = self.1.frame_start(context, frame_input);
183+
first.or(second)
184+
}
185+
186+
fn frame_end(&mut self, context: &mut CTX, frame_input: &FI, frame_result: &mut FR) {
187+
self.0.frame_end(context, frame_input, frame_result);
188+
self.1.frame_end(context, frame_input, frame_result);
189+
}
190+
155191
fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
156192
let first = self.0.call(context, inputs);
157193
let second = self.1.call(context, inputs);

crates/inspector/src/traits.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use handler::{
55
EthFrame, EvmTr, FrameInitOrResult, FrameResult, ItemOrResult,
66
};
77
use interpreter::{
8-
interpreter::EthInterpreter, interpreter_action::FrameInit, CallOutcome, InterpreterTypes,
8+
interpreter::EthInterpreter, interpreter_action::FrameInit, CallOutcome, FrameInput,
9+
InterpreterTypes,
910
};
1011

1112
use crate::{
@@ -26,7 +27,7 @@ pub trait InspectorEvmTr:
2627
>
2728
{
2829
/// The inspector type used for EVM execution inspection.
29-
type Inspector: Inspector<Self::Context, EthInterpreter>;
30+
type Inspector: Inspector<Self::Context, EthInterpreter, FrameInput, FrameResult>;
3031

3132
/// Returns a tuple of mutable references to the context, the inspector, the frame and the instructions.
3233
///
@@ -118,7 +119,7 @@ pub trait InspectorEvmTr:
118119
{
119120
if *was_precompile_called {
120121
let logs = ctx.journal_mut().logs()[logs_i..].to_vec();
121-
for log in logs.iter().chain(precompile_call_logs.iter()).cloned() {
122+
for log in logs.into_iter().chain(precompile_call_logs.iter().cloned()) {
122123
inspector.log(ctx, log);
123124
}
124125
}

crates/precompile/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ criterion.workspace = true
7474
rand = { workspace = true, features = ["std"] }
7575
ark-std = { workspace = true }
7676
rstest.workspace = true
77+
p256 = { workspace = true, features = ["ecdsa"] }
7778

7879
[features]
7980
default = ["std", "secp256k1", "blst", "c-kzg", "portable"]

crates/precompile/bench/blake2.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ pub fn add_benches(group: &mut BenchmarkGroup<'_, criterion::measurement::WallTi
107107
blake2::algo::compress(
108108
black_box(12),
109109
&mut h_copy,
110-
black_box(m),
111-
black_box(t),
110+
&black_box(m),
111+
&black_box(t),
112112
black_box(false),
113113
);
114114
});

crates/precompile/bench/main.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub mod ecrecover;
66
pub mod eip1962;
77
pub mod eip2537;
88
pub mod eip4844;
9+
pub mod secp256r1;
910

1011
use criterion::{criterion_group, criterion_main, Criterion};
1112

@@ -35,6 +36,9 @@ pub fn benchmark_crypto_precompiles(c: &mut Criterion) {
3536

3637
// Run Blake2 benchmarks
3738
blake2::add_benches(&mut group);
39+
40+
// Run secp256r1 benchmarks
41+
secp256r1::add_benches(&mut group);
3842
}
3943

4044
criterion_group! {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//! Benchmarks for the secp256r1 (P256) precompile
2+
use criterion::{measurement::Measurement, BenchmarkGroup};
3+
use p256::ecdsa::{signature::hazmat::PrehashSigner, SigningKey};
4+
use primitives::Bytes;
5+
use revm_precompile::secp256r1::p256_verify;
6+
7+
/// Add benches for the secp256r1 precompile
8+
pub fn add_benches<M: Measurement>(group: &mut BenchmarkGroup<'_, M>) {
9+
// Generate a valid P256 signature using p256's own OsRng (rand_core 0.6)
10+
let signing_key = SigningKey::random(&mut p256::elliptic_curve::rand_core::OsRng);
11+
let verifying_key = signing_key.verifying_key();
12+
13+
let msg_hash = [0xabu8; 32];
14+
15+
let (signature, _) = signing_key.sign_prehash(&msg_hash).unwrap();
16+
let sig_bytes = signature.to_bytes();
17+
18+
let pk_encoded = verifying_key.to_encoded_point(false);
19+
// Uncompressed point is 0x04 || x || y, skip the 0x04 prefix
20+
let pk_bytes = &pk_encoded.as_bytes()[1..];
21+
22+
// Input layout: msg_hash (32) || r (32) || s (32) || pubkey_x (32) || pubkey_y (32)
23+
let mut input = Vec::with_capacity(160);
24+
input.extend_from_slice(&msg_hash);
25+
input.extend_from_slice(&sig_bytes);
26+
input.extend_from_slice(pk_bytes);
27+
28+
let input = Bytes::from(input);
29+
30+
group.bench_function("p256verify precompile", |b| {
31+
b.iter(|| p256_verify(&input, u64::MAX).unwrap())
32+
});
33+
}

crates/precompile/src/blake2.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub fn run(input: &[u8], gas_limit: u64) -> PrecompileResult {
5454
let t_0 = u64::from_le_bytes(input[196..204].try_into().unwrap());
5555
let t_1 = u64::from_le_bytes(input[204..212].try_into().unwrap());
5656

57-
crypto().blake2_compress(rounds, &mut h, m, [t_0, t_1], f);
57+
crypto().blake2_compress(rounds, &mut h, &m, &[t_0, t_1], f);
5858

5959
let mut out = [0u8; 64];
6060
for (i, h) in (0..64).step_by(8).zip(h.iter()) {
@@ -124,7 +124,7 @@ pub mod algo {
124124
/// returns a new state vector. The number of rounds, "r", is 12 for
125125
/// BLAKE2b and 10 for BLAKE2s. Rounds are numbered from 0 to r - 1.
126126
#[allow(clippy::many_single_char_names)]
127-
pub fn compress(rounds: usize, h: &mut [u64; 8], m: [u64; 16], t: [u64; 2], f: bool) {
127+
pub fn compress(rounds: usize, h: &mut [u64; 8], m: &[u64; 16], t: &[u64; 2], f: bool) {
128128
#[cfg(all(target_feature = "avx2", feature = "std"))]
129129
{
130130
// only if it is compiled with avx2 flag and it is std, we can use avx2.
@@ -133,7 +133,7 @@ pub mod algo {
133133
unsafe {
134134
super::avx2::compress_block(
135135
rounds,
136-
&m,
136+
m,
137137
h,
138138
((t[1] as u128) << 64) | (t[0] as u128),
139139
if f { !0 } else { 0 },
@@ -157,7 +157,7 @@ pub mod algo {
157157
v[14] = !v[14] // Invert all bits if the last-block-flag is set.
158158
}
159159
for i in 0..rounds {
160-
round(&mut v, &m, i);
160+
round(&mut v, m, i);
161161
}
162162

163163
for i in 0..8 {

crates/precompile/src/interface.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ pub trait Crypto: Send + Sync + Debug {
8989
recid: u8,
9090
msg: &[u8; 32],
9191
) -> Result<[u8; 32], PrecompileError> {
92-
crate::secp256k1::ecrecover_bytes(*sig, recid, *msg)
92+
crate::secp256k1::ecrecover_bytes(sig, recid, msg)
9393
.ok_or(PrecompileError::Secp256k1RecoverFailed)
9494
}
9595

@@ -101,14 +101,14 @@ pub trait Crypto: Send + Sync + Debug {
101101

102102
/// Blake2 compression function.
103103
#[inline]
104-
fn blake2_compress(&self, rounds: u32, h: &mut [u64; 8], m: [u64; 16], t: [u64; 2], f: bool) {
104+
fn blake2_compress(&self, rounds: u32, h: &mut [u64; 8], m: &[u64; 16], t: &[u64; 2], f: bool) {
105105
crate::blake2::algo::compress(rounds as usize, h, m, t, f);
106106
}
107107

108108
/// secp256r1 (P-256) signature verification.
109109
#[inline]
110110
fn secp256r1_verify_signature(&self, msg: &[u8; 32], sig: &[u8; 64], pk: &[u8; 64]) -> bool {
111-
crate::secp256r1::verify_signature(*msg, *sig, *pk).is_some()
111+
crate::secp256r1::verify_signature(msg, sig, pk).is_some()
112112
}
113113

114114
/// KZG point evaluation.

0 commit comments

Comments
 (0)