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

Storage proof: change BlockDigest to DomainRuntimeUpgrades #3329

Merged
merged 7 commits into from
Jan 6, 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
26 changes: 16 additions & 10 deletions crates/pallet-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ mod pallet {
#[pallet::storage]
pub(super) type AccumulatedTreasuryFunds<T> = StorageValue<_, BalanceOf<T>, ValueQuery>;

/// Storage used to keep track of which consensus block the domain runtime upgrade happen.
/// Storage used to keep track of which consensus block each domain runtime upgrade happens in.
#[pallet::storage]
pub(super) type DomainRuntimeUpgradeRecords<T: Config> = StorageMap<
_,
Expand All @@ -709,8 +709,8 @@ mod pallet {
ValueQuery,
>;

/// Temporary storage keep track of domain runtime upgrade happen in the current block, cleared
/// in the next block initialization.
/// Temporary storage to keep track of domain runtime upgrades which happened in the parent
/// block. Cleared in the current block's initialization.
#[pallet::storage]
pub type DomainRuntimeUpgrades<T> = StorageValue<_, Vec<RuntimeId>, ValueQuery>;

Expand Down Expand Up @@ -1865,8 +1865,7 @@ mod pallet {
let parent_number = block_number - One::one();
let parent_hash = frame_system::Pallet::<T>::block_hash(parent_number);

// Record any previous domain runtime upgrade in `DomainRuntimeUpgradeRecords` and then do the
// domain runtime upgrade scheduled in the current block
// Record any previous domain runtime upgrades in `DomainRuntimeUpgradeRecords`
for runtime_id in DomainRuntimeUpgrades::<T>::take() {
let reference_count = RuntimeRegistry::<T>::get(runtime_id)
.expect("Runtime object must be present since domain is insantiated; qed")
Expand All @@ -1883,9 +1882,14 @@ mod pallet {
});
}
}
// Set DomainRuntimeUpgrades to an empty list. (If there are no runtime upgrades
// scheduled in the current block, we can generate a proof the list is empty.)
DomainRuntimeUpgrades::<T>::set(Vec::new());
// Do the domain runtime upgrades scheduled in the current block, and record them in
// DomainRuntimeUpgrades
do_upgrade_runtimes::<T>(block_number);

// Store the hash of the parent consensus block for domain that have bundles submitted
// Store the hash of the parent consensus block for domains that have bundles submitted
// in that consensus block
for (domain_id, _) in SuccessfulBundles::<T>::drain() {
ConsensusBlockHash::<T>::insert(domain_id, parent_number, parent_hash);
Expand All @@ -1896,7 +1900,8 @@ mod pallet {
}

for (operator_id, slot_set) in OperatorBundleSlot::<T>::drain() {
// NOTE: `OperatorBundleSlot` use `BTreeSet` so `last` will return the maximum value in the set
// NOTE: `OperatorBundleSlot` uses `BTreeSet` so `last` will return the maximum
// value in the set
if let Some(highest_slot) = slot_set.last() {
OperatorHighestSlot::<T>::insert(operator_id, highest_slot);
}
Expand All @@ -1908,9 +1913,10 @@ mod pallet {
}

fn on_finalize(_: BlockNumberFor<T>) {
// If this consensus block will derive any domain block, gather the necessary storage for potential fraud proof usage
// If this consensus block will derive any domain block, gather the necessary storage
// for potential fraud proof usage
if SuccessfulBundles::<T>::iter_keys().count() > 0
|| DomainRuntimeUpgrades::<T>::exists()
|| !DomainRuntimeUpgrades::<T>::get().is_empty()
teor2345 marked this conversation as resolved.
Show resolved Hide resolved
{
let extrinsics_shuffling_seed = Randomness::from(
Into::<H256>::into(Self::extrinsics_shuffling_seed()).to_fixed_bytes(),
Expand Down Expand Up @@ -2910,7 +2916,7 @@ impl<T: Config> Pallet<T> {
}

// Get the domain runtime code that used to derive `receipt`, if the runtime code still present in
// the state then get it from the state otherwise from the `maybe_domain_runtime_code_at` prood.
// the state then get it from the state otherwise from the `maybe_domain_runtime_code_at` proof.
pub fn get_domain_runtime_code_for_receipt(
domain_id: DomainId,
receipt: &ExecutionReceiptOf<T>,
Expand Down
16 changes: 11 additions & 5 deletions crates/pallet-domains/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ use sp_domains::{
};
use sp_domains_fraud_proof::fraud_proof::FraudProof;
use sp_runtime::traits::{
AccountIdConversion, BlakeTwo256, BlockNumberProvider, Hash as HashT, IdentityLookup, One,
AccountIdConversion, BlakeTwo256, BlockNumberProvider, Hash as HashT, IdentityLookup, One, Zero,
};
use sp_runtime::transaction_validity::TransactionValidityError;
use sp_runtime::{BuildStorage, OpaqueExtrinsic, Saturating};
use sp_runtime::{BuildStorage, OpaqueExtrinsic};
use sp_version::RuntimeVersion;
use subspace_core_primitives::U256 as P256;
use subspace_runtime_primitives::{HoldIdentifier, Moment, StorageFee, SSC};
Expand Down Expand Up @@ -430,14 +430,20 @@ impl sp_core::traits::ReadRuntimeVersion for ReadRuntimeVersion {
}

pub(crate) fn run_to_block<T: Config>(block_number: BlockNumberFor<T>, parent_hash: T::Hash) {
// Finalize previous block
crate::Pallet::<T>::on_finalize(block_number.saturating_sub(One::one()));
// Finalize the previous block
// on_finalize() does not run on the genesis block
if block_number > One::one() {
crate::Pallet::<T>::on_finalize(block_number - One::one());
}
frame_system::Pallet::<T>::finalize();

// Initialize current block
frame_system::Pallet::<T>::set_block_number(block_number);
frame_system::Pallet::<T>::initialize(&block_number, &parent_hash, &Default::default());
crate::Pallet::<T>::on_initialize(block_number);
// on_initialize() does not run on the genesis block
if block_number > Zero::zero() {
crate::Pallet::<T>::on_initialize(block_number);
}
}

pub(crate) fn register_genesis_domain(creator: u128, operator_ids: Vec<OperatorId>) -> DomainId {
Expand Down
5 changes: 0 additions & 5 deletions crates/pallet-transaction-fees/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@

pub mod weights;

#[cfg(not(feature = "std"))]
extern crate alloc;

#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use codec::{Codec, Decode, Encode};
use frame_support::sp_runtime::traits::Zero;
use frame_support::sp_runtime::SaturatedConversion;
Expand Down
8 changes: 5 additions & 3 deletions crates/sp-domains-fraud-proof/src/fraud_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,9 +497,11 @@ pub struct InvalidExtrinsicsRootProof {
/// The combined storage proofs used during verification
pub invalid_inherent_extrinsic_proofs: InvalidInherentExtrinsicDataProof,

/// The individual storage proofs used during verification
// TODO: combine these proofs into `InvalidInherentExtrinsicDataProof`
pub invalid_inherent_extrinsic_proof: InvalidInherentExtrinsicProof,
/// Domain runtime code upgraded (or "not upgraded") storage proof
pub domain_runtime_upgraded_proof: DomainRuntimeUpgradedProof,

/// Storage proof for a change to the chains that are allowed to open a channel with each domain
pub domain_chain_allowlist_proof: DomainChainsAllowlistUpdateStorageProof,

/// Optional sudo extrinsic call storage proof
pub domain_sudo_call_proof: DomainSudoCallStorageProof,
Expand Down
150 changes: 39 additions & 111 deletions crates/sp-domains-fraud-proof/src/storage_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ use sp_domains::proof_provider_and_verifier::{
StorageProofVerifier, VerificationError as StorageProofVerificationError,
};
use sp_domains::{
DomainAllowlistUpdates, DomainId, DomainSudoCall, DomainsDigestItem, OpaqueBundle, RuntimeId,
RuntimeObject,
DomainAllowlistUpdates, DomainId, DomainSudoCall, OpaqueBundle, RuntimeId, RuntimeObject,
};
use sp_runtime::generic::Digest;
use sp_runtime::traits::{Block as BlockT, HashingFor, Header as HeaderT, NumberFor};
use sp_runtime_interface::pass_by;
use sp_runtime_interface::pass_by::PassBy;
Expand Down Expand Up @@ -40,7 +38,7 @@ pub enum VerificationError {
InvalidInherentExtrinsicStorageProof(StorageProofVerificationError),
SuccessfulBundlesStorageProof(StorageProofVerificationError),
DomainAllowlistUpdatesStorageProof(StorageProofVerificationError),
BlockDigestStorageProof(StorageProofVerificationError),
DomainRuntimeUpgradesStorageProof(StorageProofVerificationError),
RuntimeRegistryStorageProof(StorageProofVerificationError),
DigestStorageProof(StorageProofVerificationError),
BlockFeesStorageProof(StorageProofVerificationError),
Expand All @@ -55,7 +53,7 @@ pub enum FraudProofStorageKeyRequest<Number> {
InvalidInherentExtrinsicData,
SuccessfulBundles(DomainId),
DomainAllowlistUpdates(DomainId),
BlockDigest,
DomainRuntimeUpgrades,
RuntimeRegistry(RuntimeId),
DomainSudoCall(DomainId),
MmrRoot(Number),
Expand All @@ -71,7 +69,9 @@ impl<Number> FraudProofStorageKeyRequest<Number> {
Self::DomainAllowlistUpdates(_) => {
VerificationError::DomainAllowlistUpdatesStorageProof(err)
}
Self::BlockDigest => VerificationError::BlockDigestStorageProof(err),
Self::DomainRuntimeUpgrades => {
VerificationError::DomainRuntimeUpgradesStorageProof(err)
}
Self::RuntimeRegistry(_) => VerificationError::RuntimeRegistryStorageProof(err),
FraudProofStorageKeyRequest::DomainSudoCall(_) => {
VerificationError::DomainSudoCallStorageProof(err)
Expand Down Expand Up @@ -179,17 +179,6 @@ impl<Block: BlockT> BasicStorageProof<Block> for DomainChainsAllowlistUpdateStor
}
}

#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
pub struct BlockDigestProof(StorageProof);

impl_storage_proof!(BlockDigestProof);
impl<Block: BlockT> BasicStorageProof<Block> for BlockDigestProof {
type StorageValue = Digest;
fn storage_key_request(_key: Self::Key) -> FraudProofStorageKeyRequest<NumberFor<Block>> {
FraudProofStorageKeyRequest::BlockDigest
}
}

#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
pub struct DomainSudoCallStorageProof(StorageProof);

Expand All @@ -202,7 +191,18 @@ impl<Block: BlockT> BasicStorageProof<Block> for DomainSudoCallStorageProof {
}
}

// TODO: get the runtime id from pallet-domains since it won't change for a given domain
#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
pub struct DomainRuntimeUpgradesProof(StorageProof);

impl_storage_proof!(DomainRuntimeUpgradesProof);
impl<Block: BlockT> BasicStorageProof<Block> for DomainRuntimeUpgradesProof {
type StorageValue = Vec<RuntimeId>;
type Key = ();
fn storage_key_request(_key: Self::Key) -> FraudProofStorageKeyRequest<NumberFor<Block>> {
FraudProofStorageKeyRequest::DomainRuntimeUpgrades
}
}

// The domain runtime code with storage proof
//
// NOTE: usually we should use the parent consensus block hash to `generate` or `verify` the
Expand Down Expand Up @@ -287,14 +287,15 @@ where
}

#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
pub struct MaybeDomainRuntimeUpgradedProof {
pub block_digest: BlockDigestProof,
pub struct DomainRuntimeUpgradedProof {
pub domain_runtime_upgrades: DomainRuntimeUpgradesProof,
pub new_domain_runtime_code: Option<DomainRuntimeCodeProof>,
}

impl MaybeDomainRuntimeUpgradedProof {
/// Generate the `MaybeDomainRuntimeUpgradedProof`, it is the caller's responsibility to check
/// if the domain runtime is upgraded at `block_hash` if so the `maybe_runtime_id` should be `Some`.
impl DomainRuntimeUpgradedProof {
/// Generate the `DomainRuntimeUpgradedProof`.
/// It is the caller's responsibility to check if the domain runtime is upgraded at
/// `block_hash`. If it is, the `maybe_runtime_id` should be `Some`.
#[cfg(feature = "std")]
#[allow(clippy::let_and_return)]
pub fn generate<
Expand All @@ -307,8 +308,12 @@ impl MaybeDomainRuntimeUpgradedProof {
block_hash: Block::Hash,
maybe_runtime_id: Option<RuntimeId>,
) -> Result<Self, GenerationError> {
let block_digest =
BlockDigestProof::generate(proof_provider, block_hash, (), storage_key_provider)?;
let domain_runtime_upgrades = DomainRuntimeUpgradesProof::generate(
proof_provider,
block_hash,
(),
storage_key_provider,
)?;
let new_domain_runtime_code = if let Some(runtime_id) = maybe_runtime_id {
Some(DomainRuntimeCodeProof::generate(
proof_provider,
Expand All @@ -319,8 +324,8 @@ impl MaybeDomainRuntimeUpgradedProof {
} else {
None
};
Ok(MaybeDomainRuntimeUpgradedProof {
block_digest,
Ok(DomainRuntimeUpgradedProof {
domain_runtime_upgrades,
new_domain_runtime_code,
})
}
Expand All @@ -330,17 +335,13 @@ impl MaybeDomainRuntimeUpgradedProof {
runtime_id: RuntimeId,
state_root: &Block::Hash,
) -> Result<Option<Vec<u8>>, VerificationError> {
let block_digest = <BlockDigestProof as BasicStorageProof<Block>>::verify::<SKP>(
self.block_digest.clone(),
(),
state_root,
)?;

let runtime_upgraded = block_digest
.logs
.iter()
.filter_map(|log| log.as_domain_runtime_upgrade())
.any(|upgraded_runtime_id| upgraded_runtime_id == runtime_id);
let domain_runtime_upgrades =
<DomainRuntimeUpgradesProof as BasicStorageProof<Block>>::verify::<SKP>(
self.domain_runtime_upgrades.clone(),
(),
state_root,
)?;
let runtime_upgraded = domain_runtime_upgrades.contains(&runtime_id);

match (runtime_upgraded, self.new_domain_runtime_code.as_ref()) {
(true, None) | (false, Some(_)) => {
Expand Down Expand Up @@ -390,79 +391,6 @@ impl<Block: BlockT> BasicStorageProof<Block> for InvalidInherentExtrinsicDataPro
}
}

#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
pub struct InvalidInherentExtrinsicProof {
/// Optional domain runtime code upgrade storage proof
pub maybe_domain_runtime_upgrade_proof: MaybeDomainRuntimeUpgradedProof,

/// Change in the allowed chains storage proof
pub domain_chain_allowlist_proof: DomainChainsAllowlistUpdateStorageProof,
}

/// The verified data from an `InvalidInherentExtrinsicProof`
#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
pub struct InvalidInherentExtrinsicVerified {
pub maybe_domain_runtime_upgrade: Option<Vec<u8>>,
pub domain_chain_allowlist: DomainAllowlistUpdates,
}

impl InvalidInherentExtrinsicProof {
#[cfg(feature = "std")]
#[allow(clippy::let_and_return)]
pub fn generate<
Block: BlockT,
PP: ProofProvider<Block>,
SKP: FraudProofStorageKeyProviderInstance<NumberFor<Block>>,
>(
storage_key_provider: &SKP,
proof_provider: &PP,
domain_id: DomainId,
block_hash: Block::Hash,
maybe_runtime_id: Option<RuntimeId>,
) -> Result<Self, GenerationError> {
let maybe_domain_runtime_upgrade_proof = MaybeDomainRuntimeUpgradedProof::generate(
storage_key_provider,
proof_provider,
block_hash,
maybe_runtime_id,
)?;
let domain_chain_allowlist_proof = DomainChainsAllowlistUpdateStorageProof::generate(
proof_provider,
block_hash,
domain_id,
storage_key_provider,
)?;

Ok(Self {
maybe_domain_runtime_upgrade_proof,
domain_chain_allowlist_proof,
})
}

pub fn verify<Block: BlockT, SKP: FraudProofStorageKeyProvider<NumberFor<Block>>>(
&self,
domain_id: DomainId,
runtime_id: RuntimeId,
state_root: &Block::Hash,
) -> Result<InvalidInherentExtrinsicVerified, VerificationError> {
let maybe_domain_runtime_upgrade = self
.maybe_domain_runtime_upgrade_proof
.verify::<Block, SKP>(runtime_id, state_root)?;

let domain_chain_allowlist =
<DomainChainsAllowlistUpdateStorageProof as BasicStorageProof<Block>>::verify::<SKP>(
self.domain_chain_allowlist_proof.clone(),
domain_id,
state_root,
)?;

Ok(InvalidInherentExtrinsicVerified {
maybe_domain_runtime_upgrade,
domain_chain_allowlist,
})
}
}

#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
pub struct MmrRootStorageProof<MmrHash> {
storage_proof: StorageProof,
Expand Down
Loading
Loading