Skip to content

Commit

Permalink
Merge pull request #2638 from subspace/domain-compatible-3h
Browse files Browse the repository at this point in the history
Keep domain compatible with gemini-3h
  • Loading branch information
NingLin-P authored Mar 25, 2024
2 parents 7d420f7 + 7ae1d26 commit 360fb7e
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 5 deletions.
2 changes: 1 addition & 1 deletion crates/pallet-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1549,7 +1549,7 @@ mod pallet {
if let Err(e) = Self::validate_fraud_proof(fraud_proof) {
log::warn!(
target: "runtime::domains",
"Bad fraud proof {:?}, error: {e:?}", fraud_proof.domain_id(),
"Bad fraud proof {fraud_proof:?}, error: {e:?}",
);
return InvalidTransactionCode::FraudProof.into();
}
Expand Down
77 changes: 76 additions & 1 deletion crates/sp-domains-fraud-proof/src/fraud_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::verification::InvalidBundleEquivocationError;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use codec::{Decode, Encode};
use core::fmt;
use scale_info::TypeInfo;
use sp_consensus_slots::Slot;
use sp_core::H256;
Expand Down Expand Up @@ -454,7 +455,7 @@ impl<ReceiptHash> InvalidBundlesFraudProof<ReceiptHash> {
/// Fraud proof.
// TODO: Revisit when fraud proof v2 is implemented.
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
#[derive(Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
pub enum FraudProof<Number, Hash, DomainHeader: HeaderT> {
InvalidStateTransition(InvalidStateTransitionProof<HeaderHashFor<DomainHeader>>),
InvalidTransaction(InvalidTransactionProof<HeaderHashFor<DomainHeader>>),
Expand Down Expand Up @@ -550,6 +551,80 @@ where
}
}

impl<Number, Hash, DomainHeader: HeaderT> fmt::Debug for FraudProof<Number, Hash, DomainHeader> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let domain_id = self.domain_id();
let bad_receipt_hash = self.targeted_bad_receipt_hash();
let bad_operator = self.targeted_bad_operator_and_slot_for_bundle_equivocation();
match self {
Self::InvalidStateTransition(_) => {
write!(
f,
"InvalidStateTransitionFraudProof({domain_id:?}#{bad_receipt_hash:?})"
)
}
Self::InvalidTransaction(_) => {
write!(
f,
"InvalidTransactionFraudProof({domain_id:?}#{bad_receipt_hash:?})"
)
}
Self::ImproperTransactionSortition(_) => {
write!(
f,
"ImproperTransactionSortitionFraudProof({domain_id:?}#{bad_receipt_hash:?})"
)
}
Self::BundleEquivocation(_) => {
write!(
f,
"BundleEquivocationFraudProof({domain_id:?}#{bad_operator:?})"
)
}
Self::InvalidExtrinsicsRoot(_) => {
write!(
f,
"InvalidExtrinsicsRootFraudProof({domain_id:?}#{bad_receipt_hash:?})"
)
}
Self::InvalidBlockFees(_) => {
write!(
f,
"InvalidBlockFeesFraudProof({domain_id:?}#{bad_receipt_hash:?})"
)
}
Self::ValidBundle(_) => {
write!(
f,
"ValidBundleFraudProof({domain_id:?}#{bad_receipt_hash:?})"
)
}
Self::InvalidBundles(_) => {
write!(
f,
"InvalidBundlesFraudProof({domain_id:?}#{bad_receipt_hash:?})"
)
}
Self::InvalidDomainBlockHash(_) => {
write!(
f,
"InvalidDomainBlockHashFraudProof({domain_id:?}#{bad_receipt_hash:?})"
)
}
Self::InvalidTransfers(_) => {
write!(
f,
"InvalidTransfersFraudProof({domain_id:?}#{bad_receipt_hash:?})"
)
}
#[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
Self::Dummy { .. } => {
write!(f, "DummyFraudProof({domain_id:?}#{bad_receipt_hash:?})")
}
}
}
}

/// Proves an invalid state transition by challenging the trace at specific index in a bad receipt.
#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
pub struct InvalidStateTransitionProof<ReceiptHash> {
Expand Down
24 changes: 21 additions & 3 deletions domains/client/block-builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ where
backend: &'a B,
mut extrinsics: VecDeque<Block::Extrinsic>,
maybe_inherent_data: Option<sp_inherents::InherentData>,
is_gemini_3h: bool,
) -> Result<Self, Error> {
let header = <<Block as BlockT>::Header as HeaderT>::new(
parent_number + One::one(),
Expand All @@ -179,9 +180,26 @@ where

if let Some(inherent_data) = maybe_inherent_data {
let inherent_extrinsics = Self::create_inherents(parent_hash, &api, inherent_data)?;
// reverse and push the inherents so that order is maintained
for inherent_extrinsic in inherent_extrinsics.into_iter().rev() {
extrinsics.push_front(inherent_extrinsic)

// TODO: This is used to keep compatible with gemini-3h, remove before next network
//
// HACK: ideally, any network should maintain the inherent extrinsic order to keep consistency
// with the order in the fraud proof verifiaction side, but in gemini-3h, the domain inherent
// extrinsic order is changed in the ER that derived from the consensus block #168431, we have
// to follow this change in the client side to ensure every domain node that sync from genesis
// will produce the same ER and hence can successfully submit ER to exend the previous ER.
let maintain_runtime_inherent_extrinsic_order =
!is_gemini_3h || parent_number >= 168430u32.into();

if maintain_runtime_inherent_extrinsic_order {
// reverse and push the inherents so that order is maintained
for inherent_extrinsic in inherent_extrinsics.into_iter().rev() {
extrinsics.push_front(inherent_extrinsic)
}
} else {
for inherent_extrinsic in inherent_extrinsics {
extrinsics.push_front(inherent_extrinsic)
}
}
}

Expand Down
12 changes: 12 additions & 0 deletions domains/client/domain-operator/src/domain_block_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor, One, Zer
use sp_runtime::{Digest, Saturating};
use std::cmp::Ordering;
use std::collections::VecDeque;
use std::str::FromStr;
use std::sync::Arc;

struct DomainBlockBuildResult<Block>
Expand Down Expand Up @@ -419,6 +420,15 @@ where
inherent_digests: Digest,
inherent_data: sp_inherents::InherentData,
) -> Result<DomainBlockBuildResult<Block>, sp_blockchain::Error> {
// TODO: This is used to keep compatible with gemini-3h, remove before next network
let is_gemini_3h = self.consensus_client.info().genesis_hash
== FromStr::from_str(
// The genesis hash of gemini-3h
"0c121c75f4ef450f40619e1fca9d1e8e7fbabc42c895bc4790801e85d5a91c34",
)
.map_err(|_| ())
.expect("parsing consensus block hash should success");

let block_builder = BlockBuilder::new(
&*self.client,
parent_hash,
Expand All @@ -428,6 +438,7 @@ where
&*self.backend,
extrinsics,
Some(inherent_data),
is_gemini_3h,
)?;

let BuiltBlock {
Expand Down Expand Up @@ -749,6 +760,7 @@ where
if let Some(mismatched_receipts) = self.find_mismatch_receipt(consensus_block_hash)? {
let fraud_proof = self.generate_fraud_proof(mismatched_receipts)?;

tracing::info!("Submit fraud proof: {fraud_proof:?}");
let consensus_best_hash = self.consensus_client.info().best_hash;
let mut runtime_api = self.consensus_client.runtime_api();
runtime_api.register_extension(
Expand Down
5 changes: 5 additions & 0 deletions domains/client/domain-operator/src/fraud_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,12 @@ where
inherent_digests.clone(),
&*self.backend,
extrinsics.into(),
// NOTE: the inherent extrinsic is already contained in the above `extrinsics`, which
// is getting from the block body, thus it is okay to pass `maybe_inherent_data` as
// `None` and `is_gemini_3h` as `false`, the latter is only used when `maybe_inherent_data`
// is `Some`.
None,
false,
)?;

let (storage_changes, call_data) = match &execution_phase {
Expand Down

0 comments on commit 360fb7e

Please sign in to comment.