Skip to content

Commit

Permalink
verify invalid domain extrinsic root
Browse files Browse the repository at this point in the history
  • Loading branch information
vedhavyas committed Oct 9, 2023
1 parent 1ebad8f commit 945e9ab
Show file tree
Hide file tree
Showing 25 changed files with 310 additions and 370 deletions.
11 changes: 7 additions & 4 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions crates/pallet-domains/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ log = { version = "0.4.20", default-features = false }
scale-info = { version = "2.7.0", default-features = false, features = ["derive"] }
sp-core = { version = "21.0.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "c90d6edfd8c63168eff0dce6f2ace4d66dd139f7" }
sp-domains = { version = "0.1.0", default-features = false, path = "../sp-domains" }
sp-domains-fraud-proof = { version = "0.1.0", default-features = false, path = "../sp-domains-fraud-proof" }
sp-io = { version = "23.0.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "c90d6edfd8c63168eff0dce6f2ace4d66dd139f7" }
sp-runtime = { version = "24.0.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "c90d6edfd8c63168eff0dce6f2ace4d66dd139f7" }
sp-std = { version = "8.0.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "c90d6edfd8c63168eff0dce6f2ace4d66dd139f7" }
Expand All @@ -45,6 +46,7 @@ std = [
"scale-info/std",
"sp-core/std",
"sp-domains/std",
"sp-domains-fraud-proof/std",
"sp-io/std",
"sp-runtime/std",
"sp-std/std",
Expand Down
31 changes: 12 additions & 19 deletions crates/pallet-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ use scale_info::TypeInfo;
use sp_core::H256;
use sp_domains::bundle_producer_election::{is_below_threshold, BundleProducerElectionParams};
use sp_domains::fraud_proof::{FraudProof, InvalidTotalRewardsProof};
use sp_domains::verification::{
verify_invalid_domain_extrinsics_root_fraud_proof, verify_invalid_total_rewards_fraud_proof,
};
use sp_domains::verification::verify_invalid_total_rewards_fraud_proof;
use sp_domains::{
DomainBlockLimit, DomainId, DomainInstanceData, ExecutionReceipt, OpaqueBundle, OperatorId,
OperatorPublicKey, ProofOfElection, RuntimeId, DOMAIN_EXTRINSICS_SHUFFLING_SEED_SUBJECT,
EMPTY_EXTRINSIC_ROOT,
};
use sp_domains_fraud_proof::fraud_proof_runtime_interface::get_invalid_domain_extrinsic_root_info;
use sp_domains_fraud_proof::verification::verify_invalid_domain_extrinsics_root_fraud_proof;
use sp_runtime::traits::{BlakeTwo256, CheckedSub, Hash, One, Zero};
use sp_runtime::{RuntimeAppPublic, SaturatedConversion, Saturating};
use sp_std::boxed::Box;
Expand Down Expand Up @@ -141,7 +141,7 @@ mod pallet {
use frame_support::{Identity, PalletError};
use frame_system::pallet_prelude::*;
use sp_core::H256;
use sp_domains::fraud_proof::{DeriveExtrinsics, FraudProof, StorageKeys};
use sp_domains::fraud_proof::FraudProof;
use sp_domains::transaction::InvalidTransactionCode;
use sp_domains::{
BundleDigest, DomainId, EpochIndex, GenesisDomain, OperatorId, ReceiptHash, RuntimeId,
Expand All @@ -159,7 +159,6 @@ mod pallet {
use sp_std::vec;
use sp_std::vec::Vec;
use subspace_core_primitives::U256;
use subspace_runtime_primitives::Moment;

#[pallet::config]
pub trait Config: frame_system::Config {
Expand Down Expand Up @@ -287,12 +286,6 @@ mod pallet {

/// Randomness source.
type Randomness: RandomnessT<Self::Hash, BlockNumberFor<Self>>;

/// Trait impl to fetch storage keys.
type StorageKeys: StorageKeys;

/// Derive extrinsics trait impl.
type DeriveExtrinsics: DeriveExtrinsics<Moment>;
}

#[pallet::pallet]
Expand Down Expand Up @@ -590,10 +583,10 @@ mod pallet {
DescendantsOfFraudulentERNotPruned,
/// Invalid fraud proof since total rewards are not mismatched.
InvalidTotalRewardsFraudProof(sp_domains::verification::VerificationError),
/// Missing state root for a given consensus block
MissingConsensusStateRoot,
/// Invalid domain extrinsic fraud proof
InvalidExtrinsicRootFraudProof(sp_domains::verification::VerificationError),
/// Failed to get invalid domain extrinsic verification info.
FailedToGetInvalidDomainExtrinsicRootVerificationInfo,
}

impl<T> From<FraudProofError> for Error<T> {
Expand Down Expand Up @@ -1497,21 +1490,21 @@ impl<T: Config> Pallet<T> {
.map_err(FraudProofError::InvalidTotalRewardsFraudProof)?;
}
FraudProof::InvalidExtrinsicsRoot(proof) => {
let consensus_state_root = ConsensusBlockHash::<T>::get(
let consensus_block_hash = bad_receipt.consensus_block_hash;
let verification_info = get_invalid_domain_extrinsic_root_info(
H256::from_slice(consensus_block_hash.as_ref()),
proof.domain_id,
bad_receipt.consensus_block_number,
)
.ok_or(FraudProofError::MissingConsensusStateRoot)?;
.ok_or(FraudProofError::FailedToGetInvalidDomainExtrinsicRootVerificationInfo)?;

verify_invalid_domain_extrinsics_root_fraud_proof::<
T::Block,
T::DomainNumber,
T::DomainHash,
BalanceOf<T>,
T::Hashing,
T::StorageKeys,
T::DeriveExtrinsics,
>(consensus_state_root, bad_receipt, proof)
T::DomainHashing,
>(bad_receipt, proof, verification_info)
.map_err(FraudProofError::InvalidExtrinsicRootFraudProof)?;
}
_ => {}
Expand Down
110 changes: 43 additions & 67 deletions crates/pallet-domains/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use crate::{
};
use codec::{Decode, Encode, MaxEncodedLen};
use frame_support::dispatch::RawOrigin;
use frame_support::storage::generator::StorageValue;
use frame_support::traits::{ConstU16, ConstU32, ConstU64, Currency, Hooks};
use frame_support::weights::Weight;
use frame_support::{assert_err, assert_ok, parameter_types, PalletId};
Expand All @@ -27,10 +26,14 @@ use sp_domains::{
OperatorPair, ProofOfElection, ReceiptHash, RuntimeType, SealedBundleHeader,
StakingHoldIdentifier,
};
use sp_domains_fraud_proof::{
FraudProofExtension, FraudProofHostFunctions, InvalidDomainExtrinsicRootInfo,
};
use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, Hash as HashT, IdentityLookup, Zero};
use sp_runtime::{BuildStorage, OpaqueExtrinsic};
use sp_state_machine::backend::AsTrieBackend;
use sp_state_machine::{prove_read, Backend, TrieBackendBuilder};
use sp_std::sync::Arc;
use sp_trie::trie_types::TrieDBMutBuilderV1;
use sp_trie::{PrefixedMemoryDB, StorageProof, TrieMut};
use sp_version::RuntimeVersion;
Expand Down Expand Up @@ -193,20 +196,6 @@ impl frame_support::traits::Randomness<Hash, BlockNumber> for MockRandomness {
}
}

pub struct StorageKeys;
impl sp_domains::fraud_proof::StorageKeys for StorageKeys {
fn block_randomness_storage_key() -> StorageKey {
StorageKey(
frame_support::storage::storage_prefix("Subspace".as_ref(), "BlockRandomness".as_ref())
.to_vec(),
)
}

fn timestamp_storage_key() -> StorageKey {
StorageKey(pallet_timestamp::pallet::Now::<Test>::storage_value_final_key().to_vec())
}
}

const SLOT_DURATION: u64 = 1000;
impl pallet_timestamp::Config for Test {
/// A timestamp: milliseconds since the unix epoch.
Expand All @@ -216,14 +205,6 @@ impl pallet_timestamp::Config for Test {
type WeightInfo = ();
}

pub struct DeriveExtrinsics;
impl sp_domains::fraud_proof::DeriveExtrinsics<Moment> for DeriveExtrinsics {
fn derive_timestamp_extrinsic(now: Moment) -> Vec<u8> {
UncheckedExtrinsic::new_unsigned(pallet_timestamp::Call::<Test>::set { now }.into())
.encode()
}
}

impl pallet_domains::Config for Test {
type RuntimeEvent = RuntimeEvent;
type DomainNumber = BlockNumber;
Expand All @@ -249,8 +230,6 @@ impl pallet_domains::Config for Test {
type TreasuryAccount = TreasuryAccount;
type MaxPendingStakingOperation = MaxPendingStakingOperation;
type Randomness = MockRandomness;
type StorageKeys = StorageKeys;
type DeriveExtrinsics = DeriveExtrinsics;
}

pub(crate) fn new_test_ext() -> sp_io::TestExternalities {
Expand All @@ -261,6 +240,24 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities {
t.into()
}

pub(crate) struct MockDomainFraudProofExtension(Randomness, Moment);

impl FraudProofHostFunctions for MockDomainFraudProofExtension {
fn get_invalid_domain_extrinsic_root_info(
&self,
_consensus_block_hash: H256,
_domain_id: DomainId,
) -> Option<InvalidDomainExtrinsicRootInfo> {
Some(InvalidDomainExtrinsicRootInfo {
block_randomness: self.0,
timestamp_extrinsic: UncheckedExtrinsic::new_unsigned(
pallet_timestamp::Call::<Test>::set { now: self.1 }.into(),
)
.encode(),
})
}
}

pub(crate) fn new_test_ext_with_extensions() -> sp_io::TestExternalities {
let version = RuntimeVersion {
spec_name: "test".into(),
Expand Down Expand Up @@ -842,13 +839,12 @@ fn storage_proof_for_key<T: Config, B: Backend<T::Hashing> + AsTrieBackend<T::Ha
}

#[test]
#[ignore]
fn test_invalid_domain_extrinsic_root_proof() {
let creator = 0u64;
let operator_id = 1u64;
let head_domain_number = 10;
let mut ext = new_test_ext_with_extensions();
ext.execute_with(|| {
let fraud_proof = ext.execute_with(|| {
let domain_id = register_genesis_domain(creator, vec![operator_id]);
extend_block_tree(domain_id, operator_id, head_domain_number + 1);
assert_eq!(
Expand All @@ -860,62 +856,42 @@ fn test_invalid_domain_extrinsic_root_proof() {
let domain_block = get_block_tree_node_at::<Test>(domain_id, bad_receipt_at).unwrap();

let bad_receipt_hash = domain_block.execution_receipt.hash();
let (fraud_proof, _root) = generate_invalid_domain_extrinsic_root_fraud_proof::<Test>(
domain_id,
bad_receipt_hash,
Randomness::from([1u8; 32]),
1000,
);
let fraud_proof =
generate_invalid_domain_extrinsic_root_fraud_proof::<Test>(domain_id, bad_receipt_hash);
let (consensus_block_number, consensus_block_hash) = (
domain_block.execution_receipt.consensus_block_number,
domain_block.execution_receipt.consensus_block_hash,
);
ConsensusBlockHash::<Test>::insert(domain_id, consensus_block_number, consensus_block_hash);
DomainBlocks::<Test>::insert(bad_receipt_hash, domain_block);
assert_ok!(Domains::validate_fraud_proof(&fraud_proof),);
fraud_proof
});

let fraud_proof_ext = FraudProofExtension::new(Arc::new(MockDomainFraudProofExtension(
Randomness::from([1u8; 32]),
1000,
)));
ext.register_extension(fraud_proof_ext);

ext.execute_with(|| {
assert_ok!(Domains::validate_fraud_proof(&fraud_proof),);
})
}

fn generate_invalid_domain_extrinsic_root_fraud_proof<T: Config + pallet_timestamp::Config>(
domain_id: DomainId,
bad_receipt_hash: ReceiptHash,
randomness: Randomness,
moment: Moment,
) -> (FraudProof<BlockNumberFor<T>, T::Hash>, T::Hash) {
let randomness_storage_key =
frame_support::storage::storage_prefix("Subspace".as_ref(), "BlockRandomness".as_ref())
.to_vec();
let timestamp_storage_key =
pallet_timestamp::pallet::Now::<T>::storage_value_final_key().to_vec();
let mut root = T::Hash::default();
let mut mdb = PrefixedMemoryDB::<T::Hashing>::default();
{
let mut trie = TrieDBMutBuilderV1::new(&mut mdb, &mut root).build();
trie.insert(&randomness_storage_key, &randomness.encode())
.unwrap();
trie.insert(&timestamp_storage_key, &moment.encode())
.unwrap();
};

let backend = TrieBackendBuilder::new(mdb, root).build();
let (_, randomness_storage_proof) =
storage_proof_for_key::<T, _>(backend.clone(), StorageKey(randomness_storage_key));
let (root, timestamp_storage_proof) =
storage_proof_for_key::<T, _>(backend, StorageKey(timestamp_storage_key));
) -> FraudProof<BlockNumberFor<T>, T::Hash> {
let valid_bundle_digests = vec![ValidBundleDigest {
bundle_index: 0,
bundle_digest: vec![(Some(vec![1, 2, 3]), ExtrinsicDigest::Data(vec![4, 5, 6]))],
}];
(
FraudProof::InvalidExtrinsicsRoot(InvalidExtrinsicsRootProof {
domain_id,
bad_receipt_hash,
randomness_storage_proof,
valid_bundle_digests,
timestamp_storage_proof,
}),
root,
)

FraudProof::InvalidExtrinsicsRoot(InvalidExtrinsicsRootProof {
domain_id,
bad_receipt_hash,
valid_bundle_digests,
})
}

#[test]
Expand Down
12 changes: 11 additions & 1 deletion crates/sp-domains-fraud-proof/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,38 @@ include = [

[dependencies]
codec = { package = "parity-scale-codec", version = "3.6.5", default-features = false, features = ["derive"] }
hash-db = { version = "0.16.0", default-features = false }
scale-info = { version = "2.7.0", default-features = false, features = ["derive"] }
domain-block-preprocessor = { version = "0.1.0", default-features = false, path = "../../domains/client/block-preprocessor", optional = true }
sp-api = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "c90d6edfd8c63168eff0dce6f2ace4d66dd139f7" }
sp-blockchain = { version = "4.0.0-dev", git = "https://github.com/subspace/polkadot-sdk", rev = "c90d6edfd8c63168eff0dce6f2ace4d66dd139f7", optional = true }
sp-core = { version = "21.0.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "c90d6edfd8c63168eff0dce6f2ace4d66dd139f7" }
sp-domains = { version = "0.1.0", default-features = false, path = "../sp-domains" }
sp-externalities = { version = "0.19.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "c90d6edfd8c63168eff0dce6f2ace4d66dd139f7" }
sp-runtime = { version = "24.0.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "c90d6edfd8c63168eff0dce6f2ace4d66dd139f7" }
sp-runtime-interface = { version = "17.0.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "c90d6edfd8c63168eff0dce6f2ace4d66dd139f7" }
sp-std = { version = "8.0.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "c90d6edfd8c63168eff0dce6f2ace4d66dd139f7" }
sp-trie = { version = "22.0.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "c90d6edfd8c63168eff0dce6f2ace4d66dd139f7" }
subspace-core-primitives = { version = "0.1.0", default-features = false, path = "../subspace-core-primitives" }
trie-db = { version = "0.28.0", default-features = false }

[features]
default = ["std"]
std = [
"codec/std",
"hash-db/std",
"scale-info/std",
"domain-block-preprocessor",
"sp-api/std",
"sp-blockchain",
"sp-core/std",
"sp-domains/std",
"sp-externalities/std",
"sp-runtime/std",
"sp-runtime-interface/std",
"sp-std/std",
"subspace-core-primitives/std"
"sp-trie/std",
"subspace-core-primitives/std",
"trie-db/std"
]
runtime-benchmarks = []
Loading

0 comments on commit 945e9ab

Please sign in to comment.