mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 21:11:07 +00:00
Pass transaction source to validate_transaction (#5366)
* WiP * Support source in the runtime API. * Finish implementation in txpool. * Fix warning. * Fix tests. * Apply suggestions from code review Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-Authored-By: Nikolay Volf <nikvolf@gmail.com> * Extra changes. * Fix test and benches. * fix test * Fix test & benches again. * Fix tests. * Update bumpalo * Fix doc test. * Fix doctest. * Fix doctest. Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Nikolay Volf <nikvolf@gmail.com>
This commit is contained in:
@@ -11,8 +11,8 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
||||
use sp_std::prelude::*;
|
||||
use sp_core::OpaqueMetadata;
|
||||
use sp_runtime::{
|
||||
ApplyExtrinsicResult, transaction_validity::TransactionValidity, generic, create_runtime_str,
|
||||
impl_opaque_keys, MultiSignature,
|
||||
ApplyExtrinsicResult, generic, create_runtime_str, impl_opaque_keys, MultiSignature,
|
||||
transaction_validity::{TransactionValidity, TransactionSource},
|
||||
};
|
||||
use sp_runtime::traits::{
|
||||
BlakeTwo256, Block as BlockT, IdentityLookup, Verify, ConvertInto, IdentifyAccount
|
||||
@@ -318,8 +318,11 @@ impl_runtime_apis! {
|
||||
}
|
||||
|
||||
impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
|
||||
fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
|
||||
Executive::validate_transaction(tx)
|
||||
fn validate_transaction(
|
||||
source: TransactionSource,
|
||||
tx: <Block as BlockT>::Extrinsic,
|
||||
) -> TransactionValidity {
|
||||
Executive::validate_transaction(source, tx)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ fn should_submit_signed_twice_from_the_same_account() {
|
||||
fn submitted_transaction_should_be_valid() {
|
||||
use codec::Encode;
|
||||
use frame_support::storage::StorageMap;
|
||||
use sp_runtime::transaction_validity::ValidTransaction;
|
||||
use sp_runtime::transaction_validity::{ValidTransaction, TransactionSource};
|
||||
use sp_runtime::traits::StaticLookup;
|
||||
|
||||
let mut t = new_test_ext(COMPACT_CODE, false);
|
||||
@@ -163,6 +163,7 @@ fn submitted_transaction_should_be_valid() {
|
||||
let tx0 = state.read().transactions[0].clone();
|
||||
let mut t = new_test_ext(COMPACT_CODE, false);
|
||||
t.execute_with(|| {
|
||||
let source = TransactionSource::External;
|
||||
let extrinsic = UncheckedExtrinsic::decode(&mut &*tx0).unwrap();
|
||||
// add balance to the account
|
||||
let author = extrinsic.signature.clone().unwrap().0;
|
||||
@@ -172,7 +173,7 @@ fn submitted_transaction_should_be_valid() {
|
||||
<frame_system::Account<Runtime>>::insert(&address, account);
|
||||
|
||||
// check validity
|
||||
let res = Executive::validate_transaction(extrinsic);
|
||||
let res = Executive::validate_transaction(source, extrinsic);
|
||||
|
||||
assert_eq!(res.unwrap(), ValidTransaction {
|
||||
priority: 2_411_002_000_000,
|
||||
|
||||
@@ -35,7 +35,7 @@ use sp_runtime::{
|
||||
impl_opaque_keys, generic, create_runtime_str,
|
||||
};
|
||||
use sp_runtime::curve::PiecewiseLinear;
|
||||
use sp_runtime::transaction_validity::TransactionValidity;
|
||||
use sp_runtime::transaction_validity::{TransactionValidity, TransactionSource};
|
||||
use sp_runtime::traits::{
|
||||
self, BlakeTwo256, Block as BlockT, StaticLookup, SaturatedConversion,
|
||||
ConvertInto, OpaqueKeys,
|
||||
@@ -734,8 +734,11 @@ impl_runtime_apis! {
|
||||
}
|
||||
|
||||
impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
|
||||
fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
|
||||
Executive::validate_transaction(tx)
|
||||
fn validate_transaction(
|
||||
source: TransactionSource,
|
||||
tx: <Block as BlockT>::Extrinsic,
|
||||
) -> TransactionValidity {
|
||||
Executive::validate_transaction(source, tx)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -315,13 +315,15 @@ mod tests {
|
||||
prelude::*,
|
||||
runtime::{Extrinsic, Transfer},
|
||||
};
|
||||
use sp_transaction_pool::{ChainEvent, MaintainedTransactionPool};
|
||||
use sp_transaction_pool::{ChainEvent, MaintainedTransactionPool, TransactionSource};
|
||||
use sc_transaction_pool::{BasicPool, FullChainApi};
|
||||
use sp_api::Core;
|
||||
use backend::Backend;
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_runtime::traits::NumberFor;
|
||||
|
||||
const SOURCE: TransactionSource = TransactionSource::External;
|
||||
|
||||
fn extrinsic(nonce: u64) -> Extrinsic {
|
||||
Transfer {
|
||||
amount: Default::default(),
|
||||
@@ -338,7 +340,7 @@ mod tests {
|
||||
id: BlockId::Number(block_number.into()),
|
||||
retracted: vec![],
|
||||
is_new_best: true,
|
||||
header: header,
|
||||
header,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,7 +353,7 @@ mod tests {
|
||||
);
|
||||
|
||||
futures::executor::block_on(
|
||||
txpool.submit_at(&BlockId::number(0), vec![extrinsic(0), extrinsic(1)])
|
||||
txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0), extrinsic(1)])
|
||||
).unwrap();
|
||||
|
||||
futures::executor::block_on(
|
||||
@@ -403,7 +405,7 @@ mod tests {
|
||||
let block_id = BlockId::Hash(genesis_hash);
|
||||
|
||||
futures::executor::block_on(
|
||||
txpool.submit_at(&BlockId::number(0), vec![extrinsic(0)]),
|
||||
txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0)]),
|
||||
).unwrap();
|
||||
|
||||
futures::executor::block_on(
|
||||
@@ -454,7 +456,7 @@ mod tests {
|
||||
);
|
||||
|
||||
futures::executor::block_on(
|
||||
txpool.submit_at(&BlockId::number(0), vec![
|
||||
txpool.submit_at(&BlockId::number(0), SOURCE, vec![
|
||||
extrinsic(0),
|
||||
extrinsic(1),
|
||||
Transfer {
|
||||
|
||||
@@ -224,7 +224,7 @@ mod tests {
|
||||
txpool::Options,
|
||||
};
|
||||
use substrate_test_runtime_transaction_pool::{TestApi, uxt};
|
||||
use sp_transaction_pool::{TransactionPool, MaintainedTransactionPool};
|
||||
use sp_transaction_pool::{TransactionPool, MaintainedTransactionPool, TransactionSource};
|
||||
use sp_runtime::generic::BlockId;
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_consensus::ImportedAux;
|
||||
@@ -236,6 +236,8 @@ mod tests {
|
||||
Arc::new(TestApi::empty())
|
||||
}
|
||||
|
||||
const SOURCE: TransactionSource = TransactionSource::External;
|
||||
|
||||
#[tokio::test]
|
||||
async fn instant_seal() {
|
||||
let builder = TestClientBuilder::new();
|
||||
@@ -278,7 +280,7 @@ mod tests {
|
||||
rt.block_on(future);
|
||||
});
|
||||
// submit a transaction to pool.
|
||||
let result = pool.submit_one(&BlockId::Number(0), uxt(Alice, 0)).await;
|
||||
let result = pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Alice, 0)).await;
|
||||
// assert that it was successfully imported
|
||||
assert!(result.is_ok());
|
||||
// assert that the background task returns ok
|
||||
@@ -330,7 +332,7 @@ mod tests {
|
||||
rt.block_on(future);
|
||||
});
|
||||
// submit a transaction to pool.
|
||||
let result = pool.submit_one(&BlockId::Number(0), uxt(Alice, 0)).await;
|
||||
let result = pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Alice, 0)).await;
|
||||
// assert that it was successfully imported
|
||||
assert!(result.is_ok());
|
||||
let (tx, rx) = futures::channel::oneshot::channel();
|
||||
@@ -399,7 +401,7 @@ mod tests {
|
||||
rt.block_on(future);
|
||||
});
|
||||
// submit a transaction to pool.
|
||||
let result = pool.submit_one(&BlockId::Number(0), uxt(Alice, 0)).await;
|
||||
let result = pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Alice, 0)).await;
|
||||
// assert that it was successfully imported
|
||||
assert!(result.is_ok());
|
||||
|
||||
@@ -430,7 +432,7 @@ mod tests {
|
||||
);
|
||||
// assert that there's a new block in the db.
|
||||
assert!(backend.blockchain().header(BlockId::Number(0)).unwrap().is_some());
|
||||
assert!(pool.submit_one(&BlockId::Number(1), uxt(Alice, 1)).await.is_ok());
|
||||
assert!(pool.submit_one(&BlockId::Number(1), SOURCE, uxt(Alice, 1)).await.is_ok());
|
||||
|
||||
pool.maintain(sp_transaction_pool::ChainEvent::NewBlock {
|
||||
id: BlockId::Number(1),
|
||||
@@ -453,7 +455,7 @@ mod tests {
|
||||
assert!(backend.blockchain().header(BlockId::Number(1)).unwrap().is_some());
|
||||
pool_api.increment_nonce(Alice.into());
|
||||
|
||||
assert!(pool.submit_one(&BlockId::Number(2), uxt(Alice, 2)).await.is_ok());
|
||||
assert!(pool.submit_one(&BlockId::Number(2), SOURCE, uxt(Alice, 2)).await.is_ok());
|
||||
let (tx2, rx2) = futures::channel::oneshot::channel();
|
||||
assert!(sink.send(EngineCommand::SealNewBlock {
|
||||
parent_hash: Some(created_block.hash),
|
||||
|
||||
@@ -191,7 +191,8 @@ mod tests {
|
||||
at: &BlockId<Block>,
|
||||
extrinsic: <Block as traits::Block>::Extrinsic,
|
||||
) -> Result<(), ()> {
|
||||
futures::executor::block_on(self.0.submit_one(&at, extrinsic))
|
||||
let source = sp_transaction_pool::TransactionSource::Local;
|
||||
futures::executor::block_on(self.0.submit_one(&at, source, extrinsic))
|
||||
.map(|_| ())
|
||||
.map_err(|_| ())
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ use sp_core::{Bytes, traits::BareCryptoStorePtr};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_runtime::generic;
|
||||
use sp_transaction_pool::{
|
||||
TransactionPool, InPoolTransaction, TransactionStatus,
|
||||
TransactionPool, InPoolTransaction, TransactionStatus, TransactionSource,
|
||||
BlockHash, TxHash, TransactionFor, error::IntoPoolError,
|
||||
};
|
||||
use sp_session::SessionKeys;
|
||||
@@ -75,6 +75,14 @@ impl<P, Client> Author<P, Client> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Currently we treat all RPC transactions as externals.
|
||||
///
|
||||
/// Possibly in the future we could allow opt-in for special treatment
|
||||
/// of such transactions, so that the block authors can inject
|
||||
/// some unique transactions via RPC and have them included in the pool.
|
||||
const TX_SOURCE: TransactionSource = TransactionSource::External;
|
||||
|
||||
impl<P, Client> AuthorApi<TxHash<P>, BlockHash<P>> for Author<P, Client>
|
||||
where
|
||||
P: TransactionPool + Sync + Send + 'static,
|
||||
@@ -127,7 +135,7 @@ impl<P, Client> AuthorApi<TxHash<P>, BlockHash<P>> for Author<P, Client>
|
||||
};
|
||||
let best_block_hash = self.client.info().best_hash;
|
||||
Box::new(self.pool
|
||||
.submit_one(&generic::BlockId::hash(best_block_hash), xt)
|
||||
.submit_one(&generic::BlockId::hash(best_block_hash), TX_SOURCE, xt)
|
||||
.compat()
|
||||
.map_err(|e| e.into_pool_error()
|
||||
.map(Into::into)
|
||||
@@ -173,7 +181,7 @@ impl<P, Client> AuthorApi<TxHash<P>, BlockHash<P>> for Author<P, Client>
|
||||
.map_err(error::Error::from)?;
|
||||
Ok(
|
||||
self.pool
|
||||
.submit_and_watch(&generic::BlockId::hash(best_block_hash), dxt)
|
||||
.submit_and_watch(&generic::BlockId::hash(best_block_hash), TX_SOURCE, dxt)
|
||||
.map_err(|e| e.into_pool_error()
|
||||
.map(error::Error::from)
|
||||
.unwrap_or_else(|e| error::Error::Verification(Box::new(e)).into())
|
||||
|
||||
@@ -403,7 +403,7 @@ fn should_return_runtime_version() {
|
||||
|
||||
let result = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\
|
||||
\"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",2],\
|
||||
[\"0x37e397fc7c91f5e4\",1],[\"0xd2bc9897eed08f15\",1],[\"0x40fe3ad401f8959a\",4],\
|
||||
[\"0x37e397fc7c91f5e4\",1],[\"0xd2bc9897eed08f15\",2],[\"0x40fe3ad401f8959a\",4],\
|
||||
[\"0xc6e9a76309f39b09\",1],[\"0xdd718d5cc53262d4\",1],[\"0xcbca25e39f142387\",1],\
|
||||
[\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]]}";
|
||||
|
||||
|
||||
@@ -621,7 +621,8 @@ where
|
||||
match Decode::decode(&mut &encoded[..]) {
|
||||
Ok(uxt) => {
|
||||
let best_block_id = BlockId::hash(self.client.info().best_hash);
|
||||
let import_future = self.pool.submit_one(&best_block_id, uxt);
|
||||
let source = sp_transaction_pool::TransactionSource::External;
|
||||
let import_future = self.pool.submit_one(&best_block_id, source, uxt);
|
||||
let import_future = import_future
|
||||
.map(move |import_result| {
|
||||
match import_result {
|
||||
@@ -674,6 +675,7 @@ mod tests {
|
||||
Default::default(),
|
||||
Arc::new(FullChainApi::new(client.clone())),
|
||||
).0);
|
||||
let source = sp_runtime::transaction_validity::TransactionSource::External;
|
||||
let best = longest_chain.best_chain().unwrap();
|
||||
let transaction = Transfer {
|
||||
amount: 5,
|
||||
@@ -681,8 +683,12 @@ mod tests {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: Default::default(),
|
||||
}.into_signed_tx();
|
||||
block_on(pool.submit_one(&BlockId::hash(best.hash()), transaction.clone())).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::hash(best.hash()), Extrinsic::IncludeData(vec![1]))).unwrap();
|
||||
block_on(pool.submit_one(
|
||||
&BlockId::hash(best.hash()), source, transaction.clone()),
|
||||
).unwrap();
|
||||
block_on(pool.submit_one(
|
||||
&BlockId::hash(best.hash()), source, Extrinsic::IncludeData(vec![1])),
|
||||
).unwrap();
|
||||
assert_eq!(pool.status().ready, 2);
|
||||
|
||||
// when
|
||||
|
||||
@@ -482,9 +482,10 @@ pub fn sync<G, E, Fb, F, Lb, L, B, ExF, U>(
|
||||
let first_user_data = &network.full_nodes[0].2;
|
||||
let best_block = BlockId::number(first_service.get().client().chain_info().best_number);
|
||||
let extrinsic = extrinsic_factory(&first_service.get(), first_user_data);
|
||||
let source = sp_transaction_pool::TransactionSource::External;
|
||||
|
||||
futures::executor::block_on(
|
||||
first_service.get().transaction_pool().submit_one(&best_block, extrinsic)
|
||||
first_service.get().transaction_pool().submit_one(&best_block, source, extrinsic)
|
||||
).expect("failed to submit extrinsic");
|
||||
|
||||
network.run_until_all_full(
|
||||
|
||||
@@ -18,12 +18,14 @@ use criterion::{criterion_group, criterion_main, Criterion};
|
||||
|
||||
use futures::{future::{ready, Ready}, executor::block_on};
|
||||
use sc_transaction_graph::*;
|
||||
use sp_runtime::transaction_validity::{ValidTransaction, InvalidTransaction};
|
||||
use codec::Encode;
|
||||
use substrate_test_runtime::{Block, Extrinsic, Transfer, H256, AccountId};
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
transaction_validity::{TransactionValidity, TransactionTag as Tag},
|
||||
transaction_validity::{
|
||||
ValidTransaction, InvalidTransaction, TransactionValidity, TransactionTag as Tag,
|
||||
TransactionSource,
|
||||
},
|
||||
};
|
||||
use sp_core::blake2_256;
|
||||
|
||||
@@ -55,6 +57,7 @@ impl ChainApi for TestApi {
|
||||
fn validate_transaction(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
_source: TransactionSource,
|
||||
uxt: ExtrinsicFor<Self>,
|
||||
) -> Self::ValidationFuture {
|
||||
let nonce = uxt.transfer().nonce;
|
||||
@@ -121,6 +124,7 @@ fn uxt(transfer: Transfer) -> Extrinsic {
|
||||
}
|
||||
|
||||
fn bench_configured(pool: Pool<TestApi>, number: u64) {
|
||||
let source = TransactionSource::External;
|
||||
let mut futures = Vec::new();
|
||||
let mut tags = Vec::new();
|
||||
|
||||
@@ -133,7 +137,7 @@ fn bench_configured(pool: Pool<TestApi>, number: u64) {
|
||||
});
|
||||
|
||||
tags.push(to_tag(nonce, AccountId::from_h256(H256::from_low_u64_be(1))));
|
||||
futures.push(pool.submit_one(&BlockId::Number(1), xt));
|
||||
futures.push(pool.submit_one(&BlockId::Number(1), source, xt));
|
||||
}
|
||||
|
||||
let res = block_on(futures::future::join_all(futures.into_iter()));
|
||||
|
||||
@@ -33,6 +33,7 @@ use sp_runtime::transaction_validity::{
|
||||
TransactionTag as Tag,
|
||||
TransactionLongevity as Longevity,
|
||||
TransactionPriority as Priority,
|
||||
TransactionSource as Source,
|
||||
};
|
||||
use sp_transaction_pool::{error, PoolStatus, InPoolTransaction};
|
||||
|
||||
@@ -102,6 +103,8 @@ pub struct Transaction<Hash, Extrinsic> {
|
||||
pub provides: Vec<Tag>,
|
||||
/// Should that transaction be propagated.
|
||||
pub propagate: bool,
|
||||
/// Source of that transaction.
|
||||
pub source: Source,
|
||||
}
|
||||
|
||||
impl<Hash, Extrinsic> AsRef<Extrinsic> for Transaction<Hash, Extrinsic> {
|
||||
@@ -155,6 +158,7 @@ impl<Hash: Clone, Extrinsic: Clone> Transaction<Hash, Extrinsic> {
|
||||
bytes: self.bytes.clone(),
|
||||
hash: self.hash.clone(),
|
||||
priority: self.priority.clone(),
|
||||
source: self.source,
|
||||
valid_till: self.valid_till.clone(),
|
||||
requires: self.requires.clone(),
|
||||
provides: self.provides.clone(),
|
||||
@@ -185,6 +189,7 @@ impl<Hash, Extrinsic> fmt::Debug for Transaction<Hash, Extrinsic> where
|
||||
write!(fmt, "valid_till: {:?}, ", &self.valid_till)?;
|
||||
write!(fmt, "bytes: {:?}, ", &self.bytes)?;
|
||||
write!(fmt, "propagate: {:?}, ", &self.propagate)?;
|
||||
write!(fmt, "source: {:?}, ", &self.source)?;
|
||||
write!(fmt, "requires: [")?;
|
||||
print_tags(fmt, &self.requires)?;
|
||||
write!(fmt, "], provides: [")?;
|
||||
@@ -556,6 +561,7 @@ mod tests {
|
||||
requires: vec![],
|
||||
provides: vec![vec![1]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
|
||||
// then
|
||||
@@ -578,6 +584,7 @@ mod tests {
|
||||
requires: vec![],
|
||||
provides: vec![vec![1]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
pool.import(Transaction {
|
||||
data: vec![1u8],
|
||||
@@ -588,6 +595,7 @@ mod tests {
|
||||
requires: vec![],
|
||||
provides: vec![vec![1]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap_err();
|
||||
|
||||
// then
|
||||
@@ -611,6 +619,7 @@ mod tests {
|
||||
requires: vec![vec![0]],
|
||||
provides: vec![vec![1]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
assert_eq!(pool.ready().count(), 0);
|
||||
assert_eq!(pool.ready.len(), 0);
|
||||
@@ -623,6 +632,7 @@ mod tests {
|
||||
requires: vec![],
|
||||
provides: vec![vec![0]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
|
||||
// then
|
||||
@@ -645,6 +655,7 @@ mod tests {
|
||||
requires: vec![vec![0]],
|
||||
provides: vec![vec![1]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
pool.import(Transaction {
|
||||
data: vec![3u8],
|
||||
@@ -655,6 +666,7 @@ mod tests {
|
||||
requires: vec![vec![2]],
|
||||
provides: vec![],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
pool.import(Transaction {
|
||||
data: vec![2u8],
|
||||
@@ -665,6 +677,7 @@ mod tests {
|
||||
requires: vec![vec![1]],
|
||||
provides: vec![vec![3], vec![2]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
pool.import(Transaction {
|
||||
data: vec![4u8],
|
||||
@@ -675,6 +688,7 @@ mod tests {
|
||||
requires: vec![vec![3], vec![4]],
|
||||
provides: vec![],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
assert_eq!(pool.ready().count(), 0);
|
||||
assert_eq!(pool.ready.len(), 0);
|
||||
@@ -688,6 +702,7 @@ mod tests {
|
||||
requires: vec![],
|
||||
provides: vec![vec![0], vec![4]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
|
||||
// then
|
||||
@@ -720,6 +735,7 @@ mod tests {
|
||||
requires: vec![vec![0]],
|
||||
provides: vec![vec![1]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
pool.import(Transaction {
|
||||
data: vec![3u8],
|
||||
@@ -730,6 +746,7 @@ mod tests {
|
||||
requires: vec![vec![1]],
|
||||
provides: vec![vec![2]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
assert_eq!(pool.ready().count(), 0);
|
||||
assert_eq!(pool.ready.len(), 0);
|
||||
@@ -744,6 +761,7 @@ mod tests {
|
||||
requires: vec![vec![2]],
|
||||
provides: vec![vec![0]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
|
||||
// then
|
||||
@@ -764,6 +782,7 @@ mod tests {
|
||||
requires: vec![],
|
||||
provides: vec![vec![0]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
let mut it = pool.ready().into_iter().map(|tx| tx.data[0]);
|
||||
assert_eq!(it.next(), Some(4));
|
||||
@@ -792,6 +811,7 @@ mod tests {
|
||||
requires: vec![vec![0]],
|
||||
provides: vec![vec![1]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
pool.import(Transaction {
|
||||
data: vec![3u8],
|
||||
@@ -802,6 +822,7 @@ mod tests {
|
||||
requires: vec![vec![1]],
|
||||
provides: vec![vec![2]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
assert_eq!(pool.ready().count(), 0);
|
||||
assert_eq!(pool.ready.len(), 0);
|
||||
@@ -816,6 +837,7 @@ mod tests {
|
||||
requires: vec![vec![2]],
|
||||
provides: vec![vec![0]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
|
||||
// then
|
||||
@@ -836,6 +858,7 @@ mod tests {
|
||||
requires: vec![],
|
||||
provides: vec![vec![0]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap_err();
|
||||
let mut it = pool.ready().into_iter().map(|tx| tx.data[0]);
|
||||
assert_eq!(it.next(), None);
|
||||
@@ -859,6 +882,7 @@ mod tests {
|
||||
requires: vec![],
|
||||
provides: vec![vec![0], vec![4]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).expect("import 1 should be ok");
|
||||
pool.import(Transaction {
|
||||
data: vec![3u8; 1024],
|
||||
@@ -869,6 +893,7 @@ mod tests {
|
||||
requires: vec![],
|
||||
provides: vec![vec![2], vec![7]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).expect("import 2 should be ok");
|
||||
|
||||
assert!(parity_util_mem::malloc_size(&pool) > 5000);
|
||||
@@ -887,6 +912,7 @@ mod tests {
|
||||
requires: vec![],
|
||||
provides: vec![vec![0], vec![4]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
pool.import(Transaction {
|
||||
data: vec![1u8],
|
||||
@@ -897,6 +923,7 @@ mod tests {
|
||||
requires: vec![vec![0]],
|
||||
provides: vec![vec![1]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
pool.import(Transaction {
|
||||
data: vec![3u8],
|
||||
@@ -907,6 +934,7 @@ mod tests {
|
||||
requires: vec![vec![2]],
|
||||
provides: vec![],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
pool.import(Transaction {
|
||||
data: vec![2u8],
|
||||
@@ -917,6 +945,7 @@ mod tests {
|
||||
requires: vec![vec![1]],
|
||||
provides: vec![vec![3], vec![2]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
pool.import(Transaction {
|
||||
data: vec![4u8],
|
||||
@@ -927,6 +956,7 @@ mod tests {
|
||||
requires: vec![vec![3], vec![4]],
|
||||
provides: vec![],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
// future
|
||||
pool.import(Transaction {
|
||||
@@ -938,6 +968,7 @@ mod tests {
|
||||
requires: vec![vec![11]],
|
||||
provides: vec![],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
assert_eq!(pool.ready().count(), 5);
|
||||
assert_eq!(pool.future.len(), 1);
|
||||
@@ -964,6 +995,7 @@ mod tests {
|
||||
requires: vec![vec![0]],
|
||||
provides: vec![vec![100]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
// ready
|
||||
pool.import(Transaction {
|
||||
@@ -975,6 +1007,7 @@ mod tests {
|
||||
requires: vec![],
|
||||
provides: vec![vec![1]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
pool.import(Transaction {
|
||||
data: vec![2u8],
|
||||
@@ -985,6 +1018,7 @@ mod tests {
|
||||
requires: vec![vec![2]],
|
||||
provides: vec![vec![3]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
pool.import(Transaction {
|
||||
data: vec![3u8],
|
||||
@@ -995,6 +1029,7 @@ mod tests {
|
||||
requires: vec![vec![1]],
|
||||
provides: vec![vec![2]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
pool.import(Transaction {
|
||||
data: vec![4u8],
|
||||
@@ -1005,6 +1040,7 @@ mod tests {
|
||||
requires: vec![vec![3], vec![2]],
|
||||
provides: vec![vec![4]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
|
||||
assert_eq!(pool.ready().count(), 4);
|
||||
@@ -1040,10 +1076,11 @@ mod tests {
|
||||
requires: vec![vec![3], vec![2]],
|
||||
provides: vec![vec![4]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}),
|
||||
"Transaction { \
|
||||
hash: 4, priority: 1000, valid_till: 64, bytes: 1, propagate: true, \
|
||||
requires: [03,02], provides: [04], data: [4]}".to_owned()
|
||||
source: TransactionSource::External, requires: [03,02], provides: [04], data: [4]}".to_owned()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1058,6 +1095,7 @@ requires: [03,02], provides: [04], data: [4]}".to_owned()
|
||||
requires: vec![vec![3], vec![2]],
|
||||
provides: vec![vec![4]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}.is_propagable(), true);
|
||||
|
||||
assert_eq!(Transaction {
|
||||
@@ -1069,6 +1107,7 @@ requires: [03,02], provides: [04], data: [4]}".to_owned()
|
||||
requires: vec![vec![3], vec![2]],
|
||||
provides: vec![vec![4]],
|
||||
propagate: false,
|
||||
source: Source::External,
|
||||
}.is_propagable(), false);
|
||||
}
|
||||
|
||||
@@ -1090,6 +1129,7 @@ requires: [03,02], provides: [04], data: [4]}".to_owned()
|
||||
requires: vec![vec![0]],
|
||||
provides: vec![],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
});
|
||||
|
||||
if let Err(error::Error::RejectedFutureTransaction) = err {
|
||||
@@ -1113,6 +1153,7 @@ requires: [03,02], provides: [04], data: [4]}".to_owned()
|
||||
requires: vec![vec![0]],
|
||||
provides: vec![],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
|
||||
// then
|
||||
@@ -1142,6 +1183,7 @@ requires: [03,02], provides: [04], data: [4]}".to_owned()
|
||||
requires: vec![vec![0]],
|
||||
provides: vec![],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}).unwrap();
|
||||
|
||||
flag
|
||||
|
||||
@@ -249,6 +249,7 @@ impl<Hash: hash::Hash + Eq + Clone, Ex> FutureTransactions<Hash, Ex> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sp_runtime::transaction_validity::TransactionSource;
|
||||
|
||||
#[test]
|
||||
fn can_track_heap_size() {
|
||||
@@ -263,6 +264,7 @@ mod tests {
|
||||
requires: vec![vec![1], vec![2]],
|
||||
provides: vec![vec![3], vec![4]],
|
||||
propagate: true,
|
||||
source: TransactionSource::External,
|
||||
}.into(),
|
||||
missing_tags: vec![vec![1u8], vec![2u8]].into_iter().collect(),
|
||||
imported_at: std::time::Instant::now(),
|
||||
|
||||
@@ -31,7 +31,9 @@ use futures::{
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{self, SaturatedConversion},
|
||||
transaction_validity::{TransactionValidity, TransactionTag as Tag, TransactionValidityError},
|
||||
transaction_validity::{
|
||||
TransactionValidity, TransactionTag as Tag, TransactionValidityError, TransactionSource,
|
||||
},
|
||||
};
|
||||
use sp_transaction_pool::error;
|
||||
use wasm_timer::Instant;
|
||||
@@ -76,6 +78,7 @@ pub trait ChainApi: Send + Sync {
|
||||
fn validate_transaction(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
source: TransactionSource,
|
||||
uxt: ExtrinsicFor<Self>,
|
||||
) -> Self::ValidationFuture;
|
||||
|
||||
@@ -144,12 +147,17 @@ impl<B: ChainApi> Pool<B> {
|
||||
}
|
||||
|
||||
/// Imports a bunch of unverified extrinsics to the pool
|
||||
pub async fn submit_at<T>(&self, at: &BlockId<B::Block>, xts: T, force: bool)
|
||||
-> Result<Vec<Result<ExHash<B>, B::Error>>, B::Error>
|
||||
where
|
||||
T: IntoIterator<Item=ExtrinsicFor<B>>
|
||||
pub async fn submit_at<T>(
|
||||
&self,
|
||||
at: &BlockId<B::Block>,
|
||||
source: TransactionSource,
|
||||
xts: T,
|
||||
force: bool,
|
||||
) -> Result<Vec<Result<ExHash<B>, B::Error>>, B::Error> where
|
||||
T: IntoIterator<Item=ExtrinsicFor<B>>,
|
||||
{
|
||||
let validated_pool = self.validated_pool.clone();
|
||||
let xts = xts.into_iter().map(|xt| (source, xt));
|
||||
self.verify(at, xts, force)
|
||||
.map(move |validated_transactions| validated_transactions
|
||||
.map(|validated_transactions| validated_pool.submit(validated_transactions
|
||||
@@ -162,9 +170,10 @@ impl<B: ChainApi> Pool<B> {
|
||||
pub async fn submit_one(
|
||||
&self,
|
||||
at: &BlockId<B::Block>,
|
||||
source: TransactionSource,
|
||||
xt: ExtrinsicFor<B>,
|
||||
) -> Result<ExHash<B>, B::Error> {
|
||||
self.submit_at(at, std::iter::once(xt), false)
|
||||
self.submit_at(at, source, std::iter::once(xt), false)
|
||||
.map(|import_result| import_result.and_then(|mut import_result| import_result
|
||||
.pop()
|
||||
.expect("One extrinsic passed; one result returned; qed")
|
||||
@@ -176,10 +185,13 @@ impl<B: ChainApi> Pool<B> {
|
||||
pub async fn submit_and_watch(
|
||||
&self,
|
||||
at: &BlockId<B::Block>,
|
||||
source: TransactionSource,
|
||||
xt: ExtrinsicFor<B>,
|
||||
) -> Result<Watcher<ExHash<B>, BlockHash<B>>, B::Error> {
|
||||
let block_number = self.resolve_block_number(at)?;
|
||||
let (_, tx) = self.verify_one(at, block_number, xt, false).await;
|
||||
let (_, tx) = self.verify_one(
|
||||
at, block_number, source, xt, false
|
||||
).await;
|
||||
self.validated_pool.submit_and_watch(tx)
|
||||
}
|
||||
|
||||
@@ -249,7 +261,7 @@ impl<B: ChainApi> Pool<B> {
|
||||
// to get validity info and tags that the extrinsic provides.
|
||||
None => {
|
||||
let validity = self.validated_pool.api()
|
||||
.validate_transaction(parent, extrinsic.clone())
|
||||
.validate_transaction(parent, TransactionSource::InBlock, extrinsic.clone())
|
||||
.await;
|
||||
|
||||
if let Ok(Ok(validity)) = validity {
|
||||
@@ -303,8 +315,12 @@ impl<B: ChainApi> Pool<B> {
|
||||
|
||||
// Try to re-validate pruned transactions since some of them might be still valid.
|
||||
// note that `known_imported_hashes` will be rejected here due to temporary ban.
|
||||
let pruned_hashes = prune_status.pruned.iter().map(|tx| tx.hash.clone()).collect::<Vec<_>>();
|
||||
let pruned_transactions = prune_status.pruned.into_iter().map(|tx| tx.data.clone());
|
||||
let pruned_hashes = prune_status.pruned
|
||||
.iter()
|
||||
.map(|tx| tx.hash.clone()).collect::<Vec<_>>();
|
||||
let pruned_transactions = prune_status.pruned
|
||||
.into_iter()
|
||||
.map(|tx| (tx.source, tx.data.clone()));
|
||||
|
||||
let reverified_transactions = self.verify(at, pruned_transactions, false).await?;
|
||||
|
||||
@@ -335,7 +351,7 @@ impl<B: ChainApi> Pool<B> {
|
||||
async fn verify(
|
||||
&self,
|
||||
at: &BlockId<B::Block>,
|
||||
xts: impl IntoIterator<Item=ExtrinsicFor<B>>,
|
||||
xts: impl IntoIterator<Item=(TransactionSource, ExtrinsicFor<B>)>,
|
||||
force: bool,
|
||||
) -> Result<HashMap<ExHash<B>, ValidatedTransactionFor<B>>, B::Error> {
|
||||
// we need a block number to compute tx validity
|
||||
@@ -345,7 +361,7 @@ impl<B: ChainApi> Pool<B> {
|
||||
for (hash, validated_tx) in
|
||||
futures::future::join_all(
|
||||
xts.into_iter()
|
||||
.map(|xt| self.verify_one(at, block_number, xt, force))
|
||||
.map(|(source, xt)| self.verify_one(at, block_number, source, xt, force))
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -360,6 +376,7 @@ impl<B: ChainApi> Pool<B> {
|
||||
&self,
|
||||
block_id: &BlockId<B::Block>,
|
||||
block_number: NumberFor<B>,
|
||||
source: TransactionSource,
|
||||
xt: ExtrinsicFor<B>,
|
||||
force: bool,
|
||||
) -> (ExHash<B>, ValidatedTransactionFor<B>) {
|
||||
@@ -371,7 +388,11 @@ impl<B: ChainApi> Pool<B> {
|
||||
)
|
||||
}
|
||||
|
||||
let validation_result = self.validated_pool.api().validate_transaction(block_id, xt.clone()).await;
|
||||
let validation_result = self.validated_pool.api().validate_transaction(
|
||||
block_id,
|
||||
source,
|
||||
xt.clone(),
|
||||
).await;
|
||||
|
||||
let status = match validation_result {
|
||||
Ok(status) => status,
|
||||
@@ -386,6 +407,7 @@ impl<B: ChainApi> Pool<B> {
|
||||
ValidatedTransaction::valid_at(
|
||||
block_number.saturated_into::<u64>(),
|
||||
hash.clone(),
|
||||
source,
|
||||
xt,
|
||||
bytes,
|
||||
validity,
|
||||
@@ -422,7 +444,7 @@ mod tests {
|
||||
use futures::executor::block_on;
|
||||
use super::*;
|
||||
use sp_transaction_pool::TransactionStatus;
|
||||
use sp_runtime::transaction_validity::{ValidTransaction, InvalidTransaction};
|
||||
use sp_runtime::transaction_validity::{ValidTransaction, InvalidTransaction, TransactionSource};
|
||||
use codec::Encode;
|
||||
use substrate_test_runtime::{Block, Extrinsic, Transfer, H256, AccountId};
|
||||
use assert_matches::assert_matches;
|
||||
@@ -430,6 +452,7 @@ mod tests {
|
||||
use crate::base_pool::Limit;
|
||||
|
||||
const INVALID_NONCE: u64 = 254;
|
||||
const SOURCE: TransactionSource = TransactionSource::External;
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct TestApi {
|
||||
@@ -450,6 +473,7 @@ mod tests {
|
||||
fn validate_transaction(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
_source: TransactionSource,
|
||||
uxt: ExtrinsicFor<Self>,
|
||||
) -> Self::ValidationFuture {
|
||||
let hash = self.hash_and_length(&uxt).0;
|
||||
@@ -541,7 +565,7 @@ mod tests {
|
||||
let pool = pool();
|
||||
|
||||
// when
|
||||
let hash = block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
let hash = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
@@ -565,7 +589,7 @@ mod tests {
|
||||
|
||||
// when
|
||||
pool.validated_pool.rotator().ban(&Instant::now(), vec![pool.hash_of(&uxt)]);
|
||||
let res = block_on(pool.submit_one(&BlockId::Number(0), uxt));
|
||||
let res = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt));
|
||||
assert_eq!(pool.validated_pool().status().ready, 0);
|
||||
assert_eq!(pool.validated_pool().status().future, 0);
|
||||
|
||||
@@ -581,20 +605,20 @@ mod tests {
|
||||
let stream = pool.validated_pool().import_notification_stream();
|
||||
|
||||
// when
|
||||
let _hash = block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
let _hash = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
}))).unwrap();
|
||||
let _hash = block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
let _hash = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 1,
|
||||
}))).unwrap();
|
||||
// future doesn't count
|
||||
let _hash = block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
let _hash = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
@@ -617,19 +641,19 @@ mod tests {
|
||||
fn should_clear_stale_transactions() {
|
||||
// given
|
||||
let pool = pool();
|
||||
let hash1 = block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
let hash1 = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
}))).unwrap();
|
||||
let hash2 = block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
let hash2 = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 1,
|
||||
}))).unwrap();
|
||||
let hash3 = block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
let hash3 = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
@@ -653,7 +677,7 @@ mod tests {
|
||||
fn should_ban_mined_transactions() {
|
||||
// given
|
||||
let pool = pool();
|
||||
let hash1 = block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
let hash1 = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
@@ -680,7 +704,7 @@ mod tests {
|
||||
..Default::default()
|
||||
}, TestApi::default().into());
|
||||
|
||||
let hash1 = block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
let hash1 = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
@@ -689,7 +713,7 @@ mod tests {
|
||||
assert_eq!(pool.validated_pool().status().future, 1);
|
||||
|
||||
// when
|
||||
let hash2 = block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
let hash2 = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
@@ -716,7 +740,7 @@ mod tests {
|
||||
}, TestApi::default().into());
|
||||
|
||||
// when
|
||||
block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
@@ -734,7 +758,7 @@ mod tests {
|
||||
let pool = pool();
|
||||
|
||||
// when
|
||||
let err = block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
let err = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
@@ -754,7 +778,7 @@ mod tests {
|
||||
fn should_trigger_ready_and_finalized() {
|
||||
// given
|
||||
let pool = pool();
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), uxt(Transfer {
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
@@ -778,7 +802,7 @@ mod tests {
|
||||
fn should_trigger_ready_and_finalized_when_pruning_via_hash() {
|
||||
// given
|
||||
let pool = pool();
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), uxt(Transfer {
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
@@ -802,7 +826,7 @@ mod tests {
|
||||
fn should_trigger_future_and_ready_after_promoted() {
|
||||
// given
|
||||
let pool = pool();
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), uxt(Transfer {
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
@@ -812,7 +836,7 @@ mod tests {
|
||||
assert_eq!(pool.validated_pool().status().future, 1);
|
||||
|
||||
// when
|
||||
block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
@@ -836,7 +860,7 @@ mod tests {
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
});
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), uxt)).unwrap();
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, uxt)).unwrap();
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
|
||||
// when
|
||||
@@ -860,7 +884,7 @@ mod tests {
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
});
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), uxt)).unwrap();
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, uxt)).unwrap();
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
|
||||
// when
|
||||
@@ -895,7 +919,7 @@ mod tests {
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
});
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), xt)).unwrap();
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, xt)).unwrap();
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
|
||||
// when
|
||||
@@ -905,7 +929,7 @@ mod tests {
|
||||
amount: 4,
|
||||
nonce: 1,
|
||||
});
|
||||
block_on(pool.submit_one(&BlockId::Number(1), xt)).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::Number(1), SOURCE, xt)).unwrap();
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
|
||||
// then
|
||||
@@ -934,7 +958,7 @@ mod tests {
|
||||
// This transaction should go to future, since we use `nonce: 1`
|
||||
let pool2 = pool.clone();
|
||||
std::thread::spawn(move || {
|
||||
block_on(pool2.submit_one(&BlockId::Number(0), xt)).unwrap();
|
||||
block_on(pool2.submit_one(&BlockId::Number(0), SOURCE, xt)).unwrap();
|
||||
ready.send(()).unwrap();
|
||||
});
|
||||
|
||||
@@ -948,7 +972,7 @@ mod tests {
|
||||
});
|
||||
// The tag the above transaction provides (TestApi is using just nonce as u8)
|
||||
let provides = vec![0_u8];
|
||||
block_on(pool.submit_one(&BlockId::Number(0), xt)).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::Number(0), SOURCE, xt)).unwrap();
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
|
||||
// Now block import happens before the second transaction is able to finish verification.
|
||||
|
||||
@@ -545,6 +545,7 @@ fn remove_item<T: PartialEq>(vec: &mut Vec<T>, item: &T) {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sp_runtime::transaction_validity::TransactionSource as Source;
|
||||
|
||||
fn tx(id: u8) -> Transaction<u64, Vec<u8>> {
|
||||
Transaction {
|
||||
@@ -556,6 +557,7 @@ mod tests {
|
||||
requires: vec![vec![1], vec![2]],
|
||||
provides: vec![vec![3], vec![4]],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,6 +658,7 @@ mod tests {
|
||||
requires: vec![tx1.provides[0].clone()],
|
||||
provides: vec![],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
};
|
||||
|
||||
// when
|
||||
@@ -688,6 +691,7 @@ mod tests {
|
||||
requires: vec![],
|
||||
provides: vec![],
|
||||
propagate: true,
|
||||
source: Source::External,
|
||||
};
|
||||
import(&mut ready, tx).unwrap();
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ impl<Hash: hash::Hash + Eq + Clone> PoolRotator<Hash> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sp_runtime::transaction_validity::TransactionSource;
|
||||
|
||||
type Hash = u64;
|
||||
type Ex = ();
|
||||
@@ -122,6 +123,7 @@ mod tests {
|
||||
requires: vec![],
|
||||
provides: vec![],
|
||||
propagate: true,
|
||||
source: TransactionSource::External,
|
||||
};
|
||||
|
||||
(hash, tx)
|
||||
@@ -188,6 +190,7 @@ mod tests {
|
||||
requires: vec![],
|
||||
provides: vec![],
|
||||
propagate: true,
|
||||
source: TransactionSource::External,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ use parking_lot::{Mutex, RwLock};
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{self, SaturatedConversion},
|
||||
transaction_validity::{TransactionTag as Tag, ValidTransaction},
|
||||
transaction_validity::{TransactionTag as Tag, ValidTransaction, TransactionSource},
|
||||
};
|
||||
use sp_transaction_pool::{error, PoolStatus};
|
||||
use wasm_timer::Instant;
|
||||
@@ -58,6 +58,7 @@ impl<Hash, Ex, Error> ValidatedTransaction<Hash, Ex, Error> {
|
||||
pub fn valid_at(
|
||||
at: u64,
|
||||
hash: Hash,
|
||||
source: TransactionSource,
|
||||
data: Ex,
|
||||
bytes: usize,
|
||||
validity: ValidTransaction,
|
||||
@@ -66,6 +67,7 @@ impl<Hash, Ex, Error> ValidatedTransaction<Hash, Ex, Error> {
|
||||
data,
|
||||
bytes,
|
||||
hash,
|
||||
source,
|
||||
priority: validity.priority,
|
||||
requires: validity.requires,
|
||||
provides: validity.provides,
|
||||
|
||||
@@ -29,10 +29,10 @@ use sc_client_api::{
|
||||
};
|
||||
use sp_runtime::{
|
||||
generic::BlockId, traits::{self, Block as BlockT, BlockIdTo, Header as HeaderT, Hash as HashT},
|
||||
transaction_validity::TransactionValidity,
|
||||
transaction_validity::{TransactionValidity, TransactionSource},
|
||||
};
|
||||
use sp_transaction_pool::runtime_api::TaggedTransactionQueue;
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_api::{ProvideRuntimeApi, ApiExt};
|
||||
|
||||
use crate::error::{self, Error};
|
||||
|
||||
@@ -81,6 +81,7 @@ impl<Client, Block> sc_transaction_graph::ChainApi for FullChainApi<Client, Bloc
|
||||
fn validate_transaction(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
source: TransactionSource,
|
||||
uxt: sc_transaction_graph::ExtrinsicFor<Self>,
|
||||
) -> Self::ValidationFuture {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
@@ -88,8 +89,19 @@ impl<Client, Block> sc_transaction_graph::ChainApi for FullChainApi<Client, Bloc
|
||||
let at = at.clone();
|
||||
|
||||
self.pool.spawn_ok(futures_diagnose::diagnose("validate-transaction", async move {
|
||||
let res = client.runtime_api().validate_transaction(&at, uxt)
|
||||
.map_err(|e| Error::RuntimeApi(format!("{:?}", e)));
|
||||
let runtime_api = client.runtime_api();
|
||||
let has_v2 = runtime_api
|
||||
.has_api_with::<dyn TaggedTransactionQueue<Self::Block, Error=()>, _>(
|
||||
&at, |v| v >= 2,
|
||||
)
|
||||
.unwrap_or_default();
|
||||
let res = if has_v2 {
|
||||
runtime_api.validate_transaction(&at, source, uxt)
|
||||
} else {
|
||||
#[allow(deprecated)] // old validate_transaction
|
||||
runtime_api.validate_transaction_before_version_2(&at, uxt)
|
||||
};
|
||||
let res = res.map_err(|e| Error::RuntimeApi(format!("{:?}", e)));
|
||||
if let Err(e) = tx.send(res) {
|
||||
log::warn!("Unable to send a validate transaction result: {:?}", e);
|
||||
}
|
||||
@@ -160,6 +172,7 @@ impl<Client, F, Block> sc_transaction_graph::ChainApi for LightChainApi<Client,
|
||||
fn validate_transaction(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
source: TransactionSource,
|
||||
uxt: sc_transaction_graph::ExtrinsicFor<Self>,
|
||||
) -> Self::ValidationFuture {
|
||||
let header_hash = self.client.expect_block_hash_from_id(at);
|
||||
@@ -174,7 +187,7 @@ impl<Client, F, Block> sc_transaction_graph::ChainApi for LightChainApi<Client,
|
||||
block,
|
||||
header,
|
||||
method: "TaggedTransactionQueue_validate_transaction".into(),
|
||||
call_data: uxt.encode(),
|
||||
call_data: (source, uxt).encode(),
|
||||
retry_count: None,
|
||||
});
|
||||
let remote_validation_request = remote_validation_request.then(move |result| {
|
||||
|
||||
@@ -41,6 +41,7 @@ use sp_runtime::{
|
||||
use sp_transaction_pool::{
|
||||
TransactionPool, PoolStatus, ImportNotificationStream, TxHash, TransactionFor,
|
||||
TransactionStatusStreamFor, MaintainedTransactionPool, PoolFuture, ChainEvent,
|
||||
TransactionSource,
|
||||
};
|
||||
use wasm_timer::Instant;
|
||||
|
||||
@@ -201,37 +202,40 @@ impl<PoolApi, Block> TransactionPool for BasicPool<PoolApi, Block>
|
||||
fn submit_at(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
source: TransactionSource,
|
||||
xts: Vec<TransactionFor<Self>>,
|
||||
) -> PoolFuture<Vec<Result<TxHash<Self>, Self::Error>>, Self::Error> {
|
||||
let pool = self.pool.clone();
|
||||
let at = *at;
|
||||
async move {
|
||||
pool.submit_at(&at, xts, false).await
|
||||
pool.submit_at(&at, source, xts, false).await
|
||||
}.boxed()
|
||||
}
|
||||
|
||||
fn submit_one(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
source: TransactionSource,
|
||||
xt: TransactionFor<Self>,
|
||||
) -> PoolFuture<TxHash<Self>, Self::Error> {
|
||||
let pool = self.pool.clone();
|
||||
let at = *at;
|
||||
async move {
|
||||
pool.submit_one(&at, xt).await
|
||||
pool.submit_one(&at, source, xt).await
|
||||
}.boxed()
|
||||
}
|
||||
|
||||
fn submit_and_watch(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
source: TransactionSource,
|
||||
xt: TransactionFor<Self>,
|
||||
) -> PoolFuture<Box<TransactionStatusStreamFor<Self>>, Self::Error> {
|
||||
let at = *at;
|
||||
let pool = self.pool.clone();
|
||||
|
||||
async move {
|
||||
pool.submit_and_watch(&at, xt)
|
||||
pool.submit_and_watch(&at, source, xt)
|
||||
.map(|result| result.map(|watcher| Box::new(watcher.into_stream()) as _))
|
||||
.await
|
||||
}.boxed()
|
||||
@@ -437,7 +441,14 @@ impl<PoolApi, Block> MaintainedTransactionPool for BasicPool<PoolApi, Block>
|
||||
|
||||
resubmit_transactions.extend(block_transactions);
|
||||
}
|
||||
if let Err(e) = pool.submit_at(&id, resubmit_transactions, true).await {
|
||||
if let Err(e) = pool.submit_at(
|
||||
&id,
|
||||
// These transactions are coming from retracted blocks, we should
|
||||
// simply consider them external.
|
||||
TransactionSource::External,
|
||||
resubmit_transactions,
|
||||
true
|
||||
).await {
|
||||
log::debug!(
|
||||
target: "txpool",
|
||||
"[{:?}] Error re-submitting transactions: {:?}", id, e
|
||||
|
||||
@@ -78,7 +78,7 @@ async fn batch_revalidate<Api: ChainApi>(
|
||||
None => continue,
|
||||
};
|
||||
|
||||
match api.validate_transaction(&BlockId::Number(at), ext.data.clone()).await {
|
||||
match api.validate_transaction(&BlockId::Number(at), ext.source, ext.data.clone()).await {
|
||||
Ok(Err(TransactionValidityError::Invalid(err))) => {
|
||||
log::debug!(target: "txpool", "[{:?}]: Revalidation: invalid {:?}", ext_hash, err);
|
||||
invalid_hashes.push(ext_hash);
|
||||
@@ -94,6 +94,7 @@ async fn batch_revalidate<Api: ChainApi>(
|
||||
ValidatedTransaction::valid_at(
|
||||
at.saturated_into::<u64>(),
|
||||
ext_hash,
|
||||
ext.source,
|
||||
ext.data.clone(),
|
||||
api.hash_and_length(&ext.data).1,
|
||||
validity,
|
||||
@@ -312,9 +313,9 @@ where
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use sc_transaction_graph::Pool;
|
||||
use sp_transaction_pool::TransactionSource;
|
||||
use substrate_test_runtime_transaction_pool::{TestApi, uxt};
|
||||
use futures::executor::block_on;
|
||||
use substrate_test_runtime_client::{
|
||||
@@ -334,7 +335,9 @@ mod tests {
|
||||
let queue = Arc::new(RevalidationQueue::new(api.clone(), pool.clone()));
|
||||
|
||||
let uxt = uxt(Alice, 0);
|
||||
let uxt_hash = block_on(pool.submit_one(&BlockId::number(0), uxt.clone())).expect("Should be valid");
|
||||
let uxt_hash = block_on(
|
||||
pool.submit_one(&BlockId::number(0), TransactionSource::External, uxt.clone())
|
||||
).expect("Should be valid");
|
||||
|
||||
block_on(queue.revalidate_later(0, vec![uxt_hash]));
|
||||
|
||||
@@ -343,4 +346,4 @@ mod tests {
|
||||
// number of ready
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ use futures::executor::block_on;
|
||||
use txpool::{self, Pool};
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
transaction_validity::{ValidTransaction, InvalidTransaction},
|
||||
transaction_validity::{ValidTransaction, InvalidTransaction, TransactionSource},
|
||||
};
|
||||
use substrate_test_runtime_client::{
|
||||
runtime::{Block, Hash, Index, Header, Extrinsic, Transfer},
|
||||
@@ -53,10 +53,12 @@ fn header(number: u64) -> Header {
|
||||
}
|
||||
}
|
||||
|
||||
const SOURCE: TransactionSource = TransactionSource::External;
|
||||
|
||||
#[test]
|
||||
fn submission_should_work() {
|
||||
let pool = pool();
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt(Alice, 209))).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap();
|
||||
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
assert_eq!(pending, vec![209]);
|
||||
@@ -65,8 +67,8 @@ fn submission_should_work() {
|
||||
#[test]
|
||||
fn multiple_submission_should_work() {
|
||||
let pool = pool();
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt(Alice, 209))).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt(Alice, 210))).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 210))).unwrap();
|
||||
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
assert_eq!(pending, vec![209, 210]);
|
||||
@@ -75,7 +77,7 @@ fn multiple_submission_should_work() {
|
||||
#[test]
|
||||
fn early_nonce_should_be_culled() {
|
||||
let pool = pool();
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt(Alice, 208))).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 208))).unwrap();
|
||||
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
assert_eq!(pending, Vec::<Index>::new());
|
||||
@@ -85,11 +87,11 @@ fn early_nonce_should_be_culled() {
|
||||
fn late_nonce_should_be_queued() {
|
||||
let pool = pool();
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt(Alice, 210))).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 210))).unwrap();
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
assert_eq!(pending, Vec::<Index>::new());
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt(Alice, 209))).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap();
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
assert_eq!(pending, vec![209, 210]);
|
||||
}
|
||||
@@ -97,8 +99,8 @@ fn late_nonce_should_be_queued() {
|
||||
#[test]
|
||||
fn prune_tags_should_work() {
|
||||
let pool = pool();
|
||||
let hash209 = block_on(pool.submit_one(&BlockId::number(0), uxt(Alice, 209))).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt(Alice, 210))).unwrap();
|
||||
let hash209 = block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 210))).unwrap();
|
||||
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
assert_eq!(pending, vec![209, 210]);
|
||||
@@ -119,16 +121,16 @@ fn prune_tags_should_work() {
|
||||
fn should_ban_invalid_transactions() {
|
||||
let pool = pool();
|
||||
let uxt = uxt(Alice, 209);
|
||||
let hash = block_on(pool.submit_one(&BlockId::number(0), uxt.clone())).unwrap();
|
||||
let hash = block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt.clone())).unwrap();
|
||||
pool.validated_pool().remove_invalid(&[hash]);
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt.clone())).unwrap_err();
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt.clone())).unwrap_err();
|
||||
|
||||
// when
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
assert_eq!(pending, Vec::<Index>::new());
|
||||
|
||||
// then
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt.clone())).unwrap_err();
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt.clone())).unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -139,7 +141,7 @@ fn should_correctly_prune_transactions_providing_more_than_one_tag() {
|
||||
}));
|
||||
let pool = Pool::new(Default::default(), api.clone());
|
||||
let xt = uxt(Alice, 209);
|
||||
block_on(pool.submit_one(&BlockId::number(0), xt.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
|
||||
// remove the transaction that just got imported.
|
||||
@@ -152,7 +154,7 @@ fn should_correctly_prune_transactions_providing_more_than_one_tag() {
|
||||
// so now let's insert another transaction that also provides the 155
|
||||
api.increment_nonce(Alice.into());
|
||||
let xt = uxt(Alice, 211);
|
||||
block_on(pool.submit_one(&BlockId::number(2), xt.clone())).expect("2. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(2), SOURCE, xt.clone())).expect("2. Imported");
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
assert_eq!(pool.validated_pool().status().future, 1);
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
@@ -190,7 +192,7 @@ fn should_prune_old_during_maintenance() {
|
||||
|
||||
let (pool, _guard) = maintained_pool();
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(0), xt.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
pool.api.push_block(1, vec![xt.clone()]);
|
||||
@@ -205,8 +207,8 @@ fn should_revalidate_during_maintenance() {
|
||||
let xt2 = uxt(Alice, 210);
|
||||
|
||||
let (pool, _guard) = maintained_pool();
|
||||
block_on(pool.submit_one(&BlockId::number(0), xt1.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), xt2.clone())).expect("2. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt1.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt2.clone())).expect("2. Imported");
|
||||
assert_eq!(pool.status().ready, 2);
|
||||
assert_eq!(pool.api.validation_requests().len(), 2);
|
||||
|
||||
@@ -230,7 +232,7 @@ fn should_resubmit_from_retracted_during_maintenance() {
|
||||
|
||||
let (pool, _guard) = maintained_pool();
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(0), xt.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
pool.api.push_block(1, vec![]);
|
||||
@@ -249,7 +251,7 @@ fn should_not_retain_invalid_hashes_from_retracted() {
|
||||
|
||||
let (pool, _guard) = maintained_pool();
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(0), xt.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
pool.api.push_block(1, vec![]);
|
||||
@@ -275,7 +277,7 @@ fn should_revalidate_transaction_multiple_times() {
|
||||
|
||||
let (pool, _guard) = maintained_pool();
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(0), xt.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
pool.api.push_block(1, vec![xt.clone()]);
|
||||
@@ -284,7 +286,7 @@ fn should_revalidate_transaction_multiple_times() {
|
||||
block_on(pool.maintain(block_event(1)));
|
||||
block_on(futures_timer::Delay::new(BACKGROUND_REVALIDATION_INTERVAL*2));
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(0), xt.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
pool.api.push_block(2, vec![]);
|
||||
@@ -305,8 +307,8 @@ fn should_revalidate_across_many_blocks() {
|
||||
|
||||
let (pool, _guard) = maintained_pool();
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(1), xt1.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(1), xt2.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(1), SOURCE, xt1.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(1), SOURCE, xt2.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 2);
|
||||
|
||||
pool.api.push_block(1, vec![]);
|
||||
@@ -314,7 +316,7 @@ fn should_revalidate_across_many_blocks() {
|
||||
block_on(futures_timer::Delay::new(BACKGROUND_REVALIDATION_INTERVAL*2));
|
||||
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(2), xt3.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(2), SOURCE, xt3.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 3);
|
||||
|
||||
pool.api.push_block(2, vec![xt1.clone()]);
|
||||
@@ -337,15 +339,25 @@ fn should_push_watchers_during_maintaince() {
|
||||
let (pool, _guard) = maintained_pool();
|
||||
|
||||
let tx0 = alice_uxt(0);
|
||||
let watcher0 = block_on(pool.submit_and_watch(&BlockId::Number(0), tx0.clone())).unwrap();
|
||||
let watcher0 = block_on(
|
||||
pool.submit_and_watch(&BlockId::Number(0), SOURCE, tx0.clone())
|
||||
).unwrap();
|
||||
let tx1 = alice_uxt(1);
|
||||
let watcher1 = block_on(pool.submit_and_watch(&BlockId::Number(0), tx1.clone())).unwrap();
|
||||
let watcher1 = block_on(
|
||||
pool.submit_and_watch(&BlockId::Number(0), SOURCE, tx1.clone())
|
||||
).unwrap();
|
||||
let tx2 = alice_uxt(2);
|
||||
let watcher2 = block_on(pool.submit_and_watch(&BlockId::Number(0), tx2.clone())).unwrap();
|
||||
let watcher2 = block_on(
|
||||
pool.submit_and_watch(&BlockId::Number(0), SOURCE, tx2.clone())
|
||||
).unwrap();
|
||||
let tx3 = alice_uxt(3);
|
||||
let watcher3 = block_on(pool.submit_and_watch(&BlockId::Number(0), tx3.clone())).unwrap();
|
||||
let watcher3 = block_on(
|
||||
pool.submit_and_watch(&BlockId::Number(0), SOURCE, tx3.clone())
|
||||
).unwrap();
|
||||
let tx4 = alice_uxt(4);
|
||||
let watcher4 = block_on(pool.submit_and_watch(&BlockId::Number(0), tx4.clone())).unwrap();
|
||||
let watcher4 = block_on(
|
||||
pool.submit_and_watch(&BlockId::Number(0), SOURCE, tx4.clone())
|
||||
).unwrap();
|
||||
assert_eq!(pool.status().ready, 5);
|
||||
|
||||
// when
|
||||
@@ -398,10 +410,10 @@ fn should_push_watchers_during_maintaince() {
|
||||
#[test]
|
||||
fn can_track_heap_size() {
|
||||
let (pool, _guard) = maintained_pool();
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt(Alice, 209))).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt(Alice, 210))).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt(Alice, 211))).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt(Alice, 212))).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 210))).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 211))).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 212))).expect("1. Imported");
|
||||
|
||||
assert!(parity_util_mem::malloc_size(&pool) > 3000);
|
||||
}
|
||||
@@ -412,7 +424,9 @@ fn finalization() {
|
||||
let api = TestApi::with_alice_nonce(209);
|
||||
api.push_block(1, vec![]);
|
||||
let (pool, _background) = BasicPool::new(Default::default(), api.into());
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::number(1), xt.clone())).expect("1. Imported");
|
||||
let watcher = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, xt.clone())
|
||||
).expect("1. Imported");
|
||||
pool.api.push_block(2, vec![xt.clone()]);
|
||||
|
||||
let header = pool.api.chain().read().header_by_number.get(&2).cloned().unwrap();
|
||||
@@ -462,7 +476,9 @@ fn fork_aware_finalization() {
|
||||
|
||||
// block B1
|
||||
{
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::number(1), from_alice.clone())).expect("1. Imported");
|
||||
let watcher = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())
|
||||
).expect("1. Imported");
|
||||
let header = pool.api.push_block(2, vec![from_alice.clone()]);
|
||||
canon_watchers.push((watcher, header.hash()));
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
@@ -483,8 +499,9 @@ fn fork_aware_finalization() {
|
||||
// block C2
|
||||
{
|
||||
let header = pool.api.push_fork_block_with_parent(b1, vec![from_dave.clone()]);
|
||||
from_dave_watcher = block_on(pool.submit_and_watch(&BlockId::number(1), from_dave.clone()))
|
||||
.expect("1. Imported");
|
||||
from_dave_watcher = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, from_dave.clone())
|
||||
).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
let event = ChainEvent::NewBlock {
|
||||
id: BlockId::Hash(header.hash()),
|
||||
@@ -499,7 +516,9 @@ fn fork_aware_finalization() {
|
||||
|
||||
// block D2
|
||||
{
|
||||
from_bob_watcher = block_on(pool.submit_and_watch(&BlockId::number(1), from_bob.clone())).expect("1. Imported");
|
||||
from_bob_watcher = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())
|
||||
).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
let header = pool.api.push_fork_block_with_parent(c2, vec![from_bob.clone()]);
|
||||
|
||||
@@ -516,7 +535,9 @@ fn fork_aware_finalization() {
|
||||
|
||||
// block C1
|
||||
{
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::number(1), from_charlie.clone())).expect("1.Imported");
|
||||
let watcher = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, from_charlie.clone())
|
||||
).expect("1.Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
let header = pool.api.push_block(3, vec![from_charlie.clone()]);
|
||||
|
||||
@@ -536,7 +557,9 @@ fn fork_aware_finalization() {
|
||||
// block D1
|
||||
{
|
||||
let xt = uxt(Eve, 0);
|
||||
let w = block_on(pool.submit_and_watch(&BlockId::number(1), xt.clone())).expect("1. Imported");
|
||||
let w = block_on(
|
||||
pool.submit_and_watch(&BlockId::number(1), SOURCE, xt.clone())
|
||||
).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 3);
|
||||
let header = pool.api.push_block(4, vec![xt.clone()]);
|
||||
canon_watchers.push((w, header.hash()));
|
||||
@@ -608,7 +631,7 @@ fn fork_aware_finalization() {
|
||||
fn ready_set_should_not_resolve_before_block_update() {
|
||||
let (pool, _guard) = maintained_pool();
|
||||
let xt1 = uxt(Alice, 209);
|
||||
block_on(pool.submit_one(&BlockId::number(1), xt1.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(1), SOURCE, xt1.clone())).expect("1. Imported");
|
||||
|
||||
assert!(pool.ready_at(1).now_or_never().is_none());
|
||||
}
|
||||
@@ -620,7 +643,7 @@ fn ready_set_should_resolve_after_block_update() {
|
||||
|
||||
let xt1 = uxt(Alice, 209);
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(1), xt1.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(1), SOURCE, xt1.clone())).expect("1. Imported");
|
||||
block_on(pool.maintain(block_event(1)));
|
||||
|
||||
assert!(pool.ready_at(1).now_or_never().is_some());
|
||||
@@ -633,7 +656,7 @@ fn ready_set_should_eventually_resolve_when_block_update_arrives() {
|
||||
|
||||
let xt1 = uxt(Alice, 209);
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(1), xt1.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(1), SOURCE, xt1.clone())).expect("1. Imported");
|
||||
|
||||
let noop_waker = futures::task::noop_waker();
|
||||
let mut context = futures::task::Context::from_waker(&noop_waker);
|
||||
@@ -681,7 +704,7 @@ fn should_not_accept_old_signatures() {
|
||||
let xt = Extrinsic::Transfer { transfer, signature: old_singature, exhaust_resources_when_not_first: false };
|
||||
|
||||
assert_matches::assert_matches!(
|
||||
block_on(pool.submit_one(&BlockId::number(0), xt.clone())),
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())),
|
||||
Err(error::Error::Pool(
|
||||
sp_transaction_pool::error::Error::InvalidTransaction(InvalidTransaction::BadProof)
|
||||
)),
|
||||
|
||||
@@ -51,7 +51,9 @@ use sp_core::crypto::KeyTypeId;
|
||||
use sp_runtime::{
|
||||
offchain::{http, Duration, storage::StorageValueRef},
|
||||
traits::Zero,
|
||||
transaction_validity::{InvalidTransaction, ValidTransaction, TransactionValidity},
|
||||
transaction_validity::{
|
||||
InvalidTransaction, ValidTransaction, TransactionValidity, TransactionSource,
|
||||
},
|
||||
};
|
||||
use sp_std::{vec, vec::Vec};
|
||||
use lite_json::json::JsonValue;
|
||||
@@ -509,7 +511,10 @@ impl<T: Trait> frame_support::unsigned::ValidateUnsigned for Module<T> {
|
||||
/// By default unsigned transactions are disallowed, but implementing the validator
|
||||
/// here we make sure that some particular calls (the ones produced by offchain worker)
|
||||
/// are being whitelisted and marked as valid.
|
||||
fn validate_unsigned(call: &Self::Call) -> TransactionValidity {
|
||||
fn validate_unsigned(
|
||||
_source: TransactionSource,
|
||||
call: &Self::Call,
|
||||
) -> TransactionValidity {
|
||||
// Firstly let's check that we call the right function.
|
||||
if let Call::submit_price_unsigned(block_number, new_price) = call {
|
||||
// Now let's check if the transaction has any chance to succeed.
|
||||
|
||||
@@ -59,12 +59,14 @@
|
||||
//! # pub type Balances = u64;
|
||||
//! # pub type AllModules = u64;
|
||||
//! # pub enum Runtime {};
|
||||
//! # use sp_runtime::transaction_validity::{TransactionValidity, UnknownTransaction};
|
||||
//! # use sp_runtime::transaction_validity::{
|
||||
//! TransactionValidity, UnknownTransaction, TransactionSource,
|
||||
//! # };
|
||||
//! # use sp_runtime::traits::ValidateUnsigned;
|
||||
//! # impl ValidateUnsigned for Runtime {
|
||||
//! # type Call = ();
|
||||
//! #
|
||||
//! # fn validate_unsigned(_call: &Self::Call) -> TransactionValidity {
|
||||
//! # fn validate_unsigned(_source: TransactionSource, _call: &Self::Call) -> TransactionValidity {
|
||||
//! # UnknownTransaction::NoUnsignedValidator.into()
|
||||
//! # }
|
||||
//! # }
|
||||
@@ -85,7 +87,7 @@ use sp_runtime::{
|
||||
self, Header, Zero, One, Checkable, Applyable, CheckEqual, ValidateUnsigned, NumberFor,
|
||||
Block as BlockT, Dispatchable, Saturating,
|
||||
},
|
||||
transaction_validity::TransactionValidity,
|
||||
transaction_validity::{TransactionValidity, TransactionSource},
|
||||
};
|
||||
use codec::{Codec, Encode};
|
||||
use frame_system::{extrinsics_root, DigestOf};
|
||||
@@ -338,12 +340,15 @@ where
|
||||
/// side-effects; it merely checks whether the transaction would panic if it were included or not.
|
||||
///
|
||||
/// Changes made to storage should be discarded.
|
||||
pub fn validate_transaction(uxt: Block::Extrinsic) -> TransactionValidity {
|
||||
pub fn validate_transaction(
|
||||
source: TransactionSource,
|
||||
uxt: Block::Extrinsic,
|
||||
) -> TransactionValidity {
|
||||
let encoded_len = uxt.using_encoded(|d| d.len());
|
||||
let xt = uxt.check(&Default::default())?;
|
||||
|
||||
let dispatch_info = xt.get_dispatch_info();
|
||||
xt.validate::<UnsignedValidator>(dispatch_info, encoded_len)
|
||||
xt.validate::<UnsignedValidator>(source, dispatch_info, encoded_len)
|
||||
}
|
||||
|
||||
/// Start an offchain worker and generate extrinsics.
|
||||
@@ -511,7 +516,10 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_unsigned(call: &Self::Call) -> TransactionValidity {
|
||||
fn validate_unsigned(
|
||||
_source: TransactionSource,
|
||||
call: &Self::Call,
|
||||
) -> TransactionValidity {
|
||||
match call {
|
||||
Call::Balances(BalancesCall::set_balance(_, _, _)) => Ok(Default::default()),
|
||||
_ => UnknownTransaction::NoUnsignedValidator.into(),
|
||||
@@ -725,7 +733,10 @@ mod tests {
|
||||
let mut t = new_test_ext(1);
|
||||
|
||||
t.execute_with(|| {
|
||||
assert_eq!(Executive::validate_transaction(xt.clone()), Ok(Default::default()));
|
||||
assert_eq!(
|
||||
Executive::validate_transaction(TransactionSource::InBlock, xt.clone()),
|
||||
Ok(Default::default()),
|
||||
);
|
||||
assert_eq!(Executive::apply_extrinsic(xt), Ok(Err(DispatchError::BadOrigin)));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ use frame_system::RawOrigin;
|
||||
use frame_benchmarking::benchmarks;
|
||||
use sp_core::offchain::{OpaquePeerId, OpaqueMultiaddr};
|
||||
use sp_runtime::traits::{ValidateUnsigned, Zero};
|
||||
use sp_runtime::transaction_validity::TransactionSource;
|
||||
|
||||
use crate::Module as ImOnline;
|
||||
|
||||
@@ -72,7 +73,7 @@ benchmarks! {
|
||||
let (input_heartbeat, signature) = create_heartbeat::<T>(k, e)?;
|
||||
let call = Call::heartbeat(input_heartbeat, signature);
|
||||
}: {
|
||||
ImOnline::<T>::validate_unsigned(&call)?;
|
||||
ImOnline::<T>::validate_unsigned(TransactionSource::InBlock, &call)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ use sp_runtime::{
|
||||
RuntimeDebug,
|
||||
traits::{Convert, Member, Saturating, AtLeast32Bit}, Perbill, PerThing,
|
||||
transaction_validity::{
|
||||
TransactionValidity, ValidTransaction, InvalidTransaction,
|
||||
TransactionValidity, ValidTransaction, InvalidTransaction, TransactionSource,
|
||||
TransactionPriority,
|
||||
},
|
||||
};
|
||||
@@ -624,7 +624,10 @@ impl<T: Trait> pallet_session::OneSessionHandler<T::AccountId> for Module<T> {
|
||||
impl<T: Trait> frame_support::unsigned::ValidateUnsigned for Module<T> {
|
||||
type Call = Call<T>;
|
||||
|
||||
fn validate_unsigned(call: &Self::Call) -> TransactionValidity {
|
||||
fn validate_unsigned(
|
||||
_source: TransactionSource,
|
||||
call: &Self::Call,
|
||||
) -> TransactionValidity {
|
||||
if let Call::heartbeat(heartbeat, signature) = call {
|
||||
if <Module<T>>::is_online(heartbeat.authority_index) {
|
||||
// we already received a heartbeat for this authority
|
||||
|
||||
@@ -89,7 +89,7 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result<TokenStream
|
||||
let inherent = decl_outer_inherent(&block, &unchecked_extrinsic, modules.iter(), &scrate);
|
||||
let validate_unsigned = decl_validate_unsigned(&name, modules.iter(), &scrate);
|
||||
|
||||
Ok(quote!(
|
||||
let res = quote!(
|
||||
#scrate_decl
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
@@ -119,8 +119,9 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result<TokenStream
|
||||
#inherent
|
||||
|
||||
#validate_unsigned
|
||||
)
|
||||
.into())
|
||||
);
|
||||
|
||||
Ok(res.into())
|
||||
}
|
||||
|
||||
fn decl_validate_unsigned<'a>(
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
pub use crate::sp_runtime::traits::ValidateUnsigned;
|
||||
#[doc(hidden)]
|
||||
pub use crate::sp_runtime::transaction_validity::{
|
||||
TransactionValidity, UnknownTransaction, TransactionValidityError,
|
||||
TransactionValidity, UnknownTransaction, TransactionValidityError, TransactionSource,
|
||||
};
|
||||
|
||||
|
||||
@@ -34,7 +34,8 @@ pub use crate::sp_runtime::transaction_validity::{
|
||||
/// # impl frame_support::unsigned::ValidateUnsigned for Module {
|
||||
/// # type Call = Call;
|
||||
/// #
|
||||
/// # fn validate_unsigned(call: &Self::Call) -> frame_support::unsigned::TransactionValidity {
|
||||
/// # fn validate_unsigned(_source: frame_support::unsigned::TransactionSource, _call: &Self::Call)
|
||||
/// -> frame_support::unsigned::TransactionValidity {
|
||||
/// # unimplemented!();
|
||||
/// # }
|
||||
/// # }
|
||||
@@ -78,10 +79,14 @@ macro_rules! impl_outer_validate_unsigned {
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_unsigned(call: &Self::Call) -> $crate::unsigned::TransactionValidity {
|
||||
fn validate_unsigned(
|
||||
#[allow(unused_variables)]
|
||||
source: $crate::unsigned::TransactionSource,
|
||||
call: &Self::Call,
|
||||
) -> $crate::unsigned::TransactionValidity {
|
||||
#[allow(unreachable_patterns)]
|
||||
match call {
|
||||
$( Call::$module(inner_call) => $module::validate_unsigned(inner_call), )*
|
||||
$( Call::$module(inner_call) => $module::validate_unsigned(source, inner_call), )*
|
||||
_ => $crate::unsigned::UnknownTransaction::NoUnsignedValidator.into(),
|
||||
}
|
||||
}
|
||||
@@ -110,7 +115,10 @@ mod test_partial_and_full_call {
|
||||
impl super::super::ValidateUnsigned for Module {
|
||||
type Call = Call;
|
||||
|
||||
fn validate_unsigned(_call: &Self::Call) -> super::super::TransactionValidity {
|
||||
fn validate_unsigned(
|
||||
_source: super::super::TransactionSource,
|
||||
_call: &Self::Call
|
||||
) -> super::super::TransactionValidity {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ use crate::traits::{
|
||||
self, Member, MaybeDisplay, SignedExtension, Dispatchable,
|
||||
};
|
||||
use crate::traits::ValidateUnsigned;
|
||||
use crate::transaction_validity::TransactionValidity;
|
||||
use crate::transaction_validity::{TransactionValidity, TransactionSource};
|
||||
|
||||
/// Definition of something that the external world might want to say; its
|
||||
/// existence implies that it has been checked and is good, particularly with
|
||||
@@ -50,6 +50,9 @@ where
|
||||
|
||||
fn validate<U: ValidateUnsigned<Call = Self::Call>>(
|
||||
&self,
|
||||
// TODO [#5006;ToDr] should source be passed to `SignedExtension`s?
|
||||
// Perhaps a change for 2.0 to avoid breaking too much APIs?
|
||||
source: TransactionSource,
|
||||
info: Self::DispatchInfo,
|
||||
len: usize,
|
||||
) -> TransactionValidity {
|
||||
@@ -57,7 +60,7 @@ where
|
||||
Extra::validate(extra, id, &self.function, info.clone(), len)
|
||||
} else {
|
||||
let valid = Extra::validate_unsigned(&self.function, info, len)?;
|
||||
let unsigned_validation = U::validate_unsigned(&self.function)?;
|
||||
let unsigned_validation = U::validate_unsigned(source, &self.function)?;
|
||||
Ok(valid.combine_with(unsigned_validation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ use crate::traits::ValidateUnsigned;
|
||||
use crate::{generic, KeyTypeId, ApplyExtrinsicResult};
|
||||
pub use sp_core::{H256, sr25519};
|
||||
use sp_core::{crypto::{CryptoType, Dummy, key_types, Public}, U256};
|
||||
use crate::transaction_validity::{TransactionValidity, TransactionValidityError};
|
||||
use crate::transaction_validity::{TransactionValidity, TransactionValidityError, TransactionSource};
|
||||
|
||||
/// Authority Id
|
||||
#[derive(Default, PartialEq, Eq, Clone, Encode, Decode, Debug, Hash, Serialize, Deserialize, PartialOrd, Ord)]
|
||||
@@ -357,6 +357,7 @@ impl<Origin, Call, Extra, Info> Applyable for TestXt<Call, Extra> where
|
||||
/// Checks to see if this is a valid *transaction*. It returns information on it if so.
|
||||
fn validate<U: ValidateUnsigned<Call=Self::Call>>(
|
||||
&self,
|
||||
_source: TransactionSource,
|
||||
_info: Self::DispatchInfo,
|
||||
_len: usize,
|
||||
) -> TransactionValidity {
|
||||
|
||||
@@ -28,7 +28,8 @@ use serde::{Serialize, Deserialize, de::DeserializeOwned};
|
||||
use sp_core::{self, Hasher, TypeId, RuntimeDebug};
|
||||
use crate::codec::{Codec, Encode, Decode};
|
||||
use crate::transaction_validity::{
|
||||
ValidTransaction, TransactionValidity, TransactionValidityError, UnknownTransaction,
|
||||
ValidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
|
||||
UnknownTransaction,
|
||||
};
|
||||
use crate::generic::{Digest, DigestItem};
|
||||
pub use sp_arithmetic::traits::{
|
||||
@@ -851,6 +852,7 @@ pub trait Applyable: Sized + Send + Sync {
|
||||
/// Checks to see if this is a valid *transaction*. It returns information on it if so.
|
||||
fn validate<V: ValidateUnsigned<Call=Self::Call>>(
|
||||
&self,
|
||||
source: TransactionSource,
|
||||
info: Self::DispatchInfo,
|
||||
len: usize,
|
||||
) -> TransactionValidity;
|
||||
@@ -897,7 +899,7 @@ pub trait ValidateUnsigned {
|
||||
///
|
||||
/// Changes made to storage WILL be persisted if the call returns `Ok`.
|
||||
fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> {
|
||||
Self::validate_unsigned(call)
|
||||
Self::validate_unsigned(TransactionSource::InBlock, call)
|
||||
.map(|_| ())
|
||||
.map_err(Into::into)
|
||||
}
|
||||
@@ -908,7 +910,7 @@ pub trait ValidateUnsigned {
|
||||
/// whether the transaction would panic if it were included or not.
|
||||
///
|
||||
/// Changes made to storage should be discarded by caller.
|
||||
fn validate_unsigned(call: &Self::Call) -> TransactionValidity;
|
||||
fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity;
|
||||
}
|
||||
|
||||
/// Opaque data type that may be destructured into a series of raw byte slices (which represent
|
||||
|
||||
@@ -161,6 +161,35 @@ impl Into<TransactionValidity> for UnknownTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
/// The source of the transaction.
|
||||
///
|
||||
/// Depending on the source we might apply different validation schemes.
|
||||
/// For instance we can disallow specific kinds of transactions if they were not produced
|
||||
/// by our local node (for instance off-chain workers).
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, parity_util_mem::MallocSizeOf)]
|
||||
pub enum TransactionSource {
|
||||
/// Transaction is already included in block.
|
||||
///
|
||||
/// This means that we can't really tell where the transaction is coming from,
|
||||
/// since it's already in the received block. Note that the custom validation logic
|
||||
/// using either `Local` or `External` should most likely just allow `InBlock`
|
||||
/// transactions as well.
|
||||
InBlock,
|
||||
|
||||
/// Transaction is coming from a local source.
|
||||
///
|
||||
/// This means that the transaction was produced internally by the node
|
||||
/// (for instance an Off-Chain Worker, or an Off-Chain Call), as opposed
|
||||
/// to being received over the network.
|
||||
Local,
|
||||
|
||||
/// Transaction has been received externally.
|
||||
///
|
||||
/// This means the transaction has been received from (usually) "untrusted" source,
|
||||
/// for instance received over the network or RPC.
|
||||
External,
|
||||
}
|
||||
|
||||
/// Information concerning a valid transaction.
|
||||
#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)]
|
||||
pub struct ValidTransaction {
|
||||
|
||||
@@ -29,5 +29,5 @@ mod pool;
|
||||
pub use pool::*;
|
||||
|
||||
pub use sp_runtime::transaction_validity::{
|
||||
TransactionLongevity, TransactionPriority, TransactionTag,
|
||||
TransactionLongevity, TransactionPriority, TransactionTag, TransactionSource,
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@ use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, Member, NumberFor},
|
||||
transaction_validity::{
|
||||
TransactionLongevity, TransactionPriority, TransactionTag,
|
||||
TransactionLongevity, TransactionPriority, TransactionTag, TransactionSource,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -192,6 +192,7 @@ pub trait TransactionPool: Send + Sync {
|
||||
fn submit_at(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
source: TransactionSource,
|
||||
xts: Vec<TransactionFor<Self>>,
|
||||
) -> PoolFuture<Vec<Result<TxHash<Self>, Self::Error>>, Self::Error>;
|
||||
|
||||
@@ -199,6 +200,7 @@ pub trait TransactionPool: Send + Sync {
|
||||
fn submit_one(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
source: TransactionSource,
|
||||
xt: TransactionFor<Self>,
|
||||
) -> PoolFuture<TxHash<Self>, Self::Error>;
|
||||
|
||||
@@ -206,6 +208,7 @@ pub trait TransactionPool: Send + Sync {
|
||||
fn submit_and_watch(
|
||||
&self,
|
||||
at: &BlockId<Self::Block>,
|
||||
source: TransactionSource,
|
||||
xt: TransactionFor<Self>,
|
||||
) -> PoolFuture<Box<TransactionStatusStreamFor<Self>>, Self::Error>;
|
||||
|
||||
@@ -299,7 +302,9 @@ impl<TPool: TransactionPool> OffchainSubmitTransaction<TPool::Block> for TPool {
|
||||
extrinsic
|
||||
);
|
||||
|
||||
let result = futures::executor::block_on(self.submit_one(&at, extrinsic));
|
||||
let result = futures::executor::block_on(self.submit_one(
|
||||
&at, TransactionSource::Local, extrinsic,
|
||||
));
|
||||
|
||||
result.map(|_| ())
|
||||
.map_err(|e| log::warn!(
|
||||
|
||||
@@ -16,13 +16,27 @@
|
||||
|
||||
//! Tagged Transaction Queue Runtime API.
|
||||
|
||||
use sp_runtime::transaction_validity::TransactionValidity;
|
||||
use sp_runtime::transaction_validity::{TransactionValidity, TransactionSource};
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
/// The `TaggedTransactionQueue` api trait for interfering with the transaction queue.
|
||||
#[api_version(2)]
|
||||
pub trait TaggedTransactionQueue {
|
||||
/// Validate the given transaction.
|
||||
/// Validate the transaction.
|
||||
#[changed_in(2)]
|
||||
fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity;
|
||||
|
||||
/// Validate the transaction.
|
||||
///
|
||||
/// This method is invoked by the transaction pool to learn details about given transaction.
|
||||
/// The implementation should make sure to verify the correctness of the transaction
|
||||
/// against current state.
|
||||
/// Note that this call may be performed by the pool multiple times and transactions
|
||||
/// might be verified in any possible order.
|
||||
fn validate_transaction(
|
||||
source: TransactionSource,
|
||||
tx: <Block as BlockT>::Extrinsic,
|
||||
) -> TransactionValidity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ use sp_runtime::{
|
||||
ApplyExtrinsicResult, create_runtime_str, Perbill, impl_opaque_keys,
|
||||
transaction_validity::{
|
||||
TransactionValidity, ValidTransaction, TransactionValidityError, InvalidTransaction,
|
||||
TransactionSource,
|
||||
},
|
||||
traits::{
|
||||
BlindCheckable, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT,
|
||||
@@ -492,7 +493,10 @@ cfg_if! {
|
||||
}
|
||||
|
||||
impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
|
||||
fn validate_transaction(utx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
|
||||
fn validate_transaction(
|
||||
_source: TransactionSource,
|
||||
utx: <Block as BlockT>::Extrinsic,
|
||||
) -> TransactionValidity {
|
||||
if let Extrinsic::IncludeData(data) = utx {
|
||||
return Ok(ValidTransaction {
|
||||
priority: data.len() as u64,
|
||||
@@ -679,7 +683,10 @@ cfg_if! {
|
||||
}
|
||||
|
||||
impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
|
||||
fn validate_transaction(utx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
|
||||
fn validate_transaction(
|
||||
_source: TransactionSource,
|
||||
utx: <Block as BlockT>::Extrinsic,
|
||||
) -> TransactionValidity {
|
||||
if let Extrinsic::IncludeData(data) = utx {
|
||||
return Ok(ValidTransaction{
|
||||
priority: data.len() as u64,
|
||||
|
||||
@@ -25,6 +25,7 @@ use sp_runtime::{
|
||||
traits::{BlakeTwo256, Hash as HashT},
|
||||
transaction_validity::{
|
||||
TransactionValidity, ValidTransaction, TransactionValidityError, InvalidTransaction,
|
||||
TransactionSource,
|
||||
},
|
||||
};
|
||||
use std::collections::{HashSet, HashMap};
|
||||
@@ -180,6 +181,7 @@ impl sc_transaction_graph::ChainApi for TestApi {
|
||||
fn validate_transaction(
|
||||
&self,
|
||||
_at: &BlockId<Self::Block>,
|
||||
_source: TransactionSource,
|
||||
uxt: sc_transaction_graph::ExtrinsicFor<Self>,
|
||||
) -> Self::ValidationFuture {
|
||||
self.validation_requests.write().push(uxt.clone());
|
||||
|
||||
@@ -239,6 +239,7 @@ mod tests {
|
||||
BasicPool::new(Default::default(), Arc::new(FullChainApi::new(client.clone()))).0
|
||||
);
|
||||
|
||||
let source = sp_runtime::transaction_validity::TransactionSource::External;
|
||||
let new_transaction = |nonce: u64| {
|
||||
let t = Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
@@ -250,9 +251,9 @@ mod tests {
|
||||
};
|
||||
// Populate the pool
|
||||
let ext0 = new_transaction(0);
|
||||
block_on(pool.submit_one(&BlockId::number(0), ext0)).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::number(0), source, ext0)).unwrap();
|
||||
let ext1 = new_transaction(1);
|
||||
block_on(pool.submit_one(&BlockId::number(0), ext1)).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::number(0), source, ext1)).unwrap();
|
||||
|
||||
let accounts = FullSystem::new(client, pool);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user