diff --git a/crates/pallet-domains/src/lib.rs b/crates/pallet-domains/src/lib.rs index 0ba8ff0c23..02346765c0 100644 --- a/crates/pallet-domains/src/lib.rs +++ b/crates/pallet-domains/src/lib.rs @@ -52,8 +52,11 @@ use sp_domains::{ 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::fraud_proof_runtime_interface::get_fraud_proof_verification_info; use sp_domains_fraud_proof::verification::verify_invalid_domain_extrinsics_root_fraud_proof; +use sp_domains_fraud_proof::{ + FraudProofVerificationInfoRequest, FraudProofVerificationInfoResponse, +}; use sp_runtime::traits::{BlakeTwo256, CheckedSub, Hash, One, Zero}; use sp_runtime::{RuntimeAppPublic, SaturatedConversion, Saturating}; use sp_std::boxed::Box; @@ -585,8 +588,12 @@ mod pallet { InvalidTotalRewardsFraudProof(sp_domains::verification::VerificationError), /// Invalid domain extrinsic fraud proof InvalidExtrinsicRootFraudProof(sp_domains::verification::VerificationError), - /// Failed to get invalid domain extrinsic verification info. - FailedToGetInvalidDomainExtrinsicRootVerificationInfo, + /// Failed to get block randomness. + FailedToGetBlockRandomness, + /// Failed to get domain timestamp extrinsic. + FailedToGetDomainTimestampExtrinsic, + /// Received invalid Verification info from host function. + ReceivedInvalidVerificationInfo, } impl From for Error { @@ -1491,11 +1498,29 @@ impl Pallet { } FraudProof::InvalidExtrinsicsRoot(proof) => { let consensus_block_hash = bad_receipt.consensus_block_hash; - let verification_info = get_invalid_domain_extrinsic_root_info( + let block_randomness = match get_fraud_proof_verification_info( + H256::from_slice(consensus_block_hash.as_ref()), + FraudProofVerificationInfoRequest::BlockRandomness, + ) + .ok_or(FraudProofError::FailedToGetBlockRandomness)? + { + FraudProofVerificationInfoResponse::BlockRandomness(randomness) => { + Ok(randomness) + } + _ => Err(FraudProofError::ReceivedInvalidVerificationInfo), + }?; + + let domain_timestamp_extrinsic = match get_fraud_proof_verification_info( H256::from_slice(consensus_block_hash.as_ref()), - proof.domain_id, + FraudProofVerificationInfoRequest::DomainTimestampExtrinsic(proof.domain_id), ) - .ok_or(FraudProofError::FailedToGetInvalidDomainExtrinsicRootVerificationInfo)?; + .ok_or(FraudProofError::FailedToGetDomainTimestampExtrinsic)? + { + FraudProofVerificationInfoResponse::DomainTimestampExtrinsic( + domain_timestamp_extrinsic, + ) => Ok(domain_timestamp_extrinsic), + _ => Err(FraudProofError::ReceivedInvalidVerificationInfo), + }?; verify_invalid_domain_extrinsics_root_fraud_proof::< T::Block, @@ -1504,7 +1529,12 @@ impl Pallet { BalanceOf, T::Hashing, T::DomainHashing, - >(bad_receipt, proof, verification_info) + >( + bad_receipt, + proof, + block_randomness, + domain_timestamp_extrinsic, + ) .map_err(FraudProofError::InvalidExtrinsicRootFraudProof)?; } _ => {} diff --git a/crates/pallet-domains/src/tests.rs b/crates/pallet-domains/src/tests.rs index 1d46d4c4a4..c54916af66 100644 --- a/crates/pallet-domains/src/tests.rs +++ b/crates/pallet-domains/src/tests.rs @@ -27,7 +27,8 @@ use sp_domains::{ StakingHoldIdentifier, }; use sp_domains_fraud_proof::{ - FraudProofExtension, FraudProofHostFunctions, InvalidDomainExtrinsicRootInfo, + FraudProofExtension, FraudProofHostFunctions, FraudProofVerificationInfoRequest, + FraudProofVerificationInfoResponse, }; use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, Hash as HashT, IdentityLookup, Zero}; use sp_runtime::{BuildStorage, OpaqueExtrinsic}; @@ -240,21 +241,35 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities { t.into() } -pub(crate) struct MockDomainFraudProofExtension(Randomness, Moment); +pub(crate) struct MockDomainFraudProofExtension { + block_randomness: Randomness, + timestamp: Moment, +} impl FraudProofHostFunctions for MockDomainFraudProofExtension { - fn get_invalid_domain_extrinsic_root_info( + fn get_fraud_proof_verification_info( &self, _consensus_block_hash: H256, - _domain_id: DomainId, - ) -> Option { - Some(InvalidDomainExtrinsicRootInfo { - block_randomness: self.0, - timestamp_extrinsic: UncheckedExtrinsic::new_unsigned( - pallet_timestamp::Call::::set { now: self.1 }.into(), - ) - .encode(), - }) + fraud_proof_verification_info_req: FraudProofVerificationInfoRequest, + ) -> Option { + let response = match fraud_proof_verification_info_req { + FraudProofVerificationInfoRequest::BlockRandomness => { + FraudProofVerificationInfoResponse::BlockRandomness(self.block_randomness) + } + FraudProofVerificationInfoRequest::DomainTimestampExtrinsic(_) => { + FraudProofVerificationInfoResponse::DomainTimestampExtrinsic( + UncheckedExtrinsic::new_unsigned( + pallet_timestamp::Call::::set { + now: self.timestamp, + } + .into(), + ) + .encode(), + ) + } + }; + + Some(response) } } @@ -883,10 +898,10 @@ fn test_invalid_domain_extrinsic_root_proof() { fraud_proof }); - let fraud_proof_ext = FraudProofExtension::new(Arc::new(MockDomainFraudProofExtension( - Randomness::from([1u8; 32]), - 1000, - ))); + let fraud_proof_ext = FraudProofExtension::new(Arc::new(MockDomainFraudProofExtension { + block_randomness: Randomness::from([1u8; 32]), + timestamp: 1000, + })); ext.register_extension(fraud_proof_ext); ext.execute_with(|| { diff --git a/crates/sp-domains-fraud-proof/src/host_functions.rs b/crates/sp-domains-fraud-proof/src/host_functions.rs index 07c0b7cb06..098c143b3e 100644 --- a/crates/sp-domains-fraud-proof/src/host_functions.rs +++ b/crates/sp-domains-fraud-proof/src/host_functions.rs @@ -1,4 +1,4 @@ -use crate::InvalidDomainExtrinsicRootInfo; +use crate::{FraudProofVerificationInfoRequest, FraudProofVerificationInfoResponse}; use codec::Encode; use domain_block_preprocessor::runtime_api::InherentExtrinsicConstructor; use domain_block_preprocessor::runtime_api_light::RuntimeApiLight; @@ -10,15 +10,16 @@ use sp_domains::{DomainId, DomainsApi}; use sp_runtime::traits::NumberFor; use std::marker::PhantomData; use std::sync::Arc; +use subspace_core_primitives::Randomness; /// Trait to query and verify Domains Fraud proof. pub trait FraudProofHostFunctions: Send + Sync { - /// Returns the required info to verify invalid domain extrinsic root. - fn get_invalid_domain_extrinsic_root_info( + /// Returns the required verification info for the runtime to verify the Fraud proof. + fn get_fraud_proof_verification_info( &self, consensus_block_hash: H256, - domain_id: DomainId, - ) -> Option; + fraud_proof_verification_req: FraudProofVerificationInfoRequest, + ) -> Option; } sp_externalities::decl_extension! { @@ -52,8 +53,8 @@ impl } } -impl FraudProofHostFunctions - for FraudProofHostFunctionsImpl +impl + FraudProofHostFunctionsImpl where Block: BlockT, Block::Hash: From, @@ -62,37 +63,69 @@ where Client::Api: DomainsApi, DomainBlock::Hash>, Executor: CodeExecutor, { - fn get_invalid_domain_extrinsic_root_info( + fn get_block_randomness(&self, consensus_block_hash: H256) -> Option { + let runtime_api = self.consensus_client.runtime_api(); + let consensus_block_hash = consensus_block_hash.into(); + runtime_api + .extrinsics_shuffling_seed(consensus_block_hash) + .ok() + } + + fn derive_domain_timestamp_extrinsic( &self, consensus_block_hash: H256, domain_id: DomainId, - ) -> Option { + ) -> Option> { let runtime_api = self.consensus_client.runtime_api(); let consensus_block_hash = consensus_block_hash.into(); let runtime_code = runtime_api .domain_runtime_code(consensus_block_hash, domain_id) .ok()??; - let block_randomness = runtime_api - .extrinsics_shuffling_seed(consensus_block_hash) - .ok()?; let timestamp = runtime_api.timestamp(consensus_block_hash).ok()?; let domain_runtime_api_light = RuntimeApiLight::new(self.executor.clone(), runtime_code.into()); - let timestamp_extrinsic = - InherentExtrinsicConstructor::::construct_timestamp_inherent_extrinsic( - &domain_runtime_api_light, - // We do not care about the domain hash since this is stateless call into - // domain runtime, - Default::default(), - timestamp, - ) - .ok()? - .encode(); - Some(InvalidDomainExtrinsicRootInfo { - block_randomness, - timestamp_extrinsic, - }) + InherentExtrinsicConstructor::::construct_timestamp_inherent_extrinsic( + &domain_runtime_api_light, + // We do not care about the domain hash since this is stateless call into + // domain runtime, + Default::default(), + timestamp, + ) + .ok() + .map(|ext| ext.encode()) + } +} + +impl FraudProofHostFunctions + for FraudProofHostFunctionsImpl +where + Block: BlockT, + Block::Hash: From, + DomainBlock: BlockT, + Client: HeaderBackend + ProvideRuntimeApi, + Client::Api: DomainsApi, DomainBlock::Hash>, + Executor: CodeExecutor, +{ + fn get_fraud_proof_verification_info( + &self, + consensus_block_hash: H256, + fraud_proof_verification_req: FraudProofVerificationInfoRequest, + ) -> Option { + match fraud_proof_verification_req { + FraudProofVerificationInfoRequest::BlockRandomness => self + .get_block_randomness(consensus_block_hash) + .map(|block_randomness| { + FraudProofVerificationInfoResponse::BlockRandomness(block_randomness) + }), + FraudProofVerificationInfoRequest::DomainTimestampExtrinsic(doman_id) => self + .derive_domain_timestamp_extrinsic(consensus_block_hash, doman_id) + .map(|domain_timestamp_extrinsic| { + FraudProofVerificationInfoResponse::DomainTimestampExtrinsic( + domain_timestamp_extrinsic, + ) + }), + } } } diff --git a/crates/sp-domains-fraud-proof/src/lib.rs b/crates/sp-domains-fraud-proof/src/lib.rs index 1dde2e1cfc..1ac4a3cb90 100644 --- a/crates/sp-domains-fraud-proof/src/lib.rs +++ b/crates/sp-domains-fraud-proof/src/lib.rs @@ -31,12 +31,30 @@ pub use runtime_interface::fraud_proof_runtime_interface; #[cfg(feature = "std")] pub use runtime_interface::fraud_proof_runtime_interface::HostFunctions; use sp_api::scale_info::TypeInfo; +use sp_domains::DomainId; +use sp_runtime_interface::pass_by; +use sp_runtime_interface::pass_by::PassBy; use sp_std::vec::Vec; use subspace_core_primitives::Randomness; -/// Type to hold required information to verify invalid domain extrinsics root. +/// Request type to fetch required verification information for fraud proof through Host function. #[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)] -pub struct InvalidDomainExtrinsicRootInfo { - pub block_randomness: Randomness, - pub timestamp_extrinsic: Vec, +pub enum FraudProofVerificationInfoRequest { + /// Block randomness at a given consensus block hash. + BlockRandomness, + /// Domain timestamp extrinsic using the timestamp at a given consensus block hash. + DomainTimestampExtrinsic(DomainId), +} + +impl PassBy for FraudProofVerificationInfoRequest { + type PassBy = pass_by::Codec; +} + +/// Response holds required verification information for fraud proof from Host function. +#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)] +pub enum FraudProofVerificationInfoResponse { + /// Block randomness fetched from consensus state at a specific block hash. + BlockRandomness(Randomness), + /// Encoded domain timestamp extrinsic using the timestamp from consensus state at a specific block hash. + DomainTimestampExtrinsic(Vec), } diff --git a/crates/sp-domains-fraud-proof/src/runtime_interface.rs b/crates/sp-domains-fraud-proof/src/runtime_interface.rs index 7ae5651aef..cbe25aeefd 100644 --- a/crates/sp-domains-fraud-proof/src/runtime_interface.rs +++ b/crates/sp-domains-fraud-proof/src/runtime_interface.rs @@ -1,8 +1,7 @@ #[cfg(feature = "std")] use crate::FraudProofExtension; -use crate::InvalidDomainExtrinsicRootInfo; +use crate::{FraudProofVerificationInfoRequest, FraudProofVerificationInfoResponse}; use sp_core::H256; -use sp_domains::DomainId; #[cfg(feature = "std")] use sp_externalities::ExternalitiesExt; use sp_runtime_interface::runtime_interface; @@ -10,13 +9,14 @@ use sp_runtime_interface::runtime_interface; /// Domain fraud proof related runtime interface #[runtime_interface] pub trait FraudProofRuntimeInterface { - fn get_invalid_domain_extrinsic_root_info( + /// Returns required fraud proof verification information to the runtime through host function. + fn get_fraud_proof_verification_info( &mut self, consensus_block_hash: H256, - domain_id: DomainId, - ) -> Option { + fraud_proof_verification_req: FraudProofVerificationInfoRequest, + ) -> Option { self.extension::() .expect("No `FraudProofExtension` associated for the current context!") - .get_invalid_domain_extrinsic_root_info(consensus_block_hash, domain_id) + .get_fraud_proof_verification_info(consensus_block_hash, fraud_proof_verification_req) } } diff --git a/crates/sp-domains-fraud-proof/src/verification.rs b/crates/sp-domains-fraud-proof/src/verification.rs index f4a1706a75..6800803b97 100644 --- a/crates/sp-domains-fraud-proof/src/verification.rs +++ b/crates/sp-domains-fraud-proof/src/verification.rs @@ -1,4 +1,3 @@ -use crate::InvalidDomainExtrinsicRootInfo; use hash_db::Hasher; use sp_core::H256; use sp_domains::fraud_proof::{ExtrinsicDigest, InvalidExtrinsicsRootProof}; @@ -29,7 +28,8 @@ pub fn verify_invalid_domain_extrinsics_root_fraud_proof< Balance, >, fraud_proof: &InvalidExtrinsicsRootProof, - verification_info: InvalidDomainExtrinsicRootInfo, + block_randomness: Randomness, + domain_timestamp_extrinsic: Vec, ) -> Result<(), VerificationError> where CBlock: Block, @@ -42,11 +42,6 @@ where .. } = fraud_proof; - let InvalidDomainExtrinsicRootInfo { - block_randomness, - timestamp_extrinsic, - } = verification_info; - let mut bundle_extrinsics_digests = Vec::new(); for (bad_receipt_valid_bundle_digest, bundle_digest) in bad_receipt .valid_bundle_digests() @@ -69,7 +64,8 @@ where Randomness::from(shuffling_seed.to_fixed_bytes()), ); - let timestamp_extrinsic = ExtrinsicDigest::new::>(timestamp_extrinsic); + let timestamp_extrinsic = + ExtrinsicDigest::new::>(domain_timestamp_extrinsic); ordered_extrinsics.insert(0, timestamp_extrinsic); let ordered_trie_node_values = ordered_extrinsics