Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XDM: Relayer and Fraud proof updates #2562

Merged
merged 6 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion Cargo.lock

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

7 changes: 7 additions & 0 deletions crates/pallet-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1986,6 +1986,13 @@ impl<T: Config> Pallet<T> {
.unwrap_or_default()
}

pub fn latest_confirmed_domain_block(
domain_id: DomainId,
) -> Option<(DomainBlockNumberFor<T>, T::DomainHash)> {
LatestConfirmedDomainBlock::<T>::get(domain_id)
.map(|block| (block.block_number, block.block_hash))
}

/// Returns the domain block limit of the given domain.
pub fn domain_block_limit(domain_id: DomainId) -> Option<DomainBlockLimit> {
DomainRegistry::<T>::get(domain_id).map(|domain_obj| DomainBlockLimit {
Expand Down
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 @@ -1016,6 +1020,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 @@ -1097,6 +1102,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 @@ -1164,6 +1170,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 @@ -386,6 +386,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
66 changes: 53 additions & 13 deletions crates/sp-domains-fraud-proof/src/host_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,33 +85,33 @@ impl FraudProofExtension {
}

/// Trait Impl to query and verify Domains Fraud proof.
pub struct FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor> {
pub struct FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor, EFC> {
consensus_client: Arc<Client>,
executor: Arc<Executor>,
domain_extensions_factory: Box<dyn ExtensionsFactory<DomainBlock>>,
domain_extensions_factory_creator: EFC,
_phantom: PhantomData<(Block, DomainBlock)>,
}

impl<Block, Client, DomainBlock, Executor>
FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor>
impl<Block, Client, DomainBlock, Executor, EFC>
FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor, EFC>
{
pub fn new(
consensus_client: Arc<Client>,
executor: Arc<Executor>,
domain_extensions_factory: Box<dyn ExtensionsFactory<DomainBlock>>,
domain_extensions_factory_creator: EFC,
) -> Self {
FraudProofHostFunctionsImpl {
consensus_client,
executor,
domain_extensions_factory,
domain_extensions_factory_creator,
_phantom: Default::default(),
}
}
}

// TODO: Revisit the host function implementation once we decide best strategy to structure them.
impl<Block, Client, DomainBlock, Executor>
FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor>
impl<Block, Client, DomainBlock, Executor, EFC>
FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor, EFC>
where
Block: BlockT,
Block::Hash: From<H256>,
Expand All @@ -120,6 +120,7 @@ where
Client: BlockBackend<Block> + HeaderBackend<Block> + ProvideRuntimeApi<Block>,
Client::Api: DomainsApi<Block, DomainBlock::Header> + BundleProducerElectionApi<Block, Balance>,
Executor: CodeExecutor + RuntimeVersionOf,
EFC: Fn(Arc<Client>, Arc<Executor>) -> Box<dyn ExtensionsFactory<DomainBlock>> + Send + Sync,
{
fn get_block_randomness(&self, consensus_block_hash: H256) -> Option<Randomness> {
let runtime_api = self.consensus_client.runtime_api();
Expand Down Expand Up @@ -297,6 +298,36 @@ 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 mut domain_stateless_runtime =
StatelessRuntime::<DomainBlock, _>::new(self.executor.clone(), runtime_code.into());
let extension_factory = (self.domain_extensions_factory_creator)(
self.consensus_client.clone(),
self.executor.clone(),
);
domain_stateless_runtime.set_extension_factory(extension_factory);

let consensus_api = self.consensus_client.runtime_api();
let domain_initial_state = consensus_api
.domain_instance_data(consensus_block_hash.into(), domain_id)
.expect("Runtime Api must not fail. This is unrecoverable error")?
.0
.raw_genesis
.into_storage();
domain_stateless_runtime.set_storage(domain_initial_state);

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 @@ -389,8 +420,8 @@ where
}
}

impl<Block, Client, DomainBlock, Executor> FraudProofHostFunctions
for FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor>
impl<Block, Client, DomainBlock, Executor, EFC> FraudProofHostFunctions
for FraudProofHostFunctionsImpl<Block, Client, DomainBlock, Executor, EFC>
where
Block: BlockT,
Block::Hash: From<H256>,
Expand All @@ -400,6 +431,7 @@ where
Client: BlockBackend<Block> + HeaderBackend<Block> + ProvideRuntimeApi<Block>,
Client::Api: DomainsApi<Block, DomainBlock::Header> + BundleProducerElectionApi<Block, Balance>,
Executor: CodeExecutor + RuntimeVersionOf,
EFC: Fn(Arc<Client>, Arc<Executor>) -> Box<dyn ExtensionsFactory<DomainBlock>> + Send + Sync,
{
fn get_fraud_proof_verification_info(
&self,
Expand Down Expand Up @@ -515,6 +547,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 Expand Up @@ -574,9 +612,11 @@ where
};

let (domain_block_number, domain_block_hash) = domain_block_id;
let mut domain_extensions = self
.domain_extensions_factory
.extensions_for(domain_block_hash.into(), domain_block_number.into());
let mut domain_extensions = (self.domain_extensions_factory_creator)(
self.consensus_client.clone(),
self.executor.clone(),
)
.extensions_for(domain_block_hash.into(), domain_block_number.into());

execution_proof_check::<<DomainBlock::Header as HeaderT>::Hashing, _>(
pre_state_root.into(),
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 @@ -128,6 +128,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 @@ -186,6 +192,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 @@ -264,6 +273,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 @@ -633,9 +633,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 an invalid xdm and
// If it is false invalid fraud proof then extrinsic must be a valid xdm
if is_valid_xdm != invalid_bundles_fraud_proof.is_true_invalid_fraud_proof {
Ok(())
} else {
Err(VerificationError::InvalidProof)
}
}
}
}

Expand Down
9 changes: 6 additions & 3 deletions crates/sp-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1007,8 +1007,8 @@ impl InvalidBundleType {
Self::UndecodableTx(_) => 1,
Self::OutOfRangeTx(_) => 2,
Self::InherentExtrinsic(_) => 3,
Self::IllegalTx(_) => 4,
Self::InvalidXDM(_) => 5,
Self::InvalidXDM(_) => 4,
Self::IllegalTx(_) => 5,
}
}

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

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

/// Returns the latest confirmed domain block number and hash
fn latest_confirmed_domain_block(domain_id: DomainId) -> Option<(HeaderNumberFor<DomainHeader>, HeaderHashFor<DomainHeader>)>;

/// Return if the receipt is exist and pending to prune
fn is_bad_er_pending_to_prune(domain_id: DomainId, receipt_hash: HeaderHashFor<DomainHeader>) -> bool;
}
Expand Down
Loading
Loading