Skip to content

Commit

Permalink
Merge pull request #2327 from subspace/illegal-tx-fraud-proof
Browse files Browse the repository at this point in the history
Illegal Tx fraud proof generation + verification
  • Loading branch information
ParthDesai authored Dec 22, 2023
2 parents 32ae21f + 7546c87 commit e26b7c8
Show file tree
Hide file tree
Showing 19 changed files with 1,399 additions and 252 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

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

6 changes: 6 additions & 0 deletions crates/pallet-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1716,8 +1716,14 @@ impl<T: Config> Pallet<T> {
})?;
}
FraudProof::InvalidBundles(invalid_bundles_fraud_proof) => {
let bad_receipt_parent =
BlockTreeNodes::<T>::get(bad_receipt.parent_domain_block_receipt_hash)
.ok_or(FraudProofError::ParentReceiptNotFound)?
.execution_receipt;

verify_invalid_bundles_fraud_proof::<T::Block, T::DomainHeader, BalanceOf<T>>(
bad_receipt,
bad_receipt_parent,
invalid_bundles_fraud_proof,
)
.map_err(|err| {
Expand Down
11 changes: 10 additions & 1 deletion crates/pallet-domains/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ pub(crate) struct MockDomainFraudProofExtension {
domain_total_stake: Balance,
bundle_slot_probability: (u64, u64),
operator_stake: Balance,
maybe_illegal_extrinsic_index: Option<u32>,
}

impl FraudProofHostFunctions for MockDomainFraudProofExtension {
Expand Down Expand Up @@ -339,6 +340,11 @@ impl FraudProofHostFunctions for MockDomainFraudProofExtension {
FraudProofVerificationInfoRequest::OperatorStake { .. } => {
FraudProofVerificationInfoResponse::OperatorStake(self.operator_stake)
}
FraudProofVerificationInfoRequest::CheckExtrinsicsInSingleContext { .. } => {
FraudProofVerificationInfoResponse::CheckExtrinsicsInSingleContext(
self.maybe_illegal_extrinsic_index,
)
}
};

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

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

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

Expand Down Expand Up @@ -1200,7 +1209,7 @@ fn generate_invalid_bundle_inherent_extrinsic_fraud_proof<T: Config>(
bad_receipt_hash,
bundle_index,
invalid_bundle_type: InvalidBundleType::InherentExtrinsic(bundle_extrinsic_index),
extrinsic_inclusion_proof,
proof_data: extrinsic_inclusion_proof,
is_true_invalid_fraud_proof,
})
}
Expand Down
10 changes: 10 additions & 0 deletions crates/sp-domains-fraud-proof/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,19 @@ thiserror = { version = "1.0.48", optional = true }
domain-block-builder = { version = "0.1.0", path = "../../domains/client/block-builder" }
domain-block-preprocessor = { version = "0.1.0", path = "../../domains/client/block-preprocessor" }
domain-test-service = { version = "0.1.0", path = "../../domains/test/service" }
ethereum = "0.14.0"
fp-rpc = { version = "3.0.0-dev", git = "https://github.com/subspace/frontier", rev = "1c667eb43c3d087ac66dc9ed0aa44128373f5b0a", features = ['default'] }
fp-self-contained = { version = "1.0.0-dev", git = "https://github.com/subspace/frontier", rev = "1c667eb43c3d087ac66dc9ed0aa44128373f5b0a", features = ['default'] }
frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "0831dfc3c54b10ab46e82acf98603b4af1a47bd5" }
frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "0831dfc3c54b10ab46e82acf98603b4af1a47bd5" }
futures = "0.3.29"
libsecp256k1 = { version = "0.7.1", features = ["static-context", "hmac"] }
pallet-balances = { version = "4.0.0-dev", git = "https://github.com/subspace/polkadot-sdk", rev = "0831dfc3c54b10ab46e82acf98603b4af1a47bd5" }
pallet-ethereum = { version = "4.0.0-dev", git = "https://github.com/subspace/frontier", rev = "1c667eb43c3d087ac66dc9ed0aa44128373f5b0a", features = ['default'] }
pallet-evm = { version = "6.0.0-dev", git = "https://github.com/subspace/frontier", rev = "1c667eb43c3d087ac66dc9ed0aa44128373f5b0a", default-features = false }
rand = { version = "0.8.5", features = ["min_const_gen"] }
rlp = "0.5.2"
sp-core = { version = "21.0.0", default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "0831dfc3c54b10ab46e82acf98603b4af1a47bd5" }
sc-cli = { version = "0.10.0-dev", git = "https://github.com/subspace/polkadot-sdk", rev = "0831dfc3c54b10ab46e82acf98603b4af1a47bd5", default-features = false }
sc-executor = { version = "0.10.0-dev", git = "https://github.com/subspace/polkadot-sdk", rev = "0831dfc3c54b10ab46e82acf98603b4af1a47bd5", default-features = false }
sc-service = { version = "0.10.0-dev", git = "https://github.com/subspace/polkadot-sdk", rev = "0831dfc3c54b10ab46e82acf98603b4af1a47bd5", default-features = false }
Expand Down
12 changes: 9 additions & 3 deletions crates/sp-domains-fraud-proof/src/fraud_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,12 @@ pub enum VerificationError<DomainHash> {
error("Invalid bundle equivocation fraud proof: {0}")
)]
InvalidBundleEquivocationFraudProof(InvalidBundleEquivocationError),
/// Failed to check extrinsics in single context
#[cfg_attr(
feature = "thiserror",
error("Failed to check extrinsics in single context")
)]
FailedToCheckExtrinsicsInSingleContext,
}

impl<DomainHash> From<InvalidBundleEquivocationError> for VerificationError<DomainHash> {
Expand All @@ -338,7 +344,7 @@ pub struct InvalidBundlesFraudProof<ReceiptHash> {
pub domain_id: DomainId,
pub bundle_index: u32,
pub invalid_bundle_type: InvalidBundleType,
pub extrinsic_inclusion_proof: StorageProof,
pub proof_data: StorageProof,
pub is_true_invalid_fraud_proof: bool,
}

Expand All @@ -348,15 +354,15 @@ impl<ReceiptHash> InvalidBundlesFraudProof<ReceiptHash> {
domain_id: DomainId,
bundle_index: u32,
invalid_bundle_type: InvalidBundleType,
extrinsic_inclusion_proof: StorageProof,
proof_data: StorageProof,
is_true_invalid_fraud_proof: bool,
) -> Self {
Self {
bad_receipt_hash,
domain_id,
bundle_index,
invalid_bundle_type,
extrinsic_inclusion_proof,
proof_data,
is_true_invalid_fraud_proof,
}
}
Expand Down
56 changes: 56 additions & 0 deletions crates/sp-domains-fraud-proof/src/host_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use crate::{
use codec::{Decode, Encode};
use domain_block_preprocessor::inherents::extract_domain_runtime_upgrade_code;
use domain_block_preprocessor::stateless_runtime::StatelessRuntime;
use domain_runtime_primitives::{
CheckExtrinsicsValidityError, CHECK_EXTRINSICS_AND_DO_PRE_DISPATCH_METHOD_NAME,
};
use sc_client_api::BlockBackend;
use sc_executor::RuntimeVersionOf;
use sp_api::{BlockT, HashT, ProvideRuntimeApi};
Expand Down Expand Up @@ -97,6 +100,7 @@ where
Block: BlockT,
Block::Hash: From<H256>,
DomainBlock: BlockT,
DomainBlock::Hash: From<H256> + Into<H256>,
Client: BlockBackend<Block> + HeaderBackend<Block> + ProvideRuntimeApi<Block>,
Client::Api: DomainsApi<Block, DomainBlock::Header> + BundleProducerElectionApi<Block, Balance>,
Executor: CodeExecutor + RuntimeVersionOf,
Expand Down Expand Up @@ -282,6 +286,37 @@ where
.ok()??;
Some(operator_stake)
}

fn check_extrinsics_in_single_context(
&self,
consensus_block_hash: H256,
domain_id: DomainId,
domain_block_id: (u32, H256),
domain_block_state_root: H256,
bundle_extrinsics: Vec<OpaqueExtrinsic>,
storage_proof: StorageProof,
) -> Option<Option<u32>> {
let (domain_block_number, domain_block_hash) = domain_block_id;

let runtime_code = self.get_domain_runtime_code(consensus_block_hash, domain_id)?;

let raw_response = self.execution_proof_check(
domain_block_state_root,
storage_proof.encode(),
CHECK_EXTRINSICS_AND_DO_PRE_DISPATCH_METHOD_NAME,
// The call data must be encoded form of arguments to `DomainCoreApi::check_extrinsic_and_do_pre_dispatch`
&(&bundle_extrinsics, &domain_block_number, &domain_block_hash).encode(),
runtime_code,
)?;

let bundle_extrinsics_validity_response: Result<(), CheckExtrinsicsValidityError> =
Decode::decode(&mut raw_response.as_slice()).ok()?;
if let Err(bundle_extrinsic_validity_error) = bundle_extrinsics_validity_response {
Some(Some(bundle_extrinsic_validity_error.extrinsic_index))
} else {
Some(None)
}
}
}

impl<Block, Client, DomainBlock, Executor> FraudProofHostFunctions
Expand Down Expand Up @@ -368,6 +403,27 @@ where
.map(|operator_stake| {
FraudProofVerificationInfoResponse::OperatorStake(operator_stake)
}),
FraudProofVerificationInfoRequest::CheckExtrinsicsInSingleContext {
domain_id,
domain_block_number,
domain_block_hash,
domain_block_state_root,
extrinsics,
storage_proof,
} => self
.check_extrinsics_in_single_context(
consensus_block_hash,
domain_id,
(domain_block_number, domain_block_hash),
domain_block_state_root,
extrinsics,
storage_proof,
)
.map(|transactions_check_result| {
FraudProofVerificationInfoResponse::CheckExtrinsicsInSingleContext(
transactions_check_result,
)
}),
}
}

Expand Down
31 changes: 31 additions & 0 deletions crates/sp-domains-fraud-proof/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ mod host_functions;
mod runtime_interface;
#[cfg(test)]
mod tests;

#[cfg(test)]
pub mod test_ethereum_tx;

pub mod verification;

use crate::fraud_proof::FraudProof;
Expand All @@ -40,13 +44,15 @@ pub use runtime_interface::fraud_proof_runtime_interface;
pub use runtime_interface::fraud_proof_runtime_interface::HostFunctions;
use sp_api::scale_info::TypeInfo;
use sp_api::HeaderT;
use sp_core::H256;
use sp_domains::{DomainId, OperatorId};
use sp_runtime::traits::NumberFor;
use sp_runtime::transaction_validity::{InvalidTransaction, TransactionValidity};
use sp_runtime::OpaqueExtrinsic;
use sp_runtime_interface::pass_by;
use sp_runtime_interface::pass_by::PassBy;
use sp_std::vec::Vec;
use sp_trie::StorageProof;
use subspace_core_primitives::Randomness;
use subspace_runtime_primitives::Balance;

Expand Down Expand Up @@ -108,6 +114,20 @@ pub enum FraudProofVerificationInfoRequest {
DomainElectionParams { domain_id: DomainId },
/// Request to get Operator stake.
OperatorStake { operator_id: OperatorId },
/// Request to check extrinsics in single context
CheckExtrinsicsInSingleContext {
domain_id: DomainId,
/// Domain block number from ER
domain_block_number: u32,
/// Domain block hash from ER
domain_block_hash: H256,
/// Domain block state root from ER
domain_block_state_root: H256,
/// Extrinsics which we want to check in single context
extrinsics: Vec<OpaqueExtrinsic>,
/// Storage proof for the keys used in validating the extrinsic
storage_proof: StorageProof,
},
}

impl PassBy for FraudProofVerificationInfoRequest {
Expand Down Expand Up @@ -147,6 +167,8 @@ pub enum FraudProofVerificationInfoResponse {
},
/// Operators Stake at a given Consensus hash.
OperatorStake(Balance),
/// Result of check extrinsics in single context
CheckExtrinsicsInSingleContext(Option<u32>),
}

impl FraudProofVerificationInfoResponse {
Expand Down Expand Up @@ -221,6 +243,15 @@ impl FraudProofVerificationInfoResponse {
_ => None,
}
}

pub fn into_single_context_extrinsic_check(self) -> Option<Option<u32>> {
match self {
FraudProofVerificationInfoResponse::CheckExtrinsicsInSingleContext(result) => {
Some(result)
}
_ => None,
}
}
}

sp_api::decl_runtime_apis! {
Expand Down
Loading

0 comments on commit e26b7c8

Please sign in to comment.