mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 14:11:09 +00:00
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:
committed by
Gavin Wood
parent
8d378cb293
commit
25b9c12c20
Generated
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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![]);
|
||||
}
|
||||
}
|
||||
@@ -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"] }
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user