Skip to content

Commit 360fb7e

Browse files
authored
Merge pull request #2638 from subspace/domain-compatible-3h
Keep domain compatible with gemini-3h
2 parents 7d420f7 + 7ae1d26 commit 360fb7e

File tree

5 files changed

+115
-5
lines changed

5 files changed

+115
-5
lines changed

crates/pallet-domains/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1549,7 +1549,7 @@ mod pallet {
15491549
if let Err(e) = Self::validate_fraud_proof(fraud_proof) {
15501550
log::warn!(
15511551
target: "runtime::domains",
1552-
"Bad fraud proof {:?}, error: {e:?}", fraud_proof.domain_id(),
1552+
"Bad fraud proof {fraud_proof:?}, error: {e:?}",
15531553
);
15541554
return InvalidTransactionCode::FraudProof.into();
15551555
}

crates/sp-domains-fraud-proof/src/fraud_proof.rs

+76-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::verification::InvalidBundleEquivocationError;
55
#[cfg(not(feature = "std"))]
66
use alloc::vec::Vec;
77
use codec::{Decode, Encode};
8+
use core::fmt;
89
use scale_info::TypeInfo;
910
use sp_consensus_slots::Slot;
1011
use sp_core::H256;
@@ -454,7 +455,7 @@ impl<ReceiptHash> InvalidBundlesFraudProof<ReceiptHash> {
454455
/// Fraud proof.
455456
// TODO: Revisit when fraud proof v2 is implemented.
456457
#[allow(clippy::large_enum_variant)]
457-
#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
458+
#[derive(Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
458459
pub enum FraudProof<Number, Hash, DomainHeader: HeaderT> {
459460
InvalidStateTransition(InvalidStateTransitionProof<HeaderHashFor<DomainHeader>>),
460461
InvalidTransaction(InvalidTransactionProof<HeaderHashFor<DomainHeader>>),
@@ -550,6 +551,80 @@ where
550551
}
551552
}
552553

554+
impl<Number, Hash, DomainHeader: HeaderT> fmt::Debug for FraudProof<Number, Hash, DomainHeader> {
555+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
556+
let domain_id = self.domain_id();
557+
let bad_receipt_hash = self.targeted_bad_receipt_hash();
558+
let bad_operator = self.targeted_bad_operator_and_slot_for_bundle_equivocation();
559+
match self {
560+
Self::InvalidStateTransition(_) => {
561+
write!(
562+
f,
563+
"InvalidStateTransitionFraudProof({domain_id:?}#{bad_receipt_hash:?})"
564+
)
565+
}
566+
Self::InvalidTransaction(_) => {
567+
write!(
568+
f,
569+
"InvalidTransactionFraudProof({domain_id:?}#{bad_receipt_hash:?})"
570+
)
571+
}
572+
Self::ImproperTransactionSortition(_) => {
573+
write!(
574+
f,
575+
"ImproperTransactionSortitionFraudProof({domain_id:?}#{bad_receipt_hash:?})"
576+
)
577+
}
578+
Self::BundleEquivocation(_) => {
579+
write!(
580+
f,
581+
"BundleEquivocationFraudProof({domain_id:?}#{bad_operator:?})"
582+
)
583+
}
584+
Self::InvalidExtrinsicsRoot(_) => {
585+
write!(
586+
f,
587+
"InvalidExtrinsicsRootFraudProof({domain_id:?}#{bad_receipt_hash:?})"
588+
)
589+
}
590+
Self::InvalidBlockFees(_) => {
591+
write!(
592+
f,
593+
"InvalidBlockFeesFraudProof({domain_id:?}#{bad_receipt_hash:?})"
594+
)
595+
}
596+
Self::ValidBundle(_) => {
597+
write!(
598+
f,
599+
"ValidBundleFraudProof({domain_id:?}#{bad_receipt_hash:?})"
600+
)
601+
}
602+
Self::InvalidBundles(_) => {
603+
write!(
604+
f,
605+
"InvalidBundlesFraudProof({domain_id:?}#{bad_receipt_hash:?})"
606+
)
607+
}
608+
Self::InvalidDomainBlockHash(_) => {
609+
write!(
610+
f,
611+
"InvalidDomainBlockHashFraudProof({domain_id:?}#{bad_receipt_hash:?})"
612+
)
613+
}
614+
Self::InvalidTransfers(_) => {
615+
write!(
616+
f,
617+
"InvalidTransfersFraudProof({domain_id:?}#{bad_receipt_hash:?})"
618+
)
619+
}
620+
#[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
621+
Self::Dummy { .. } => {
622+
write!(f, "DummyFraudProof({domain_id:?}#{bad_receipt_hash:?})")
623+
}
624+
}
625+
}
626+
}
627+
553628
/// Proves an invalid state transition by challenging the trace at specific index in a bad receipt.
554629
#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
555630
pub struct InvalidStateTransitionProof<ReceiptHash> {

domains/client/block-builder/src/lib.rs

+21-3
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ where
158158
backend: &'a B,
159159
mut extrinsics: VecDeque<Block::Extrinsic>,
160160
maybe_inherent_data: Option<sp_inherents::InherentData>,
161+
is_gemini_3h: bool,
161162
) -> Result<Self, Error> {
162163
let header = <<Block as BlockT>::Header as HeaderT>::new(
163164
parent_number + One::one(),
@@ -179,9 +180,26 @@ where
179180

180181
if let Some(inherent_data) = maybe_inherent_data {
181182
let inherent_extrinsics = Self::create_inherents(parent_hash, &api, inherent_data)?;
182-
// reverse and push the inherents so that order is maintained
183-
for inherent_extrinsic in inherent_extrinsics.into_iter().rev() {
184-
extrinsics.push_front(inherent_extrinsic)
183+
184+
// TODO: This is used to keep compatible with gemini-3h, remove before next network
185+
//
186+
// HACK: ideally, any network should maintain the inherent extrinsic order to keep consistency
187+
// with the order in the fraud proof verifiaction side, but in gemini-3h, the domain inherent
188+
// extrinsic order is changed in the ER that derived from the consensus block #168431, we have
189+
// to follow this change in the client side to ensure every domain node that sync from genesis
190+
// will produce the same ER and hence can successfully submit ER to exend the previous ER.
191+
let maintain_runtime_inherent_extrinsic_order =
192+
!is_gemini_3h || parent_number >= 168430u32.into();
193+
194+
if maintain_runtime_inherent_extrinsic_order {
195+
// reverse and push the inherents so that order is maintained
196+
for inherent_extrinsic in inherent_extrinsics.into_iter().rev() {
197+
extrinsics.push_front(inherent_extrinsic)
198+
}
199+
} else {
200+
for inherent_extrinsic in inherent_extrinsics {
201+
extrinsics.push_front(inherent_extrinsic)
202+
}
185203
}
186204
}
187205

domains/client/domain-operator/src/domain_block_processor.rs

+12
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor, One, Zer
2727
use sp_runtime::{Digest, Saturating};
2828
use std::cmp::Ordering;
2929
use std::collections::VecDeque;
30+
use std::str::FromStr;
3031
use std::sync::Arc;
3132

3233
struct DomainBlockBuildResult<Block>
@@ -419,6 +420,15 @@ where
419420
inherent_digests: Digest,
420421
inherent_data: sp_inherents::InherentData,
421422
) -> Result<DomainBlockBuildResult<Block>, sp_blockchain::Error> {
423+
// TODO: This is used to keep compatible with gemini-3h, remove before next network
424+
let is_gemini_3h = self.consensus_client.info().genesis_hash
425+
== FromStr::from_str(
426+
// The genesis hash of gemini-3h
427+
"0c121c75f4ef450f40619e1fca9d1e8e7fbabc42c895bc4790801e85d5a91c34",
428+
)
429+
.map_err(|_| ())
430+
.expect("parsing consensus block hash should success");
431+
422432
let block_builder = BlockBuilder::new(
423433
&*self.client,
424434
parent_hash,
@@ -428,6 +438,7 @@ where
428438
&*self.backend,
429439
extrinsics,
430440
Some(inherent_data),
441+
is_gemini_3h,
431442
)?;
432443

433444
let BuiltBlock {
@@ -749,6 +760,7 @@ where
749760
if let Some(mismatched_receipts) = self.find_mismatch_receipt(consensus_block_hash)? {
750761
let fraud_proof = self.generate_fraud_proof(mismatched_receipts)?;
751762

763+
tracing::info!("Submit fraud proof: {fraud_proof:?}");
752764
let consensus_best_hash = self.consensus_client.info().best_hash;
753765
let mut runtime_api = self.consensus_client.runtime_api();
754766
runtime_api.register_extension(

domains/client/domain-operator/src/fraud_proof.rs

+5
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,12 @@ where
433433
inherent_digests.clone(),
434434
&*self.backend,
435435
extrinsics.into(),
436+
// NOTE: the inherent extrinsic is already contained in the above `extrinsics`, which
437+
// is getting from the block body, thus it is okay to pass `maybe_inherent_data` as
438+
// `None` and `is_gemini_3h` as `false`, the latter is only used when `maybe_inherent_data`
439+
// is `Some`.
436440
None,
441+
false,
437442
)?;
438443

439444
let (storage_changes, call_data) = match &execution_phase {

0 commit comments

Comments
 (0)