diff --git a/crates/pallet-domains/src/benchmarking.rs b/crates/pallet-domains/src/benchmarking.rs index 80167eeff18..18005a334f3 100644 --- a/crates/pallet-domains/src/benchmarking.rs +++ b/crates/pallet-domains/src/benchmarking.rs @@ -14,42 +14,41 @@ use sp_runtime::traits::SaturatedConversion; mod benchmarks { use super::*; - // TODO: pick https://github.com/paritytech/substrate/pull/13919 to support generic argument: - // Linear<1, { T::ReceiptsPruningDepth::get() }> /// Benchmark `submit_bundle` extrinsic with the worst possible conditions: /// - Submit a system domain bundle - /// - All receipts are new and will prune the same number of expired receipts + /// - The receipts will prune a expired receipt #[benchmark] - fn submit_system_bundle(x: Linear<1, 256>) { + fn submit_system_bundle() { let receipts_pruning_depth = T::ReceiptsPruningDepth::get().saturated_into::(); // Import `ReceiptsPruningDepth` number of receipts which will be pruned later run_to_block::(1, receipts_pruning_depth); - let receipts: Vec<_> = (0..receipts_pruning_depth) - .map(|i| ExecutionReceipt::dummy(i.into(), block_hash_n::(i))) - .collect(); - let bundle = create_dummy_bundle_with_receipts_generic( - DomainId::SYSTEM, - receipts_pruning_depth.into(), - Default::default(), - receipts, - ); - assert_ok!(Domains::::submit_bundle(RawOrigin::None.into(), bundle)); + for i in 0..receipts_pruning_depth { + let receipt = ExecutionReceipt::dummy(i.into(), block_hash_n::(i)); + let bundle = create_dummy_bundle_with_receipts_generic( + DomainId::SYSTEM, + (i + 1).into(), + Default::default(), + receipt, + ); + assert_ok!(Domains::::submit_bundle(RawOrigin::None.into(), bundle)); + } assert_eq!( Domains::::head_receipt_number(), (receipts_pruning_depth - 1).into() ); - // Construct a bundle that contain `x` number of new receipts - run_to_block::(receipts_pruning_depth + 1, receipts_pruning_depth + x); - let receipts: Vec<_> = (receipts_pruning_depth..(receipts_pruning_depth + x)) - .map(|i| ExecutionReceipt::dummy(i.into(), block_hash_n::(i))) - .collect(); + // Construct a bundle that contains a new receipt + run_to_block::(receipts_pruning_depth + 1, receipts_pruning_depth + 2); + let receipt = ExecutionReceipt::dummy( + receipts_pruning_depth.into(), + block_hash_n::(receipts_pruning_depth), + ); let bundle = create_dummy_bundle_with_receipts_generic( DomainId::SYSTEM, - x.into(), + (receipts_pruning_depth + 1).into(), Default::default(), - receipts, + receipt, ); #[extrinsic_call] @@ -57,9 +56,9 @@ mod benchmarks { assert_eq!( Domains::::head_receipt_number(), - ((receipts_pruning_depth + x) - 1).into() + receipts_pruning_depth.into() ); - assert_eq!(Domains::::oldest_receipt_number(), x.into()); + assert_eq!(Domains::::oldest_receipt_number(), 1u32.into()); } #[benchmark] @@ -68,7 +67,7 @@ mod benchmarks { DomainId::CORE_PAYMENTS, 2u32.into(), Default::default(), - vec![ExecutionReceipt::dummy(1u32.into(), block_hash_n::(1))], + ExecutionReceipt::dummy(1u32.into(), block_hash_n::(1)), ); #[extrinsic_call] @@ -84,16 +83,16 @@ mod benchmarks { // Import `ReceiptsPruningDepth` number of receipts which will be revert later run_to_block::(1, receipts_pruning_depth); - let receipts: Vec<_> = (0..receipts_pruning_depth) - .map(|i| ExecutionReceipt::dummy(i.into(), block_hash_n::(i))) - .collect(); - let bundle = create_dummy_bundle_with_receipts_generic( - DomainId::SYSTEM, - receipts_pruning_depth.into(), - Default::default(), - receipts, - ); - assert_ok!(Domains::::submit_bundle(RawOrigin::None.into(), bundle)); + for i in 0..receipts_pruning_depth { + let receipt = ExecutionReceipt::dummy(i.into(), block_hash_n::(i)); + let bundle = create_dummy_bundle_with_receipts_generic( + DomainId::SYSTEM, + (i + 1).into(), + Default::default(), + receipt, + ); + assert_ok!(Domains::::submit_bundle(RawOrigin::None.into(), bundle)); + } assert_eq!( Domains::::head_receipt_number(), (receipts_pruning_depth - 1).into() diff --git a/crates/pallet-domains/src/lib.rs b/crates/pallet-domains/src/lib.rs index 61d352af104..1f174fde8f6 100644 --- a/crates/pallet-domains/src/lib.rs +++ b/crates/pallet-domains/src/lib.rs @@ -38,6 +38,7 @@ use sp_domains::transaction::InvalidTransactionCode; use sp_domains::{BundleSolution, DomainId, ExecutionReceipt, OpaqueBundle, ProofOfElection}; use sp_runtime::traits::{BlockNumberProvider, CheckedSub, One, Zero}; use sp_runtime::transaction_validity::TransactionValidityError; +use sp_std::cmp::Ordering; use sp_std::vec::Vec; #[frame_support::pallet] @@ -161,9 +162,7 @@ mod pallet { #[pallet::call_index(0)] #[pallet::weight( if opaque_bundle.domain_id().is_system() { - T::WeightInfo::submit_system_bundle( - opaque_bundle.receipts.len() as u32 - ) + T::WeightInfo::submit_system_bundle() } else { T::WeightInfo::submit_core_bundle() } @@ -180,11 +179,8 @@ mod pallet { // Only process the system domain receipts. if domain_id.is_system() { - pallet_settlement::Pallet::::track_receipts( - domain_id, - opaque_bundle.receipts.as_slice(), - ) - .map_err(Error::::from)?; + pallet_settlement::Pallet::::track_receipt(domain_id, &opaque_bundle.receipt) + .map_err(Error::::from)?; } let bundle_hash = opaque_bundle.hash(); @@ -358,74 +354,44 @@ impl Pallet { pallet_settlement::Pallet::::oldest_receipt_number(DomainId::SYSTEM) } - fn receipts_are_consecutive( - receipts: &[ExecutionReceipt], - ) -> bool { - receipts - .array_windows() - .all(|[ref head, ref tail]| head.primary_number + One::one() == tail.primary_number) - } - fn pre_dispatch_submit_bundle( opaque_bundle: &OpaqueBundle, ) -> Result<(), TransactionValidityError> { - let execution_receipts = &opaque_bundle.receipts; - - if !Self::receipts_are_consecutive(execution_receipts) { - return Err(TransactionValidityError::Invalid( - InvalidTransactionCode::ExecutionReceipt.into(), - )); + if !opaque_bundle.domain_id().is_system() { + return Ok(()); } - if opaque_bundle.domain_id().is_system() { - let oldest_receipt_number = Self::oldest_receipt_number(); - let mut best_number = Self::head_receipt_number(); - - for receipt in execution_receipts { - let primary_number = receipt.primary_number; + let receipt = &opaque_bundle.receipt; + let oldest_receipt_number = Self::oldest_receipt_number(); + let next_head_receipt_number = Self::head_receipt_number() + One::one(); + let primary_number = receipt.primary_number; - // Ignore the receipt if it has already been pruned. - if primary_number < oldest_receipt_number { - continue; - } + // Ignore the receipt if it has already been pruned. + if primary_number < oldest_receipt_number { + return Ok(()); + } - // Non-best receipt - if primary_number <= best_number { - if !pallet_settlement::Pallet::::point_to_valid_primary_block( - DomainId::SYSTEM, - receipt, - ) { - log::debug!( - target: "runtime::domains", - "Invalid primary hash for #{primary_number:?} in receipt, \ - expected: {:?}, got: {:?}", - pallet_settlement::PrimaryBlockHash::::get(DomainId::SYSTEM, primary_number), - receipt.primary_hash, - ); - return Err(TransactionValidityError::Invalid( - InvalidTransactionCode::ExecutionReceipt.into(), - )); - } - // New best receipt. - } else if primary_number == best_number + One::one() { - if !pallet_settlement::Pallet::::point_to_valid_primary_block( - DomainId::SYSTEM, - receipt, - ) { - log::debug!( - target: "runtime::domains", - "Invalid primary hash for #{primary_number:?} in receipt, \ - expected: {:?}, got: {:?}", - pallet_settlement::PrimaryBlockHash::::get(DomainId::SYSTEM, primary_number), - receipt.primary_hash, - ); - return Err(TransactionValidityError::Invalid( - InvalidTransactionCode::ExecutionReceipt.into(), - )); - } - best_number += One::one(); - // Missing receipt. - } else { + // TODO: check if the receipt extend the receipt chain or add confirmations to the head receipt. + match primary_number.cmp(&next_head_receipt_number) { + // Missing receipt. + Ordering::Greater => { + return Err(TransactionValidityError::Invalid( + InvalidTransactionCode::ExecutionReceipt.into(), + )); + } + // Non-best receipt or new best receipt. + Ordering::Less | Ordering::Equal => { + if !pallet_settlement::Pallet::::point_to_valid_primary_block( + DomainId::SYSTEM, + receipt, + ) { + log::debug!( + target: "runtime::domains", + "Invalid primary hash for #{primary_number:?} in receipt, \ + expected: {:?}, got: {:?}", + pallet_settlement::PrimaryBlockHash::::get(DomainId::SYSTEM, primary_number), + receipt.primary_hash, + ); return Err(TransactionValidityError::Invalid( InvalidTransactionCode::ExecutionReceipt.into(), )); @@ -437,7 +403,7 @@ impl Pallet { } fn validate_system_bundle_solution( - receipts: &[ExecutionReceipt], + receipt: &ExecutionReceipt, authority_stake_weight: sp_domains::StakeWeight, authority_witness: &Witness, proof_of_election: &ProofOfElection, @@ -453,24 +419,17 @@ impl Pallet { let block_number = T::BlockNumber::from(*system_block_number); let block_hash = *system_block_hash; - let new_best_receipt_number = receipts - .iter() - .map(|receipt| receipt.primary_number) - .max() - .unwrap_or_default() - .max(Self::head_receipt_number()); + let new_best_receipt_number = receipt.primary_number.max(Self::head_receipt_number()); let state_root_verifiable = block_number <= new_best_receipt_number; if !block_number.is_zero() && state_root_verifiable { - let maybe_state_root = receipts.iter().find_map(|receipt| { - receipt.trace.last().and_then(|state_root| { - if (receipt.primary_number, receipt.domain_hash) == (block_number, block_hash) { - Some(*state_root) - } else { - None - } - }) + let maybe_state_root = receipt.trace.last().and_then(|state_root| { + if (receipt.primary_number, receipt.domain_hash) == (block_number, block_hash) { + Some(*state_root) + } else { + None + } }); let expected_state_root = match maybe_state_root { @@ -516,29 +475,10 @@ impl Pallet { Ok(()) } - /// Common validation of receipts in all kinds of domain bundle. - fn validate_execution_receipts( - execution_receipts: &[ExecutionReceipt], - ) -> Result<(), ExecutionReceiptError> { - let current_block_number = frame_system::Pallet::::current_block_number(); - - // Genesis block receipt is initialized on primary chain, the first block has no receipts, - // but any block after the first one requires at least one receipt. - if current_block_number > One::one() && execution_receipts.is_empty() { - return Err(ExecutionReceiptError::Empty); - } - - if !Self::receipts_are_consecutive(execution_receipts) { - return Err(ExecutionReceiptError::Inconsecutive); - } - - Ok(()) - } - fn validate_bundle( OpaqueBundle { sealed_header, - receipts, + receipt, extrinsics: _, }: &OpaqueBundle, ) -> Result<(), BundleError> { @@ -583,8 +523,6 @@ impl Pallet { .verify_vrf_proof() .map_err(|_| BundleError::BadVrfProof)?; - Self::validate_execution_receipts(receipts).map_err(BundleError::Receipt)?; - if proof_of_election.domain_id.is_system() { let BundleSolution::System { authority_stake_weight, @@ -623,7 +561,7 @@ impl Pallet { } Self::validate_system_bundle_solution( - receipts, + receipt, *authority_stake_weight, authority_witness, proof_of_election, @@ -631,50 +569,46 @@ impl Pallet { let best_number = Self::head_receipt_number(); let max_allowed = best_number + T::MaximumReceiptDrift::get(); - let oldest_receipt_number = Self::oldest_receipt_number(); + let primary_number = receipt.primary_number; - for execution_receipt in receipts.iter() { - let primary_number = execution_receipt.primary_number; - - // The corresponding block info has been pruned, such expired receipts - // will be skipped too while applying the bundle. - if primary_number < oldest_receipt_number { - continue; - } + // The corresponding block info has been pruned, such expired receipts + // will be skipped too while applying the bundle. + if primary_number < oldest_receipt_number { + return Ok(()); + } - // Due to `initialize_block` is skipped while calling the runtime api, the block - // hash mapping for last block is unknown to the transaction pool, but this info - // is already available in System. - let point_to_parent_block = primary_number == current_block_number - One::one() - && execution_receipt.primary_hash == frame_system::Pallet::::parent_hash(); + // Due to `initialize_block` is skipped while calling the runtime api, the block + // hash mapping for last block is unknown to the transaction pool, but this info + // is already available in System. + let point_to_parent_block = primary_number == current_block_number - One::one() + && receipt.primary_hash == frame_system::Pallet::::parent_hash(); - let point_to_valid_primary_block = - pallet_settlement::Pallet::::point_to_valid_primary_block( - DomainId::SYSTEM, - execution_receipt, - ); + let point_to_valid_primary_block = + pallet_settlement::Pallet::::point_to_valid_primary_block( + DomainId::SYSTEM, + receipt, + ); - if !point_to_parent_block && !point_to_valid_primary_block { - log::debug!( - target: "runtime::domains", - "Receipt of #{primary_number:?},{:?} points to an unknown primary block, \ - expected: #{primary_number:?},{:?}", - execution_receipt.primary_hash, - pallet_settlement::PrimaryBlockHash::::get(DomainId::SYSTEM, primary_number), - ); - return Err(BundleError::Receipt(ExecutionReceiptError::UnknownBlock)); - } + if !point_to_parent_block && !point_to_valid_primary_block { + log::debug!( + target: "runtime::domains", + "Receipt of #{primary_number:?},{:?} points to an unknown primary block, \ + expected: #{primary_number:?},{:?}", + receipt.primary_hash, + pallet_settlement::PrimaryBlockHash::::get(DomainId::SYSTEM, primary_number), + ); + return Err(BundleError::Receipt(ExecutionReceiptError::UnknownBlock)); + } - // Ensure the receipt is not too new. - if primary_number == current_block_number || primary_number > max_allowed { - log::debug!( - target: "runtime::domains", - "Receipt for #{primary_number:?} is too far in future, \ - current_block_number: {current_block_number:?}, max_allowed: {max_allowed:?}", - ); - return Err(BundleError::Receipt(ExecutionReceiptError::TooFarInFuture)); - } + // Ensure the receipt is not too new. + if primary_number == current_block_number || primary_number > max_allowed { + log::debug!( + target: "runtime::domains", + "Receipt for #{primary_number:?} is too far in future, \ + current_block_number: {current_block_number:?}, max_allowed: {max_allowed:?}", + ); + return Err(BundleError::Receipt(ExecutionReceiptError::TooFarInFuture)); } } @@ -691,7 +625,6 @@ where opaque_bundle: OpaqueBundle, ) { let slot = opaque_bundle.sealed_header.header.slot_number; - let receipts_count = opaque_bundle.receipts.len(); let extrincis_count = opaque_bundle.extrinsics.len(); let call = Call::submit_bundle { opaque_bundle }; @@ -700,7 +633,7 @@ where Ok(()) => { log::info!( target: "runtime::domains", - "Submitted bundle from slot {slot}, receipts: {receipts_count}, extrinsics: {extrincis_count}", + "Submitted bundle from slot {slot}, extrinsics: {extrincis_count}", ); } Err(()) => { diff --git a/crates/pallet-domains/src/tests.rs b/crates/pallet-domains/src/tests.rs index df0aea6c555..fc633538c08 100644 --- a/crates/pallet-domains/src/tests.rs +++ b/crates/pallet-domains/src/tests.rs @@ -146,7 +146,7 @@ fn create_dummy_bundle( OpaqueBundle { sealed_header: SealedBundleHeader::new(header, signature), - receipts: vec![execution_receipt], + receipt: execution_receipt, extrinsics: Vec::new(), } } @@ -155,13 +155,13 @@ fn create_dummy_bundle_with_receipts( domain_id: DomainId, primary_number: BlockNumber, primary_hash: Hash, - receipts: Vec>, + receipt: ExecutionReceipt, ) -> OpaqueBundle { create_dummy_bundle_with_receipts_generic::( domain_id, primary_number, primary_hash, - receipts, + receipt, ) } @@ -177,8 +177,12 @@ fn submit_execution_receipt_incrementally_should_work() { }) .unzip(); - let receipt_hash = - |block_number| dummy_bundles[block_number as usize - 1].clone().receipts[0].hash(); + let receipt_hash = |block_number| { + dummy_bundles[block_number as usize - 1] + .clone() + .receipt + .hash() + }; new_test_ext().execute_with(|| { let genesis_hash = frame_system::Pallet::::block_hash(0); @@ -296,74 +300,6 @@ fn submit_execution_receipt_with_huge_gap_should_work() { }); } -#[test] -fn submit_bundle_with_many_reeipts_should_work() { - let (receipts, mut block_hashes): (Vec<_>, Vec<_>) = (1u64..=255u64) - .map(|n| { - let primary_hash = Hash::random(); - (create_dummy_receipt(n, primary_hash), primary_hash) - }) - .unzip(); - - let primary_hash_255 = *block_hashes.last().unwrap(); - let bundle1 = - create_dummy_bundle_with_receipts(DomainId::SYSTEM, 255u64, primary_hash_255, receipts); - - let primary_hash_256 = Hash::random(); - block_hashes.push(primary_hash_256); - let bundle2 = create_dummy_bundle(DomainId::SYSTEM, 256, primary_hash_256); - - let primary_hash_257 = Hash::random(); - block_hashes.push(primary_hash_257); - let bundle3 = create_dummy_bundle(DomainId::SYSTEM, 257, primary_hash_257); - - let primary_hash_258 = Hash::random(); - block_hashes.push(primary_hash_258); - let bundle4 = create_dummy_bundle(DomainId::SYSTEM, 258, primary_hash_258); - - let run_to_block = |n: BlockNumber, block_hashes: Vec| { - System::initialize(&1, &System::parent_hash(), &Default::default()); - >::on_initialize(1); - System::finalize(); - - for b in 2..=n { - System::set_block_number(b); - System::initialize(&b, &block_hashes[b as usize - 2], &Default::default()); - >::on_initialize(b); - System::finalize(); - } - }; - - new_test_ext().execute_with(|| { - run_to_block(256 + 2, block_hashes); - - // Submit ancient receipts still works even the block hash mapping for [1, 256) - // in System has been removed. - assert!(!frame_system::BlockHash::::contains_key(1)); - assert!(!frame_system::BlockHash::::contains_key(255)); - assert_ok!(Domains::submit_bundle(RuntimeOrigin::none(), bundle1)); - assert_eq!(Settlement::head_receipt_number(DomainId::SYSTEM), 255); - - // Reaching the receipts pruning depth, block hash mapping will be pruned as well. - assert!(PrimaryBlockHash::::contains_key(DomainId::SYSTEM, 0)); - assert_ok!(Domains::submit_bundle(RuntimeOrigin::none(), bundle2)); - assert!(!PrimaryBlockHash::::contains_key(DomainId::SYSTEM, 0)); - assert_eq!(Settlement::oldest_receipt_number(DomainId::SYSTEM), 1); - - assert!(PrimaryBlockHash::::contains_key(DomainId::SYSTEM, 1)); - assert_ok!(Domains::submit_bundle(RuntimeOrigin::none(), bundle3)); - assert!(!PrimaryBlockHash::::contains_key(DomainId::SYSTEM, 1)); - assert_eq!(Settlement::oldest_receipt_number(DomainId::SYSTEM), 2); - - assert!(PrimaryBlockHash::::contains_key(DomainId::SYSTEM, 2)); - assert_ok!(Domains::submit_bundle(RuntimeOrigin::none(), bundle4)); - assert!(!PrimaryBlockHash::::contains_key(DomainId::SYSTEM, 2)); - assert_eq!(Settlement::oldest_receipt_number(DomainId::SYSTEM), 3); - assert_eq!(Settlement::finalized_receipt_number(DomainId::SYSTEM), 2); - assert_eq!(Settlement::head_receipt_number(DomainId::SYSTEM), 258); - }); -} - #[test] fn only_system_domain_receipts_are_maintained_on_primary_chain() { let primary_hash = Hash::random(); @@ -373,15 +309,11 @@ fn only_system_domain_receipts_are_maintained_on_primary_chain() { DomainId::SYSTEM, 1, primary_hash, - vec![system_receipt.clone()], + system_receipt.clone(), ); let core_receipt = create_dummy_receipt(1, primary_hash); - let core_bundle = create_dummy_bundle_with_receipts( - DomainId::new(1), - 1, - primary_hash, - vec![core_receipt.clone()], - ); + let core_bundle = + create_dummy_bundle_with_receipts(DomainId::new(1), 1, primary_hash, core_receipt.clone()); new_test_ext().execute_with(|| { assert_ok!(Domains::submit_bundle(RuntimeOrigin::none(), system_bundle)); @@ -429,7 +361,7 @@ fn submit_fraud_proof_should_work() { dummy_bundles[index].clone(), )); - let receipt_hash = dummy_bundles[index].clone().receipts[0].hash(); + let receipt_hash = dummy_bundles[index].clone().receipt.hash(); assert!(Settlement::receipts(DomainId::SYSTEM, receipt_hash).is_some()); let mut votes = ReceiptVotes::::iter_prefix((DomainId::SYSTEM, block_hash)); assert_eq!(votes.next(), Some((receipt_hash, 1))); @@ -442,7 +374,7 @@ fn submit_fraud_proof_should_work() { dummy_proof(DomainId::new(100)) )); assert_eq!(Domains::head_receipt_number(), 256); - let receipt_hash = dummy_bundles[255].clone().receipts[0].hash(); + let receipt_hash = dummy_bundles[255].clone().receipt.hash(); assert!(Settlement::receipts(DomainId::SYSTEM, receipt_hash).is_some()); assert_ok!(Domains::submit_fraud_proof( @@ -450,11 +382,14 @@ fn submit_fraud_proof_should_work() { dummy_proof(DomainId::SYSTEM) )); assert_eq!(Settlement::head_receipt_number(DomainId::SYSTEM), 99); - let receipt_hash = dummy_bundles[98].clone().receipts[0].hash(); + let receipt_hash = dummy_bundles[98].clone().receipt.hash(); assert!(Settlement::receipts(DomainId::SYSTEM, receipt_hash).is_some()); // Receipts for block [100, 256] should be removed as being invalid. (100..=256).for_each(|block_number| { - let receipt_hash = dummy_bundles[block_number as usize - 1].clone().receipts[0].hash(); + let receipt_hash = dummy_bundles[block_number as usize - 1] + .clone() + .receipt + .hash(); assert!(Settlement::receipts(DomainId::SYSTEM, receipt_hash).is_none()); let block_hash = block_hashes[block_number as usize - 1]; assert!( @@ -466,25 +401,6 @@ fn submit_fraud_proof_should_work() { }); } -#[test] -fn test_receipts_are_consecutive() { - let receipts = vec![ - create_dummy_receipt(1, Hash::random()), - create_dummy_receipt(2, Hash::random()), - create_dummy_receipt(3, Hash::random()), - ]; - assert!(Domains::receipts_are_consecutive(&receipts)); - let receipts = vec![ - create_dummy_receipt(1, Hash::random()), - create_dummy_receipt(2, Hash::random()), - create_dummy_receipt(4, Hash::random()), - ]; - assert!(!Domains::receipts_are_consecutive(&receipts)); - let receipts = vec![create_dummy_receipt(1, Hash::random())]; - assert!(Domains::receipts_are_consecutive(&receipts)); - assert!(Domains::receipts_are_consecutive(&[])); -} - #[test] fn test_stale_bundle_should_be_rejected() { // Small macro in order to be more readable. diff --git a/crates/pallet-domains/src/weights.rs b/crates/pallet-domains/src/weights.rs index 3fbfe6335a2..a69a274a557 100644 --- a/crates/pallet-domains/src/weights.rs +++ b/crates/pallet-domains/src/weights.rs @@ -1,9 +1,8 @@ -//! TODO: regenerate this file once the standard machine for subspace node is determined. //! Autogenerated weights for pallet_domains //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-06-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `local`, CPU: `` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -33,7 +32,7 @@ use core::marker::PhantomData; /// Weight functions needed for pallet_domains. pub trait WeightInfo { - fn submit_system_bundle(x: u32, ) -> Weight; + fn submit_system_bundle() -> Weight; fn submit_core_bundle() -> Weight; fn submit_system_domain_invalid_state_transition_proof() -> Weight; } @@ -41,114 +40,118 @@ pub trait WeightInfo { /// Weights for pallet_domains using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Receipts OldestReceiptNumber (r:1 w:1) - /// Proof Skipped: Receipts OldestReceiptNumber (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts HeadReceiptNumber (r:1 w:1) - /// Proof Skipped: Receipts HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts Receipts (r:256 w:512) - /// Proof Skipped: Receipts Receipts (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts ReceiptVotes (r:768 w:512) - /// Proof Skipped: Receipts ReceiptVotes (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts PrimaryBlockHash (r:256 w:256) - /// Proof Skipped: Receipts PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts StateRoots (r:255 w:511) - /// Proof Skipped: Receipts StateRoots (max_values: None, max_size: None, mode: Measured) - /// The range of component `x` is `[1, 256]`. - fn submit_system_bundle(x: u32, ) -> Weight { + /// Storage: Settlement OldestReceiptNumber (r:1 w:1) + /// Proof Skipped: Settlement OldestReceiptNumber (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement HeadReceiptNumber (r:1 w:1) + /// Proof Skipped: Settlement HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement Receipts (r:1 w:2) + /// Proof Skipped: Settlement Receipts (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement ReceiptVotes (r:3 w:2) + /// Proof Skipped: Settlement ReceiptVotes (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement PrimaryBlockHash (r:1 w:1) + /// Proof Skipped: Settlement PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Domains SuccessfulBundles (r:1 w:1) + /// Proof Skipped: Domains SuccessfulBundles (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Settlement StateRoots (r:0 w:1) + /// Proof Skipped: Settlement StateRoots (max_values: None, max_size: None, mode: Measured) + fn submit_system_bundle() -> Weight { // Proof Size summary in bytes: - // Measured: `30097 + x * (236 ±0)` - // Estimated: `156064 + x * (16435 ±2)` - // Minimum execution time: 100_000_000 picoseconds. - Weight::from_parts(114_000_000, 156064) - // Standard Error: 83_023 - .saturating_add(Weight::from_parts(57_171_657, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(x.into()))) - .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(x.into()))) - .saturating_add(Weight::from_parts(0, 16435).saturating_mul(x.into())) + // Measured: `4063` + // Estimated: `52201` + // Minimum execution time: 128_000_000 picoseconds. + Weight::from_parts(133_000_000, 52201) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(9_u64)) } + /// Storage: Domains SuccessfulBundles (r:1 w:1) + /// Proof Skipped: Domains SuccessfulBundles (max_values: Some(1), max_size: None, mode: Measured) fn submit_core_bundle() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 0) + // Measured: `6` + // Estimated: `1491` + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 1491) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Receipts HeadReceiptNumber (r:1 w:1) - /// Proof Skipped: Receipts HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts PrimaryBlockHash (r:256 w:0) - /// Proof Skipped: Receipts PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts ReceiptVotes (r:510 w:255) - /// Proof Skipped: Receipts ReceiptVotes (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts Receipts (r:255 w:255) - /// Proof Skipped: Receipts Receipts (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts StateRoots (r:100 w:255) - /// Proof Skipped: Receipts StateRoots (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement HeadReceiptNumber (r:1 w:1) + /// Proof Skipped: Settlement HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement PrimaryBlockHash (r:256 w:0) + /// Proof Skipped: Settlement PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement ReceiptVotes (r:510 w:255) + /// Proof Skipped: Settlement ReceiptVotes (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement Receipts (r:255 w:255) + /// Proof Skipped: Settlement Receipts (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement StateRoots (r:100 w:255) + /// Proof Skipped: Settlement StateRoots (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement SuccessfulFraudProofs (r:1 w:1) + /// Proof Skipped: Settlement SuccessfulFraudProofs (max_values: Some(1), max_size: None, mode: Measured) fn submit_system_domain_invalid_state_transition_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `100459` - // Estimated: `3284195` - // Minimum execution time: 7_251_000_000 picoseconds. - Weight::from_parts(7_404_000_000, 3284195) - .saturating_add(T::DbWeight::get().reads(1122_u64)) - .saturating_add(T::DbWeight::get().writes(766_u64)) + // Measured: `100355` + // Estimated: `3385515` + // Minimum execution time: 7_486_000_000 picoseconds. + Weight::from_parts(7_972_000_000, 3385515) + .saturating_add(T::DbWeight::get().reads(1123_u64)) + .saturating_add(T::DbWeight::get().writes(767_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - /// Storage: Receipts OldestReceiptNumber (r:1 w:1) - /// Proof Skipped: Receipts OldestReceiptNumber (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts HeadReceiptNumber (r:1 w:1) - /// Proof Skipped: Receipts HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts Receipts (r:256 w:512) - /// Proof Skipped: Receipts Receipts (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts ReceiptVotes (r:768 w:512) - /// Proof Skipped: Receipts ReceiptVotes (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts PrimaryBlockHash (r:256 w:256) - /// Proof Skipped: Receipts PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts StateRoots (r:255 w:511) - /// Proof Skipped: Receipts StateRoots (max_values: None, max_size: None, mode: Measured) - /// The range of component `x` is `[1, 256]`. - fn submit_system_bundle(x: u32, ) -> Weight { + /// Storage: Settlement OldestReceiptNumber (r:1 w:1) + /// Proof Skipped: Settlement OldestReceiptNumber (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement HeadReceiptNumber (r:1 w:1) + /// Proof Skipped: Settlement HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement Receipts (r:1 w:2) + /// Proof Skipped: Settlement Receipts (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement ReceiptVotes (r:3 w:2) + /// Proof Skipped: Settlement ReceiptVotes (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement PrimaryBlockHash (r:1 w:1) + /// Proof Skipped: Settlement PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Domains SuccessfulBundles (r:1 w:1) + /// Proof Skipped: Domains SuccessfulBundles (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Settlement StateRoots (r:0 w:1) + /// Proof Skipped: Settlement StateRoots (max_values: None, max_size: None, mode: Measured) + fn submit_system_bundle() -> Weight { // Proof Size summary in bytes: - // Measured: `30097 + x * (236 ±0)` - // Estimated: `156064 + x * (16435 ±2)` - // Minimum execution time: 100_000_000 picoseconds. - Weight::from_parts(114_000_000, 156064) - // Standard Error: 83_023 - .saturating_add(Weight::from_parts(57_171_657, 0).saturating_mul(x.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(x.into()))) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(x.into()))) - .saturating_add(Weight::from_parts(0, 16435).saturating_mul(x.into())) + // Measured: `4063` + // Estimated: `52201` + // Minimum execution time: 128_000_000 picoseconds. + Weight::from_parts(133_000_000, 52201) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(9_u64)) } + /// Storage: Domains SuccessfulBundles (r:1 w:1) + /// Proof Skipped: Domains SuccessfulBundles (max_values: Some(1), max_size: None, mode: Measured) fn submit_core_bundle() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(12_000_000, 0) + // Measured: `6` + // Estimated: `1491` + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 1491) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Receipts HeadReceiptNumber (r:1 w:1) - /// Proof Skipped: Receipts HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts PrimaryBlockHash (r:256 w:0) - /// Proof Skipped: Receipts PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts ReceiptVotes (r:510 w:255) - /// Proof Skipped: Receipts ReceiptVotes (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts Receipts (r:255 w:255) - /// Proof Skipped: Receipts Receipts (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts StateRoots (r:100 w:255) - /// Proof Skipped: Receipts StateRoots (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement HeadReceiptNumber (r:1 w:1) + /// Proof Skipped: Settlement HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement PrimaryBlockHash (r:256 w:0) + /// Proof Skipped: Settlement PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement ReceiptVotes (r:510 w:255) + /// Proof Skipped: Settlement ReceiptVotes (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement Receipts (r:255 w:255) + /// Proof Skipped: Settlement Receipts (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement StateRoots (r:100 w:255) + /// Proof Skipped: Settlement StateRoots (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement SuccessfulFraudProofs (r:1 w:1) + /// Proof Skipped: Settlement SuccessfulFraudProofs (max_values: Some(1), max_size: None, mode: Measured) fn submit_system_domain_invalid_state_transition_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `100459` - // Estimated: `3284195` - // Minimum execution time: 7_251_000_000 picoseconds. - Weight::from_parts(7_404_000_000, 3284195) - .saturating_add(RocksDbWeight::get().reads(1122_u64)) - .saturating_add(RocksDbWeight::get().writes(766_u64)) + // Measured: `100355` + // Estimated: `3385515` + // Minimum execution time: 7_486_000_000 picoseconds. + Weight::from_parts(7_972_000_000, 3385515) + .saturating_add(RocksDbWeight::get().reads(1123_u64)) + .saturating_add(RocksDbWeight::get().writes(767_u64)) } } diff --git a/crates/pallet-settlement/src/lib.rs b/crates/pallet-settlement/src/lib.rs index 52a30e08f52..21b14b4f77d 100644 --- a/crates/pallet-settlement/src/lib.rs +++ b/crates/pallet-settlement/src/lib.rs @@ -282,32 +282,30 @@ impl Pallet { } /// Track the execution receipts for the domain - pub fn track_receipts( + pub fn track_receipt( domain_id: DomainId, - receipts: &[ExecutionReceipt], + receipt: &ExecutionReceipt, ) -> Result<(), Error> { let oldest_receipt_number = >::get(domain_id); let mut best_number = >::get(domain_id); - for receipt in receipts { - let primary_number = receipt.primary_number; + let primary_number = receipt.primary_number; - // Ignore the receipt if it has already been pruned. - if primary_number < oldest_receipt_number { - continue; - } + // Ignore the receipt if it has already been pruned. + if primary_number < oldest_receipt_number { + return Ok(()); + } - if primary_number <= best_number { - // Either increase the vote for a known receipt or add a fork receipt at this height. - Self::import_receipt(domain_id, receipt); - } else if primary_number == best_number + One::one() { - Self::import_head_receipt(domain_id, receipt); - Self::remove_expired_receipts(domain_id, primary_number); - best_number += One::one(); - } else { - // Reject the entire Bundle due to the missing receipt(s) between [best_number, .., receipt.primary_number]. - return Err(Error::MissingParent); - } + if primary_number <= best_number { + // Either increase the vote for a known receipt or add a fork receipt at this height. + Self::import_receipt(domain_id, receipt); + } else if primary_number == best_number + One::one() { + Self::import_head_receipt(domain_id, receipt); + Self::remove_expired_receipts(domain_id, primary_number); + best_number += One::one(); + } else { + // Reject the entire Bundle due to the missing receipt(s) between [best_number, .., receipt.primary_number]. + return Err(Error::MissingParent); } Ok(()) } diff --git a/crates/sp-domains/src/lib.rs b/crates/sp-domains/src/lib.rs index a8190bde7b8..6499e93dc7c 100644 --- a/crates/sp-domains/src/lib.rs +++ b/crates/sp-domains/src/lib.rs @@ -369,12 +369,9 @@ impl BundleSolution { pub struct Bundle { /// Sealed bundle header. pub sealed_header: SealedBundleHeader, - /// Expected receipts by the primay chain when the bundle was created. - /// - /// NOTE: It's fine to `Vec` instead of `BoundedVec` as each bundle is - /// wrapped in an unsigned extrinsic, therefore the number of receipts - /// in a bundle is inherently constrained by the max extrinsic size limit. - pub receipts: Vec>, + /// Execution receipt that should extend the receipt chain or add confirmations + /// to the head receipt. + pub receipt: ExecutionReceipt, /// The accompanying extrinsics. pub extrinsics: Vec, } @@ -417,7 +414,7 @@ impl Bundle OpaqueBundle { let Bundle { sealed_header, - receipts, + receipt, extrinsics, } = self; let opaque_extrinsics = extrinsics @@ -429,7 +426,7 @@ impl Bundle( domain_id: DomainId, primary_number: BlockNumber, primary_hash: Hash, - receipts: Vec>, + receipt: ExecutionReceipt, ) -> OpaqueBundle where BlockNumber: Encode + Default, @@ -512,7 +509,7 @@ where OpaqueBundle { sealed_header, - receipts, + receipt, extrinsics: Vec::new(), } } diff --git a/crates/subspace-fraud-proof/src/tests.rs b/crates/subspace-fraud-proof/src/tests.rs index a57653793ab..eb8eabf03e3 100644 --- a/crates/subspace-fraud-proof/src/tests.rs +++ b/crates/subspace-fraud-proof/src/tests.rs @@ -24,7 +24,7 @@ use sp_runtime::OpaqueExtrinsic; use std::sync::Arc; use subspace_runtime_primitives::opaque::Block; use subspace_test_client::Client; -use subspace_test_service::{produce_blocks, MockPrimaryNode}; +use subspace_test_service::{produce_block_with, produce_blocks, MockPrimaryNode}; use tempfile::TempDir; struct TestVerifierClient { @@ -169,13 +169,9 @@ async fn execution_proof_creation_and_verification_should_work() { // to apply these txs let (slot, bundle) = ferdie.produce_slot_and_wait_for_bundle_submission().await; assert!(bundle.is_some()); - futures::future::join( - alice.wait_for_blocks(1), - ferdie.produce_block_with_slot(slot), - ) - .await - .1 - .unwrap(); + produce_block_with!(ferdie.produce_block_with_slot(slot), alice) + .await + .unwrap(); let best_hash = alice.client.info().best_hash; let header = alice.client.header(best_hash).unwrap().unwrap(); @@ -489,13 +485,9 @@ async fn invalid_execution_proof_should_not_work() { assert!(bundle.is_some()); // Wait for `alice` to apply these txs - futures::future::join( - alice.wait_for_blocks(1), - ferdie.produce_block_with_slot(slot), - ) - .await - .1 - .unwrap(); + produce_block_with!(ferdie.produce_block_with_slot(slot), alice) + .await + .unwrap(); let best_hash = alice.client.info().best_hash; let header = alice.client.header(best_hash).unwrap().unwrap(); @@ -665,6 +657,8 @@ async fn test_invalid_transaction_proof_creation_and_verification() { .build_with_mock_primary_node(Role::Authority, &mut ferdie) .await; + produce_blocks!(ferdie, alice, 3).await.unwrap(); + alice .construct_and_send_extrinsic(pallet_balances::Call::transfer { dest: domain_test_service::system_domain_test_runtime::Address::Id(One.public().into()), @@ -675,15 +669,11 @@ async fn test_invalid_transaction_proof_creation_and_verification() { ferdie.produce_slot_and_wait_for_bundle_submission().await; - futures::join!(alice.wait_for_blocks(1), ferdie.produce_blocks(1)) - .1 - .unwrap(); + produce_blocks!(ferdie, alice, 1).await.unwrap(); let (_slot, maybe_bundle) = ferdie.produce_slot_and_wait_for_bundle_submission().await; - futures::join!(alice.wait_for_blocks(3), ferdie.produce_blocks(3)) - .1 - .unwrap(); + produce_blocks!(ferdie, alice, 3).await.unwrap(); // This is an invalid transaction. let transfer_from_one_to_bob = alice.construct_extrinsic_with_caller( diff --git a/crates/subspace-runtime/src/domains.rs b/crates/subspace-runtime/src/domains.rs index d5ea3a13074..88ffab56b89 100644 --- a/crates/subspace-runtime/src/domains.rs +++ b/crates/subspace-runtime/src/domains.rs @@ -68,11 +68,10 @@ pub(crate) fn extract_receipts( if opaque_bundle.domain_id() == domain_id && successful_bundles.contains(&opaque_bundle.hash()) => { - Some(opaque_bundle.receipts) + Some(opaque_bundle.receipt) } _ => None, }) - .flatten() .collect() } diff --git a/crates/subspace-transaction-pool/src/bundle_validator.rs b/crates/subspace-transaction-pool/src/bundle_validator.rs index 324062149b6..d96e0fd4b5a 100644 --- a/crates/subspace-transaction-pool/src/bundle_validator.rs +++ b/crates/subspace-transaction-pool/src/bundle_validator.rs @@ -340,17 +340,15 @@ where .ok_or(sp_blockchain::Error::Backend(format!( "Can not convert BlockId {at:?} to block number" )))?; - for receipt in opaque_bundle.receipts.iter() { - if receipt.primary_number > best_primary_number { - return Err(BundleError::ReceiptInFuture); - } - if let Some(expected_hash) = self - .bundle_stored_in_last_k - .get_canonical_block_hash(receipt.primary_number) - { - if receipt.primary_hash != expected_hash { - return Err(BundleError::ReceiptPointToUnknownBlock); - } + if opaque_bundle.receipt.primary_number > best_primary_number { + return Err(BundleError::ReceiptInFuture); + } + if let Some(expected_hash) = self + .bundle_stored_in_last_k + .get_canonical_block_hash(opaque_bundle.receipt.primary_number) + { + if opaque_bundle.receipt.primary_hash != expected_hash { + return Err(BundleError::ReceiptPointToUnknownBlock); } } Ok(()) diff --git a/domains/client/domain-executor/src/core_gossip_message_validator.rs b/domains/client/domain-executor/src/core_gossip_message_validator.rs index fe2f42b3501..37b5f2cbfaf 100644 --- a/domains/client/domain-executor/src/core_gossip_message_validator.rs +++ b/domains/client/domain-executor/src/core_gossip_message_validator.rs @@ -187,7 +187,7 @@ where let domain_id = bundle.domain_id(); self.gossip_message_validator - .validate_bundle_receipts(&bundle.receipts, domain_id)?; + .validate_bundle_receipt(&bundle.receipt, domain_id)?; let at = bundle .sealed_header diff --git a/domains/client/domain-executor/src/domain_bundle_producer.rs b/domains/client/domain-executor/src/domain_bundle_producer.rs index 6fba05a76ca..2a739f7af19 100644 --- a/domains/client/domain-executor/src/domain_bundle_producer.rs +++ b/domains/client/domain-executor/src/domain_bundle_producer.rs @@ -196,21 +196,22 @@ where self.client.info().best_number.saturating_sub(One::one()) }; - let should_skip_slot = if domain_best_number.is_zero() { + let should_skip_slot = { let primary_block_number = primary_info.1; - - // Executor hasn't able to finish the processing of domain block #1. - !primary_block_number.is_zero() - } else { let head_receipt_number = self .parent_chain .head_receipt_number(self.parent_chain.best_hash())?; - // Executor is lagging behind the receipt chain on its parent chain as another executor - // already processed a block higher than the local best and submitted the receipt to - // the parent chain, we ought to catch up with the primary block processing before - // producing new bundle. - domain_best_number <= head_receipt_number + // Receipt for block #0 does not exist, simply skip slot here to bypasss this case and + // make the code cleaner + primary_block_number.is_zero() + // Executor hasn't able to finish the processing of domain block #1. + || domain_best_number.is_zero() + // Executor is lagging behind the receipt chain on its parent chain as another executor + // already processed a block higher than the local best and submitted the receipt to + // the parent chain, we ought to catch up with the primary block processing before + // producing new bundle. + || domain_best_number <= head_receipt_number }; if should_skip_slot { @@ -239,7 +240,7 @@ where .executor_public_key .clone(); - let (bundle_header, receipts, extrinsics) = self + let (bundle_header, receipt, extrinsics) = self .domain_bundle_proposer .propose_bundle_at( bundle_solution, @@ -277,7 +278,7 @@ where let bundle = Bundle { sealed_header: SealedBundleHeader::new(bundle_header, signature), - receipts, + receipt, extrinsics, }; diff --git a/domains/client/domain-executor/src/domain_bundle_proposer.rs b/domains/client/domain-executor/src/domain_bundle_proposer.rs index 09cbab673a7..6f5fcf8df53 100644 --- a/domains/client/domain-executor/src/domain_bundle_proposer.rs +++ b/domains/client/domain-executor/src/domain_bundle_proposer.rs @@ -9,7 +9,7 @@ use sp_block_builder::BlockBuilder; use sp_blockchain::HeaderBackend; use sp_consensus_slots::Slot; use sp_domains::{BundleHeader, BundleSolution}; -use sp_runtime::traits::{BlakeTwo256, Block as BlockT, Hash as HashT, One, Saturating, Zero}; +use sp_runtime::traits::{BlakeTwo256, Block as BlockT, Hash as HashT, One, Saturating}; use std::marker::PhantomData; use std::sync::Arc; use std::time; @@ -36,7 +36,7 @@ impl Clone pub(super) type ProposeBundleOutput = ( BundleHeader, ::Hash, ::Hash>, - Vec::Hash>>, + ExecutionReceiptFor::Hash>, Vec<::Extrinsic>, ); @@ -119,13 +119,7 @@ where let (primary_hash, primary_number) = primary_info; - let receipts = if primary_number.is_zero() { - Vec::new() - } else { - self.collect_bundle_receipts(parent_number, parent_hash, parent_chain)? - }; - - receipts_sanity_check::(&receipts)?; + let receipt = self.load_bundle_receipt(parent_number, parent_hash, parent_chain)?; let header = BundleHeader { primary_number, @@ -135,18 +129,16 @@ where bundle_solution, }; - Ok((header, receipts, extrinsics)) + Ok((header, receipt, extrinsics)) } - /// Returns the receipts in the next domain bundle. - /// - /// There will be at least one receipt in the collected receipts. - fn collect_bundle_receipts( + /// Returns the receipt in the next domain bundle. + fn load_bundle_receipt( &self, header_number: NumberFor, header_hash: Block::Hash, parent_chain: ParentChain, - ) -> sp_blockchain::Result>> + ) -> sp_blockchain::Result> where ParentChainBlock: BlockT, ParentChain: ParentChainInterface, @@ -176,9 +168,6 @@ where }) }; - let mut receipts = Vec::new(); - let mut to_send = head_receipt_number + One::one(); - let header_block_receipt_is_written = crate::aux_schema::primary_hash_for::<_, _, PBlock::Hash>(&*self.client, header_hash)? .is_some(); @@ -196,96 +185,17 @@ where header_number.saturating_sub(One::one()) }; - let max_allowed = (head_receipt_number + max_drift).min(available_best_receipt_number); - - loop { - let primary_block_hash = - self.primary_chain_client - .hash(to_send.into())? - .ok_or_else(|| { - sp_blockchain::Error::Backend(format!( - "Primary block hash for #{to_send:?} not found" - )) - })?; - receipts.push(load_receipt(primary_block_hash, to_send)?); - to_send += One::one(); - - if to_send > max_allowed { - break; - } - } - - Ok(receipts) - } -} - -/// Performs the sanity check in order to detect the potential invalid receipts earlier. -fn receipts_sanity_check( - receipts: &[ExecutionReceiptFor], -) -> sp_blockchain::Result<()> -where - Block: BlockT, - PBlock: BlockT, -{ - for (i, [ref head, ref tail]) in receipts.array_windows().enumerate() { - if head.primary_number + One::one() != tail.primary_number { - return Err(sp_blockchain::Error::Application(Box::from(format!( - "Found inconsecutive receipt at index {}, receipts[{i}]: {:?}, receipts[{}]: {:?}", - i + 1, - (head.primary_number, head.primary_hash), - i + 1, - (tail.primary_number, tail.primary_hash), - )))); - } - } - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::receipts_sanity_check; - use domain_test_service::system_domain_test_runtime::Block; - use sp_core::H256; - use sp_domains::ExecutionReceipt; - use subspace_core_primitives::BlockNumber; - use subspace_runtime_primitives::Hash; - use subspace_test_runtime::Block as PBlock; + let receipt_number = (head_receipt_number + One::one()).min(available_best_receipt_number); - fn create_dummy_receipt_for( - primary_number: BlockNumber, - ) -> ExecutionReceipt { - ExecutionReceipt { - primary_number, - primary_hash: H256::random(), - domain_hash: H256::random(), - trace: if primary_number == 0 { - Vec::new() - } else { - vec![H256::random(), H256::random()] - }, - trace_root: Default::default(), - } - } - - #[test] - fn test_receipts_sanity_check() { - let receipts = vec![ - create_dummy_receipt_for(1), - create_dummy_receipt_for(2), - create_dummy_receipt_for(4), - ]; - assert!(receipts_sanity_check::(&receipts).is_err()); - - let receipts = vec![ - create_dummy_receipt_for(1), - create_dummy_receipt_for(2), - create_dummy_receipt_for(3), - ]; - assert!(receipts_sanity_check::(&receipts).is_ok()); - - let receipts = vec![create_dummy_receipt_for(1)]; - assert!(receipts_sanity_check::(&receipts).is_ok()); + let primary_block_hash = self + .primary_chain_client + .hash(receipt_number.into())? + .ok_or_else(|| { + sp_blockchain::Error::Backend(format!( + "Primary block hash for #{receipt_number:?} not found" + )) + })?; - assert!(receipts_sanity_check::(&[]).is_ok()); + load_receipt(primary_block_hash, receipt_number) } } diff --git a/domains/client/domain-executor/src/gossip_message_validator.rs b/domains/client/domain-executor/src/gossip_message_validator.rs index 94d10e2c986..b9a732220b2 100644 --- a/domains/client/domain-executor/src/gossip_message_validator.rs +++ b/domains/client/domain-executor/src/gossip_message_validator.rs @@ -190,9 +190,9 @@ where } } - pub(crate) fn validate_bundle_receipts( + pub(crate) fn validate_bundle_receipt( &self, - receipts: &[ExecutionReceiptFor], + receipt: &ExecutionReceiptFor, domain_id: DomainId, ) -> Result<(), GossipMessageError> { let head_receipt_number = self @@ -200,12 +200,10 @@ where .head_receipt_number(self.parent_chain.best_hash())?; let head_receipt_number = to_number_primitive(head_receipt_number); - for receipt in receipts { - if let Some(fraud_proof) = - self.validate_execution_receipt(receipt, head_receipt_number, domain_id)? - { - self.parent_chain.submit_fraud_proof_unsigned(fraud_proof)?; - } + if let Some(fraud_proof) = + self.validate_execution_receipt(receipt, head_receipt_number, domain_id)? + { + self.parent_chain.submit_fraud_proof_unsigned(fraud_proof)?; } Ok(()) diff --git a/domains/client/domain-executor/src/system_gossip_message_validator.rs b/domains/client/domain-executor/src/system_gossip_message_validator.rs index 7545d54ce14..42324ce1805 100644 --- a/domains/client/domain-executor/src/system_gossip_message_validator.rs +++ b/domains/client/domain-executor/src/system_gossip_message_validator.rs @@ -134,7 +134,7 @@ where let domain_id = bundle.domain_id(); self.gossip_message_validator - .validate_bundle_receipts(&bundle.receipts, domain_id)?; + .validate_bundle_receipt(&bundle.receipt, domain_id)?; let at = bundle .sealed_header diff --git a/domains/client/domain-executor/src/tests.rs b/domains/client/domain-executor/src/tests.rs index cec43ebc83b..de947e1d532 100644 --- a/domains/client/domain-executor/src/tests.rs +++ b/domains/client/domain-executor/src/tests.rs @@ -38,33 +38,6 @@ fn number_of(primary_node: &MockPrimaryNode, block_hash: Hash) -> u32 { .unwrap_or_else(|| panic!("header {block_hash} not in the chain")) } -/// Returns a list of (block_number, block_hash) ranging from head_receipt_number(exclusive) to best_header(inclusive). -fn number_hash_mappings_from_head_receipt_number_to_best_header( - primary_node: &MockPrimaryNode, - best_header: Header, -) -> Vec<(u32, Hash)> { - let head_receipt_number = primary_node - .client - .runtime_api() - .head_receipt_number(best_header.hash(), DomainId::SYSTEM) - .unwrap(); - - let mut current_best = best_header; - let mut mappings = vec![]; - while *current_best.number() > head_receipt_number { - mappings.push((*current_best.number(), current_best.hash())); - current_best = primary_node - .client - .header(*current_best.parent_hash()) - .unwrap() - .unwrap(); - } - - mappings.reverse(); - - mappings -} - #[substrate_test_utils::test(flavor = "multi_thread")] async fn collected_receipts_should_be_on_the_same_branch_with_current_best_block() { let directory = TempDir::new().expect("Must be able to create temporary directory"); @@ -125,23 +98,17 @@ async fn collected_receipts_should_be_on_the_same_branch_with_current_best_block best_primary_hash ); + let primary_block_info = + |best_header: Header| -> (u32, Hash) { (*best_header.number(), best_header.hash()) }; let receipts_primary_info = |bundle: Bundle| { - bundle - .receipts - .iter() - .map(|receipt| (receipt.primary_number, receipt.primary_hash)) - .collect::>() + (bundle.receipt.primary_number, bundle.receipt.primary_hash) }; // Produce a bundle after the fork block #3a has been produced. let signed_bundle = primary_node.notify_new_slot_and_wait_for_bundle(slot).await; - let expected_receipts_primary_info = - number_hash_mappings_from_head_receipt_number_to_best_header( - &primary_node, - best_header.clone(), - ); + let expected_receipts_primary_info = primary_block_info(best_header.clone()); // TODO: make MaximumReceiptDrift configurable in order to submit all the pending receipts at // once, now the max drift is 2, the receipts is limitted to [2, 3]. Once configurable, we @@ -149,10 +116,10 @@ async fn collected_receipts_should_be_on_the_same_branch_with_current_best_block // assert_eq!(receipts_primary_info, expected_receipts_primary_info). // // Receipts are always collected against the current best block. - receipts_primary_info(signed_bundle.unwrap()) - .into_iter() - .zip(expected_receipts_primary_info.clone()) - .for_each(|(a, b)| assert_eq!(a, b)); + assert_eq!( + receipts_primary_info(signed_bundle.unwrap()), + expected_receipts_primary_info + ); let slot = primary_node.produce_slot(); let fork_block_hash_3b = primary_node @@ -173,10 +140,10 @@ async fn collected_receipts_should_be_on_the_same_branch_with_current_best_block // Produce a bundle after the fork block #3b has been produced. let signed_bundle = primary_node.notify_new_slot_and_wait_for_bundle(slot).await; // Receipts are always collected against the current best block. - receipts_primary_info(signed_bundle.unwrap()) - .into_iter() - .zip(expected_receipts_primary_info) - .for_each(|(a, b)| assert_eq!(a, b)); + assert_eq!( + receipts_primary_info(signed_bundle.unwrap()), + expected_receipts_primary_info + ); // Produce a new tip at #4. let slot = primary_node.produce_slot(); @@ -206,17 +173,14 @@ async fn collected_receipts_should_be_on_the_same_branch_with_current_best_block .produce_slot_and_wait_for_bundle_submission() .await; - let expected_receipts_primary_info = - number_hash_mappings_from_head_receipt_number_to_best_header( - &primary_node, - new_best_header, - ); - - // Receipts are always collected against the current best block. - receipts_primary_info(signed_bundle.unwrap()) - .into_iter() - .zip(expected_receipts_primary_info) - .for_each(|(a, b)| assert_eq!(a, b)); + // In the new best fork, the receipt header number is 1 thus it produce the receipt + // of next block namely block 2 + let hash_2 = primary_node.client.hash(2).unwrap().unwrap(); + let header_2 = primary_node.client.header(hash_2).unwrap().unwrap(); + assert_eq!( + receipts_primary_info(signed_bundle.unwrap()), + primary_block_info(header_2) + ); } #[substrate_test_utils::test(flavor = "multi_thread")] @@ -408,12 +372,14 @@ async fn test_invalid_state_transition_proof_creation_and_verification( let original_submit_bundle_tx = bundle_to_tx(bundle.clone().unwrap()); let bad_submit_bundle_tx = { let mut opaque_bundle = bundle.unwrap(); - for receipt in opaque_bundle.receipts.iter_mut() { - if receipt.primary_number == target_bundle.sealed_header.header.primary_number + 1 { - assert_eq!(receipt.trace.len(), 3); - receipt.trace[mismatch_trace_index] = Default::default(); - } - } + let receipt = &mut opaque_bundle.receipt; + assert_eq!( + receipt.primary_number, + target_bundle.sealed_header.header.primary_number + 1 + ); + assert_eq!(receipt.trace.len(), 3); + + receipt.trace[mismatch_trace_index] = Default::default(); opaque_bundle.sealed_header.signature = alice .key .pair() @@ -514,10 +480,10 @@ async fn fraud_proof_verification_in_tx_pool_should_work() { let (_, bundle) = ferdie.produce_slot_and_wait_for_bundle_submission().await; let bad_bundle = { let mut opaque_bundle = bundle.unwrap(); - opaque_bundle.receipts.last_mut().unwrap().trace[0] = Default::default(); + opaque_bundle.receipt.trace[0] = Default::default(); opaque_bundle }; - let bad_receipt = bad_bundle.receipts.last().unwrap().clone(); + let bad_receipt = bad_bundle.receipt.clone(); let bad_receipt_number = bad_receipt.primary_number; assert_ne!(bad_receipt_number, 1); @@ -829,7 +795,7 @@ async fn pallet_domains_unsigned_extrinsics_should_work() { .pair() .sign(opaque_bundle.sealed_header.pre_hash().as_ref()) .into(); - opaque_bundle.receipts = vec![execution_receipt]; + opaque_bundle.receipt = execution_receipt; subspace_test_runtime::UncheckedExtrinsic::new_unsigned( pallet_domains::Call::submit_bundle { opaque_bundle }.into(), diff --git a/domains/pallets/domain-registry/src/benchmarking.rs b/domains/pallets/domain-registry/src/benchmarking.rs index 0e7d6b61334..2bb86955d60 100644 --- a/domains/pallets/domain-registry/src/benchmarking.rs +++ b/domains/pallets/domain-registry/src/benchmarking.rs @@ -97,44 +97,43 @@ mod benchmarks { assert!(DomainOperators::::get(operator, domain_id).is_none()); } - // TODO: pick https://github.com/paritytech/substrate/pull/13919 to support generic argument: - // Linear<1, { T::ReceiptsPruningDepth::get() }> /// Benchmark `submit_core_bundle` extrinsic with the worst possible conditions: - /// - All receipts are new and will prune the same number of expired receipts + /// - The receipts will prune a expired receipt #[benchmark] - fn submit_core_bundle(x: Linear<1, 256>) { + fn submit_core_bundle() { let receipts_pruning_depth = T::ReceiptsPruningDepth::get().saturated_into::(); // Import `ReceiptsPruningDepth` number of receipts which will be pruned later run_to_block::(1, receipts_pruning_depth); - let receipts: Vec<_> = (0..receipts_pruning_depth) - .map(|i| ExecutionReceipt::dummy(i.into(), block_hash_n::(i))) - .collect(); - let bundle = create_dummy_bundle_with_receipts_generic( - TEST_CORE_DOMAIN_ID, - receipts_pruning_depth.into(), - Default::default(), - receipts, - ); - assert_ok!(DomainRegistry::::submit_core_bundle( - RawOrigin::None.into(), - bundle - )); + for i in 0..receipts_pruning_depth { + let receipt = ExecutionReceipt::dummy(i.into(), block_hash_n::(i)); + let bundle = create_dummy_bundle_with_receipts_generic( + TEST_CORE_DOMAIN_ID, + (i + 1).into(), + Default::default(), + receipt, + ); + assert_ok!(DomainRegistry::::submit_core_bundle( + RawOrigin::None.into(), + bundle + )); + } assert_eq!( DomainRegistry::::head_receipt_number(TEST_CORE_DOMAIN_ID), (receipts_pruning_depth - 1).into() ); - // Construct a bundle that contain `x` number of new receipts - run_to_block::(receipts_pruning_depth + 1, receipts_pruning_depth + x); - let receipts: Vec<_> = (receipts_pruning_depth..(receipts_pruning_depth + x)) - .map(|i| ExecutionReceipt::dummy(i.into(), block_hash_n::(i))) - .collect(); + // Construct a bundle that contains a new receipts + run_to_block::(receipts_pruning_depth + 1, receipts_pruning_depth + 2); + let receipt = ExecutionReceipt::dummy( + receipts_pruning_depth.into(), + block_hash_n::(receipts_pruning_depth), + ); let bundle = create_dummy_bundle_with_receipts_generic( TEST_CORE_DOMAIN_ID, - x.into(), + (receipts_pruning_depth + 1).into(), Default::default(), - receipts, + receipt, ); #[extrinsic_call] @@ -142,11 +141,11 @@ mod benchmarks { assert_eq!( DomainRegistry::::head_receipt_number(TEST_CORE_DOMAIN_ID), - ((receipts_pruning_depth + x) - 1).into() + receipts_pruning_depth.into() ); assert_eq!( DomainRegistry::::oldest_receipt_number(TEST_CORE_DOMAIN_ID), - x.into() + 1u32.into() ); } @@ -159,19 +158,19 @@ mod benchmarks { // Import `ReceiptsPruningDepth` number of receipts which will be revert later run_to_block::(1, receipts_pruning_depth); - let receipts: Vec<_> = (0..receipts_pruning_depth) - .map(|i| ExecutionReceipt::dummy(i.into(), block_hash_n::(i))) - .collect(); - let bundle = create_dummy_bundle_with_receipts_generic( - TEST_CORE_DOMAIN_ID, - receipts_pruning_depth.into(), - Default::default(), - receipts, - ); - assert_ok!(DomainRegistry::::submit_core_bundle( - RawOrigin::None.into(), - bundle - )); + for i in 0..receipts_pruning_depth { + let receipt = ExecutionReceipt::dummy(i.into(), block_hash_n::(i)); + let bundle = create_dummy_bundle_with_receipts_generic( + TEST_CORE_DOMAIN_ID, + (i + 1).into(), + Default::default(), + receipt, + ); + assert_ok!(DomainRegistry::::submit_core_bundle( + RawOrigin::None.into(), + bundle + )); + } assert_eq!( DomainRegistry::::head_receipt_number(TEST_CORE_DOMAIN_ID), (receipts_pruning_depth - 1).into() diff --git a/domains/pallets/domain-registry/src/lib.rs b/domains/pallets/domain-registry/src/lib.rs index 548e4d190eb..f4ce5336bcf 100644 --- a/domains/pallets/domain-registry/src/lib.rs +++ b/domains/pallets/domain-registry/src/lib.rs @@ -41,6 +41,7 @@ use sp_domains::{ use sp_executor_registry::{ExecutorRegistry, OnNewEpoch}; use sp_runtime::traits::{BlakeTwo256, One, Zero}; use sp_runtime::Percent; +use sp_std::cmp::Ordering; use sp_std::collections::btree_map::BTreeMap; use sp_std::vec; use sp_std::vec::Vec; @@ -308,16 +309,16 @@ mod pallet { // TODO: Rename this extrinsic since the core bundle is not submit to the transaction pool but crafted and injected // on fly when building the system domain block. #[pallet::call_index(5)] - #[pallet::weight(T::WeightInfo::submit_core_bundle(opaque_bundle.receipts.len() as u32))] + #[pallet::weight(T::WeightInfo::submit_core_bundle())] pub fn submit_core_bundle( origin: OriginFor, opaque_bundle: OpaqueBundle, ) -> DispatchResult { ensure_none(origin)?; - pallet_settlement::Pallet::::track_receipts( + pallet_settlement::Pallet::::track_receipt( opaque_bundle.domain_id(), - opaque_bundle.receipts.as_slice(), + &opaque_bundle.receipt, ) .map_err(Error::::from)?; @@ -759,56 +760,55 @@ impl Pallet { let created_at = CreatedAt::::get(domain_id).ok_or(Error::::DomainNotCreated)?; let head_receipt_number = Self::head_receipt_number(domain_id); + let next_head_receipt_number = head_receipt_number + One::one(); let max_allowed = head_receipt_number + T::MaximumReceiptDrift::get(); + let receipt = &opaque_bundle.receipt; - let mut new_best_number = head_receipt_number; - let receipts = &opaque_bundle.receipts; - for receipt in receipts { - // Non-best receipt - if receipt.primary_number <= new_best_number { - continue; - // New nest receipt. - } else if receipt.primary_number == new_best_number + One::one() { - new_best_number += One::one(); - // Missing receipt. - } else { - let missing_receipt_number = new_best_number + One::one(); + // TODO: Check if the receipt extend the receipt chain or add confirmations to the head receipt + match receipt.primary_number.cmp(&next_head_receipt_number) { + // Missing receipt. + Ordering::Greater => { log::debug!( target: "runtime::domain-registry", - "Receipt for {domain_id:?} #{missing_receipt_number:?} is missing, \ + "Receipt for {domain_id:?} #{next_head_receipt_number:?} is missing, \ head_receipt_number: {head_receipt_number:?}, max_allowed: {max_allowed:?}, received: {:?}", - receipts.iter().map(|r| r.primary_number).collect::>() + receipt.primary_number ); return Err(Error::::Receipt(ReceiptError::MissingParent)); } + // Non-best receipt + Ordering::Less => {} + // New nest receipt. + Ordering::Equal => { + let primary_number = receipt.primary_number; + + if primary_number <= created_at { + log::debug!( + target: "runtime::domain-registry", + "Domain was created at #{created_at:?}, but this receipt points to an earlier block #{:?}", receipt.primary_number, + ); + return Err(Error::::Receipt(ReceiptError::BeforeDomainCreation)); + } - let primary_number = receipt.primary_number; - - if primary_number <= created_at { - log::debug!( - target: "runtime::domain-registry", - "Domain was created at #{created_at:?}, but this receipt points to an earlier block #{:?}", receipt.primary_number, - ); - return Err(Error::::Receipt(ReceiptError::BeforeDomainCreation)); - } - - if !pallet_settlement::Pallet::::point_to_valid_primary_block(domain_id, receipt) { - log::debug!( - target: "runtime::domain-registry", - "Receipt of {domain_id:?} #{primary_number:?},{:?} points to an unknown primary block, \ - expected: #{primary_number:?},{:?}", - receipt.primary_hash, - pallet_settlement::PrimaryBlockHash::::get(domain_id, primary_number), - ); - return Err(Error::::Receipt(ReceiptError::UnknownBlock)); - } + if !pallet_settlement::Pallet::::point_to_valid_primary_block(domain_id, receipt) + { + log::debug!( + target: "runtime::domain-registry", + "Receipt of {domain_id:?} #{primary_number:?},{:?} points to an unknown primary block, \ + expected: #{primary_number:?},{:?}", + receipt.primary_hash, + pallet_settlement::PrimaryBlockHash::::get(domain_id, primary_number), + ); + return Err(Error::::Receipt(ReceiptError::UnknownBlock)); + } - if primary_number > max_allowed { - log::debug!( - target: "runtime::domain-registry", - "Receipt for #{primary_number:?} is too far in future, max_allowed: {max_allowed:?}", - ); - return Err(Error::::Receipt(ReceiptError::TooFarInFuture)); + if primary_number > max_allowed { + log::debug!( + target: "runtime::domain-registry", + "Receipt for #{primary_number:?} is too far in future, max_allowed: {max_allowed:?}", + ); + return Err(Error::::Receipt(ReceiptError::TooFarInFuture)); + } } } @@ -837,20 +837,16 @@ impl Pallet { // domain resumes because the computation resource per block is limited anyway. // // This edge case does not impact the security due to the fraud-proof mechanism. - let state_root_verifiable = core_block_number <= new_best_number; + let state_root_verifiable = core_block_number <= head_receipt_number; if !core_block_number.is_zero() && state_root_verifiable { - let maybe_state_root = opaque_bundle.receipts.iter().find_map(|receipt| { - receipt.trace.last().and_then(|state_root| { - if (receipt.primary_number, receipt.domain_hash) - == (core_block_number, *core_block_hash) - { - Some(*state_root) - } else { - None - } - }) - }); + let maybe_state_root = if (receipt.primary_number, receipt.domain_hash) + == (core_block_number, *core_block_hash) + { + receipt.trace.last().cloned() + } else { + None + }; let expected_state_root = match maybe_state_root { Some(v) => v, diff --git a/domains/pallets/domain-registry/src/weights.rs b/domains/pallets/domain-registry/src/weights.rs index 7b6de8b6621..e8ec179db29 100644 --- a/domains/pallets/domain-registry/src/weights.rs +++ b/domains/pallets/domain-registry/src/weights.rs @@ -2,7 +2,7 @@ //! Autogenerated weights for pallet_domain_registry //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-06-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `local`, CPU: `` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -36,7 +36,7 @@ pub trait WeightInfo { fn create_domain() -> Weight; fn register_domain_operator() -> Weight; fn deregister_domain_operator() -> Weight; - fn submit_core_bundle(x: u32, ) -> Weight; + fn submit_core_bundle() -> Weight; fn submit_fraud_proof() -> Weight; } @@ -57,14 +57,14 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: DomainRegistry DomainCreators (max_values: None, max_size: None, mode: Measured) /// Storage: DomainRegistry CreatedAt (r:0 w:1) /// Proof Skipped: DomainRegistry CreatedAt (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts HeadReceiptNumber (r:0 w:1) - /// Proof Skipped: Receipts HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement HeadReceiptNumber (r:0 w:1) + /// Proof Skipped: Settlement HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) fn create_domain() -> Weight { // Proof Size summary in bytes: // Measured: `316` // Estimated: `14936` // Minimum execution time: 46_000_000 picoseconds. - Weight::from_parts(47_000_000, 14936) + Weight::from_parts(49_000_000, 14936) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -79,7 +79,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `810` // Estimated: `15300` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 15300) + Weight::from_parts(30_000_000, 15300) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -91,56 +91,52 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `369` // Estimated: `7668` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 7668) + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 7668) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Receipts OldestReceiptNumber (r:1 w:1) - /// Proof Skipped: Receipts OldestReceiptNumber (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts HeadReceiptNumber (r:1 w:1) - /// Proof Skipped: Receipts HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts Receipts (r:256 w:511) - /// Proof Skipped: Receipts Receipts (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts ReceiptVotes (r:766 w:511) - /// Proof Skipped: Receipts ReceiptVotes (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts PrimaryBlockHash (r:256 w:256) - /// Proof Skipped: Receipts PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts StateRoots (r:255 w:511) - /// Proof Skipped: Receipts StateRoots (max_values: None, max_size: None, mode: Measured) - /// The range of component `x` is `[1, 256]`. - fn submit_core_bundle(x: u32, ) -> Weight { + /// Storage: Settlement OldestReceiptNumber (r:1 w:1) + /// Proof Skipped: Settlement OldestReceiptNumber (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement HeadReceiptNumber (r:1 w:1) + /// Proof Skipped: Settlement HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement Receipts (r:1 w:2) + /// Proof Skipped: Settlement Receipts (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement ReceiptVotes (r:3 w:2) + /// Proof Skipped: Settlement ReceiptVotes (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement PrimaryBlockHash (r:1 w:1) + /// Proof Skipped: Settlement PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) + /// Storage: DomainRegistry SuccessfulBundles (r:1 w:1) + /// Proof Skipped: DomainRegistry SuccessfulBundles (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Settlement StateRoots (r:0 w:1) + /// Proof Skipped: Settlement StateRoots (max_values: None, max_size: None, mode: Measured) + fn submit_core_bundle() -> Weight { // Proof Size summary in bytes: - // Measured: `30039 + x * (237 ±0)` - // Estimated: `150815 + x * (16438 ±2)` - // Minimum execution time: 78_000_000 picoseconds. - Weight::from_parts(80_000_000, 150815) - // Standard Error: 45_968 - .saturating_add(Weight::from_parts(52_463_603, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(x.into()))) - .saturating_add(T::DbWeight::get().writes(8_u64)) - .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(x.into()))) - .saturating_add(Weight::from_parts(0, 16438).saturating_mul(x.into())) + // Measured: `4145` + // Estimated: `52775` + // Minimum execution time: 100_000_000 picoseconds. + Weight::from_parts(118_000_000, 52775) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(9_u64)) } - /// Storage: Receipts HeadReceiptNumber (r:1 w:1) - /// Proof Skipped: Receipts HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts PrimaryBlockHash (r:256 w:0) - /// Proof Skipped: Receipts PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts ReceiptVotes (r:510 w:255) - /// Proof Skipped: Receipts ReceiptVotes (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts Receipts (r:255 w:255) - /// Proof Skipped: Receipts Receipts (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts StateRoots (r:255 w:255) - /// Proof Skipped: Receipts StateRoots (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts SuccessfulFraudProofs (r:1 w:1) - /// Proof Skipped: Receipts SuccessfulFraudProofs (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Settlement HeadReceiptNumber (r:1 w:1) + /// Proof Skipped: Settlement HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement PrimaryBlockHash (r:256 w:0) + /// Proof Skipped: Settlement PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement ReceiptVotes (r:510 w:255) + /// Proof Skipped: Settlement ReceiptVotes (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement Receipts (r:255 w:255) + /// Proof Skipped: Settlement Receipts (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement StateRoots (r:255 w:255) + /// Proof Skipped: Settlement StateRoots (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement SuccessfulFraudProofs (r:1 w:1) + /// Proof Skipped: Settlement SuccessfulFraudProofs (max_values: Some(1), max_size: None, mode: Measured) fn submit_fraud_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `113653` - // Estimated: `3848928` - // Minimum execution time: 6_960_000_000 picoseconds. - Weight::from_parts(7_113_000_000, 3848928) + // Measured: `113582` + // Estimated: `3848502` + // Minimum execution time: 7_131_000_000 picoseconds. + Weight::from_parts(7_645_000_000, 3848502) .saturating_add(T::DbWeight::get().reads(1278_u64)) .saturating_add(T::DbWeight::get().writes(767_u64)) } @@ -162,14 +158,14 @@ impl WeightInfo for () { /// Proof Skipped: DomainRegistry DomainCreators (max_values: None, max_size: None, mode: Measured) /// Storage: DomainRegistry CreatedAt (r:0 w:1) /// Proof Skipped: DomainRegistry CreatedAt (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts HeadReceiptNumber (r:0 w:1) - /// Proof Skipped: Receipts HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement HeadReceiptNumber (r:0 w:1) + /// Proof Skipped: Settlement HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) fn create_domain() -> Weight { // Proof Size summary in bytes: // Measured: `316` // Estimated: `14936` // Minimum execution time: 46_000_000 picoseconds. - Weight::from_parts(47_000_000, 14936) + Weight::from_parts(49_000_000, 14936) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -184,7 +180,7 @@ impl WeightInfo for () { // Measured: `810` // Estimated: `15300` // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(29_000_000, 15300) + Weight::from_parts(30_000_000, 15300) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -196,56 +192,52 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `369` // Estimated: `7668` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_000_000, 7668) + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(17_000_000, 7668) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Receipts OldestReceiptNumber (r:1 w:1) - /// Proof Skipped: Receipts OldestReceiptNumber (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts HeadReceiptNumber (r:1 w:1) - /// Proof Skipped: Receipts HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts Receipts (r:256 w:511) - /// Proof Skipped: Receipts Receipts (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts ReceiptVotes (r:766 w:511) - /// Proof Skipped: Receipts ReceiptVotes (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts PrimaryBlockHash (r:256 w:256) - /// Proof Skipped: Receipts PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts StateRoots (r:255 w:511) - /// Proof Skipped: Receipts StateRoots (max_values: None, max_size: None, mode: Measured) - /// The range of component `x` is `[1, 256]`. - fn submit_core_bundle(x: u32, ) -> Weight { + /// Storage: Settlement OldestReceiptNumber (r:1 w:1) + /// Proof Skipped: Settlement OldestReceiptNumber (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement HeadReceiptNumber (r:1 w:1) + /// Proof Skipped: Settlement HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement Receipts (r:1 w:2) + /// Proof Skipped: Settlement Receipts (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement ReceiptVotes (r:3 w:2) + /// Proof Skipped: Settlement ReceiptVotes (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement PrimaryBlockHash (r:1 w:1) + /// Proof Skipped: Settlement PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) + /// Storage: DomainRegistry SuccessfulBundles (r:1 w:1) + /// Proof Skipped: DomainRegistry SuccessfulBundles (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Settlement StateRoots (r:0 w:1) + /// Proof Skipped: Settlement StateRoots (max_values: None, max_size: None, mode: Measured) + fn submit_core_bundle() -> Weight { // Proof Size summary in bytes: - // Measured: `30039 + x * (237 ±0)` - // Estimated: `150815 + x * (16438 ±2)` - // Minimum execution time: 78_000_000 picoseconds. - Weight::from_parts(80_000_000, 150815) - // Standard Error: 45_968 - .saturating_add(Weight::from_parts(52_463_603, 0).saturating_mul(x.into())) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(x.into()))) - .saturating_add(RocksDbWeight::get().writes(8_u64)) - .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(x.into()))) - .saturating_add(Weight::from_parts(0, 16438).saturating_mul(x.into())) + // Measured: `4145` + // Estimated: `52775` + // Minimum execution time: 100_000_000 picoseconds. + Weight::from_parts(118_000_000, 52775) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(9_u64)) } - /// Storage: Receipts HeadReceiptNumber (r:1 w:1) - /// Proof Skipped: Receipts HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts PrimaryBlockHash (r:256 w:0) - /// Proof Skipped: Receipts PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts ReceiptVotes (r:510 w:255) - /// Proof Skipped: Receipts ReceiptVotes (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts Receipts (r:255 w:255) - /// Proof Skipped: Receipts Receipts (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts StateRoots (r:255 w:255) - /// Proof Skipped: Receipts StateRoots (max_values: None, max_size: None, mode: Measured) - /// Storage: Receipts SuccessfulFraudProofs (r:1 w:1) - /// Proof Skipped: Receipts SuccessfulFraudProofs (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Settlement HeadReceiptNumber (r:1 w:1) + /// Proof Skipped: Settlement HeadReceiptNumber (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement PrimaryBlockHash (r:256 w:0) + /// Proof Skipped: Settlement PrimaryBlockHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement ReceiptVotes (r:510 w:255) + /// Proof Skipped: Settlement ReceiptVotes (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement Receipts (r:255 w:255) + /// Proof Skipped: Settlement Receipts (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement StateRoots (r:255 w:255) + /// Proof Skipped: Settlement StateRoots (max_values: None, max_size: None, mode: Measured) + /// Storage: Settlement SuccessfulFraudProofs (r:1 w:1) + /// Proof Skipped: Settlement SuccessfulFraudProofs (max_values: Some(1), max_size: None, mode: Measured) fn submit_fraud_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `113653` - // Estimated: `3848928` - // Minimum execution time: 6_960_000_000 picoseconds. - Weight::from_parts(7_113_000_000, 3848928) + // Measured: `113582` + // Estimated: `3848502` + // Minimum execution time: 7_131_000_000 picoseconds. + Weight::from_parts(7_645_000_000, 3848502) .saturating_add(RocksDbWeight::get().reads(1278_u64)) .saturating_add(RocksDbWeight::get().writes(767_u64)) } diff --git a/domains/runtime/system/src/runtime.rs b/domains/runtime/system/src/runtime.rs index 53edf1f1e80..012081a4266 100644 --- a/domains/runtime/system/src/runtime.rs +++ b/domains/runtime/system/src/runtime.rs @@ -651,11 +651,10 @@ impl_runtime_apis! { }) if opaque_bundle.domain_id() == domain_id && successful_bundles.contains(&opaque_bundle.hash()) => { - Some(opaque_bundle.receipts) + Some(opaque_bundle.receipt) } _ => None, }) - .flatten() .collect() } diff --git a/domains/test/runtime/system/src/runtime.rs b/domains/test/runtime/system/src/runtime.rs index e63ea63de49..d1da833350c 100644 --- a/domains/test/runtime/system/src/runtime.rs +++ b/domains/test/runtime/system/src/runtime.rs @@ -663,11 +663,10 @@ impl_runtime_apis! { }) if opaque_bundle.domain_id() == domain_id && successful_bundles.contains(&opaque_bundle.hash()) => { - Some(opaque_bundle.receipts) + Some(opaque_bundle.receipt) } _ => None, }) - .flatten() .collect() } diff --git a/test/subspace-test-runtime/src/lib.rs b/test/subspace-test-runtime/src/lib.rs index 812b19463ab..d91950bfe7e 100644 --- a/test/subspace-test-runtime/src/lib.rs +++ b/test/subspace-test-runtime/src/lib.rs @@ -898,11 +898,10 @@ fn extract_receipts( if opaque_bundle.domain_id() == domain_id && successful_bundles.contains(&opaque_bundle.hash()) => { - Some(opaque_bundle.receipts) + Some(opaque_bundle.receipt) } _ => None, }) - .flatten() .collect() }