Transaction eras (#758)

* Initial groundwork

* A mess.

* Integrate

* Fix tests

* Unit tests

* Tests for unchecked_extrisnic

* fix tab

* Improve binary format.

* fix tests

* Rename extrinsic-pool -> transaction-pool

Closes #770

* Implement unimplemented.

* typo
This commit is contained in:
Gav Wood
2018-09-20 14:01:01 +02:00
committed by GitHub
parent 43068f8fc3
commit 67bf1a6eaa
42 changed files with 782 additions and 232 deletions
+2 -2
View File
@@ -38,7 +38,7 @@ pub fn start<C>(service: &Service<C>, exit: ::exit_future::Exit, handle: TaskExe
let network = service.network();
let client = service.client();
let txpool = service.extrinsic_pool();
let txpool = service.transaction_pool();
let mut last_number = None;
let mut sys = System::new();
@@ -98,7 +98,7 @@ pub fn start<C>(service: &Service<C>, exit: ::exit_future::Exit, handle: TaskExe
Ok(())
});
let txpool = service.extrinsic_pool();
let txpool = service.transaction_pool();
let display_txpool_import = txpool.import_notification_stream().for_each(move |_| {
let status = txpool.light_status();
telemetry!("txpool.import"; "mem_usage" => status.mem_usage, "count" => status.transaction_count, "sender" => status.senders);
+24 -1
View File
@@ -21,7 +21,7 @@ use futures::sync::mpsc;
use parking_lot::{Mutex, RwLock};
use primitives::AuthorityId;
use runtime_primitives::{bft::Justification, generic::{BlockId, SignedBlock, Block as RuntimeBlock}};
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, One, As, NumberFor};
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, One, As, NumberFor, GetHeight, BlockNumberToHash};
use runtime_primitives::BuildStorage;
use primitives::{Blake2Hasher, RlpCodec, H256};
use primitives::storage::{StorageKey, StorageData};
@@ -568,6 +568,29 @@ impl<B, E, Block> Client<B, E, Block> where
}
}
impl<B, E, Block> GetHeight for Client<B, E, Block> where
B: backend::Backend<Block, Blake2Hasher, RlpCodec>,
E: CallExecutor<Block, Blake2Hasher, RlpCodec> + Clone,
Block: BlockT,
{
type BlockNumber = <Block::Header as HeaderT>::Number;
fn get_height(&self) -> Self::BlockNumber {
self.backend.blockchain().info().map(|i| i.best_number).unwrap_or_else(|_| Zero::zero())
}
}
impl<B, E, Block> BlockNumberToHash for Client<B, E, Block> where
B: backend::Backend<Block, Blake2Hasher, RlpCodec>,
E: CallExecutor<Block, Blake2Hasher, RlpCodec> + Clone,
Block: BlockT,
{
type BlockNumber = <Block::Header as HeaderT>::Number;
type Hash = Block::Hash;
fn block_number_to_hash(&self, n: Self::BlockNumber) -> Option<Self::Hash> {
self.block_hash(n).unwrap_or(None)
}
}
impl<B, E, Block> bft::BlockImport<Block> for Client<B, E, Block>
where
B: backend::Backend<Block, Blake2Hasher, RlpCodec>,
+1 -1
View File
@@ -13,7 +13,7 @@ parking_lot = "0.4"
parity-codec = { version = "1.1" }
substrate-client = { path = "../client" }
substrate-executor = { path = "../executor" }
substrate-extrinsic-pool = { path = "../extrinsic-pool" }
substrate-transaction-pool = { path = "../transaction-pool" }
substrate-primitives = { path = "../primitives" }
sr-primitives = { path = "../sr-primitives" }
sr-version = { path = "../sr-version" }
+2 -2
View File
@@ -17,14 +17,14 @@
//! Authoring RPC module errors.
use client;
use extrinsic_pool;
use transaction_pool;
use rpc;
use errors;
error_chain! {
links {
Pool(extrinsic_pool::Error, extrinsic_pool::ErrorKind) #[doc = "Pool error"];
Pool(transaction_pool::Error, transaction_pool::ErrorKind) #[doc = "Pool error"];
Client(client::error::Error, client::error::ErrorKind) #[doc = "Client error"];
}
errors {
+1 -1
View File
@@ -20,7 +20,7 @@ use std::sync::Arc;
use client::{self, Client};
use codec::Decode;
use extrinsic_pool::{
use transaction_pool::{
Pool,
IntoPoolError,
ChainApi as PoolChainApi,
+1 -1
View File
@@ -18,7 +18,7 @@ use super::*;
use std::{sync::Arc, result::Result};
use codec::Encode;
use extrinsic_pool::{VerifiedTransaction, scoring, Transaction, ChainApi, Error as PoolError,
use transaction_pool::{VerifiedTransaction, scoring, Transaction, ChainApi, Error as PoolError,
Readiness, ExtrinsicFor, VerifiedFor};
use test_client::runtime::{Block, Extrinsic, Transfer};
use test_client;
+1 -1
View File
@@ -25,7 +25,7 @@ extern crate jsonrpc_pubsub;
extern crate parking_lot;
extern crate parity_codec as codec;
extern crate substrate_client as client;
extern crate substrate_extrinsic_pool as extrinsic_pool;
extern crate substrate_transaction_pool as transaction_pool;
extern crate substrate_primitives as primitives;
extern crate sr_primitives as runtime_primitives;
extern crate substrate_state_machine as state_machine;
+1 -1
View File
@@ -25,7 +25,7 @@ substrate-client = { path = "../../core/client" }
substrate-client-db = { path = "../../core/client/db" }
parity-codec = { version = "1.1" }
substrate-executor = { path = "../../core/executor" }
substrate-extrinsic-pool = { path = "../../core/extrinsic-pool" }
substrate-transaction-pool = { path = "../../core/transaction-pool" }
substrate-rpc = { path = "../../core/rpc" }
substrate-rpc-servers = { path = "../../core/rpc-servers" }
substrate-telemetry = { path = "../../core/telemetry" }
+21 -21
View File
@@ -26,7 +26,7 @@ use client::{self, Client};
use error;
use network::{self, OnDemand};
use substrate_executor::{NativeExecutor, NativeExecutionDispatch};
use extrinsic_pool::{self, Options as ExtrinsicPoolOptions, Pool as ExtrinsicPool};
use transaction_pool::{self, Options as TransactionPoolOptions, Pool as TransactionPool};
use runtime_primitives::{traits::Block as BlockT, traits::Header as HeaderT, BuildStorage};
use config::Configuration;
use primitives::{Blake2Hasher, RlpCodec, H256};
@@ -101,13 +101,13 @@ pub type ComponentClient<C> = Client<
pub type ComponentBlock<C> = <<C as Components>::Factory as ServiceFactory>::Block;
/// Extrinsic hash type for `Components`
pub type ComponentExHash<C> = <<C as Components>::ExtrinsicPoolApi as extrinsic_pool::ChainApi>::Hash;
pub type ComponentExHash<C> = <<C as Components>::TransactionPoolApi as transaction_pool::ChainApi>::Hash;
/// Extrinsic type.
pub type ComponentExtrinsic<C> = <ComponentBlock<C> as BlockT>::Extrinsic;
/// Extrinsic pool API type for `Components`.
pub type PoolApi<C> = <C as Components>::ExtrinsicPoolApi;
pub type PoolApi<C> = <C as Components>::TransactionPoolApi;
/// A set of traits for the runtime genesis config.
pub trait RuntimeGenesis: Serialize + DeserializeOwned + BuildStorage {}
@@ -124,9 +124,9 @@ pub trait ServiceFactory: 'static {
/// Chain runtime.
type RuntimeDispatch: NativeExecutionDispatch + Send + Sync + 'static;
/// Extrinsic pool backend type for the full client.
type FullExtrinsicPoolApi: extrinsic_pool::ChainApi<Hash=Self::ExtrinsicHash, Block=Self::Block> + Send + 'static;
type FullTransactionPoolApi: transaction_pool::ChainApi<Hash=Self::ExtrinsicHash, Block=Self::Block> + Send + 'static;
/// Extrinsic pool backend type for the light client.
type LightExtrinsicPoolApi: extrinsic_pool::ChainApi<Hash=Self::ExtrinsicHash, Block=Self::Block> + 'static;
type LightTransactionPoolApi: transaction_pool::ChainApi<Hash=Self::ExtrinsicHash, Block=Self::Block> + 'static;
/// Genesis configuration for the runtime.
type Genesis: RuntimeGenesis;
/// Other configuration for service members.
@@ -135,13 +135,13 @@ pub trait ServiceFactory: 'static {
/// Network protocol id.
const NETWORK_PROTOCOL_ID: network::ProtocolId;
//TODO: replace these with a constructor trait. that ExtrinsicPool implements.
//TODO: replace these with a constructor trait. that TransactionPool implements.
/// Extrinsic pool constructor for the full client.
fn build_full_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc<FullClient<Self>>)
-> Result<ExtrinsicPool<Self::FullExtrinsicPoolApi>, error::Error>;
fn build_full_transaction_pool(config: TransactionPoolOptions, client: Arc<FullClient<Self>>)
-> Result<TransactionPool<Self::FullTransactionPoolApi>, error::Error>;
/// Extrinsic pool constructor for the light client.
fn build_light_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc<LightClient<Self>>)
-> Result<ExtrinsicPool<Self::LightExtrinsicPoolApi>, error::Error>;
fn build_light_transaction_pool(config: TransactionPoolOptions, client: Arc<LightClient<Self>>)
-> Result<TransactionPool<Self::LightTransactionPoolApi>, error::Error>;
/// Build network protocol.
fn build_network_protocol(config: &FactoryFullConfiguration<Self>)
@@ -157,7 +157,7 @@ pub trait Components: 'static {
/// Client executor.
type Executor: 'static + client::CallExecutor<FactoryBlock<Self::Factory>, Blake2Hasher, RlpCodec> + Send + Sync;
/// Extrinsic pool type.
type ExtrinsicPoolApi: 'static + extrinsic_pool::ChainApi<Hash=<Self::Factory as ServiceFactory>::ExtrinsicHash, Block=FactoryBlock<Self::Factory>>;
type TransactionPoolApi: 'static + transaction_pool::ChainApi<Hash=<Self::Factory as ServiceFactory>::ExtrinsicHash, Block=FactoryBlock<Self::Factory>>;
/// Create client.
fn build_client(
@@ -170,8 +170,8 @@ pub trait Components: 'static {
), error::Error>;
/// Create extrinsic pool.
fn build_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc<ComponentClient<Self>>)
-> Result<ExtrinsicPool<Self::ExtrinsicPoolApi>, error::Error>;
fn build_transaction_pool(config: TransactionPoolOptions, client: Arc<ComponentClient<Self>>)
-> Result<TransactionPool<Self::TransactionPoolApi>, error::Error>;
}
/// A struct that implement `Components` for the full client.
@@ -183,7 +183,7 @@ impl<Factory: ServiceFactory> Components for FullComponents<Factory> {
type Factory = Factory;
type Executor = FullExecutor<Factory>;
type Backend = FullBackend<Factory>;
type ExtrinsicPoolApi = <Factory as ServiceFactory>::FullExtrinsicPoolApi;
type TransactionPoolApi = <Factory as ServiceFactory>::FullTransactionPoolApi;
fn build_client(
config: &FactoryFullConfiguration<Factory>,
@@ -202,10 +202,10 @@ impl<Factory: ServiceFactory> Components for FullComponents<Factory> {
Ok((Arc::new(client_db::new_client(db_settings, executor, &config.chain_spec, config.execution_strategy)?), None))
}
fn build_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc<ComponentClient<Self>>)
-> Result<ExtrinsicPool<Self::ExtrinsicPoolApi>, error::Error>
fn build_transaction_pool(config: TransactionPoolOptions, client: Arc<ComponentClient<Self>>)
-> Result<TransactionPool<Self::TransactionPoolApi>, error::Error>
{
Factory::build_full_extrinsic_pool(config, client)
Factory::build_full_transaction_pool(config, client)
}
}
@@ -222,7 +222,7 @@ impl<Factory: ServiceFactory> Components for LightComponents<Factory>
type Factory = Factory;
type Executor = LightExecutor<Factory>;
type Backend = LightBackend<Factory>;
type ExtrinsicPoolApi = <Factory as ServiceFactory>::LightExtrinsicPoolApi;
type TransactionPoolApi = <Factory as ServiceFactory>::LightTransactionPoolApi;
fn build_client(
config: &FactoryFullConfiguration<Factory>,
@@ -248,9 +248,9 @@ impl<Factory: ServiceFactory> Components for LightComponents<Factory>
Ok((Arc::new(client), Some(fetcher)))
}
fn build_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc<ComponentClient<Self>>)
-> Result<ExtrinsicPool<Self::ExtrinsicPoolApi>, error::Error>
fn build_transaction_pool(config: TransactionPoolOptions, client: Arc<ComponentClient<Self>>)
-> Result<TransactionPool<Self::TransactionPoolApi>, error::Error>
{
Factory::build_light_extrinsic_pool(config, client)
Factory::build_light_transaction_pool(config, client)
}
}
+3 -3
View File
@@ -17,7 +17,7 @@
//! Service configuration.
use std::net::SocketAddr;
use extrinsic_pool;
use transaction_pool;
use chain_spec::ChainSpec;
pub use client::ExecutionStrategy;
pub use network::Roles;
@@ -38,7 +38,7 @@ pub struct Configuration<C, G: Serialize + DeserializeOwned + BuildStorage> {
/// Node roles.
pub roles: Roles,
/// Extrinsic pool configuration.
pub extrinsic_pool: extrinsic_pool::Options,
pub transaction_pool: transaction_pool::Options,
/// Network configuration.
pub network: NetworkConfiguration,
/// Path to key files.
@@ -77,7 +77,7 @@ impl<C: Default, G: Serialize + DeserializeOwned + BuildStorage> Configuration<C
chain_spec,
name: Default::default(),
roles: Roles::FULL,
extrinsic_pool: Default::default(),
transaction_pool: Default::default(),
network: Default::default(),
keystore_path: Default::default(),
database_path: Default::default(),
+19 -19
View File
@@ -33,7 +33,7 @@ extern crate substrate_executor;
extern crate substrate_client as client;
extern crate substrate_client_db as client_db;
extern crate parity_codec as codec;
extern crate substrate_extrinsic_pool as extrinsic_pool;
extern crate substrate_transaction_pool as transaction_pool;
extern crate substrate_rpc;
extern crate substrate_rpc_servers as rpc;
extern crate target_info;
@@ -73,7 +73,7 @@ use codec::{Encode, Decode};
pub use self::error::{ErrorKind, Error};
pub use config::{Configuration, Roles, PruningMode};
pub use chain_spec::ChainSpec;
pub use extrinsic_pool::{Pool as ExtrinsicPool, Options as ExtrinsicPoolOptions, ChainApi, VerifiedTransaction, IntoPoolError};
pub use transaction_pool::{Pool as TransactionPool, Options as TransactionPoolOptions, ChainApi, VerifiedTransaction, IntoPoolError};
pub use client::ExecutionStrategy;
pub use components::{ServiceFactory, FullBackend, FullExecutor, LightBackend,
@@ -88,7 +88,7 @@ pub use components::{ServiceFactory, FullBackend, FullExecutor, LightBackend,
pub struct Service<Components: components::Components> {
client: Arc<ComponentClient<Components>>,
network: Option<Arc<components::NetworkService<Components::Factory>>>,
extrinsic_pool: Arc<ExtrinsicPool<Components::ExtrinsicPoolApi>>,
transaction_pool: Arc<TransactionPool<Components::TransactionPoolApi>>,
keystore: Keystore,
exit: ::exit_future::Exit,
signal: Option<Signal>,
@@ -150,12 +150,12 @@ impl<Components> Service<Components>
telemetry!("node.start"; "height" => best_header.number().as_(), "best" => ?best_header.hash());
let network_protocol = <Components::Factory>::build_network_protocol(&config)?;
let extrinsic_pool = Arc::new(
Components::build_extrinsic_pool(config.extrinsic_pool, client.clone())?
let transaction_pool = Arc::new(
Components::build_transaction_pool(config.transaction_pool, client.clone())?
);
let extrinsic_pool_adapter = ExtrinsicPoolAdapter::<Components> {
let transaction_pool_adapter = TransactionPoolAdapter::<Components> {
imports_external_transactions: !config.roles == Roles::LIGHT,
pool: extrinsic_pool.clone(),
pool: transaction_pool.clone(),
client: client.clone(),
};
@@ -167,7 +167,7 @@ impl<Components> Service<Components>
chain: client.clone(),
on_demand: on_demand.clone()
.map(|d| d as Arc<network::OnDemandService<ComponentBlock<Components>>>),
transaction_pool: Arc::new(extrinsic_pool_adapter),
transaction_pool: Arc::new(transaction_pool_adapter),
specialization: network_protocol,
};
@@ -177,7 +177,7 @@ impl<Components> Service<Components>
{
// block notifications
let network = network.clone();
let txpool = extrinsic_pool.clone();
let txpool = transaction_pool.clone();
let events = client.import_notification_stream()
.for_each(move |notification| {
@@ -194,7 +194,7 @@ impl<Components> Service<Components>
{
// extrinsic notifications
let network = network.clone();
let events = extrinsic_pool.import_notification_stream()
let events = transaction_pool.import_notification_stream()
// TODO [ToDr] Consider throttling?
.for_each(move |_| {
network.trigger_repropagate();
@@ -218,7 +218,7 @@ impl<Components> Service<Components>
let client = client.clone();
let chain = rpc::apis::chain::Chain::new(client.clone(), task_executor.clone());
let state = rpc::apis::state::State::new(client.clone(), task_executor.clone());
let author = rpc::apis::author::Author::new(client.clone(), extrinsic_pool.clone(), task_executor.clone());
let author = rpc::apis::author::Author::new(client.clone(), transaction_pool.clone(), task_executor.clone());
rpc::rpc_handler::<ComponentBlock<Components>, ComponentExHash<Components>, _, _, _, _, _>(
state,
chain,
@@ -262,7 +262,7 @@ impl<Components> Service<Components>
Ok(Service {
client: client,
network: Some(network),
extrinsic_pool: extrinsic_pool,
transaction_pool: transaction_pool,
signal: Some(signal),
keystore: keystore,
exit,
@@ -283,8 +283,8 @@ impl<Components> Service<Components>
}
/// Get shared extrinsic pool instance.
pub fn extrinsic_pool(&self) -> Arc<ExtrinsicPool<Components::ExtrinsicPoolApi>> {
self.extrinsic_pool.clone()
pub fn transaction_pool(&self) -> Arc<TransactionPool<Components::TransactionPoolApi>> {
self.transaction_pool.clone()
}
/// Get shared keystore.
@@ -350,13 +350,13 @@ impl substrate_rpc::system::SystemApi for RpcConfig {
}
/// Transaction pool adapter.
pub struct ExtrinsicPoolAdapter<C: Components> {
pub struct TransactionPoolAdapter<C: Components> {
imports_external_transactions: bool,
pool: Arc<ExtrinsicPool<C::ExtrinsicPoolApi>>,
pool: Arc<TransactionPool<C::TransactionPoolApi>>,
client: Arc<ComponentClient<C>>,
}
impl<C: Components> ExtrinsicPoolAdapter<C> {
impl<C: Components> TransactionPoolAdapter<C> {
fn best_block_id(&self) -> Option<BlockId<ComponentBlock<C>>> {
self.client.info()
.map(|info| BlockId::hash(info.chain.best_hash))
@@ -367,7 +367,7 @@ impl<C: Components> ExtrinsicPoolAdapter<C> {
}
}
impl<C: Components> network::TransactionPool<ComponentExHash<C>, ComponentBlock<C>> for ExtrinsicPoolAdapter<C> {
impl<C: Components> network::TransactionPool<ComponentExHash<C>, ComponentBlock<C>> for TransactionPoolAdapter<C> {
fn transactions(&self) -> Vec<(ComponentExHash<C>, ComponentExtrinsic<C>)> {
let best_block_id = match self.best_block_id() {
Some(id) => id,
@@ -398,7 +398,7 @@ impl<C: Components> network::TransactionPool<ComponentExHash<C>, ComponentBlock<
Ok(xt) => Some(*xt.hash()),
Err(e) => match e.into_pool_error() {
Ok(e) => match e.kind() {
extrinsic_pool::ErrorKind::AlreadyImported(hash) =>
transaction_pool::ErrorKind::AlreadyImported(hash) =>
Some(::std::str::FromStr::from_str(&hash).map_err(|_| {})
.expect("Hash string is always valid")),
_ => {
@@ -25,10 +25,9 @@ use traits::{self, Member, SimpleArithmetic, MaybeDisplay};
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct CheckedExtrinsic<AccountId, Index, Call> {
/// Who this purports to be from, if anyone (note this is not a signature).
pub signed: Option<AccountId>,
/// The number of extrinsics have come before from the same signer.
pub index: Index,
/// Who this purports to be from and the number of extrinsics have come before
/// from the same signer, if anyone (note this is not a signature).
pub signed: Option<(AccountId, Index)>,
/// The function that should be called.
pub function: Call,
}
@@ -44,15 +43,15 @@ where
type AccountId = AccountId;
type Call = Call;
fn index(&self) -> &Self::Index {
&self.index
fn index(&self) -> Option<&Self::Index> {
self.signed.as_ref().map(|x| &x.1)
}
fn sender(&self) -> Option<&Self::AccountId> {
self.signed.as_ref()
self.signed.as_ref().map(|x| &x.0)
}
fn deconstruct(self) -> (Self::Call, Option<Self::AccountId>) {
(self.function, self.signed)
(self.function, self.signed.map(|x| x.0))
}
}
@@ -0,0 +1,192 @@
// Copyright 2017 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 <http://www.gnu.org/licenses/>.
//! Generic implementation of an unchecked (pre-verification) extrinsic.
use codec::{Decode, Encode, Input, Output};
pub type Period = u64;
pub type Phase = u64;
/// An era to describe the longevity of a transaction.
#[derive(PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub enum Era {
/// The transaction is valid forever. The genesis hash must be present in the signed content.
Immortal,
/// Period and phase are encoded:
/// - The period of validity from the block hash found in the signing material.
/// - The phase in the period that this transaction's lifetime begins (and, importantly,
/// implies which block hash is included in the signature material). If the `period` is
/// greater than 1 << 12, then it will be a factor of the times greater than 1<<12 that
/// `period` is.
Mortal(Period, Phase),
}
/*
E.g. with period == 4:
0 10 20 30 40
0123456789012345678901234567890123456789012
|...|
authored -/ \- expiry
phase = 1
n = Q(current - phase, period) + phase
*/
impl Era {
/// Create a new era based on a period (which should be a power of two between 4 and 65536 inclusive)
/// and a block number on which it should start (or, for long periods, be shortly after the start).
pub fn mortal(period: u64, current: u64) -> Self {
let period = period.checked_next_power_of_two()
.unwrap_or(1 << 16)
.max(4)
.min(1 << 16);
let phase = current % period;
let quantize_factor = (period >> 12).max(1);
let quantized_phase = phase / quantize_factor * quantize_factor;
Era::Mortal(period, quantized_phase)
}
/// Create an "immortal" transaction.
pub fn immortal() -> Self {
Era::Immortal
}
/// `true` if this is an immortal transaction.
pub fn is_immortal(&self) -> bool {
match self {
Era::Immortal => true,
_ => false,
}
}
/// Get the block number of the start of the era whose properties this object
/// describes that `current` belongs to.
pub fn birth(self, current: u64) -> u64 {
match self {
Era::Immortal => 0,
Era::Mortal(period, phase) => (current - phase) / period * period + phase,
}
}
/// Get the block number of the first block at which the era has ended.
pub fn death(self, current: u64) -> u64 {
match self {
Era::Immortal => u64::max_value(),
Era::Mortal(period, _) => self.birth(current) + period,
}
}
}
impl Encode for Era {
fn encode_to<T: Output>(&self, output: &mut T) {
match self {
Era::Immortal => output.push_byte(0),
Era::Mortal(period, phase) => {
let quantize_factor = (*period as u64 >> 12).max(1);
let encoded = (period.trailing_zeros() - 1).max(1).min(15) as u16 | ((phase / quantize_factor) << 4) as u16;
output.push(&encoded);
}
}
}
}
impl Decode for Era {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
let first = input.read_byte()?;
if first == 0 {
Some(Era::Immortal)
} else {
let encoded = first as u64 + ((input.read_byte()? as u64) << 8);
let period = 2 << (encoded % (1 << 4));
let quantize_factor = (period >> 12).max(1);
let phase = (encoded >> 4) * quantize_factor;
if period >= 4 && phase < period {
Some(Era::Mortal(period, phase))
} else {
None
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn immortal_works() {
let e = Era::immortal();
assert_eq!(e.birth(0), 0);
assert_eq!(e.death(0), u64::max_value());
assert_eq!(e.birth(1), 0);
assert_eq!(e.death(1), u64::max_value());
assert_eq!(e.birth(u64::max_value()), 0);
assert_eq!(e.death(u64::max_value()), u64::max_value());
assert!(e.is_immortal());
assert_eq!(e.encode(), vec![0u8]);
assert_eq!(e, Era::decode(&mut&[0u8][..]).unwrap());
}
#[test]
fn mortal_codec_works() {
let e = Era::mortal(64, 42);
assert!(!e.is_immortal());
let expected = vec![5 + 42 % 16 * 16, 42 / 16];
assert_eq!(e.encode(), expected);
assert_eq!(e, Era::decode(&mut&expected[..]).unwrap());
}
#[test]
fn long_period_mortal_codec_works() {
let e = Era::mortal(32768, 20000);
let expected = vec![(14 + 2500 % 16 * 16) as u8, (2500 / 16) as u8];
assert_eq!(e.encode(), expected);
assert_eq!(e, Era::decode(&mut&expected[..]).unwrap());
}
#[test]
fn era_initialisation_works() {
assert_eq!(Era::mortal(64, 42), Era::Mortal(64, 42));
assert_eq!(Era::mortal(32768, 20000), Era::Mortal(32768, 20000));
assert_eq!(Era::mortal(200, 513), Era::Mortal(256, 1));
assert_eq!(Era::mortal(2, 1), Era::Mortal(4, 1));
assert_eq!(Era::mortal(4, 5), Era::Mortal(4, 1));
}
#[test]
fn quantised_clamped_era_initialisation_works() {
// clamp 1000000 to 65536, quantise 1000001 % 65536 to the nearest 4
assert_eq!(Era::mortal(1000000, 1000001), Era::Mortal(65536, 1000001 % 65536 / 4 * 4));
}
#[test]
fn mortal_birth_death_works() {
let e = Era::mortal(4, 6);
for i in 6..10 {
assert_eq!(e.birth(i), 6);
assert_eq!(e.death(i), 10);
}
// wrong because it's outside of the (current...current + period) range
assert_ne!(e.birth(10), 6);
assert_ne!(e.birth(5), 6);
}
}
@@ -19,6 +19,8 @@
// end::description[]
mod unchecked_extrinsic;
mod unchecked_mortal_extrinsic;
mod era;
mod checked_extrinsic;
mod header;
mod block;
@@ -27,6 +29,8 @@ mod digest;
mod tests;
pub use self::unchecked_extrinsic::UncheckedExtrinsic;
pub use self::unchecked_mortal_extrinsic::UncheckedMortalExtrinsic;
pub use self::era::Era;
pub use self::checked_extrinsic::CheckedExtrinsic;
pub use self::header::Header;
pub use self::block::{Block, SignedBlock, BlockId};
@@ -21,7 +21,7 @@ use std::fmt;
use rstd::prelude::*;
use codec::{Decode, Encode, Input};
use traits::{self, Member, SimpleArithmetic, MaybeDisplay};
use traits::{self, Member, SimpleArithmetic, MaybeDisplay, Lookup};
use super::CheckedExtrinsic;
/// A extrinsic right from the external world. This is unchecked and so
@@ -29,10 +29,9 @@ use super::CheckedExtrinsic;
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct UncheckedExtrinsic<Address, Index, Call, Signature> {
/// The signature and address, if this is a signed extrinsic.
pub signature: Option<(Address, Signature)>,
/// The number of extrinsics have come before from the same signer.
pub index: Index,
/// The signature, address and number of extrinsics have come before from
/// the same signer, if this is a signed extrinsic.
pub signature: Option<(Address, Signature, Index)>,
/// The function that should be called.
pub function: Call,
}
@@ -41,17 +40,15 @@ impl<Address, Index, Call, Signature> UncheckedExtrinsic<Address, Index, Call, S
/// New instance of a signed extrinsic aka "transaction".
pub fn new_signed(index: Index, function: Call, signed: Address, signature: Signature) -> Self {
UncheckedExtrinsic {
signature: Some((signed, signature)),
index,
signature: Some((signed, signature, index)),
function,
}
}
/// New instance of an unsigned extrinsic aka "inherent".
pub fn new_unsigned(index: Index, function: Call) -> Self {
pub fn new_unsigned(function: Call) -> Self {
UncheckedExtrinsic {
signature: None,
index,
function,
}
}
@@ -62,7 +59,7 @@ impl<Address, Index, Call, Signature> UncheckedExtrinsic<Address, Index, Call, S
}
}
impl<Address, AccountId, Index, Call, Signature, ThisLookup> traits::Checkable<ThisLookup>
impl<Address, AccountId, Index, Call, Signature, Context> traits::Checkable<Context>
for UncheckedExtrinsic<Address, Index, Call, Signature>
where
Address: Member + MaybeDisplay,
@@ -70,27 +67,25 @@ where
Call: Encode + Member,
Signature: Member + traits::Verify<Signer=AccountId>,
AccountId: Member + MaybeDisplay,
ThisLookup: FnOnce(Address) -> Result<AccountId, &'static str>,
Context: Lookup<Source=Address, Target=AccountId>,
{
type Checked = CheckedExtrinsic<AccountId, Index, Call>;
fn check_with(self, lookup: ThisLookup) -> Result<Self::Checked, &'static str> {
fn check(self, context: &Context) -> Result<Self::Checked, &'static str> {
Ok(match self.signature {
Some((signed, signature)) => {
let payload = (self.index, self.function);
let signed = lookup(signed)?;
Some((signed, signature, index)) => {
let payload = (index, self.function);
let signed = context.lookup(signed)?;
if !::verify_encoded_lazy(&signature, &payload, &signed) {
return Err("bad signature in extrinsic")
}
CheckedExtrinsic {
signed: Some(signed),
index: payload.0,
signed: Some((signed, payload.0)),
function: payload.1,
}
}
None => CheckedExtrinsic {
signed: None,
index: self.index,
function: self.function,
},
})
@@ -114,7 +109,6 @@ where
Some(UncheckedExtrinsic {
signature: Decode::decode(input)?,
index: Decode::decode(input)?,
function: Decode::decode(input)?,
})
}
@@ -136,7 +130,6 @@ where
v.extend(&[0u8; 4]);
self.signature.encode_to(&mut v);
self.index.encode_to(&mut v);
self.function.encode_to(&mut v);
let length = (v.len() - 4) as u32;
@@ -154,6 +147,6 @@ impl<Address, Index, Call, Signature> fmt::Debug for UncheckedExtrinsic<Address,
Call: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "UncheckedExtrinsic({:?}, {:?}, {:?})", self.signature.as_ref().map(|x| &x.0), self.function, self.index)
write!(f, "UncheckedExtrinsic({:?}, {:?})", self.signature.as_ref().map(|x| (&x.0, &x.2)), self.function)
}
}
@@ -0,0 +1,278 @@
// Copyright 2017 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 <http://www.gnu.org/licenses/>.
//! Generic implementation of an unchecked (pre-verification) extrinsic.
#[cfg(feature = "std")]
use std::fmt;
use rstd::prelude::*;
use codec::{Decode, Encode, Input};
use traits::{self, Member, SimpleArithmetic, MaybeDisplay, GetHeight, BlockNumberToHash, Lookup,
Checkable};
use super::{CheckedExtrinsic, Era};
const TRANSACTION_VERSION: u8 = 1;
/// A extrinsic right from the external world. This is unchecked and so
/// can contain a signature.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct UncheckedMortalExtrinsic<Address, Index, Call, Signature> {
/// The signature, address, number of extrinsics have come before from
/// the same signer and an era describing the longevity of this transaction,
/// if this is a signed extrinsic.
pub signature: Option<(Address, Signature, Index, Era)>,
/// The function that should be called.
pub function: Call,
}
impl<Address, Index, Call, Signature> UncheckedMortalExtrinsic<Address, Index, Call, Signature> {
/// New instance of a signed extrinsic aka "transaction".
pub fn new_signed(index: Index, function: Call, signed: Address, signature: Signature, era: Era) -> Self {
UncheckedMortalExtrinsic {
signature: Some((signed, signature, index, era)),
function,
}
}
/// New instance of an unsigned extrinsic aka "inherent".
pub fn new_unsigned(function: Call) -> Self {
UncheckedMortalExtrinsic {
signature: None,
function,
}
}
/// `true` if there is a signature.
pub fn is_signed(&self) -> bool {
self.signature.is_some()
}
}
impl<Address, AccountId, Index, Call, Signature, Context, Hash, BlockNumber> Checkable<Context>
for UncheckedMortalExtrinsic<Address, Index, Call, Signature>
where
Address: Member + MaybeDisplay,
Index: Encode + Member + MaybeDisplay + SimpleArithmetic,
Call: Encode + Member,
Signature: Member + traits::Verify<Signer=AccountId>,
AccountId: Member + MaybeDisplay,
BlockNumber: SimpleArithmetic,
Hash: Encode,
Context: Lookup<Source=Address, Target=AccountId>
+ GetHeight<BlockNumber=BlockNumber>
+ BlockNumberToHash<BlockNumber=BlockNumber, Hash=Hash>,
{
type Checked = CheckedExtrinsic<AccountId, Index, Call>;
fn check(self, context: &Context) -> Result<Self::Checked, &'static str> {
Ok(match self.signature {
Some((signed, signature, index, era)) => {
let h = context.block_number_to_hash(BlockNumber::sa(era.birth(context.get_height().as_())))
.ok_or("transaction birth block ancient")?;
let payload = (index, self.function, h);
let signed = context.lookup(signed)?;
if !::verify_encoded_lazy(&signature, &payload, &signed) {
return Err("bad signature in extrinsic")
}
CheckedExtrinsic {
signed: Some((signed, payload.0)),
function: payload.1,
}
}
None => CheckedExtrinsic {
signed: None,
function: self.function,
},
})
}
}
impl<Address, Index, Call, Signature> Decode
for UncheckedMortalExtrinsic<Address, Index, Call, Signature>
where
Address: Decode,
Signature: Decode,
Index: Decode,
Call: Decode,
{
fn decode<I: Input>(input: &mut I) -> Option<Self> {
// This is a little more complicated than usual since the binary format must be compatible
// with substrate's generic `Vec<u8>` type. Basically this just means accepting that there
// will be a prefix of u32, which has the total number of bytes following (we don't need
// to use this).
let _length_do_not_remove_me_see_above: u32 = Decode::decode(input)?;
let version = input.read_byte()?;
let is_signed = version & 0b1000_0000 != 0;
let version = version & 0b0111_1111;
if version != TRANSACTION_VERSION {
return None
}
Some(UncheckedMortalExtrinsic {
signature: if is_signed { Some(Decode::decode(input)?) } else { None },
function: Decode::decode(input)?,
})
}
}
impl<Address, Index, Call, Signature> Encode
for UncheckedMortalExtrinsic<Address, Index, Call, Signature>
where
Address: Encode,
Signature: Encode,
Index: Encode,
Call: Encode,
{
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
// need to prefix with the total length as u32 to ensure it's binary comptible with
// Vec<u8>. we'll make room for it here, then overwrite once we know the length.
v.extend(&[0u8; 4]);
// 1 byte version id.
match self.signature.as_ref() {
Some(s) => {
v.push(TRANSACTION_VERSION | 0b1000_0000);
s.encode_to(&mut v);
}
None => {
v.push(TRANSACTION_VERSION & 0b0111_1111);
}
}
self.function.encode_to(&mut v);
let length = (v.len() - 4) as u32;
length.using_encoded(|s| v[0..4].copy_from_slice(s));
v
}
}
/// TODO: use derive when possible.
#[cfg(feature = "std")]
impl<Address, Index, Call, Signature> fmt::Debug for UncheckedMortalExtrinsic<Address, Index, Call, Signature> where
Address: fmt::Debug,
Index: fmt::Debug,
Call: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "UncheckedMortalExtrinsic({:?}, {:?})", self.signature.as_ref().map(|x| (&x.0, &x.2)), self.function)
}
}
#[cfg(test)]
mod tests {
use super::*;
struct TestContext;
impl Lookup for TestContext {
type Source = u64;
type Target = u64;
fn lookup(&self, s: u64) -> Result<u64, &'static str> { Ok(s) }
}
impl GetHeight for TestContext {
type BlockNumber = u64;
fn get_height(&self) -> u64 { 42 }
}
impl BlockNumberToHash for TestContext {
type BlockNumber = u64;
type Hash = u64;
fn block_number_to_hash(&self, n: u64) -> Option<u64> { Some(n) }
}
#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Encode, Decode)]
struct TestSig(u64, Vec<u8>);
impl traits::Verify for TestSig {
type Signer = u64;
fn verify<L: traits::Lazy<[u8]>>(&self, mut msg: L, signer: &Self::Signer) -> bool {
*signer == self.0 && msg.get() == &self.1[..]
}
}
const DUMMY_FUNCTION: u64 = 0;
const DUMMY_ACCOUNTID: u64 = 0;
type Ex = UncheckedMortalExtrinsic<u64, u64, u64, TestSig>;
type CEx = CheckedExtrinsic<u64, u64, u64>;
#[test]
fn unsigned_codec_should_work() {
let ux = Ex::new_unsigned(DUMMY_FUNCTION);
let encoded = ux.encode();
assert_eq!(Ex::decode(&mut &encoded[..]), Some(ux));
}
#[test]
fn signed_codec_should_work() {
let ux = Ex::new_signed(0, DUMMY_FUNCTION, DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, DUMMY_FUNCTION, 0u64).encode()), Era::immortal());
let encoded = ux.encode();
assert_eq!(Ex::decode(&mut &encoded[..]), Some(ux));
}
#[test]
fn unsigned_check_should_work() {
let ux = Ex::new_unsigned(DUMMY_FUNCTION);
assert!(!ux.is_signed());
assert!(<Ex as Checkable<TestContext>>::check(ux, &TestContext).is_ok());
}
#[test]
fn badly_signed_check_should_fail() {
let ux = Ex::new_signed(0, DUMMY_FUNCTION, DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, vec![0u8]), Era::immortal());
assert!(ux.is_signed());
assert_eq!(<Ex as Checkable<TestContext>>::check(ux, &TestContext), Err("bad signature in extrinsic"));
}
#[test]
fn immortal_signed_check_should_work() {
let ux = Ex::new_signed(0, DUMMY_FUNCTION, DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, DUMMY_FUNCTION, 0u64).encode()), Era::immortal());
assert!(ux.is_signed());
assert_eq!(<Ex as Checkable<TestContext>>::check(ux, &TestContext), Ok(CEx { signed: Some((DUMMY_ACCOUNTID, 0)), function: DUMMY_FUNCTION }));
}
#[test]
fn mortal_signed_check_should_work() {
let ux = Ex::new_signed(0, DUMMY_FUNCTION, DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, DUMMY_FUNCTION, 42u64).encode()), Era::mortal(32, 42));
assert!(ux.is_signed());
assert_eq!(<Ex as Checkable<TestContext>>::check(ux, &TestContext), Ok(CEx { signed: Some((DUMMY_ACCOUNTID, 0)), function: DUMMY_FUNCTION }));
}
#[test]
fn later_mortal_signed_check_should_work() {
let ux = Ex::new_signed(0, DUMMY_FUNCTION, DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, DUMMY_FUNCTION, 11u64).encode()), Era::mortal(32, 11));
assert!(ux.is_signed());
assert_eq!(<Ex as Checkable<TestContext>>::check(ux, &TestContext), Ok(CEx { signed: Some((DUMMY_ACCOUNTID, 0)), function: DUMMY_FUNCTION }));
}
#[test]
fn too_late_mortal_signed_check_should_fail() {
let ux = Ex::new_signed(0, DUMMY_FUNCTION, DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, DUMMY_FUNCTION, 10u64).encode()), Era::mortal(32, 10));
assert!(ux.is_signed());
assert_eq!(<Ex as Checkable<TestContext>>::check(ux, &TestContext), Err("bad signature in extrinsic"));
}
#[test]
fn too_early_mortal_signed_check_should_fail() {
let ux = Ex::new_signed(0, DUMMY_FUNCTION, DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, DUMMY_FUNCTION, 43u64).encode()), Era::mortal(32, 43));
assert!(ux.is_signed());
assert_eq!(<Ex as Checkable<TestContext>>::check(ux, &TestContext), Err("bad signature in extrinsic"));
}
}
+2 -2
View File
@@ -123,7 +123,7 @@ pub struct TestXt<Call>(pub Option<u64>, pub u64, pub Call);
impl<Call: Codec + Sync + Send + Serialize, Context> Checkable<Context> for TestXt<Call> {
type Checked = Self;
fn check_with(self, _: Context) -> Result<Self::Checked, &'static str> { Ok(self) }
fn check(self, _: &Context) -> Result<Self::Checked, &'static str> { Ok(self) }
}
impl<Call> Applyable for TestXt<Call> where
Call: 'static + Sized + Send + Sync + Clone + Eq + Codec + Debug + Serialize + DeserializeOwned,
@@ -132,7 +132,7 @@ impl<Call> Applyable for TestXt<Call> where
type Index = u64;
type Call = Call;
fn sender(&self) -> Option<&u64> { self.0.as_ref() }
fn index(&self) -> &u64 { &self.1 }
fn index(&self) -> Option<&u64> { self.0.as_ref().map(|_| &self.1) }
fn deconstruct(self) -> (Self::Call, Option<Self::AccountId>) {
(self.2, self.0)
}
+34 -6
View File
@@ -60,7 +60,33 @@ pub trait Lookup {
/// Type to lookup into.
type Target;
/// Attempt a lookup.
fn lookup(s: Self::Source) -> result::Result<Self::Target, &'static str>;
fn lookup(&self, s: Self::Source) -> result::Result<Self::Target, &'static str>;
}
/// Get the "current" block number.
pub trait GetHeight {
/// The type of the block number.
type BlockNumber;
/// Return the current block number. Not allowed to fail.
fn get_height(&self) -> Self::BlockNumber;
}
/// Translate a block number into a hash.
pub trait BlockNumberToHash {
/// The type of the block number.
type BlockNumber: Zero;
/// The type of the hash.
type Hash;
/// Get the hash for a given block number, or `None` if unknown.
fn block_number_to_hash(&self, n: Self::BlockNumber) -> Option<Self::Hash>;
/// Get the genesis block hash; this should always be known.
fn genesis_hash(&self) -> Self::Hash {
self.block_number_to_hash(Zero::zero()).expect("All blockchains must know their genesis block hash; qed")
}
}
/// Simple payment making trait, operating on a single generic `AccountId` type.
@@ -407,10 +433,11 @@ pub type NumberFor<B> = <<B as Block>::Header as Header>::Number;
/// Implement for pieces of information that require some additional context `Context` in order to be
/// checked.
pub trait Checkable<Context>: Sized {
/// Returned if `check_with` succeeds.
/// Returned if `check` succeeds.
type Checked;
fn check_with(self, context: Context) -> Result<Self::Checked, &'static str>;
/// Check self, given an instance of Context.
fn check(self, c: &Context) -> Result<Self::Checked, &'static str>;
}
/// A "checkable" piece of information, used by the standard Substrate Executive in order to
@@ -421,13 +448,14 @@ pub trait BlindCheckable: Sized {
/// Returned if `check` succeeds.
type Checked;
/// Check self.
fn check(self) -> Result<Self::Checked, &'static str>;
}
// Every `BlindCheckable` is also a `Checkable` for arbitrary `Context`.
// Every `BlindCheckable` is also a `StaticCheckable` for arbitrary `Context`.
impl<T: BlindCheckable, Context> Checkable<Context> for T {
type Checked = <Self as BlindCheckable>::Checked;
fn check_with(self, _: Context) -> Result<Self::Checked, &'static str> {
fn check(self, _c: &Context) -> Result<Self::Checked, &'static str> {
BlindCheckable::check(self)
}
}
@@ -442,7 +470,7 @@ pub trait Applyable: Sized + Send + Sync {
type AccountId: Member + MaybeDisplay;
type Index: Member + MaybeDisplay + SimpleArithmetic;
type Call: Member;
fn index(&self) -> &Self::Index;
fn index(&self) -> Option<&Self::Index>;
fn sender(&self) -> Option<&Self::AccountId>;
fn deconstruct(self) -> (Self::Call, Option<Self::AccountId>);
}
@@ -1,5 +1,5 @@
[package]
name = "substrate-extrinsic-pool"
name = "substrate-transaction-pool"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
@@ -1,5 +1,5 @@
= extrinsic-pool
= transaction-pool
.Summary
[source, toml]
@@ -76,15 +76,15 @@ impl<H, T> txpool::Listener<T> for Listener<H> where
}
fn rejected(&mut self, tx: &Arc<T>, reason: &txpool::ErrorKind) {
warn!(target: "extrinsic-pool", "Extrinsic rejected ({}): {:?}", reason, tx);
warn!(target: "transaction-pool", "Extrinsic rejected ({}): {:?}", reason, tx);
}
fn invalid(&mut self, tx: &Arc<T>) {
warn!(target: "extrinsic-pool", "Extrinsic invalid: {:?}", tx);
warn!(target: "transaction-pool", "Extrinsic invalid: {:?}", tx);
}
fn canceled(&mut self, tx: &Arc<T>) {
debug!(target: "extrinsic-pool", "Extrinsic canceled: {:?}", tx);
debug!(target: "transaction-pool", "Extrinsic canceled: {:?}", tx);
}
fn culled(&mut self, tx: &Arc<T>) {
@@ -133,7 +133,7 @@ pub struct Ready<'a, 'b, B: 'a + ChainApi> {
impl<'a, 'b, B: ChainApi> txpool::Ready<VerifiedFor<B>> for Ready<'a, 'b, B> {
fn is_ready(&mut self, xt: &VerifiedFor<B>) -> Readiness {
if self.rotator.ban_if_stale(&self.now, xt) {
debug!(target: "extrinsic-pool", "[{:?}] Banning as stale.", txpool::VerifiedTransaction::hash(xt));
debug!(target: "transaction-pool", "[{:?}] Banning as stale.", txpool::VerifiedTransaction::hash(xt));
return Readiness::Stale;
}