Remove InherentsPool and introduce non-propagateable transactions. (#2695)

* Remove InherentsPool.

* Introduce transactions that are not propagated over the network.

* Bump spec version.

* Use separate flag for propagation.

* Fix tests.
This commit is contained in:
Tomasz Drwięga
2019-05-29 16:06:49 +02:00
committed by Gavin Wood
parent 8d378cb293
commit 25b9c12c20
22 changed files with 250 additions and 171 deletions
-2
View File
@@ -4238,7 +4238,6 @@ dependencies = [
"sr-primitives 2.0.0",
"substrate-client 2.0.0",
"substrate-consensus-common 2.0.0",
"substrate-inherents 2.0.0",
"substrate-offchain-primitives 2.0.0",
"substrate-primitives 2.0.0",
"substrate-test-client 2.0.0",
@@ -4384,7 +4383,6 @@ dependencies = [
"substrate-consensus-common 2.0.0",
"substrate-executor 2.0.0",
"substrate-finality-grandpa 2.0.0",
"substrate-inherents 2.0.0",
"substrate-keystore 2.0.0",
"substrate-network 2.0.0",
"substrate-offchain 2.0.0",
@@ -20,7 +20,7 @@
//
use std::{self, time, sync::Arc};
use log::{info, debug, warn, trace};
use log::{info, debug, trace};
use client::{
self, error, Client as SubstrateClient, CallExecutor,
@@ -36,7 +36,7 @@ use runtime_primitives::traits::{
use runtime_primitives::generic::BlockId;
use runtime_primitives::ApplyError;
use transaction_pool::txpool::{self, Pool as TransactionPool};
use inherents::{InherentData, pool::InherentsPool};
use inherents::InherentData;
use substrate_telemetry::{telemetry, CONSENSUS_INFO};
/// Build new blocks.
@@ -119,8 +119,6 @@ pub struct ProposerFactory<C, A> where A: txpool::ChainApi {
pub client: Arc<C>,
/// The transaction pool.
pub transaction_pool: Arc<TransactionPool<A>>,
/// The inherents pool
pub inherents_pool: Arc<InherentsPool<<A::Block as BlockT>::Extrinsic>>,
}
impl<C, A> consensus_common::Environment<<C as AuthoringApi>::Block> for ProposerFactory<C, A> where
@@ -150,7 +148,6 @@ impl<C, A> consensus_common::Environment<<C as AuthoringApi>::Block> for Propose
parent_id: id,
parent_number: *parent_header.number(),
transaction_pool: self.transaction_pool.clone(),
inherents_pool: self.inherents_pool.clone(),
now: Box::new(time::Instant::now),
};
@@ -165,7 +162,6 @@ pub struct Proposer<Block: BlockT, C, A: txpool::ChainApi> {
parent_id: BlockId<Block>,
parent_number: <<Block as BlockT>::Header as HeaderT>::Number,
transaction_pool: Arc<TransactionPool<A>>,
inherents_pool: Arc<InherentsPool<<Block as BlockT>::Extrinsic>>,
now: Box<Fn() -> time::Instant>,
}
@@ -218,14 +214,6 @@ impl<Block, C, A> Proposer<Block, C, A> where
inherent_data,
inherent_digests.clone(),
|block_builder| {
// Add inherents from the internal pool
let inherents = self.inherents_pool.drain();
debug!("Pushing {} queued inherent extrinsics.", inherents.len());
for i in inherents {
if let Err(e) = block_builder.push_extrinsic(i) {
warn!("Error while pushing inherent extrinsic from the pool: {:?}", e);
}
}
// proceed with transactions
let mut is_first = true;
let mut skipped = 0;
@@ -328,7 +316,6 @@ mod tests {
let proposer_factory = ProposerFactory {
client: client.clone(),
transaction_pool: txpool.clone(),
inherents_pool: Default::default(),
};
let mut proposer = proposer_factory.init(
@@ -350,33 +337,4 @@ mod tests {
assert_eq!(block.extrinsics().len(), 1);
assert_eq!(txpool.ready().count(), 2);
}
#[test]
fn should_include_inherents_from_the_pool() {
// given
let client = Arc::new(test_client::new());
let chain_api = transaction_pool::ChainApi::new(client.clone());
let txpool = Arc::new(TransactionPool::new(Default::default(), chain_api));
let inpool = Arc::new(InherentsPool::default());
let proposer_factory = ProposerFactory {
client: client.clone(),
transaction_pool: txpool.clone(),
inherents_pool: inpool.clone(),
};
inpool.add(extrinsic(0));
let proposer = proposer_factory.init(
&client.header(&BlockId::number(0)).unwrap().unwrap(),
&[]
).unwrap();
// when
let deadline = time::Duration::from_secs(3);
let block = proposer.propose(Default::default(), Default::default(), deadline).unwrap();
// then
assert_eq!(block.extrinsics().len(), 1);
}
}
-3
View File
@@ -44,9 +44,6 @@ use parking_lot::RwLock;
#[cfg(feature = "std")]
use std::{sync::Arc, format};
#[cfg(feature = "std")]
pub mod pool;
pub use runtime_primitives::RuntimeString;
/// An identifier for an inherent.
-75
View File
@@ -1,75 +0,0 @@
// Copyright 2019 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/>.
//! Inherents Pool
use std::{fmt, mem, vec};
use parking_lot::Mutex;
/// Inherents Pool
///
/// The pool is responsible to collect inherents asynchronously generated
/// by some other parts of the code and make them ready for the next block production.
pub struct InherentsPool<T> {
data: Mutex<Vec<T>>,
}
impl<T> Default for InherentsPool<T> {
fn default() -> Self {
InherentsPool {
data: Default::default(),
}
}
}
impl<T: fmt::Debug> fmt::Debug for InherentsPool<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let mut builder = fmt.debug_struct("InherentsPool");
if let Some(data) = self.data.try_lock() {
builder.field("data", &*data);
}
builder.finish()
}
}
impl<T> InherentsPool<T> {
/// Add inherent extrinsic to the pool.
///
/// This inherent will be appended to the next produced block.
pub fn add(&self, extrinsic: T) {
self.data.lock().push(extrinsic);
}
/// Drain all currently queued inherents.
pub fn drain(&self) -> Vec<T> {
mem::replace(&mut *self.data.lock(), vec![])
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_drain_inherents_to_given_data() {
let pool = InherentsPool::default();
pool.add(5);
pool.add(7);
assert_eq!(pool.drain(), vec![5, 7]);
assert_eq!(pool.drain(), vec![]);
}
}
-1
View File
@@ -10,7 +10,6 @@ edition = "2018"
client = { package = "substrate-client", path = "../../core/client" }
consensus = { package = "substrate-consensus-common", path = "../../core/consensus/common" }
futures = "0.1.25"
inherents = { package = "substrate-inherents", path = "../../core/inherents" }
log = "0.4"
offchain-primitives = { package = "substrate-offchain-primitives", path = "./primitives" }
parity-codec = { version = "3.3", features = ["derive"] }
+2 -7
View File
@@ -16,7 +16,6 @@
use std::sync::Arc;
use futures::{Stream, Future, sync::mpsc};
use inherents::pool::InherentsPool;
use log::{info, debug, warn};
use parity_codec::Decode;
use primitives::OffchainExt;
@@ -46,21 +45,18 @@ impl OffchainExt for AsyncApi {
pub(crate) struct Api<A: ChainApi> {
receiver: Option<mpsc::UnboundedReceiver<ExtMessage>>,
transaction_pool: Arc<Pool<A>>,
inherents_pool: Arc<InherentsPool<<A::Block as traits::Block>::Extrinsic>>,
at: BlockId<A::Block>,
}
impl<A: ChainApi> Api<A> {
pub fn new(
transaction_pool: Arc<Pool<A>>,
inherents_pool: Arc<InherentsPool<<A::Block as traits::Block>::Extrinsic>>,
at: BlockId<A::Block>,
) -> (AsyncApi, Self) {
let (tx, rx) = mpsc::unbounded();
let api = Self {
receiver: Some(rx),
transaction_pool,
inherents_pool,
at,
};
(AsyncApi(tx), api)
@@ -90,9 +86,8 @@ impl<A: ChainApi> Api<A> {
info!("Submitting to the pool: {:?} (isSigned: {:?})", xt, xt.is_signed());
match self.transaction_pool.submit_one(&self.at, xt.clone()) {
Ok(hash) => debug!("[{:?}] Offchain transaction added to the pool.", hash),
Err(_) => {
debug!("Offchain inherent added to the pool.");
self.inherents_pool.add(xt);
Err(e) => {
debug!("Couldn't submit transaction: {:?}", e);
},
}
}
+6 -10
View File
@@ -19,8 +19,8 @@
//! The offchain workers is a special function of the runtime that
//! gets executed after block is imported. During execution
//! it's able to asynchronously submit extrinsics that will either
//! be propagated to other nodes (transactions) or will be
//! added to the next block produced by the node as inherents.
//! be propagated to other nodes added to the next block
//! produced by the node as unsigned transactions.
//!
//! Offchain workers can be used for computation-heavy tasks
//! that are not feasible for execution during regular block processing.
@@ -39,7 +39,6 @@ use std::{
};
use client::runtime_api::ApiExt;
use inherents::pool::InherentsPool;
use log::{debug, warn};
use primitives::ExecutionContext;
use runtime_primitives::{
@@ -57,7 +56,6 @@ pub use offchain_primitives::OffchainWorkerApi;
#[derive(Debug)]
pub struct OffchainWorkers<C, Block: traits::Block> {
client: Arc<C>,
inherents_pool: Arc<InherentsPool<<Block as traits::Block>::Extrinsic>>,
executor: TaskExecutor,
_block: PhantomData<Block>,
}
@@ -66,12 +64,10 @@ impl<C, Block: traits::Block> OffchainWorkers<C, Block> {
/// Creates new `OffchainWorkers`.
pub fn new(
client: Arc<C>,
inherents_pool: Arc<InherentsPool<<Block as traits::Block>::Extrinsic>>,
executor: TaskExecutor,
) -> Self {
Self {
client,
inherents_pool,
executor,
_block: PhantomData,
}
@@ -97,7 +93,7 @@ impl<C, Block> OffchainWorkers<C, Block> where
debug!("Checking offchain workers at {:?}: {:?}", at, has_api);
if has_api.unwrap_or(false) {
let (api, runner) = api::Api::new(pool.clone(), self.inherents_pool.clone(), at.clone());
let (api, runner) = api::Api::new(pool.clone(), at.clone());
self.executor.spawn(runner.process());
debug!("Running offchain workers at {:?}", at);
@@ -119,14 +115,14 @@ mod tests {
let runtime = tokio::runtime::Runtime::new().unwrap();
let client = Arc::new(test_client::new());
let pool = Arc::new(Pool::new(Default::default(), ::transaction_pool::ChainApi::new(client.clone())));
let inherents = Arc::new(InherentsPool::default());
// when
let offchain = OffchainWorkers::new(client, inherents.clone(), runtime.executor());
let offchain = OffchainWorkers::new(client, runtime.executor());
offchain.on_block_imported(&0u64, &pool);
// then
runtime.shutdown_on_idle().wait().unwrap();
assert_eq!(inherents.drain().len(), 1);
assert_eq!(pool.status().ready, 1);
assert_eq!(pool.ready().next().unwrap().is_propagateable(), false);
}
}
-1
View File
@@ -16,7 +16,6 @@ exit-future = "0.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
target_info = "0.1"
inherents = { package = "substrate-inherents", path = "../../core/inherents" }
keystore = { package = "substrate-keystore", path = "../../core/keystore" }
sr-io = { path = "../../core/sr-io" }
runtime_primitives = { package = "sr-primitives", path = "../../core/sr-primitives" }
+1 -1
View File
@@ -635,7 +635,7 @@ mod tests {
use super::*;
use consensus_common::BlockOrigin;
use client::LongestChain;
use substrate_test_client::{self, TestClient, AccountKeyring, runtime::Transfer};
use substrate_test_client::{TestClient, AccountKeyring, runtime::Transfer};
#[test]
fn should_remove_transactions_from_the_pool() {
+61 -17
View File
@@ -34,7 +34,6 @@ use parking_lot::Mutex;
use client::BlockchainEvents;
use exit_future::Signal;
use futures::prelude::*;
use inherents::pool::InherentsPool;
use keystore::Store as Keystore;
use log::{info, warn, debug};
use parity_codec::{Encode, Decode};
@@ -76,7 +75,6 @@ pub struct Service<Components: components::Components> {
select_chain: Option<<Components as components::Components>::SelectChain>,
network: Option<Arc<components::NetworkService<Components::Factory>>>,
transaction_pool: Arc<TransactionPool<Components::TransactionPoolApi>>,
inherents_pool: Arc<InherentsPool<ComponentExtrinsic<Components>>>,
keystore: Keystore,
exit: ::exit_future::Exit,
signal: Option<Signal>,
@@ -211,11 +209,9 @@ impl<Components: components::Components> Service<Components> {
.select(exit.clone())
.then(|_| Ok(())));
let inherents_pool = Arc::new(InherentsPool::default());
let offchain_workers = if config.offchain_worker {
Some(Arc::new(offchain::OffchainWorkers::new(
client.clone(),
inherents_pool.clone(),
task_executor.clone(),
)))
} else {
@@ -381,7 +377,6 @@ impl<Components: components::Components> Service<Components> {
network: Some(network),
select_chain,
transaction_pool,
inherents_pool,
signal: Some(signal),
keystore,
config,
@@ -433,11 +428,6 @@ impl<Components> Service<Components> where Components: components::Components {
self.transaction_pool.clone()
}
/// Get shared inherents pool instance.
pub fn inherents_pool(&self) -> Arc<InherentsPool<ComponentExtrinsic<Components>>> {
self.inherents_pool.clone()
}
/// Get shared keystore.
pub fn keystore(&self) -> &Keystore {
&self.keystore
@@ -498,17 +488,32 @@ impl<C: Components> TransactionPoolAdapter<C> {
}
}
/// Get transactions for propagation.
///
/// Function extracted to simplify the test and prevent creating `ServiceFactory`.
fn transactions_to_propagate<PoolApi, B, H, E>(pool: &TransactionPool<PoolApi>)
-> Vec<(H, B::Extrinsic)>
where
PoolApi: ChainApi<Block=B, Hash=H, Error=E>,
B: BlockT,
H: std::hash::Hash + Eq + runtime_primitives::traits::Member + serde::Serialize,
E: txpool::error::IntoPoolError + From<txpool::error::Error>,
{
pool.ready()
.filter(|t| t.is_propagateable())
.map(|t| {
let hash = t.hash.clone();
let ex: B::Extrinsic = t.data.clone();
(hash, ex)
})
.collect()
}
impl<C: Components> network::TransactionPool<ComponentExHash<C>, ComponentBlock<C>> for
TransactionPoolAdapter<C> where <C as components::Components>::RuntimeApi: Send + Sync
{
fn transactions(&self) -> Vec<(ComponentExHash<C>, ComponentExtrinsic<C>)> {
self.pool.ready()
.map(|t| {
let hash = t.hash.clone();
let ex: ComponentExtrinsic<C> = t.data.clone();
(hash, ex)
})
.collect()
transactions_to_propagate(&self.pool)
}
fn import(&self, transaction: &ComponentExtrinsic<C>) -> Option<ComponentExHash<C>> {
@@ -745,3 +750,42 @@ macro_rules! construct_service_factory {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use client::LongestChain;
use consensus_common::SelectChain;
use runtime_primitives::traits::BlindCheckable;
use substrate_test_client::{AccountKeyring, runtime::{Extrinsic, Transfer}};
#[test]
fn should_not_propagate_transactions_that_are_marked_as_such() {
// given
let client = Arc::new(substrate_test_client::new());
let pool = Arc::new(TransactionPool::new(
Default::default(),
transaction_pool::ChainApi::new(client.clone())
));
let best = LongestChain::new(client.backend().clone(), client.import_lock())
.best_chain().unwrap();
let transaction = Transfer {
amount: 5,
nonce: 0,
from: AccountKeyring::Alice.into(),
to: Default::default(),
}.into_signed_tx();
pool.submit_one(&BlockId::hash(best.hash()), transaction.clone()).unwrap();
pool.submit_one(&BlockId::hash(best.hash()), Extrinsic::IncludeData(vec![1])).unwrap();
assert_eq!(pool.status().ready, 2);
// when
let transactions = transactions_to_propagate(&pool);
// then
assert_eq!(transactions.len(), 1);
assert!(transactions[0].1.clone().check().is_ok());
// this should not panic
let _ = transactions[0].1.transfer();
}
}
@@ -30,7 +30,7 @@ pub type TransactionLongevity = u64;
pub type TransactionTag = Vec<u8>;
/// Information on a transaction's validity and, if valid, on how it relates to other transactions.
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
#[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum TransactionValidity {
/// Transaction is invalid. Details are described by the error code.
@@ -59,7 +59,74 @@ pub enum TransactionValidity {
/// Longevity describes minimum number of blocks the validity is correct.
/// After this period transaction should be removed from the pool or revalidated.
longevity: TransactionLongevity,
/// A flag indicating if the transaction should be propagated to other peers.
///
/// By setting `false` here the transaction will still be considered for
/// including in blocks that are authored on the current node, but will
/// never be sent to other peers.
propagate: bool,
},
/// Transaction validity can't be determined.
Unknown(i8),
}
impl Decode for TransactionValidity {
fn decode<I: crate::codec::Input>(value: &mut I) -> Option<Self> {
match value.read_byte()? {
0 => Some(TransactionValidity::Invalid(i8::decode(value)?)),
1 => {
let priority = TransactionPriority::decode(value)?;
let requires = Vec::decode(value)?;
let provides = Vec::decode(value)?;
let longevity = TransactionLongevity::decode(value)?;
let propagate = bool::decode(value).unwrap_or(true);
Some(TransactionValidity::Valid {
priority, requires, provides, longevity, propagate,
})
},
2 => Some(TransactionValidity::Unknown(i8::decode(value)?)),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_decode_with_backward_compat() {
let old_encoding = vec![
1, 5, 0, 0, 0, 0, 0, 0, 0, 4, 16, 1, 2, 3, 4, 4, 12, 4, 5, 6, 42, 0, 0, 0, 0, 0, 0, 0
];
assert_eq!(TransactionValidity::decode(&mut &*old_encoding), Some(TransactionValidity::Valid {
priority: 5,
requires: vec![vec![1, 2, 3, 4]],
provides: vec![vec![4, 5, 6]],
longevity: 42,
propagate: true,
}));
}
#[test]
fn should_encode_and_decode() {
let v = TransactionValidity::Valid {
priority: 5,
requires: vec![vec![1, 2, 3, 4]],
provides: vec![vec![4, 5, 6]],
longevity: 42,
propagate: false,
};
let encoded = v.encode();
assert_eq!(
encoded,
vec![1, 5, 0, 0, 0, 0, 0, 0, 0, 4, 16, 1, 2, 3, 4, 4, 12, 4, 5, 6, 42, 0, 0, 0, 0, 0, 0, 0, 0]
);
// decode back
assert_eq!(TransactionValidity::decode(&mut &*encoded), Some(v));
}
}
+28 -3
View File
@@ -34,8 +34,9 @@ use substrate_client::{
impl_runtime_apis,
};
use runtime_primitives::{
ApplyResult, transaction_validity::TransactionValidity,
ApplyResult,
create_runtime_str,
transaction_validity::TransactionValidity,
traits::{
BlindCheckable, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT,
GetNodeBlockType, GetRuntimeBlockType, AuthorityIdFor, Verify,
@@ -121,14 +122,18 @@ impl BlindCheckable for Extrinsic {
Err(runtime_primitives::BAD_SIGNATURE)
}
},
Extrinsic::IncludeData(data) => Ok(Extrinsic::IncludeData(data)),
Extrinsic::IncludeData(_) => Err(runtime_primitives::BAD_SIGNATURE),
}
}
}
impl ExtrinsicT for Extrinsic {
fn is_signed(&self) -> Option<bool> {
Some(true)
if let Extrinsic::IncludeData(_) = *self {
Some(false)
} else {
Some(true)
}
}
}
@@ -361,6 +366,16 @@ cfg_if! {
impl client_api::TaggedTransactionQueue<Block> for Runtime {
fn validate_transaction(utx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
if let Extrinsic::IncludeData(data) = utx {
return TransactionValidity::Valid {
priority: data.len() as u64,
requires: vec![],
provides: vec![data],
longevity: 1,
propagate: false,
};
}
system::validate_transaction(utx)
}
}
@@ -499,6 +514,16 @@ cfg_if! {
impl client_api::TaggedTransactionQueue<Block> for Runtime {
fn validate_transaction(utx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
if let Extrinsic::IncludeData(data) = utx {
return TransactionValidity::Valid {
priority: data.len() as u64,
requires: vec![],
provides: vec![data],
longevity: 1,
propagate: false,
};
}
system::validate_transaction(utx)
}
}
@@ -190,6 +190,7 @@ pub fn validate_transaction(utx: Extrinsic) -> TransactionValidity {
requires,
provides,
longevity: 64,
propagate: true,
}
}
@@ -100,6 +100,15 @@ pub struct Transaction<Hash, Extrinsic> {
pub requires: Vec<Tag>,
/// Tags that this transaction provides.
pub provides: Vec<Tag>,
/// Should that transaction be propagated.
pub propagate: bool,
}
impl<Hash, Extrinsic> Transaction<Hash, Extrinsic> {
/// Returns `true` if the transaction should be propagated to other peers.
pub fn is_propagateable(&self) -> bool {
self.propagate
}
}
impl<Hash, Extrinsic> fmt::Debug for Transaction<Hash, Extrinsic> where
@@ -123,6 +132,7 @@ impl<Hash, Extrinsic> fmt::Debug for Transaction<Hash, Extrinsic> where
write!(fmt, "priority: {:?}, ", &self.priority)?;
write!(fmt, "valid_till: {:?}, ", &self.valid_till)?;
write!(fmt, "bytes: {:?}, ", &self.bytes)?;
write!(fmt, "propagate: {:?}, ", &self.propagate)?;
write!(fmt, "requires: [")?;
print_tags(fmt, &self.requires)?;
write!(fmt, "], provides: [")?;
@@ -473,6 +483,7 @@ mod tests {
valid_till: 64u64,
requires: vec![],
provides: vec![vec![1]],
propagate: true,
}).unwrap();
// then
@@ -494,6 +505,7 @@ mod tests {
valid_till: 64u64,
requires: vec![],
provides: vec![vec![1]],
propagate: true,
}).unwrap();
pool.import(Transaction {
data: vec![1u8],
@@ -503,6 +515,7 @@ mod tests {
valid_till: 64u64,
requires: vec![],
provides: vec![vec![1]],
propagate: true,
}).unwrap_err();
// then
@@ -525,6 +538,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![0]],
provides: vec![vec![1]],
propagate: true,
}).unwrap();
assert_eq!(pool.ready().count(), 0);
assert_eq!(pool.ready.len(), 0);
@@ -536,6 +550,7 @@ mod tests {
valid_till: 64u64,
requires: vec![],
provides: vec![vec![0]],
propagate: true,
}).unwrap();
// then
@@ -557,6 +572,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![0]],
provides: vec![vec![1]],
propagate: true,
}).unwrap();
pool.import(Transaction {
data: vec![3u8],
@@ -566,6 +582,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![2]],
provides: vec![],
propagate: true,
}).unwrap();
pool.import(Transaction {
data: vec![2u8],
@@ -575,6 +592,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![1]],
provides: vec![vec![3], vec![2]],
propagate: true,
}).unwrap();
pool.import(Transaction {
data: vec![4u8],
@@ -584,6 +602,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![3], vec![4]],
provides: vec![],
propagate: true,
}).unwrap();
assert_eq!(pool.ready().count(), 0);
assert_eq!(pool.ready.len(), 0);
@@ -596,6 +615,7 @@ mod tests {
valid_till: 64u64,
requires: vec![],
provides: vec![vec![0], vec![4]],
propagate: true,
}).unwrap();
// then
@@ -627,6 +647,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![0]],
provides: vec![vec![1]],
propagate: true,
}).unwrap();
pool.import(Transaction {
data: vec![3u8],
@@ -636,6 +657,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![1]],
provides: vec![vec![2]],
propagate: true,
}).unwrap();
assert_eq!(pool.ready().count(), 0);
assert_eq!(pool.ready.len(), 0);
@@ -649,6 +671,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![2]],
provides: vec![vec![0]],
propagate: true,
}).unwrap();
// then
@@ -668,6 +691,7 @@ mod tests {
valid_till: 64u64,
requires: vec![],
provides: vec![vec![0]],
propagate: true,
}).unwrap();
let mut it = pool.ready().into_iter().map(|tx| tx.data[0]);
assert_eq!(it.next(), Some(4));
@@ -695,6 +719,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![0]],
provides: vec![vec![1]],
propagate: true,
}).unwrap();
pool.import(Transaction {
data: vec![3u8],
@@ -704,6 +729,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![1]],
provides: vec![vec![2]],
propagate: true,
}).unwrap();
assert_eq!(pool.ready().count(), 0);
assert_eq!(pool.ready.len(), 0);
@@ -717,6 +743,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![2]],
provides: vec![vec![0]],
propagate: true,
}).unwrap();
// then
@@ -736,6 +763,7 @@ mod tests {
valid_till: 64u64,
requires: vec![],
provides: vec![vec![0]],
propagate: true,
}).unwrap_err();
let mut it = pool.ready().into_iter().map(|tx| tx.data[0]);
assert_eq!(it.next(), None);
@@ -759,6 +787,7 @@ mod tests {
valid_till: 64u64,
requires: vec![],
provides: vec![vec![0], vec![4]],
propagate: true,
}).unwrap();
pool.import(Transaction {
data: vec![1u8],
@@ -768,6 +797,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![0]],
provides: vec![vec![1]],
propagate: true,
}).unwrap();
pool.import(Transaction {
data: vec![3u8],
@@ -777,6 +807,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![2]],
provides: vec![],
propagate: true,
}).unwrap();
pool.import(Transaction {
data: vec![2u8],
@@ -786,6 +817,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![1]],
provides: vec![vec![3], vec![2]],
propagate: true,
}).unwrap();
pool.import(Transaction {
data: vec![4u8],
@@ -795,6 +827,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![3], vec![4]],
provides: vec![],
propagate: true,
}).unwrap();
// future
pool.import(Transaction {
@@ -805,6 +838,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![11]],
provides: vec![],
propagate: true,
}).unwrap();
assert_eq!(pool.ready().count(), 5);
assert_eq!(pool.future.len(), 1);
@@ -830,6 +864,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![0]],
provides: vec![vec![100]],
propagate: true,
}).unwrap();
// ready
pool.import(Transaction {
@@ -840,6 +875,7 @@ mod tests {
valid_till: 64u64,
requires: vec![],
provides: vec![vec![1]],
propagate: true,
}).unwrap();
pool.import(Transaction {
data: vec![2u8],
@@ -849,6 +885,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![2]],
provides: vec![vec![3]],
propagate: true,
}).unwrap();
pool.import(Transaction {
data: vec![3u8],
@@ -858,6 +895,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![1]],
provides: vec![vec![2]],
propagate: true,
}).unwrap();
pool.import(Transaction {
data: vec![4u8],
@@ -867,6 +905,7 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![3], vec![2]],
provides: vec![vec![4]],
propagate: true,
}).unwrap();
assert_eq!(pool.ready().count(), 4);
@@ -901,8 +940,36 @@ mod tests {
valid_till: 64u64,
requires: vec![vec![3], vec![2]],
provides: vec![vec![4]],
propagate: true,
}),
r#"Transaction { hash: 4, priority: 1000, valid_till: 64, bytes: 1, requires: [03,02], provides: [04], data: [4]}"#.to_owned()
"Transaction { \
hash: 4, priority: 1000, valid_till: 64, bytes: 1, propagate: true, \
requires: [03,02], provides: [04], data: [4]}".to_owned()
);
}
#[test]
fn transaction_propagation() {
assert_eq!(Transaction {
data: vec![4u8],
bytes: 1,
hash: 4,
priority: 1_000u64,
valid_till: 64u64,
requires: vec![vec![3], vec![2]],
provides: vec![vec![4]],
propagate: true,
}.is_propagateable(), true);
assert_eq!(Transaction {
data: vec![4u8],
bytes: 1,
hash: 4,
priority: 1_000u64,
valid_till: 64u64,
requires: vec![vec![3], vec![2]],
provides: vec![vec![4]],
propagate: false,
}.is_propagateable(), false);
}
}
@@ -129,7 +129,7 @@ impl<B: ChainApi> Pool<B> {
}
match self.api.validate_transaction(at, xt.clone())? {
TransactionValidity::Valid { priority, requires, provides, longevity } => {
TransactionValidity::Valid { priority, requires, provides, longevity, propagate } => {
Ok(base::Transaction {
data: xt,
bytes,
@@ -137,6 +137,7 @@ impl<B: ChainApi> Pool<B> {
priority,
requires,
provides,
propagate,
valid_till: block_number
.saturated_into::<u64>()
.saturating_add(longevity),
@@ -491,6 +492,7 @@ mod tests {
requires: if nonce > block_number { vec![vec![nonce as u8 - 1]] } else { vec![] },
provides: vec![vec![nonce as u8]],
longevity: 3,
propagate: true,
})
}
}
@@ -499,6 +499,7 @@ mod tests {
valid_till: 2,
requires: vec![vec![1], vec![2]],
provides: vec![vec![3], vec![4]],
propagate: true,
}
}
@@ -558,6 +559,7 @@ mod tests {
valid_till: u64::max_value(), // use the max_value() here for testing.
requires: vec![tx1.provides[0].clone()],
provides: vec![],
propagate: true,
};
// when
@@ -120,6 +120,7 @@ mod tests {
valid_till: 1,
requires: vec![],
provides: vec![],
propagate: true,
};
(hash, tx)
@@ -185,6 +186,7 @@ mod tests {
valid_till,
requires: vec![],
provides: vec![],
propagate: true,
}
}
@@ -53,6 +53,7 @@ impl txpool::ChainApi for TestApi {
requires,
provides,
longevity: 64,
propagate: true,
})
}
-1
View File
@@ -71,7 +71,6 @@ construct_service_factory! {
let proposer = Arc::new(ProposerFactory {
client: service.client(),
transaction_pool: service.transaction_pool(),
inherents_pool: service.inherents_pool(),
});
let client = service.client();
let select_chain = service.select_chain()
-1
View File
@@ -87,7 +87,6 @@ construct_service_factory! {
let proposer = Arc::new(substrate_basic_authorship::ProposerFactory {
client: service.client(),
transaction_pool: service.transaction_pool(),
inherents_pool: service.inherents_pool(),
});
let client = service.client();
+1 -1
View File
@@ -59,7 +59,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
impl_name: create_runtime_str!("substrate-node"),
authoring_version: 10,
spec_version: 88,
impl_version: 89,
impl_version: 90,
apis: RUNTIME_API_VERSIONS,
};
+4 -1
View File
@@ -358,6 +358,7 @@ where
requires,
provides,
longevity: TransactionLongevity::max_value(),
propagate: true,
}
},
(None, None) => UnsignedValidator::validate_unsigned(&xt.deconstruct().0),
@@ -432,6 +433,7 @@ mod tests {
requires: vec![],
provides: vec![],
longevity: std::u64::MAX,
propagate: false,
},
_ => TransactionValidity::Invalid(0),
}
@@ -569,7 +571,8 @@ mod tests {
priority: 0,
requires: vec![],
provides: vec![],
longevity: 18446744073709551615
longevity: 18446744073709551615,
propagate: false,
};
let mut t = new_test_ext();