{
imports_external_transactions: bool,
pool: Arc,
client: Arc,
}
/// Get transactions for propagation.
///
/// Function extracted to simplify the test and prevent creating `ServiceFactory`.
fn transactions_to_propagate(pool: &TransactionPool)
-> Vec<(H, B::Extrinsic)>
where
PoolApi: ChainApi,
B: BlockT,
H: std::hash::Hash + Eq + sr_primitives::traits::Member + serde::Serialize,
E: txpool::error::IntoPoolError + From,
{
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 network::TransactionPool for
TransactionPoolAdapter>
where
C: network::ClientHandle + Send + Sync,
PoolApi: ChainApi,
B: BlockT,
H: std::hash::Hash + Eq + sr_primitives::traits::Member + serde::Serialize,
E: txpool::error::IntoPoolError + From,
{
fn transactions(&self) -> Vec<(H, ::Extrinsic)> {
transactions_to_propagate(&self.pool)
}
fn import(&self, transaction: &::Extrinsic) -> Option {
if !self.imports_external_transactions {
debug!("Transaction rejected");
return None;
}
let encoded = transaction.encode();
match Decode::decode(&mut &encoded[..]) {
Ok(uxt) => {
let best_block_id = BlockId::hash(self.client.info().chain.best_hash);
match self.pool.submit_one(&best_block_id, uxt) {
Ok(hash) => Some(hash),
Err(e) => match e.into_pool_error() {
Ok(txpool::error::Error::AlreadyImported(hash)) => {
hash.downcast::().ok()
.map(|x| x.as_ref().clone())
},
Ok(e) => {
debug!("Error adding transaction to the pool: {:?}", e);
None
},
Err(e) => {
debug!("Error converting pool error: {:?}", e);
None
},
}
}
}
Err(e) => {
debug!("Error decoding transaction {}", e);
None
}
}
}
fn on_broadcasted(&self, propagations: HashMap>) {
self.pool.on_broadcasted(propagations)
}
}
#[cfg(test)]
mod tests {
use super::*;
use consensus_common::SelectChain;
use sr_primitives::traits::BlindCheckable;
use substrate_test_runtime_client::{prelude::*, runtime::{Extrinsic, Transfer}};
#[test]
fn should_not_propagate_transactions_that_are_marked_as_such() {
// given
let (client, longest_chain) = TestClientBuilder::new().build_with_longest_chain();
let client = Arc::new(client);
let pool = Arc::new(TransactionPool::new(
Default::default(),
transaction_pool::ChainApi::new(client.clone())
));
let best = longest_chain.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();
}
}