1
1
use anyhow:: { anyhow, bail, Context } ;
2
- use eth_types:: { geth_types:: Account , Address , Bytes , Word , H256 , U256 , U64 } ;
3
- use ethers_core:: { k256:: ecdsa:: SigningKey , utils:: secret_key_to_address} ;
2
+ use eth_types:: {
3
+ geth_types:: { Account , TxType } ,
4
+ Address , Bytes , Word , H256 , U256 , U64 ,
5
+ } ;
6
+ use ethers_core:: {
7
+ k256:: ecdsa:: SigningKey ,
8
+ types:: {
9
+ transaction:: { eip2718:: TypedTransaction , eip2930:: AccessList } ,
10
+ Eip1559TransactionRequest , TransactionRequest ,
11
+ } ,
12
+ utils:: secret_key_to_address,
13
+ } ;
4
14
use std:: {
5
15
collections:: { BTreeMap , HashMap } ,
6
16
str:: FromStr ,
@@ -9,6 +19,8 @@ use std::{
9
19
/// <https://github.com/ethereum/tests/pull/857> "set default gasPrice to 10"
10
20
pub const DEFAULT_BASE_FEE : u32 = 10 ;
11
21
22
+ const ETH_CHAIN_ID : u64 = 1 ;
23
+
12
24
#[ derive( PartialEq , Eq , Debug , Clone ) ]
13
25
pub struct Env {
14
26
pub current_base_fee : U256 ,
@@ -53,10 +65,13 @@ pub struct StateTest {
53
65
pub from : Address ,
54
66
pub to : Option < Address > ,
55
67
pub gas_limit : u64 ,
68
+ pub max_priority_fee_per_gas : Option < U256 > ,
69
+ pub max_fee_per_gas : Option < U256 > ,
56
70
pub gas_price : U256 ,
57
71
pub nonce : u64 ,
58
72
pub value : U256 ,
59
73
pub data : Bytes ,
74
+ pub access_list : Option < AccessList > ,
60
75
pub pre : BTreeMap < Address , Account > ,
61
76
pub result : StateTestResult ,
62
77
pub exception : bool ,
@@ -108,10 +123,19 @@ impl std::fmt::Display for StateTest {
108
123
table. add_row ( row ! [ "from" , format!( "{:?}" , self . from) ] ) ;
109
124
table. add_row ( row ! [ "to" , format!( "{:?}" , self . to) ] ) ;
110
125
table. add_row ( row ! [ "gas_limit" , format!( "{}" , self . gas_limit) ] ) ;
126
+ table. add_row ( row ! [
127
+ "max_priority_fee_per_gas" ,
128
+ format!( "{:?}" , self . max_priority_fee_per_gas)
129
+ ] ) ;
130
+ table. add_row ( row ! [
131
+ "max_fee_per_gas" ,
132
+ format!( "{:?}" , self . max_fee_per_gas)
133
+ ] ) ;
111
134
table. add_row ( row ! [ "gas_price" , format!( "{}" , self . gas_price) ] ) ;
112
135
table. add_row ( row ! [ "nonce" , format!( "{}" , self . nonce) ] ) ;
113
136
table. add_row ( row ! [ "value" , format!( "{}" , self . value) ] ) ;
114
137
table. add_row ( row ! [ "data" , format( & hex:: encode( & self . data) , "" ) ] ) ;
138
+ table. add_row ( row ! [ "access_list" , format!( "{:?}" , self . access_list) ] ) ;
115
139
table. add_row ( row ! [ "exception" , self . exception] ) ;
116
140
117
141
let mut addrs: Vec < _ > = self . pre . keys ( ) . collect ( ) ;
@@ -273,15 +297,102 @@ impl StateTest {
273
297
from,
274
298
to,
275
299
gas_limit,
300
+ max_priority_fee_per_gas : None ,
301
+ max_fee_per_gas : None ,
276
302
gas_price : U256 :: one ( ) ,
277
303
nonce : 0 ,
278
304
value,
279
305
data : data. into ( ) ,
306
+ access_list : None ,
280
307
pre,
281
308
result : HashMap :: new ( ) ,
282
309
exception : false ,
283
310
} ;
284
311
285
312
Ok ( state_test)
286
313
}
314
+
315
+ /// Parse transaction type.
316
+ pub fn tx_type ( & self ) -> TxType {
317
+ if self . max_priority_fee_per_gas . is_some ( ) {
318
+ // For EIP-1559, both maxPriorityFeePerGas and maxFeePerGas must
319
+ // exist, and accessList should exist but may be empty.
320
+ assert ! ( self . max_fee_per_gas. is_some( ) ) ;
321
+ assert ! ( self . access_list. is_some( ) ) ;
322
+
323
+ TxType :: Eip1559
324
+ } else if self . access_list . is_some ( ) {
325
+ TxType :: Eip2930
326
+ } else {
327
+ // Set transaction type to EIP-155 as default.
328
+ TxType :: Eip155
329
+ }
330
+ }
331
+
332
+ /// Normalize the signature back to 0/1.
333
+ pub fn normalize_sig_v ( & self , v : u64 ) -> u64 {
334
+ match self . tx_type ( ) {
335
+ TxType :: Eip1559 | TxType :: Eip2930 => {
336
+ // <https://github.com/gakonst/ethers-rs/blob/8421cfdbb4f26be3989bd11e525f8768d4323bfe/ethers-core/src/types/transaction/mod.rs#L40>
337
+ if v > 1 {
338
+ v - ETH_CHAIN_ID * 2 - 35
339
+ } else {
340
+ v
341
+ }
342
+ }
343
+ _ => v,
344
+ }
345
+ }
346
+
347
+ /// Build a transaction from this test case.
348
+ pub fn build_tx ( & self ) -> TypedTransaction {
349
+ match self . tx_type ( ) {
350
+ TxType :: Eip1559 => self . build_eip1559_tx ( ) ,
351
+ TxType :: Eip2930 => self . build_eip2930_tx ( ) ,
352
+ _ => self . build_normal_tx_request ( ) . into ( ) ,
353
+ }
354
+ }
355
+
356
+ fn build_eip1559_tx ( & self ) -> TypedTransaction {
357
+ let mut request = Eip1559TransactionRequest :: new ( )
358
+ . chain_id ( ETH_CHAIN_ID )
359
+ . from ( self . from )
360
+ . nonce ( self . nonce )
361
+ . value ( self . value )
362
+ . data ( self . data . clone ( ) )
363
+ . gas ( self . gas_limit )
364
+ . access_list ( self . access_list . clone ( ) . unwrap ( ) )
365
+ . max_priority_fee_per_gas ( self . max_priority_fee_per_gas . unwrap ( ) )
366
+ . max_fee_per_gas ( self . max_fee_per_gas . unwrap ( ) ) ;
367
+
368
+ if let Some ( to) = self . to {
369
+ request = request. to ( to) ;
370
+ }
371
+
372
+ request. into ( )
373
+ }
374
+
375
+ fn build_eip2930_tx ( & self ) -> TypedTransaction {
376
+ let request = self . build_normal_tx_request ( ) ;
377
+ request
378
+ . with_access_list ( self . access_list . clone ( ) . unwrap ( ) )
379
+ . into ( )
380
+ }
381
+
382
+ fn build_normal_tx_request ( & self ) -> TransactionRequest {
383
+ let mut request = TransactionRequest :: new ( )
384
+ . chain_id ( ETH_CHAIN_ID )
385
+ . from ( self . from )
386
+ . nonce ( self . nonce )
387
+ . value ( self . value )
388
+ . data ( self . data . clone ( ) )
389
+ . gas ( self . gas_limit )
390
+ . gas_price ( self . gas_price ) ;
391
+
392
+ if let Some ( to) = self . to {
393
+ request = request. to ( to) ;
394
+ }
395
+
396
+ request
397
+ }
287
398
}
0 commit comments