mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 08:51:09 +00:00
Make offchain tx pool creation reusable (#14230)
* Make offchain tx pool creation reusable Introduces an `OffchainTransactionPoolFactory` for creating offchain transactions pools that can be registered in the runtime externalities context. This factory will be required for a later pr to make the creation of offchain transaction pools easier. * Update client/transaction-pool/api/src/lib.rs Co-authored-by: Anton <anton.kalyaev@gmail.com> --------- Co-authored-by: Anton <anton.kalyaev@gmail.com>
This commit is contained in:
@@ -10,11 +10,13 @@ description = "Transaction pool client facing API."
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.57"
|
||||
codec = { package = "parity-scale-codec", version = "3.2.2" }
|
||||
futures = "0.3.21"
|
||||
log = "0.4.17"
|
||||
serde = { version = "1.0.136", features = ["derive"] }
|
||||
thiserror = "1.0.30"
|
||||
sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" }
|
||||
sp-core = { version = "8.0.0", default-features = false, path = "../../../primitives/core" }
|
||||
sp-runtime = { version = "8.0.0", default-features = false, path = "../../../primitives/runtime" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -24,11 +24,17 @@ pub mod error;
|
||||
use async_trait::async_trait;
|
||||
use futures::{Future, Stream};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use sp_core::offchain::TransactionPoolExt;
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, Member, NumberFor},
|
||||
};
|
||||
use std::{collections::HashMap, hash::Hash, pin::Pin, sync::Arc};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
hash::Hash,
|
||||
pin::Pin,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
|
||||
const LOG_TARGET: &str = "txpool::api";
|
||||
|
||||
@@ -329,29 +335,27 @@ pub trait LocalTransactionPool: Send + Sync {
|
||||
/// `TransactionSource::Local`.
|
||||
fn submit_local(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
at: <Self::Block as BlockT>::Hash,
|
||||
xt: LocalTransactionFor<Self>,
|
||||
) -> Result<Self::Hash, Self::Error>;
|
||||
}
|
||||
|
||||
/// An abstraction for transaction pool.
|
||||
/// An abstraction for [`LocalTransactionPool`]
|
||||
///
|
||||
/// This trait is used by offchain calls to be able to submit transactions.
|
||||
/// The main use case is for offchain workers, to feed back the results of computations,
|
||||
/// but since the transaction pool access is a separate `ExternalitiesExtension` it can
|
||||
/// be also used in context of other offchain calls. For one may generate and submit
|
||||
/// a transaction for some misbehavior reports (say equivocation).
|
||||
pub trait OffchainSubmitTransaction<Block: BlockT>: Send + Sync {
|
||||
/// We want to use a transaction pool in [`OffchainTransactionPoolFactory`] in a `Arc` without
|
||||
/// bleeding the associated types besides the `Block`. Thus, this abstraction here exists to achieve
|
||||
/// the wrapping in a `Arc`.
|
||||
trait OffchainSubmitTransaction<Block: BlockT>: Send + Sync {
|
||||
/// Submit transaction.
|
||||
///
|
||||
/// The transaction will end up in the pool and be propagated to others.
|
||||
fn submit_at(&self, at: &BlockId<Block>, extrinsic: Block::Extrinsic) -> Result<(), ()>;
|
||||
fn submit_at(&self, at: Block::Hash, extrinsic: Block::Extrinsic) -> Result<(), ()>;
|
||||
}
|
||||
|
||||
impl<TPool: LocalTransactionPool> OffchainSubmitTransaction<TPool::Block> for TPool {
|
||||
fn submit_at(
|
||||
&self,
|
||||
at: &BlockId<TPool::Block>,
|
||||
at: <TPool::Block as BlockT>::Hash,
|
||||
extrinsic: <TPool::Block as BlockT>::Extrinsic,
|
||||
) -> Result<(), ()> {
|
||||
log::debug!(
|
||||
@@ -372,6 +376,56 @@ impl<TPool: LocalTransactionPool> OffchainSubmitTransaction<TPool::Block> for TP
|
||||
}
|
||||
}
|
||||
|
||||
/// Factory for creating [`TransactionPoolExt`]s.
|
||||
///
|
||||
/// This provides an easy way for creating [`TransactionPoolExt`] extensions for registering them in
|
||||
/// the wasm execution environment to send transactions from an offchain call to the runtime.
|
||||
#[derive(Clone)]
|
||||
pub struct OffchainTransactionPoolFactory<Block: BlockT> {
|
||||
// To break retain cycle between `Client` and `TransactionPool` we require this
|
||||
// extension to be a `Weak` reference.
|
||||
pool: Weak<dyn OffchainSubmitTransaction<Block>>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> OffchainTransactionPoolFactory<Block> {
|
||||
/// Creates a new instance using the given `tx_pool`.
|
||||
pub fn new<T: LocalTransactionPool<Block = Block> + 'static>(tx_pool: &Arc<T>) -> Self {
|
||||
Self { pool: Arc::downgrade(tx_pool) as Weak<_> }
|
||||
}
|
||||
|
||||
/// Returns an instance of [`TransactionPoolExt`] bound to the given `block_hash`.
|
||||
///
|
||||
/// Transactions that are being submitted by this instance will be submitted with `block_hash`
|
||||
/// as context for validation.
|
||||
pub fn offchain_transaction_pool(&self, block_hash: Block::Hash) -> TransactionPoolExt {
|
||||
TransactionPoolExt::new(OffchainTransactionPool { pool: self.pool.clone(), block_hash })
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps a `pool` and `block_hash` to implement [`sp_core::offchain::TransactionPool`].
|
||||
struct OffchainTransactionPool<Block: BlockT> {
|
||||
block_hash: Block::Hash,
|
||||
pool: Weak<dyn OffchainSubmitTransaction<Block>>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> sp_core::offchain::TransactionPool for OffchainTransactionPool<Block> {
|
||||
fn submit_transaction(&mut self, extrinsic: Vec<u8>) -> Result<(), ()> {
|
||||
let extrinsic = match codec::Decode::decode(&mut &extrinsic[..]) {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
log::error!(
|
||||
target: LOG_TARGET,
|
||||
"Failed to decode extrinsic in `OffchainTransactionPool::submit_transaction`: {e:?}"
|
||||
);
|
||||
|
||||
return Err(())
|
||||
},
|
||||
};
|
||||
|
||||
self.pool.upgrade().ok_or(())?.submit_at(self.block_hash, extrinsic)
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper functions to keep the API backwards compatible over the wire for the old RPC spec.
|
||||
mod v1_compatible {
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
@@ -52,8 +52,8 @@ use std::{
|
||||
use graph::{ExtrinsicHash, IsValidator};
|
||||
use sc_transaction_pool_api::{
|
||||
error::Error as TxPoolError, ChainEvent, ImportNotificationStream, MaintainedTransactionPool,
|
||||
PoolFuture, PoolStatus, ReadyTransactions, TransactionFor, TransactionPool, TransactionSource,
|
||||
TransactionStatusStreamFor, TxHash,
|
||||
OffchainTransactionPoolFactory, PoolFuture, PoolStatus, ReadyTransactions, TransactionFor,
|
||||
TransactionPool, TransactionSource, TransactionStatusStreamFor, TxHash,
|
||||
};
|
||||
use sp_core::traits::SpawnEssentialNamed;
|
||||
use sp_runtime::{
|
||||
@@ -397,7 +397,9 @@ where
|
||||
));
|
||||
|
||||
// make transaction pool available for off-chain runtime calls.
|
||||
client.execution_extensions().register_transaction_pool(&pool);
|
||||
client
|
||||
.execution_extensions()
|
||||
.register_transaction_pool_factory(OffchainTransactionPoolFactory::new(&pool));
|
||||
|
||||
pool
|
||||
}
|
||||
@@ -421,7 +423,7 @@ where
|
||||
|
||||
fn submit_local(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
at: Block::Hash,
|
||||
xt: sc_transaction_pool_api::LocalTransactionFor<Self>,
|
||||
) -> Result<Self::Hash, Self::Error> {
|
||||
use sp_runtime::{
|
||||
@@ -430,7 +432,11 @@ where
|
||||
|
||||
let validity = self
|
||||
.api
|
||||
.validate_transaction_blocking(at, TransactionSource::Local, xt.clone())?
|
||||
.validate_transaction_blocking(
|
||||
&BlockId::hash(at),
|
||||
TransactionSource::Local,
|
||||
xt.clone(),
|
||||
)?
|
||||
.map_err(|e| {
|
||||
Self::Error::Pool(match e {
|
||||
TransactionValidityError::Invalid(i) => TxPoolError::InvalidTransaction(i),
|
||||
@@ -441,7 +447,7 @@ where
|
||||
let (hash, bytes) = self.pool.validated_pool().api().hash_and_length(&xt);
|
||||
let block_number = self
|
||||
.api
|
||||
.block_id_to_number(at)?
|
||||
.block_id_to_number(&BlockId::hash(at))?
|
||||
.ok_or_else(|| error::Error::BlockIdConversion(format!("{:?}", at)))?;
|
||||
|
||||
let validated = ValidatedTransaction::valid_at(
|
||||
|
||||
Reference in New Issue
Block a user