mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 09:21:05 +00:00
Improve transaction submission (#6599)
* Improve transaction submission Before this pr the transaction pool validated each transaction, even if the transaction was already known to the pool. This pr changes the behavior to first check if we are already aware of a transaction and thus, to only validate them if we don't know them yet. However, there is still the possibility that a given transaction is validated multiple times. This can happen if the transaction is added the first time, but is not yet validated and added to the validated pool. Besides that, this pr fixes the wrong metrics of gossiped transactions in the network. It also moves some metrics to the transaction pool api, to better track when a transaction actually is scheduled for validation. * Make sure we don't submit the same transaction twice from the network concurrently * Remove added listener call * Feedback * Ignore banned on resubmit
This commit is contained in:
@@ -33,19 +33,38 @@ use sp_runtime::{
|
||||
};
|
||||
use sp_transaction_pool::runtime_api::TaggedTransactionQueue;
|
||||
use sp_api::{ProvideRuntimeApi, ApiExt};
|
||||
use prometheus_endpoint::Registry as PrometheusRegistry;
|
||||
|
||||
use crate::error::{self, Error};
|
||||
use crate::{metrics::{ApiMetrics, ApiMetricsExt}, error::{self, Error}};
|
||||
|
||||
/// The transaction pool logic for full client.
|
||||
pub struct FullChainApi<Client, Block> {
|
||||
client: Arc<Client>,
|
||||
pool: ThreadPool,
|
||||
_marker: PhantomData<Block>,
|
||||
metrics: Option<Arc<ApiMetrics>>,
|
||||
}
|
||||
|
||||
impl<Client, Block> FullChainApi<Client, Block> {
|
||||
/// Create new transaction pool logic.
|
||||
pub fn new(client: Arc<Client>) -> Self {
|
||||
pub fn new(
|
||||
client: Arc<Client>,
|
||||
prometheus: Option<&PrometheusRegistry>,
|
||||
) -> Self {
|
||||
let metrics = prometheus.map(ApiMetrics::register).and_then(|r| {
|
||||
match r {
|
||||
Err(err) => {
|
||||
log::warn!(
|
||||
target: "txpool",
|
||||
"Failed to register transaction pool api prometheus metrics: {:?}",
|
||||
err,
|
||||
);
|
||||
None
|
||||
},
|
||||
Ok(api) => Some(Arc::new(api))
|
||||
}
|
||||
});
|
||||
|
||||
FullChainApi {
|
||||
client,
|
||||
pool: ThreadPoolBuilder::new()
|
||||
@@ -54,6 +73,7 @@ impl<Client, Block> FullChainApi<Client, Block> {
|
||||
.create()
|
||||
.expect("Failed to spawn verifier threads, that are critical for node operation."),
|
||||
_marker: Default::default(),
|
||||
metrics,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,6 +107,9 @@ where
|
||||
let client = self.client.clone();
|
||||
let at = at.clone();
|
||||
|
||||
let metrics = self.metrics.clone();
|
||||
metrics.report(|m| m.validations_scheduled.inc());
|
||||
|
||||
self.pool.spawn_ok(futures_diagnose::diagnose(
|
||||
"validate-transaction",
|
||||
async move {
|
||||
@@ -94,6 +117,7 @@ where
|
||||
if let Err(e) = tx.send(res) {
|
||||
log::warn!("Unable to send a validate transaction result: {:?}", e);
|
||||
}
|
||||
metrics.report(|m| m.validations_finished.inc());
|
||||
},
|
||||
));
|
||||
|
||||
|
||||
@@ -248,15 +248,9 @@ impl<PoolApi, Block> TransactionPool for BasicPool<PoolApi, Block>
|
||||
let pool = self.pool.clone();
|
||||
let at = *at;
|
||||
|
||||
self.metrics.report(|metrics| metrics.validations_scheduled.inc_by(xts.len() as u64));
|
||||
self.metrics.report(|metrics| metrics.submitted_transactions.inc_by(xts.len() as u64));
|
||||
|
||||
let metrics = self.metrics.clone();
|
||||
async move {
|
||||
let tx_count = xts.len();
|
||||
let res = pool.submit_at(&at, source, xts, false).await;
|
||||
metrics.report(|metrics| metrics.validations_finished.inc_by(tx_count as u64));
|
||||
res
|
||||
}.boxed()
|
||||
async move { pool.submit_at(&at, source, xts).await }.boxed()
|
||||
}
|
||||
|
||||
fn submit_one(
|
||||
@@ -268,16 +262,9 @@ impl<PoolApi, Block> TransactionPool for BasicPool<PoolApi, Block>
|
||||
let pool = self.pool.clone();
|
||||
let at = *at;
|
||||
|
||||
self.metrics.report(|metrics| metrics.validations_scheduled.inc());
|
||||
self.metrics.report(|metrics| metrics.submitted_transactions.inc());
|
||||
|
||||
let metrics = self.metrics.clone();
|
||||
async move {
|
||||
let res = pool.submit_one(&at, source, xt).await;
|
||||
|
||||
metrics.report(|metrics| metrics.validations_finished.inc());
|
||||
res
|
||||
|
||||
}.boxed()
|
||||
async move { pool.submit_one(&at, source, xt).await }.boxed()
|
||||
}
|
||||
|
||||
fn submit_and_watch(
|
||||
@@ -289,17 +276,12 @@ impl<PoolApi, Block> TransactionPool for BasicPool<PoolApi, Block>
|
||||
let at = *at;
|
||||
let pool = self.pool.clone();
|
||||
|
||||
self.metrics.report(|metrics| metrics.validations_scheduled.inc());
|
||||
self.metrics.report(|metrics| metrics.submitted_transactions.inc());
|
||||
|
||||
let metrics = self.metrics.clone();
|
||||
async move {
|
||||
let result = pool.submit_and_watch(&at, source, xt)
|
||||
pool.submit_and_watch(&at, source, xt)
|
||||
.map(|result| result.map(|watcher| Box::new(watcher.into_stream()) as _))
|
||||
.await;
|
||||
|
||||
metrics.report(|metrics| metrics.validations_finished.inc());
|
||||
|
||||
result
|
||||
.await
|
||||
}.boxed()
|
||||
}
|
||||
|
||||
@@ -632,13 +614,12 @@ impl<PoolApi, Block> MaintainedTransactionPool for BasicPool<PoolApi, Block>
|
||||
);
|
||||
}
|
||||
|
||||
if let Err(e) = pool.submit_at(
|
||||
if let Err(e) = pool.resubmit_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",
|
||||
|
||||
@@ -45,8 +45,7 @@ impl MetricsLink {
|
||||
|
||||
/// Transaction pool Prometheus metrics.
|
||||
pub struct Metrics {
|
||||
pub validations_scheduled: Counter<U64>,
|
||||
pub validations_finished: Counter<U64>,
|
||||
pub submitted_transactions: Counter<U64>,
|
||||
pub validations_invalid: Counter<U64>,
|
||||
pub block_transactions_pruned: Counter<U64>,
|
||||
pub block_transactions_resubmitted: Counter<U64>,
|
||||
@@ -55,17 +54,10 @@ pub struct Metrics {
|
||||
impl Metrics {
|
||||
pub fn register(registry: &Registry) -> Result<Self, PrometheusError> {
|
||||
Ok(Self {
|
||||
validations_scheduled: register(
|
||||
submitted_transactions: register(
|
||||
Counter::new(
|
||||
"sub_txpool_validations_scheduled",
|
||||
"Total number of transactions scheduled for validation",
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
validations_finished: register(
|
||||
Counter::new(
|
||||
"sub_txpool_validations_finished",
|
||||
"Total number of transactions that finished validation",
|
||||
"sub_txpool_submitted_transactions",
|
||||
"Total number of transactions submitted",
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
@@ -93,3 +85,45 @@ impl Metrics {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Transaction pool api Prometheus metrics.
|
||||
pub struct ApiMetrics {
|
||||
pub validations_scheduled: Counter<U64>,
|
||||
pub validations_finished: Counter<U64>,
|
||||
}
|
||||
|
||||
impl ApiMetrics {
|
||||
/// Register the metrics at the given Prometheus registry.
|
||||
pub fn register(registry: &Registry) -> Result<Self, PrometheusError> {
|
||||
Ok(Self {
|
||||
validations_scheduled: register(
|
||||
Counter::new(
|
||||
"sub_txpool_validations_scheduled",
|
||||
"Total number of transactions scheduled for validation",
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
validations_finished: register(
|
||||
Counter::new(
|
||||
"sub_txpool_validations_finished",
|
||||
"Total number of transactions that finished validation",
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// An extension trait for [`ApiMetrics`].
|
||||
pub trait ApiMetricsExt {
|
||||
/// Report an event to the metrics.
|
||||
fn report(&self, report: impl FnOnce(&ApiMetrics));
|
||||
}
|
||||
|
||||
impl ApiMetricsExt for Option<Arc<ApiMetrics>> {
|
||||
fn report(&self, report: impl FnOnce(&ApiMetrics)) {
|
||||
if let Some(metrics) = self.as_ref() {
|
||||
report(metrics)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1008,7 +1008,7 @@ fn should_not_accept_old_signatures() {
|
||||
let client = Arc::new(substrate_test_runtime_client::new());
|
||||
|
||||
let pool = Arc::new(
|
||||
BasicPool::new_test(Arc::new(FullChainApi::new(client))).0
|
||||
BasicPool::new_test(Arc::new(FullChainApi::new(client, None))).0
|
||||
);
|
||||
|
||||
let transfer = Transfer {
|
||||
@@ -1044,7 +1044,7 @@ fn import_notification_to_pool_maintain_works() {
|
||||
let mut client = Arc::new(substrate_test_runtime_client::new());
|
||||
|
||||
let pool = Arc::new(
|
||||
BasicPool::new_test(Arc::new(FullChainApi::new(client.clone()))).0
|
||||
BasicPool::new_test(Arc::new(FullChainApi::new(client.clone(), None))).0
|
||||
);
|
||||
|
||||
// Prepare the extrisic, push it to the pool and check that it was added.
|
||||
|
||||
Reference in New Issue
Block a user