Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
Minimal effective gas price.
Browse files Browse the repository at this point in the history
  • Loading branch information
tomusdrw committed Jun 11, 2018
1 parent 1318f53 commit 7f4d825
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 19 deletions.
3 changes: 2 additions & 1 deletion miner/src/pool/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ impl TransactionQueue {
let _timer = ::trace_time::PerfTimer::new("pool::verify_and_import");
let options = self.options.read().clone();

let verifier = verifier::Verifier::new(client, options, self.insertion_id.clone());
let min_effective_gas_price = self.pool.read().minimal_entry_score().map(scoring::bump_gas_price);
let verifier = verifier::Verifier::new(client, options, self.insertion_id.clone(), min_effective_gas_price);
let results = transactions
.into_par_iter()
.map(|transaction| verifier.verify_transaction(transaction))
Expand Down
8 changes: 7 additions & 1 deletion miner/src/pool/scoring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ use super::{PrioritizationStrategy, VerifiedTransaction};
/// `new_gas_price > old_gas_price + old_gas_price >> SHIFT`
const GAS_PRICE_BUMP_SHIFT: usize = 3; // 2 = 25%, 3 = 12.5%, 4 = 6.25%

/// Calculate minimal gas price requirement.
#[inline]
pub fn bump_gas_price(old_gp: U256) -> U256 {
old_gp.saturating_add(old_gp >> GAS_PRICE_BUMP_SHIFT)
}

/// Simple, gas-price based scoring for transactions.
///
/// NOTE: Currently penalization does not apply to new transactions that enter the pool.
Expand All @@ -60,7 +66,7 @@ impl txpool::Scoring<VerifiedTransaction> for NonceAndGasPrice {
let old_gp = old.transaction.gas_price;
let new_gp = new.transaction.gas_price;

let min_required_gp = old_gp + (old_gp >> GAS_PRICE_BUMP_SHIFT);
let min_required_gp = bump_gas_price(old_gp);

match min_required_gp.cmp(&new_gp) {
cmp::Ordering::Greater => txpool::scoring::Choice::RejectNew,
Expand Down
7 changes: 7 additions & 0 deletions miner/src/pool/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -796,3 +796,10 @@ fn should_include_local_transaction_to_a_full_pool() {
// then
assert_eq!(txq.status().status.transaction_count, 1);
}


#[test]
fn should_reject_early_in_case_gas_price_is_less_than_min_effective() {
// TODO [ToDr]
assert_eq!(true, false);
}
59 changes: 42 additions & 17 deletions miner/src/pool/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,22 @@ impl Transaction {
pub struct Verifier<C> {
client: C,
options: Options,
min_effective_gas_price: Option<U256>,
id: Arc<AtomicUsize>,
}

impl<C> Verifier<C> {
/// Creates new transaction verfier with specified options.
pub fn new(client: C, options: Options, id: Arc<AtomicUsize>) -> Self {
pub fn new(
client: C,
options: Options,
id: Arc<AtomicUsize>,
min_effective_gas_price: Option<U256>,
) -> Self {
Verifier {
client,
options,
min_effective_gas_price,
id,
}
}
Expand Down Expand Up @@ -190,22 +197,40 @@ impl<C: Client> txpool::Verifier<Transaction> for Verifier<C> {
}

let is_own = tx.is_local();
// Quick exit for non-service transactions
if tx.gas_price() < &self.options.minimal_gas_price
&& !tx.gas_price().is_zero()
&& !is_own
{
trace!(
target: "txqueue",
"[{:?}] Rejected tx below minimal gas price threshold: {} < {}",
hash,
tx.gas_price(),
self.options.minimal_gas_price,
);
bail!(transaction::Error::InsufficientGasPrice {
minimal: self.options.minimal_gas_price,
got: *tx.gas_price(),
});
// Quick exit for non-service and non-local transactions
//
// We're checking if the transaction is below configured minimal gas price
// or the effective minimal gas price in case the pool is full.
if !tx.gas_price().is_zero() && !is_own {
if tx.gas_price() < &self.options.minimal_gas_price {
trace!(
target: "txqueue",
"[{:?}] Rejected tx below minimal gas price threshold: {} < {}",
hash,
tx.gas_price(),
self.options.minimal_gas_price,
);
bail!(transaction::Error::InsufficientGasPrice {
minimal: self.options.minimal_gas_price,
got: *tx.gas_price(),
});
}

if let Some(ref gp) = self.min_effective_gas_price {
if tx.gas_price() < gp {
trace!(
target: "txqueue",
"[{:?}] Rejected tx below minimal effective gas price threshold: {} < {}",
hash,
tx.gas_price(),
gp,
);
bail!(transaction::Error::InsufficientGasPrice {
minimal: *gp,
got: *tx.gas_price(),
});
}
}
}

// Some more heavy checks below.
Expand Down
20 changes: 20 additions & 0 deletions transaction-pool/src/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,26 @@ impl<T, S, L> Pool<T, S, L> where
self.worst_transactions.iter().next().map(|x| x.transaction.transaction.clone())
}

/// Returns the score of the worst transaction if the pool is almost full.
///
/// This method can be used to determine what is the minimal required score
/// for the replacement transaction. If `None` is returned it means that
/// there is still plenty of room in the pool. Otherwise we return
/// `Some` with the score of the worst transaction.
pub fn minimal_entry_score(&self) -> Option<S::Score> {
let threshold = |x: usize| x * 9 / 10;
let is_full = {
self.by_hash.len() > threshold(self.options.max_count)
|| self.mem_usage > threshold(self.options.max_mem_usage)
};

if !is_full {
return None
}

self.worst_transactions.iter().next().map(|x| x.score.clone())
}

/// Returns an iterator of pending (ready) transactions.
pub fn pending<R: Ready<T>>(&self, ready: R) -> PendingIterator<T, R, S, L> {
PendingIterator {
Expand Down

0 comments on commit 7f4d825

Please sign in to comment.