@@ -54,7 +54,7 @@ type CallOf<T> = <T as frame_system::Config>::RuntimeCall;
54
54
/// - Not too high, ensuring the gas value is large enough (at least 7 digits) to encode the
55
55
/// ref_time, proof_size, and deposit into the less significant (6 lower) digits of the gas value.
56
56
/// - Not too low, enabling users to adjust the gas price to define a tip.
57
- pub const GAS_PRICE : u32 = 100_000u32 ;
57
+ pub const GAS_PRICE : u32 = 1_000u32 ;
58
58
59
59
/// Convert a `Balance` into a gas value, using the fixed `GAS_PRICE`.
60
60
/// The gas is calculated as `balance / GAS_PRICE`, rounded up to the nearest integer.
@@ -324,6 +324,11 @@ pub trait EthExtra {
324
324
let GenericTransaction { nonce, chain_id, to, value, input, gas, gas_price, .. } =
325
325
GenericTransaction :: from_signed ( tx, None ) ;
326
326
327
+ let Some ( gas) = gas else {
328
+ log:: debug!( target: LOG_TARGET , "No gas provided" ) ;
329
+ return Err ( InvalidTransaction :: Call ) ;
330
+ } ;
331
+
327
332
if chain_id. unwrap_or_default ( ) != <Self :: Config as Config >:: ChainId :: get ( ) . into ( ) {
328
333
log:: debug!( target: LOG_TARGET , "Invalid chain_id {chain_id:?}" ) ;
329
334
return Err ( InvalidTransaction :: Call ) ;
@@ -337,13 +342,11 @@ pub trait EthExtra {
337
342
338
343
let data = input. unwrap_or_default ( ) . 0 ;
339
344
340
- let ( gas_limit, storage_deposit_limit) = <Self :: Config as Config >:: EthGasEncoder :: decode (
341
- gas. unwrap_or_default ( ) ,
342
- )
343
- . ok_or_else ( || {
344
- log:: debug!( target: LOG_TARGET , "Failed to decode gas: {gas:?}" ) ;
345
- InvalidTransaction :: Call
346
- } ) ?;
345
+ let ( gas_limit, storage_deposit_limit) =
346
+ <Self :: Config as Config >:: EthGasEncoder :: decode ( gas) . ok_or_else ( || {
347
+ log:: debug!( target: LOG_TARGET , "Failed to decode gas: {gas:?}" ) ;
348
+ InvalidTransaction :: Call
349
+ } ) ?;
347
350
348
351
let call = if let Some ( dest) = to {
349
352
crate :: Call :: call:: < Self :: Config > {
@@ -380,13 +383,13 @@ pub trait EthExtra {
380
383
// Fees calculated with the fixed `GAS_PRICE`
381
384
// When we dry-run the transaction, we set the gas to `Fee / GAS_PRICE`
382
385
let eth_fee_no_tip = U256 :: from ( GAS_PRICE )
383
- . saturating_mul ( gas. unwrap_or_default ( ) )
386
+ . saturating_mul ( gas)
384
387
. try_into ( )
385
388
. map_err ( |_| InvalidTransaction :: Call ) ?;
386
389
387
390
// Fees with the actual gas_price from the transaction.
388
391
let eth_fee: BalanceOf < Self :: Config > = U256 :: from ( gas_price. unwrap_or_default ( ) )
389
- . saturating_mul ( gas. unwrap_or_default ( ) )
392
+ . saturating_mul ( gas)
390
393
. try_into ( )
391
394
. map_err ( |_| InvalidTransaction :: Call ) ?;
392
395
@@ -410,11 +413,6 @@ pub trait EthExtra {
410
413
return Err ( InvalidTransaction :: Payment . into ( ) )
411
414
}
412
415
413
- if eth_fee_no_tip > actual_fee. saturating_mul ( 2u32 . into ( ) ) {
414
- log:: debug!( target: LOG_TARGET , "actual fees: {actual_fee:?} too high, base eth fees: {eth_fee_no_tip:?}" ) ;
415
- return Err ( InvalidTransaction :: Call . into ( ) )
416
- }
417
-
418
416
let tip = eth_fee. saturating_sub ( eth_fee_no_tip) ;
419
417
log:: debug!( target: LOG_TARGET , "Created checked Ethereum transaction with nonce: {nonce:?} and tip: {tip:?}" ) ;
420
418
Ok ( CheckedExtrinsic {
@@ -473,8 +471,6 @@ mod test {
473
471
#[ derive( Clone ) ]
474
472
struct UncheckedExtrinsicBuilder {
475
473
tx : GenericTransaction ,
476
- gas_limit : Weight ,
477
- storage_deposit_limit : BalanceOf < Test > ,
478
474
before_validate : Option < std:: sync:: Arc < dyn Fn ( ) + Send + Sync > > ,
479
475
}
480
476
@@ -488,8 +484,6 @@ mod test {
488
484
gas_price : Some ( U256 :: from ( GAS_PRICE ) ) ,
489
485
..Default :: default ( )
490
486
} ,
491
- gas_limit : Weight :: zero ( ) ,
492
- storage_deposit_limit : 0 ,
493
487
before_validate : None ,
494
488
}
495
489
}
@@ -506,11 +500,6 @@ mod test {
506
500
Ok ( dry_run) => {
507
501
log:: debug!( target: LOG_TARGET , "Estimated gas: {:?}" , dry_run. eth_gas) ;
508
502
self . tx . gas = Some ( dry_run. eth_gas ) ;
509
- let ( gas_limit, deposit) =
510
- <<Test as Config >:: EthGasEncoder as GasEncoder < _ > >:: decode ( dry_run. eth_gas )
511
- . unwrap ( ) ;
512
- self . gas_limit = gas_limit;
513
- self . storage_deposit_limit = deposit;
514
503
} ,
515
504
Err ( err) => {
516
505
log:: debug!( target: LOG_TARGET , "Failed to estimate gas: {:?}" , err) ;
@@ -522,31 +511,35 @@ mod test {
522
511
fn call_with ( dest : H160 ) -> Self {
523
512
let mut builder = Self :: new ( ) ;
524
513
builder. tx . to = Some ( dest) ;
525
- ExtBuilder :: default ( ) . build ( ) . execute_with ( || builder. estimate_gas ( ) ) ;
526
514
builder
527
515
}
528
516
529
517
/// Create a new builder with an instantiate call.
530
518
fn instantiate_with ( code : Vec < u8 > , data : Vec < u8 > ) -> Self {
531
519
let mut builder = Self :: new ( ) ;
532
520
builder. tx . input = Some ( Bytes ( code. into_iter ( ) . chain ( data. into_iter ( ) ) . collect ( ) ) ) ;
533
- ExtBuilder :: default ( ) . build ( ) . execute_with ( || builder. estimate_gas ( ) ) ;
534
521
builder
535
522
}
536
523
537
- /// Update the transaction with the given function.
538
- fn update ( mut self , f : impl FnOnce ( & mut GenericTransaction ) -> ( ) ) -> Self {
539
- f ( & mut self . tx ) ;
540
- self
541
- }
542
524
/// Set before_validate function.
543
525
fn before_validate ( mut self , f : impl Fn ( ) + Send + Sync + ' static ) -> Self {
544
526
self . before_validate = Some ( std:: sync:: Arc :: new ( f) ) ;
545
527
self
546
528
}
547
529
530
+ fn check (
531
+ self ,
532
+ ) -> Result < ( RuntimeCall , SignedExtra , GenericTransaction ) , TransactionValidityError > {
533
+ self . mutate_estimate_and_check ( Box :: new ( |_| ( ) ) )
534
+ }
535
+
548
536
/// Call `check` on the unchecked extrinsic, and `pre_dispatch` on the signed extension.
549
- fn check ( & self ) -> Result < ( RuntimeCall , SignedExtra ) , TransactionValidityError > {
537
+ fn mutate_estimate_and_check (
538
+ mut self ,
539
+ f : Box < dyn FnOnce ( & mut GenericTransaction ) -> ( ) > ,
540
+ ) -> Result < ( RuntimeCall , SignedExtra , GenericTransaction ) , TransactionValidityError > {
541
+ ExtBuilder :: default ( ) . build ( ) . execute_with ( || self . estimate_gas ( ) ) ;
542
+ f ( & mut self . tx ) ;
550
543
ExtBuilder :: default ( ) . build ( ) . execute_with ( || {
551
544
let UncheckedExtrinsicBuilder { tx, before_validate, .. } = self . clone ( ) ;
552
545
@@ -557,8 +550,9 @@ mod test {
557
550
100_000_000_000_000 ,
558
551
) ;
559
552
560
- let payload =
561
- account. sign_transaction ( tx. try_into_unsigned ( ) . unwrap ( ) ) . signed_payload ( ) ;
553
+ let payload = account
554
+ . sign_transaction ( tx. clone ( ) . try_into_unsigned ( ) . unwrap ( ) )
555
+ . signed_payload ( ) ;
562
556
let call = RuntimeCall :: Contracts ( crate :: Call :: eth_transact { payload } ) ;
563
557
564
558
let encoded_len = call. encoded_size ( ) ;
@@ -578,22 +572,26 @@ mod test {
578
572
0 ,
579
573
) ?;
580
574
581
- Ok ( ( result. function , extra) )
575
+ Ok ( ( result. function , extra, tx ) )
582
576
} )
583
577
}
584
578
}
585
579
586
580
#[ test]
587
581
fn check_eth_transact_call_works ( ) {
588
582
let builder = UncheckedExtrinsicBuilder :: call_with ( H160 :: from ( [ 1u8 ; 20 ] ) ) ;
583
+ let ( call, _, tx) = builder. check ( ) . unwrap ( ) ;
584
+ let ( gas_limit, storage_deposit_limit) =
585
+ <<Test as Config >:: EthGasEncoder as GasEncoder < _ > >:: decode ( tx. gas . unwrap ( ) ) . unwrap ( ) ;
586
+
589
587
assert_eq ! (
590
- builder . check ( ) . unwrap ( ) . 0 ,
588
+ call ,
591
589
crate :: Call :: call:: <Test > {
592
- dest: builder . tx. to. unwrap( ) ,
593
- value: builder . tx. value. unwrap_or_default( ) . as_u64( ) ,
594
- gas_limit : builder . gas_limit ,
595
- storage_deposit_limit : builder . storage_deposit_limit ,
596
- data : builder . tx . input . unwrap_or_default ( ) . 0
590
+ dest: tx. to. unwrap( ) ,
591
+ value: tx. value. unwrap_or_default( ) . as_u64( ) ,
592
+ data : tx . input . unwrap_or_default ( ) . 0 ,
593
+ gas_limit ,
594
+ storage_deposit_limit
597
595
}
598
596
. into( )
599
597
) ;
@@ -604,28 +602,30 @@ mod test {
604
602
let ( code, _) = compile_module ( "dummy" ) . unwrap ( ) ;
605
603
let data = vec ! [ ] ;
606
604
let builder = UncheckedExtrinsicBuilder :: instantiate_with ( code. clone ( ) , data. clone ( ) ) ;
605
+ let ( call, _, tx) = builder. check ( ) . unwrap ( ) ;
606
+ let ( gas_limit, storage_deposit_limit) =
607
+ <<Test as Config >:: EthGasEncoder as GasEncoder < _ > >:: decode ( tx. gas . unwrap ( ) ) . unwrap ( ) ;
607
608
608
609
assert_eq ! (
609
- builder . check ( ) . unwrap ( ) . 0 ,
610
+ call ,
610
611
crate :: Call :: instantiate_with_code:: <Test > {
611
- value: builder. tx. value. unwrap_or_default( ) . as_u64( ) ,
612
- gas_limit: builder. gas_limit,
613
- storage_deposit_limit: builder. storage_deposit_limit,
612
+ value: tx. value. unwrap_or_default( ) . as_u64( ) ,
614
613
code,
615
614
data,
616
- salt: None
615
+ salt: None ,
616
+ gas_limit,
617
+ storage_deposit_limit
617
618
}
618
619
. into( )
619
620
) ;
620
621
}
621
622
622
623
#[ test]
623
624
fn check_eth_transact_nonce_works ( ) {
624
- let builder = UncheckedExtrinsicBuilder :: call_with ( H160 :: from ( [ 1u8 ; 20 ] ) )
625
- . update ( |tx| tx. nonce = Some ( 1u32 . into ( ) ) ) ;
625
+ let builder = UncheckedExtrinsicBuilder :: call_with ( H160 :: from ( [ 1u8 ; 20 ] ) ) ;
626
626
627
627
assert_eq ! (
628
- builder. check ( ) ,
628
+ builder. mutate_estimate_and_check ( Box :: new ( |tx| tx . nonce = Some ( 1u32 . into ( ) ) ) ) ,
629
629
Err ( TransactionValidityError :: Invalid ( InvalidTransaction :: Future ) )
630
630
) ;
631
631
@@ -642,11 +642,10 @@ mod test {
642
642
643
643
#[ test]
644
644
fn check_eth_transact_chain_id_works ( ) {
645
- let builder = UncheckedExtrinsicBuilder :: call_with ( H160 :: from ( [ 1u8 ; 20 ] ) )
646
- . update ( |tx| tx. chain_id = Some ( 42 . into ( ) ) ) ;
645
+ let builder = UncheckedExtrinsicBuilder :: call_with ( H160 :: from ( [ 1u8 ; 20 ] ) ) ;
647
646
648
647
assert_eq ! (
649
- builder. check ( ) ,
648
+ builder. mutate_estimate_and_check ( Box :: new ( |tx| tx . chain_id = Some ( 42 . into ( ) ) ) ) ,
650
649
Err ( TransactionValidityError :: Invalid ( InvalidTransaction :: Call ) )
651
650
) ;
652
651
}
@@ -659,7 +658,7 @@ mod test {
659
658
660
659
// Fail because the tx input fail to get the blob length
661
660
assert_eq ! (
662
- builder. clone ( ) . update ( |tx| tx. input = Some ( Bytes ( vec![ 1 , 2 , 3 ] ) ) ) . check ( ) ,
661
+ builder. mutate_estimate_and_check ( Box :: new ( |tx| tx. input = Some ( Bytes ( vec![ 1 , 2 , 3 ] ) ) ) ) ,
663
662
Err ( TransactionValidityError :: Invalid ( InvalidTransaction :: Call ) )
664
663
) ;
665
664
}
@@ -674,13 +673,6 @@ mod test {
674
673
} ) ,
675
674
InvalidTransaction :: Payment ,
676
675
) ,
677
- (
678
- "Gas fees too high" ,
679
- Box :: new( |tx| {
680
- tx. gas = Some ( tx. gas. unwrap( ) * 2 ) ;
681
- } ) ,
682
- InvalidTransaction :: Call ,
683
- ) ,
684
676
(
685
677
"Gas fees too low" ,
686
678
Box :: new( |tx| {
@@ -691,27 +683,27 @@ mod test {
691
683
] ;
692
684
693
685
for ( msg, update_tx, err) in scenarios {
694
- let builder =
695
- UncheckedExtrinsicBuilder :: call_with ( H160 :: from ( [ 1u8 ; 20 ] ) ) . update ( update_tx) ;
686
+ let res = UncheckedExtrinsicBuilder :: call_with ( H160 :: from ( [ 1u8 ; 20 ] ) )
687
+ . mutate_estimate_and_check ( update_tx) ;
696
688
697
- assert_eq ! ( builder . check ( ) , Err ( TransactionValidityError :: Invalid ( err) ) , "{}" , msg) ;
689
+ assert_eq ! ( res , Err ( TransactionValidityError :: Invalid ( err) ) , "{}" , msg) ;
698
690
}
699
691
}
700
692
701
693
#[ test]
702
694
fn check_transaction_tip ( ) {
703
695
let ( code, _) = compile_module ( "dummy" ) . unwrap ( ) ;
704
696
let data = vec ! [ ] ;
705
- let builder = UncheckedExtrinsicBuilder :: instantiate_with ( code. clone ( ) , data. clone ( ) )
706
- . update ( |tx| {
707
- tx. gas_price = Some ( tx. gas_price . unwrap ( ) * 103 / 100 ) ;
708
- log:: debug!( target: LOG_TARGET , "Gas price: {:?}" , tx. gas_price) ;
709
- } ) ;
697
+ let ( _, extra, tx) =
698
+ UncheckedExtrinsicBuilder :: instantiate_with ( code. clone ( ) , data. clone ( ) )
699
+ . mutate_estimate_and_check ( Box :: new ( |tx| {
700
+ tx. gas_price = Some ( tx. gas_price . unwrap ( ) * 103 / 100 ) ;
701
+ log:: debug!( target: LOG_TARGET , "Gas price: {:?}" , tx. gas_price) ;
702
+ } ) )
703
+ . unwrap ( ) ;
710
704
711
- let tx = & builder. tx ;
712
705
let expected_tip =
713
706
tx. gas_price . unwrap ( ) * tx. gas . unwrap ( ) - U256 :: from ( GAS_PRICE ) * tx. gas . unwrap ( ) ;
714
- let ( _, extra) = builder. check ( ) . unwrap ( ) ;
715
707
assert_eq ! ( U256 :: from( extra. 1 . tip( ) ) , expected_tip) ;
716
708
}
717
709
}
0 commit comments