1
1
import functools
2
2
import time
3
3
4
+ from eth_tester .backends .mock .common import (
5
+ calculate_effective_gas_price ,
6
+ )
7
+ from eth_tester .utils .transactions import (
8
+ extract_transaction_type ,
9
+ )
4
10
from eth_utils import (
5
11
apply_to_return_value ,
6
12
is_bytes ,
20
26
)
21
27
22
28
from eth_tester .backends .common import merge_genesis_overrides
29
+ from eth_tester .constants import DYNAMIC_FEE_TRANSACTION_PARAMS
23
30
from eth_tester .utils .address import (
24
31
generate_contract_address ,
25
32
)
28
35
ZERO_32BYTES = b'\x00 ' * 32
29
36
ZERO_8BYTES = b'\x00 ' * 8
30
37
ZERO_ADDRESS = b'\x00 ' * 20
38
+ BLOCK_ELASTICITY_MULTIPLIER = 2
39
+ BASE_FEE_MAX_CHANGE_DENOMINATOR = 8
31
40
32
41
33
42
@apply_to_return_value (b'|' .join )
@@ -86,69 +95,53 @@ def create_transaction(transaction, block, transaction_index, is_pending, overri
86
95
87
96
@to_dict
88
97
def _fill_transaction (transaction , block , transaction_index , is_pending , overrides = None ):
98
+ is_dynamic_fee_transaction = (
99
+ any (_ in transaction for _ in DYNAMIC_FEE_TRANSACTION_PARAMS )
100
+ or not any (_ in transaction for _ in DYNAMIC_FEE_TRANSACTION_PARAMS + ('gas_price' ,))
101
+ )
102
+
89
103
if overrides is None :
90
104
overrides = {}
91
105
92
- if 'nonce' in overrides :
93
- yield 'nonce' , overrides ['nonce' ]
94
- else :
95
- yield 'nonce' , 0
96
-
97
- if 'hash' in overrides :
106
+ if 'hash' in overrides : # else calculate hash after all fields are filled
98
107
yield 'hash' , overrides ['hash' ]
99
- else :
100
- # calculate hash after all fields are filled
101
- pass
102
-
103
- if 'from' in overrides :
104
- yield 'from' , overrides ['from' ]
105
- else :
106
- yield 'from' , transaction ['from' ]
107
108
108
- if 'gas' in overrides :
109
- yield 'gas' , overrides ['gas' ]
110
- else :
111
- yield 'gas' , transaction ['gas' ]
109
+ # Here, we yield the key with the overrides value if it exists, else either the transaction
110
+ # value if it exists or a default value
111
+ yield 'nonce' , overrides .get ('nonce' , 0 )
112
+ yield 'from' , overrides .get ('from' , transaction .get ('from' ))
113
+ yield 'to' , overrides .get ('to' , transaction .get ('to' , b'' ))
114
+ yield 'data' , overrides .get ('data' , transaction .get ('data' , b'' ))
115
+ yield 'value' , overrides .get ('value' , transaction .get ('value' , 0 ))
116
+ yield 'gas' , overrides .get ('gas' , transaction .get ('gas' ))
117
+ yield 'r' , overrides .get ('r' , transaction .get ('r' , 12345 ))
118
+ yield 's' , overrides .get ('s' , transaction .get ('s' , 67890 ))
119
+
120
+ if is_dynamic_fee_transaction :
121
+ # dynamic fee transaction (type = 2)
122
+ yield 'max_fee_per_gas' , overrides .get (
123
+ 'max_fee_per_gas' , transaction .get ('max_fee_per_gas' , 1000000000 )
124
+ )
125
+ yield 'max_priority_fee_per_gas' , overrides .get (
126
+ 'max_priority_fee_per_gas' , transaction .get ('max_priority_fee_per_gas' , 1000000000 )
127
+ )
128
+ yield from _yield_typed_transaction_fields (overrides , transaction )
129
+
130
+ else :
131
+ yield 'gas_price' , overrides .get ('gas_price' , transaction .get ('gas_price' ))
132
+ if 'access_list' in transaction :
133
+ # access list transaction (type = 1)
134
+ yield from _yield_typed_transaction_fields (overrides , transaction )
112
135
113
- if 'gas_price' in overrides :
114
- yield 'gas_price' , overrides ['gas_price' ]
115
- else :
116
- yield 'gas_price' , transaction .get ('gas_price' , 1 ) # TODO: make configurable
117
-
118
- if 'to' in overrides :
119
- yield 'to' , overrides ['to' ]
120
- else :
121
- yield 'to' , transaction .get ('to' , b'' )
122
-
123
- if 'data' in overrides :
124
- yield 'data' , overrides ['data' ]
125
- else :
126
- yield 'data' , transaction .get ('data' , b'' )
127
-
128
- if 'value' in overrides :
129
- yield 'value' , overrides ['value' ]
130
- else :
131
- yield 'value' , transaction .get ('value' , 0 )
132
-
133
- if 'nonce' in overrides :
134
- yield 'nonce' , overrides ['nonce' ]
135
- else :
136
- yield 'nonce' , transaction .get ('nonce' , 0 )
137
-
138
- if 'v' in overrides :
139
- yield 'v' , overrides ['v' ]
140
- else :
141
- yield 'v' , transaction .get ('v' , 27 )
136
+ else :
137
+ # legacy transaction
138
+ yield 'v' , overrides .get ('v' , transaction .get ('v' , 27 ))
142
139
143
- if 'r' in overrides :
144
- yield 'r' , overrides ['r' ]
145
- else :
146
- yield 'r' , transaction .get ('r' , 12345 )
147
140
148
- if 's' in overrides :
149
- yield 's ' , overrides [ 's' ]
150
- else :
151
- yield 's ' , transaction .get ('s ' , 67890 )
141
+ def _yield_typed_transaction_fields ( overrides , transaction ) :
142
+ yield 'chain_id ' , overrides . get ( 'chain_id' , transaction . get ( 'chain_id' , 131277322940537 ))
143
+ yield 'access_list' , overrides . get ( 'access_list' , transaction . get ( 'access_list' , ()))
144
+ yield 'y_parity ' , overrides . get ( 'y_parity' , transaction .get ('y_parity ' , 0 ) )
152
145
153
146
154
147
@to_dict
@@ -200,36 +193,33 @@ def make_log(transaction, block, transaction_index, log_index, overrides=None):
200
193
201
194
202
195
@to_dict
203
- def make_receipt (transaction , block , transaction_index , overrides = None ):
196
+ def make_receipt (transaction , block , _transaction_index , overrides = None ):
204
197
if overrides is None :
205
198
overrides = {}
206
199
207
- if 'gas_used' in overrides :
208
- gas_used = overrides ['gas_used' ]
209
- else :
210
- gas_used = 21000
200
+ gas_used = overrides .get ('gas_used' , 21000 )
211
201
yield 'gas_used' , gas_used
212
-
213
- if 'cumulative_gas_used' in overrides :
214
- yield 'cumulative_gas_used' , overrides [ 'cumulative_gas_used' ]
215
- else :
216
- yield 'cumulative_gas_used' , block [ 'gas_used' ] + gas_used
217
-
218
- if 'contract_address' in overrides :
219
- yield 'contract_address' , overrides [ 'contract_address' ]
220
- else :
221
- contract_address = generate_contract_address ( transaction [ 'from' ], transaction [ 'nonce' ] )
222
- yield 'contract_address' , contract_address
223
-
224
- if 'logs' in overrides :
225
- yield 'logs' , overrides [ 'logs' ]
226
- else :
227
- yield 'logs' , []
228
-
229
- if 'transaction_hash' in overrides :
230
- yield 'transaction_hash' , overrides [ 'transaction_hash' ]
231
- else :
232
- yield 'transaction_hash' , transaction [ 'hash' ]
202
+ yield 'logs' , overrides . get ( 'logs' , [])
203
+ yield 'transaction_hash' , overrides . get ( 'transaction_hash' , transaction . get ( 'hash' ))
204
+ yield (
205
+ 'cumulative_gas_used' ,
206
+ overrides . get ( 'cumulative_gas_used' , block . get ( 'gas_used' ) + gas_used )
207
+ )
208
+ yield (
209
+ 'effective_gas_price' ,
210
+ overrides . get ( 'effective_gas_price' , calculate_effective_gas_price ( transaction , block ))
211
+ )
212
+ yield (
213
+ 'type' ,
214
+ overrides . get ( 'type' , transaction . get ( 'type' , extract_transaction_type ( transaction )))
215
+ )
216
+ yield (
217
+ 'contract_address' ,
218
+ overrides . get (
219
+ 'contract_address' ,
220
+ generate_contract_address ( transaction [ 'from' ], transaction [ 'nonce' ])
221
+ )
222
+ )
233
223
234
224
235
225
GENESIS_NONCE = b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 *' # 42 encoded as big-endian-integer
@@ -253,11 +243,12 @@ def make_genesis_block(overrides=None):
253
243
"total_difficulty" : 131072 ,
254
244
"size" : 0 ,
255
245
"extra_data" : ZERO_32BYTES ,
256
- "gas_limit" : 3141592 ,
246
+ "gas_limit" : 30029122 , # gas limit at London fork block 12965000 on mainnet
257
247
"gas_used" : 0 ,
258
248
"timestamp" : int (time .time ()),
259
249
"transactions" : [],
260
250
"uncles" : [],
251
+ "base_fee_per_gas" : 1000000000 , # base fee at London fork block 12965000 on mainnet
261
252
}
262
253
if overrides is not None :
263
254
genesis_block = merge_genesis_overrides (defaults = default_genesis_block ,
@@ -368,3 +359,38 @@ def make_block_from_parent(parent_block, overrides=None):
368
359
yield 'uncles' , overrides ['uncles' ]
369
360
else :
370
361
yield 'uncles' , []
362
+
363
+ if 'base_fee_per_gas' in overrides :
364
+ yield 'base_fee_per_gas' , overrides ['base_fee_per_gas' ]
365
+ else :
366
+ yield 'base_fee_per_gas' , _calculate_expected_base_fee_per_gas (parent_block )
367
+
368
+
369
+ def _calculate_expected_base_fee_per_gas (parent_block ) -> int :
370
+ """py-evm logic for calculating the base fee from parent header"""
371
+ parent_base_fee_per_gas = parent_block ['base_fee_per_gas' ]
372
+
373
+ parent_gas_target = parent_block ['gas_limit' ] // BLOCK_ELASTICITY_MULTIPLIER
374
+ parent_gas_used = parent_block ['gas_used' ]
375
+
376
+ if parent_gas_used == parent_gas_target :
377
+ return parent_base_fee_per_gas
378
+
379
+ elif parent_gas_used > parent_gas_target :
380
+ gas_used_delta = parent_gas_used - parent_gas_target
381
+ overburnt_wei = parent_base_fee_per_gas * gas_used_delta
382
+ base_fee_per_gas_delta = max (
383
+ overburnt_wei // parent_gas_target // BASE_FEE_MAX_CHANGE_DENOMINATOR ,
384
+ 1 ,
385
+ )
386
+ return parent_base_fee_per_gas + base_fee_per_gas_delta
387
+
388
+ else :
389
+ gas_used_delta = parent_gas_target - parent_gas_used
390
+ underburnt_wei = parent_base_fee_per_gas * gas_used_delta
391
+ base_fee_per_gas_delta = (
392
+ underburnt_wei
393
+ // parent_gas_target
394
+ // BASE_FEE_MAX_CHANGE_DENOMINATOR
395
+ )
396
+ return max (parent_base_fee_per_gas - base_fee_per_gas_delta , 0 )
0 commit comments