Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "trevm"
version = "0.27.8"
version = "0.27.9"
rust-version = "1.83.0"
edition = "2021"
authors = ["init4"]
Expand Down
9 changes: 9 additions & 0 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,19 @@ impl<Db, Insp> TrevmBuilder<Db, Insp> {
}

/// Set the inspector for the EVM.
///
/// Equivalent to [`Self::with_inspector`].
pub fn with_insp<OInsp>(self, insp: OInsp) -> TrevmBuilder<Db, OInsp> {
TrevmBuilder { db: self.db, insp, spec: self.spec, precompiles: self.precompiles }
}

/// Set the inspector for the EVM.
///
/// Equivalent to [`Self::with_insp`].
pub fn with_inspector<OInsp>(self, insp: OInsp) -> TrevmBuilder<Db, OInsp> {
self.with_insp(insp)
}

/// Set the spec id for the EVM.
pub const fn with_spec_id(mut self, spec: SpecId) -> Self {
self.spec = spec;
Expand Down
33 changes: 33 additions & 0 deletions src/est.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,39 @@ impl EstimationResult {
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_search_range() {
let mut range = SearchRange::new(100, 200);
assert_eq!(range.min(), 100);
assert_eq!(range.max(), 200);
assert_eq!(range.size(), 100);
assert_eq!(range.ratio(), 0.5);
assert_eq!(range.midpoint(), 150);
assert!(range.contains(150));

range.maybe_raise_min(100);
assert_eq!(range.min(), 100);

range.maybe_raise_min(125);
assert_eq!(range.min(), 125);
assert_eq!(range.midpoint(), 162);

range.maybe_lower_max(180);
assert_eq!(range.max(), 180);
assert_eq!(range.midpoint(), 152);

range.maybe_raise_min(100);
assert_eq!(range.min(), 125);

range.maybe_lower_max(200);
assert_eq!(range.max(), 180);
}
}

// Some code above is reproduced from `reth`. It is reused here under the MIT
// license.
//
Expand Down
80 changes: 79 additions & 1 deletion src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2033,7 +2033,7 @@ where
// NB: 64 / 63 is due to Ethereum's gas-forwarding rules. Each call
// frame can forward only 63/64 of the gas it has when it makes a new
// frame.
let mut needle = gas_used + gas_refunded + revm::interpreter::gas::CALL_STIPEND * 64 / 63;
let mut needle = (gas_used + gas_refunded + revm::interpreter::gas::CALL_STIPEND) * 64 / 63;

// If the first search is outside the range, we don't need to try it.
if search_range.contains(needle) {
Expand Down Expand Up @@ -2346,6 +2346,84 @@ where
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{
test_utils::{test_trevm_with_funds, ALICE, BOB, LOG_DEPLOYED_BYTECODE},
NoopBlock, NoopCfg, TrevmBuilder,
};
use alloy::{
consensus::constants::ETH_TO_WEI,
network::{TransactionBuilder, TransactionBuilder7702},
rpc::types::{Authorization, TransactionRequest},
signers::SignerSync,
};
use revm::{context::transaction::AuthorizationTr, database::InMemoryDB, primitives::bytes};

#[test]
fn test_estimate_gas_simple_transfer() {
let trevm = test_trevm_with_funds(&[
(ALICE.address(), U256::from(ETH_TO_WEI)),
(BOB.address(), U256::from(ETH_TO_WEI)),
]);

let tx = TransactionRequest::default()
.from(ALICE.address())
.to(BOB.address())
.value(U256::from(ETH_TO_WEI / 2));

let (estimation, _trevm) =
trevm.fill_cfg(&NoopCfg).fill_block(&NoopBlock).fill_tx(&tx).estimate_gas().unwrap();

assert!(estimation.is_success());
// The gas used should correspond to a simple transfer.
assert_eq!(estimation.gas_used(), 21000);
}

#[test]
fn test_7702_authorization_estimation() {
// Insert the LogContract code
let db = InMemoryDB::default();
let log_address = Address::repeat_byte(0x32);

// Set up trevm, and test balances.
let mut trevm =
TrevmBuilder::new().with_db(db).with_spec_id(SpecId::PRAGUE).build_trevm().unwrap();
let _ = trevm.test_set_balance(ALICE.address(), U256::from(ETH_TO_WEI));
let _ = trevm.set_bytecode_unchecked(log_address, Bytecode::new_raw(LOG_DEPLOYED_BYTECODE));

// Bob will sign the authorization.
let authorization = Authorization {
chain_id: U256::ZERO,
address: log_address,
// We know Bob's nonce is 0.
nonce: 0,
};
let signature = BOB.sign_hash_sync(&authorization.signature_hash()).unwrap();
let signed_authorization = authorization.into_signed(signature);
assert_eq!(signed_authorization.authority().unwrap(), BOB.address());

let tx = TransactionRequest::default()
.from(ALICE.address())
.to(BOB.address())
.with_authorization_list(vec![signed_authorization])
.with_input(bytes!("0x7b3ab2d0")); // emitHello()

let (estimation, trevm) =
trevm.fill_cfg(&NoopCfg).fill_block(&NoopBlock).fill_tx(&tx).estimate_gas().unwrap();

assert!(estimation.is_success());

let tx = tx.with_gas_limit(estimation.limit());

let output = trevm.clear_tx().fill_tx(&tx).run().unwrap().accept();

assert!(output.0.is_success());
assert_eq!(output.0.logs().len(), 1);
}
}

// Some code above and documentation is adapted from the revm crate, and is
// reproduced here under the terms of the MIT license.
//
Expand Down
19 changes: 16 additions & 3 deletions src/fill/alloy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,9 +359,22 @@ impl Tx for alloy::rpc::types::TransactionRequest {

*caller = self.from.unwrap_or_default();

// NB: this is set to max if not provided, as users will typically
// intend that to mean "as much as possible"
*tx_type = self.transaction_type.unwrap_or(TxType::Eip1559 as u8);
// Determine the minimal tx type usable.
*tx_type = {
if self.transaction_type.is_some() {
self.transaction_type.unwrap()
} else if self.authorization_list.is_some() {
TxType::Eip7702 as u8
} else if self.has_eip4844_fields() {
TxType::Eip4844 as u8
} else if self.has_eip1559_fields() {
TxType::Eip1559 as u8
} else if self.access_list.is_some() {
TxType::Eip2930 as u8
} else {
TxType::Legacy as u8
}
};
*gas_limit = self.gas.unwrap_or(u64::MAX);
*gas_price =
self.gas_price.unwrap_or_default().max(self.max_fee_per_gas.unwrap_or_default());
Expand Down
34 changes: 32 additions & 2 deletions src/test_utils.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,47 @@
use std::sync::LazyLock;

use crate::{helpers::Ctx, EvmNeedsCfg, Trevm};
use alloy::primitives::{Address, U256};
use alloy::{
primitives::{Address, U256},
signers::{k256::ecdsa::SigningKey, local::PrivateKeySigner},
};
use revm::{
bytecode::Bytecode,
database::{CacheDB, EmptyDB, InMemoryDB, State},
inspector::{inspectors::TracerEip3155, NoOpInspector},
interpreter::{
CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter, InterpreterTypes,
},
primitives::{hardfork::SpecId, Log},
primitives::{bytes, hardfork::SpecId, Log},
state::AccountInfo,
Context, Inspector, MainBuilder,
};

/// LogContract bytecode
/// This is the runtime bytecode. This should be set directly with ``set_bytecode_unchecked``
/// ```ignore
/// contract LogContract {
/// event Hello();
/// event World();
///
/// function emitHello() public {
/// emit Hello();
/// }
///
/// function emitWorld() public {
/// emit World();
/// }
/// }
/// ```
pub const LOG_DEPLOYED_BYTECODE: alloy::primitives::Bytes = bytes!("6080604052348015600e575f80fd5b50600436106030575f3560e01c80637b3ab2d01460345780639ee1a44014603c575b5f80fd5b603a6044565b005b60426072565b005b7fbcdfe0d5b27dd186282e187525415c57ea3077c34efb39148111e4d342e7ab0e60405160405180910390a1565b7f2d67bb91f17bca05af6764ab411e86f4ddf757adb89fcec59a7d21c525d4171260405160405180910390a156fea2646970667358221220144b313f421e29c7119666392827595d05f3dc33d0ccb0e75314cc9180e4fb1f64736f6c634300081a0033");

/// Alice testing signer
pub static ALICE: LazyLock<PrivateKeySigner> =
LazyLock::new(|| PrivateKeySigner::from(SigningKey::from_slice(&[0x11; 32]).unwrap()));
/// Bob testing signer
pub static BOB: LazyLock<PrivateKeySigner> =
LazyLock::new(|| PrivateKeySigner::from(SigningKey::from_slice(&[0x22; 32]).unwrap()));

impl<Insp, State> Trevm<InMemoryDB, Insp, State>
where
Insp: Inspector<Ctx<InMemoryDB>>,
Expand Down