@@ -34,7 +34,7 @@ use sp_domains::{
3434 SignedOpaqueBundle , StakeWeight ,
3535} ;
3636use sp_executor_registry:: { ExecutorRegistry , OnNewEpoch } ;
37- use sp_runtime:: traits:: { BlakeTwo256 , Hash , One , Saturating , Zero } ;
37+ use sp_runtime:: traits:: { BlakeTwo256 , CheckedSub , Hash , One , Saturating , Zero } ;
3838use sp_runtime:: Percent ;
3939use sp_std:: collections:: btree_map:: BTreeMap ;
4040use sp_std:: vec;
@@ -228,6 +228,25 @@ mod pallet {
228228 OptionQuery ,
229229 > ;
230230
231+ /// Map of primary block number to primary block hash for tracking bounded receipts per domain.
232+ ///
233+ /// NOTE: This storage item is extended on adding a new non-system receipt since each receipt
234+ /// is validated to point to a valid primary block on the primary chain.
235+ ///
236+ /// The oldest block hash will be pruned once the oldest receipt is pruned. However, if a
237+ /// core domain stalls, i.e., no receipts are included in the system domain for a long time,
238+ /// the corresponding entry will grow indefinitely.
239+ #[ pallet:: storage]
240+ pub ( super ) type BlockHash < T : Config > = StorageDoubleMap <
241+ _ ,
242+ Twox64Concat ,
243+ DomainId ,
244+ Twox64Concat ,
245+ T :: BlockNumber ,
246+ T :: Hash ,
247+ ValueQuery ,
248+ > ;
249+
231250 #[ pallet:: call]
232251 impl < T : Config > Pallet < T > {
233252 /// Creates a new domain with some deposit locked.
@@ -371,15 +390,10 @@ mod pallet {
371390 Self :: apply_new_best_receipt ( domain_id, receipt) ;
372391 best_number += One :: one ( ) ;
373392 } else {
374- /*
375393 // Reject the entire Bundle due to the missing receipt(s) between [best_number, .., receipt.primary_number].
376394 //
377395 // This should never happen as pre_dispatch_submit_bundle ensures no missing receipt.
378- return Err(Error::<T>::Bundle(BundleError::Receipt(
379- ExecutionReceiptError::MissingParent,
380- ))
381- .into());
382- */
396+ return Err ( Error :: < T > :: MissingParentReceipt . into ( ) ) ;
383397 }
384398 }
385399
@@ -538,6 +552,9 @@ mod pallet {
538552
539553 /// Not a core domain bundle.
540554 NotCoreDomainBundle ,
555+
556+ /// A missing core domain parent receipt.
557+ MissingParentReceipt ,
541558 }
542559
543560 #[ pallet:: event]
@@ -760,6 +777,20 @@ impl<T: Config> Pallet<T> {
760777 return Err ( Error :: < T > :: NotCoreDomainBundle ) ;
761778 } ;
762779
780+ let mut best_number = Self :: head_receipt_number ( signed_opaque_bundle. domain_id ( ) ) ;
781+ for receipt in & signed_opaque_bundle. bundle . receipts {
782+ // Non-best receipt
783+ if receipt. primary_number <= best_number {
784+ continue ;
785+ // New nest receipt.
786+ } else if receipt. primary_number == best_number + One :: one ( ) {
787+ best_number += One :: one ( ) ;
788+ // Missing receipt.
789+ } else {
790+ return Err ( Error :: < T > :: MissingParentReceipt ) ;
791+ }
792+ }
793+
763794 // The validity of vrf proof itself has been verified on the primary chain, thus only the
764795 // proof_of_election is necessary to be checked here.
765796 let ProofOfElection {
@@ -985,6 +1016,10 @@ impl<T: Config> Pallet<T> {
9851016 let primary_number = execution_receipt. primary_number ;
9861017 let receipt_hash = execution_receipt. hash ( ) ;
9871018
1019+ // (primary_number, primary_hash) has been verified on the primary chain, thus it
1020+ // can be used directly.
1021+ <BlockHash < T > >:: insert ( domain_id, primary_number, primary_hash) ;
1022+
9881023 // Apply the new best receipt.
9891024 <Receipts < T > >:: insert ( domain_id, receipt_hash, execution_receipt) ;
9901025 <ReceiptHead < T > >:: insert ( domain_id, ( primary_hash, primary_number) ) ;
@@ -1006,20 +1041,20 @@ impl<T: Config> Pallet<T> {
10061041 T :: CoreDomainTracker :: add_core_domain_state_root ( domain_id, primary_number, * state_root)
10071042 }
10081043
1009- /* TODO:
10101044 // Remove the expired receipts once the receipts cache is full.
10111045 if let Some ( to_prune) = primary_number. checked_sub ( & T :: ReceiptsPruningDepth :: get ( ) ) {
1012- BlockHash::<T>::mutate_exists(to_prune, |maybe_block_hash| {
1046+ BlockHash :: < T > :: mutate_exists ( domain_id , to_prune, |maybe_block_hash| {
10131047 if let Some ( block_hash) = maybe_block_hash. take ( ) {
1014- for (receipt_hash, _) in <ReceiptVotes<T>>::drain_prefix(block_hash) {
1015- Receipts::<T>::remove(receipt_hash);
1048+ for ( receipt_hash, _) in
1049+ <ReceiptVotes < T > >:: drain_prefix ( ( domain_id, block_hash) )
1050+ {
1051+ Receipts :: < T > :: remove ( domain_id, receipt_hash) ;
10161052 }
10171053 }
10181054 } ) ;
1019- OldestReceiptNumber::<T>::put( to_prune + One::one());
1020- let _ = <StateRoots<T>>::clear_prefix(to_prune, u32::MAX, None);
1055+ OldestReceiptNumber :: < T > :: insert ( domain_id , to_prune + One :: one ( ) ) ;
1056+ let _ = <StateRoots < T > >:: clear_prefix ( ( domain_id , to_prune) , u32:: MAX , None ) ;
10211057 }
1022- */
10231058
10241059 Self :: deposit_event ( Event :: NewCoreDomainReceipt {
10251060 domain_id,
0 commit comments