add gas tests at op-level

This commit is contained in:
Alejandro Cabeza Romero
2026-08-25 17:27:45 +02:00
parent a944f0f8bd
commit a05760db73
14 changed files with 250 additions and 11 deletions
+58
View File
@@ -160,3 +160,61 @@ pub trait SignedOperationExecutionGas {
Self::GAS_COST.checked_mul(self.gas_multiplier())
}
}
#[cfg(test)]
mod tests {
use super::{Gas, GasOverflow, MainnetGasProfile, OperationGas, SignedOperationExecutionGas};
use crate::mantle::Value;
struct ScalingOp(Value);
impl OperationGas<MainnetGasProfile> for ScalingOp {
const GAS_COST: Gas = Gas::new(7);
}
impl SignedOperationExecutionGas for ScalingOp {
fn gas_multiplier(&self) -> Value {
self.0
}
}
struct MaxCostOp;
impl OperationGas<MainnetGasProfile> for MaxCostOp {
const GAS_COST: Gas = Gas::new(Value::MAX);
}
impl SignedOperationExecutionGas for MaxCostOp {
fn gas_multiplier(&self) -> Value {
2
}
}
#[test]
fn execution_gas_scales_the_base_cost() {
assert_eq!(
ScalingOp(0).execution_gas::<MainnetGasProfile>().unwrap(),
Gas::new(0)
);
assert_eq!(
ScalingOp(1).execution_gas::<MainnetGasProfile>().unwrap(),
Gas::new(7)
);
assert_eq!(
ScalingOp(2).execution_gas::<MainnetGasProfile>().unwrap(),
Gas::new(14)
);
assert_eq!(
ScalingOp(3).execution_gas::<MainnetGasProfile>().unwrap(),
Gas::new(21)
);
}
#[test]
fn execution_gas_reports_overflow() {
assert_eq!(
MaxCostOp.execution_gas::<MainnetGasProfile>(),
Err(GasOverflow)
);
}
}
@@ -258,4 +258,17 @@ mod test {
Err(Error::Inputs(InputsError::EmptyInputs))
);
}
#[test]
fn channel_transfer_op_execution_gas() {
let signed_operation = SignedOperation::<_, Unverified, StandardMode>::new(
ChannelTransferOp::sample(),
ChannelMultiSigProof::sample_with_signatures(3),
);
assert_eq!(
signed_operation.execution_gas::<MainnetGasProfile>(),
Ok(Gas::new(168))
);
}
}
+18
View File
@@ -205,3 +205,21 @@ impl<State: VerificationState, Mode: VerificationMode> SignedOperationExecutionG
.expect("Channel multi-signature proofs are bound to u16::MAX signatures.")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn channel_config_op_execution_gas() {
let signed_operation = SignedOperation::<_, Unverified, StandardMode>::new(
ChannelConfigOp::sample(),
ChannelMultiSigProof::sample_with_signatures(3),
);
assert_eq!(
signed_operation.execution_gas::<MainnetGasProfile>(),
Ok(Gas::new(168))
);
}
}
+14
View File
@@ -204,6 +204,7 @@ mod test {
use lb_groth16::CompressedGroth16Proof;
use super::*;
use crate::mantle::ops::op_proof::samples::SampleProof as _;
#[test]
fn test_preverify_rejects_empty_inputs() {
@@ -220,4 +221,17 @@ mod test {
Err(Error::Inputs(InputsError::EmptyInputs))
);
}
#[test]
fn deposit_op_execution_gas() {
let signed_operation = SignedOperation::<_, Unverified, StandardMode>::new(
DepositOp::sample(),
<DepositOp as ProvableOperation>::Proof::sample(),
);
assert_eq!(
signed_operation.execution_gas::<MainnetGasProfile>(),
Ok(Gas::new(590))
);
}
}
+14
View File
@@ -237,6 +237,7 @@ mod tests {
use lb_utils::bounded::BoundedError;
use super::*;
use crate::mantle::ops::op_proof::samples::SampleProof as _;
fn sample() -> InscriptionOp {
InscriptionOp {
@@ -292,4 +293,17 @@ mod tests {
let recovered: InscriptionOp = bincode::deserialize(&bytes).unwrap();
assert_eq!(op, recovered);
}
#[test]
fn inscription_op_execution_gas() {
let signed_operation = SignedOperation::<_, Unverified, StandardMode>::new(
InscriptionOp::sample(),
<InscriptionOp as ProvableOperation>::Proof::sample(),
);
assert_eq!(
signed_operation.execution_gas::<MainnetGasProfile>(),
Ok(Gas::new(56))
);
}
}
+13
View File
@@ -210,4 +210,17 @@ mod test {
Err(Error::Inputs(InputsError::EmptyInputs))
);
}
#[test]
fn channel_withdraw_op_execution_gas() {
let signed_operation = SignedOperation::<_, Unverified, StandardMode>::new(
ChannelWithdrawOp::sample(),
ChannelMultiSigProof::sample_with_signatures(3),
);
assert_eq!(
signed_operation.execution_gas::<MainnetGasProfile>(),
Ok(Gas::new(168))
);
}
}
+17 -1
View File
@@ -307,7 +307,10 @@ mod tests {
use lb_mmr::MerkleMountainRange;
use super::*;
use crate::proofs::leader_claim_proof::LeaderClaimPrivate;
use crate::{
mantle::ops::op_proof::samples::SampleProof as _,
proofs::leader_claim_proof::LeaderClaimPrivate,
};
#[test]
fn validate_accepts_valid_proof_of_claim() {
@@ -494,4 +497,17 @@ mod tests {
let preverify_result = unverified_signed_operation.into_preverified(&preverify_context);
assert_eq!(preverify_result.err(), Some(LeaderClaimError::InvalidPoC));
}
#[test]
fn leader_claim_op_execution_gas() {
let signed_operation = SignedOperation::<_, Unverified, StandardMode>::new(
LeaderClaimOp::sample(),
<LeaderClaimOp as ProvableOperation>::Proof::sample(),
);
assert_eq!(
signed_operation.execution_gas::<MainnetGasProfile>(),
Ok(Gas::new(580))
);
}
}
+14
View File
@@ -371,6 +371,7 @@ mod tests {
use lb_groth16::{AdditiveGroup as _, Field as _};
use super::*;
use crate::mantle::ops::op_proof::samples::SampleProof as _;
fn validation_context(
nullifiers: &HashTrieMapSync<PowNullifier, Slot>,
@@ -719,4 +720,17 @@ mod tests {
block_slots: std::iter::once((CLAIM_BLOCK_HASH, Slot::from(45u64))).collect(),
}));
}
#[test]
fn claim_pow_reward_op_execution_gas() {
let signed_operation = SignedOperation::<_, Unverified, StandardMode>::new(
ClaimPowRewardOp::sample(),
<ClaimPowRewardOp as ProvableOperation>::Proof::sample(),
);
assert_eq!(
signed_operation.execution_gas::<MainnetGasProfile>(),
Ok(Gas::new(1))
);
}
}
+19
View File
@@ -136,3 +136,22 @@ impl<State: VerificationState, Mode: VerificationMode> SignedOperationExecutionG
1
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mantle::ops::op_proof::samples::SampleProof as _;
#[test]
fn sdp_active_op_execution_gas() {
let signed_operation = SignedOperation::<_, Unverified, StandardMode>::new(
SDPActiveOp::sample(),
<SDPActiveOp as ProvableOperation>::Proof::sample(),
);
assert_eq!(
signed_operation.execution_gas::<MainnetGasProfile>(),
Ok(Gas::new(590))
);
}
}
+22 -2
View File
@@ -278,9 +278,16 @@ mod tests {
use lb_key_management_system_keys::keys::{Ed25519Key, ZkKey};
use num_bigint::BigUint;
use super::{SDPDeclareOp, SdpError, validate_service_scoped_uniqueness};
use super::{
ProvableOperation, SDPDeclareOp, SdpError, SignedOperation, StandardMode, Unverified,
validate_service_scoped_uniqueness,
};
use crate::{
mantle::ledger::Declarations,
mantle::{
gas::{Gas, MainnetGasProfile, SignedOperationExecutionGas as _},
ledger::Declarations,
ops::op_proof::samples::SampleProof as _,
},
sdp::{Declaration, ServiceType},
};
@@ -329,4 +336,17 @@ mod tests {
Err(SdpError::DuplicateZkId { .. })
));
}
#[test]
fn sdp_declare_op_execution_gas() {
let signed_operation = SignedOperation::<_, Unverified, StandardMode>::new(
SDPDeclareOp::sample(),
<SDPDeclareOp as ProvableOperation>::Proof::sample(),
);
assert_eq!(
signed_operation.execution_gas::<MainnetGasProfile>(),
Ok(Gas::new(646))
);
}
}
+19
View File
@@ -171,3 +171,22 @@ impl<State: VerificationState, Mode: VerificationMode> SignedOperationExecutionG
1
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mantle::ops::op_proof::samples::SampleProof as _;
#[test]
fn sdp_withdraw_op_execution_gas() {
let signed_operation = SignedOperation::<_, Unverified, StandardMode>::new(
SDPWithdrawOp::sample(),
<SDPWithdrawOp as ProvableOperation>::Proof::sample(),
);
assert_eq!(
signed_operation.execution_gas::<MainnetGasProfile>(),
Ok(Gas::new(590))
);
}
}
+2 -7
View File
@@ -437,13 +437,8 @@ impl_try_from_op_and_proof! {
#[cfg(test)]
mod tests {
use super::{SignedOp, TransferOp};
use crate::mantle::{
Op, OpProof,
ledger::verification_mode::StandardMode,
ops::NoOpProof,
transactions::states::Unverified,
};
use super::{SignedOp, StandardMode, TransferOp, Unverified};
use crate::mantle::{Op, OpProof, ops::NoOpProof};
type UnverifiedOp = SignedOp<Unverified, StandardMode>;
+14
View File
@@ -189,6 +189,7 @@ mod test {
use num_bigint::BigUint;
use super::*;
use crate::mantle::ops::op_proof::samples::SampleProof as _;
#[test]
fn test_preverify_rejects_empty_inputs() {
@@ -246,4 +247,17 @@ mod test {
assert!(transfer.utxo_by_index(3).is_none());
}
#[test]
fn transfer_op_execution_gas() {
let signed_operation = SignedOperation::<_, Unverified, StandardMode>::new(
TransferOp::sample(),
<TransferOp as ProvableOperation>::Proof::sample(),
);
assert_eq!(
signed_operation.execution_gas::<MainnetGasProfile>(),
Ok(Gas::new(590))
);
}
}
+13 -1
View File
@@ -107,6 +107,18 @@ impl ChannelMultiSigProof {
pub fn signatures(&self) -> &[IndexedSignature] {
self.signatures.as_slice()
}
#[cfg(any(test, feature = "samples"))]
#[must_use]
pub fn sample_with_signatures(signature_count: u16) -> Self {
let signatures = IndexedSignatures::try_from_iter((0..signature_count).map(|index| {
let [low, _] = index.to_le_bytes();
IndexedSignature::new(index, Ed25519Signature::from_bytes(&[low; 64]))
}))
.expect("`signature_count` is bounded by `MAX_SIGNATURES`");
Self::new(signatures)
}
}
impl BinaryEncode for ChannelMultiSigProof {
@@ -173,7 +185,7 @@ pub mod codec {
#[cfg(any(test, feature = "samples"))]
impl crate::mantle::ops::op_proof::samples::SampleProof for ChannelMultiSigProof {
fn sample() -> Self {
Self::new(IndexedSignatures::empty())
Self::sample_with_signatures(2)
}
}