Skip to content

Commit 21f33a7

Browse files
authored
feat: traits for things that behave like State (#85)
* feat: traits for things that behave like State * chore: version * doc: add note
1 parent f83eed9 commit 21f33a7

File tree

9 files changed

+370
-99
lines changed

9 files changed

+370
-99
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "trevm"
3-
version = "0.19.8"
3+
version = "0.19.9"
44
rust-version = "1.83.0"
55
edition = "2021"
66
authors = ["init4"]
@@ -35,6 +35,7 @@ zenith-types = { version = "0.15" }
3535

3636
dashmap = { version = "6.1.0", optional = true }
3737
tracing = { version = "0.1.41", optional = true}
38+
thiserror = "2.0.11"
3839

3940
[dev-dependencies]
4041
revm = { version = "19.5.0", features = [

src/db/mod.rs

Lines changed: 6 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,7 @@
1-
mod builder;
1+
/// Concurrent version of [`revm::db::State`]
2+
#[cfg(feature = "concurrent-db")]
3+
pub mod sync;
24

3-
use alloy::rpc::types::BlockOverrides;
4-
pub use builder::ConcurrentStateBuilder;
5-
6-
mod cache_state;
7-
pub use cache_state::ConcurrentCacheState;
8-
9-
mod sync_state;
10-
pub use sync_state::{ConcurrentState, ConcurrentStateInfo};
11-
12-
use crate::{Block, EvmNeedsBlock, EvmNeedsTx, Trevm};
13-
use revm::{
14-
db::{states::bundle_state::BundleRetention, BundleState},
15-
DatabaseRef,
16-
};
17-
18-
impl<Ext, Db: DatabaseRef + Sync, TrevmState> Trevm<'_, Ext, ConcurrentState<Db>, TrevmState> {
19-
/// Set the [EIP-161] state clear flag, activated in the Spurious Dragon
20-
/// hardfork.
21-
///
22-
/// This function changes the behavior of the inner [`ConcurrentState`].
23-
pub fn set_state_clear_flag(&mut self, flag: bool) {
24-
self.inner.db_mut().set_state_clear_flag(flag)
25-
}
26-
}
27-
28-
impl<Ext, Db: DatabaseRef + Sync> EvmNeedsBlock<'_, Ext, ConcurrentState<Db>> {
29-
/// Finish execution and return the outputs.
30-
///
31-
/// If the State has not been built with
32-
/// [revm::StateBuilder::with_bundle_update] then the returned
33-
/// [`BundleState`] will be meaningless.
34-
///
35-
/// See [`ConcurrentState::merge_transitions`] and
36-
/// [`ConcurrentState::take_bundle`].
37-
pub fn finish(self) -> BundleState {
38-
let Self { inner: mut evm, .. } = self;
39-
evm.db_mut().merge_transitions(BundleRetention::Reverts);
40-
let bundle = evm.db_mut().take_bundle();
41-
42-
bundle
43-
}
44-
}
45-
46-
impl<Ext, Db: DatabaseRef + Sync> EvmNeedsTx<'_, Ext, ConcurrentState<Db>> {
47-
/// Apply block overrides to the current block.
48-
///
49-
/// Note that this is NOT reversible. The overrides are applied directly to
50-
/// the underlying state and these changes cannot be removed. If it is
51-
/// important that you have access to the pre-change state, you should wrap
52-
/// the existing DB in a new [`ConcurrentState`] and apply the overrides to
53-
/// that.
54-
pub fn apply_block_overrides(mut self, overrides: &BlockOverrides) -> Self {
55-
overrides.fill_block(&mut self.inner);
56-
57-
if let Some(hashes) = &overrides.block_hash {
58-
self.inner.db_mut().info.block_hashes.write().unwrap().extend(hashes)
59-
}
60-
61-
self
62-
}
63-
64-
/// Apply block overrides to the current block, if they are provided.
65-
///
66-
/// Note that this is NOT reversible. The overrides are applied directly to
67-
/// the underlying state and these changes cannot be removed. If it is
68-
/// important that you have access to the pre-change state, you should wrap
69-
/// the existing DB in a new [`ConcurrentState`] and apply the overrides to
70-
/// that.
71-
pub fn maybe_apply_block_overrides(self, overrides: Option<&BlockOverrides>) -> Self {
72-
if let Some(overrides) = overrides {
73-
self.apply_block_overrides(overrides)
74-
} else {
75-
self
76-
}
77-
}
78-
}
5+
/// Database abstraction traits.
6+
mod traits;
7+
pub use traits::{ArcUpgradeError, StateAcc, TryDatabaseCommit, TryStateAcc};

src/db/builder.rs renamed to src/db/sync/builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::db::ConcurrentState;
1+
use crate::db::sync::ConcurrentState;
22
use revm::{
33
db::{
44
states::{BundleState, TransitionState},
File renamed without changes.

src/db/sync/mod.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
mod builder;
2+
3+
pub use builder::ConcurrentStateBuilder;
4+
5+
mod cache;
6+
pub use cache::ConcurrentCacheState;
7+
8+
mod state;
9+
pub use state::{ConcurrentState, ConcurrentStateInfo};
10+
11+
use crate::db::StateAcc;
12+
use revm::{
13+
db::{states::bundle_state::BundleRetention, BundleState},
14+
primitives::B256,
15+
DatabaseRef,
16+
};
17+
use std::collections::BTreeMap;
18+
19+
impl<Db: DatabaseRef + Sync> StateAcc for ConcurrentState<Db> {
20+
fn set_state_clear_flag(&mut self, flag: bool) {
21+
Self::set_state_clear_flag(self, flag)
22+
}
23+
24+
fn merge_transitions(&mut self, retention: BundleRetention) {
25+
Self::merge_transitions(self, retention)
26+
}
27+
28+
fn take_bundle(&mut self) -> BundleState {
29+
Self::take_bundle(self)
30+
}
31+
32+
fn set_block_hashes(&mut self, block_hashes: &BTreeMap<u64, B256>) {
33+
self.info.block_hashes.write().unwrap().extend(block_hashes)
34+
}
35+
}

src/db/sync_state.rs renamed to src/db/sync/state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::db::ConcurrentCacheState;
1+
use crate::db::sync::ConcurrentCacheState;
22
use alloy::primitives::{Address, B256, U256};
33
use dashmap::mapref::one::RefMut;
44
use revm::{

src/db/traits.rs

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
use revm::{
2+
db::{states::bundle_state::BundleRetention, BundleState, State},
3+
primitives::{Account, Address, B256},
4+
Database, DatabaseCommit,
5+
};
6+
use std::{collections::BTreeMap, convert::Infallible, sync::Arc};
7+
8+
/// Abstraction trait covering types that accumulate state changes into a
9+
/// [`BundleState`]. The prime example of this is [`State`]. These types are
10+
/// use to accumulate state changes during the execution of a sequence of
11+
/// transactions, and then provide access to the net changes in the form of a
12+
/// [`BundleState`].
13+
pub trait StateAcc {
14+
/// Set the state clear flag. See [`State::set_state_clear_flag`].
15+
fn set_state_clear_flag(&mut self, flag: bool);
16+
17+
/// Merge transitions into the bundle. See [`State::merge_transitions`].
18+
fn merge_transitions(&mut self, retention: BundleRetention);
19+
20+
/// Take the bundle. See [`State::take_bundle`].
21+
fn take_bundle(&mut self) -> BundleState;
22+
23+
/// Set the block hashes, overriding any existing values, and inserting any
24+
/// absent values.
25+
fn set_block_hashes(&mut self, block_hashes: &BTreeMap<u64, B256>);
26+
}
27+
28+
impl<Db: Database> StateAcc for State<Db> {
29+
fn set_state_clear_flag(&mut self, flag: bool) {
30+
Self::set_state_clear_flag(self, flag)
31+
}
32+
33+
fn merge_transitions(&mut self, retention: BundleRetention) {
34+
Self::merge_transitions(self, retention)
35+
}
36+
37+
fn take_bundle(&mut self) -> BundleState {
38+
Self::take_bundle(self)
39+
}
40+
41+
fn set_block_hashes(&mut self, block_hashes: &BTreeMap<u64, B256>) {
42+
self.block_hashes.extend(block_hashes)
43+
}
44+
}
45+
46+
/// Fallible version of [`StateAcc`].
47+
///
48+
/// Abstraction trait covering types that accumulate state changes into a
49+
/// [`BundleState`]. The prime example of this is [`State`]. These types are
50+
/// use to accumulate state changes during the execution of a sequence of
51+
/// transactions, and then provide access to the net changes in the form of a
52+
/// [`BundleState`].
53+
///
54+
/// The primary motivator for this trait is to allow for the implementation of
55+
/// [`StateAcc`] for [`Arc`]-wrapped DBs, which may fail to mutate if the
56+
/// reference is not unique.
57+
pub trait TryStateAcc: Sync {
58+
/// Error type to be thrown when state accumulation fails.
59+
type Error: core::error::Error;
60+
61+
/// Attempt to set the state clear flag. See [`State::set_state_clear_flag`].
62+
fn try_set_state_clear_flag(&mut self, flag: bool) -> Result<(), Self::Error>;
63+
64+
/// Attempt to merge transitions into the bundle. See
65+
/// [`State::merge_transitions`].
66+
fn try_merge_transitions(&mut self, retention: BundleRetention) -> Result<(), Self::Error>;
67+
68+
/// Attempt to take the bundle. See [`State::take_bundle`].
69+
fn try_take_bundle(&mut self) -> Result<BundleState, Self::Error>;
70+
71+
/// Attempt to set the block hashes, overriding any existing values, and
72+
/// inserting any absent values.
73+
fn try_set_block_hashes(
74+
&mut self,
75+
block_hashes: &BTreeMap<u64, B256>,
76+
) -> Result<(), Self::Error>;
77+
}
78+
79+
impl<Db> TryStateAcc for Db
80+
where
81+
Db: StateAcc + Sync,
82+
{
83+
type Error = Infallible;
84+
85+
fn try_set_state_clear_flag(&mut self, flag: bool) -> Result<(), Infallible> {
86+
self.set_state_clear_flag(flag);
87+
Ok(())
88+
}
89+
90+
fn try_merge_transitions(&mut self, retention: BundleRetention) -> Result<(), Infallible> {
91+
self.merge_transitions(retention);
92+
Ok(())
93+
}
94+
95+
fn try_take_bundle(&mut self) -> Result<BundleState, Infallible> {
96+
Ok(self.take_bundle())
97+
}
98+
99+
fn try_set_block_hashes(
100+
&mut self,
101+
block_hashes: &BTreeMap<u64, B256>,
102+
) -> Result<(), Infallible> {
103+
self.set_block_hashes(block_hashes);
104+
Ok(())
105+
}
106+
}
107+
108+
/// Error type for implementation of [`TryStateAcc`] for [`Arc`]-wrapped
109+
/// DBs.
110+
#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq)]
111+
pub enum ArcUpgradeError {
112+
/// Arc reference is not unique. Ensure that all other references are
113+
/// dropped before attempting to mutate the state.
114+
#[error("Arc reference is not unique, cannot mutate")]
115+
NotUnique,
116+
}
117+
118+
impl<Db> TryStateAcc for Arc<Db>
119+
where
120+
Db: StateAcc + Sync + Send,
121+
{
122+
type Error = ArcUpgradeError;
123+
124+
fn try_set_state_clear_flag(&mut self, flag: bool) -> Result<(), ArcUpgradeError> {
125+
Self::get_mut(self).ok_or(ArcUpgradeError::NotUnique)?.set_state_clear_flag(flag);
126+
Ok(())
127+
}
128+
129+
fn try_merge_transitions(&mut self, retention: BundleRetention) -> Result<(), ArcUpgradeError> {
130+
Self::get_mut(self).ok_or(ArcUpgradeError::NotUnique)?.merge_transitions(retention);
131+
Ok(())
132+
}
133+
134+
fn try_take_bundle(&mut self) -> Result<BundleState, ArcUpgradeError> {
135+
Ok(Self::get_mut(self).ok_or(ArcUpgradeError::NotUnique)?.take_bundle())
136+
}
137+
138+
fn try_set_block_hashes(
139+
&mut self,
140+
block_hashes: &BTreeMap<u64, B256>,
141+
) -> Result<(), ArcUpgradeError> {
142+
Self::get_mut(self).ok_or(ArcUpgradeError::NotUnique)?.set_block_hashes(block_hashes);
143+
Ok(())
144+
}
145+
}
146+
147+
/// A fallible version of [`DatabaseCommit`].
148+
pub trait TryDatabaseCommit {
149+
/// Error type to be thrown when committing changes fails.
150+
type Error: core::error::Error;
151+
152+
/// Attempt to commit changes to the database.
153+
fn try_commit(
154+
&mut self,
155+
changes: revm::primitives::HashMap<Address, Account>,
156+
) -> Result<(), Self::Error>;
157+
}
158+
159+
impl<Db> TryDatabaseCommit for Arc<Db>
160+
where
161+
Db: DatabaseCommit,
162+
{
163+
type Error = ArcUpgradeError;
164+
165+
fn try_commit(
166+
&mut self,
167+
changes: revm::primitives::HashMap<Address, Account>,
168+
) -> Result<(), Self::Error> {
169+
Self::get_mut(self).ok_or(ArcUpgradeError::NotUnique)?.commit(changes);
170+
Ok(())
171+
}
172+
}

0 commit comments

Comments
 (0)