-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2f532dd
Showing
17 changed files
with
2,902 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Cargo.lock | ||
/target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Copyright 2021 Gnosis Ltd. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
[package] | ||
name = "txpool" | ||
version = "1.0.0-alpha" | ||
authors = ["Dragan Rakita <[email protected]","Karim Agha <[email protected]>"] | ||
edition = "2018" | ||
description = "Generic transaction pool." | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
[dependencies.log] | ||
version = "0.4" | ||
|
||
[dependencies.smallvec] | ||
version = "0.6" | ||
|
||
[dependencies.trace-time] | ||
version = "0.1" | ||
[dev-dependencies.ethereum-types] | ||
version = "0.7" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Generic ethereum transaction pool forked from here: | ||
|
||
https://github.com/openethereum/openethereum/tree/main/crates/transaction-pool |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// Copyright 2015-2018 Parity Technologies (UK) Ltd. | ||
// This file is part of Parity. | ||
|
||
// Parity 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. | ||
|
||
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
use std::{error, fmt, result}; | ||
|
||
/// Transaction Pool Error | ||
#[derive(Debug)] | ||
pub enum Error<Hash: fmt::Debug + fmt::LowerHex> { | ||
/// Transaction is already imported | ||
AlreadyImported(Hash), | ||
/// Transaction is too cheap to enter the queue | ||
TooCheapToEnter(Hash, String), | ||
/// Transaction is too cheap to replace existing transaction that occupies the same slot. | ||
TooCheapToReplace(Hash, Hash), | ||
} | ||
|
||
/// Transaction Pool Result | ||
pub type Result<T, H> = result::Result<T, Error<H>>; | ||
|
||
impl<H: fmt::Debug + fmt::LowerHex> fmt::Display for Error<H> { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
match self { | ||
Error::AlreadyImported(h) => write!(f, "[{:?}] already imported", h), | ||
Error::TooCheapToEnter(hash, min_score) => write!( | ||
f, | ||
"[{:x}] too cheap to enter the pool. Min score: {}", | ||
hash, min_score | ||
), | ||
Error::TooCheapToReplace(old_hash, hash) => { | ||
write!(f, "[{:x}] too cheap to replace: {:x}", hash, old_hash) | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl<H: fmt::Debug + fmt::LowerHex> error::Error for Error<H> {} | ||
|
||
#[cfg(test)] | ||
impl<H: fmt::Debug + fmt::LowerHex> PartialEq for Error<H> | ||
where | ||
H: PartialEq, | ||
{ | ||
fn eq(&self, other: &Self) -> bool { | ||
use self::Error::*; | ||
|
||
match (self, other) { | ||
(&AlreadyImported(ref h1), &AlreadyImported(ref h2)) => h1 == h2, | ||
(&TooCheapToEnter(ref h1, ref s1), &TooCheapToEnter(ref h2, ref s2)) => { | ||
h1 == h2 && s1 == s2 | ||
} | ||
(&TooCheapToReplace(ref old1, ref new1), &TooCheapToReplace(ref old2, ref new2)) => { | ||
old1 == old2 && new1 == new2 | ||
} | ||
_ => false, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// Copyright 2015-2018 Parity Technologies (UK) Ltd. | ||
// This file is part of Parity. | ||
|
||
// Parity 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. | ||
|
||
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
//! Generic Transaction Pool | ||
//! | ||
//! An extensible and performant implementation of Ethereum Transaction Pool. | ||
//! The pool stores ordered, verified transactions according to some pluggable | ||
//! `Scoring` implementation. | ||
//! The pool also allows you to construct a set of `pending` transactions according | ||
//! to some notion of `Readiness` (pluggable). | ||
//! | ||
//! The pool is generic over transactions and should make no assumptions about them. | ||
//! The only thing we can rely on is the `Scoring` that defines: | ||
//! - the ordering of transactions from a single sender | ||
//! - the priority of the transaction compared to other transactions from different senders | ||
//! | ||
//! NOTE: the transactions from a single sender are not ordered by priority, | ||
//! but still when constructing pending set we always need to maintain the ordering | ||
//! (i.e. `txs[1]` always needs to be included after `txs[0]` even if it has higher priority) | ||
//! | ||
//! ### Design Details | ||
//! | ||
//! Performance assumptions: | ||
//! - Possibility to handle tens of thousands of transactions | ||
//! - Fast insertions and replacements `O(per-sender + log(senders))` | ||
//! - Reasonably fast removal of stalled transactions `O(per-sender)` | ||
//! - Reasonably fast construction of pending set `O(txs * (log(senders) + log(per-sender))` | ||
//! | ||
//! The removal performance could be improved by trading some memory. Currently `SmallVec` is used | ||
//! to store senders transactions, instead we could use `VecDeque` and efficiently `pop_front` | ||
//! the best transactions. | ||
//! | ||
//! The pending set construction and insertion complexity could be reduced by introducing | ||
//! a notion of `nonce` - an absolute, numeric ordering of transactions. | ||
//! We don't do that because of possible implications of EIP208 where nonce might not be | ||
//! explicitly available. | ||
//! | ||
//! 1. The pool groups transactions from particular sender together | ||
//! and stores them ordered by `Scoring` within that group | ||
//! i.e. `HashMap<Sender, Vec<Transaction>>`. | ||
//! 2. Additionaly we maintain the best and the worst transaction from each sender | ||
//! (by `Scoring` not `priority`) ordered by `priority`. | ||
//! It means that we can easily identify the best transaction inside the entire pool | ||
//! and the worst transaction. | ||
//! 3. Whenever new transaction is inserted to the queue: | ||
//! - first check all the limits (overall, memory, per-sender) | ||
//! - retrieve all transactions from a sender | ||
//! - binary search for position to insert the transaction | ||
//! - decide if we are replacing existing transaction (3 outcomes: drop, replace, insert) | ||
//! - update best and worst transaction from that sender if affected | ||
//! 4. Pending List construction: | ||
//! - Take the best transaction (by priority) from all senders to the List | ||
//! - Replace the transaction with next transaction (by ordering) from that sender (if any) | ||
//! - Repeat | ||
#![warn(missing_docs)] | ||
|
||
#[cfg(test)] | ||
mod tests; | ||
|
||
mod error; | ||
mod listener; | ||
mod options; | ||
mod pool; | ||
mod ready; | ||
mod replace; | ||
mod status; | ||
mod transactions; | ||
mod verifier; | ||
|
||
pub mod scoring; | ||
|
||
pub use self::{ | ||
error::Error, | ||
listener::{Listener, NoopListener}, | ||
options::Options, | ||
pool::{PendingIterator, Pool, Transaction, UnorderedIterator}, | ||
ready::{Readiness, Ready}, | ||
replace::{ReplaceTransaction, ShouldReplace}, | ||
scoring::Scoring, | ||
status::{LightStatus, Status}, | ||
verifier::Verifier, | ||
}; | ||
|
||
use std::{fmt, hash::Hash}; | ||
|
||
/// Already verified transaction that can be safely queued. | ||
pub trait VerifiedTransaction: fmt::Debug { | ||
/// Transaction hash type. | ||
type Hash: fmt::Debug + fmt::LowerHex + Eq + Clone + Hash; | ||
|
||
/// Transaction sender type. | ||
type Sender: fmt::Debug + Eq + Clone + Hash + Send; | ||
|
||
/// Transaction hash | ||
fn hash(&self) -> &Self::Hash; | ||
|
||
/// Memory usage | ||
fn mem_usage(&self) -> usize; | ||
|
||
/// Transaction sender | ||
fn sender(&self) -> &Self::Sender; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// Copyright 2015-2018 Parity Technologies (UK) Ltd. | ||
// This file is part of Parity. | ||
|
||
// Parity 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. | ||
|
||
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
use crate::error::Error; | ||
use std::{ | ||
fmt::{Debug, LowerHex}, | ||
sync::Arc, | ||
}; | ||
|
||
/// Transaction pool listener. | ||
/// | ||
/// Listener is being notified about status of every transaction in the pool. | ||
pub trait Listener<T> { | ||
/// The transaction has been successfuly added to the pool. | ||
/// If second argument is `Some` the transaction has took place of some other transaction | ||
/// which was already in pool. | ||
/// NOTE: You won't be notified about drop of `old` transaction separately. | ||
fn added(&mut self, _tx: &Arc<T>, _old: Option<&Arc<T>>) {} | ||
|
||
/// The transaction was rejected from the pool. | ||
/// It means that it was too cheap to replace any transaction already in the pool. | ||
fn rejected<H: Debug + LowerHex>(&mut self, _tx: &Arc<T>, _reason: &Error<H>) {} | ||
|
||
/// The transaction was pushed out from the pool because of the limit. | ||
fn dropped(&mut self, _tx: &Arc<T>, _by: Option<&T>) {} | ||
|
||
/// The transaction was marked as invalid by executor. | ||
fn invalid(&mut self, _tx: &Arc<T>) {} | ||
|
||
/// The transaction has been canceled. | ||
fn canceled(&mut self, _tx: &Arc<T>) {} | ||
|
||
/// The transaction has been culled from the pool. | ||
fn culled(&mut self, _tx: &Arc<T>) {} | ||
} | ||
|
||
/// A no-op implementation of `Listener`. | ||
#[derive(Debug)] | ||
pub struct NoopListener; | ||
impl<T> Listener<T> for NoopListener {} | ||
|
||
impl<T, A, B> Listener<T> for (A, B) | ||
where | ||
A: Listener<T>, | ||
B: Listener<T>, | ||
{ | ||
fn added(&mut self, tx: &Arc<T>, old: Option<&Arc<T>>) { | ||
self.0.added(tx, old); | ||
self.1.added(tx, old); | ||
} | ||
|
||
fn rejected<H: Debug + LowerHex>(&mut self, tx: &Arc<T>, reason: &Error<H>) { | ||
self.0.rejected(tx, reason); | ||
self.1.rejected(tx, reason); | ||
} | ||
|
||
fn dropped(&mut self, tx: &Arc<T>, by: Option<&T>) { | ||
self.0.dropped(tx, by); | ||
self.1.dropped(tx, by); | ||
} | ||
|
||
fn invalid(&mut self, tx: &Arc<T>) { | ||
self.0.invalid(tx); | ||
self.1.invalid(tx); | ||
} | ||
|
||
fn canceled(&mut self, tx: &Arc<T>) { | ||
self.0.canceled(tx); | ||
self.1.canceled(tx); | ||
} | ||
|
||
fn culled(&mut self, tx: &Arc<T>) { | ||
self.0.culled(tx); | ||
self.1.culled(tx); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright 2015-2018 Parity Technologies (UK) Ltd. | ||
// This file is part of Parity. | ||
|
||
// Parity 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. | ||
|
||
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
/// Transaction Pool options. | ||
#[derive(Clone, Debug, PartialEq)] | ||
pub struct Options { | ||
/// Maximal number of transactions in the pool. | ||
pub max_count: usize, | ||
/// Maximal number of transactions from single sender. | ||
pub max_per_sender: usize, | ||
/// Maximal memory usage. | ||
pub max_mem_usage: usize, | ||
} | ||
|
||
impl Default for Options { | ||
fn default() -> Self { | ||
Options { | ||
max_count: 1024, | ||
max_per_sender: 16, | ||
max_mem_usage: 8 * 1024 * 1024, | ||
} | ||
} | ||
} |
Oops, something went wrong.