Skip to content

Commit

Permalink
Merge pull request #1303 from subspace/refactor-subspace-transaction-…
Browse files Browse the repository at this point in the history
…pool

Refactor subspace transaction pool
  • Loading branch information
liuchengxu authored Mar 29, 2023
2 parents c871b9e + ff403e4 commit 82b1b9d
Show file tree
Hide file tree
Showing 20 changed files with 481 additions and 510 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions crates/sp-domains/src/fraud_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ pub enum VerificationError {
#[cfg(feature = "std")]
#[cfg_attr(feature = "thiserror", error("Failed to get runtime code: {0}"))]
RuntimeCode(String),
#[cfg(feature = "std")]
#[cfg_attr(
feature = "thiserror",
error("Oneshot error when verifying fraud proof in tx pool: {0}")
)]
Oneshot(String),
}

/// Fraud proof.
Expand Down
2 changes: 1 addition & 1 deletion crates/subspace-fraud-proof/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { package = "parity-scale-codec", version = "3.4.0", features = ["derive"] }
domain-runtime-primitives = { version = "0.1.0", path = "../../domains/primitives/runtime" }
futures = "0.3.26"
hash-db = "0.15.2"
sc-client-api = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "456cfad45a178617f6886ec400c312f2fea59232" }
sp-api = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "456cfad45a178617f6886ec400c312f2fea59232" }
Expand All @@ -30,7 +31,6 @@ tracing = "0.1.37"
[dev-dependencies]
domain-block-builder = { version = "0.1.0", path = "../../domains/client/block-builder" }
domain-test-service = { version = "0.1.0", path = "../../domains/test/service" }
futures = "0.3.26"
pallet-balances = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "456cfad45a178617f6886ec400c312f2fea59232" }
sc-cli = { version = "0.10.0-dev", git = "https://github.com/subspace/substrate", rev = "456cfad45a178617f6886ec400c312f2fea59232", default-features = false }
sc-service = { version = "0.10.0-dev", git = "https://github.com/subspace/substrate", rev = "456cfad45a178617f6886ec400c312f2fea59232", default-features = false }
Expand Down
33 changes: 33 additions & 0 deletions crates/subspace-fraud-proof/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ mod invalid_state_transition_proof;
mod tests;

use codec::{Decode, Encode};
use futures::channel::oneshot;
use futures::FutureExt;
use invalid_state_transition_proof::InvalidStateTransitionProofVerifier;
pub use invalid_state_transition_proof::{
ExecutionProver, PrePostStateRootVerifier, VerifyPrePostStateRoot,
Expand Down Expand Up @@ -117,3 +119,34 @@ where
self.verify(proof)
}
}

/// Verifies the fraud proof extracted from extrinsic in the transaction pool.
pub async fn validate_fraud_proof_in_tx_pool<Block, Verifier>(
spawner: &dyn SpawnNamed,
fraud_proof_verifier: Verifier,
fraud_proof: FraudProof<NumberFor<Block>, Block::Hash>,
) -> Result<(), VerificationError>
where
Block: BlockT,
Verifier: VerifyFraudProof<Block> + Send + 'static,
{
let (verified_result_sender, verified_result_receiver) = oneshot::channel();

// Verify the fraud proof in another blocking task as it might be pretty heavy.
spawner.spawn_blocking(
"txpool-fraud-proof-verification",
None,
async move {
let verified_result = fraud_proof_verifier.verify_fraud_proof(&fraud_proof);
verified_result_sender
.send(verified_result)
.expect("Failed to send the verified fraud proof result");
}
.boxed(),
);

match verified_result_receiver.await {
Ok(verified_result) => verified_result,
Err(err) => Err(VerificationError::Oneshot(err.to_string())),
}
}
48 changes: 32 additions & 16 deletions crates/subspace-service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ pub mod dsn;
pub mod piece_cache;
pub mod rpc;
pub mod segment_headers;
pub mod tx_pre_validator;

use crate::dsn::import_blocks::import_blocks as import_blocks_from_dsn;
use crate::dsn::{create_dsn_instance, DsnConfigurationError};
use crate::piece_cache::PieceCache;
use crate::segment_headers::{start_segment_header_archiver, SegmentHeaderCache};
use crate::tx_pre_validator::PrimaryChainTxPreValidator;
use derive_more::{Deref, DerefMut, Into};
use domain_runtime_primitives::Hash as DomainHash;
use dsn::start_dsn_archiver;
Expand Down Expand Up @@ -74,14 +76,13 @@ use sp_transaction_pool::runtime_api::TaggedTransactionQueue;
use std::num::NonZeroUsize;
use std::sync::{Arc, Mutex};
use subspace_core_primitives::crypto::kzg::{embedded_kzg_settings, Kzg};
use subspace_fraud_proof::VerifyFraudProof;
use subspace_networking::libp2p::multiaddr::Protocol;
use subspace_networking::libp2p::Multiaddr;
use subspace_networking::{peer_id, Node};
use subspace_runtime_primitives::opaque::Block;
use subspace_runtime_primitives::{AccountId, Balance, Hash, Index as Nonce};
use subspace_transaction_pool::bundle_validator::{BundleValidator, ValidateBundle};
use subspace_transaction_pool::FullPool;
use subspace_transaction_pool::bundle_validator::BundleValidator;
use subspace_transaction_pool::{FullPool, PreValidateTransaction};
use tracing::{debug, error, info, Instrument};

/// Error type for Subspace service.
Expand Down Expand Up @@ -209,8 +210,12 @@ pub fn new_partial<RuntimeApi, ExecutorDispatch>(
FullPool<
Block,
FullClient<RuntimeApi, ExecutorDispatch>,
FraudProofVerifier<RuntimeApi, ExecutorDispatch>,
BundleValidator<Block, FullClient<RuntimeApi, ExecutorDispatch>>,
PrimaryChainTxPreValidator<
Block,
FullClient<RuntimeApi, ExecutorDispatch>,
FraudProofVerifier<RuntimeApi, ExecutorDispatch>,
BundleValidator<Block, FullClient<RuntimeApi, ExecutorDispatch>>,
>,
>,
(
impl BlockImport<
Expand Down Expand Up @@ -293,12 +298,17 @@ where
task_manager.spawn_handle(),
subspace_fraud_proof::PrePostStateRootVerifier::new(client.clone()),
);
let tx_pre_validator = PrimaryChainTxPreValidator::new(
client.clone(),
Box::new(task_manager.spawn_handle()),
proof_verifier.clone(),
bundle_validator.clone(),
);
let transaction_pool = subspace_transaction_pool::new_full(
config,
&task_manager,
client.clone(),
proof_verifier.clone(),
bundle_validator.clone(),
tx_pre_validator,
);

let fraud_proof_block_import =
Expand Down Expand Up @@ -367,7 +377,7 @@ where
}

/// Full node along with some other components.
pub struct NewFull<Client, Validator, Verifier>
pub struct NewFull<Client, TxPreValidator>
where
Client: ProvideRuntimeApi<Block>
+ BlockBackend<Block>
Expand All @@ -378,9 +388,7 @@ where
Client::Api: TaggedTransactionQueue<Block>
+ ExecutorApi<Block, DomainHash>
+ PreValidationObjectApi<Block, domain_runtime_primitives::Hash>,
Validator:
ValidateBundle<Block, domain_runtime_primitives::Hash> + Clone + Send + Sync + 'static,
Verifier: VerifyFraudProof<Block> + Clone + Send + Sync + 'static,
TxPreValidator: PreValidateTransaction<Block = Block> + Send + Sync + Clone + 'static,
{
/// Task manager.
pub task_manager: TaskManager,
Expand All @@ -407,13 +415,17 @@ where
/// Network starter.
pub network_starter: NetworkStarter,
/// Transaction pool.
pub transaction_pool: Arc<FullPool<Block, Client, Verifier, Validator>>,
pub transaction_pool: Arc<FullPool<Block, Client, TxPreValidator>>,
}

type FullNode<RuntimeApi, ExecutorDispatch> = NewFull<
FullClient<RuntimeApi, ExecutorDispatch>,
BundleValidator<Block, FullClient<RuntimeApi, ExecutorDispatch>>,
FraudProofVerifier<RuntimeApi, ExecutorDispatch>,
PrimaryChainTxPreValidator<
Block,
FullClient<RuntimeApi, ExecutorDispatch>,
FraudProofVerifier<RuntimeApi, ExecutorDispatch>,
BundleValidator<Block, FullClient<RuntimeApi, ExecutorDispatch>>,
>,
>;

/// Builds a new service for a full client.
Expand All @@ -428,8 +440,12 @@ pub async fn new_full<RuntimeApi, ExecutorDispatch, I>(
FullPool<
Block,
FullClient<RuntimeApi, ExecutorDispatch>,
FraudProofVerifier<RuntimeApi, ExecutorDispatch>,
BundleValidator<Block, FullClient<RuntimeApi, ExecutorDispatch>>,
PrimaryChainTxPreValidator<
Block,
FullClient<RuntimeApi, ExecutorDispatch>,
FraudProofVerifier<RuntimeApi, ExecutorDispatch>,
BundleValidator<Block, FullClient<RuntimeApi, ExecutorDispatch>>,
>,
>,
(
I,
Expand Down
114 changes: 114 additions & 0 deletions crates/subspace-service/src/tx_pre_validator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use sc_transaction_pool::error::Result as TxPoolResult;
use sc_transaction_pool_api::error::Error as TxPoolError;
use sc_transaction_pool_api::TransactionSource;
use sp_api::ProvideRuntimeApi;
use sp_core::traits::SpawnNamed;
use sp_domains::transaction::{
InvalidTransactionCode, PreValidationObject, PreValidationObjectApi,
};
use sp_runtime::generic::BlockId;
use sp_runtime::traits::Block as BlockT;
use std::marker::PhantomData;
use std::sync::Arc;
use subspace_fraud_proof::VerifyFraudProof;
use subspace_transaction_pool::bundle_validator::ValidateBundle;
use subspace_transaction_pool::PreValidateTransaction;

pub struct PrimaryChainTxPreValidator<Block, Client, Verifier, BundleValidator> {
client: Arc<Client>,
spawner: Box<dyn SpawnNamed>,
fraud_proof_verifier: Verifier,
bundle_validator: BundleValidator,
_phantom_data: PhantomData<Block>,
}

impl<Block, Client, Verifier, BundleValidator> Clone
for PrimaryChainTxPreValidator<Block, Client, Verifier, BundleValidator>
where
Verifier: Clone,
BundleValidator: Clone,
{
fn clone(&self) -> Self {
Self {
client: self.client.clone(),
spawner: self.spawner.clone(),
fraud_proof_verifier: self.fraud_proof_verifier.clone(),
bundle_validator: self.bundle_validator.clone(),
_phantom_data: self._phantom_data,
}
}
}

impl<Block, Client, Verifier, BundleValidator>
PrimaryChainTxPreValidator<Block, Client, Verifier, BundleValidator>
{
pub fn new(
client: Arc<Client>,
spawner: Box<dyn SpawnNamed>,
fraud_proof_verifier: Verifier,
bundle_validator: BundleValidator,
) -> Self {
Self {
client,
spawner,
fraud_proof_verifier,
bundle_validator,
_phantom_data: Default::default(),
}
}
}

#[async_trait::async_trait]
impl<Block, Client, Verifier, BundleValidator> PreValidateTransaction
for PrimaryChainTxPreValidator<Block, Client, Verifier, BundleValidator>
where
Block: BlockT,
Client: ProvideRuntimeApi<Block> + Send + Sync,
Client::Api: PreValidationObjectApi<Block, domain_runtime_primitives::Hash>,
Verifier: VerifyFraudProof<Block> + Clone + Send + Sync + 'static,
BundleValidator:
ValidateBundle<Block, domain_runtime_primitives::Hash> + Clone + Send + Sync + 'static,
{
type Block = Block;
async fn pre_validate_transaction(
&self,
at: Block::Hash,
_source: TransactionSource,
uxt: Block::Extrinsic,
) -> TxPoolResult<()> {
let pre_validation_object = self
.client
.runtime_api()
.extract_pre_validation_object(at, uxt.clone())
.map_err(|err| sc_transaction_pool::error::Error::Blockchain(err.into()))?;

match pre_validation_object {
PreValidationObject::Null => {
// No pre-validation is required.
}
PreValidationObject::Bundle(bundle) => {
if let Err(err) = self
.bundle_validator
.validate_bundle(&BlockId::Hash(at), &bundle)
{
tracing::trace!(target: "txpool", error = ?err, "Dropped `submit_bundle` extrinsic");
return Err(TxPoolError::ImmediatelyDropped.into());
}
}
PreValidationObject::FraudProof(fraud_proof) => {
subspace_fraud_proof::validate_fraud_proof_in_tx_pool(
&self.spawner,
self.fraud_proof_verifier.clone(),
fraud_proof,
)
.await
.map_err(|err| {
tracing::debug!(target: "txpool", error = ?err, "Invalid fraud proof");
TxPoolError::InvalidTransaction(InvalidTransactionCode::FraudProof.into())
})?;
}
}

Ok(())
}
}
2 changes: 1 addition & 1 deletion crates/subspace-transaction-pool/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ repository = "https://github.com/subspace/subspace"
description = "Subspace transaction pool"

[dependencies]
async-trait = "0.1.64"
codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false, features = ["derive"] }
domain-runtime-primitives = { version = "0.1.0", path = "../../domains/primitives/runtime" }
futures = "0.3.26"
Expand All @@ -26,6 +27,5 @@ sp-consensus-subspace = { version = "0.1.0", path = "../sp-consensus-subspace" }
sp-domains = { version = "0.1.0", path = "../sp-domains" }
sp-runtime = { version = "7.0.0", git = "https://github.com/subspace/substrate", rev = "456cfad45a178617f6886ec400c312f2fea59232" }
sp-transaction-pool = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "456cfad45a178617f6886ec400c312f2fea59232" }
subspace-fraud-proof = { version = "0.1.0", path = "../subspace-fraud-proof" }
substrate-prometheus-endpoint = { git = "https://github.com/subspace/substrate", rev = "456cfad45a178617f6886ec400c312f2fea59232" }
tracing = "0.1.37"
13 changes: 0 additions & 13 deletions crates/subspace-transaction-pool/src/bundle_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,19 +307,6 @@ pub trait ValidateBundle<Block: BlockT, DomainHash: Encode> {
) -> Result<(), BundleError>;
}

#[derive(Clone)]
pub struct SkipBundleValidation;

impl<Block: BlockT, DomainHash: Encode> ValidateBundle<Block, DomainHash> for SkipBundleValidation {
fn validate_bundle(
&self,
_at: &BlockId<Block>,
_signed_opaque_bundle: &SignedOpaqueBundle<NumberFor<Block>, Block::Hash, DomainHash>,
) -> Result<(), BundleError> {
Ok(())
}
}

impl<Block, DomainHash, Client> ValidateBundle<Block, DomainHash> for BundleValidator<Block, Client>
where
Block: BlockT,
Expand Down
Loading

0 comments on commit 82b1b9d

Please sign in to comment.