Skip to content

Commit

Permalink
add fraud proof verification for XDM on domains
Browse files Browse the repository at this point in the history
  • Loading branch information
vedhavyas committed Feb 26, 2024
1 parent afd4f94 commit 19f1bab
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 6 deletions.
7 changes: 7 additions & 0 deletions crates/pallet-domains/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ pub(crate) struct MockDomainFraudProofExtension {
bundle_slot_probability: (u64, u64),
operator_stake: Balance,
maybe_illegal_extrinsic_index: Option<u32>,
is_valid_xdm: Option<bool>,
}

impl FraudProofHostFunctions for MockDomainFraudProofExtension {
Expand Down Expand Up @@ -432,6 +433,9 @@ impl FraudProofHostFunctions for MockDomainFraudProofExtension {
FraudProofVerificationInfoRequest::StorageKey { .. } => {
FraudProofVerificationInfoResponse::StorageKey(None)
}
FraudProofVerificationInfoRequest::XDMValidationCheck { .. } => {
FraudProofVerificationInfoResponse::XDMValidationCheck(self.is_valid_xdm)
}
};

Some(response)
Expand Down Expand Up @@ -1032,6 +1036,7 @@ fn test_invalid_domain_extrinsic_root_proof() {
operator_stake: 10 * SSC,
bundle_slot_probability: (0, 0),
maybe_illegal_extrinsic_index: None,
is_valid_xdm: None,
}));
ext.register_extension(fraud_proof_ext);

Expand Down Expand Up @@ -1113,6 +1118,7 @@ fn test_true_invalid_bundles_inherent_extrinsic_proof() {
operator_stake: 10 * SSC,
bundle_slot_probability: (0, 0),
maybe_illegal_extrinsic_index: None,
is_valid_xdm: None,
}));
ext.register_extension(fraud_proof_ext);

Expand Down Expand Up @@ -1180,6 +1186,7 @@ fn test_false_invalid_bundles_inherent_extrinsic_proof() {
operator_stake: 10 * SSC,
bundle_slot_probability: (0, 0),
maybe_illegal_extrinsic_index: None,
is_valid_xdm: None,
}));
ext.register_extension(fraud_proof_ext);

Expand Down
3 changes: 3 additions & 0 deletions crates/sp-domains-fraud-proof/src/fraud_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,9 @@ pub enum VerificationError<DomainHash> {
error("Failed to check if a given extrinsic is inherent or not")
)]
FailedToCheckInherentExtrinsic,
/// Failed to check if a given extrinsic is inherent or not.
#[cfg_attr(feature = "thiserror", error("Failed to validate given XDM"))]
FailedToValidateXDM,
/// Failed to check if a given extrinsic is decodable or not.
#[cfg_attr(
feature = "thiserror",
Expand Down
23 changes: 23 additions & 0 deletions crates/sp-domains-fraud-proof/src/host_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,23 @@ where
.ok()
}

fn is_valid_xdm(
&self,
consensus_block_hash: H256,
domain_id: DomainId,
opaque_extrinsic: OpaqueExtrinsic,
) -> Option<bool> {
let runtime_code = self.get_domain_runtime_code(consensus_block_hash, domain_id)?;

let domain_stateless_runtime =
StatelessRuntime::<DomainBlock, _>::new(self.executor.clone(), runtime_code.into());

let encoded_extrinsic = opaque_extrinsic.encode();
domain_stateless_runtime
.is_valid_xdm(encoded_extrinsic)
.expect("Runtime api must not fail. This is an unrecoverable error")
}

fn is_decodable_extrinsic(
&self,
consensus_block_hash: H256,
Expand Down Expand Up @@ -511,6 +528,12 @@ where
self.storage_key(consensus_block_hash, domain_id, req),
))
}
FraudProofVerificationInfoRequest::XDMValidationCheck {
domain_id,
opaque_extrinsic,
} => Some(FraudProofVerificationInfoResponse::XDMValidationCheck(
self.is_valid_xdm(consensus_block_hash, domain_id, opaque_extrinsic),
)),
}
}

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 @@ -126,6 +126,12 @@ pub enum FraudProofVerificationInfoRequest {
/// Extrinsic for which we need to if it is decodable or not.
opaque_extrinsic: OpaqueExtrinsic,
},
/// Request to check if the XDM is valid
XDMValidationCheck {
domain_id: DomainId,
/// Encoded XDM extrinsic that needs to be validated.
opaque_extrinsic: OpaqueExtrinsic,
},
/// Request to get Domain election params.
DomainElectionParams { domain_id: DomainId },
/// Request to get Operator stake.
Expand Down Expand Up @@ -184,6 +190,9 @@ pub enum FraudProofVerificationInfoResponse {
TxRangeCheck(bool),
/// If the particular extrinsic provided is either inherent or not.
InherentExtrinsicCheck(bool),
/// If the particular xdm extrinsic is valid or not.
/// Returns None if extrinsic is not an XDM
XDMValidationCheck(Option<bool>),
/// If the domain extrinsic is decodable or not.
ExtrinsicDecodableCheck(bool),
/// Domain's total stake at a given Consensus hash.
Expand Down Expand Up @@ -262,6 +271,13 @@ impl FraudProofVerificationInfoResponse {
}
}

pub fn into_xdm_validation_check(self) -> Option<bool> {
match self {
FraudProofVerificationInfoResponse::XDMValidationCheck(maybe_valid) => maybe_valid,
_ => None,
}
}

pub fn into_extrinsic_decodable_check(self) -> Option<bool> {
match self {
FraudProofVerificationInfoResponse::ExtrinsicDecodableCheck(is_decodable) => {
Expand Down
27 changes: 25 additions & 2 deletions crates/sp-domains-fraud-proof/src/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -629,9 +629,32 @@ where
}
Ok(())
}
InvalidBundleType::InvalidXDM(extrinsic_index) => {
let extrinsic = get_extrinsic_from_proof::<DomainHeader>(
*extrinsic_index,
invalid_bundle_entry.extrinsics_root,
invalid_bundles_fraud_proof.proof_data.clone(),
)?;

// TODO: implement the other invalid bundle types
_ => Err(VerificationError::InvalidProof),
let is_valid_xdm = get_fraud_proof_verification_info(
H256::from_slice(bad_receipt.consensus_block_hash.as_ref()),
FraudProofVerificationInfoRequest::XDMValidationCheck {
domain_id: invalid_bundles_fraud_proof.domain_id,
opaque_extrinsic: extrinsic,
},
)
.and_then(FraudProofVerificationInfoResponse::into_xdm_validation_check)
.ok_or(VerificationError::FailedToValidateXDM)?;

// Proof to be considered valid only,
// If it is true invalid fraud proof then extrinsic must be a valid xdm and
// If it is false invalid fraud proof then extrinsic must not be a valid xdm
if is_valid_xdm == invalid_bundles_fraud_proof.is_true_invalid_fraud_proof {
Ok(())
} else {
Err(VerificationError::InvalidProof)
}
}
}
}

Expand Down
4 changes: 0 additions & 4 deletions domains/client/block-preprocessor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,11 +316,7 @@ where
)));
}

// TODO: the behavior is changed, as before invalid XDM will be dropped silently,
// and the other extrinsic of the bundle will be continue processed, now the whole
// bundle is considered as invalid and excluded from further processing.
if let Some(false) = runtime_api.is_xdm_valid(at, extrinsic.encode())? {
// TODO: Generate a fraud proof for this invalid bundle
return Ok(BundleValidity::Invalid(InvalidBundleType::InvalidXDM(
index as u32,
)));
Expand Down
8 changes: 8 additions & 0 deletions domains/client/block-preprocessor/src/stateless_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,14 @@ where
<Self as DomainCoreApi<Block>>::is_inherent_extrinsic(self, Default::default(), extrinsic)
}

pub fn is_valid_xdm(&self, extrinsic: Vec<u8>) -> Result<Option<bool>, ApiError> {
<Self as MessengerApi<Block, NumberFor<Block>>>::is_xdm_valid(
self,
Default::default(),
extrinsic,
)
}

pub fn decode_extrinsic(
&self,
opaque_extrinsic: sp_runtime::OpaqueExtrinsic,
Expand Down

0 comments on commit 19f1bab

Please sign in to comment.