Skip to content
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
14 changes: 8 additions & 6 deletions crates/pallet-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -537,11 +537,17 @@ impl<T: Config> Pallet<T> {

fn validate_bundle(
OpaqueBundle {
header,
sealed_header,
receipts,
extrinsics: _,
}: &OpaqueBundle<T::BlockNumber, T::Hash, T::DomainHash>,
) -> Result<(), BundleError> {
if !sealed_header.verify_signature() {
return Err(BundleError::BadSignature);
}

let header = &sealed_header.header;

let current_block_number = frame_system::Pallet::<T>::current_block_number();

// Reject the stale bundles so that they can't be used by attacker to occupy the block space without cost.
Expand Down Expand Up @@ -572,10 +578,6 @@ impl<T: Config> Pallet<T> {
}
}

if !header.verify_signature() {
return Err(BundleError::BadSignature);
}

let proof_of_election = header.bundle_solution.proof_of_election();
proof_of_election
.verify_vrf_proof()
Expand Down Expand Up @@ -688,7 +690,7 @@ where
pub fn submit_bundle_unsigned(
opaque_bundle: OpaqueBundle<T::BlockNumber, T::Hash, T::DomainHash>,
) {
let slot = opaque_bundle.header.slot_number;
let slot = opaque_bundle.sealed_header.header.slot_number;
let receipts_count = opaque_bundle.receipts.len();
let extrincis_count = opaque_bundle.extrinsics.len();

Expand Down
10 changes: 5 additions & 5 deletions crates/pallet-domains/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use sp_core::{Get, H256, U256};
use sp_domains::fraud_proof::{ExecutionPhase, FraudProof, InvalidStateTransitionProof};
use sp_domains::transaction::InvalidTransactionCode;
use sp_domains::{
create_dummy_bundle_with_receipts_generic, BundleSolution, DomainId, ExecutionReceipt,
ExecutorPair, OpaqueBundle, PreliminaryBundleHeader,
create_dummy_bundle_with_receipts_generic, BundleHeader, BundleSolution, DomainId,
ExecutionReceipt, ExecutorPair, OpaqueBundle, SealedBundleHeader,
};
use sp_runtime::testing::Header;
use sp_runtime::traits::{BlakeTwo256, IdentityLookup, ValidateUnsigned};
Expand Down Expand Up @@ -134,18 +134,18 @@ fn create_dummy_bundle(

let execution_receipt = create_dummy_receipt(primary_number, primary_hash);

let preliminary_bundle_header = PreliminaryBundleHeader {
let header = BundleHeader {
primary_number,
primary_hash,
slot_number: 0u64,
extrinsics_root: Default::default(),
bundle_solution: BundleSolution::dummy(domain_id, pair.public()),
};

let signature = pair.sign(preliminary_bundle_header.hash().as_ref());
let signature = pair.sign(header.hash().as_ref());

OpaqueBundle {
header: preliminary_bundle_header.into_bundle_header(signature),
sealed_header: SealedBundleHeader::new(header, signature),
receipts: vec![execution_receipt],
extrinsics: Vec::new(),
}
Expand Down
26 changes: 14 additions & 12 deletions crates/sp-domains/src/fraud_proof.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{BundleHeader, DomainId};
use crate::{BundleHeader, DomainId, SealedBundleHeader};
use parity_scale_codec::{Decode, Encode};
use scale_info::TypeInfo;
use sp_consensus_slots::Slot;
Expand Down Expand Up @@ -265,9 +265,9 @@ pub struct BundleEquivocationProof<Number, Hash> {
pub slot: Slot,
// TODO: Make H256 a generic when bundle equivocation is implemented properly.
/// The first header involved in the equivocation.
pub first_header: BundleHeader<Number, Hash, H256>,
pub first_header: SealedBundleHeader<Number, Hash, H256>,
/// The second header involved in the equivocation.
pub second_header: BundleHeader<Number, Hash, H256>,
pub second_header: SealedBundleHeader<Number, Hash, H256>,
}

impl<Number: Clone + From<u32> + Encode, Hash: Clone + Default + Encode>
Expand All @@ -284,15 +284,17 @@ impl<Number: Clone + From<u32> + Encode, Hash: Clone + Default + Encode>
pub fn dummy_at(slot_number: u64) -> Self {
use sp_application_crypto::UncheckedFrom;

let dummy_header = BundleHeader {
primary_number: Number::from(0u32),
primary_hash: Hash::default(),
slot_number,
extrinsics_root: H256::default(),
bundle_solution: crate::BundleSolution::dummy(
DomainId::SYSTEM,
crate::ExecutorPublicKey::unchecked_from([0u8; 32]),
),
let dummy_header = SealedBundleHeader {
header: BundleHeader {
primary_number: Number::from(0u32),
primary_hash: Hash::default(),
slot_number,
extrinsics_root: H256::default(),
bundle_solution: crate::BundleSolution::dummy(
DomainId::SYSTEM,
crate::ExecutorPublicKey::unchecked_from([0u8; 32]),
),
},
signature: crate::ExecutorSignature::unchecked_from([0u8; 64]),
};

Expand Down
120 changes: 46 additions & 74 deletions crates/sp-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,13 +175,12 @@ pub struct DomainConfig<Hash, Balance, Weight> {
pub min_operator_stake: Balance,
}

/// Preliminary header of bundle.
/// Unsealed header of bundle.
///
/// [`PreliminaryBundleHeader`] contains everything of [`BundleHeader`] except for the signature,
/// domain operator needs to sign the hash of [`PreliminaryBundleHeader`] and uses the signature to
/// assemble the final [`BundleHeader`].
/// Domain operator needs to sign the hash of [`BundleHeader`] and uses the signature to
/// assemble the final [`SealedBundleHeader`].
#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
pub struct PreliminaryBundleHeader<Number, Hash, DomainHash> {
pub struct BundleHeader<Number, Hash, DomainHash> {
/// The block number of primary block at which the bundle was created.
pub primary_number: Number,
/// The hash of primary block at which the bundle was created.
Expand All @@ -194,70 +193,36 @@ pub struct PreliminaryBundleHeader<Number, Hash, DomainHash> {
pub bundle_solution: BundleSolution<DomainHash>,
}

impl<Number: Encode, Hash: Encode, DomainHash: Encode>
PreliminaryBundleHeader<Number, Hash, DomainHash>
{
/// Returns the hash of this preliminary header.
impl<Number: Encode, Hash: Encode, DomainHash: Encode> BundleHeader<Number, Hash, DomainHash> {
/// Returns the hash of this header.
pub fn hash(&self) -> H256 {
BlakeTwo256::hash_of(self)
}
}

impl<Number, Hash, DomainHash> PreliminaryBundleHeader<Number, Hash, DomainHash> {
/// Converts [`PreliminaryBundleHeader`] into [`BundleHeader`].
pub fn into_bundle_header(
self,
signature: ExecutorSignature,
) -> BundleHeader<Number, Hash, DomainHash> {
BundleHeader {
primary_number: self.primary_number,
primary_hash: self.primary_hash,
slot_number: self.slot_number,
extrinsics_root: self.extrinsics_root,
bundle_solution: self.bundle_solution,
signature,
}
}
}

#[derive(Encode)]
struct PreliminaryBundleHeaderRef<'a, Number, Hash, DomainHash> {
primary_number: &'a Number,
primary_hash: &'a Hash,
slot_number: u64,
extrinsics_root: H256,
bundle_solution: &'a BundleSolution<DomainHash>,
}

/// Header of bundle.
#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
pub struct BundleHeader<Number, Hash, DomainHash> {
/// The block number of primary block at which the bundle was created.
pub primary_number: Number,
/// The hash of primary block at which the bundle was created.
pub primary_hash: Hash,
/// The slot number.
pub slot_number: u64,
/// The merkle root of the extrinsics.
pub extrinsics_root: H256,
/// Solution of the bundle election.
pub bundle_solution: BundleSolution<DomainHash>,
pub struct SealedBundleHeader<Number, Hash, DomainHash> {
/// Unsealed header.
pub header: BundleHeader<Number, Hash, DomainHash>,
/// Signature of the bundle.
pub signature: ExecutorSignature,
}

impl<Number: Encode, Hash: Encode, DomainHash: Encode> BundleHeader<Number, Hash, DomainHash> {
/// Returns the hash of the corresponding preliminary header.
pub fn pre_hash(&self) -> H256 {
let preliminary_bundle_header_ref = PreliminaryBundleHeaderRef {
primary_number: &self.primary_number,
primary_hash: &self.primary_hash,
slot_number: self.slot_number,
extrinsics_root: self.extrinsics_root,
bundle_solution: &self.bundle_solution,
};
impl<Number: Encode, Hash: Encode, DomainHash: Encode>
SealedBundleHeader<Number, Hash, DomainHash>
{
/// Constructs a new instance of [`SealedBundleHeader`].
pub fn new(
header: BundleHeader<Number, Hash, DomainHash>,
signature: ExecutorSignature,
) -> Self {
Self { header, signature }
}

BlakeTwo256::hash_of(&preliminary_bundle_header_ref)
/// Returns the hash of the inner unsealed header.
pub fn pre_hash(&self) -> H256 {
self.header.hash()
}

/// Returns the hash of this header.
Expand All @@ -267,7 +232,8 @@ impl<Number: Encode, Hash: Encode, DomainHash: Encode> BundleHeader<Number, Hash

/// Returns whether the signature is valid.
pub fn verify_signature(&self) -> bool {
self.bundle_solution
self.header
.bundle_solution
.proof_of_election()
.executor_public_key
.verify(&self.pre_hash(), &self.signature)
Expand Down Expand Up @@ -401,8 +367,8 @@ impl<DomainHash: Default> BundleSolution<DomainHash> {
/// Domain bundle.
#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
pub struct Bundle<Extrinsic, Number, Hash, DomainHash> {
/// The bundle header.
pub header: BundleHeader<Number, Hash, DomainHash>,
/// Sealed bundle header.
pub sealed_header: SealedBundleHeader<Number, Hash, DomainHash>,
/// Expected receipts by the primay chain when the bundle was created.
///
/// NOTE: It's fine to `Vec` instead of `BoundedVec` as each bundle is
Expand All @@ -423,12 +389,16 @@ impl<Extrinsic: Encode, Number: Encode, Hash: Encode, DomainHash: Encode>

/// Returns the domain_id of this bundle.
pub fn domain_id(&self) -> DomainId {
self.header.bundle_solution.proof_of_election().domain_id
self.sealed_header
.header
.bundle_solution
.proof_of_election()
.domain_id
}

/// Consumes [`Bundle`] to extract the inner executor public key.
pub fn into_executor_public_key(self) -> ExecutorPublicKey {
match self.header.bundle_solution {
match self.sealed_header.header.bundle_solution {
BundleSolution::System {
proof_of_election, ..
}
Expand All @@ -446,7 +416,7 @@ impl<Extrinsic: Encode, Number, Hash, DomainHash> Bundle<Extrinsic, Number, Hash
/// Convert a bundle with generic extrinsic to a bundle with opaque extrinsic.
pub fn into_opaque_bundle(self) -> OpaqueBundle<Number, Hash, DomainHash> {
let Bundle {
header,
sealed_header,
receipts,
extrinsics,
} = self;
Expand All @@ -458,7 +428,7 @@ impl<Extrinsic: Encode, Number, Hash, DomainHash> Bundle<Extrinsic, Number, Hash
})
.collect();
OpaqueBundle {
header,
sealed_header,
receipts,
extrinsics: opaque_extrinsics,
}
Expand Down Expand Up @@ -526,20 +496,22 @@ where
{
use sp_core::crypto::UncheckedFrom;

let header = BundleHeader {
primary_number,
primary_hash,
slot_number: 0u64,
extrinsics_root: Default::default(),
bundle_solution: BundleSolution::dummy(
domain_id,
ExecutorPublicKey::unchecked_from([0u8; 32]),
),
let sealed_header = SealedBundleHeader {
header: BundleHeader {
primary_number,
primary_hash,
slot_number: 0u64,
extrinsics_root: Default::default(),
bundle_solution: BundleSolution::dummy(
domain_id,
ExecutorPublicKey::unchecked_from([0u8; 32]),
),
},
signature: ExecutorSignature::unchecked_from([0u8; 64]),
};

OpaqueBundle {
header,
sealed_header,
receipts,
extrinsics: Vec::new(),
}
Expand Down
4 changes: 2 additions & 2 deletions crates/subspace-fraud-proof/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -697,10 +697,10 @@ async fn test_invalid_transaction_proof_creation_and_verification() {
let mut bundle_with_bad_extrinsics = maybe_bundle.unwrap();
bundle_with_bad_extrinsics.extrinsics =
vec![OpaqueExtrinsic::from_bytes(&transfer_from_one_to_bob.encode()).unwrap()];
bundle_with_bad_extrinsics.header.signature = alice
bundle_with_bad_extrinsics.sealed_header.signature = alice
.key
.pair()
.sign(bundle_with_bad_extrinsics.header.pre_hash().as_ref())
.sign(bundle_with_bad_extrinsics.sealed_header.pre_hash().as_ref())
.into();

alice
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ where
if bundle_exists {
Ok(Action::Empty)
} else {
if !bundle.header.verify_signature() {
if !bundle.sealed_header.verify_signature() {
return Err(Self::Error::BadBundleSignature);
}

Expand All @@ -189,7 +189,11 @@ where
self.gossip_message_validator
.validate_bundle_receipts(&bundle.receipts, domain_id)?;

let at = bundle.header.bundle_solution.creation_block_hash();
let at = bundle
.sealed_header
.header
.bundle_solution
.creation_block_hash();

self.gossip_message_validator.validate_bundle_transactions(
&bundle.extrinsics,
Expand Down
10 changes: 6 additions & 4 deletions domains/client/domain-executor/src/domain_bundle_producer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use sc_client_api::{AuxStore, BlockBackend, ProofProvider};
use sp_api::{NumberFor, ProvideRuntimeApi};
use sp_block_builder::BlockBuilder;
use sp_blockchain::HeaderBackend;
use sp_domains::{Bundle, BundleSolution, DomainId, ExecutorPublicKey, ExecutorSignature};
use sp_domains::{
Bundle, BundleSolution, DomainId, ExecutorPublicKey, ExecutorSignature, SealedBundleHeader,
};
use sp_keystore::KeystorePtr;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, One, Saturating, Zero};
use sp_runtime::RuntimeAppPublic;
Expand Down Expand Up @@ -237,7 +239,7 @@ where
.executor_public_key
.clone();

let (preliminary_bundle_header, receipts, extrinsics) = self
let (bundle_header, receipts, extrinsics) = self
.domain_bundle_proposer
.propose_bundle_at(
bundle_solution,
Expand All @@ -247,7 +249,7 @@ where
)
.await?;

let to_sign = preliminary_bundle_header.hash();
let to_sign = bundle_header.hash();

let signature = self
.keystore
Expand All @@ -274,7 +276,7 @@ where
})?;

let bundle = Bundle {
header: preliminary_bundle_header.into_bundle_header(signature),
sealed_header: SealedBundleHeader::new(bundle_header, signature),
receipts,
extrinsics,
};
Expand Down
Loading