Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update storages and types for Domains #2512

Merged
merged 3 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading