Skip to content

Commit

Permalink
Merge pull request #3329 from autonomys/fraud-proof-data-digest
Browse files Browse the repository at this point in the history
Storage proof: change BlockDigest to DomainRuntimeUpgrades
  • Loading branch information
teor2345 authored Jan 6, 2025
2 parents 7ffa30b + 4c366f5 commit 0992ef6
Show file tree
Hide file tree
Showing 12 changed files with 288 additions and 242 deletions.
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()
{
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

0 comments on commit 0992ef6

Please sign in to comment.