@@ -2023,14 +2023,13 @@ impl FrameTransaction {
20232023 keccak ( & buf)
20242024 }
20252025
2026- /// Per EIP-8141 (spec commit fe0940cae2): 2800 gas per SECP256K1 signature,
2027- /// 6700 per P256. Unknown schemes are rejected by static validation, so
2028- /// they are treated as 0 here (validation runs first).
2026+ /// Per EIP-8141: 100 gas per ARBITRARY signature, 2800 per SECP256K1, and
2027+ /// 6700 per P256. Unknown schemes are rejected by static validation.
20292028 pub fn signature_verification_cost ( & self ) -> u64 {
20302029 self . signatures
20312030 . iter ( )
20322031 . map ( |s| match s. scheme {
2033- FRAME_SIG_SCHEME_ARBITRARY => 0u64 ,
2032+ FRAME_SIG_SCHEME_ARBITRARY => 100u64 ,
20342033 FRAME_SIG_SCHEME_SECP256K1 => 2800u64 ,
20352034 FRAME_SIG_SCHEME_P256 => 6700u64 ,
20362035 _ => 0 ,
@@ -5485,11 +5484,11 @@ mod tests {
54855484 #[ test]
54865485 fn static_validation_accepts_arbitrary_with_empty_signer ( ) {
54875486 let mut tx = make_test_frame_tx ( ) ;
5488- // ARBITRARY (scheme 0) requires an empty signer and costs no verify gas.
5487+ // ARBITRARY requires an empty signer and charges 100 verification gas.
54895488 tx. signatures [ 0 ] . scheme = FRAME_SIG_SCHEME_ARBITRARY ;
54905489 tx. signatures [ 0 ] . signer = None ;
54915490 assert ! ( tx. validate_static_constraints( ) . is_ok( ) ) ;
5492- assert_eq ! ( tx. signature_verification_cost( ) , 0 ) ;
5491+ assert_eq ! ( tx. signature_verification_cost( ) , 100 ) ;
54935492 }
54945493
54955494 #[ test]
@@ -5574,6 +5573,50 @@ mod tests {
55745573 assert_eq ! ( tx. signature_verification_cost( ) , 2800 + 6700 ) ;
55755574 }
55765575
5576+ #[ test]
5577+ fn total_gas_limit_charges_arbitrary_signature_100_gas ( ) {
5578+ let mut arb = make_test_frame_tx ( ) ;
5579+ arb. signatures [ 0 ] . scheme = FRAME_SIG_SCHEME_ARBITRARY ;
5580+ arb. signatures [ 0 ] . signer = None ;
5581+ let mut secp = make_test_frame_tx ( ) ;
5582+ secp. signatures [ 0 ] . signer = None ;
5583+
5584+ let sig_rlp = |sigs : & Vec < FrameSignature > | -> ( usize , usize ) {
5585+ let mut buf = Vec :: new ( ) ;
5586+ sigs. encode ( & mut buf) ;
5587+ ( buf. len ( ) , buf. iter ( ) . filter ( |b| * * b == 0 ) . count ( ) )
5588+ } ;
5589+ assert_eq ! ( sig_rlp( & arb. signatures) , sig_rlp( & secp. signatures) ) ;
5590+
5591+ assert_eq ! ( arb. signature_verification_cost( ) , 100 ) ;
5592+ assert_eq ! ( secp. signature_verification_cost( ) , 2800 ) ;
5593+ assert_eq ! ( secp. total_gas_limit( ) - arb. total_gas_limit( ) , 2800 - 100 ) ;
5594+ }
5595+
5596+ #[ test]
5597+ fn prefix_gas_budget_counts_arbitrary_signature_cost_at_boundary ( ) {
5598+ let mut tx = make_test_frame_tx ( ) ;
5599+ tx. signatures [ 0 ] . scheme = FRAME_SIG_SCHEME_ARBITRARY ;
5600+ tx. signatures [ 0 ] . signer = None ;
5601+ assert ! ( tx. validate_static_constraints( ) . is_ok( ) ) ;
5602+
5603+ tx. frames [ 0 ] . gas_limit = FRAME_TX_MAX_VERIFY_GAS - 100 ;
5604+ let prefix = tx. validation_prefix ( ) . unwrap ( ) ;
5605+ assert_eq ! ( prefix. shape, PrefixShape :: SelfVerify ) ;
5606+ assert_eq ! ( prefix. frame_indices, vec![ 0 ] ) ;
5607+ assert ! ( tx. validate_prefix_structure( & prefix) . is_ok( ) ) ;
5608+
5609+ tx. frames [ 0 ] . gas_limit = FRAME_TX_MAX_VERIFY_GAS - 99 ;
5610+ let prefix = tx. validation_prefix ( ) . unwrap ( ) ;
5611+ assert_eq ! (
5612+ tx. validate_prefix_structure( & prefix) . unwrap_err( ) ,
5613+ FrameValidationError :: VerifyGasBudgetExceeded {
5614+ actual: FRAME_TX_MAX_VERIFY_GAS + 1 ,
5615+ limit: FRAME_TX_MAX_VERIFY_GAS ,
5616+ } ,
5617+ ) ;
5618+ }
5619+
55775620 #[ test]
55785621 fn golden_frame_tx_rlp_and_sig_hash ( ) {
55795622 // Regression lock for the EIP-8141 signatures-list wire format (spec
0 commit comments