Skip to content

Commit 0d22229

Browse files
authored
Merge pull request #2562 from subspace/xdm_mmr_2
XDM: Relayer and Fraud proof updates
2 parents 8fff19c + bfb2d38 commit 0d22229

File tree

40 files changed

+1367
-664
lines changed

40 files changed

+1367
-664
lines changed

Cargo.lock

+21-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/pallet-domains/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1988,6 +1988,13 @@ impl<T: Config> Pallet<T> {
19881988
.unwrap_or_default()
19891989
}
19901990

1991+
pub fn latest_confirmed_domain_block(
1992+
domain_id: DomainId,
1993+
) -> Option<(DomainBlockNumberFor<T>, T::DomainHash)> {
1994+
LatestConfirmedDomainBlock::<T>::get(domain_id)
1995+
.map(|block| (block.block_number, block.block_hash))
1996+
}
1997+
19911998
/// Returns the domain block limit of the given domain.
19921999
pub fn domain_block_limit(domain_id: DomainId) -> Option<DomainBlockLimit> {
19932000
DomainRegistry::<T>::get(domain_id).map(|domain_obj| DomainBlockLimit {

crates/pallet-domains/src/tests.rs

+7
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ pub(crate) struct MockDomainFraudProofExtension {
353353
bundle_slot_probability: (u64, u64),
354354
operator_stake: Balance,
355355
maybe_illegal_extrinsic_index: Option<u32>,
356+
is_valid_xdm: Option<bool>,
356357
}
357358

358359
impl FraudProofHostFunctions for MockDomainFraudProofExtension {
@@ -432,6 +433,9 @@ impl FraudProofHostFunctions for MockDomainFraudProofExtension {
432433
FraudProofVerificationInfoRequest::StorageKey { .. } => {
433434
FraudProofVerificationInfoResponse::StorageKey(None)
434435
}
436+
FraudProofVerificationInfoRequest::XDMValidationCheck { .. } => {
437+
FraudProofVerificationInfoResponse::XDMValidationCheck(self.is_valid_xdm)
438+
}
435439
};
436440

437441
Some(response)
@@ -1016,6 +1020,7 @@ fn test_invalid_domain_extrinsic_root_proof() {
10161020
operator_stake: 10 * SSC,
10171021
bundle_slot_probability: (0, 0),
10181022
maybe_illegal_extrinsic_index: None,
1023+
is_valid_xdm: None,
10191024
}));
10201025
ext.register_extension(fraud_proof_ext);
10211026

@@ -1097,6 +1102,7 @@ fn test_true_invalid_bundles_inherent_extrinsic_proof() {
10971102
operator_stake: 10 * SSC,
10981103
bundle_slot_probability: (0, 0),
10991104
maybe_illegal_extrinsic_index: None,
1105+
is_valid_xdm: None,
11001106
}));
11011107
ext.register_extension(fraud_proof_ext);
11021108

@@ -1164,6 +1170,7 @@ fn test_false_invalid_bundles_inherent_extrinsic_proof() {
11641170
operator_stake: 10 * SSC,
11651171
bundle_slot_probability: (0, 0),
11661172
maybe_illegal_extrinsic_index: None,
1173+
is_valid_xdm: None,
11671174
}));
11681175
ext.register_extension(fraud_proof_ext);
11691176

crates/sp-domains-fraud-proof/src/fraud_proof.rs

+3
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,9 @@ pub enum VerificationError<DomainHash> {
386386
error("Failed to check if a given extrinsic is inherent or not")
387387
)]
388388
FailedToCheckInherentExtrinsic,
389+
/// Failed to check if a given extrinsic is inherent or not.
390+
#[cfg_attr(feature = "thiserror", error("Failed to validate given XDM"))]
391+
FailedToValidateXDM,
389392
/// Failed to check if a given extrinsic is decodable or not.
390393
#[cfg_attr(
391394
feature = "thiserror",

crates/sp-domains-fraud-proof/src/host_functions.rs

+53-13
Original file line numberDiff line numberDiff line change
@@ -85,33 +85,33 @@ impl FraudProofExtension {
8585
}
8686

8787
/// Trait Impl to query and verify Domains Fraud proof.
88-
pub struct FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor> {
88+
pub struct FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor, EFC> {
8989
consensus_client: Arc<Client>,
9090
executor: Arc<Executor>,
91-
domain_extensions_factory: Box<dyn ExtensionsFactory<DomainBlock>>,
91+
domain_extensions_factory_creator: EFC,
9292
_phantom: PhantomData<(Block, DomainBlock)>,
9393
}
9494

95-
impl<Block, Client, DomainBlock, Executor>
96-
FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor>
95+
impl<Block, Client, DomainBlock, Executor, EFC>
96+
FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor, EFC>
9797
{
9898
pub fn new(
9999
consensus_client: Arc<Client>,
100100
executor: Arc<Executor>,
101-
domain_extensions_factory: Box<dyn ExtensionsFactory<DomainBlock>>,
101+
domain_extensions_factory_creator: EFC,
102102
) -> Self {
103103
FraudProofHostFunctionsImpl {
104104
consensus_client,
105105
executor,
106-
domain_extensions_factory,
106+
domain_extensions_factory_creator,
107107
_phantom: Default::default(),
108108
}
109109
}
110110
}
111111

112112
// TODO: Revisit the host function implementation once we decide best strategy to structure them.
113-
impl<Block, Client, DomainBlock, Executor>
114-
FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor>
113+
impl<Block, Client, DomainBlock, Executor, EFC>
114+
FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor, EFC>
115115
where
116116
Block: BlockT,
117117
Block::Hash: From<H256>,
@@ -120,6 +120,7 @@ where
120120
Client: BlockBackend<Block> + HeaderBackend<Block> + ProvideRuntimeApi<Block>,
121121
Client::Api: DomainsApi<Block, DomainBlock::Header> + BundleProducerElectionApi<Block, Balance>,
122122
Executor: CodeExecutor + RuntimeVersionOf,
123+
EFC: Fn(Arc<Client>, Arc<Executor>) -> Box<dyn ExtensionsFactory<DomainBlock>> + Send + Sync,
123124
{
124125
fn get_block_randomness(&self, consensus_block_hash: H256) -> Option<Randomness> {
125126
let runtime_api = self.consensus_client.runtime_api();
@@ -297,6 +298,36 @@ where
297298
.ok()
298299
}
299300

301+
fn is_valid_xdm(
302+
&self,
303+
consensus_block_hash: H256,
304+
domain_id: DomainId,
305+
opaque_extrinsic: OpaqueExtrinsic,
306+
) -> Option<bool> {
307+
let runtime_code = self.get_domain_runtime_code(consensus_block_hash, domain_id)?;
308+
let mut domain_stateless_runtime =
309+
StatelessRuntime::<DomainBlock, _>::new(self.executor.clone(), runtime_code.into());
310+
let extension_factory = (self.domain_extensions_factory_creator)(
311+
self.consensus_client.clone(),
312+
self.executor.clone(),
313+
);
314+
domain_stateless_runtime.set_extension_factory(extension_factory);
315+
316+
let consensus_api = self.consensus_client.runtime_api();
317+
let domain_initial_state = consensus_api
318+
.domain_instance_data(consensus_block_hash.into(), domain_id)
319+
.expect("Runtime Api must not fail. This is unrecoverable error")?
320+
.0
321+
.raw_genesis
322+
.into_storage();
323+
domain_stateless_runtime.set_storage(domain_initial_state);
324+
325+
let encoded_extrinsic = opaque_extrinsic.encode();
326+
domain_stateless_runtime
327+
.is_valid_xdm(encoded_extrinsic)
328+
.expect("Runtime api must not fail. This is an unrecoverable error")
329+
}
330+
300331
fn is_decodable_extrinsic(
301332
&self,
302333
consensus_block_hash: H256,
@@ -389,8 +420,8 @@ where
389420
}
390421
}
391422

392-
impl<Block, Client, DomainBlock, Executor> FraudProofHostFunctions
393-
for FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor>
423+
impl<Block, Client, DomainBlock, Executor, EFC> FraudProofHostFunctions
424+
for FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor, EFC>
394425
where
395426
Block: BlockT,
396427
Block::Hash: From<H256>,
@@ -400,6 +431,7 @@ where
400431
Client: BlockBackend<Block> + HeaderBackend<Block> + ProvideRuntimeApi<Block>,
401432
Client::Api: DomainsApi<Block, DomainBlock::Header> + BundleProducerElectionApi<Block, Balance>,
402433
Executor: CodeExecutor + RuntimeVersionOf,
434+
EFC: Fn(Arc<Client>, Arc<Executor>) -> Box<dyn ExtensionsFactory<DomainBlock>> + Send + Sync,
403435
{
404436
fn get_fraud_proof_verification_info(
405437
&self,
@@ -515,6 +547,12 @@ where
515547
self.storage_key(consensus_block_hash, domain_id, req),
516548
))
517549
}
550+
FraudProofVerificationInfoRequest::XDMValidationCheck {
551+
domain_id,
552+
opaque_extrinsic,
553+
} => Some(FraudProofVerificationInfoResponse::XDMValidationCheck(
554+
self.is_valid_xdm(consensus_block_hash, domain_id, opaque_extrinsic),
555+
)),
518556
}
519557
}
520558

@@ -574,9 +612,11 @@ where
574612
};
575613

576614
let (domain_block_number, domain_block_hash) = domain_block_id;
577-
let mut domain_extensions = self
578-
.domain_extensions_factory
579-
.extensions_for(domain_block_hash.into(), domain_block_number.into());
615+
let mut domain_extensions = (self.domain_extensions_factory_creator)(
616+
self.consensus_client.clone(),
617+
self.executor.clone(),
618+
)
619+
.extensions_for(domain_block_hash.into(), domain_block_number.into());
580620

581621
execution_proof_check::<<DomainBlock::Header as HeaderT>::Hashing, _>(
582622
pre_state_root.into(),

crates/sp-domains-fraud-proof/src/lib.rs

+16
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ pub enum FraudProofVerificationInfoRequest {
128128
/// Extrinsic for which we need to if it is decodable or not.
129129
opaque_extrinsic: OpaqueExtrinsic,
130130
},
131+
/// Request to check if the XDM is valid
132+
XDMValidationCheck {
133+
domain_id: DomainId,
134+
/// Encoded XDM extrinsic that needs to be validated.
135+
opaque_extrinsic: OpaqueExtrinsic,
136+
},
131137
/// Request to get Domain election params.
132138
DomainElectionParams { domain_id: DomainId },
133139
/// Request to get Operator stake.
@@ -186,6 +192,9 @@ pub enum FraudProofVerificationInfoResponse {
186192
TxRangeCheck(bool),
187193
/// If the particular extrinsic provided is either inherent or not.
188194
InherentExtrinsicCheck(bool),
195+
/// If the particular xdm extrinsic is valid or not.
196+
/// Returns None if extrinsic is not an XDM
197+
XDMValidationCheck(Option<bool>),
189198
/// If the domain extrinsic is decodable or not.
190199
ExtrinsicDecodableCheck(bool),
191200
/// Domain's total stake at a given Consensus hash.
@@ -264,6 +273,13 @@ impl FraudProofVerificationInfoResponse {
264273
}
265274
}
266275

276+
pub fn into_xdm_validation_check(self) -> Option<bool> {
277+
match self {
278+
FraudProofVerificationInfoResponse::XDMValidationCheck(maybe_valid) => maybe_valid,
279+
_ => None,
280+
}
281+
}
282+
267283
pub fn into_extrinsic_decodable_check(self) -> Option<bool> {
268284
match self {
269285
FraudProofVerificationInfoResponse::ExtrinsicDecodableCheck(is_decodable) => {

crates/sp-domains-fraud-proof/src/verification.rs

+25-2
Original file line numberDiff line numberDiff line change
@@ -633,9 +633,32 @@ where
633633
}
634634
Ok(())
635635
}
636+
InvalidBundleType::InvalidXDM(extrinsic_index) => {
637+
let extrinsic = get_extrinsic_from_proof::<DomainHeader>(
638+
*extrinsic_index,
639+
invalid_bundle_entry.extrinsics_root,
640+
invalid_bundles_fraud_proof.proof_data.clone(),
641+
)?;
636642

637-
// TODO: implement the other invalid bundle types
638-
_ => Err(VerificationError::InvalidProof),
643+
let is_valid_xdm = get_fraud_proof_verification_info(
644+
H256::from_slice(bad_receipt.consensus_block_hash.as_ref()),
645+
FraudProofVerificationInfoRequest::XDMValidationCheck {
646+
domain_id: invalid_bundles_fraud_proof.domain_id,
647+
opaque_extrinsic: extrinsic,
648+
},
649+
)
650+
.and_then(FraudProofVerificationInfoResponse::into_xdm_validation_check)
651+
.ok_or(VerificationError::FailedToValidateXDM)?;
652+
653+
// Proof to be considered valid only,
654+
// If it is true invalid fraud proof then extrinsic must be an invalid xdm and
655+
// If it is false invalid fraud proof then extrinsic must be a valid xdm
656+
if is_valid_xdm != invalid_bundles_fraud_proof.is_true_invalid_fraud_proof {
657+
Ok(())
658+
} else {
659+
Err(VerificationError::InvalidProof)
660+
}
661+
}
639662
}
640663
}
641664

crates/sp-domains/src/lib.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -1007,8 +1007,8 @@ impl InvalidBundleType {
10071007
Self::UndecodableTx(_) => 1,
10081008
Self::OutOfRangeTx(_) => 2,
10091009
Self::InherentExtrinsic(_) => 3,
1010-
Self::IllegalTx(_) => 4,
1011-
Self::InvalidXDM(_) => 5,
1010+
Self::InvalidXDM(_) => 4,
1011+
Self::IllegalTx(_) => 5,
10121012
}
10131013
}
10141014

@@ -1248,10 +1248,13 @@ sp_api::decl_runtime_apis! {
12481248
/// Returns the execution receipt hash of the given domain and domain block number
12491249
fn receipt_hash(domain_id: DomainId, domain_number: HeaderNumberFor<DomainHeader>) -> Option<HeaderHashFor<DomainHeader>>;
12501250

1251-
/// Reture the consensus chain byte fee that will used to charge the domain transaction for consensus
1251+
/// Return the consensus chain byte fee that will used to charge the domain transaction for consensus
12521252
/// chain storage fee
12531253
fn consensus_chain_byte_fee() -> Balance;
12541254

1255+
/// Returns the latest confirmed domain block number and hash
1256+
fn latest_confirmed_domain_block(domain_id: DomainId) -> Option<(HeaderNumberFor<DomainHeader>, HeaderHashFor<DomainHeader>)>;
1257+
12551258
/// Return if the receipt is exist and pending to prune
12561259
fn is_bad_er_pending_to_prune(domain_id: DomainId, receipt_hash: HeaderHashFor<DomainHeader>) -> bool;
12571260
}

0 commit comments

Comments
 (0)