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

Commit 9d4adc5

Browse files
committed
tx-pool: accept local tx with higher gas price when pool full
1 parent 7f707fa commit 9d4adc5

File tree

1 file changed

+62
-5
lines changed

1 file changed

+62
-5
lines changed

miner/src/pool/replace.rs

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,21 +75,36 @@ where
7575
// calculate readiness based on state nonce + pooled txs from same sender
7676
let is_ready = |replace: &ReplaceTransaction<T>| {
7777
let mut nonce = state.account_nonce(replace.sender());
78+
let mut tx_same_nonce = None;
7879
if let Some(txs) = replace.pooled_by_sender {
7980
for tx in txs.iter() {
8081
if nonce == tx.nonce() && *tx.transaction != ***replace.transaction {
81-
nonce = nonce.saturating_add(U256::from(1))
82+
nonce = nonce.saturating_add(U256::from(1));
83+
if tx.nonce() == replace.nonce() {
84+
tx_same_nonce = Some(tx.clone());
85+
}
8286
} else {
8387
break
8488
}
8589
}
8690
}
87-
nonce == replace.nonce()
91+
(nonce == replace.nonce(), tx_same_nonce)
8892
};
8993

90-
if !is_ready(new) && is_ready(old) {
91-
// prevent a ready transaction being replace by a non-ready transaction
92-
Choice::RejectNew
94+
let (new_is_ready, tx_same_nonce) = is_ready(new);
95+
let (old_is_ready, _) = is_ready(old);
96+
97+
if !new_is_ready && old_is_ready {
98+
let new_is_same_nonce_and_better = tx_same_nonce
99+
.map_or(false, |existing_tx| {
100+
new.priority().is_local() && self.scoring.choose(&existing_tx, &new) != Choice::RejectNew
101+
});
102+
if new_is_same_nonce_and_better {
103+
Choice::InsertNew
104+
} else {
105+
// prevent a ready transaction being replace by a non-ready transaction
106+
Choice::RejectNew
107+
}
93108
} else {
94109
Choice::ReplaceOld
95110
}
@@ -412,4 +427,46 @@ mod tests {
412427

413428
assert_eq!(replace.should_replace(&old, &new), ReplaceOld);
414429
}
430+
431+
#[test]
432+
fn should_accept_local_tx_with_same_sender_and_nonce_with_better_gas_price() {
433+
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
434+
let client = TestClient::new().with_nonce(1);
435+
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
436+
437+
// current transaction is ready
438+
let old_tx = {
439+
let tx = Tx {
440+
nonce: 1,
441+
gas_price: 1,
442+
..Default::default()
443+
};
444+
tx.signed().verified()
445+
};
446+
447+
let new_sender = Random.generate().unwrap();
448+
let tx_new_ready_1 = local_tx_verified(Tx {
449+
nonce: 1,
450+
gas_price: 1,
451+
..Default::default()
452+
}, &new_sender);
453+
454+
let tx_new_ready_2 = local_tx_verified(Tx {
455+
nonce: 1,
456+
gas_price: 2, // same nonce, higher gas price
457+
..Default::default()
458+
}, &new_sender);
459+
460+
let old_tx = txpool::Transaction { insertion_id: 0, transaction: Arc::new(old_tx) };
461+
462+
let new_tx = txpool::Transaction { insertion_id: 0, transaction: Arc::new(tx_new_ready_2) };
463+
let pooled_txs = [
464+
txpool::Transaction { insertion_id: 0, transaction: Arc::new(tx_new_ready_1) },
465+
];
466+
467+
let old = ReplaceTransaction::new(&old_tx, None);
468+
let new = ReplaceTransaction::new(&new_tx, Some(&pooled_txs));
469+
470+
assert_eq!(replace.should_replace(&old, &new), InsertNew);
471+
}
415472
}

0 commit comments

Comments
 (0)