diff --git a/core/src/mantle/gas.rs b/core/src/mantle/gas.rs index fe739bcc8..eeab14f9f 100644 --- a/core/src/mantle/gas.rs +++ b/core/src/mantle/gas.rs @@ -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 for ScalingOp { + const GAS_COST: Gas = Gas::new(7); + } + + impl SignedOperationExecutionGas for ScalingOp { + fn gas_multiplier(&self) -> Value { + self.0 + } + } + + struct MaxCostOp; + + impl OperationGas 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::().unwrap(), + Gas::new(0) + ); + assert_eq!( + ScalingOp(1).execution_gas::().unwrap(), + Gas::new(7) + ); + assert_eq!( + ScalingOp(2).execution_gas::().unwrap(), + Gas::new(14) + ); + assert_eq!( + ScalingOp(3).execution_gas::().unwrap(), + Gas::new(21) + ); + } + + #[test] + fn execution_gas_reports_overflow() { + assert_eq!( + MaxCostOp.execution_gas::(), + Err(GasOverflow) + ); + } +} diff --git a/core/src/mantle/ops/channel/channel_transfer.rs b/core/src/mantle/ops/channel/channel_transfer.rs index 447558b28..f94eaba8d 100644 --- a/core/src/mantle/ops/channel/channel_transfer.rs +++ b/core/src/mantle/ops/channel/channel_transfer.rs @@ -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::(), + Ok(Gas::new(168)) + ); + } } diff --git a/core/src/mantle/ops/channel/config.rs b/core/src/mantle/ops/channel/config.rs index 033d42190..e739d2b01 100644 --- a/core/src/mantle/ops/channel/config.rs +++ b/core/src/mantle/ops/channel/config.rs @@ -205,3 +205,21 @@ impl 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::(), + Ok(Gas::new(168)) + ); + } +} diff --git a/core/src/mantle/ops/channel/deposit.rs b/core/src/mantle/ops/channel/deposit.rs index 1ada03c92..346040845 100644 --- a/core/src/mantle/ops/channel/deposit.rs +++ b/core/src/mantle/ops/channel/deposit.rs @@ -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(), + ::Proof::sample(), + ); + + assert_eq!( + signed_operation.execution_gas::(), + Ok(Gas::new(590)) + ); + } } diff --git a/core/src/mantle/ops/channel/inscribe.rs b/core/src/mantle/ops/channel/inscribe.rs index 6452202ba..c55ab674d 100644 --- a/core/src/mantle/ops/channel/inscribe.rs +++ b/core/src/mantle/ops/channel/inscribe.rs @@ -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(), + ::Proof::sample(), + ); + + assert_eq!( + signed_operation.execution_gas::(), + Ok(Gas::new(56)) + ); + } } diff --git a/core/src/mantle/ops/channel/withdraw.rs b/core/src/mantle/ops/channel/withdraw.rs index ef0063b95..08f297cf4 100644 --- a/core/src/mantle/ops/channel/withdraw.rs +++ b/core/src/mantle/ops/channel/withdraw.rs @@ -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::(), + Ok(Gas::new(168)) + ); + } } diff --git a/core/src/mantle/ops/leader_claim.rs b/core/src/mantle/ops/leader_claim.rs index 328f40762..63521bfe6 100644 --- a/core/src/mantle/ops/leader_claim.rs +++ b/core/src/mantle/ops/leader_claim.rs @@ -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(), + ::Proof::sample(), + ); + + assert_eq!( + signed_operation.execution_gas::(), + Ok(Gas::new(580)) + ); + } } diff --git a/core/src/mantle/ops/pow.rs b/core/src/mantle/ops/pow.rs index 56f4d76f4..6b26d6fef 100644 --- a/core/src/mantle/ops/pow.rs +++ b/core/src/mantle/ops/pow.rs @@ -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, @@ -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(), + ::Proof::sample(), + ); + + assert_eq!( + signed_operation.execution_gas::(), + Ok(Gas::new(1)) + ); + } } diff --git a/core/src/mantle/ops/sdp/active.rs b/core/src/mantle/ops/sdp/active.rs index e35f7b1eb..3a02d3a96 100644 --- a/core/src/mantle/ops/sdp/active.rs +++ b/core/src/mantle/ops/sdp/active.rs @@ -136,3 +136,22 @@ impl 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(), + ::Proof::sample(), + ); + + assert_eq!( + signed_operation.execution_gas::(), + Ok(Gas::new(590)) + ); + } +} diff --git a/core/src/mantle/ops/sdp/declare.rs b/core/src/mantle/ops/sdp/declare.rs index 7667b8ce5..2f545ff97 100644 --- a/core/src/mantle/ops/sdp/declare.rs +++ b/core/src/mantle/ops/sdp/declare.rs @@ -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(), + ::Proof::sample(), + ); + + assert_eq!( + signed_operation.execution_gas::(), + Ok(Gas::new(646)) + ); + } } diff --git a/core/src/mantle/ops/sdp/withdraw.rs b/core/src/mantle/ops/sdp/withdraw.rs index a4d7da64e..dfe2dfcfa 100644 --- a/core/src/mantle/ops/sdp/withdraw.rs +++ b/core/src/mantle/ops/sdp/withdraw.rs @@ -171,3 +171,22 @@ impl 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(), + ::Proof::sample(), + ); + + assert_eq!( + signed_operation.execution_gas::(), + Ok(Gas::new(590)) + ); + } +} diff --git a/core/src/mantle/ops/signed_op.rs b/core/src/mantle/ops/signed_op.rs index 6987f6896..9eea9537a 100644 --- a/core/src/mantle/ops/signed_op.rs +++ b/core/src/mantle/ops/signed_op.rs @@ -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; diff --git a/core/src/mantle/ops/transfer.rs b/core/src/mantle/ops/transfer.rs index e4b2a40b1..9ae2698c1 100644 --- a/core/src/mantle/ops/transfer.rs +++ b/core/src/mantle/ops/transfer.rs @@ -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(), + ::Proof::sample(), + ); + + assert_eq!( + signed_operation.execution_gas::(), + Ok(Gas::new(590)) + ); + } } diff --git a/core/src/proofs/channel_multi_sig_proof.rs b/core/src/proofs/channel_multi_sig_proof.rs index 71706d34c..040c3bb95 100644 --- a/core/src/proofs/channel_multi_sig_proof.rs +++ b/core/src/proofs/channel_multi_sig_proof.rs @@ -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) } }