1
1
use crate :: {
2
2
evm_circuit:: {
3
3
execution:: ExecutionGadget ,
4
- param:: { N_BYTES_ACCOUNT_ADDRESS , N_BYTES_GAS , N_BYTES_WORD } ,
4
+ param:: { N_BYTES_ACCOUNT_ADDRESS , N_BYTES_GAS , N_BYTES_U64 , N_BYTES_WORD } ,
5
5
step:: ExecutionState ,
6
6
util:: {
7
7
and,
@@ -12,14 +12,16 @@ use crate::{
12
12
} ,
13
13
is_precompiled,
14
14
math_gadget:: {
15
- ContractCreateGadget , IsEqualGadget , IsZeroGadget , MulWordByU64Gadget ,
16
- RangeCheckGadget ,
15
+ ConstantDivisionGadget , ContractCreateGadget , IsEqualGadget , IsZeroGadget ,
16
+ MulWordByU64Gadget , RangeCheckGadget ,
17
17
} ,
18
18
not, or, select, CachedRegion , Cell , StepRws , Word ,
19
19
} ,
20
20
witness:: { Block , Call , ExecStep , Transaction } ,
21
21
} ,
22
- table:: { AccountFieldTag , CallContextFieldTag , TxFieldTag as TxContextFieldTag } ,
22
+ table:: {
23
+ AccountFieldTag , BlockContextFieldTag , CallContextFieldTag , TxFieldTag as TxContextFieldTag ,
24
+ } ,
23
25
util:: Expr ,
24
26
} ;
25
27
use eth_types:: { evm_types:: GasCost , Field , ToLittleEndian , ToScalar } ;
@@ -42,6 +44,7 @@ pub(crate) struct BeginTxGadget<F> {
42
44
tx_value : Word < F > ,
43
45
tx_call_data_length : Cell < F > ,
44
46
tx_call_data_gas_cost : Cell < F > ,
47
+ tx_call_data_word_length : ConstantDivisionGadget < F , N_BYTES_U64 > ,
45
48
reversion_info : ReversionInfo < F > ,
46
49
sufficient_gas_left : RangeCheckGadget < F , N_BYTES_GAS > ,
47
50
transfer_with_gas_fee : TransferWithGasFeeGadget < F > ,
@@ -51,6 +54,12 @@ pub(crate) struct BeginTxGadget<F> {
51
54
create : ContractCreateGadget < F , false > ,
52
55
callee_not_exists : IsZeroGadget < F > ,
53
56
is_caller_callee_equal : Cell < F > ,
57
+ // EIP-3651 (Warm COINBASE)
58
+ coinbase : Cell < F > ,
59
+ // Caller, callee and a list addresses are added to the access list before
60
+ // coinbase, and may be duplicate.
61
+ // <https://github.com/ethereum/go-ethereum/blob/604e215d1bb070dff98fb76aa965064c74e3633f/core/state/statedb.go#LL1119C9-L1119C9>
62
+ is_coinbase_warm : Cell < F > ,
54
63
}
55
64
56
65
impl < F : Field > ExecutionGadget < F > for BeginTxGadget < F > {
@@ -126,13 +135,25 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
126
135
let mul_gas_fee_by_gas =
127
136
MulWordByU64Gadget :: construct ( cb, tx_gas_price. clone ( ) , tx_gas. expr ( ) ) ;
128
137
138
+ let tx_call_data_word_length =
139
+ ConstantDivisionGadget :: construct ( cb, tx_call_data_length. expr ( ) + 31 . expr ( ) , 32 ) ;
140
+
141
+ // Calculate gas cost of init code for EIP-3860.
142
+ let init_code_gas_cost = select:: expr (
143
+ tx_is_create. expr ( ) ,
144
+ tx_call_data_word_length. quotient ( ) . expr ( )
145
+ * eth_types:: evm_types:: INIT_CODE_WORD_GAS . expr ( ) ,
146
+ 0 . expr ( ) ,
147
+ ) ;
148
+
129
149
// TODO: Take gas cost of access list (EIP 2930) into consideration.
130
150
// Use intrinsic gas
131
151
let intrinsic_gas_cost = select:: expr (
132
152
tx_is_create. expr ( ) ,
133
153
GasCost :: CREATION_TX . expr ( ) ,
134
154
GasCost :: TX . expr ( ) ,
135
- ) + tx_call_data_gas_cost. expr ( ) ;
155
+ ) + tx_call_data_gas_cost. expr ( )
156
+ + init_code_gas_cost;
136
157
137
158
// Check gas_left is sufficient
138
159
let gas_left = tx_gas. expr ( ) - intrinsic_gas_cost;
@@ -157,6 +178,18 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
157
178
None ,
158
179
) ; // rwc_delta += 1
159
180
181
+ // Query coinbase address.
182
+ let coinbase = cb. query_cell ( ) ;
183
+ let is_coinbase_warm = cb. query_bool ( ) ;
184
+ cb. block_lookup ( BlockContextFieldTag :: Coinbase . expr ( ) , None , coinbase. expr ( ) ) ;
185
+ cb. account_access_list_write (
186
+ tx_id. expr ( ) ,
187
+ coinbase. expr ( ) ,
188
+ 1 . expr ( ) ,
189
+ is_coinbase_warm. expr ( ) ,
190
+ None ,
191
+ ) ; // rwc_delta += 1
192
+
160
193
// Read code_hash of callee
161
194
let phase2_code_hash = cb. query_cell_phase2 ( ) ;
162
195
let is_empty_code_hash =
@@ -261,8 +294,9 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
261
294
// - Write CallContext IsPersistent
262
295
// - Write CallContext IsSuccess
263
296
// - Write Account (Caller) Nonce
264
- // - Write TxAccessListAccount
265
- // - Write TxAccessListAccount
297
+ // - Write TxAccessListAccount (Caller)
298
+ // - Write TxAccessListAccount (Callee)
299
+ // - Write TxAccessListAccount (Coinbase) for EIP-3651
266
300
// - a TransferWithGasFeeGadget
267
301
// - Write Account (Callee) Nonce (Reversible)
268
302
// - Write CallContext Depth
@@ -278,7 +312,7 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
278
312
// - Write CallContext IsRoot
279
313
// - Write CallContext IsCreate
280
314
// - Write CallContext CodeHash
281
- rw_counter : Delta ( 21 . expr ( ) + transfer_with_gas_fee. rw_delta ( ) ) ,
315
+ rw_counter : Delta ( 22 . expr ( ) + transfer_with_gas_fee. rw_delta ( ) ) ,
282
316
call_id : To ( call_id. expr ( ) ) ,
283
317
is_root : To ( true . expr ( ) ) ,
284
318
is_create : To ( tx_is_create. expr ( ) ) ,
@@ -317,11 +351,12 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
317
351
// - Write CallContext IsPersistent
318
352
// - Write CallContext IsSuccess
319
353
// - Write Account Nonce
320
- // - Write TxAccessListAccount
321
- // - Write TxAccessListAccount
354
+ // - Write TxAccessListAccount (Caller)
355
+ // - Write TxAccessListAccount (Callee)
356
+ // - Write TxAccessListAccount (Coinbase) for EIP-3651
322
357
// - Read Account CodeHash
323
358
// - a TransferWithGasFeeGadget
324
- rw_counter : Delta ( 8 . expr ( ) + transfer_with_gas_fee. rw_delta ( ) ) ,
359
+ rw_counter : Delta ( 9 . expr ( ) + transfer_with_gas_fee. rw_delta ( ) ) ,
325
360
call_id : To ( call_id. expr ( ) ) ,
326
361
..StepStateTransition :: any ( )
327
362
} ) ;
@@ -361,8 +396,9 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
361
396
// - Write CallContext IsPersistent
362
397
// - Write CallContext IsSuccess
363
398
// - Write Account Nonce
364
- // - Write TxAccessListAccount
365
- // - Write TxAccessListAccount
399
+ // - Write TxAccessListAccount (Caller)
400
+ // - Write TxAccessListAccount (Callee)
401
+ // - Write TxAccessListAccount (Coinbase) for EIP-3651
366
402
// - Read Account CodeHash
367
403
// - a TransferWithGasFeeGadget
368
404
// - Write CallContext Depth
@@ -378,7 +414,7 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
378
414
// - Write CallContext IsRoot
379
415
// - Write CallContext IsCreate
380
416
// - Write CallContext CodeHash
381
- rw_counter : Delta ( 21 . expr ( ) + transfer_with_gas_fee. rw_delta ( ) ) ,
417
+ rw_counter : Delta ( 22 . expr ( ) + transfer_with_gas_fee. rw_delta ( ) ) ,
382
418
call_id : To ( call_id. expr ( ) ) ,
383
419
is_root : To ( true . expr ( ) ) ,
384
420
is_create : To ( tx_is_create. expr ( ) ) ,
@@ -405,6 +441,7 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
405
441
tx_value,
406
442
tx_call_data_length,
407
443
tx_call_data_gas_cost,
444
+ tx_call_data_word_length,
408
445
reversion_info,
409
446
sufficient_gas_left,
410
447
transfer_with_gas_fee,
@@ -414,6 +451,8 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
414
451
create,
415
452
callee_not_exists,
416
453
is_caller_callee_equal,
454
+ coinbase,
455
+ is_coinbase_warm,
417
456
}
418
457
}
419
458
@@ -431,6 +470,8 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
431
470
432
471
let mut rws = StepRws :: new ( block, step) ;
433
472
rws. offset_add ( 7 ) ;
473
+
474
+ let is_coinbase_warm = rws. next ( ) . tx_access_list_value_pair ( ) . 1 ;
434
475
let mut callee_code_hash = zero;
435
476
if !is_precompiled ( & tx. callee_address ) && !tx. is_create {
436
477
callee_code_hash = rws. next ( ) . account_value_pair ( ) . 1 ;
@@ -503,6 +544,8 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
503
544
offset,
504
545
Value :: known ( F :: from ( tx. call_data_gas_cost ) ) ,
505
546
) ?;
547
+ self . tx_call_data_word_length
548
+ . assign ( region, offset, tx. call_data_length as u128 + 31 ) ?;
506
549
self . reversion_info . assign (
507
550
region,
508
551
offset,
@@ -556,6 +599,23 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
556
599
None ,
557
600
) ?;
558
601
602
+ self . coinbase . assign (
603
+ region,
604
+ offset,
605
+ Value :: known (
606
+ block
607
+ . context
608
+ . coinbase
609
+ . to_scalar ( )
610
+ . expect ( "unexpected Address -> Scalar conversion failure" ) ,
611
+ ) ,
612
+ ) ?;
613
+ self . is_coinbase_warm . assign (
614
+ region,
615
+ offset,
616
+ Value :: known ( F :: from ( is_coinbase_warm as u64 ) ) ,
617
+ ) ?;
618
+
559
619
Ok ( ( ) )
560
620
}
561
621
}
0 commit comments