Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
29 changes: 28 additions & 1 deletion src/est.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl SearchRange {

/// Calculate the midpoint of the search range.
pub(crate) const fn midpoint(&self) -> u64 {
(self.max() + self.min()) / 2
((self.max() as u128 + self.min() as u128) / 2) as u64
}

/// Get the start of the search range.
Expand Down Expand Up @@ -272,6 +272,33 @@ 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);
}
}

// Some code above is reproduced from `reth`. It is reused here under the MIT
// license.
//
Expand Down
101 changes: 100 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,105 @@ where
}
}

#[cfg(test)]
mod tests {
use std::sync::LazyLock;

use alloy::network::{TransactionBuilder, TransactionBuilder7702};
use alloy::rpc::types::Authorization;
use alloy::signers::k256::ecdsa::SigningKey;
use alloy::signers::local::PrivateKeySigner;
use alloy::signers::SignerSync;
use alloy::{consensus::constants::ETH_TO_WEI, rpc::types::TransactionRequest};

use revm::context::transaction::AuthorizationTr;
use revm::database::InMemoryDB;
use revm::inspector::NoOpInspector;
use revm::primitives::bytes;

use crate::test_utils::{test_trevm_with_funds, LOG_BYTECODE};
use crate::{EvmNeedsCfg, TrevmBuilder};
use crate::{NoopBlock, NoopCfg};

use super::*;

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

fn trevm_with_funds() -> EvmNeedsCfg<InMemoryDB, NoOpInspector> {
test_trevm_with_funds(&[
(ALICE.address(), U256::from(ETH_TO_WEI)),
(BOB.address(), U256::from(ETH_TO_WEI)),
])
}

#[test]
fn test_estimate_gas_simple_transfer() {
let trevm = trevm_with_funds();

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!(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_BYTECODE.into()));

// 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!(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();

dbg!(&estimation);
assert!(estimation.is_success());

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

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

let bob_code = output.1.read_code(BOB.address());
dbg!(&bob_code);

dbg!(&output.0);
assert!(output.0.is_success());
assert!(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
3 changes: 3 additions & 0 deletions src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ use revm::{
Context, Inspector, MainBuilder,
};

/// LogContract bytecode
pub const LOG_BYTECODE: &str = "0x60806040526004361015610013575b6100ca565b61001d5f3561003c565b80637b3ab2d01461003757639ee1a4400361000e57610097565b610064565b60e01c90565b60405190565b5f80fd5b5f80fd5b5f91031261005a57565b61004c565b5f0190565b3461009257610074366004610050565b61007c6100ce565b610084610042565b8061008e8161005f565b0390f35b610048565b346100c5576100a7366004610050565b6100af610106565b6100b7610042565b806100c18161005f565b0390f35b610048565b5f80fd5b7fbcdfe0d5b27dd186282e187525415c57ea3077c34efb39148111e4d342e7ab0e6100f7610042565b806101018161005f565b0390a1565b7f2d67bb91f17bca05af6764ab411e86f4ddf757adb89fcec59a7d21c525d4171261012f610042565b806101398161005f565b0390a156fea2646970667358221220e22cd46ba129dcbd6f62f632cc862b0924d3f36c991fd0b45947581aa3010d6464736f6c634300081a0033";

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