Skip to content

Commit

Permalink
Handle large storage proofs.
Browse files Browse the repository at this point in the history
1. When the storage proof in InvalidStateTransitionProof
   exceeds a threshold, a summary of the storage proof is
   included in the fraud proof instead of the full storage
   proof.
2. The verifier is expected to recreate the storage proof
   and verify that the summary is correct.
  • Loading branch information
rahulksnv committed Oct 13, 2023
1 parent d0a1813 commit ae57b31
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 16 deletions.
40 changes: 38 additions & 2 deletions crates/sp-domains/src/fraud_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ use subspace_core_primitives::BlockNumber;
use subspace_runtime_primitives::{AccountId, Balance};
use trie_db::TrieLayout;

/// Maximum encoded size of storage proof.
/// TODO: fill the right size.
pub const MAX_STORAGE_PROOF_SIZE: usize = 64_000_000;

/// A phase of a block's execution, carrying necessary information needed for verifying the
/// invalid state transition proof.
#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
Expand Down Expand Up @@ -231,6 +235,38 @@ impl InvalidBundlesFraudProof {
}
}

/// State of the storage witness needed for verifying this proof.
#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
pub enum StorageWitness {
/// The storage proof included in the fraud proof.
Proof(StorageProof),

/// The storage proof size exceeded the max limit.
/// So instead of the storage proof, the summary is
/// included in the fraud proof.
SizeExceeded(StorageProofSummary),
}

/// Summary of the storage proof
#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
pub struct StorageProofSummary {
/// Encoded size of the storage proof.
proof_size: u64,

/// Hash of the storage proof.
proof_hash: H256,
}

impl From<&StorageProof> for StorageProofSummary {
fn from(proof: &StorageProof) -> Self {
let encoded = proof.encode();
Self {
proof_size: encoded.len() as u64,
proof_hash: BlakeTwo256::hash_of(&encoded),
}
}
}

/// Fraud proof.
// TODO: Revisit when fraud proof v2 is implemented.
#[allow(clippy::large_enum_variant)]
Expand Down Expand Up @@ -329,7 +365,7 @@ pub struct InvalidStateTransitionProof {
/// State root after the fraudulent transaction.
pub post_state_root: H256,
/// Proof recorded during the computation.
pub proof: StorageProof,
pub proof: StorageWitness,
/// Execution phase.
pub execution_phase: ExecutionPhase,
}
Expand All @@ -345,7 +381,7 @@ pub fn dummy_invalid_state_transition_proof(
consensus_parent_hash: H256::default(),
pre_state_root: H256::default(),
post_state_root: H256::default(),
proof: StorageProof::empty(),
proof: StorageWitness::Proof(StorageProof::empty()),
execution_phase: ExecutionPhase::ApplyExtrinsic(0),
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ use sc_client_api::backend;
use sp_api::{ProvideRuntimeApi, StorageProof};
use sp_core::traits::{CodeExecutor, RuntimeCode};
use sp_core::H256;
use sp_domains::fraud_proof::{ExecutionPhase, InvalidStateTransitionProof, VerificationError};
use sp_domains::fraud_proof::{
ExecutionPhase, InvalidStateTransitionProof, StorageWitness, VerificationError,
};
use sp_domains::DomainsApi;
use sp_runtime::traits::{BlakeTwo256, Block as BlockT, HashingFor, Header as HeaderT, NumberFor};
use sp_runtime::Digest;
Expand Down Expand Up @@ -285,6 +287,17 @@ where
ExecutionPhase::FinalizeBlock { .. } => Vec::new(),
};

let proof = match proof {
StorageWitness::Proof(proof) => proof,
StorageWitness::SizeExceeded(_) => {
// TODO: idea is to recreate the storage proof locally,
// and verify that the proof size indeed exceeds the threshold
// and matches the summary. To be determined: if all the
// info is available to recreate the storage proof locally.
return Ok(());
}
};

let execution_result = sp_state_machine::execution_proof_check::<BlakeTwo256, _>(
*pre_state_root,
proof.clone(),
Expand Down
14 changes: 7 additions & 7 deletions crates/subspace-fraud-proof/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use sp_api::ProvideRuntimeApi;
use sp_core::H256;
use sp_domain_digests::AsPredigest;
use sp_domains::fraud_proof::{
ExecutionPhase, FraudProof, InvalidStateTransitionProof, VerificationError,
ExecutionPhase, FraudProof, InvalidStateTransitionProof, StorageWitness, VerificationError,
};
use sp_domains::DomainId;
use sp_runtime::generic::{Digest, DigestItem};
Expand Down Expand Up @@ -283,7 +283,7 @@ async fn execution_proof_creation_and_verification_should_work() {
consensus_parent_hash,
pre_state_root: *parent_header.state_root(),
post_state_root: intermediate_roots[0].into(),
proof: storage_proof,
proof: StorageWitness::Proof(storage_proof),
execution_phase,
};
let fraud_proof = FraudProof::InvalidStateTransition(invalid_state_transition_proof);
Expand Down Expand Up @@ -340,7 +340,7 @@ async fn execution_proof_creation_and_verification_should_work() {
consensus_parent_hash,
pre_state_root: intermediate_roots[target_extrinsic_index].into(),
post_state_root: intermediate_roots[target_extrinsic_index + 1].into(),
proof: storage_proof,
proof: StorageWitness::Proof(storage_proof),
execution_phase,
};
let fraud_proof = FraudProof::InvalidStateTransition(invalid_state_transition_proof);
Expand Down Expand Up @@ -393,7 +393,7 @@ async fn execution_proof_creation_and_verification_should_work() {
consensus_parent_hash,
pre_state_root: intermediate_roots.last().unwrap().into(),
post_state_root: post_execution_root,
proof: storage_proof,
proof: StorageWitness::Proof(storage_proof),
execution_phase,
};
let fraud_proof = FraudProof::InvalidStateTransition(invalid_state_transition_proof);
Expand Down Expand Up @@ -570,7 +570,7 @@ async fn invalid_execution_proof_should_not_work() {
consensus_parent_hash,
pre_state_root: post_delta_root0,
post_state_root: post_delta_root1,
proof: proof1,
proof: StorageWitness::Proof(proof1),
execution_phase: execution_phase0.clone(),
};
let fraud_proof = FraudProof::InvalidStateTransition(invalid_state_transition_proof);
Expand All @@ -583,7 +583,7 @@ async fn invalid_execution_proof_should_not_work() {
consensus_parent_hash,
pre_state_root: post_delta_root0,
post_state_root: post_delta_root1,
proof: proof0.clone(),
proof: StorageWitness::Proof(proof0.clone()),
execution_phase: execution_phase1,
};
let fraud_proof = FraudProof::InvalidStateTransition(invalid_state_transition_proof);
Expand All @@ -596,7 +596,7 @@ async fn invalid_execution_proof_should_not_work() {
consensus_parent_hash,
pre_state_root: post_delta_root0,
post_state_root: post_delta_root1,
proof: proof0,
proof: StorageWitness::Proof(proof0),
execution_phase: execution_phase0,
};
let fraud_proof = FraudProof::InvalidStateTransition(invalid_state_transition_proof);
Expand Down
18 changes: 14 additions & 4 deletions domains/client/domain-operator/src/fraud_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ use sp_core::H256;
use sp_domains::fraud_proof::{
ExecutionPhase, ExtrinsicDigest, FraudProof, InvalidBundlesFraudProof,
InvalidExtrinsicsRootProof, InvalidStateTransitionProof, InvalidTotalRewardsProof,
MissingInvalidBundleEntryFraudProof, ValidAsInvalidBundleEntryFraudProof, ValidBundleDigest,
MissingInvalidBundleEntryFraudProof, StorageWitness, ValidAsInvalidBundleEntryFraudProof,
ValidBundleDigest, MAX_STORAGE_PROOF_SIZE,
};
use sp_domains::{DomainId, DomainsApi};
use sp_runtime::traits::{BlakeTwo256, Block as BlockT, HashingFor, Header as HeaderT, NumberFor};
Expand Down Expand Up @@ -310,7 +311,7 @@ where
consensus_parent_hash,
pre_state_root,
post_state_root,
proof,
proof: storage_witness(proof),
execution_phase,
}
} else if local_trace_index as usize == local_receipt.execution_trace.len() - 1 {
Expand Down Expand Up @@ -352,7 +353,7 @@ where
consensus_parent_hash,
pre_state_root,
post_state_root,
proof,
proof: storage_witness(proof),
execution_phase,
}
} else {
Expand All @@ -377,7 +378,7 @@ where
consensus_parent_hash,
pre_state_root,
post_state_root,
proof,
proof: storage_witness(proof),
execution_phase,
}
};
Expand Down Expand Up @@ -469,3 +470,12 @@ pub(crate) fn find_trace_mismatch<Hash: Copy + Eq>(
}
})
}

/// Builds the storage witness from the proof.
fn storage_witness(proof: StorageProof) -> StorageWitness {
if proof.encoded_size() <= MAX_STORAGE_PROOF_SIZE {
StorageWitness::Proof(proof)
} else {
StorageWitness::SizeExceeded((&proof).into())
}
}
4 changes: 2 additions & 2 deletions domains/client/domain-operator/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use sp_core::Pair;
use sp_domain_digests::AsPredigest;
use sp_domains::fraud_proof::{
ExecutionPhase, FraudProof, InvalidExtrinsicsRootProof, InvalidStateTransitionProof,
InvalidTotalRewardsProof,
InvalidTotalRewardsProof, StorageWitness,
};
use sp_domains::transaction::InvalidTransactionCode;
use sp_domains::{Bundle, DomainId, DomainsApi};
Expand Down Expand Up @@ -1212,7 +1212,7 @@ async fn fraud_proof_verification_in_tx_pool_should_work() {
consensus_parent_hash: parent_hash_ferdie,
pre_state_root: *parent_header.state_root(),
post_state_root: intermediate_roots[0].into(),
proof: storage_proof,
proof: StorageWitness::Proof(storage_proof),
execution_phase,
};
let valid_fraud_proof =
Expand Down

0 comments on commit ae57b31

Please sign in to comment.