Skip to content

Commit

Permalink
Merge pull request #2891 from subspace/XDM-FP
Browse files Browse the repository at this point in the history
Re-introduce the invalid XDM fraud proof
  • Loading branch information
NingLin-P authored Jul 10, 2024
2 parents 875ea99 + f165ffd commit ac21065
Show file tree
Hide file tree
Showing 44 changed files with 1,472 additions and 345 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion crates/pallet-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ mod pallet {
>;

/// Fraud proof storage key provider
type FraudProofStorageKeyProvider: FraudProofStorageKeyProvider;
type FraudProofStorageKeyProvider: FraudProofStorageKeyProvider<BlockNumberFor<Self>>;

/// Hook to handle chain rewards.
type OnChainRewards: OnChainRewards<BalanceOf<Self>>;
Expand Down Expand Up @@ -2207,8 +2207,10 @@ impl<T: Config> Pallet<T> {
verify_invalid_bundles_fraud_proof::<
T::Block,
T::DomainHeader,
T::MmrHash,
BalanceOf<T>,
T::FraudProofStorageKeyProvider,
T::MmrProofVerifier,
>(
bad_receipt,
bad_receipt_parent,
Expand Down
19 changes: 14 additions & 5 deletions crates/sc-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,20 @@ pub type RuntimeExecutor = sc_executor::WasmExecutor<HostFunctions>;
pub struct ExtensionsFactory<CClient, CBlock, Block, Executor> {
consensus_client: Arc<CClient>,
executor: Arc<Executor>,
confirmation_depth_k: u32,
_marker: PhantomData<(CBlock, Block)>,
}

impl<CClient, CBlock, Block, Executor> ExtensionsFactory<CClient, CBlock, Block, Executor> {
pub fn new(consensus_client: Arc<CClient>, executor: Arc<Executor>) -> Self {
pub fn new(
consensus_client: Arc<CClient>,
executor: Arc<Executor>,
confirmation_depth_k: u32,
) -> Self {
Self {
consensus_client,
executor,
confirmation_depth_k,
_marker: Default::default(),
}
}
Expand All @@ -82,7 +88,7 @@ where
CBlock::Hash: From<H256> + Into<H256>,
CClient: HeaderBackend<CBlock> + ProvideRuntimeApi<CBlock> + 'static,
CClient::Api: MmrApi<CBlock, H256, NumberFor<CBlock>>
+ MessengerApi<CBlock>
+ MessengerApi<CBlock, NumberFor<CBlock>, CBlock::Hash>
+ DomainsApi<CBlock, Block::Header>,
Executor: CodeExecutor + RuntimeVersionOf,
{
Expand All @@ -93,7 +99,10 @@ where
) -> Extensions {
let mut exts = Extensions::new();
exts.register(SubspaceMmrExtension::new(Arc::new(
SubspaceMmrHostFunctionsImpl::<CBlock, _>::new(self.consensus_client.clone()),
SubspaceMmrHostFunctionsImpl::<CBlock, _>::new(
self.consensus_client.clone(),
self.confirmation_depth_k,
),
)));

exts.register(MessengerExtension::new(Arc::new(
Expand Down Expand Up @@ -134,15 +143,15 @@ impl<CBlock, DomainHeader, CClient> FPStorageKeyProvider<CBlock, DomainHeader, C
}
}

impl<CBlock, DomainHeader, CClient> FraudProofStorageKeyProviderInstance
impl<CBlock, DomainHeader, CClient> FraudProofStorageKeyProviderInstance<NumberFor<CBlock>>
for FPStorageKeyProvider<CBlock, DomainHeader, CClient>
where
CBlock: BlockT,
DomainHeader: HeaderT,
CClient: HeaderBackend<CBlock> + ProvideRuntimeApi<CBlock> + 'static,
CClient::Api: FraudProofApi<CBlock, DomainHeader>,
{
fn storage_key(&self, req: FraudProofStorageKeyRequest) -> Option<Vec<u8>> {
fn storage_key(&self, req: FraudProofStorageKeyRequest<NumberFor<CBlock>>) -> Option<Vec<u8>> {
let best_hash = self.consensus_client.info().best_hash;
self.consensus_client
.runtime_api()
Expand Down
26 changes: 20 additions & 6 deletions crates/sp-domains-fraud-proof/src/fraud_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,10 @@ pub enum VerificationError<DomainHash> {
/// Failed to get bundle weight
#[cfg_attr(feature = "thiserror", error("Failed to get bundle weight"))]
FailedToGetBundleWeight,
#[cfg_attr(feature = "thiserror", error("Failed to extract xdm mmr proof"))]
FailedToGetExtractXdmMmrProof,
#[cfg_attr(feature = "thiserror", error("Failed to decode xdm mmr proof"))]
FailedToDecodeXdmMmrProof,
}

impl<DomainHash> From<storage_proof::VerificationError> for VerificationError<DomainHash> {
Expand All @@ -362,16 +366,16 @@ pub struct FraudProof<Number, Hash, DomainHeader: HeaderT, MmrHash> {
/// or the required domain runtime code is available from the current runtime state.
pub maybe_domain_runtime_code_proof: Option<DomainRuntimeCodeAt<Number, Hash, MmrHash>>,
/// The specific fraud proof variant
pub proof: FraudProofVariant<Number, Hash, DomainHeader>,
pub proof: FraudProofVariant<Number, Hash, MmrHash, DomainHeader>,
}

#[allow(clippy::large_enum_variant)]
#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
pub enum FraudProofVariant<Number, Hash, DomainHeader: HeaderT> {
pub enum FraudProofVariant<Number, Hash, MmrHash, DomainHeader: HeaderT> {
InvalidStateTransition(InvalidStateTransitionProof),
ValidBundle(ValidBundleProof<Number, Hash, DomainHeader>),
InvalidExtrinsicsRoot(InvalidExtrinsicsRootProof),
InvalidBundles(InvalidBundlesProof<Number, Hash, DomainHeader>),
InvalidBundles(InvalidBundlesProof<Number, Hash, MmrHash, DomainHeader>),
InvalidDomainBlockHash(InvalidDomainBlockHashProof),
InvalidBlockFees(InvalidBlockFeesProof),
InvalidTransfers(InvalidTransfersProof),
Expand Down Expand Up @@ -526,23 +530,33 @@ pub struct InvalidExtrinsicsRootProof {
pub domain_inherent_extrinsic_data_proof: DomainInherentExtrinsicDataProof,
}

#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
pub struct MmrRootProof<Number, Hash, MmrHash> {
pub mmr_proof: ConsensusChainMmrLeafProof<Number, Hash, MmrHash>,
pub mmr_root_storage_proof: MmrRootStorageProof<MmrHash>,
}

#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
pub enum InvalidBundlesProofData<Number, Hash, DomainHeader: HeaderT> {
pub enum InvalidBundlesProofData<Number, Hash, MmrHash, DomainHeader: HeaderT> {
Extrinsic(StorageProof),
Bundle(OpaqueBundleWithProof<Number, Hash, DomainHeader, Balance>),
BundleAndExecution {
bundle_with_proof: OpaqueBundleWithProof<Number, Hash, DomainHeader, Balance>,
execution_proof: StorageProof,
},
InvalidXDMProofData {
extrinsic_proof: StorageProof,
mmr_root_proof: Option<MmrRootProof<Number, Hash, MmrHash>>,
},
}

#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
pub struct InvalidBundlesProof<Number, Hash, DomainHeader: HeaderT> {
pub struct InvalidBundlesProof<Number, Hash, MmrHash, DomainHeader: HeaderT> {
pub bundle_index: u32,
pub invalid_bundle_type: InvalidBundleType,
pub is_true_invalid_fraud_proof: bool,
/// Proof data of the invalid bundle
pub proof_data: InvalidBundlesProofData<Number, Hash, DomainHeader>,
pub proof_data: InvalidBundlesProofData<Number, Hash, MmrHash, DomainHeader>,
}

/// Represents an invalid block fees proof.
Expand Down
52 changes: 38 additions & 14 deletions crates/sp-domains-fraud-proof/src/host_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ pub trait FraudProofHostFunctions: Send + Sync {
domain_runtime_code: Vec<u8>,
bundle_body: Vec<OpaqueExtrinsic>,
) -> Option<Weight>;

fn extract_xdm_mmr_proof(
&self,
domain_runtime_code: Vec<u8>,
opaque_extrinsic: Vec<u8>,
) -> Option<Option<Vec<u8>>>;
}

sp_externalities::decl_extension! {
Expand Down Expand Up @@ -165,7 +171,7 @@ where
Client: BlockBackend<Block> + HeaderBackend<Block> + ProvideRuntimeApi<Block>,
Client::Api: DomainsApi<Block, DomainBlock::Header>
+ BundleProducerElectionApi<Block, Balance>
+ MessengerApi<Block>,
+ MessengerApi<Block, NumberFor<Block>, Block::Hash>,
Executor: CodeExecutor + RuntimeVersionOf,
EFC: Fn(Arc<Client>, Arc<Executor>) -> Box<dyn ExtensionsFactory<DomainBlock>> + Send + Sync,
{
Expand All @@ -186,7 +192,7 @@ where
let runtime_code = self.get_domain_runtime_code(consensus_block_hash, domain_id)?;
let timestamp = runtime_api.timestamp(consensus_block_hash.into()).ok()?;

let domain_stateless_runtime = StatelessRuntime::<DomainBlock, _>::new(
let domain_stateless_runtime = StatelessRuntime::<Block, DomainBlock, _>::new(
self.domain_executor.clone(),
runtime_code.into(),
);
Expand All @@ -208,7 +214,7 @@ where
.domain_chains_allowlist_update(consensus_block_hash.into(), domain_id)
.ok()??;

let domain_stateless_runtime = StatelessRuntime::<DomainBlock, _>::new(
let domain_stateless_runtime = StatelessRuntime::<Block, DomainBlock, _>::new(
self.domain_executor.clone(),
runtime_code.into(),
);
Expand All @@ -230,7 +236,7 @@ where
.ok()?;

let runtime_code = self.get_domain_runtime_code(consensus_block_hash, domain_id)?;
let domain_stateless_runtime = StatelessRuntime::<DomainBlock, _>::new(
let domain_stateless_runtime = StatelessRuntime::<Block, DomainBlock, _>::new(
self.domain_executor.clone(),
runtime_code.into(),
);
Expand Down Expand Up @@ -280,7 +286,7 @@ where

if let Some(upgraded_runtime) = maybe_upgraded_runtime {
let runtime_code = self.get_domain_runtime_code(consensus_block_hash, domain_id)?;
let domain_stateless_runtime = StatelessRuntime::<DomainBlock, _>::new(
let domain_stateless_runtime = StatelessRuntime::<Block, DomainBlock, _>::new(
self.domain_executor.clone(),
runtime_code.into(),
);
Expand Down Expand Up @@ -371,7 +377,7 @@ where
opaque_extrinsic: OpaqueExtrinsic,
) -> Option<bool> {
let runtime_code = self.get_domain_runtime_code(consensus_block_hash, domain_id)?;
let mut domain_stateless_runtime = StatelessRuntime::<DomainBlock, _>::new(
let mut domain_stateless_runtime = StatelessRuntime::<Block, DomainBlock, _>::new(
self.domain_executor.clone(),
runtime_code.into(),
);
Expand All @@ -391,8 +397,10 @@ where
domain_stateless_runtime.set_storage(domain_initial_state);

let encoded_extrinsic = opaque_extrinsic.encode();
let extrinsic =
<DomainBlock as BlockT>::Extrinsic::decode(&mut encoded_extrinsic.as_slice()).ok()?;
domain_stateless_runtime
.is_valid_xdm(encoded_extrinsic)
.is_xdm_mmr_proof_valid(&extrinsic)
.expect("Runtime api must not fail. This is an unrecoverable error")
}

Expand All @@ -416,7 +424,7 @@ where
req: StorageKeyRequest,
) -> Option<Vec<u8>> {
let runtime_code = self.get_domain_runtime_code(consensus_block_hash, domain_id)?;
let domain_stateless_runtime = StatelessRuntime::<DomainBlock, _>::new(
let domain_stateless_runtime = StatelessRuntime::<Block, DomainBlock, _>::new(
self.domain_executor.clone(),
runtime_code.into(),
);
Expand Down Expand Up @@ -485,7 +493,7 @@ where
Client: BlockBackend<Block> + HeaderBackend<Block> + ProvideRuntimeApi<Block>,
Client::Api: DomainsApi<Block, DomainBlock::Header>
+ BundleProducerElectionApi<Block, Balance>
+ MessengerApi<Block>,
+ MessengerApi<Block, NumberFor<Block>, Block::Hash>,
Executor: CodeExecutor + RuntimeVersionOf,
EFC: Fn(Arc<Client>, Arc<Executor>) -> Box<dyn ExtensionsFactory<DomainBlock>> + Send + Sync,
{
Expand Down Expand Up @@ -644,7 +652,7 @@ where
extrinsics.push(ext);
}

let domain_stateless_runtime = StatelessRuntime::<DomainBlock, _>::new(
let domain_stateless_runtime = StatelessRuntime::<Block, DomainBlock, _>::new(
self.domain_executor.clone(),
domain_runtime_code.into(),
);
Expand Down Expand Up @@ -746,7 +754,7 @@ where
maybe_sudo_runtime_call,
} = domain_inherent_extrinsic_data;

let domain_stateless_runtime = StatelessRuntime::<DomainBlock, _>::new(
let domain_stateless_runtime = StatelessRuntime::<Block, DomainBlock, _>::new(
self.domain_executor.clone(),
domain_runtime_code.into(),
);
Expand Down Expand Up @@ -806,7 +814,7 @@ where
domain_runtime_code: Vec<u8>,
req: DomainStorageKeyRequest,
) -> Option<Vec<u8>> {
let domain_stateless_runtime = StatelessRuntime::<DomainBlock, _>::new(
let domain_stateless_runtime = StatelessRuntime::<Block, DomainBlock, _>::new(
self.domain_executor.clone(),
domain_runtime_code.into(),
);
Expand All @@ -823,7 +831,7 @@ where
domain_runtime_code: Vec<u8>,
call: StatelessDomainRuntimeCall,
) -> Option<bool> {
let domain_stateless_runtime = StatelessRuntime::<DomainBlock, _>::new(
let domain_stateless_runtime = StatelessRuntime::<Block, DomainBlock, _>::new(
self.domain_executor.clone(),
domain_runtime_code.into(),
);
Expand Down Expand Up @@ -868,7 +876,7 @@ where
domain_runtime_code: Vec<u8>,
bundle_body: Vec<OpaqueExtrinsic>,
) -> Option<Weight> {
let domain_stateless_runtime = StatelessRuntime::<DomainBlock, _>::new(
let domain_stateless_runtime = StatelessRuntime::<Block, DomainBlock, _>::new(
self.domain_executor.clone(),
domain_runtime_code.into(),
);
Expand All @@ -883,6 +891,22 @@ where
}
Some(estimated_bundle_weight)
}

fn extract_xdm_mmr_proof(
&self,
domain_runtime_code: Vec<u8>,
opaque_extrinsic: Vec<u8>,
) -> Option<Option<Vec<u8>>> {
let domain_stateless_runtime = StatelessRuntime::<Block, DomainBlock, _>::new(
self.domain_executor.clone(),
domain_runtime_code.into(),
);
let extrinsic =
<DomainBlock as BlockT>::Extrinsic::decode(&mut opaque_extrinsic.as_slice()).ok()?;
domain_stateless_runtime
.extract_xdm_mmr_proof(&extrinsic)
.ok()
}
}

type CreateProofCheckBackedResult<H> = Result<
Expand Down
2 changes: 1 addition & 1 deletion crates/sp-domains-fraud-proof/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,6 @@ sp_api::decl_runtime_apis! {
fn submit_fraud_proof_unsigned(fraud_proof: FraudProof<NumberFor<Block>, Block::Hash, DomainHeader, H256>);

/// Reture the storage key used in fraud proof
fn fraud_proof_storage_key(req: FraudProofStorageKeyRequest) -> Vec<u8>;
fn fraud_proof_storage_key(req: FraudProofStorageKeyRequest<NumberFor<Block>>) -> Vec<u8>;
}
}
11 changes: 11 additions & 0 deletions crates/sp-domains-fraud-proof/src/runtime_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,15 @@ pub trait FraudProofRuntimeInterface {
.expect("No `FraudProofExtension` associated for the current context!")
.bundle_weight(domain_runtime_code, bundle_body)
}

#[version(1)]
fn extract_xdm_mmr_proof(
&mut self,
domain_runtime_code: Vec<u8>,
opaque_extrinsic: Vec<u8>,
) -> Option<Option<Vec<u8>>> {
self.extension::<FraudProofExtension>()
.expect("No `FraudProofExtension` associated for the current context!")
.extract_xdm_mmr_proof(domain_runtime_code, opaque_extrinsic)
}
}
Loading

0 comments on commit ac21065

Please sign in to comment.