Skip to content

Commit 873b506

Browse files
authored
chore(deps): upgrade to revm23/alloy1.0.5 (#104)
* chore(deps): upgrade to revm22/alloy0.14 * chore: alloy1.0.5/revm23 fixes * chore: more fixes * chore: keep optional validation * chore: nicer auth list wrangling * fix: proper selector parsing * chore: no underscore * chore: validate on example * chore: keep selector as option * feat: version bump * chore: vendor alloydb, fix example * chore: clippy * chore: docs * chore: improve code style * chore: backticks * chore: more docs * chore: do not use SAFETY disclaimers, as its not unsafe code
1 parent 0f21f79 commit 873b506

File tree

13 files changed

+285
-79
lines changed

13 files changed

+285
-79
lines changed

Cargo.toml

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "trevm"
3-
version = "0.20.11"
3+
version = "0.23.0"
44
rust-version = "1.83.0"
55
edition = "2021"
66
authors = ["init4"]
@@ -26,24 +26,37 @@ use-self = "warn"
2626
option-if-let-else = "warn"
2727
redundant-clone = "warn"
2828

29+
[[example]]
30+
name = "basic_transact"
31+
32+
[[example]]
33+
name = "fork_ref_transact"
34+
required-features = ["alloy-db"]
35+
2936
[dependencies]
30-
alloy = { version = "0.12.6", default-features = false, features = ["consensus", "rpc-types-mev", "eips", "k256", "std", "rlp", "sol-types"] }
37+
alloy = { version = "1.0.5", default-features = false, features = [
38+
"consensus",
39+
"rpc-types-mev",
40+
"eips",
41+
"k256",
42+
"std",
43+
"rlp",
44+
"sol-types",
45+
] }
3146

32-
revm = { version = "20.0.0", default-features = false }
47+
revm = { version = "23.1.0", default-features = false }
3348

3449
dashmap = { version = "6.1.0", optional = true }
35-
tracing = { version = "0.1.41", optional = true}
50+
tracing = { version = "0.1.41", optional = true }
3651
thiserror = "2.0.11"
3752

53+
tokio = { version = "1.44", optional = true }
54+
3855
[dev-dependencies]
39-
revm = { version = "20.0.0", features = [
40-
"serde-json",
41-
"std",
42-
"alloydb",
43-
] }
56+
revm = { version = "23.1.0", features = ["serde-json", "std", "alloydb"] }
4457
trevm = { path = ".", features = ["test-utils"] }
4558

46-
alloy = { version = "0.12.6", features = ["providers"]}
59+
alloy = { version = "1.0.5", features = ["providers", "transports"] }
4760

4861
# misc
4962
eyre = "0.6"
@@ -63,6 +76,8 @@ default = [
6376
"revm/secp256k1",
6477
]
6578

79+
alloy-db = ["dep:tokio"]
80+
6681
call = ["optional_eip3607", "optional_no_base_fee"]
6782

6883
concurrent-db = ["dep:dashmap"]

examples/fork_ref_transact.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
//! This example demonstrates how to query storage slots of a contract, using
2-
//! [`AlloyDB`].
3-
4-
//! This example is currently disabled while waiting for revm @ 14.0.4
2+
//! [`AlloyDb`].
53
64
use alloy::{
75
eips::BlockId,
@@ -11,10 +9,7 @@ use alloy::{
119
sol_types::SolCall,
1210
};
1311
use revm::{context::TxEnv, database::WrapDatabaseAsync};
14-
use trevm::{
15-
revm::database::{AlloyDB, CacheDB},
16-
NoopBlock, NoopCfg, TrevmBuilder, Tx,
17-
};
12+
use trevm::{db::alloy::AlloyDb, revm::database::CacheDB, NoopBlock, NoopCfg, TrevmBuilder, Tx};
1813

1914
sol! {
2015
#[allow(missing_docs)]
@@ -42,7 +37,7 @@ async fn main() -> eyre::Result<()> {
4237
// create ethers client and wrap it in Arc<M>
4338
let rpc_url = "https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27";
4439

45-
let client = ProviderBuilder::new().on_http(rpc_url.parse()?);
40+
let client = ProviderBuilder::new().connect_http(rpc_url.parse()?);
4641

4742
// ----------------------------------------------------------- //
4843
// Storage slots of UniV2Pair contract //
@@ -57,7 +52,7 @@ async fn main() -> eyre::Result<()> {
5752
// =========================================================== //
5853

5954
// initialize new AlloyDB
60-
let alloydb = WrapDatabaseAsync::new(AlloyDB::new(client, BlockId::default())).unwrap();
55+
let alloydb = WrapDatabaseAsync::new(AlloyDb::new(client, BlockId::default())).unwrap();
6156

6257
// initialise empty in-memory-db
6358
let cache_db = CacheDB::new(alloydb);
@@ -78,7 +73,7 @@ async fn main() -> eyre::Result<()> {
7873
let output = evm.output().expect("Execution halted");
7974

8075
// decode bytes to reserves + ts via alloy's abi decode
81-
let return_vals = getReservesCall::abi_decode_returns(output, true)?;
76+
let return_vals = getReservesCall::abi_decode_returns_validate(output)?;
8277

8378
// Print emulated getReserves() call output
8479
println!("Reserve0: {:#?}", return_vals.reserve0);

src/db/alloy.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
use alloy::{
2+
eips::BlockId,
3+
primitives::{StorageValue, U256},
4+
providers::{
5+
network::{primitives::HeaderResponse, BlockResponse},
6+
Network, Provider,
7+
},
8+
transports::TransportError,
9+
};
10+
use core::error::Error;
11+
use revm::{
12+
database_interface::{async_db::DatabaseAsyncRef, DBErrorMarker},
13+
primitives::{Address, B256},
14+
state::{AccountInfo, Bytecode},
15+
};
16+
use std::fmt::Display;
17+
18+
/// A type alias for the storage key used in the database.
19+
/// We use this instead of alloy's [`alloy::primitives::StorageKey`] as Revm requires
20+
/// the actual type to be an [`U256`] instead of a [`B256`].
21+
pub type StorageKey = U256;
22+
23+
/// An error that can occur when using [`AlloyDb`].
24+
#[derive(Debug)]
25+
pub struct DBTransportError(pub TransportError);
26+
27+
impl DBErrorMarker for DBTransportError {}
28+
29+
impl Display for DBTransportError {
30+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
31+
write!(f, "Transport error: {}", self.0)
32+
}
33+
}
34+
35+
impl Error for DBTransportError {}
36+
37+
impl From<TransportError> for DBTransportError {
38+
fn from(e: TransportError) -> Self {
39+
Self(e)
40+
}
41+
}
42+
43+
/// An alloy-powered REVM [`Database`][revm::database_interface::Database].
44+
///
45+
/// When accessing the database, it'll use the given provider to fetch the corresponding account's data.
46+
#[derive(Debug)]
47+
pub struct AlloyDb<N: Network, P: Provider<N>> {
48+
/// The provider to fetch the data from.
49+
provider: P,
50+
/// The block number on which the queries will be based on.
51+
block_number: BlockId,
52+
_marker: core::marker::PhantomData<fn() -> N>,
53+
}
54+
55+
impl<N: Network, P: Provider<N>> AlloyDb<N, P> {
56+
/// Creates a new AlloyDB instance, with a [`Provider`] and a block.
57+
pub fn new(provider: P, block_number: BlockId) -> Self {
58+
Self { provider, block_number, _marker: core::marker::PhantomData }
59+
}
60+
61+
/// Sets the block number on which the queries will be based on.
62+
pub const fn set_block_number(&mut self, block_number: BlockId) {
63+
self.block_number = block_number;
64+
}
65+
}
66+
67+
impl<N: Network, P: Provider<N>> DatabaseAsyncRef for AlloyDb<N, P> {
68+
type Error = DBTransportError;
69+
70+
async fn basic_async_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
71+
let nonce = self.provider.get_transaction_count(address).block_id(self.block_number);
72+
let balance = self.provider.get_balance(address).block_id(self.block_number);
73+
let code = self.provider.get_code_at(address).block_id(self.block_number);
74+
75+
let (nonce, balance, code) = tokio::join!(nonce, balance, code,);
76+
77+
let balance = balance?;
78+
let code = Bytecode::new_raw(code?.0.into());
79+
let code_hash = code.hash_slow();
80+
let nonce = nonce?;
81+
82+
Ok(Some(AccountInfo::new(balance, nonce, code_hash, code)))
83+
}
84+
85+
async fn block_hash_async_ref(&self, number: u64) -> Result<B256, Self::Error> {
86+
let block = self
87+
.provider
88+
// We know number <= u64::MAX, so we can safely convert it to u64
89+
.get_block_by_number(number.into())
90+
.await?;
91+
// If the number is given, the block is supposed to be finalized, so unwrapping is safe.
92+
Ok(B256::new(*block.unwrap().header().hash()))
93+
}
94+
95+
async fn code_by_hash_async_ref(&self, _code_hash: B256) -> Result<Bytecode, Self::Error> {
96+
panic!("This should not be called, as the code is already loaded");
97+
// This is not needed, as the code is already loaded with basic_ref
98+
}
99+
100+
async fn storage_async_ref(
101+
&self,
102+
address: Address,
103+
index: StorageKey,
104+
) -> Result<StorageValue, Self::Error> {
105+
Ok(self.provider.get_storage_at(address, index).block_id(self.block_number).await?)
106+
}
107+
}
108+
109+
#[cfg(test)]
110+
mod tests {
111+
use super::*;
112+
use alloy::providers::ProviderBuilder;
113+
use revm::database_interface::{DatabaseRef, WrapDatabaseAsync};
114+
115+
#[test]
116+
#[ignore = "flaky RPC"]
117+
fn can_get_basic() {
118+
let client = ProviderBuilder::new().connect_http(
119+
"https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27".parse().unwrap(),
120+
);
121+
let alloydb = AlloyDb::new(client, BlockId::from(16148323));
122+
let wrapped_alloydb = WrapDatabaseAsync::new(alloydb).unwrap();
123+
124+
// ETH/USDT pair on Uniswap V2
125+
let address: Address = "0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852".parse().unwrap();
126+
127+
let acc_info = wrapped_alloydb.basic_ref(address).unwrap().unwrap();
128+
assert!(acc_info.exists());
129+
}
130+
}
131+
132+
// This code has been reproduced from the original AlloyDB implementation
133+
// contained in revm.
134+
// <https://github.com/bluealloy/revm>
135+
// The original license is included below:
136+
//
137+
// MIT License
138+
// Copyright (c) 2021-2025 draganrakita
139+
// Permission is hereby granted, free of charge, to any person obtaining a copy
140+
// of this software and associated documentation files (the "Software"), to deal
141+
// in the Software without restriction, including without limitation the rights
142+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
143+
// copies of the Software, and to permit persons to whom the Software is
144+
// furnished to do so, subject to the following conditions:
145+
// The above copyright notice and this permission notice shall be included in all
146+
// copies or substantial portions of the Software.
147+
//
148+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
149+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
150+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
151+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
152+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
153+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
154+
// SOFTWARE.

src/db/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@ pub use traits::{ArcUpgradeError, CachingDb, StateAcc, TryCachingDb, TryStateAcc
99
/// Cache-on-write database. A memory cache that caches only on write, not on
1010
/// read. Intended to wrap some other caching database.
1111
pub mod cow;
12+
13+
#[cfg(feature = "alloy-db")]
14+
/// Alloy-powered revm Database implementation that fetches data over the network.
15+
pub mod alloy;

src/driver/alloy.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ use crate::{
44
trevm_bail, trevm_ensure, trevm_try, Block, BundleDriver, DriveBundleResult,
55
};
66
use alloy::{
7-
consensus::{Transaction, TxEip4844Variant, TxEnvelope},
7+
consensus::{
8+
crypto::RecoveryError, transaction::SignerRecoverable, Transaction, TxEip4844Variant,
9+
TxEnvelope,
10+
},
811
eips::{eip2718::Decodable2718, BlockNumberOrTag},
912
primitives::{bytes::Buf, keccak256, Address, Bytes, TxKind, U256},
1013
rpc::types::mev::{
@@ -35,7 +38,7 @@ pub enum BundleError<Db: Database> {
3538
/// An error occurred while decoding a transaction contained in the bundle.
3639
TransactionDecodingError(alloy::eips::eip2718::Eip2718Error),
3740
/// An error occurred while recovering the sender of a transaction.
38-
TransactionSenderRecoveryError(alloy::primitives::SignatureError),
41+
TransactionSenderRecoveryError(alloy::consensus::crypto::RecoveryError),
3942
/// An error occurred while running the EVM.
4043
EVMError {
4144
/// The error that occurred while running the EVM.
@@ -71,7 +74,7 @@ impl<Db: Database> From<alloy::eips::eip2718::Eip2718Error> for BundleError<Db>
7174

7275
impl<Db: Database> From<alloy::primitives::SignatureError> for BundleError<Db> {
7376
fn from(err: alloy::primitives::SignatureError) -> Self {
74-
Self::TransactionSenderRecoveryError(err)
77+
Self::TransactionSenderRecoveryError(err.into())
7578
}
7679
}
7780

@@ -91,6 +94,12 @@ impl<Db: Database> std::error::Error for BundleError<Db> {
9194
}
9295
}
9396

97+
impl<Db: Database> From<RecoveryError> for BundleError<Db> {
98+
fn from(err: RecoveryError) -> Self {
99+
Self::TransactionSenderRecoveryError(err)
100+
}
101+
}
102+
94103
impl<Db: Database> core::fmt::Debug for BundleError<Db> {
95104
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
96105
match self {

0 commit comments

Comments
 (0)