Skip to content

Commit

Permalink
Merge pull request #3337 from autonomys/runtime-upgrades-api
Browse files Browse the repository at this point in the history
Add runtime_upgrades() runtime API for DomainRuntimeUpgrades
  • Loading branch information
teor2345 authored Jan 8, 2025
2 parents c1d6159 + 76e29b5 commit bfa1eef
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 87 deletions.
6 changes: 6 additions & 0 deletions crates/pallet-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2102,11 +2102,17 @@ impl<T: Config> Pallet<T> {
Ok(HeadDomainNumber::<T>::get(domain_id) + missed_upgrade.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)
.map(|domain_object| domain_object.domain_config.runtime_id)
}

/// Returns the list of runtime upgrades in the current block.
pub fn runtime_upgrades() -> Vec<RuntimeId> {
DomainRuntimeUpgrades::<T>::get()
}

pub fn domain_instance_data(
domain_id: DomainId,
) -> Option<(DomainInstanceData, BlockNumberFor<T>)> {
Expand Down
4 changes: 2 additions & 2 deletions crates/sp-domains-fraud-proof/src/fraud_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,8 +497,8 @@ pub struct InvalidExtrinsicsRootProof {
/// The combined storage proofs used during verification
pub invalid_inherent_extrinsic_proofs: InvalidInherentExtrinsicDataProof,

/// Domain runtime code upgraded (or "not upgraded") storage proof
pub domain_runtime_upgraded_proof: DomainRuntimeUpgradedProof,
/// A single domain runtime code upgrade (or "not upgraded") storage proof
pub maybe_domain_runtime_upgraded_proof: MaybeDomainRuntimeUpgradedProof,

/// Storage proof for a change to the chains that are allowed to open a channel with each domain
pub domain_chain_allowlist_proof: DomainChainsAllowlistUpdateStorageProof,
Expand Down
12 changes: 8 additions & 4 deletions crates/sp-domains-fraud-proof/src/storage_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,14 +286,18 @@ where
}
}

/// A proof of a single domain runtime upgrade (or that there wasn't an upgrade).
#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
pub struct DomainRuntimeUpgradedProof {
pub struct MaybeDomainRuntimeUpgradedProof {
/// A list of domain runtime upgrades for a block.
pub domain_runtime_upgrades: DomainRuntimeUpgradesProof,

/// The new domain runtime code, if the domain runtime was upgraded.
pub new_domain_runtime_code: Option<DomainRuntimeCodeProof>,
}

impl DomainRuntimeUpgradedProof {
/// Generate the `DomainRuntimeUpgradedProof`.
impl MaybeDomainRuntimeUpgradedProof {
/// Generate the `MaybeDomainRuntimeUpgradedProof`.
/// 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")]
Expand Down Expand Up @@ -324,7 +328,7 @@ impl DomainRuntimeUpgradedProof {
} else {
None
};
Ok(DomainRuntimeUpgradedProof {
Ok(MaybeDomainRuntimeUpgradedProof {
domain_runtime_upgrades,
new_domain_runtime_code,
})
Expand Down
4 changes: 2 additions & 2 deletions crates/sp-domains-fraud-proof/src/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ where
let InvalidExtrinsicsRootProof {
valid_bundle_digests,
invalid_inherent_extrinsic_proofs,
domain_runtime_upgraded_proof,
maybe_domain_runtime_upgraded_proof,
domain_chain_allowlist_proof,
domain_sudo_call_proof,
} = fraud_proof;
Expand All @@ -79,7 +79,7 @@ where
)?;

let maybe_domain_runtime_upgrade =
domain_runtime_upgraded_proof.verify::<CBlock, SKP>(runtime_id, &state_root)?;
maybe_domain_runtime_upgraded_proof.verify::<CBlock, SKP>(runtime_id, &state_root)?;

let domain_chain_allowlist = <DomainChainsAllowlistUpdateStorageProof as BasicStorageProof<
CBlock,
Expand Down
55 changes: 27 additions & 28 deletions crates/sp-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1448,14 +1448,6 @@ pub fn system_digest_final_key() -> Vec<u8> {
frame_support::storage::storage_prefix("System".as_ref(), "Digest".as_ref()).to_vec()
}

// TODO: This is used to keep compatible with gemini-3h, remove before next network
/// This is a representation of actual Block Fees storage in pallet-block-fees.
/// Any change in key or value there should be changed here accordingly.
pub fn operator_block_fees_final_key() -> Vec<u8> {
frame_support::storage::storage_prefix("BlockFees".as_ref(), "CollectedBlockFees".as_ref())
.to_vec()
}

/// Hook to handle chain rewards.
pub trait OnChainRewards<Balance> {
fn on_chain_rewards(chain_id: ChainId, reward: Balance);
Expand All @@ -1476,15 +1468,18 @@ pub enum OperatorRewardSource<Number> {
}

sp_api::decl_runtime_apis! {
/// API necessary for domains pallet.
/// APIs used to access the domains pallet.
// When updating this version, document new APIs with "Only present in API versions" comments.
// TODO: when removing this version, also remove "Only present in API versions" comments.
#[api_version(2)]
pub trait DomainsApi<DomainHeader: HeaderT> {
/// Submits the transaction bundle via an unsigned extrinsic.
fn submit_bundle_unsigned(opaque_bundle: OpaqueBundle<NumberFor<Block>, Block::Hash, DomainHeader, Balance>);

// Submit singleton receipt via an unsigned extrinsic.
// Submits a singleton receipt via an unsigned extrinsic.
fn submit_receipt_unsigned(singleton_receipt: SealedSingletonReceipt<NumberFor<Block>, Block::Hash, DomainHeader, Balance>);

/// Extract the bundles stored successfully from the given extrinsics.
/// Extracts the bundles successfully stored from the given extrinsics.
fn extract_successful_bundles(
domain_id: DomainId,
extrinsics: Vec<Block::Extrinsic>,
Expand All @@ -1493,22 +1488,26 @@ sp_api::decl_runtime_apis! {
/// Generates a randomness seed for extrinsics shuffling.
fn extrinsics_shuffling_seed() -> Randomness;

/// Returns the WASM bundle for given `domain_id`.
/// Returns the current WASM bundle for the given `domain_id`.
fn domain_runtime_code(domain_id: DomainId) -> Option<Vec<u8>>;

/// Returns the runtime id for given `domain_id`.
/// Returns the runtime id for the given `domain_id`.
fn runtime_id(domain_id: DomainId) -> Option<RuntimeId>;

/// Returns the domain instance data for given `domain_id`.
/// Returns the list of runtime upgrades in the current block.
/// Only present in API versions 2 and later.
fn runtime_upgrades() -> Vec<RuntimeId>;

/// Returns the domain instance data for the given `domain_id`.
fn domain_instance_data(domain_id: DomainId) -> Option<(DomainInstanceData, NumberFor<Block>)>;

/// Returns the current timestamp at given height.
/// Returns the current timestamp at the current height.
fn timestamp() -> Moment;

/// Returns the current Tx range for the given domain Id.
fn domain_tx_range(domain_id: DomainId) -> U256;

/// Return the genesis state root if not pruned
/// Returns the genesis state root if not pruned.
fn genesis_state_root(domain_id: DomainId) -> Option<H256>;

/// Returns the best execution chain number.
Expand All @@ -1523,38 +1522,38 @@ sp_api::decl_runtime_apis! {
/// Returns true if there are any ERs in the challenge period with non empty extrinsics.
fn non_empty_er_exists(domain_id: DomainId) -> bool;

/// Returns the current best number of the domain.
/// Returns the current best block number for the domain.
fn domain_best_number(domain_id: DomainId) -> Option<HeaderNumberFor<DomainHeader>>;

/// Returns the execution receipt
/// Returns the execution receipt with the given hash.
fn execution_receipt(receipt_hash: HeaderHashFor<DomainHeader>) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;

/// Returns the current epoch and the next epoch operators of the given domain
/// Returns the current epoch and the next epoch operators of the given domain.
fn domain_operators(domain_id: DomainId) -> Option<(BTreeMap<OperatorId, Balance>, Vec<OperatorId>)>;

/// Returns the execution receipt hash of the given domain and domain block number
/// Returns the execution receipt hash of the given domain and domain block number.
fn receipt_hash(domain_id: DomainId, domain_number: HeaderNumberFor<DomainHeader>) -> Option<HeaderHashFor<DomainHeader>>;

/// Return the consensus chain byte fee that will used to charge the domain transaction for consensus
/// chain storage fee
/// Returns the consensus chain byte fee that will used to charge the domain transaction for consensus
/// chain storage fees.
fn consensus_chain_byte_fee() -> Balance;

/// Returns the latest confirmed domain block number and hash
/// Returns the latest confirmed domain block number and hash.
fn latest_confirmed_domain_block(domain_id: DomainId) -> Option<(HeaderNumberFor<DomainHeader>, HeaderHashFor<DomainHeader>)>;

/// Return if the receipt is exist and pending to prune
/// Returns if the receipt is exist and pending to prune
fn is_bad_er_pending_to_prune(domain_id: DomainId, receipt_hash: HeaderHashFor<DomainHeader>) -> bool;

/// Return the balance of the storage fund account
/// Returns the balance of the storage fund account.
fn storage_fund_account_balance(operator_id: OperatorId) -> Balance;

/// Return if the domain runtime code is upgraded since `at`
/// Returns true if the given domain's runtime code has been upgraded since `at`.
fn is_domain_runtime_upgraded_since(domain_id: DomainId, at: NumberFor<Block>) -> Option<bool>;

/// Return domain sudo call.
/// Returns the domain sudo calls for the given domain, if any.
fn domain_sudo_call(domain_id: DomainId) -> Option<Vec<u8>>;

/// Return last confirmed domain block execution receipt.
/// Returns the last confirmed domain block execution receipt.
fn last_confirmed_domain_block_receipt(domain_id: DomainId) ->Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
}

Expand Down
4 changes: 4 additions & 0 deletions crates/subspace-fake-runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,10 @@ sp_api::impl_runtime_apis! {
unreachable!()
}

fn runtime_upgrades() -> Vec<sp_domains::RuntimeId> {
unreachable!()
}

fn domain_instance_data(_domain_id: DomainId) -> Option<(DomainInstanceData, NumberFor<Block>)> {
unreachable!()
}
Expand Down
4 changes: 4 additions & 0 deletions crates/subspace-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,10 @@ impl_runtime_apis! {
Domains::runtime_id(domain_id)
}

fn runtime_upgrades() -> Vec<sp_domains::RuntimeId> {
Domains::runtime_upgrades()
}

fn domain_instance_data(domain_id: DomainId) -> Option<(DomainInstanceData, NumberFor<Block>)> {
Domains::domain_instance_data(domain_id)
}
Expand Down
65 changes: 31 additions & 34 deletions domains/client/block-preprocessor/src/inherents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//! Deriving these extrinsics during fraud proof verification should be possible since
//! verification environment will have access to consensus chain.
use sp_api::ProvideRuntimeApi;
use sp_api::{ApiExt, ProvideRuntimeApi};
use sp_blockchain::HeaderBackend;
use sp_domains::{DomainId, DomainsApi, DomainsDigestItem};
use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider};
Expand Down Expand Up @@ -69,25 +69,40 @@ where
CBlock: BlockT,
Block: BlockT,
{
let header = consensus_client.header(consensus_block_hash)?.ok_or(
sp_blockchain::Error::MissingHeader(format!(
"No header found for {consensus_block_hash:?}"
)),
)?;

let runtime_api = consensus_client.runtime_api();

let runtime_id = runtime_api
.runtime_id(consensus_block_hash, domain_id)?
.ok_or(sp_blockchain::Error::Application(Box::from(format!(
"No RuntimeId found for {domain_id:?}"
))))?;

Ok(header
.digest()
.logs
.iter()
.filter_map(|log| log.as_domain_runtime_upgrade())
.any(|upgraded_runtime_id| upgraded_runtime_id == runtime_id))
// The runtime_upgrades() API is only present in API versions 2 and later. On earlier versions,
// we need to call legacy code.
// TODO: remove version check before next network
let domains_api_version = runtime_api
.api_version::<dyn DomainsApi<CBlock, CBlock::Header>>(consensus_block_hash)?
// It is safe to return a default version of 1, since there will always be version 1.
.unwrap_or(1);

let is_upgraded = if domains_api_version >= 2 {
let runtime_upgrades = runtime_api.runtime_upgrades(consensus_block_hash)?;
runtime_upgrades.contains(&runtime_id)
} else {
let header = consensus_client.header(consensus_block_hash)?.ok_or(
sp_blockchain::Error::MissingHeader(format!(
"No header found for {consensus_block_hash:?}"
)),
)?;
header
.digest()
.logs
.iter()
.filter_map(|log| log.as_domain_runtime_upgrade())
.any(|upgraded_runtime_id| upgraded_runtime_id == runtime_id)
};

Ok(is_upgraded)
}

/// Returns new upgraded runtime if upgraded did happen in the provided consensus block.
Expand All @@ -102,27 +117,9 @@ where
CBlock: BlockT,
Block: BlockT,
{
let header = consensus_client.header(consensus_block_hash)?.ok_or(
sp_blockchain::Error::MissingHeader(format!(
"No header found for {consensus_block_hash:?}"
)),
)?;

let runtime_api = consensus_client.runtime_api();
let runtime_id = runtime_api
.runtime_id(consensus_block_hash, domain_id)?
.ok_or(sp_blockchain::Error::Application(Box::from(format!(
"No RuntimeId found for {domain_id:?}"
))))?;

if header
.digest()
.logs
.iter()
.filter_map(|log| log.as_domain_runtime_upgrade())
.any(|upgraded_runtime_id| upgraded_runtime_id == runtime_id)
{
let new_domain_runtime = runtime_api
if is_runtime_upgraded::<_, _, Block>(consensus_client, consensus_block_hash, domain_id)? {
let new_domain_runtime = consensus_client
.runtime_api()
.domain_runtime_code(consensus_block_hash, domain_id)?
.ok_or_else(|| {
sp_blockchain::Error::Application(Box::from(format!(
Expand Down
26 changes: 9 additions & 17 deletions domains/client/domain-operator/src/fraud_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ use sp_domain_digests::AsPredigest;
use sp_domains::core_api::DomainCoreApi;
use sp_domains::proof_provider_and_verifier::StorageProofProvider;
use sp_domains::{
DomainId, DomainsApi, DomainsDigestItem, ExtrinsicDigest, HeaderHashingFor, InvalidBundleType,
RuntimeId,
DomainId, DomainsApi, ExtrinsicDigest, HeaderHashingFor, InvalidBundleType, RuntimeId,
};
use sp_domains_fraud_proof::execution_prover::ExecutionProver;
use sp_domains_fraud_proof::fraud_proof::{
Expand Down Expand Up @@ -389,7 +388,7 @@ where
&self.storage_key_provider,
)?;

let domain_runtime_upgraded_proof = DomainRuntimeUpgradedProof::generate(
let maybe_domain_runtime_upgraded_proof = MaybeDomainRuntimeUpgradedProof::generate(
&self.storage_key_provider,
self.consensus_client.as_ref(),
consensus_block_hash,
Expand Down Expand Up @@ -418,7 +417,7 @@ where
proof: FraudProofVariant::InvalidExtrinsicsRoot(InvalidExtrinsicsRootProof {
valid_bundle_digests,
invalid_inherent_extrinsic_proofs,
domain_runtime_upgraded_proof,
maybe_domain_runtime_upgraded_proof,
domain_chain_allowlist_proof,
domain_sudo_call_proof,
}),
Expand All @@ -432,27 +431,20 @@ where
domain_id: DomainId,
at: CBlock::Hash,
) -> Result<Option<RuntimeId>, FraudProofError> {
let header =
self.consensus_client
.header(at)?
.ok_or(sp_blockchain::Error::MissingHeader(format!(
"No header found for {at:?}"
)))?;

let runtime_id = self
.consensus_client
.runtime_api()
.runtime_id(at, domain_id)?
.ok_or(sp_blockchain::Error::Application(Box::from(format!(
"No RuntimeId found for {domain_id:?}"
))))?;
// This API is only present in API versions 2 and later, but it is safe to call
// unconditionally, because:
// - on Mainnet, there are no domains yet, and
// - on Taurus, there are no invalid execution receipts yet.
let runtime_upgrades = self.consensus_client.runtime_api().runtime_upgrades(at)?;

let is_runtime_upgraded = header
.digest()
.logs
.iter()
.filter_map(|log| log.as_domain_runtime_upgrade())
.any(|upgraded_runtime_id| upgraded_runtime_id == runtime_id);
let is_runtime_upgraded = runtime_upgrades.contains(&runtime_id);

Ok(is_runtime_upgraded.then_some(runtime_id))
}
Expand Down
4 changes: 4 additions & 0 deletions test/subspace-test-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1318,6 +1318,10 @@ impl_runtime_apis! {
Domains::runtime_id(domain_id)
}

fn runtime_upgrades() -> Vec<sp_domains::RuntimeId> {
Domains::runtime_upgrades()
}

fn domain_instance_data(domain_id: DomainId) -> Option<(DomainInstanceData, NumberFor<Block>)> {
Domains::domain_instance_data(domain_id)
}
Expand Down

0 comments on commit bfa1eef

Please sign in to comment.