Skip to content

Commit 95d8779

Browse files
feat: reject all block overwrites
1 parent cfd7699 commit 95d8779

2 files changed

Lines changed: 83 additions & 27 deletions

File tree

crates/evm/src/overrides.rs

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use revm::{
2020

2121
/// Errors that can occur when applying state overrides.
2222
#[derive(Debug, thiserror::Error)]
23-
pub enum StateOverrideError<E> {
23+
pub enum OverrideError<E> {
2424
/// Invalid bytecode provided in override.
2525
#[error(transparent)]
2626
InvalidBytecode(#[from] BytecodeDecodeError),
@@ -33,6 +33,9 @@ pub enum StateOverrideError<E> {
3333
/// Storage overrides (state/stateDiff) are not permitted (Seismic privacy).
3434
#[error("Storage overrides are not permitted on Seismic (account: {0})")]
3535
StorageOverrideNotPermitted(Address),
36+
/// Block overrides are not permitted.
37+
#[error("Block overrides are not permitted")]
38+
BlockOverrideNotPermitted,
3639
/// Database error occurred.
3740
#[error(transparent)]
3841
Database(E),
@@ -46,11 +49,15 @@ pub trait OverrideBlockHashes {
4649
fn override_block_hashes(&mut self, block_hashes: BTreeMap<u64, B256>);
4750

4851
/// Applies the given block overrides to the env and updates overridden block hashes.
49-
fn apply_block_overrides(&mut self, overrides: BlockOverrides, env: &mut BlockEnv)
52+
fn apply_block_overrides(
53+
&mut self,
54+
overrides: BlockOverrides,
55+
env: &mut BlockEnv,
56+
) -> Result<(), OverrideError<Self::Error>>
5057
where
51-
Self: Sized,
58+
Self: Sized + Database,
5259
{
53-
apply_block_overrides(overrides, self, env);
60+
apply_block_overrides(overrides, self, env)
5461
}
5562
}
5663

@@ -69,10 +76,20 @@ impl<DB> OverrideBlockHashes for State<DB> {
6976
}
7077

7178
/// Applies the given block overrides to the env and updates overridden block hashes in the db.
72-
pub fn apply_block_overrides<DB>(overrides: BlockOverrides, db: &mut DB, env: &mut BlockEnv)
79+
///
80+
/// The overrides are first validated by
81+
/// [`crate::seismic_security::validate_block_overrides`], which currently
82+
/// rejects all block overrides on Seismic.
83+
pub fn apply_block_overrides<DB>(
84+
overrides: BlockOverrides,
85+
db: &mut DB,
86+
env: &mut BlockEnv,
87+
) -> Result<(), OverrideError<DB::Error>>
7388
where
74-
DB: OverrideBlockHashes,
89+
DB: Database + OverrideBlockHashes,
7590
{
91+
let overrides = seismic_security::validate_block_overrides(&overrides, db)?;
92+
7693
let BlockOverrides {
7794
number,
7895
difficulty,
@@ -110,13 +127,15 @@ where
110127
if let Some(base_fee) = base_fee {
111128
env.basefee = base_fee.saturating_to();
112129
}
130+
131+
Ok(())
113132
}
114133

115134
/// Applies the given state overrides (a set of [`AccountOverride`]) to the database.
116135
pub fn apply_state_overrides<DB>(
117136
overrides: StateOverride,
118137
db: &mut DB,
119-
) -> Result<(), StateOverrideError<DB::Error>>
138+
) -> Result<(), OverrideError<DB::Error>>
120139
where
121140
DB: Database + DatabaseCommit,
122141
{
@@ -138,11 +157,11 @@ fn apply_account_override<DB>(
138157
account: Address,
139158
account_override: AccountOverride,
140159
db: &mut DB,
141-
) -> Result<(), StateOverrideError<DB::Error>>
160+
) -> Result<(), OverrideError<DB::Error>>
142161
where
143162
DB: Database + DatabaseCommit,
144163
{
145-
let mut info = db.basic(account).map_err(StateOverrideError::Database)?.unwrap_or_default();
164+
let mut info = db.basic(account).map_err(OverrideError::Database)?.unwrap_or_default();
146165

147166
if let Some(nonce) = account_override.nonce {
148167
info.nonce = nonce;
@@ -182,7 +201,7 @@ mod tests {
182201
let acc_override = AccountOverride::default().with_code(code.clone());
183202
let result = apply_state_overrides(StateOverride::from_iter([(to, acc_override)]), &mut db);
184203
assert!(
185-
matches!(result, Err(StateOverrideError::CodeOverrideNotPermitted(_))),
204+
matches!(result, Err(OverrideError::CodeOverrideNotPermitted(_))),
186205
"Code overrides should be rejected"
187206
);
188207
}
@@ -199,7 +218,7 @@ mod tests {
199218
let acc_override = AccountOverride::default().with_code(code.clone());
200219
let result = apply_state_overrides(StateOverride::from_iter([(to, acc_override)]), &mut db);
201220
assert!(
202-
matches!(result, Err(StateOverrideError::CodeOverrideNotPermitted(_))),
221+
matches!(result, Err(OverrideError::CodeOverrideNotPermitted(_))),
203222
"Code overrides should be rejected"
204223
);
205224
}
@@ -238,4 +257,41 @@ mod tests {
238257
let result = apply_state_overrides(state_overrides, &mut db);
239258
assert!(result.is_err(), "state overrides should be rejected");
240259
}
260+
261+
#[test]
262+
fn test_block_overrides_rejected_cache_db() {
263+
let mut db = CacheDB::new(EmptyDB::new());
264+
let mut env = BlockEnv::default();
265+
let original_env = env.clone();
266+
267+
let overrides = BlockOverrides {
268+
time: Some(12345),
269+
number: Some(U256::from(100)),
270+
block_hash: Some(BTreeMap::from_iter([(1u64, B256::from(U256::from(42)))])),
271+
..Default::default()
272+
};
273+
let result = apply_block_overrides(overrides, &mut db, &mut env);
274+
assert!(
275+
matches!(result, Err(OverrideError::BlockOverrideNotPermitted)),
276+
"block overrides should be rejected"
277+
);
278+
assert_eq!(env, original_env, "env must not be modified");
279+
assert!(db.cache.block_hashes.is_empty(), "block hashes must not be overridden");
280+
}
281+
282+
#[test]
283+
fn test_block_overrides_rejected_state_db() {
284+
let mut db = State::builder().with_database(CacheDB::new(EmptyDB::new())).build();
285+
let mut env = BlockEnv::default();
286+
let original_env = env.clone();
287+
288+
let overrides = BlockOverrides { gas_limit: Some(1), ..Default::default() };
289+
let result = db.apply_block_overrides(overrides, &mut env);
290+
assert!(
291+
matches!(result, Err(OverrideError::BlockOverrideNotPermitted)),
292+
"block overrides should be rejected"
293+
);
294+
assert_eq!(env, original_env, "env must not be modified");
295+
assert!(db.block_hashes.is_empty(), "block hashes must not be overridden");
296+
}
241297
}

crates/evm/src/seismic_security.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
//! code, storage slots) are rejected with an explicit error rather than
99
//! silently filtered..
1010
11-
use crate::overrides::StateOverrideError;
11+
use crate::overrides::OverrideError;
1212
use alloy_primitives::Address;
1313
use alloy_rpc_types_eth::{state::AccountOverride, BlockOverrides};
1414
use revm::Database;
@@ -26,40 +26,40 @@ pub fn validate_account_override<DB>(
2626
account: Address,
2727
account_override: &AccountOverride,
2828
_db: &DB,
29-
) -> Result<AccountOverride, StateOverrideError<DB::Error>>
29+
) -> Result<AccountOverride, OverrideError<DB::Error>>
3030
where
3131
DB: Database,
3232
{
3333
// CHECK: Ensure that the account override does not override contract code.
3434
// Allowing code overrides could lead to arbitrary code executing at the
3535
// account address, disclosing shielded storage.
3636
if account_override.code.is_some() {
37-
return Err(StateOverrideError::CodeOverrideNotPermitted(account));
37+
return Err(OverrideError::CodeOverrideNotPermitted(account));
3838
}
3939

4040
// CHECK: Ensure that the account override does not override storage, which
4141
// could lead to manipulating contract state (e.g. access-control slots) to
4242
// disclose shielded storage.
4343
if account_override.state.is_some() || account_override.state_diff.is_some() {
44-
return Err(StateOverrideError::StorageOverrideNotPermitted(account));
44+
return Err(OverrideError::StorageOverrideNotPermitted(account));
4545
}
4646

4747
Ok(account_override.clone())
4848
}
4949

5050
/// Validates the given block overrides.
5151
///
52-
/// Currently a pass-through: no block override field gates access to shielded
53-
/// data. This is the hook point for future block-level policy (e.g. clamping
54-
/// timestamp or gas-limit manipulation).
52+
/// Block overrides are not permitted on Seismic: manipulating block context
53+
/// (e.g. timestamp, number, prevrandao) could be used to trick contracts into
54+
/// disclosing shielded storage.
5555
pub fn validate_block_overrides<DB>(
56-
overrides: &BlockOverrides,
56+
_overrides: &BlockOverrides,
5757
_db: &DB,
58-
) -> Result<BlockOverrides, StateOverrideError<DB::Error>>
58+
) -> Result<BlockOverrides, OverrideError<DB::Error>>
5959
where
6060
DB: Database,
6161
{
62-
Ok(overrides.clone())
62+
Err(OverrideError::BlockOverrideNotPermitted)
6363
}
6464

6565
#[cfg(test)]
@@ -75,7 +75,7 @@ mod tests {
7575
let db = CacheDB::new(EmptyDB::new());
7676
let acc_override = AccountOverride::default().with_code(bytes!("0x60016001"));
7777
let result = validate_account_override(ACCOUNT, &acc_override, &db);
78-
assert!(matches!(result, Err(StateOverrideError::CodeOverrideNotPermitted(_))));
78+
assert!(matches!(result, Err(OverrideError::CodeOverrideNotPermitted(_))));
7979
}
8080

8181
#[test]
@@ -86,18 +86,18 @@ mod tests {
8686

8787
let state_override = AccountOverride::default().with_state(storage.clone());
8888
let result = validate_account_override(ACCOUNT, &state_override, &db);
89-
assert!(matches!(result, Err(StateOverrideError::StorageOverrideNotPermitted(_))));
89+
assert!(matches!(result, Err(OverrideError::StorageOverrideNotPermitted(_))));
9090

9191
let diff_override = AccountOverride::default().with_state_diff(storage);
9292
let result = validate_account_override(ACCOUNT, &diff_override, &db);
93-
assert!(matches!(result, Err(StateOverrideError::StorageOverrideNotPermitted(_))));
93+
assert!(matches!(result, Err(OverrideError::StorageOverrideNotPermitted(_))));
9494
}
9595

9696
#[test]
97-
fn block_overrides_pass_through() {
97+
fn block_overrides_rejected() {
9898
let db = CacheDB::new(EmptyDB::new());
9999
let overrides = BlockOverrides { time: Some(12345), ..Default::default() };
100-
let validated = validate_block_overrides(&overrides, &db).unwrap();
101-
assert_eq!(validated.time, Some(12345));
100+
let result = validate_block_overrides(&overrides, &db);
101+
assert!(matches!(result, Err(OverrideError::BlockOverrideNotPermitted)));
102102
}
103103
}

0 commit comments

Comments
 (0)