Skip to content

Commit 504a798

Browse files
authored
Merge pull request #986 from subspace/prune-core-domain-receipts
Prune stale core domain receipts
2 parents 6ad9e1a + 66bf4ac commit 504a798

File tree

2 files changed

+75
-30
lines changed
  • crates/pallet-domains/src
  • domains/pallets/domain-registry/src

2 files changed

+75
-30
lines changed

crates/pallet-domains/src/lib.rs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -305,10 +305,10 @@ mod pallet {
305305
}
306306
}
307307

308-
/// Map of block number to block hash.
308+
/// Map of primary block number to primary block hash.
309309
///
310310
/// NOTE: The oldest block hash will be pruned once the oldest receipt is pruned. However, if the
311-
/// execution chain stalls, i.e., no receipts are included in the primary chain for a long time,
311+
/// system domain stalls, i.e., no receipts are included in the primary chain for a long time,
312312
/// this mapping will grow indefinitely.
313313
#[pallet::storage]
314314
pub(super) type BlockHash<T: Config> =
@@ -528,30 +528,40 @@ impl<T: Config> Pallet<T> {
528528
));
529529
}
530530

531-
let (_, mut best_number) = <ReceiptHead<T>>::get();
531+
if signed_opaque_bundle.domain_id().is_system() {
532+
let (_, mut best_number) = <ReceiptHead<T>>::get();
532533

533-
for receipt in execution_receipts {
534-
// Non-best receipt
535-
if receipt.primary_number <= best_number {
536-
if BlockHash::<T>::get(receipt.primary_number) != receipt.primary_hash {
534+
for receipt in execution_receipts {
535+
// Non-best receipt
536+
if receipt.primary_number <= best_number {
537+
if BlockHash::<T>::get(receipt.primary_number) != receipt.primary_hash {
538+
return Err(TransactionValidityError::Invalid(
539+
InvalidTransactionCode::ExecutionReceipt.into(),
540+
));
541+
}
542+
continue;
543+
// New nest receipt.
544+
} else if receipt.primary_number == best_number + One::one() {
545+
if BlockHash::<T>::get(receipt.primary_number) != receipt.primary_hash {
546+
return Err(TransactionValidityError::Invalid(
547+
InvalidTransactionCode::ExecutionReceipt.into(),
548+
));
549+
}
550+
best_number += One::one();
551+
// Missing receipt.
552+
} else {
537553
return Err(TransactionValidityError::Invalid(
538554
InvalidTransactionCode::ExecutionReceipt.into(),
539555
));
540556
}
541-
continue;
542-
// New nest receipt.
543-
} else if receipt.primary_number == best_number + One::one() {
557+
}
558+
} else {
559+
for receipt in execution_receipts {
544560
if BlockHash::<T>::get(receipt.primary_number) != receipt.primary_hash {
545561
return Err(TransactionValidityError::Invalid(
546562
InvalidTransactionCode::ExecutionReceipt.into(),
547563
));
548564
}
549-
best_number += One::one();
550-
// Missing receipt.
551-
} else {
552-
return Err(TransactionValidityError::Invalid(
553-
InvalidTransactionCode::ExecutionReceipt.into(),
554-
));
555565
}
556566
}
557567

domains/pallets/domain-registry/src/lib.rs

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use sp_domains::{
3434
SignedOpaqueBundle, StakeWeight,
3535
};
3636
use 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};
3838
use sp_runtime::Percent;
3939
use sp_std::collections::btree_map::BTreeMap;
4040
use 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

Comments
 (0)