Skip to content

Commit c9ce5f3

Browse files
committed
test: port forked blockchain tests
1 parent 620b2d7 commit c9ce5f3

File tree

14 files changed

+758
-1279
lines changed

14 files changed

+758
-1279
lines changed

.devcontainer/devcontainer.json

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"vadimcn.vscode-lldb"
2929
],
3030
"settings": {
31+
"rust-analyzer.cargo.features": "all",
3132
"rust-analyzer.rustfmt.extraArgs": [
3233
"+nightly"
3334
]

crates/edr_eth/src/access_list.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ impl From<AccessList> for Vec<(Address, Vec<U256>)> {
6363
}
6464
}
6565

66-
#[cfg(test)]
66+
#[cfg(all(test, feature = "serde"))]
6767
mod tests {
6868
use serde_json::json;
6969

crates/edr_eth/src/block/reorg.rs

+84-3
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ const DEFAULT_SAFE_BLOCK_TIME: Duration = Duration::from_secs(1);
1111
/// Test whether a block number is safe from a reorg for a specific chain based
1212
/// on the latest block number.
1313
pub fn is_safe_block_number(args: IsSafeBlockNumberArgs) -> bool {
14-
let safe_block_number = largest_safe_block_number((&args).into());
15-
args.block_number <= safe_block_number
14+
args.latest_block_number
15+
.checked_sub(safe_block_depth(args.chain_id))
16+
.is_some_and(|safe_block_number| args.block_number <= safe_block_number)
1617
}
1718

1819
/// Arguments for the `is_safe_block_number` function.
@@ -37,9 +38,15 @@ impl<'a> From<&'a IsSafeBlockNumberArgs> for LargestSafeBlockNumberArgs {
3738

3839
/// The largest block number that is safe from a reorg for a specific chain
3940
/// based on the latest block number.
41+
///
42+
/// Design choice: if latestBlock - maxReorg results in a negative number then
43+
/// the latest block will be used. This decision is based on the assumption
44+
/// that if maxReorg > latestBlock then there is a high probability that the
45+
/// fork is occurring on a devnet.
4046
pub fn largest_safe_block_number(args: LargestSafeBlockNumberArgs) -> u64 {
4147
args.latest_block_number
42-
.saturating_sub(safe_block_depth(args.chain_id))
48+
.checked_sub(safe_block_depth(args.chain_id))
49+
.unwrap_or(args.latest_block_number)
4350
}
4451

4552
/// Arguments for the `largest_safe_block_number` function.
@@ -92,3 +99,77 @@ pub fn block_time(chain_id: u64) -> Duration {
9299
}
93100
}
94101
}
102+
103+
#[cfg(test)]
104+
mod tests {
105+
const ROPSTEN_CHAIN_ID: u64 = 3;
106+
107+
use super::*;
108+
109+
#[test]
110+
fn largest_safe_block_number_with_safe_blocks() {
111+
const LATEST_BLOCK_NUMBER: u64 = 1_000;
112+
113+
let safe_block_depth = safe_block_depth(ROPSTEN_CHAIN_ID);
114+
let args = LargestSafeBlockNumberArgs {
115+
chain_id: ROPSTEN_CHAIN_ID,
116+
latest_block_number: LATEST_BLOCK_NUMBER,
117+
};
118+
assert_eq!(
119+
largest_safe_block_number(args),
120+
LATEST_BLOCK_NUMBER - safe_block_depth
121+
);
122+
}
123+
124+
#[test]
125+
fn largest_safe_block_number_all_blocks_unsafe() {
126+
const LATEST_BLOCK_NUMBER: u64 = 50;
127+
128+
let args = LargestSafeBlockNumberArgs {
129+
chain_id: ROPSTEN_CHAIN_ID,
130+
latest_block_number: LATEST_BLOCK_NUMBER,
131+
};
132+
assert_eq!(largest_safe_block_number(args), LATEST_BLOCK_NUMBER);
133+
}
134+
135+
#[test]
136+
fn is_safe_block_number_with_safe_blocks() {
137+
const LATEST_BLOCK_NUMBER: u64 = 1_000;
138+
139+
let safe_block_depth = safe_block_depth(ROPSTEN_CHAIN_ID);
140+
let safe_block_number = LATEST_BLOCK_NUMBER - safe_block_depth;
141+
142+
let args = IsSafeBlockNumberArgs {
143+
chain_id: ROPSTEN_CHAIN_ID,
144+
latest_block_number: LATEST_BLOCK_NUMBER,
145+
block_number: safe_block_number,
146+
};
147+
assert!(is_safe_block_number(args));
148+
149+
let args = IsSafeBlockNumberArgs {
150+
chain_id: ROPSTEN_CHAIN_ID,
151+
latest_block_number: LATEST_BLOCK_NUMBER,
152+
block_number: safe_block_number + 1,
153+
};
154+
assert!(!is_safe_block_number(args));
155+
}
156+
157+
#[test]
158+
fn is_safe_block_number_all_blocks_unsafe() {
159+
const LATEST_BLOCK_NUMBER: u64 = 50;
160+
161+
let args = IsSafeBlockNumberArgs {
162+
chain_id: ROPSTEN_CHAIN_ID,
163+
latest_block_number: LATEST_BLOCK_NUMBER,
164+
block_number: 0,
165+
};
166+
assert!(!is_safe_block_number(args));
167+
168+
let args = IsSafeBlockNumberArgs {
169+
chain_id: ROPSTEN_CHAIN_ID,
170+
latest_block_number: LATEST_BLOCK_NUMBER,
171+
block_number: LATEST_BLOCK_NUMBER,
172+
};
173+
assert!(!is_safe_block_number(args));
174+
}
175+
}

crates/edr_eth/src/log/block.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ impl alloy_rlp::Encodable for FullBlockLog {
7272
}
7373
}
7474

75-
#[cfg(test)]
75+
#[cfg(all(test, feature = "serde"))]
7676
mod tests {
7777
use std::str::FromStr;
7878

crates/edr_eth/src/log/filter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ impl alloy_rlp::Encodable for FilterLog {
3434
}
3535
}
3636

37-
#[cfg(test)]
37+
#[cfg(all(test, feature = "serde"))]
3838
mod tests {
3939
use std::str::FromStr;
4040

crates/edr_eth/src/log/receipt.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ impl alloy_rlp::Encodable for ReceiptLog {
3434
}
3535
}
3636

37-
#[cfg(test)]
37+
#[cfg(all(test, feature = "serde"))]
3838
mod tests {
3939
use std::str::FromStr;
4040

crates/edr_eth/src/receipt.rs

+1
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,7 @@ mod tests {
485485
assert_eq!(TypedReceipt::<Log>::decode(&mut encoded.as_slice()).unwrap(), receipt);
486486
}
487487

488+
#[cfg(feature = "serde")]
488489
#[test]
489490
fn [<typed_receipt_serde_ $name>]() {
490491
let receipt = [<typed_receipt_dummy_ $name>]();

crates/edr_eth/src/receipt/block.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ impl alloy_rlp::Encodable for BlockReceipt {
3737
}
3838
}
3939

40-
#[cfg(test)]
40+
#[cfg(all(test, feature = "serde"))]
4141
mod test {
4242
use assert_json_diff::assert_json_eq;
4343
use revm_primitives::SpecId;

crates/edr_eth/src/receipt/transaction.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ where
8888
}
8989
}
9090

91-
#[cfg(test)]
91+
#[cfg(all(test, feature = "serde"))]
9292
mod test {
9393
use revm_primitives::SpecId;
9494

crates/edr_evm/src/blockchain/forked.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -295,15 +295,14 @@ impl Blockchain for ForkedBlockchain {
295295
let (to_block, mut local_logs) = if to_block <= self.fork_block_number {
296296
(to_block, Vec::new())
297297
} else {
298-
(
299-
self.fork_block_number,
300-
self.local_storage.logs(
301-
self.fork_block_number + 1,
302-
to_block,
303-
addresses,
304-
normalized_topics,
305-
)?,
306-
)
298+
let local_logs = self.local_storage.logs(
299+
self.fork_block_number + 1,
300+
to_block,
301+
addresses,
302+
normalized_topics,
303+
)?;
304+
305+
(self.fork_block_number, local_logs)
307306
};
308307

309308
let mut remote_logs = tokio::task::block_in_place(move || {

crates/edr_evm/src/test_utils.rs

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
use edr_eth::{
2+
transaction::{Eip1559TransactionRequest, Eip155TransactionRequest, TransactionKind},
3+
AccountInfo, Address, Bytes, HashMap, SpecId, U256,
4+
};
5+
6+
use crate::{
7+
state::{AccountTrie, StateError, TrieState},
8+
ExecutableTransaction, MemPool, MemPoolAddTransactionError, TransactionCreationError,
9+
};
10+
11+
/// A test fixture for `MemPool`.
12+
pub struct MemPoolTestFixture {
13+
/// The mem pool.
14+
pub mem_pool: MemPool,
15+
/// The state.
16+
pub state: TrieState,
17+
}
18+
19+
impl MemPoolTestFixture {
20+
/// Constructs an instance with the provided accounts.
21+
pub fn with_accounts(accounts: &[(Address, AccountInfo)]) -> Self {
22+
let accounts = accounts.iter().cloned().collect::<HashMap<_, _>>();
23+
let trie = AccountTrie::with_accounts(&accounts);
24+
25+
MemPoolTestFixture {
26+
mem_pool: MemPool::new(10_000_000u64),
27+
state: TrieState::with_accounts(trie),
28+
}
29+
}
30+
31+
/// Tries to add the provided transaction to the mem pool.
32+
pub fn add_transaction(
33+
&mut self,
34+
transaction: ExecutableTransaction,
35+
) -> Result<(), MemPoolAddTransactionError<StateError>> {
36+
self.mem_pool.add_transaction(&self.state, transaction)
37+
}
38+
39+
/// Sets the block gas limit.
40+
pub fn set_block_gas_limit(&mut self, block_gas_limit: u64) -> Result<(), StateError> {
41+
self.mem_pool
42+
.set_block_gas_limit(&self.state, block_gas_limit)
43+
}
44+
45+
/// Updates the mem pool.
46+
pub fn update(&mut self) -> Result<(), StateError> {
47+
self.mem_pool.update(&self.state)
48+
}
49+
}
50+
51+
/// Creates a dummy EIP-155 transaction.
52+
pub fn dummy_eip155_transaction(
53+
caller: Address,
54+
nonce: u64,
55+
) -> Result<ExecutableTransaction, TransactionCreationError> {
56+
dummy_eip155_transaction_with_price(caller, nonce, U256::ZERO)
57+
}
58+
59+
/// Creates a dummy EIP-155 transaction with the provided gas price.
60+
pub fn dummy_eip155_transaction_with_price(
61+
caller: Address,
62+
nonce: u64,
63+
gas_price: U256,
64+
) -> Result<ExecutableTransaction, TransactionCreationError> {
65+
dummy_eip155_transaction_with_price_and_limit(caller, nonce, gas_price, 30_000)
66+
}
67+
68+
/// Creates a dummy EIP-155 transaction with the provided gas limit.
69+
pub fn dummy_eip155_transaction_with_limit(
70+
caller: Address,
71+
nonce: u64,
72+
gas_limit: u64,
73+
) -> Result<ExecutableTransaction, TransactionCreationError> {
74+
dummy_eip155_transaction_with_price_and_limit(caller, nonce, U256::ZERO, gas_limit)
75+
}
76+
77+
fn dummy_eip155_transaction_with_price_and_limit(
78+
caller: Address,
79+
nonce: u64,
80+
gas_price: U256,
81+
gas_limit: u64,
82+
) -> Result<ExecutableTransaction, TransactionCreationError> {
83+
dummy_eip155_transaction_with_price_limit_and_value(
84+
caller,
85+
nonce,
86+
gas_price,
87+
gas_limit,
88+
U256::ZERO,
89+
)
90+
}
91+
92+
/// Creates a dummy EIP-155 transaction with the provided gas price, gas limit,
93+
/// and value.
94+
pub fn dummy_eip155_transaction_with_price_limit_and_value(
95+
caller: Address,
96+
nonce: u64,
97+
gas_price: U256,
98+
gas_limit: u64,
99+
value: U256,
100+
) -> Result<ExecutableTransaction, TransactionCreationError> {
101+
let from = Address::random();
102+
let request = Eip155TransactionRequest {
103+
nonce,
104+
gas_price,
105+
gas_limit,
106+
kind: TransactionKind::Call(from),
107+
value,
108+
input: Bytes::new(),
109+
chain_id: 123,
110+
};
111+
let transaction = request.fake_sign(&caller);
112+
113+
ExecutableTransaction::with_caller(SpecId::LATEST, transaction.into(), caller)
114+
}
115+
116+
/// Creates a dummy EIP-1559 transaction with the provided max fee and max
117+
/// priority fee per gas.
118+
pub fn dummy_eip1559_transaction(
119+
caller: Address,
120+
nonce: u64,
121+
max_fee_per_gas: U256,
122+
max_priority_fee_per_gas: U256,
123+
) -> Result<ExecutableTransaction, TransactionCreationError> {
124+
let from = Address::random();
125+
let request = Eip1559TransactionRequest {
126+
chain_id: 123,
127+
nonce,
128+
max_priority_fee_per_gas,
129+
max_fee_per_gas,
130+
gas_limit: 30_000,
131+
kind: TransactionKind::Call(from),
132+
value: U256::ZERO,
133+
input: Bytes::new(),
134+
access_list: Vec::new(),
135+
};
136+
let transaction = request.fake_sign(&caller);
137+
138+
ExecutableTransaction::with_caller(SpecId::LATEST, transaction.into(), caller)
139+
}

0 commit comments

Comments
 (0)