@@ -61,7 +61,9 @@ use sp_runtime::{
6161 AccountIdLookup , BlakeTwo256 , Block as BlockT , DispatchInfoOf , Dispatchable , One ,
6262 PostDispatchInfoOf , UniqueSaturatedInto , Verify ,
6363 } ,
64- transaction_validity:: { TransactionSource , TransactionValidity , TransactionValidityError } ,
64+ transaction_validity:: {
65+ TransactionPriority , TransactionSource , TransactionValidity , TransactionValidityError ,
66+ } ,
6567} ;
6668use sp_std:: cmp:: Ordering ;
6769use sp_std:: prelude:: * ;
@@ -1224,6 +1226,10 @@ impl<F: FindAuthor<u32>> FindAuthor<H160> for FindAuthorTruncated<F> {
12241226}
12251227
12261228const BLOCK_GAS_LIMIT : u64 = 75_000_000 ;
1229+ pub const NORMAL_DISPATCH_BASE_PRIORITY : TransactionPriority = 1 ;
1230+ pub const OPERATIONAL_DISPATCH_PRIORITY : TransactionPriority = 10_000_000_000 ;
1231+ const EVM_TRANSACTION_BASE_PRIORITY : TransactionPriority = NORMAL_DISPATCH_BASE_PRIORITY ;
1232+ const EVM_LOG_TARGET : & str = "runtime::ethereum" ;
12271233
12281234/// `WeightPerGas` is an approximate ratio of the amount of Weight per Gas.
12291235///
@@ -1387,6 +1393,35 @@ impl<B: BlockT> fp_rpc::ConvertTransaction<<B as BlockT>::Extrinsic> for Transac
13871393 }
13881394}
13891395
1396+ fn adjust_evm_priority_and_warn (
1397+ validity : & mut Option < TransactionValidity > ,
1398+ priority_fee : Option < U256 > ,
1399+ info : & H160 ,
1400+ ) {
1401+ if let Some ( Ok ( valid_transaction) ) = validity. as_mut ( ) {
1402+ let original_priority = valid_transaction. priority ;
1403+ valid_transaction. priority = EVM_TRANSACTION_BASE_PRIORITY ;
1404+
1405+ let has_priority_fee = priority_fee. is_some_and ( |fee| !fee. is_zero ( ) ) ;
1406+ if has_priority_fee {
1407+ log:: warn!(
1408+ target: EVM_LOG_TARGET ,
1409+ "Priority fee/tip from {:?} (max_priority_fee_per_gas: {:?}) is ignored for transaction ordering" ,
1410+ info,
1411+ priority_fee. unwrap_or_default( ) ,
1412+ ) ;
1413+ } else if original_priority > EVM_TRANSACTION_BASE_PRIORITY {
1414+ log:: warn!(
1415+ target: EVM_LOG_TARGET ,
1416+ "EVM transaction priority from {:?} reduced from {} to {}; priority tips are ignored for ordering" ,
1417+ info,
1418+ original_priority,
1419+ EVM_TRANSACTION_BASE_PRIORITY ,
1420+ ) ;
1421+ }
1422+ }
1423+ }
1424+
13901425impl fp_self_contained:: SelfContainedCall for RuntimeCall {
13911426 type SignedInfo = H160 ;
13921427
@@ -1411,7 +1446,21 @@ impl fp_self_contained::SelfContainedCall for RuntimeCall {
14111446 len : usize ,
14121447 ) -> Option < TransactionValidity > {
14131448 match self {
1414- RuntimeCall :: Ethereum ( call) => call. validate_self_contained ( info, dispatch_info, len) ,
1449+ RuntimeCall :: Ethereum ( call) => {
1450+ let priority_fee = match call {
1451+ pallet_ethereum:: Call :: transact { transaction } => match transaction {
1452+ EthereumTransaction :: EIP1559 ( tx) => Some ( tx. max_priority_fee_per_gas ) ,
1453+ EthereumTransaction :: EIP7702 ( tx) => Some ( tx. max_priority_fee_per_gas ) ,
1454+ _ => None ,
1455+ } ,
1456+ _ => None ,
1457+ } ;
1458+
1459+ let mut validity = call. validate_self_contained ( info, dispatch_info, len) ;
1460+ adjust_evm_priority_and_warn ( & mut validity, priority_fee, info) ;
1461+
1462+ validity
1463+ }
14151464 _ => None ,
14161465 }
14171466 }
@@ -2622,6 +2671,52 @@ fn test_into_substrate_balance_zero_value() {
26222671 assert_eq ! ( result, Some ( expected_substrate_balance) ) ;
26232672}
26242673
2674+ #[ test]
2675+ fn evm_priority_overrides_tip_to_base ( ) {
2676+ let mut validity: Option < TransactionValidity > =
2677+ Some ( Ok ( sp_runtime:: transaction_validity:: ValidTransaction {
2678+ priority : 99 ,
2679+ requires : vec ! [ ] ,
2680+ provides : vec ! [ ] ,
2681+ longevity : sp_runtime:: transaction_validity:: TransactionLongevity :: MAX ,
2682+ propagate : true ,
2683+ } ) ) ;
2684+
2685+ let signer = H160 :: repeat_byte ( 1 ) ;
2686+ adjust_evm_priority_and_warn ( & mut validity, Some ( U256 :: from ( 10 ) ) , & signer) ;
2687+
2688+ let adjusted_priority = validity
2689+ . as_ref ( )
2690+ . and_then ( |v| v. as_ref ( ) . ok ( ) )
2691+ . map ( |v| v. priority ) ;
2692+
2693+ assert_eq ! ( adjusted_priority, Some ( EVM_TRANSACTION_BASE_PRIORITY ) ) ;
2694+ }
2695+
2696+ #[ test]
2697+ fn evm_priority_cannot_overtake_unstake ( ) {
2698+ // Unstake is a normal-class extrinsic (priority = NORMAL_DISPATCH_BASE_PRIORITY).
2699+ let unstake_priority: TransactionPriority = NORMAL_DISPATCH_BASE_PRIORITY ;
2700+ let evm_priority: TransactionPriority = EVM_TRANSACTION_BASE_PRIORITY ;
2701+
2702+ // Clamp guarantees the EVM tx is never above the unstake priority.
2703+ assert ! ( evm_priority <= unstake_priority) ;
2704+
2705+ // If both arrive with equal priority, arrival order keeps unstake first.
2706+ let mut queue: Vec < ( & str , TransactionPriority , usize ) > = vec ! [
2707+ ( "unstake" , unstake_priority, 0 ) , // arrives first
2708+ ( "evm" , evm_priority, 1 ) , // arrives later
2709+ ] ;
2710+
2711+ queue. sort_by ( |a, b| {
2712+ b. 1 . cmp ( & a. 1 ) // higher priority first
2713+ . then_with ( || a. 2 . cmp ( & b. 2 ) ) // earlier arrival first when equal
2714+ } ) ;
2715+
2716+ let first = queue. first ( ) . map ( |entry| entry. 0 ) ;
2717+ assert_eq ! ( first, Some ( "unstake" ) ) ;
2718+ }
2719+
26252720#[ test]
26262721fn test_into_evm_balance_valid ( ) {
26272722 // Valid conversion from Substrate to EVM
0 commit comments