Skip to content

Commit 1a647b0

Browse files
committed
add eip1559/2930 support to executor
1 parent c3fb00c commit 1a647b0

File tree

4 files changed

+139
-34
lines changed

4 files changed

+139
-34
lines changed

eth-types/src/geth_types.rs

+115-10
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@ use crate::{
55
keccak256,
66
sign_types::{biguint_to_32bytes_le, ct_option_ok_or, recover_pk, SignData, SECP256K1_Q},
77
AccessList, Address, Block, Bytecode, Bytes, Error, GethExecTrace, Hash, ToBigEndian,
8-
ToLittleEndian, ToWord, Word, U64,
8+
ToLittleEndian, ToWord, Word, H256, U64,
99
};
1010
use ethers_core::{
11-
types::{transaction::response, NameOrAddress, TransactionRequest},
11+
types::{
12+
transaction::{eip2718::TypedTransaction, response},
13+
Eip1559TransactionRequest, Eip2930TransactionRequest, NameOrAddress, TransactionRequest,
14+
},
1215
utils::get_contract_address,
1316
};
1417
use ethers_signers::{LocalWallet, Signer};
@@ -46,6 +49,90 @@ impl From<TxType> for u64 {
4649
}
4750
}
4851

52+
impl TxType {
53+
/// If this type is PreEip155
54+
pub fn is_pre_eip155(&self) -> bool {
55+
matches!(*self, TxType::PreEip155)
56+
}
57+
58+
/// If this type is EIP155 or not
59+
pub fn is_eip155(&self) -> bool {
60+
matches!(*self, TxType::Eip155)
61+
}
62+
63+
/// If this type is Eip1559 or not
64+
pub fn is_eip1559(&self) -> bool {
65+
matches!(*self, TxType::Eip1559)
66+
}
67+
68+
/// If this type is Eip2930 or not
69+
pub fn is_eip2930(&self) -> bool {
70+
matches!(*self, TxType::Eip2930)
71+
}
72+
73+
/// Get the type of transaction
74+
pub fn get_tx_type(tx: &crate::Transaction) -> Self {
75+
match tx.transaction_type {
76+
Some(x) if x == U64::from(1) => Self::Eip2930,
77+
Some(x) if x == U64::from(2) => Self::Eip1559,
78+
_ => match tx.v.as_u64() {
79+
0 | 1 | 27 | 28 => Self::PreEip155,
80+
_ => Self::Eip155,
81+
},
82+
}
83+
}
84+
85+
/// Return the recovery id of signature for recovering the signing pk
86+
pub fn get_recovery_id(&self, v: u64) -> u8 {
87+
let recovery_id = match *self {
88+
TxType::Eip155 => (v + 1) % 2,
89+
TxType::PreEip155 => {
90+
assert!(v == 0x1b || v == 0x1c, "v: {v}");
91+
v - 27
92+
}
93+
TxType::Eip1559 => {
94+
assert!(v <= 1);
95+
v
96+
}
97+
TxType::Eip2930 => {
98+
assert!(v <= 1);
99+
v
100+
}
101+
};
102+
103+
recovery_id as u8
104+
}
105+
}
106+
107+
/// Get the RLP bytes for signing
108+
pub fn get_rlp_unsigned(tx: &crate::Transaction) -> Vec<u8> {
109+
let sig_v = tx.v;
110+
match TxType::get_tx_type(tx) {
111+
TxType::Eip155 => {
112+
let mut tx: TransactionRequest = tx.into();
113+
tx.chain_id = Some(tx.chain_id.unwrap_or_else(|| {
114+
let recv_v = TxType::Eip155.get_recovery_id(sig_v.as_u64()) as u64;
115+
(sig_v - recv_v - 35) / 2
116+
}));
117+
tx.rlp().to_vec()
118+
}
119+
TxType::PreEip155 => {
120+
let tx: TransactionRequest = tx.into();
121+
tx.rlp_unsigned().to_vec()
122+
}
123+
TxType::Eip1559 => {
124+
let tx: Eip1559TransactionRequest = tx.into();
125+
let typed_tx: TypedTransaction = tx.into();
126+
typed_tx.rlp().to_vec()
127+
}
128+
TxType::Eip2930 => {
129+
let tx: Eip2930TransactionRequest = tx.into();
130+
let typed_tx: TypedTransaction = tx.into();
131+
typed_tx.rlp().to_vec()
132+
}
133+
}
134+
}
135+
49136
/// Definition of all of the data related to an account.
50137
#[serde_as]
51138
#[derive(PartialEq, Eq, Debug, Default, Clone, Serialize)]
@@ -183,6 +270,8 @@ pub struct Withdrawal {
183270
/// Definition of all of the constants related to an Ethereum transaction.
184271
#[derive(Debug, Default, Clone, Serialize)]
185272
pub struct Transaction {
273+
/// Tx type
274+
pub tx_type: TxType,
186275
/// Sender address
187276
pub from: Address,
188277
/// Recipient address (None for contract creation)
@@ -199,9 +288,9 @@ pub struct Transaction {
199288
/// Gas Price
200289
pub gas_price: Word,
201290
/// Gas fee cap
202-
pub gas_fee_cap: Word,
291+
pub gas_fee_cap: Option<Word>,
203292
/// Gas tip cap
204-
pub gas_tip_cap: Word,
293+
pub gas_tip_cap: Option<Word>,
205294
/// The compiled code of a contract OR the first 4 bytes of the hash of the
206295
/// invoked method signature and encoded parameters. For details see
207296
/// Ethereum Contract ABI
@@ -215,6 +304,14 @@ pub struct Transaction {
215304
pub r: Word,
216305
/// "s" value of the transaction signature
217306
pub s: Word,
307+
308+
/// RLP bytes
309+
pub rlp_bytes: Vec<u8>,
310+
/// RLP unsigned bytes
311+
pub rlp_unsigned_bytes: Vec<u8>,
312+
313+
/// Transaction hash
314+
pub hash: H256,
218315
}
219316

220317
impl From<&Transaction> for crate::Transaction {
@@ -226,8 +323,8 @@ impl From<&Transaction> for crate::Transaction {
226323
gas: tx.gas_limit.to_word(),
227324
value: tx.value,
228325
gas_price: Some(tx.gas_price),
229-
max_priority_fee_per_gas: Some(tx.gas_tip_cap),
230-
max_fee_per_gas: Some(tx.gas_fee_cap),
326+
max_priority_fee_per_gas: tx.gas_tip_cap,
327+
max_fee_per_gas: tx.gas_fee_cap,
231328
input: tx.call_data.clone(),
232329
access_list: tx.access_list.clone(),
233330
v: tx.v.into(),
@@ -241,19 +338,23 @@ impl From<&Transaction> for crate::Transaction {
241338
impl From<&crate::Transaction> for Transaction {
242339
fn from(tx: &crate::Transaction) -> Transaction {
243340
Transaction {
341+
tx_type: TxType::get_tx_type(tx),
244342
from: tx.from,
245343
to: tx.to,
246344
nonce: tx.nonce.as_u64().into(),
247345
gas_limit: tx.gas.as_u64().into(),
248346
value: tx.value,
249347
gas_price: tx.gas_price.unwrap_or_default(),
250-
gas_tip_cap: tx.max_priority_fee_per_gas.unwrap_or_default(),
251-
gas_fee_cap: tx.max_fee_per_gas.unwrap_or_default(),
348+
gas_tip_cap: tx.max_priority_fee_per_gas,
349+
gas_fee_cap: tx.max_fee_per_gas,
252350
call_data: tx.input.clone(),
253351
access_list: tx.access_list.clone(),
254352
v: tx.v.as_u64(),
255353
r: tx.r,
256354
s: tx.s,
355+
rlp_bytes: tx.rlp().to_vec(),
356+
rlp_unsigned_bytes: get_rlp_unsigned(tx),
357+
hash: tx.hash,
257358
}
258359
}
259360
}
@@ -283,13 +384,14 @@ impl Transaction {
283384
gas_limit: U64::zero(),
284385
value: Word::zero(),
285386
gas_price: Word::zero(),
286-
gas_tip_cap: Word::zero(),
287-
gas_fee_cap: Word::zero(),
387+
gas_tip_cap: Some(Word::zero()),
388+
gas_fee_cap: Some(Word::zero()),
288389
call_data: Bytes::new(),
289390
access_list: None,
290391
v: 0,
291392
r: Word::zero(),
292393
s: Word::zero(),
394+
..Default::default()
293395
}
294396
}
295397
/// Return the SignData associated with this Transaction.
@@ -382,6 +484,9 @@ impl Transaction {
382484
s: self.s,
383485
v: U64::from(self.v),
384486
block_number: Some(block_number),
487+
transaction_type: Some(U64::from(self.tx_type as u64)),
488+
max_priority_fee_per_gas: self.gas_tip_cap,
489+
max_fee_per_gas: self.gas_fee_cap,
385490
chain_id: Some(chain_id),
386491
..response::Transaction::default()
387492
}

external-tracer/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use eth_types::{
55
Address, Error, GethExecTrace, Word,
66
};
77
use serde::Serialize;
8-
use std::collections::HashMap;
8+
use std::collections::{BTreeMap, HashMap};
99

1010
/// Configuration structure for `geth_utils::trace`
1111
#[derive(Debug, Default, Clone, Serialize)]
@@ -18,7 +18,7 @@ pub struct TraceConfig {
1818
/// block constants
1919
pub block_constants: BlockConstants,
2020
/// accounts
21-
pub accounts: HashMap<Address, Account>,
21+
pub accounts: BTreeMap<Address, Account>,
2222
/// transaction
2323
pub transactions: Vec<Transaction>,
2424
/// withdrawal

testool/src/statetest/executor.rs

+19-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::{AccountMatch, StateTest, StateTestResult};
2-
use crate::config::TestSuite;
2+
use crate::{config::TestSuite, utils::ETH_CHAIN_ID};
33
use bus_mapping::{
44
circuit_input_builder::{CircuitInputBuilder, FixedCParams},
55
mock::BlockData,
@@ -8,6 +8,7 @@ use eth_types::{geth_types, Address, Bytes, Error, GethExecTrace, U256, U64};
88
use ethers_core::{
99
k256::ecdsa::SigningKey,
1010
types::{transaction::eip2718::TypedTransaction, TransactionRequest, Withdrawal},
11+
utils::keccak256,
1112
};
1213
use ethers_signers::{LocalWallet, Signer};
1314
use external_tracer::TraceConfig;
@@ -139,29 +140,21 @@ fn check_post(
139140

140141
fn into_traceconfig(st: StateTest) -> (String, TraceConfig, StateTestResult) {
141142
let tx_type = st.tx_type();
143+
let tx = st.build_tx();
142144

143-
let chain_id = 1;
144-
let wallet = LocalWallet::from_str(&hex::encode(st.secret_key.0)).unwrap();
145-
let mut tx = TransactionRequest::new()
146-
.chain_id(chain_id)
147-
.from(st.from)
148-
.nonce(st.nonce)
149-
.value(st.value)
150-
.data(st.data.clone())
151-
.gas(st.gas_limit)
152-
.gas_price(st.gas_price);
153-
154-
if let Some(to) = st.to {
155-
tx = tx.to(to);
156-
}
157-
let tx: TypedTransaction = tx.into();
145+
let wallet = LocalWallet::from_str(&hex::encode(&st.secret_key.0)).unwrap();
158146

147+
let rlp_unsigned = tx.rlp().to_vec();
159148
let sig = wallet.sign_transaction_sync(&tx).unwrap();
149+
let v = st.normalize_sig_v(sig.v);
150+
let rlp_signed = tx.rlp_signed(&sig).to_vec();
151+
let tx_hash = keccak256(tx.rlp_signed(&sig));
152+
let accounts = st.pre;
160153

161154
(
162155
st.id,
163156
TraceConfig {
164-
chain_id: U256::one(),
157+
chain_id: U256::from(ETH_CHAIN_ID),
165158
history_hashes: vec![U256::from_big_endian(st.env.previous_hash.as_bytes())],
166159
block_constants: geth_types::BlockConstants {
167160
coinbase: st.env.current_coinbase,
@@ -173,21 +166,25 @@ fn into_traceconfig(st: StateTest) -> (String, TraceConfig, StateTestResult) {
173166
},
174167

175168
transactions: vec![geth_types::Transaction {
169+
tx_type,
176170
from: st.from,
177171
to: st.to,
178172
nonce: U64::from(st.nonce),
179173
value: st.value,
180174
gas_limit: U64::from(st.gas_limit),
181175
gas_price: st.gas_price,
182-
gas_fee_cap: U256::zero(),
183-
gas_tip_cap: U256::zero(),
176+
gas_fee_cap: st.max_fee_per_gas,
177+
gas_tip_cap: st.max_priority_fee_per_gas,
184178
call_data: st.data,
185-
access_list: None,
186-
v: sig.v,
179+
access_list: st.access_list,
180+
v,
187181
r: sig.r,
188182
s: sig.s,
183+
rlp_bytes: rlp_signed,
184+
rlp_unsigned_bytes: rlp_unsigned,
185+
hash: tx_hash.into(),
189186
}],
190-
accounts: st.pre.into_iter().collect(),
187+
accounts,
191188
..Default::default()
192189
},
193190
st.result,

testool/src/utils.rs

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ use log::{error, info};
66
use prettytable::Table;
77
use std::process::{Command, Stdio};
88

9+
/// Chain ID for ETH mainnet
10+
pub const ETH_CHAIN_ID: u64 = 1;
11+
912
#[derive(Debug, Eq, PartialEq, PartialOrd)]
1013
pub enum MainnetFork {
1114
Shanghai = 15,

0 commit comments

Comments
 (0)