Skip to content

Commit dc905f1

Browse files
feat(l1): charge EIP-8141 arbitrary frame signatures their own gas
1 parent cee872d commit dc905f1

1 file changed

Lines changed: 49 additions & 6 deletions

File tree

crates/common/types/transaction.rs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)