#[non_exhaustive]pub enum StateUpdate {
Slot {
address: Address,
slot: U256,
value: U256,
},
SlotDelta {
address: Address,
slot: U256,
delta: SlotDelta,
},
BalanceDelta {
address: Address,
delta: SlotDelta,
},
SlotMasked {
address: Address,
slot: U256,
mask: U256,
value: U256,
},
Account {
address: Address,
patch: AccountPatch,
},
AccountUpsert {
address: Address,
patch: AccountPatch,
},
Purge {
address: Address,
scope: PurgeScope,
},
}Expand description
A single targeted mutation to cached EVM state.
The vocabulary an event decoder (Phase 4) emits and
EvmCache::apply_update consumes.
Generic: carries no protocol or event knowledge.
The enum is #[non_exhaustive]: new variants (e.g. a code-only convenience)
may be added pre-1.0 without a breaking change.
use alloy_primitives::{Address, U256};
use evm_fork_cache::{AccountPatch, PurgeScope, StateUpdate};
let contract = Address::repeat_byte(0x01);
// A storage-slot write (authoritative across both cache layers).
let slot = StateUpdate::slot(contract, U256::from(0), U256::from(42));
// A balance-only account patch (nonce and code left untouched).
let bal = StateUpdate::balance(contract, U256::from(1_000));
assert_eq!(
bal,
StateUpdate::Account { address: contract, patch: AccountPatch::default().balance(U256::from(1_000)) },
);
// Drop just two storage slots so the next read re-fetches them.
let purge = StateUpdate::purge(contract, PurgeScope::Slots(vec![U256::from(0), U256::from(1)]));Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Slot
Set one storage slot to value, authoritative across both cache layers.
Fields
SlotDelta
Apply a relative (saturating) mutation to one storage slot.
Read-modify-write: the current value is read, the SlotDelta applied,
and the result written back through both layers. Cold-aware — a delta
on a slot absent from both layers is not applied; it is surfaced in
StateDiff::skipped instead (see the module docs).
Fields
BalanceDelta
Apply a relative (saturating) mutation to an account’s native balance.
Read-modify-write: the current AccountInfo::balance is read, the
SlotDelta applied, and the result written back through both layers
(nonce and code preserved). Cold-aware — “cold” here means the
account’s info is unknown to the EVM: absent from both layers, or
present in the overlay as revm NotExisting (which the internal account
read also treats as cold, mirroring DbAccount::info()). A BalanceDelta
on a cold account is not applied; it is surfaced in
StateDiff::skipped_balances instead (so no default account is
materialized to mask the real on-chain one — see the module docs).
Fields
SlotMasked
Set only the mask bits of a storage slot to the corresponding bits of
value, preserving the rest: new = (old & !mask) | (value & mask).
A masked read-modify-write: it lets a pure decoder express a partial update to a packed storage word without knowing or clobbering the bits it does not own.
Cold-aware — a masked write to a slot absent from both cache layers is
not applied (the un-masked bits are unknown, so the result cannot be
computed); it is surfaced in StateDiff::skipped_masks as a
SkippedMask instead. A masked write with mask == U256::MAX equals an
absolute Slot write on a hot slot, but still skips on a
cold one (unlike Slot, which writes unconditionally). Use
Slot for an unconditional absolute write; use SlotMasked
when neighbouring bits must be preserved.
Fields
Account
Patch an already-known account’s balance/nonce/code (partial — see
AccountPatch).
Cold-aware: if the account’s info is unknown to the EVM (absent from
both layers, or present in the overlay as revm NotExisting), the patch
is not applied and is surfaced in StateDiff::skipped_accounts as a
SkippedAccountPatch. Use StateUpdate::AccountUpsert when
materializing a cold/default account is intentional.
Fields
patch: AccountPatchThe partial mutation: each Some field overwrites, None leaves it.
AccountUpsert
Apply an AccountPatch, materializing a cold account when needed.
This is the explicit escape hatch for callers that really do want a
default account to become authoritative in the backend (for example a
synthetic test account). Normal event-derived account patches should use
StateUpdate::Account so a cold account is skipped instead of masking a
future RPC fetch.
Fields
patch: AccountPatchThe partial mutation: each Some field overwrites, None leaves it.
Purge
Purge cached state for address at scope; the next read re-fetches.
Fields
scope: PurgeScopeWhat part of the cached state to remove.
Implementations§
Source§impl StateUpdate
impl StateUpdate
Sourcepub fn slot(address: Address, slot: U256, value: U256) -> Self
pub fn slot(address: Address, slot: U256, value: U256) -> Self
Construct a StateUpdate::Slot that sets (address, slot) to value.
Sourcepub fn slot_delta(address: Address, slot: U256, delta: SlotDelta) -> Self
pub fn slot_delta(address: Address, slot: U256, delta: SlotDelta) -> Self
Construct a StateUpdate::SlotDelta that applies delta relative to the
current value of (address, slot).
Sourcepub fn slot_masked(
address: Address,
slot: U256,
mask: U256,
value: U256,
) -> Self
pub fn slot_masked( address: Address, slot: U256, mask: U256, value: U256, ) -> Self
Construct a StateUpdate::SlotMasked that sets only the mask bits of
(address, slot) to the corresponding bits of value.
Sourcepub fn balance_delta(address: Address, delta: SlotDelta) -> Self
pub fn balance_delta(address: Address, delta: SlotDelta) -> Self
Construct a StateUpdate::BalanceDelta that applies delta relative to
the account’s current native balance.
Sourcepub fn balance(address: Address, value: U256) -> Self
pub fn balance(address: Address, value: U256) -> Self
Construct a StateUpdate::Account that patches only the balance.
Sourcepub fn nonce(address: Address, nonce: u64) -> Self
pub fn nonce(address: Address, nonce: u64) -> Self
Construct a StateUpdate::Account that patches only the nonce.
Sourcepub fn code(address: Address, code: Bytes) -> Self
pub fn code(address: Address, code: Bytes) -> Self
Construct a StateUpdate::Account that patches only the runtime code
(the code hash is recomputed from code when applied).
Sourcepub fn account(address: Address, patch: AccountPatch) -> Self
pub fn account(address: Address, patch: AccountPatch) -> Self
Construct a StateUpdate::Account from a prebuilt AccountPatch.
Sourcepub fn account_upsert(address: Address, patch: AccountPatch) -> Self
pub fn account_upsert(address: Address, patch: AccountPatch) -> Self
Construct a StateUpdate::AccountUpsert from a prebuilt
AccountPatch.
Use this only when materializing an account absent from both layers is the
desired behavior. For normal patches to known accounts, use
account.
Sourcepub fn purge(address: Address, scope: PurgeScope) -> Self
pub fn purge(address: Address, scope: PurgeScope) -> Self
Construct a StateUpdate::Purge for address at scope.
Trait Implementations§
Source§impl Clone for StateUpdate
impl Clone for StateUpdate
Source§fn clone(&self) -> StateUpdate
fn clone(&self) -> StateUpdate
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for StateUpdate
impl Debug for StateUpdate
Source§impl<'de> Deserialize<'de> for StateUpdate
impl<'de> Deserialize<'de> for StateUpdate
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for StateUpdate
Source§impl PartialEq for StateUpdate
impl PartialEq for StateUpdate
Source§fn eq(&self, other: &StateUpdate) -> bool
fn eq(&self, other: &StateUpdate) -> bool
self and other values to be equal, and is used by ==.Source§impl Serialize for StateUpdate
impl Serialize for StateUpdate
impl StructuralPartialEq for StateUpdate
Auto Trait Implementations§
impl !Freeze for StateUpdate
impl RefUnwindSafe for StateUpdate
impl Send for StateUpdate
impl Sync for StateUpdate
impl Unpin for StateUpdate
impl UnsafeUnpin for StateUpdate
impl UnwindSafe for StateUpdate
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<'de, T> BorrowedRpcObject<'de> for T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
impl<'de, T> RpcBorrow<'de> for T
impl<T> RpcObject for T
impl<T> RpcRecv for T
impl<T> RpcSend for T
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.