v2.5.8-stable (#11041)

* add more tx tests (#11038)
* Fix parallel transactions race-condition (#10995)
* Add blake2_f precompile (#11017)
* [trace] introduce trace failed to Ext (#11019)
* Edit publish-onchain.sh to use https (#11016)
* Fix deadlock in network-devp2p (#11013)
* EIP 1108: Reduce alt_bn128 precompile gas costs (#11008)
* xDai chain support and nodes list update (#10989)
* EIP 2028: transaction gas lowered from 68 to 16 (#10987)
* EIP-1344 Add CHAINID op-code (#10983)
* manual publish jobs for releases, no changes for nightlies (#10977)
* [blooms-db] Fix benchmarks (#10974)
* Verify transaction against its block during import (#10954)
* Better error message for rpc gas price errors (#10931)
* tx-pool: accept local tx with higher gas price when pool full (#10901)
* Fix fork choice (#10837)
* Cleanup unused vm dependencies (#10787)
* Fix compilation on recent nightlies (#10991)
This commit is contained in:
s3krit
2019-09-12 18:43:53 +02:00
committed by GitHub
parent 6bd7db96fe
commit 45f27cec34
92 changed files with 2482 additions and 538 deletions

View File

@@ -587,7 +587,7 @@ fn convert_error<H: fmt::Debug + fmt::LowerHex>(err: txpool::Error<H>) -> transa
match err {
Error::AlreadyImported(..) => transaction::Error::AlreadyImported,
Error::TooCheapToEnter(..) => transaction::Error::LimitReached,
Error::TooCheapToReplace(..) => transaction::Error::TooCheapToReplace
Error::TooCheapToReplace(..) => transaction::Error::TooCheapToReplace { prev: None, new: None }
}
}

View File

@@ -71,6 +71,20 @@ where
let old_score = (old.priority(), old.gas_price());
let new_score = (new.priority(), new.gas_price());
if new_score > old_score {
// Check if this is a replacement transaction.
//
// With replacement transactions we can safely return `InsertNew` here, because
// we don't need to remove `old` (worst transaction in the pool) since `new` will replace
// some other transaction in the pool so we will never go above limit anyway.
if let Some(txs) = new.pooled_by_sender {
if let Ok(index) = txs.binary_search_by(|old| self.scoring.compare(old, new)) {
return match self.scoring.choose(&txs[index], new) {
Choice::ReplaceOld => Choice::InsertNew,
choice => choice,
}
}
}
let state = &self.client;
// calculate readiness based on state nonce + pooled txs from same sender
let is_ready = |replace: &ReplaceTransaction<T>| {
@@ -412,4 +426,88 @@ mod tests {
assert_eq!(replace.should_replace(&old, &new), ReplaceOld);
}
#[test]
fn should_accept_local_tx_with_same_sender_and_nonce_with_better_gas_price() {
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
let client = TestClient::new().with_nonce(1);
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
// current transaction is ready
let old_tx = {
let tx = Tx {
nonce: 1,
gas_price: 1,
..Default::default()
};
tx.signed().verified()
};
let new_sender = Random.generate().unwrap();
let tx_new_ready_1 = local_tx_verified(Tx {
nonce: 1,
gas_price: 1,
..Default::default()
}, &new_sender);
let tx_new_ready_2 = local_tx_verified(Tx {
nonce: 1,
gas_price: 2, // same nonce, higher gas price
..Default::default()
}, &new_sender);
let old_tx = txpool::Transaction { insertion_id: 0, transaction: Arc::new(old_tx) };
let new_tx = txpool::Transaction { insertion_id: 0, transaction: Arc::new(tx_new_ready_2) };
let pooled_txs = [
txpool::Transaction { insertion_id: 0, transaction: Arc::new(tx_new_ready_1) },
];
let old = ReplaceTransaction::new(&old_tx, None);
let new = ReplaceTransaction::new(&new_tx, Some(&pooled_txs));
assert_eq!(replace.should_replace(&old, &new), InsertNew);
}
#[test]
fn should_reject_local_tx_with_same_sender_and_nonce_with_worse_gas_price() {
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
let client = TestClient::new().with_nonce(1);
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
// current transaction is ready
let old_tx = {
let tx = Tx {
nonce: 1,
gas_price: 1,
..Default::default()
};
tx.signed().verified()
};
let new_sender = Random.generate().unwrap();
let tx_new_ready_1 = local_tx_verified(Tx {
nonce: 1,
gas_price: 2,
..Default::default()
}, &new_sender);
let tx_new_ready_2 = local_tx_verified(Tx {
nonce: 1,
gas_price: 1, // same nonce, lower gas price
..Default::default()
}, &new_sender);
let old_tx = txpool::Transaction { insertion_id: 0, transaction: Arc::new(old_tx) };
let new_tx = txpool::Transaction { insertion_id: 0, transaction: Arc::new(tx_new_ready_2) };
let pooled_txs = [
txpool::Transaction { insertion_id: 0, transaction: Arc::new(tx_new_ready_1) },
];
let old = ReplaceTransaction::new(&old_tx, None);
let new = ReplaceTransaction::new(&new_tx, Some(&pooled_txs));
assert_eq!(replace.should_replace(&old, &new), RejectNew);
}
}

View File

@@ -91,10 +91,10 @@ fn should_return_correct_nonces_when_dropped_because_of_limit() {
// then
assert_eq!(res, vec![Ok(()), Ok(())]);
assert_eq!(res2, vec![
// The error here indicates reaching the limit
// and minimal effective gas price taken into account.
Err(transaction::Error::InsufficientGasPrice { minimal: 2.into(), got: 1.into() }),
Ok(())
// The error here indicates reaching the limit
// and minimal effective gas price taken into account.
Err(transaction::Error::TooCheapToReplace { prev: Some(2.into()), new: Some(1.into()) }),
Ok(())
]);
assert_eq!(txq.status().status.transaction_count, 3);
// tx2 transaction got dropped because of limit
@@ -585,7 +585,7 @@ fn should_not_replace_same_transaction_if_the_fee_is_less_than_minimal_bump() {
let res = txq.import(client.clone(), vec![tx2, tx4].local());
// then
assert_eq!(res, vec![Err(transaction::Error::TooCheapToReplace), Ok(())]);
assert_eq!(res, vec![Err(transaction::Error::TooCheapToReplace { prev: None, new: None }), Ok(())]);
assert_eq!(txq.status().status.transaction_count, 2);
assert_eq!(txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0))[0].signed().gas_price, U256::from(20));
assert_eq!(txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0))[1].signed().gas_price, U256::from(2));
@@ -1027,9 +1027,9 @@ fn should_reject_early_in_case_gas_price_is_less_than_min_effective() {
let client = TestClient::new();
let tx1 = Tx::default().signed().unverified();
let res = txq.import(client.clone(), vec![tx1]);
assert_eq!(res, vec![Err(transaction::Error::InsufficientGasPrice {
minimal: 2.into(),
got: 1.into(),
assert_eq!(res, vec![Err(transaction::Error::TooCheapToReplace {
prev: Some(2.into()),
new: Some(1.into()),
})]);
assert!(!client.was_verification_triggered());

View File

@@ -231,9 +231,9 @@ impl<C: Client> txpool::Verifier<Transaction> for Verifier<C, ::pool::scoring::N
tx.gas_price(),
vtx.transaction.gas_price,
);
bail!(transaction::Error::InsufficientGasPrice {
minimal: vtx.transaction.gas_price,
got: *tx.gas_price(),
return Err(transaction::Error::TooCheapToReplace {
prev: Some(vtx.transaction.gas_price),
new: Some(*tx.gas_price()),
});
}
}