Skip to content

Commit 81cfe10

Browse files
authored
Merge pull request #981 from subspace/pre-validate-submit_bundle
Check the receipts in `submit_bundle` earlier in primary chain's transaction pool
2 parents e9e0b36 + c1571bb commit 81cfe10

File tree

13 files changed

+318
-194
lines changed

13 files changed

+318
-194
lines changed

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/pallet-domains/src/lib.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ pub use pallet::*;
2929
use sp_core::H256;
3030
use sp_domains::bundle_election::{verify_system_bundle_solution, verify_vrf_proof};
3131
use sp_domains::fraud_proof::{BundleEquivocationProof, FraudProof, InvalidTransactionProof};
32-
use sp_domains::{
33-
DomainId, ExecutionReceipt, InvalidTransactionCode, ProofOfElection, SignedOpaqueBundle,
34-
};
32+
use sp_domains::transaction::InvalidTransactionCode;
33+
use sp_domains::{DomainId, ExecutionReceipt, ProofOfElection, SignedOpaqueBundle};
3534
use sp_runtime::traits::{BlockNumberProvider, CheckedSub, One, Saturating, Zero};
3635
use sp_runtime::transaction_validity::TransactionValidityError;
3736
use sp_runtime::RuntimeAppPublic;
@@ -44,9 +43,8 @@ mod pallet {
4443
use frame_system::pallet_prelude::*;
4544
use sp_core::H256;
4645
use sp_domains::fraud_proof::{BundleEquivocationProof, FraudProof, InvalidTransactionProof};
47-
use sp_domains::{
48-
DomainId, ExecutionReceipt, ExecutorPublicKey, InvalidTransactionCode, SignedOpaqueBundle,
49-
};
46+
use sp_domains::transaction::InvalidTransactionCode;
47+
use sp_domains::{DomainId, ExecutionReceipt, ExecutorPublicKey, SignedOpaqueBundle};
5048
use sp_runtime::traits::{
5149
CheckEqual, MaybeDisplay, MaybeMallocSizeOf, One, SimpleBitOps, Zero,
5250
};

crates/pallet-domains/src/tests.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ use frame_support::{assert_noop, assert_ok, parameter_types};
44
use sp_core::crypto::Pair;
55
use sp_core::{H256, U256};
66
use sp_domains::fraud_proof::{ExecutionPhase, FraudProof};
7+
use sp_domains::transaction::InvalidTransactionCode;
78
use sp_domains::{
89
Bundle, BundleHeader, BundleSolution, DomainId, ExecutionReceipt, ExecutorPair,
9-
InvalidTransactionCode, ProofOfElection, SignedOpaqueBundle,
10+
ProofOfElection, SignedOpaqueBundle,
1011
};
1112
use sp_runtime::testing::Header;
1213
use sp_runtime::traits::{BlakeTwo256, IdentityLookup, ValidateUnsigned};

crates/sp-domains/src/lib.rs

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
pub mod bundle_election;
2121
pub mod fraud_proof;
22+
pub mod transaction;
2223

2324
use crate::fraud_proof::{BundleEquivocationProof, FraudProof, InvalidTransactionProof};
2425
use parity_scale_codec::{Decode, Encode};
@@ -27,7 +28,6 @@ use schnorrkel::vrf::{VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH};
2728
use sp_core::crypto::KeyTypeId;
2829
use sp_core::H256;
2930
use sp_runtime::traits::{BlakeTwo256, Block as BlockT, Hash as HashT, NumberFor};
30-
use sp_runtime::transaction_validity::{InvalidTransaction, TransactionValidity};
3131
use sp_runtime::OpaqueExtrinsic;
3232
use sp_std::borrow::Cow;
3333
use sp_std::vec::Vec;
@@ -159,28 +159,6 @@ pub struct DomainConfig<Hash, Balance, Weight> {
159159
pub min_operator_stake: Balance,
160160
}
161161

162-
/// Custom invalid validity code for the extrinsics in pallet-executor.
163-
#[repr(u8)]
164-
pub enum InvalidTransactionCode {
165-
BundleEquivicationProof = 101,
166-
TrasactionProof = 102,
167-
ExecutionReceipt = 103,
168-
Bundle = 104,
169-
FraudProof = 105,
170-
}
171-
172-
impl From<InvalidTransactionCode> for InvalidTransaction {
173-
fn from(invalid_code: InvalidTransactionCode) -> Self {
174-
InvalidTransaction::Custom(invalid_code as u8)
175-
}
176-
}
177-
178-
impl From<InvalidTransactionCode> for TransactionValidity {
179-
fn from(invalid_code: InvalidTransactionCode) -> Self {
180-
InvalidTransaction::Custom(invalid_code as u8).into()
181-
}
182-
}
183-
184162
/// Header of transaction bundle.
185163
#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
186164
pub struct BundleHeader<Hash> {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use crate::fraud_proof::FraudProof;
2+
use crate::ExecutionReceipt;
3+
use parity_scale_codec::{Decode, Encode};
4+
use scale_info::TypeInfo;
5+
use sp_runtime::traits::{Block as BlockT, NumberFor};
6+
use sp_runtime::transaction_validity::{InvalidTransaction, TransactionValidity};
7+
use sp_std::vec::Vec;
8+
9+
/// Custom invalid validity code for the extrinsics in pallet-domains.
10+
#[repr(u8)]
11+
pub enum InvalidTransactionCode {
12+
BundleEquivicationProof = 101,
13+
TrasactionProof = 102,
14+
ExecutionReceipt = 103,
15+
Bundle = 104,
16+
FraudProof = 105,
17+
}
18+
19+
impl From<InvalidTransactionCode> for InvalidTransaction {
20+
fn from(invalid_code: InvalidTransactionCode) -> Self {
21+
InvalidTransaction::Custom(invalid_code as u8)
22+
}
23+
}
24+
25+
impl From<InvalidTransactionCode> for TransactionValidity {
26+
fn from(invalid_code: InvalidTransactionCode) -> Self {
27+
InvalidTransaction::Custom(invalid_code as u8).into()
28+
}
29+
}
30+
31+
/// Object for performing the pre-validation in the transaction pool
32+
/// before calling into the regular `validate_transaction` runtime api.
33+
#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
34+
pub enum PreValidationObject<Block, DomainHash>
35+
where
36+
Block: BlockT,
37+
{
38+
Null,
39+
FraudProof(FraudProof),
40+
Receipts(Vec<ExecutionReceipt<NumberFor<Block>, Block::Hash, DomainHash>>),
41+
}
42+
43+
sp_api::decl_runtime_apis! {
44+
/// API for extracting the pre-validation objects in the primary chain transaction pool wrapper.
45+
pub trait PreValidationObjectApi<DomainHash: Encode + Decode> {
46+
/// Extract the pre-validation object from the given extrinsic.
47+
fn extract_pre_validation_object(extrinsics: Block::Extrinsic) -> PreValidationObject<Block, DomainHash>;
48+
}
49+
}

crates/subspace-node/src/secondary_chain/chain_spec.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,10 @@ pub fn development_config() -> ExecutionChainSpec<GenesisConfig> {
6060
1_000 * SSC,
6161
// TODO: proper genesis domain config
6262
DomainConfig {
63-
wasm_runtime_hash: Hash::random(),
63+
wasm_runtime_hash: blake2b_256_hash(
64+
system_domain_runtime::CORE_PAYMENTS_WASM_BUNDLE,
65+
)
66+
.into(),
6467
max_bundle_size: 1024 * 1024,
6568
bundle_slot_probability: (1, 1),
6669
max_bundle_weight: Weight::MAX,
@@ -114,7 +117,10 @@ pub fn local_testnet_config() -> ExecutionChainSpec<GenesisConfig> {
114117
1_000 * SSC,
115118
// TODO: proper genesis domain config
116119
DomainConfig {
117-
wasm_runtime_hash: Hash::zero(),
120+
wasm_runtime_hash: blake2b_256_hash(
121+
system_domain_runtime::CORE_PAYMENTS_WASM_BUNDLE,
122+
)
123+
.into(),
118124
max_bundle_size: 1024 * 1024,
119125
bundle_slot_probability: (1, 1),
120126
max_bundle_weight: Weight::MAX,
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
use crate::{Block, BlockNumber, Hash, RuntimeCall, UncheckedExtrinsic};
2+
use sp_consensus_subspace::digests::CompatibleDigestItem;
3+
use sp_consensus_subspace::FarmerPublicKey;
4+
use sp_domains::fraud_proof::FraudProof;
5+
use sp_domains::transaction::PreValidationObject;
6+
use sp_domains::{DomainId, ExecutionReceipt};
7+
use sp_runtime::traits::{BlakeTwo256, Block as BlockT, Hash as HashT, Header as HeaderT, Zero};
8+
use sp_std::vec::Vec;
9+
use subspace_core_primitives::{PublicKey, Randomness};
10+
use subspace_verification::derive_randomness;
11+
12+
pub(crate) fn extract_system_bundles(
13+
extrinsics: Vec<UncheckedExtrinsic>,
14+
) -> (
15+
sp_domains::OpaqueBundles<Block, domain_runtime_primitives::Hash>,
16+
sp_domains::SignedOpaqueBundles<Block, domain_runtime_primitives::Hash>,
17+
) {
18+
let (system_bundles, core_bundles): (Vec<_>, Vec<_>) = extrinsics
19+
.into_iter()
20+
.filter_map(|uxt| {
21+
if let RuntimeCall::Domains(pallet_domains::Call::submit_bundle {
22+
signed_opaque_bundle,
23+
}) = uxt.function
24+
{
25+
if signed_opaque_bundle.domain_id().is_system() {
26+
Some((Some(signed_opaque_bundle.bundle), None))
27+
} else {
28+
Some((None, Some(signed_opaque_bundle)))
29+
}
30+
} else {
31+
None
32+
}
33+
})
34+
.unzip();
35+
(
36+
system_bundles.into_iter().flatten().collect(),
37+
core_bundles.into_iter().flatten().collect(),
38+
)
39+
}
40+
41+
pub(crate) fn extract_core_bundles(
42+
extrinsics: Vec<UncheckedExtrinsic>,
43+
domain_id: DomainId,
44+
) -> sp_domains::OpaqueBundles<Block, domain_runtime_primitives::Hash> {
45+
extrinsics
46+
.into_iter()
47+
.filter_map(|uxt| match uxt.function {
48+
RuntimeCall::Domains(pallet_domains::Call::submit_bundle {
49+
signed_opaque_bundle,
50+
}) if signed_opaque_bundle.domain_id() == domain_id => {
51+
Some(signed_opaque_bundle.bundle)
52+
}
53+
_ => None,
54+
})
55+
.collect()
56+
}
57+
58+
pub(crate) fn extract_receipts(
59+
extrinsics: Vec<UncheckedExtrinsic>,
60+
domain_id: DomainId,
61+
) -> Vec<ExecutionReceipt<BlockNumber, Hash, domain_runtime_primitives::Hash>> {
62+
extrinsics
63+
.into_iter()
64+
.filter_map(|uxt| match uxt.function {
65+
RuntimeCall::Domains(pallet_domains::Call::submit_bundle {
66+
signed_opaque_bundle,
67+
}) if signed_opaque_bundle.domain_id() == domain_id => {
68+
Some(signed_opaque_bundle.bundle.receipts)
69+
}
70+
_ => None,
71+
})
72+
.flatten()
73+
.collect()
74+
}
75+
76+
pub(crate) fn extract_fraud_proofs(extrinsics: Vec<UncheckedExtrinsic>) -> Vec<FraudProof> {
77+
extrinsics
78+
.into_iter()
79+
.filter_map(|uxt| {
80+
if let RuntimeCall::Domains(pallet_domains::Call::submit_fraud_proof { fraud_proof }) =
81+
uxt.function
82+
{
83+
Some(fraud_proof)
84+
} else {
85+
None
86+
}
87+
})
88+
.collect()
89+
}
90+
91+
pub(crate) fn extract_pre_validation_object(
92+
extrinsic: UncheckedExtrinsic,
93+
) -> PreValidationObject<Block, domain_runtime_primitives::Hash> {
94+
match extrinsic.function {
95+
RuntimeCall::Domains(pallet_domains::Call::submit_fraud_proof { fraud_proof }) => {
96+
PreValidationObject::FraudProof(fraud_proof)
97+
}
98+
RuntimeCall::Domains(pallet_domains::Call::submit_bundle {
99+
signed_opaque_bundle,
100+
}) => PreValidationObject::Receipts(signed_opaque_bundle.bundle.receipts),
101+
_ => PreValidationObject::Null,
102+
}
103+
}
104+
105+
pub(crate) fn extrinsics_shuffling_seed<Block: BlockT>(header: Block::Header) -> Randomness {
106+
if header.number().is_zero() {
107+
Randomness::default()
108+
} else {
109+
let mut pre_digest: Option<_> = None;
110+
for log in header.digest().logs() {
111+
match (
112+
log.as_subspace_pre_digest::<FarmerPublicKey>(),
113+
pre_digest.is_some(),
114+
) {
115+
(Some(_), true) => panic!("Multiple Subspace pre-runtime digests in a header"),
116+
(None, _) => {}
117+
(s, false) => pre_digest = s,
118+
}
119+
}
120+
121+
let pre_digest = pre_digest.expect("Header must contain one pre-runtime digest; qed");
122+
123+
let seed: &[u8] = b"extrinsics-shuffling-seed";
124+
let randomness = derive_randomness(
125+
&Into::<PublicKey>::into(&pre_digest.solution.public_key),
126+
&pre_digest.solution.chunk.to_bytes(),
127+
&pre_digest.solution.chunk_signature,
128+
)
129+
.expect("Tag signature is verified by the client and must always be valid; qed");
130+
let mut data = Vec::with_capacity(seed.len() + randomness.len());
131+
data.extend_from_slice(seed);
132+
data.extend_from_slice(&randomness);
133+
134+
BlakeTwo256::hash_of(&data).into()
135+
}
136+
}

0 commit comments

Comments
 (0)