Skip to content

Commit

Permalink
Merge pull request #2169 from subspace/enable-fraud-proof-test
Browse files Browse the repository at this point in the history
Enable fraud proof tests
  • Loading branch information
NingLin-P authored Nov 7, 2023
2 parents 1358519 + e22fa0c commit 9422744
Show file tree
Hide file tree
Showing 26 changed files with 565 additions and 737 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

13 changes: 13 additions & 0 deletions crates/pallet-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,11 @@ mod pallet {
#[pallet::storage]
pub(super) type SuccessfulBundles<T> = StorageMap<_, Identity, DomainId, Vec<H256>, ValueQuery>;

/// Fraud proofs submitted successfully in current block.
#[pallet::storage]
pub(super) type SuccessfulFraudProofs<T: Config> =
StorageMap<_, Identity, DomainId, Vec<T::DomainHash>, ValueQuery>;

/// Stores the next runtime id.
#[pallet::storage]
pub(super) type NextRuntimeId<T> = StorageValue<_, RuntimeId, ValueQuery>;
Expand Down Expand Up @@ -933,6 +938,8 @@ mod pallet {
// Slash operator who have submitted the pruned fraudulent ER
do_slash_operators::<T, _>(operator_to_slash.into_iter()).map_err(Error::<T>::from)?;

SuccessfulFraudProofs::<T>::append(domain_id, fraud_proof.hash());

Self::deposit_event(Event::FraudProofProcessed {
domain_id,
new_head_receipt_number,
Expand Down Expand Up @@ -1231,6 +1238,8 @@ mod pallet {
ConsensusBlockHash::<T>::insert(domain_id, parent_number, parent_hash);
}

let _ = SuccessfulFraudProofs::<T>::clear(u32::MAX, None);

Weight::zero()
}

Expand Down Expand Up @@ -1312,6 +1321,10 @@ impl<T: Config> Pallet<T> {
SuccessfulBundles::<T>::get(domain_id)
}

pub fn successful_fraud_proofs(domain_id: DomainId) -> Vec<T::DomainHash> {
SuccessfulFraudProofs::<T>::get(domain_id)
}

pub fn domain_runtime_code(domain_id: DomainId) -> Option<Vec<u8>> {
RuntimeRegistry::<T>::get(Self::runtime_id(domain_id)?)
.and_then(|mut runtime_object| runtime_object.raw_genesis.take_runtime_code())
Expand Down
10 changes: 5 additions & 5 deletions crates/pallet-domains/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ use sp_domains::merkle_tree::MerkleTree;
use sp_domains::proof_provider_and_verifier::StorageProofProvider;
use sp_domains::storage::RawGenesis;
use sp_domains::{
BundleHeader, DomainId, DomainsHoldIdentifier, ExecutionReceipt, InboxedBundle,
InvalidBundleType, OpaqueBundle, OperatorAllowList, OperatorId, OperatorPair, ProofOfElection,
RuntimeType, SealedBundleHeader, StakingHoldIdentifier,
BundleHeader, DomainId, DomainsHoldIdentifier, ExecutionReceipt, ExtrinsicDigest,
InboxedBundle, InvalidBundleType, OpaqueBundle, OperatorAllowList, OperatorId, OperatorPair,
ProofOfElection, RuntimeType, SealedBundleHeader, StakingHoldIdentifier,
};
use sp_domains_fraud_proof::fraud_proof::{
ExtrinsicDigest, FraudProof, InvalidBundlesFraudProof, InvalidDomainBlockHashProof,
InvalidExtrinsicsRootProof, InvalidTotalRewardsProof, ValidBundleDigest,
FraudProof, InvalidBundlesFraudProof, InvalidDomainBlockHashProof, InvalidExtrinsicsRootProof,
InvalidTotalRewardsProof, ValidBundleDigest,
};
use sp_domains_fraud_proof::{
FraudProofExtension, FraudProofHostFunctions, FraudProofVerificationInfoRequest,
Expand Down
52 changes: 11 additions & 41 deletions crates/sp-domains-fraud-proof/src/fraud_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,14 @@ use sp_core::H256;
use sp_domain_digests::AsPredigest;
use sp_domains::proof_provider_and_verifier::StorageProofVerifier;
use sp_domains::{
BundleValidity, DomainId, ExecutionReceipt, HeaderHashFor, HeaderHashingFor, InvalidBundleType,
SealedBundleHeader,
BundleValidity, DomainId, ExecutionReceiptFor, ExtrinsicDigest, HeaderHashFor,
HeaderHashingFor, InvalidBundleType, SealedBundleHeader,
};
use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, NumberFor};
use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT};
use sp_runtime::{Digest, DigestItem};
use sp_std::vec::Vec;
use sp_trie::StorageProof;
use subspace_runtime_primitives::{AccountId, Balance};
use trie_db::TrieLayout;

type ExecutionReceiptFor<DomainHeader, CBlock, Balance> = ExecutionReceipt<
NumberFor<CBlock>,
<CBlock as BlockT>::Hash,
<DomainHeader as HeaderT>::Number,
<DomainHeader as HeaderT>::Hash,
Balance,
>;

/// A phase of a block's execution, carrying necessary information needed for verifying the
/// invalid state transition proof.
Expand Down Expand Up @@ -155,9 +146,12 @@ impl ExecutionPhase {
mismatch_index,
extrinsic,
} => {
// There is a trace root of the `initialize_block` in the head of the trace so we
// need to minus one to get the correct `extrinsic_index`
let extrinsic_index = *mismatch_index - 1;
let storage_key =
StorageProofVerifier::<DomainHeader::Hashing>::enumerated_storage_key(
*mismatch_index,
extrinsic_index,
);
if !StorageProofVerifier::<DomainHeader::Hashing>::verify_storage_proof(
proof_of_inclusion.clone(),
Expand Down Expand Up @@ -372,15 +366,18 @@ pub enum FraudProof<Number, Hash, DomainHeader: HeaderT> {
InvalidExtrinsicsRoot(InvalidExtrinsicsRootProof<HeaderHashFor<DomainHeader>>),
ValidBundle(ValidBundleProof<HeaderHashFor<DomainHeader>>),
InvalidDomainBlockHash(InvalidDomainBlockHashProof<HeaderHashFor<DomainHeader>>),
InvalidBundles(InvalidBundlesFraudProof<HeaderHashFor<DomainHeader>>),
// Dummy fraud proof only used in test and benchmark
//
// NOTE: the `Dummy` must be the last variant, because the `#[cfg(..)]` will apply to
// all the variants after it.
#[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
Dummy {
/// Id of the domain this fraud proof targeted
domain_id: DomainId,
/// Hash of the bad receipt this fraud proof targeted
bad_receipt_hash: HeaderHashFor<DomainHeader>,
},
InvalidBundles(InvalidBundlesFraudProof<HeaderHashFor<DomainHeader>>),
}

impl<Number, Hash, DomainHeader: HeaderT> FraudProof<Number, Hash, DomainHeader> {
Expand Down Expand Up @@ -548,33 +545,6 @@ pub struct InvalidDomainBlockHashProof<ReceiptHash> {
pub digest_storage_proof: StorageProof,
}

/// Represents the extrinsic either as full data or hash of the data.
#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
pub enum ExtrinsicDigest {
/// Actual extrinsic data that is inlined since it is less than 33 bytes.
Data(Vec<u8>),
/// Extrinsic Hash.
Hash(H256),
}

impl ExtrinsicDigest {
pub fn new<Layout: TrieLayout>(ext: Vec<u8>) -> Self
where
Layout::Hash: HashT,
<Layout::Hash as HashT>::Output: Into<H256>,
{
if let Some(threshold) = Layout::MAX_INLINE_VALUE {
if ext.len() >= threshold as usize {
ExtrinsicDigest::Hash(Layout::Hash::hash(&ext).into())
} else {
ExtrinsicDigest::Data(ext)
}
} else {
ExtrinsicDigest::Data(ext)
}
}
}

/// Represents a valid bundle index and all the extrinsics within that bundle.
#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
pub struct ValidBundleDigest {
Expand Down
16 changes: 16 additions & 0 deletions crates/sp-domains-fraud-proof/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ mod runtime_interface;
mod tests;
pub mod verification;

use crate::fraud_proof::FraudProof;
use codec::{Decode, Encode};
#[cfg(feature = "std")]
pub use host_functions::{
Expand All @@ -37,6 +38,7 @@ pub use runtime_interface::fraud_proof_runtime_interface;
pub use runtime_interface::fraud_proof_runtime_interface::HostFunctions;
use sp_api::scale_info::TypeInfo;
use sp_domains::DomainId;
use sp_runtime::traits::{Header as HeaderT, NumberFor};
use sp_runtime::transaction_validity::{InvalidTransaction, TransactionValidity};
use sp_runtime::OpaqueExtrinsic;
use sp_runtime_interface::pass_by;
Expand Down Expand Up @@ -188,3 +190,17 @@ impl FraudProofVerificationInfoResponse {
}
}
}

sp_api::decl_runtime_apis! {
/// API necessary for fraud proof.
pub trait FraudProofApi<DomainHeader: HeaderT> {
/// Submit the fraud proof via an unsigned extrinsic.
fn submit_fraud_proof_unsigned(fraud_proof: FraudProof<NumberFor<Block>, Block::Hash, DomainHeader>);

/// Extract the fraud proof handled successfully from the given extrinsics.
fn extract_fraud_proofs(
domain_id: DomainId,
extrinsics: Vec<Block::Extrinsic>,
) -> Vec<FraudProof<NumberFor<Block>, Block::Hash, DomainHeader>>;
}
}
8 changes: 4 additions & 4 deletions crates/sp-domains-fraud-proof/src/verification.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::fraud_proof::{
ExtrinsicDigest, InvalidBundlesFraudProof, InvalidExtrinsicsRootProof,
InvalidStateTransitionProof, ValidBundleProof, VerificationError,
InvalidBundlesFraudProof, InvalidExtrinsicsRootProof, InvalidStateTransitionProof,
ValidBundleProof, VerificationError,
};
use crate::fraud_proof_runtime_interface::get_fraud_proof_verification_info;
use crate::{
Expand All @@ -15,8 +15,8 @@ use sp_domains::extrinsics::{deduplicate_and_shuffle_extrinsics, extrinsics_shuf
use sp_domains::proof_provider_and_verifier::StorageProofVerifier;
use sp_domains::valued_trie::valued_ordered_trie_root;
use sp_domains::{
BundleValidity, ExecutionReceipt, HeaderHashFor, HeaderHashingFor, HeaderNumberFor,
InboxedBundle, InvalidBundleType,
BundleValidity, ExecutionReceipt, ExtrinsicDigest, HeaderHashFor, HeaderHashingFor,
HeaderNumberFor, InboxedBundle, InvalidBundleType,
};
use sp_runtime::generic::Digest;
use sp_runtime::traits::{Block as BlockT, Hash, Header as HeaderT, NumberFor};
Expand Down
52 changes: 47 additions & 5 deletions crates/sp-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ use sp_runtime_interface::pass_by::PassBy;
use sp_std::collections::btree_set::BTreeSet;
use sp_std::fmt::{Display, Formatter};
use sp_std::vec::Vec;
use sp_trie::TrieLayout;
use sp_weights::Weight;
use subspace_core_primitives::crypto::blake3_hash;
use subspace_core_primitives::{bidirectional_distance, Blake3Hash, Randomness, U256};
Expand Down Expand Up @@ -876,6 +877,41 @@ pub fn derive_domain_block_hash<DomainHeader: HeaderT>(
domain_header.hash()
}

/// Represents the extrinsic either as full data or hash of the data.
#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
pub enum ExtrinsicDigest {
/// Actual extrinsic data that is inlined since it is less than 33 bytes.
Data(Vec<u8>),
/// Extrinsic Hash.
Hash(H256),
}

impl ExtrinsicDigest {
pub fn new<Layout: TrieLayout>(ext: Vec<u8>) -> Self
where
Layout::Hash: HashT,
<Layout::Hash as HashT>::Output: Into<H256>,
{
if let Some(threshold) = Layout::MAX_INLINE_VALUE {
if ext.len() >= threshold as usize {
ExtrinsicDigest::Hash(Layout::Hash::hash(&ext).into())
} else {
ExtrinsicDigest::Data(ext)
}
} else {
ExtrinsicDigest::Data(ext)
}
}
}

pub type ExecutionReceiptFor<DomainHeader, CBlock, Balance> = ExecutionReceipt<
NumberFor<CBlock>,
<CBlock as BlockT>::Hash,
<DomainHeader as HeaderT>::Number,
<DomainHeader as HeaderT>::Hash,
Balance,
>;

sp_api::decl_runtime_apis! {
/// API necessary for domains pallet.
pub trait DomainsApi<DomainHeader: HeaderT> {
Expand All @@ -888,6 +924,13 @@ sp_api::decl_runtime_apis! {
extrinsics: Vec<Block::Extrinsic>,
) -> OpaqueBundles<Block, DomainHeader, Balance>;

/// Extract the execution receipt stored successfully from the given extrinsics.
#[api_version(2)]
fn extract_receipts(
domain_id: DomainId,
extrinsics: Vec<Block::Extrinsic>,
) -> Vec<ExecutionReceiptFor<DomainHeader, Block, Balance>>;

/// Generates a randomness seed for extrinsics shuffling.
fn extrinsics_shuffling_seed() -> Randomness;

Expand All @@ -910,13 +953,13 @@ sp_api::decl_runtime_apis! {
fn genesis_state_root(domain_id: DomainId) -> Option<H256>;

/// Returns the best execution chain number.
fn head_receipt_number(domain_id: DomainId) -> NumberFor<Block>;
fn head_receipt_number(domain_id: DomainId) -> HeaderNumberFor<DomainHeader>;

/// Returns the block number of oldest execution receipt.
fn oldest_receipt_number(domain_id: DomainId) -> NumberFor<Block>;
fn oldest_receipt_number(domain_id: DomainId) -> HeaderNumberFor<DomainHeader>;

/// Returns the block tree pruning depth.
fn block_tree_pruning_depth() -> NumberFor<Block>;
fn block_tree_pruning_depth() -> HeaderNumberFor<DomainHeader>;

/// Returns the domain block limit of the given domain.
fn domain_block_limit(domain_id: DomainId) -> Option<DomainBlockLimit>;
Expand All @@ -934,8 +977,7 @@ sp_api::decl_runtime_apis! {
hash: HeaderHashFor<DomainHeader>) -> Option<HeaderHashFor<DomainHeader>>;

/// Returns the execution receipt
#[allow(clippy::type_complexity)]
fn execution_receipt(receipt_hash: HeaderHashFor<DomainHeader>) -> Option<ExecutionReceipt<NumberFor<Block>, Block::Hash, HeaderNumberFor<DomainHeader>, HeaderHashFor<DomainHeader>, Balance>>;
fn execution_receipt(receipt_hash: HeaderHashFor<DomainHeader>) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
}

pub trait BundleProducerElectionApi<Balance: Encode + Decode> {
Expand Down
21 changes: 21 additions & 0 deletions crates/subspace-runtime/src/domains.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::{Balance, Block, Domains, RuntimeCall, UncheckedExtrinsic};
use domain_runtime_primitives::opaque::Header as DomainHeader;
use sp_domains::DomainId;
use sp_domains_fraud_proof::fraud_proof::FraudProof;
use sp_runtime::traits::{Block as BlockT, NumberFor};
use sp_std::vec::Vec;

pub(crate) fn extract_successful_bundles(
Expand All @@ -21,3 +23,22 @@ pub(crate) fn extract_successful_bundles(
})
.collect()
}

pub(crate) fn extract_fraud_proofs(
domain_id: DomainId,
extrinsics: Vec<UncheckedExtrinsic>,
) -> Vec<FraudProof<NumberFor<Block>, <Block as BlockT>::Hash, DomainHeader>> {
let successful_fraud_proofs = Domains::successful_fraud_proofs(domain_id);
extrinsics
.into_iter()
.filter_map(|uxt| match uxt.function {
RuntimeCall::Domains(pallet_domains::Call::submit_fraud_proof { fraud_proof })
if fraud_proof.domain_id() == domain_id
&& successful_fraud_proofs.contains(&fraud_proof.hash()) =>
{
Some(*fraud_proof)
}
_ => None,
})
.collect()
}
Loading

0 comments on commit 9422744

Please sign in to comment.