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

Add fallback decoding for the pallet-domains v3 storage migration #3407

Merged
merged 2 commits into from
Feb 27, 2025
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
22 changes: 12 additions & 10 deletions crates/pallet-domains/src/domain_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::runtime_registry::DomainRuntimeInfo;
use crate::staking::StakingSummary;
use crate::{
into_complete_raw_genesis, BalanceOf, Config, DomainHashingFor, DomainRegistry,
DomainSudoCalls, ExecutionReceiptOf, HoldIdentifier, NextDomainId, RuntimeRegistry,
DomainSudoCalls, ExecutionReceiptOf, HoldIdentifier, NextDomainId, Pallet, RuntimeRegistry,
};
#[cfg(not(feature = "std"))]
use alloc::string::String;
Expand Down Expand Up @@ -368,16 +368,18 @@ pub(crate) fn do_update_domain_allow_list<T: Config>(
domain_id: DomainId,
updated_operator_allow_list: OperatorAllowList<T::AccountId>,
) -> Result<(), Error> {
DomainRegistry::<T>::try_mutate(domain_id, |maybe_domain_object| {
let domain_obj = maybe_domain_object.as_mut().ok_or(Error::DomainNotFound)?;
ensure!(
domain_obj.owner_account_id == domain_owner,
Error::NotDomainOwner
);
let mut domain_obj =
Pallet::<T>::domain_registry_fallback(domain_id).ok_or(Error::DomainNotFound)?;
Comment on lines +371 to +372
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue only shortly exists in runtime API calls on the block that contains the runtime upgrade.

While do_update_domain_allow_list (and also do_register_operator) is only called during block execution, where it is either using the old runtime and before migration or the new runtime and after the migration, it should not have the issue so not needed to use domain_registry_fallback.

Though it is also no harm to use domain_registry_fallback thus non-blocker.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fine by me 👍🏼


domain_obj.domain_config.operator_allow_list = updated_operator_allow_list;
Ok(())
})
ensure!(
domain_obj.owner_account_id == domain_owner,
Error::NotDomainOwner,
);

domain_obj.domain_config.operator_allow_list = updated_operator_allow_list;
DomainRegistry::<T>::insert(domain_id, domain_obj);

Ok(())
}

#[cfg(test)]
Expand Down
47 changes: 34 additions & 13 deletions crates/pallet-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ extern crate alloc;

use crate::block_tree::{verify_execution_receipt, Error as BlockTreeError};
use crate::bundle_storage_fund::{charge_bundle_storage_fee, storage_fund_account};
use crate::domain_registry::{DomainConfig, Error as DomainRegistryError};
use crate::domain_registry::{DomainConfig, DomainObject, Error as DomainRegistryError};
use crate::migration_v2_to_v3::DomainRegistryV2;
use crate::runtime_registry::into_complete_raw_genesis;
#[cfg(feature = "runtime-benchmarks")]
pub use crate::staking::do_register_operator;
Expand Down Expand Up @@ -2145,9 +2146,28 @@ impl<T: Config> Pallet<T> {
Ok(HeadDomainNumber::<T>::get(domain_id) + missed_upgrade.into())
}

/// Fallback decoding for the domain registry v2 to v3 migration.
/// Returns the domain registry entry for the supplied `domain_id`, if that domain exists.
/// Tries the v3 storage format first, then falls back to the v2 format.
///
/// All reads that could possibly happen between the runtime upgrade and the storage migration
/// must go through this function. (Writes are ok, because any v3 writes will look "corrupt"
/// and get skipped by the migration.)
//
// TODO: remove this fallback in the next runtime upgrade after the v3 storage format,
// and just read DomainRegistry directly.
#[expect(clippy::type_complexity)]
pub fn domain_registry_fallback(
domain_id: DomainId,
) -> Option<DomainObject<BlockNumberFor<T>, ReceiptHashFor<T>, T::AccountId, BalanceOf<T>>>
{
DomainRegistry::<T>::get(domain_id)
.or_else(|| DomainRegistryV2::<T>::get(domain_id).map(Into::into))
}

/// Returns the runtime ID for the supplied `domain_id`, if that domain exists.
pub fn runtime_id(domain_id: DomainId) -> Option<RuntimeId> {
DomainRegistry::<T>::get(domain_id)
Self::domain_registry_fallback(domain_id)
.map(|domain_object| domain_object.domain_config.runtime_id)
}

Expand All @@ -2159,7 +2179,7 @@ impl<T: Config> Pallet<T> {
pub fn domain_instance_data(
domain_id: DomainId,
) -> Option<(DomainInstanceData, BlockNumberFor<T>)> {
let domain_obj = DomainRegistry::<T>::get(domain_id)?;
let domain_obj = Self::domain_registry_fallback(domain_id)?;
let runtime_object = RuntimeRegistry::<T>::get(domain_obj.domain_config.runtime_id)?;
let runtime_type = runtime_object.runtime_type;
let total_issuance = domain_obj.domain_config.total_issuance()?;
Expand Down Expand Up @@ -2198,7 +2218,7 @@ impl<T: Config> Pallet<T> {
domain_id: DomainId,
) -> Option<BundleProducerElectionParams<BalanceOf<T>>> {
match (
DomainRegistry::<T>::get(domain_id),
Self::domain_registry_fallback(domain_id),
DomainStakingSummary::<T>::get(domain_id),
) {
(Some(domain_object), Some(stake_summary)) => Some(BundleProducerElectionParams {
Expand Down Expand Up @@ -2392,17 +2412,17 @@ impl<T: Config> Pallet<T> {
BundleError::UnexpectedReceiptGap,
);

let domain_config = DomainRegistry::<T>::get(domain_id)
let domain_config = &Self::domain_registry_fallback(domain_id)
.ok_or(BundleError::InvalidDomainId)?
.domain_config;

Self::validate_bundle(opaque_bundle, &domain_config)?;
Self::validate_bundle(opaque_bundle, domain_config)?;

Self::validate_eligibility(
sealed_header.pre_hash().as_ref(),
&sealed_header.signature,
&sealed_header.header.proof_of_election,
&domain_config,
domain_config,
pre_dispatch,
)?;

Expand All @@ -2428,7 +2448,7 @@ impl<T: Config> Pallet<T> {
BundleError::ExpectingReceiptGap,
);

let domain_config = DomainRegistry::<T>::get(domain_id)
let domain_config = Self::domain_registry_fallback(domain_id)
.ok_or(BundleError::InvalidDomainId)?
.domain_config;
Self::validate_eligibility(
Expand Down Expand Up @@ -2770,7 +2790,7 @@ impl<T: Config> Pallet<T> {
pub fn domain_bundle_limit(
domain_id: DomainId,
) -> Result<Option<DomainBundleLimit>, DomainRegistryError> {
let domain_config = match DomainRegistry::<T>::get(domain_id) {
let domain_config = match Self::domain_registry_fallback(domain_id) {
None => return Ok(None),
Some(domain_obj) => domain_obj.domain_config,
};
Expand Down Expand Up @@ -3106,7 +3126,8 @@ impl<T: Config> Pallet<T> {
// If there is no `ExecutionInbox` exist for the `last_domain_block_number` it means
// there is no bundle submitted for the domain since it is instantiated, in this case,
// we use the `domain_obj.created_at` (which derive the genesis block).
.or(DomainRegistry::<T>::get(domain_id).map(|domain_obj| domain_obj.created_at))
.or(Self::domain_registry_fallback(domain_id)
.map(|domain_obj| domain_obj.created_at))
.ok_or(BlockTreeError::LastBlockNotFound)?;

Ok(DomainRuntimeUpgradeRecords::<T>::get(runtime_id)
Expand Down Expand Up @@ -3137,7 +3158,7 @@ impl<T: Config> Pallet<T> {

/// Returns true if this is an EVM domain.
pub fn is_evm_domain(domain_id: DomainId) -> bool {
if let Some(domain_obj) = DomainRegistry::<T>::get(domain_id) {
if let Some(domain_obj) = Self::domain_registry_fallback(domain_id) {
domain_obj.domain_runtime_info.is_evm_domain()
} else {
false
Expand All @@ -3146,7 +3167,7 @@ impl<T: Config> Pallet<T> {

/// Returns true if this is a private EVM domain.
pub fn is_private_evm_domain(domain_id: DomainId) -> bool {
if let Some(domain_obj) = DomainRegistry::<T>::get(domain_id) {
if let Some(domain_obj) = Self::domain_registry_fallback(domain_id) {
domain_obj.domain_runtime_info.is_private_evm_domain()
} else {
false
Expand All @@ -3163,7 +3184,7 @@ impl<T: Config> Pallet<T> {

impl<T: Config> sp_domains::DomainOwner<T::AccountId> for Pallet<T> {
fn is_domain_owner(domain_id: DomainId, acc: T::AccountId) -> bool {
if let Some(domain_obj) = DomainRegistry::<T>::get(domain_id) {
if let Some(domain_obj) = Self::domain_registry_fallback(domain_id) {
domain_obj.owner_account_id == acc
} else {
false
Expand Down
Loading
Loading