Skip to content

Commit

Permalink
Merge pull request #2512 from subspace/type_updates
Browse files Browse the repository at this point in the history
Update storages and types for Domains
  • Loading branch information
vedhavyas authored Feb 7, 2024
2 parents 1f117fa + 8969219 commit bb3bb27
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 149 deletions.
53 changes: 27 additions & 26 deletions crates/pallet-domains/src/block_tree.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
//! Domain block tree

use crate::pallet::StateRoots;
use crate::{
BalanceOf, BlockTree, BlockTreeNodes, Config, ConsensusBlockHash, DomainBlockNumberFor,
DomainHashingFor, ExecutionInbox, ExecutionReceiptOf, HeadReceiptExtended, HeadReceiptNumber,
InboxedBundleAuthor, LatestConfirmedDomainBlockNumber, ReceiptHashFor,
InboxedBundleAuthor, LatestConfirmedDomainBlock, Pallet, ReceiptHashFor,
};
use codec::{Decode, Encode};
use frame_support::{ensure, PalletError};
use scale_info::TypeInfo;
use sp_core::Get;
use sp_domains::merkle_tree::MerkleTree;
use sp_domains::{DomainId, ExecutionReceipt, OperatorId};
use sp_domains::{ConfirmedDomainBlock, DomainId, ExecutionReceipt, OperatorId};
use sp_runtime::traits::{BlockNumberProvider, CheckedSub, One, Saturating, Zero};
use sp_std::cmp::Ordering;
use sp_std::collections::btree_map::BTreeMap;
Expand Down Expand Up @@ -109,7 +108,7 @@ pub(crate) fn execution_receipt_type<T: Config>(
let head_receipt_number = HeadReceiptNumber::<T>::get(domain_id);
let next_receipt_number = head_receipt_number.saturating_add(One::one());
let latest_confirmed_domain_block_number =
LatestConfirmedDomainBlockNumber::<T>::get(domain_id);
Pallet::<T>::latest_confirmed_domain_block_number(domain_id);

match receipt_number.cmp(&next_receipt_number) {
Ordering::Greater => ReceiptType::Rejected(RejectedReceiptType::InFuture),
Expand Down Expand Up @@ -313,12 +312,6 @@ pub(crate) fn process_execution_receipt<T: Config>(
operator_ids,
} = BlockTreeNodes::<T>::take(receipt_hash).ok_or(Error::MissingDomainBlock)?;

_ = StateRoots::<T>::take((
domain_id,
to_prune,
execution_receipt.domain_block_hash,
));

// Collect the paid bundle storage fees and the invalid bundle author
let mut paid_bundle_storage_fees = BTreeMap::new();
let mut invalid_bundle_authors = Vec::new();
Expand Down Expand Up @@ -351,6 +344,18 @@ pub(crate) fn process_execution_receipt<T: Config>(
execution_receipt.consensus_block_number,
);

LatestConfirmedDomainBlock::<T>::insert(
domain_id,
ConfirmedDomainBlock {
block_number: to_prune,
block_hash: execution_receipt.domain_block_hash,
parent_block_receipt_hash: execution_receipt
.parent_domain_block_receipt_hash,
state_root: execution_receipt.final_state_root,
extrinsics_root: execution_receipt.domain_block_extrinsic_root,
},
);

return Ok(Some(ConfirmedDomainBlockInfo {
domain_block_number: to_prune,
operator_ids,
Expand Down Expand Up @@ -383,14 +388,6 @@ fn add_new_receipt_to_block_tree<T: Config>(
// Construct and add a new domain block to the block tree
let er_hash = execution_receipt.hash::<DomainHashingFor<T>>();
let domain_block_number = execution_receipt.domain_block_number;
StateRoots::<T>::insert(
(
domain_id,
domain_block_number,
execution_receipt.domain_block_hash,
),
execution_receipt.final_state_root,
);

BlockTree::<T>::insert(domain_id, domain_block_number, er_hash);
let block_tree_node = BlockTreeNode {
Expand All @@ -407,20 +404,24 @@ pub(crate) fn import_genesis_receipt<T: Config>(
) {
let er_hash = genesis_receipt.hash::<DomainHashingFor<T>>();
let domain_block_number = genesis_receipt.domain_block_number;

LatestConfirmedDomainBlock::<T>::insert(
domain_id,
ConfirmedDomainBlock {
block_number: domain_block_number,
block_hash: genesis_receipt.domain_block_hash,
parent_block_receipt_hash: Default::default(),
state_root: genesis_receipt.final_state_root,
extrinsics_root: genesis_receipt.domain_block_extrinsic_root,
},
);

let block_tree_node = BlockTreeNode {
execution_receipt: genesis_receipt,
operator_ids: sp_std::vec![],
};
// NOTE: no need to update the head receipt number as `HeadReceiptNumber` is using `ValueQuery`
BlockTree::<T>::insert(domain_id, domain_block_number, er_hash);
StateRoots::<T>::insert(
(
domain_id,
domain_block_number,
block_tree_node.execution_receipt.domain_block_hash,
),
block_tree_node.execution_receipt.final_state_root,
);
BlockTreeNodes::<T>::insert(er_hash, block_tree_node);
}

Expand Down
69 changes: 25 additions & 44 deletions crates/pallet-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ mod pallet {
use sp_core::H256;
use sp_domains::bundle_producer_election::ProofOfElectionError;
use sp_domains::{
BundleDigest, DomainId, EpochIndex, GenesisDomain, OperatorAllowList, OperatorId,
OperatorPublicKey, RuntimeId, RuntimeType,
BundleDigest, ConfirmedDomainBlock, DomainId, EpochIndex, GenesisDomain, OperatorAllowList,
OperatorId, OperatorPublicKey, RuntimeId, RuntimeType,
};
use sp_domains_fraud_proof::fraud_proof::FraudProof;
use sp_domains_fraud_proof::InvalidTransactionCode;
Expand Down Expand Up @@ -495,29 +495,13 @@ mod pallet {
pub(super) type HeadReceiptNumber<T: Config> =
StorageMap<_, Identity, DomainId, DomainBlockNumberFor<T>, ValueQuery>;

/// The latest confirmed block number of each domain.
#[pallet::storage]
pub(super) type LatestConfirmedDomainBlockNumber<T: Config> =
StorageMap<_, Identity, DomainId, DomainBlockNumberFor<T>, ValueQuery>;

/// Whether the head receipt have extended in the current consensus block
///
/// Temporary storage only exist during block execution
#[pallet::storage]
pub(super) type HeadReceiptExtended<T: Config> =
StorageMap<_, Identity, DomainId, bool, ValueQuery>;

/// State root mapped again each domain (block, hash)
/// This acts as an index for other protocols like XDM to fetch state roots faster.
#[pallet::storage]
pub(super) type StateRoots<T: Config> = StorageMap<
_,
Identity,
(DomainId, DomainBlockNumberFor<T>, T::DomainHash),
T::DomainHash,
OptionQuery,
>;

/// The consensus block hash used to verify ER,
/// only store the consensus block hash for a domain
/// if that consensus block contains bundle of the domain, the hash will be pruned when the ER
Expand Down Expand Up @@ -571,6 +555,16 @@ mod pallet {
pub(super) type LastEpochStakingDistribution<T: Config> =
StorageMap<_, Identity, DomainId, ElectionVerificationParams<BalanceOf<T>>, OptionQuery>;

/// Storage to hold all the domain's latest confirmed block.
#[pallet::storage]
pub(super) type LatestConfirmedDomainBlock<T: Config> = StorageMap<
_,
Identity,
DomainId,
ConfirmedDomainBlock<DomainBlockNumberFor<T>, T::DomainHash>,
OptionQuery,
>;

#[derive(TypeInfo, Encode, Decode, PalletError, Debug, PartialEq)]
pub enum BundleError {
/// Can not find the operator for given operator id.
Expand Down Expand Up @@ -897,11 +891,6 @@ mod pallet {
)
.map_err(Error::<T>::from)?;

LatestConfirmedDomainBlockNumber::<T>::insert(
domain_id,
confirmed_block_info.domain_block_number,
);

if confirmed_block_info.domain_block_number % T::StakeEpochDuration::get()
== Zero::zero()
{
Expand Down Expand Up @@ -996,17 +985,9 @@ mod pallet {
let receipt_hash = BlockTree::<T>::take(domain_id, to_prune)
.ok_or::<Error<T>>(FraudProofError::BadReceiptNotFound.into())?;

let BlockTreeNode {
execution_receipt,
operator_ids,
} = BlockTreeNodes::<T>::take(receipt_hash)
.ok_or::<Error<T>>(FraudProofError::BadReceiptNotFound.into())?;

let _ = StateRoots::<T>::take((
domain_id,
execution_receipt.domain_block_number,
execution_receipt.domain_block_hash,
));
let BlockTreeNode { operator_ids, .. } =
BlockTreeNodes::<T>::take(receipt_hash)
.ok_or::<Error<T>>(FraudProofError::BadReceiptNotFound.into())?;

// NOTE: the operator id will be deduplicated since we are using `BTreeMap`
// and slashed reason will hold earliest bad execution receipt hash which this
Expand Down Expand Up @@ -1506,14 +1487,6 @@ impl<T: Config> Pallet<T> {
Some(HeadDomainNumber::<T>::get(domain_id))
}

pub fn domain_state_root(
domain_id: DomainId,
domain_block_number: DomainBlockNumberFor<T>,
domain_block_hash: T::DomainHash,
) -> Option<T::DomainHash> {
StateRoots::<T>::get((domain_id, domain_block_number, domain_block_hash))
}

pub fn runtime_id(domain_id: DomainId) -> Option<RuntimeId> {
DomainRegistry::<T>::get(domain_id)
.map(|domain_object| domain_object.domain_config.runtime_id)
Expand Down Expand Up @@ -1911,7 +1884,7 @@ impl<T: Config> Pallet<T> {
domain_id: DomainId,
) -> Option<DomainBlockNumberFor<T>> {
let oldest_nonconfirmed_er_number =
LatestConfirmedDomainBlockNumber::<T>::get(domain_id).saturating_add(One::one());
Self::latest_confirmed_domain_block_number(domain_id).saturating_add(One::one());

if BlockTree::<T>::get(domain_id, oldest_nonconfirmed_er_number).is_some() {
Some(oldest_nonconfirmed_er_number)
Expand All @@ -1924,6 +1897,14 @@ impl<T: Config> Pallet<T> {
}
}

/// Returns the latest confirmed domain block number for a given domain
/// Zero block is always a default confirmed block.
pub fn latest_confirmed_domain_block_number(domain_id: DomainId) -> DomainBlockNumberFor<T> {
LatestConfirmedDomainBlock::<T>::get(domain_id)
.map(|block| block.block_number)
.unwrap_or_default()
}

/// Returns the domain block limit of the given domain.
pub fn domain_block_limit(domain_id: DomainId) -> Option<DomainBlockLimit> {
DomainRegistry::<T>::get(domain_id).map(|domain_obj| DomainBlockLimit {
Expand All @@ -1941,7 +1922,7 @@ impl<T: Config> Pallet<T> {

// Start from the oldest non-confirmed ER to the head domain number
let mut to_check =
LatestConfirmedDomainBlockNumber::<T>::get(domain_id).saturating_add(One::one());
Self::latest_confirmed_domain_block_number(domain_id).saturating_add(One::one());
let head_number = HeadDomainNumber::<T>::get(domain_id);

while to_check <= head_number {
Expand Down
44 changes: 32 additions & 12 deletions crates/pallet-domains/src/staking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

use crate::bundle_storage_fund::{self, deposit_reserve_for_storage_fund};
use crate::pallet::{
Deposits, DomainRegistry, DomainStakingSummary, LatestConfirmedDomainBlockNumber,
NextOperatorId, NominatorCount, OperatorIdOwner, OperatorSigningKey, Operators,
PendingOperatorSwitches, PendingSlashes, PendingStakingOperationCount, Withdrawals,
Deposits, DomainRegistry, DomainStakingSummary, NextOperatorId, NominatorCount,
OperatorIdOwner, OperatorSigningKey, Operators, PendingOperatorSwitches, PendingSlashes,
PendingStakingOperationCount, Withdrawals,
};
use crate::staking_epoch::mint_funds;
use crate::{
Expand Down Expand Up @@ -685,7 +685,7 @@ pub(crate) fn do_deregister_operator<T: Config>(
.ok_or(Error::DomainNotInitialized)?;

let latest_confirmed_domain_block_number =
LatestConfirmedDomainBlockNumber::<T>::get(operator.current_domain_id);
Pallet::<T>::latest_confirmed_domain_block_number(operator.current_domain_id);
let unlock_operator_at_domain_block_number = latest_confirmed_domain_block_number
.checked_add(&T::StakeWithdrawalLockingPeriod::get())
.ok_or(Error::BlockNumberOverflow)?;
Expand Down Expand Up @@ -859,7 +859,7 @@ pub(crate) fn do_withdraw_stake<T: Config>(
}

let latest_confirmed_domain_block_number =
LatestConfirmedDomainBlockNumber::<T>::get(operator.current_domain_id);
Pallet::<T>::latest_confirmed_domain_block_number(operator.current_domain_id);
let unlock_at_confirmed_domain_block_number = latest_confirmed_domain_block_number
.checked_add(&T::StakeWithdrawalLockingPeriod::get())
.ok_or(Error::BlockNumberOverflow)?;
Expand Down Expand Up @@ -924,7 +924,8 @@ pub(crate) fn do_unlock_funds<T: Config>(
.pop_front()
.ok_or(Error::MissingWithdrawal)?;

let latest_confirmed_block_number = LatestConfirmedDomainBlockNumber::<T>::get(domain_id);
let latest_confirmed_block_number =
Pallet::<T>::latest_confirmed_domain_block_number(domain_id);
ensure!(
unlock_at_confirmed_domain_block_number <= latest_confirmed_block_number,
Error::UnlockPeriodNotComplete
Expand Down Expand Up @@ -1001,7 +1002,8 @@ pub(crate) fn do_unlock_operator<T: Config>(operator_id: OperatorId) -> Result<(
};

let (domain_id, _) = domain_epoch.deconstruct();
let latest_confirmed_block_number = LatestConfirmedDomainBlockNumber::<T>::get(domain_id);
let latest_confirmed_block_number =
Pallet::<T>::latest_confirmed_domain_block_number(domain_id);
ensure!(
unlock_at_confirmed_domain_block_number <= latest_confirmed_block_number,
Error::UnlockPeriodNotComplete
Expand Down Expand Up @@ -1233,7 +1235,7 @@ where
pub(crate) mod tests {
use crate::domain_registry::{DomainConfig, DomainObject};
use crate::pallet::{
Config, Deposits, DomainRegistry, DomainStakingSummary, LatestConfirmedDomainBlockNumber,
Config, Deposits, DomainRegistry, DomainStakingSummary, LatestConfirmedDomainBlock,
NextOperatorId, NominatorCount, OperatorIdOwner, Operators, PendingOperatorSwitches,
PendingSlashes, Withdrawals,
};
Expand All @@ -1251,8 +1253,8 @@ pub(crate) mod tests {
use frame_support::{assert_err, assert_ok};
use sp_core::{Pair, U256};
use sp_domains::{
DomainId, OperatorAllowList, OperatorId, OperatorPair, OperatorPublicKey,
ZERO_OPERATOR_SIGNING_KEY,
ConfirmedDomainBlock, DomainId, OperatorAllowList, OperatorId, OperatorPair,
OperatorPublicKey, ZERO_OPERATOR_SIGNING_KEY,
};
use sp_runtime::traits::Zero;
use sp_runtime::{PerThing, Perbill};
Expand Down Expand Up @@ -1920,7 +1922,16 @@ pub(crate) mod tests {

let nominator_count = NominatorCount::<Test>::get(operator_id);
let confirmed_domain_block = 100;
LatestConfirmedDomainBlockNumber::<Test>::insert(domain_id, confirmed_domain_block);
LatestConfirmedDomainBlock::<Test>::insert(
domain_id,
ConfirmedDomainBlock {
block_number: confirmed_domain_block,
block_hash: Default::default(),
parent_block_receipt_hash: Default::default(),
state_root: Default::default(),
extrinsics_root: Default::default(),
},
);

if let Some(deposit_amount) = maybe_deposit {
Balances::mint_into(&nominator_id, deposit_amount).unwrap();
Expand Down Expand Up @@ -1979,7 +1990,16 @@ pub(crate) mod tests {
// staking withdrawal is 5 blocks
// to unlock funds, confirmed block should be atleast 105
let confirmed_domain_block = 105;
LatestConfirmedDomainBlockNumber::<Test>::insert(domain_id, confirmed_domain_block);
LatestConfirmedDomainBlock::<Test>::insert(
domain_id,
ConfirmedDomainBlock {
block_number: confirmed_domain_block,
block_hash: Default::default(),
parent_block_receipt_hash: Default::default(),
state_root: Default::default(),
extrinsics_root: Default::default(),
},
);
assert_ok!(do_unlock_funds::<Test>(operator_id, nominator_id));

let expected_balance = if include_ed {
Expand Down
Loading

0 comments on commit bb3bb27

Please sign in to comment.