Add RPC to remove and ban transactions from the pool. (#2732)

This commit is contained in:
Tomasz Drwięga
2019-05-30 13:50:23 +02:00
committed by Gavin Wood
parent 683fd5d364
commit 7af8604cbe
4 changed files with 91 additions and 10 deletions
+30
View File
@@ -0,0 +1,30 @@
// 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/>.
use primitives::Bytes;
use serde::Deserialize;
/// RPC Extrinsic or hash
///
/// Allows to refer to extrinsics either by their raw representation or by it's hash.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ExtrinsicOrHash<Hash> {
/// The hash of the extrinsic.
Hash(Hash),
/// Raw extrinsic bytes.
Extrinsic(Bytes),
}
+32 -8
View File
@@ -18,9 +18,15 @@
use std::sync::Arc;
use log::warn;
use client::{self, Client};
use crate::rpc::futures::{Sink, Stream, Future};
use crate::subscriptions::Subscriptions;
use jsonrpc_derive::rpc;
use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId};
use log::warn;
use parity_codec::{Encode, Decode};
use primitives::{Bytes, Blake2Hasher, H256};
use runtime_primitives::{generic, traits};
use transaction_pool::{
txpool::{
ChainApi as PoolChainApi,
@@ -31,14 +37,9 @@ use transaction_pool::{
watcher::Status,
},
};
use jsonrpc_derive::rpc;
use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId};
use primitives::{Bytes, Blake2Hasher, H256};
use crate::rpc::futures::{Sink, Stream, Future};
use runtime_primitives::{generic, traits};
use crate::subscriptions::Subscriptions;
pub mod error;
mod hash;
#[cfg(test)]
mod tests;
@@ -59,6 +60,10 @@ pub trait AuthorApi<Hash, BlockHash> {
#[rpc(name = "author_pendingExtrinsics")]
fn pending_extrinsics(&self) -> Result<Vec<Bytes>>;
/// Remove given extrinsic from the pool and temporarily ban it to prevent reimporting.
#[rpc(name = "author_removeExtrinsic")]
fn remove_extrinsic(&self, bytes_or_hash: Vec<hash::ExtrinsicOrHash<Hash>>) -> Result<Vec<Hash>>;
/// Submit an extrinsic to watch.
#[pubsub(subscription = "author_extrinsicUpdate", subscribe, name = "author_submitAndWatchExtrinsic")]
fn watch_extrinsic(&self, metadata: Self::Metadata, subscriber: Subscriber<Status<Hash, BlockHash>>, bytes: Bytes);
@@ -72,7 +77,7 @@ pub trait AuthorApi<Hash, BlockHash> {
pub struct Author<B, E, P, RA> where P: PoolChainApi + Sync + Send + 'static {
/// Substrate client
client: Arc<Client<B, E, <P as PoolChainApi>::Block, RA>>,
/// Extrinsic pool
/// Transactions pool
pool: Arc<Pool<P>>,
/// Subscriptions manager
subscriptions: Subscriptions,
@@ -118,6 +123,25 @@ impl<B, E, P, RA> AuthorApi<ExHash<P>, BlockHash<P>> for Author<B, E, P, RA> whe
Ok(self.pool.ready().map(|tx| tx.data.encode().into()).collect())
}
fn remove_extrinsic(&self, bytes_or_hash: Vec<hash::ExtrinsicOrHash<ExHash<P>>>) -> Result<Vec<ExHash<P>>> {
let hashes = bytes_or_hash.into_iter()
.map(|x| match x {
hash::ExtrinsicOrHash::Hash(h) => Ok(h),
hash::ExtrinsicOrHash::Extrinsic(bytes) => {
let xt = Decode::decode(&mut &bytes[..]).ok_or(error::Error::BadFormat)?;
Ok(self.pool.hash_of(&xt))
},
})
.collect::<Result<Vec<_>>>()?;
Ok(
self.pool.remove_invalid(&hashes)
.into_iter()
.map(|tx| tx.hash.clone())
.collect()
)
}
fn watch_extrinsic(&self, _metadata: Self::Metadata, subscriber: Subscriber<Status<ExHash<P>, BlockHash<P>>>, xt: Bytes) {
let submit = || -> Result<_> {
let best_block_hash = self.client.info()?.chain.best_hash;
+28
View File
@@ -137,3 +137,31 @@ fn should_return_pending_extrinsics() {
Ok(ref expected) if *expected == vec![Bytes(ex.encode())]
);
}
#[test]
fn should_remove_extrinsics() {
let runtime = runtime::Runtime::new().unwrap();
let client = Arc::new(test_client::new());
let pool = Arc::new(Pool::new(Default::default(), ChainApi::new(client.clone())));
let p = Author {
client,
pool: pool.clone(),
subscriptions: Subscriptions::new(runtime.executor()),
};
let ex1 = uxt(AccountKeyring::Alice, 0);
p.submit_extrinsic(ex1.encode().into()).unwrap();
let ex2 = uxt(AccountKeyring::Alice, 1);
p.submit_extrinsic(ex2.encode().into()).unwrap();
let ex3 = uxt(AccountKeyring::Bob, 0);
let hash3 = p.submit_extrinsic(ex3.encode().into()).unwrap();
assert_eq!(pool.status().ready, 3);
// now remove all 3
let removed = p.remove_extrinsic(vec![
hash::ExtrinsicOrHash::Hash(hash3),
// Removing this one will also remove ex2
hash::ExtrinsicOrHash::Extrinsic(ex1.encode().into()),
]).unwrap();
assert_eq!(removed.len(), 3);
}