Skip to content

Commit fa92da6

Browse files
prestwichEvalir
authored andcommitted
feat: to_plain_state (bluealloy#1778)
* feat: to_plain_state * feat: extend to reverts
1 parent 346aa01 commit fa92da6

File tree

4 files changed

+88
-25
lines changed

4 files changed

+88
-25
lines changed

crates/primitives/src/state.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,33 @@ impl AccountInfo {
272272
}
273273
}
274274

275-
/// Returns account info without the code.
275+
/// Returns a copy of this account with the [`Bytecode`] removed. This is
276+
/// useful when creating journals or snapshots of the state, where it is
277+
/// desirable to store the code blobs elsewhere.
278+
///
279+
/// ## Note
280+
///
281+
/// This is distinct from [`AccountInfo::without_code`] in that it returns
282+
/// a new `AccountInfo` instance with the code removed.
283+
/// [`AccountInfo::without_code`] will modify and return the same instance.
284+
pub fn copy_without_code(&self) -> Self {
285+
Self {
286+
balance: self.balance,
287+
nonce: self.nonce,
288+
code_hash: self.code_hash,
289+
code: None,
290+
}
291+
}
292+
293+
/// Strip the [`Bytecode`] from this account and drop it. This is
294+
/// useful when creating journals or snapshots of the state, where it is
295+
/// desirable to store the code blobs elsewhere.
296+
///
297+
/// ## Note
298+
///
299+
/// This is distinct from [`AccountInfo::copy_without_code`] in that it
300+
/// modifies the account in place. [`AccountInfo::copy_without_code`]
301+
/// will copy the non-code fields and return a new `AccountInfo` instance.
276302
pub fn without_code(mut self) -> Self {
277303
self.take_bytecode();
278304
self

crates/revm/src/db/states/bundle_state.rs

+35-14
Original file line numberDiff line numberDiff line change
@@ -583,19 +583,20 @@ impl BundleState {
583583
self.reverts.push(reverts);
584584
}
585585

586-
/// Consume the bundle state and return plain state.
587-
pub fn into_plain_state(self, is_value_known: OriginalValuesKnown) -> StateChangeset {
586+
/// Generate a [`StateChangeset`] from the bundle state without consuming
587+
/// it.
588+
pub fn to_plain_state(&self, is_value_known: OriginalValuesKnown) -> StateChangeset {
588589
// pessimistically pre-allocate assuming _all_ accounts changed.
589590
let state_len = self.state.len();
590591
let mut accounts = Vec::with_capacity(state_len);
591592
let mut storage = Vec::with_capacity(state_len);
592593

593-
for (address, account) in self.state {
594+
for (address, account) in self.state.iter() {
594595
// append account info if it is changed.
595596
let was_destroyed = account.was_destroyed();
596597
if is_value_known.is_not_known() || account.is_info_changed() {
597-
let info = account.info.map(AccountInfo::without_code);
598-
accounts.push((address, info));
598+
let info = account.info.as_ref().map(AccountInfo::copy_without_code);
599+
accounts.push((*address, info));
599600
}
600601

601602
// append storage changes
@@ -604,7 +605,7 @@ impl BundleState {
604605
// database so we can check if plain state was wiped or not.
605606
let mut account_storage_changed = Vec::with_capacity(account.storage.len());
606607

607-
for (key, slot) in account.storage {
608+
for (key, slot) in account.storage.iter().map(|(k, v)| (*k, *v)) {
608609
// If storage was destroyed that means that storage was wiped.
609610
// In that case we need to check if present storage value is different then ZERO.
610611
let destroyed_and_not_zero = was_destroyed && !slot.present_value.is_zero();
@@ -624,17 +625,19 @@ impl BundleState {
624625
if !account_storage_changed.is_empty() || was_destroyed {
625626
// append storage changes to account.
626627
storage.push(PlainStorageChangeset {
627-
address,
628+
address: *address,
628629
wipe_storage: was_destroyed,
629630
storage: account_storage_changed,
630631
});
631632
}
632633
}
634+
633635
let contracts = self
634636
.contracts
635-
.into_iter()
637+
.iter()
636638
// remove empty bytecodes
637-
.filter(|(b, _)| *b != KECCAK_EMPTY)
639+
.filter(|(b, _)| **b != KECCAK_EMPTY)
640+
.map(|(b, code)| (*b, code.clone()))
638641
.collect::<Vec<_>>();
639642
StateChangeset {
640643
accounts,
@@ -643,14 +646,32 @@ impl BundleState {
643646
}
644647
}
645648

646-
/// Consume the bundle state and split it into reverts and plain state.
649+
/// Convert the bundle state into a [`StateChangeset`].
650+
#[deprecated = "Use `to_plain_state` instead"]
651+
pub fn into_plain_state(self, is_value_known: OriginalValuesKnown) -> StateChangeset {
652+
self.to_plain_state(is_value_known)
653+
}
654+
655+
/// Generate a [`StateChangeset`] and [`PlainStateReverts`] from the bundle
656+
/// state.
657+
pub fn to_plain_state_and_reverts(
658+
&self,
659+
is_value_known: OriginalValuesKnown,
660+
) -> (StateChangeset, PlainStateReverts) {
661+
(
662+
self.to_plain_state(is_value_known),
663+
self.reverts.to_plain_state_reverts(),
664+
)
665+
}
666+
667+
/// Consume the bundle state and split it into a [`StateChangeset`] and a
668+
/// [`PlainStateReverts`].
669+
#[deprecated = "Use `to_plain_state_and_reverts` instead"]
647670
pub fn into_plain_state_and_reverts(
648-
mut self,
671+
self,
649672
is_value_known: OriginalValuesKnown,
650673
) -> (StateChangeset, PlainStateReverts) {
651-
let reverts = self.take_all_reverts();
652-
let plain_state = self.into_plain_state(is_value_known);
653-
(plain_state, reverts.into_plain_state_reverts())
674+
self.to_plain_state_and_reverts(is_value_known)
654675
}
655676

656677
/// Extend the bundle with other state

crates/revm/src/db/states/plain_account.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ impl PlainAccount {
2121
}
2222

2323
/// This type keeps track of the current value of a storage slot.
24-
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
24+
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Hash)]
2525
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2626
pub struct StorageSlot {
2727
/// The value of the storage slot before it was changed.

crates/revm/src/db/states/reverts.rs

+25-9
Original file line numberDiff line numberDiff line change
@@ -43,26 +43,34 @@ impl Reverts {
4343
self.0.extend(other.0);
4444
}
4545

46-
/// Consume reverts and create plain state reverts.
46+
/// Generate a [`PlainStateReverts`].
4747
///
4848
/// Note that account are sorted by address.
49-
pub fn into_plain_state_reverts(mut self) -> PlainStateReverts {
49+
pub fn to_plain_state_reverts(&self) -> PlainStateReverts {
5050
let mut state_reverts = PlainStateReverts::with_capacity(self.0.len());
51-
for reverts in self.0.drain(..) {
51+
for reverts in &self.0 {
5252
// pessimistically pre-allocate assuming _all_ accounts changed.
5353
let mut accounts = Vec::with_capacity(reverts.len());
5454
let mut storage = Vec::with_capacity(reverts.len());
55-
for (address, revert_account) in reverts.into_iter() {
56-
match revert_account.account {
57-
AccountInfoRevert::RevertTo(acc) => accounts.push((address, Some(acc))),
58-
AccountInfoRevert::DeleteIt => accounts.push((address, None)),
55+
for (address, revert_account) in reverts {
56+
match &revert_account.account {
57+
AccountInfoRevert::RevertTo(acc) => {
58+
// cloning is cheap, because account info has 3 small
59+
// fields and a Bytes
60+
accounts.push((*address, Some(acc.clone())))
61+
}
62+
AccountInfoRevert::DeleteIt => accounts.push((*address, None)),
5963
AccountInfoRevert::DoNothing => (),
6064
}
6165
if revert_account.wipe_storage || !revert_account.storage.is_empty() {
6266
storage.push(PlainStorageRevert {
63-
address,
67+
address: *address,
6468
wiped: revert_account.wipe_storage,
65-
storage_revert: revert_account.storage.into_iter().collect::<Vec<_>>(),
69+
storage_revert: revert_account
70+
.storage
71+
.iter()
72+
.map(|(k, v)| (*k, *v))
73+
.collect::<Vec<_>>(),
6674
});
6775
}
6876
}
@@ -71,6 +79,14 @@ impl Reverts {
7179
}
7280
state_reverts
7381
}
82+
83+
/// Consume reverts and create [`PlainStateReverts`].
84+
///
85+
/// Note that account are sorted by address.
86+
#[deprecated = "Use `to_plain_state_reverts` instead"]
87+
pub fn into_plain_state_reverts(self) -> PlainStateReverts {
88+
self.to_plain_state_reverts()
89+
}
7490
}
7591

7692
/// Assumption is that Revert can return full state from any future state to any past state.

0 commit comments

Comments
 (0)