// Copyright 2018-2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see .
//! Chain api required for the transaction pool.
use std::{marker::PhantomData, pin::Pin, sync::Arc};
use codec::{Decode, Encode};
use futures::{
channel::oneshot, executor::{ThreadPool, ThreadPoolBuilder}, future::{Future, FutureExt, ready, Ready},
};
use sc_client_api::{
blockchain::HeaderBackend,
light::{Fetcher, RemoteCallRequest, RemoteBodyRequest},
BlockBody,
};
use sp_core::Hasher;
use sp_runtime::{
generic::BlockId, traits::{self, Block as BlockT, BlockIdTo, Header as HeaderT, Hash as HashT},
transaction_validity::TransactionValidity,
};
use sp_transaction_pool::runtime_api::TaggedTransactionQueue;
use sp_api::ProvideRuntimeApi;
use crate::error::{self, Error};
/// The transaction pool logic for full client.
pub struct FullChainApi {
client: Arc,
pool: ThreadPool,
_marker: PhantomData,
}
impl FullChainApi where
Block: BlockT,
Client: ProvideRuntimeApi + BlockIdTo,
{
/// Create new transaction pool logic.
pub fn new(client: Arc) -> Self {
FullChainApi {
client,
pool: ThreadPoolBuilder::new()
.pool_size(2)
.name_prefix("txpool-verifier")
.create()
.expect("Failed to spawn verifier threads, that are critical for node operation."),
_marker: Default::default()
}
}
}
impl sc_transaction_graph::ChainApi for FullChainApi where
Block: BlockT,
Client: ProvideRuntimeApi + BlockBody + BlockIdTo,
Client: Send + Sync + 'static,
Client::Api: TaggedTransactionQueue,
sp_api::ApiErrorFor: Send,
{
type Block = Block;
type Hash = Block::Hash;
type Error = error::Error;
type ValidationFuture = Pin> + Send>>;
type BodyFuture = Ready::Extrinsic>>>>;
fn block_body(&self, id: &BlockId) -> Self::BodyFuture {
ready(self.client.block_body(&id).map_err(|e| error::Error::from(e)))
}
fn validate_transaction(
&self,
at: &BlockId,
uxt: sc_transaction_graph::ExtrinsicFor,
) -> Self::ValidationFuture {
let (tx, rx) = oneshot::channel();
let client = self.client.clone();
let at = at.clone();
self.pool.spawn_ok(futures_diagnose::diagnose("validate-transaction", async move {
let res = client.runtime_api().validate_transaction(&at, uxt)
.map_err(|e| Error::RuntimeApi(format!("{:?}", e)));
if let Err(e) = tx.send(res) {
log::warn!("Unable to send a validate transaction result: {:?}", e);
}
}));
Box::pin(async move {
match rx.await {
Ok(r) => r,
Err(_) => Err(Error::RuntimeApi("Validation was canceled".into())),
}
})
}
fn block_id_to_number(
&self,
at: &BlockId,
) -> error::Result