|
|
|
@ -49,7 +49,7 @@
|
|
|
|
|
//! balance: U256::from(1_000_000),
|
|
|
|
|
//! };
|
|
|
|
|
//!
|
|
|
|
|
//! let mut txq = TransactionQueue::new();
|
|
|
|
|
//! let mut txq = TransactionQueue::default();
|
|
|
|
|
//! txq.add(st2.clone(), &default_account_details, TransactionOrigin::External).unwrap();
|
|
|
|
|
//! txq.add(st1.clone(), &default_account_details, TransactionOrigin::External).unwrap();
|
|
|
|
|
//!
|
|
|
|
@ -130,11 +130,20 @@ struct TransactionOrder {
|
|
|
|
|
/// (e.g. Tx(nonce:5), State(nonce:0) -> height: 5)
|
|
|
|
|
/// High nonce_height = Low priority (processed later)
|
|
|
|
|
nonce_height: U256,
|
|
|
|
|
/// Gas specified in the transaction.
|
|
|
|
|
gas: U256,
|
|
|
|
|
/// Gas Price of the transaction.
|
|
|
|
|
/// Low gas price = Low priority (processed later)
|
|
|
|
|
gas_price: U256,
|
|
|
|
|
/// Gas usage priority factor. Usage depends on strategy.
|
|
|
|
|
/// Represents the linear increment in required gas price for heavy transactions.
|
|
|
|
|
///
|
|
|
|
|
/// High gas limit + Low gas price = Low priority
|
|
|
|
|
/// High gas limit + High gas price = High priority
|
|
|
|
|
gas_factor: U256,
|
|
|
|
|
/// Gas (limit) of the transaction. Usage depends on strategy.
|
|
|
|
|
/// Low gas limit = High priority (processed earlier)
|
|
|
|
|
gas: U256,
|
|
|
|
|
/// Transaction ordering strategy
|
|
|
|
|
strategy: PrioritizationStrategy,
|
|
|
|
|
/// Hash to identify associated transaction
|
|
|
|
|
hash: H256,
|
|
|
|
|
/// Origin of the transaction
|
|
|
|
@ -145,11 +154,15 @@ struct TransactionOrder {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl TransactionOrder {
|
|
|
|
|
fn for_transaction(tx: &VerifiedTransaction, base_nonce: U256) -> Self {
|
|
|
|
|
|
|
|
|
|
fn for_transaction(tx: &VerifiedTransaction, base_nonce: U256, min_gas_price: U256, strategy: PrioritizationStrategy) -> Self {
|
|
|
|
|
let factor = (tx.transaction.gas >> 15) * min_gas_price;
|
|
|
|
|
TransactionOrder {
|
|
|
|
|
nonce_height: tx.nonce() - base_nonce,
|
|
|
|
|
gas: tx.transaction.gas.clone(),
|
|
|
|
|
gas_price: tx.transaction.gas_price,
|
|
|
|
|
gas: tx.transaction.gas,
|
|
|
|
|
gas_factor: factor,
|
|
|
|
|
strategy: strategy,
|
|
|
|
|
hash: tx.hash(),
|
|
|
|
|
origin: tx.origin,
|
|
|
|
|
penalties: 0,
|
|
|
|
@ -197,11 +210,28 @@ impl Ord for TransactionOrder {
|
|
|
|
|
return self.origin.cmp(&b.origin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
match self.strategy {
|
|
|
|
|
PrioritizationStrategy::GasAndGasPrice => {
|
|
|
|
|
if self.gas != b.gas {
|
|
|
|
|
return self.gas.cmp(&b.gas);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
PrioritizationStrategy::GasFactorAndGasPrice => {
|
|
|
|
|
// avoiding overflows
|
|
|
|
|
// (gp1 - g1) > (gp2 - g2) <=>
|
|
|
|
|
// (gp1 + g2) > (gp2 + g1)
|
|
|
|
|
let f_a = self.gas_price + b.gas_factor;
|
|
|
|
|
let f_b = b.gas_price + self.gas_factor;
|
|
|
|
|
if f_a != f_b {
|
|
|
|
|
return f_b.cmp(&f_a);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
PrioritizationStrategy::GasPriceOnly => {},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Then compare gas_prices
|
|
|
|
|
let a_gas = self.gas_price;
|
|
|
|
|
let b_gas = b.gas_price;
|
|
|
|
|
if a_gas != b_gas {
|
|
|
|
|
return b_gas.cmp(&a_gas);
|
|
|
|
|
if self.gas_price != b.gas_price {
|
|
|
|
|
return b.gas_price.cmp(&self.gas_price);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compare hashes
|
|
|
|
@ -415,8 +445,32 @@ pub struct AccountDetails {
|
|
|
|
|
/// Transactions with `gas > (gas_limit + gas_limit * Factor(in percents))` are not imported to the queue.
|
|
|
|
|
const GAS_LIMIT_HYSTERESIS: usize = 10; // (100/GAS_LIMIT_HYSTERESIS) %
|
|
|
|
|
|
|
|
|
|
/// Describes the strategy used to prioritize transactions in the queue.
|
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
|
|
|
pub enum PrioritizationStrategy {
|
|
|
|
|
/// Use only gas price. Disregards the actual computation cost of the transaction.
|
|
|
|
|
/// i.e. Higher gas price = Higher priority
|
|
|
|
|
GasPriceOnly,
|
|
|
|
|
/// Use gas limit and then gas price.
|
|
|
|
|
/// i.e. Higher gas limit = Lower priority
|
|
|
|
|
GasAndGasPrice,
|
|
|
|
|
/// Calculate and use priority based on gas and gas price.
|
|
|
|
|
/// PRIORITY = GAS_PRICE - GAS/2^15 * MIN_GAS_PRICE
|
|
|
|
|
///
|
|
|
|
|
/// Rationale:
|
|
|
|
|
/// Heavy transactions are paying linear cost (GAS * GAS_PRICE)
|
|
|
|
|
/// while the computation might be more expensive.
|
|
|
|
|
///
|
|
|
|
|
/// i.e.
|
|
|
|
|
/// 1M gas tx with `gas_price=30*min` has the same priority
|
|
|
|
|
/// as 32k gas tx with `gas_price=min`
|
|
|
|
|
GasFactorAndGasPrice,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// `TransactionQueue` implementation
|
|
|
|
|
pub struct TransactionQueue {
|
|
|
|
|
/// Prioritization strategy for this queue
|
|
|
|
|
strategy: PrioritizationStrategy,
|
|
|
|
|
/// Gas Price threshold for transactions that can be imported to this queue (defaults to 0)
|
|
|
|
|
minimal_gas_price: U256,
|
|
|
|
|
/// The maximum amount of gas any individual transaction may use.
|
|
|
|
@ -435,18 +489,18 @@ pub struct TransactionQueue {
|
|
|
|
|
|
|
|
|
|
impl Default for TransactionQueue {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
TransactionQueue::new()
|
|
|
|
|
TransactionQueue::new(PrioritizationStrategy::GasPriceOnly)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TransactionQueue {
|
|
|
|
|
/// Creates new instance of this Queue
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
Self::with_limits(1024, !U256::zero(), !U256::zero())
|
|
|
|
|
pub fn new(strategy: PrioritizationStrategy) -> Self {
|
|
|
|
|
Self::with_limits(strategy, 1024, !U256::zero(), !U256::zero())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Create new instance of this Queue with specified limits
|
|
|
|
|
pub fn with_limits(limit: usize, gas_limit: U256, tx_gas_limit: U256) -> Self {
|
|
|
|
|
pub fn with_limits(strategy: PrioritizationStrategy, limit: usize, gas_limit: U256, tx_gas_limit: U256) -> Self {
|
|
|
|
|
let current = TransactionSet {
|
|
|
|
|
by_priority: BTreeSet::new(),
|
|
|
|
|
by_address: Table::new(),
|
|
|
|
@ -464,6 +518,7 @@ impl TransactionQueue {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TransactionQueue {
|
|
|
|
|
strategy: strategy,
|
|
|
|
|
minimal_gas_price: U256::zero(),
|
|
|
|
|
tx_gas_limit: tx_gas_limit,
|
|
|
|
|
gas_limit: !U256::zero(),
|
|
|
|
@ -844,6 +899,7 @@ impl TransactionQueue {
|
|
|
|
|
return Err(TransactionError::AlreadyImported);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let min_gas_price = (self.minimal_gas_price, self.strategy);
|
|
|
|
|
let address = tx.sender();
|
|
|
|
|
let nonce = tx.nonce();
|
|
|
|
|
let hash = tx.hash();
|
|
|
|
@ -881,7 +937,7 @@ impl TransactionQueue {
|
|
|
|
|
if nonce > next_nonce {
|
|
|
|
|
// We have a gap - put to future.
|
|
|
|
|
// Insert transaction (or replace old one with lower gas price)
|
|
|
|
|
try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, &mut self.future, &mut self.by_hash)));
|
|
|
|
|
try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, min_gas_price, &mut self.future, &mut self.by_hash)));
|
|
|
|
|
// Enforce limit in Future
|
|
|
|
|
let removed = self.future.enforce_limit(&mut self.by_hash);
|
|
|
|
|
// Return an error if this transaction was not imported because of limit.
|
|
|
|
@ -897,7 +953,7 @@ impl TransactionQueue {
|
|
|
|
|
self.move_matching_future_to_current(address, nonce + U256::one(), state_nonce);
|
|
|
|
|
|
|
|
|
|
// Replace transaction if any
|
|
|
|
|
try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, &mut self.current, &mut self.by_hash)));
|
|
|
|
|
try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, min_gas_price, &mut self.current, &mut self.by_hash)));
|
|
|
|
|
// Keep track of highest nonce stored in current
|
|
|
|
|
let new_max = self.last_nonces.get(&address).map_or(nonce, |n| cmp::max(nonce, *n));
|
|
|
|
|
self.last_nonces.insert(address, new_max);
|
|
|
|
@ -934,8 +990,8 @@ impl TransactionQueue {
|
|
|
|
|
///
|
|
|
|
|
/// Returns `true` if transaction actually got to the queue (`false` if there was already a transaction with higher
|
|
|
|
|
/// gas_price)
|
|
|
|
|
fn replace_transaction(tx: VerifiedTransaction, base_nonce: U256, set: &mut TransactionSet, by_hash: &mut HashMap<H256, VerifiedTransaction>) -> bool {
|
|
|
|
|
let order = TransactionOrder::for_transaction(&tx, base_nonce);
|
|
|
|
|
fn replace_transaction(tx: VerifiedTransaction, base_nonce: U256, min_gas_price: (U256, PrioritizationStrategy), set: &mut TransactionSet, by_hash: &mut HashMap<H256, VerifiedTransaction>) -> bool {
|
|
|
|
|
let order = TransactionOrder::for_transaction(&tx, base_nonce, min_gas_price.0, min_gas_price.1);
|
|
|
|
|
let hash = tx.hash();
|
|
|
|
|
let address = tx.sender();
|
|
|
|
|
let nonce = tx.nonce();
|
|
|
|
@ -1015,12 +1071,12 @@ mod test {
|
|
|
|
|
fn default_gas_val() -> U256 { 100_000.into() }
|
|
|
|
|
fn default_gas_price() -> U256 { 1.into() }
|
|
|
|
|
|
|
|
|
|
fn new_unsigned_tx(nonce: U256, gas_price: U256) -> Transaction {
|
|
|
|
|
fn new_unsigned_tx(nonce: U256, gas: U256, gas_price: U256) -> Transaction {
|
|
|
|
|
Transaction {
|
|
|
|
|
action: Action::Create,
|
|
|
|
|
value: U256::from(100),
|
|
|
|
|
data: "3331600055".from_hex().unwrap(),
|
|
|
|
|
gas: default_gas_val(),
|
|
|
|
|
gas: gas,
|
|
|
|
|
gas_price: gas_price,
|
|
|
|
|
nonce: nonce
|
|
|
|
|
}
|
|
|
|
@ -1028,7 +1084,12 @@ mod test {
|
|
|
|
|
|
|
|
|
|
fn new_tx(nonce: U256, gas_price: U256) -> SignedTransaction {
|
|
|
|
|
let keypair = Random.generate().unwrap();
|
|
|
|
|
new_unsigned_tx(nonce, gas_price).sign(keypair.secret())
|
|
|
|
|
new_unsigned_tx(nonce, default_gas_val(), gas_price).sign(keypair.secret())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn new_tx_with_gas(gas: U256, gas_price: U256) -> SignedTransaction {
|
|
|
|
|
let keypair = Random.generate().unwrap();
|
|
|
|
|
new_unsigned_tx(default_nonce(), gas, gas_price).sign(keypair.secret())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn new_tx_default() -> SignedTransaction {
|
|
|
|
@ -1043,8 +1104,8 @@ mod test {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn new_tx_pair(nonce: U256, gas_price: U256, nonce_increment: U256, gas_price_increment: U256) -> (SignedTransaction, SignedTransaction) {
|
|
|
|
|
let tx1 = new_unsigned_tx(nonce, gas_price);
|
|
|
|
|
let tx2 = new_unsigned_tx(nonce + nonce_increment, gas_price + gas_price_increment);
|
|
|
|
|
let tx1 = new_unsigned_tx(nonce, default_gas_val(), gas_price);
|
|
|
|
|
let tx2 = new_unsigned_tx(nonce + nonce_increment, default_gas_val(), gas_price + gas_price_increment);
|
|
|
|
|
|
|
|
|
|
let keypair = Random.generate().unwrap();
|
|
|
|
|
let secret = &keypair.secret();
|
|
|
|
@ -1054,8 +1115,8 @@ mod test {
|
|
|
|
|
/// Returns two consecutive transactions, both with increased gas price
|
|
|
|
|
fn new_tx_pair_with_gas_price_increment(gas_price_increment: U256) -> (SignedTransaction, SignedTransaction) {
|
|
|
|
|
let gas = default_gas_price() + gas_price_increment;
|
|
|
|
|
let tx1 = new_unsigned_tx(default_nonce(), gas);
|
|
|
|
|
let tx2 = new_unsigned_tx(default_nonce() + 1.into(), gas);
|
|
|
|
|
let tx1 = new_unsigned_tx(default_nonce(), default_gas_val(), gas);
|
|
|
|
|
let tx2 = new_unsigned_tx(default_nonce() + 1.into(), default_gas_val(), gas);
|
|
|
|
|
|
|
|
|
|
let keypair = Random.generate().unwrap();
|
|
|
|
|
let secret = &keypair.secret();
|
|
|
|
@ -1082,17 +1143,21 @@ mod test {
|
|
|
|
|
assert_eq!(TransactionOrigin::External.cmp(&TransactionOrigin::RetractedBlock), Ordering::Greater);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn transaction_order(tx: &VerifiedTransaction, nonce: U256) -> TransactionOrder {
|
|
|
|
|
TransactionOrder::for_transaction(tx, nonce, 0.into(), PrioritizationStrategy::GasPriceOnly)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_return_correct_nonces_when_dropped_because_of_limit() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::with_limits(2, !U256::zero(), !U256::zero());
|
|
|
|
|
let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 2, !U256::zero(), !U256::zero());
|
|
|
|
|
let (tx1, tx2) = new_tx_pair(123.into(), 1.into(), 1.into(), 0.into());
|
|
|
|
|
let sender = tx1.sender().unwrap();
|
|
|
|
|
let nonce = tx1.nonce;
|
|
|
|
|
txq.add(tx1.clone(), &default_account_details, TransactionOrigin::External).unwrap();
|
|
|
|
|
txq.add(tx2.clone(), &default_account_details, TransactionOrigin::External).unwrap();
|
|
|
|
|
assert_eq!(txq.status().pending, 2);
|
|
|
|
|
assert_eq!(txq.last_nonce(&sender), Some(nonce + U256::one()));
|
|
|
|
|
assert_eq!(txq.last_nonce(&sender), Some(nonce + 1.into()));
|
|
|
|
|
|
|
|
|
|
// when
|
|
|
|
|
let tx = new_tx(123.into(), 1.into());
|
|
|
|
@ -1138,9 +1203,9 @@ mod test {
|
|
|
|
|
x
|
|
|
|
|
};
|
|
|
|
|
// Insert both transactions
|
|
|
|
|
let order1 = TransactionOrder::for_transaction(&tx1, U256::zero());
|
|
|
|
|
let order1 = transaction_order(&tx1, U256::zero());
|
|
|
|
|
set.insert(tx1.sender(), tx1.nonce(), order1.clone());
|
|
|
|
|
let order2 = TransactionOrder::for_transaction(&tx2, U256::zero());
|
|
|
|
|
let order2 = transaction_order(&tx2, U256::zero());
|
|
|
|
|
set.insert(tx2.sender(), tx2.nonce(), order2.clone());
|
|
|
|
|
assert_eq!(set.by_priority.len(), 2);
|
|
|
|
|
assert_eq!(set.by_address.len(), 2);
|
|
|
|
@ -1181,7 +1246,7 @@ mod test {
|
|
|
|
|
x
|
|
|
|
|
};
|
|
|
|
|
// Insert both transactions
|
|
|
|
|
let order1 = TransactionOrder::for_transaction(&tx1, U256::zero());
|
|
|
|
|
let order1 = transaction_order(&tx1, U256::zero());
|
|
|
|
|
set.insert(tx1.sender(), tx1.nonce(), order1.clone());
|
|
|
|
|
assert_eq!(set.by_priority.len(), 1);
|
|
|
|
|
assert_eq!(set.by_address.len(), 1);
|
|
|
|
@ -1189,7 +1254,7 @@ mod test {
|
|
|
|
|
assert_eq!(*set.by_gas_price.iter().next().unwrap().0, 1.into());
|
|
|
|
|
assert_eq!(set.by_gas_price.iter().next().unwrap().1.len(), 1);
|
|
|
|
|
// Two different orders (imagine nonce changed in the meantime)
|
|
|
|
|
let order2 = TransactionOrder::for_transaction(&tx2, U256::one());
|
|
|
|
|
let order2 = transaction_order(&tx2, U256::one());
|
|
|
|
|
set.insert(tx2.sender(), tx2.nonce(), order2.clone());
|
|
|
|
|
assert_eq!(set.by_priority.len(), 1);
|
|
|
|
|
assert_eq!(set.by_address.len(), 1);
|
|
|
|
@ -1218,10 +1283,10 @@ mod test {
|
|
|
|
|
};
|
|
|
|
|
let tx = new_tx_default();
|
|
|
|
|
let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External).unwrap();
|
|
|
|
|
let order1 = TransactionOrder::for_transaction(&tx1, U256::zero());
|
|
|
|
|
let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly);
|
|
|
|
|
assert!(set.insert(tx1.sender(), tx1.nonce(), order1).is_none());
|
|
|
|
|
let tx2 = VerifiedTransaction::new(tx, TransactionOrigin::External).unwrap();
|
|
|
|
|
let order2 = TransactionOrder::for_transaction(&tx2, U256::zero());
|
|
|
|
|
let order2 = TransactionOrder::for_transaction(&tx2, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly);
|
|
|
|
|
assert!(set.insert(tx2.sender(), tx2.nonce(), order2).is_some());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1238,7 +1303,7 @@ mod test {
|
|
|
|
|
assert_eq!(set.gas_price_entry_limit(), 0.into());
|
|
|
|
|
let tx = new_tx_default();
|
|
|
|
|
let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External).unwrap();
|
|
|
|
|
let order1 = TransactionOrder::for_transaction(&tx1, U256::zero());
|
|
|
|
|
let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly);
|
|
|
|
|
assert!(set.insert(tx1.sender(), tx1.nonce(), order1.clone()).is_none());
|
|
|
|
|
assert_eq!(set.gas_price_entry_limit(), 2.into());
|
|
|
|
|
}
|
|
|
|
@ -1246,7 +1311,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_handle_same_transaction_imported_twice_with_different_state_nonces() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let (tx, tx2) = new_similar_tx_pair();
|
|
|
|
|
let prev_nonce = |a: &Address| AccountDetails{ nonce: default_account_details(a).nonce - U256::one(), balance:
|
|
|
|
|
!U256::zero() };
|
|
|
|
@ -1271,7 +1336,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_move_all_transactions_from_future() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let (tx, tx2) = new_tx_pair_default(1.into(), 1.into());
|
|
|
|
|
let prev_nonce = |a: &Address| AccountDetails{ nonce: default_account_details(a).nonce - U256::one(), balance:
|
|
|
|
|
!U256::zero() };
|
|
|
|
@ -1297,7 +1362,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_import_tx() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let tx = new_tx_default();
|
|
|
|
|
|
|
|
|
|
// when
|
|
|
|
@ -1309,10 +1374,77 @@ mod test {
|
|
|
|
|
assert_eq!(stats.pending, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_order_by_gas() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new(PrioritizationStrategy::GasAndGasPrice);
|
|
|
|
|
let tx1 = new_tx_with_gas(50000.into(), 40.into());
|
|
|
|
|
let tx2 = new_tx_with_gas(40000.into(), 30.into());
|
|
|
|
|
let tx3 = new_tx_with_gas(30000.into(), 10.into());
|
|
|
|
|
let tx4 = new_tx_with_gas(50000.into(), 20.into());
|
|
|
|
|
txq.set_minimal_gas_price(15.into());
|
|
|
|
|
|
|
|
|
|
// when
|
|
|
|
|
let res1 = txq.add(tx1, &default_account_details, TransactionOrigin::External);
|
|
|
|
|
let res2 = txq.add(tx2, &default_account_details, TransactionOrigin::External);
|
|
|
|
|
let res3 = txq.add(tx3, &default_account_details, TransactionOrigin::External);
|
|
|
|
|
let res4 = txq.add(tx4, &default_account_details, TransactionOrigin::External);
|
|
|
|
|
|
|
|
|
|
// then
|
|
|
|
|
assert_eq!(res1.unwrap(), TransactionImportResult::Current);
|
|
|
|
|
assert_eq!(res2.unwrap(), TransactionImportResult::Current);
|
|
|
|
|
assert_eq!(unwrap_tx_err(res3), TransactionError::InsufficientGasPrice {
|
|
|
|
|
minimal: U256::from(15),
|
|
|
|
|
got: U256::from(10),
|
|
|
|
|
});
|
|
|
|
|
assert_eq!(res4.unwrap(), TransactionImportResult::Current);
|
|
|
|
|
let stats = txq.status();
|
|
|
|
|
assert_eq!(stats.pending, 3);
|
|
|
|
|
assert_eq!(txq.top_transactions()[0].gas, 40000.into());
|
|
|
|
|
assert_eq!(txq.top_transactions()[1].gas, 50000.into());
|
|
|
|
|
assert_eq!(txq.top_transactions()[2].gas, 50000.into());
|
|
|
|
|
assert_eq!(txq.top_transactions()[1].gas_price, 40.into());
|
|
|
|
|
assert_eq!(txq.top_transactions()[2].gas_price, 20.into());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_order_by_gas_factor() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new(PrioritizationStrategy::GasFactorAndGasPrice);
|
|
|
|
|
|
|
|
|
|
let tx1 = new_tx_with_gas(150_000.into(), 40.into());
|
|
|
|
|
let tx2 = new_tx_with_gas(40_000.into(), 16.into());
|
|
|
|
|
let tx3 = new_tx_with_gas(30_000.into(), 15.into());
|
|
|
|
|
let tx4 = new_tx_with_gas(150_000.into(), 62.into());
|
|
|
|
|
txq.set_minimal_gas_price(15.into());
|
|
|
|
|
|
|
|
|
|
// when
|
|
|
|
|
let res1 = txq.add(tx1, &default_account_details, TransactionOrigin::External);
|
|
|
|
|
let res2 = txq.add(tx2, &default_account_details, TransactionOrigin::External);
|
|
|
|
|
let res3 = txq.add(tx3, &default_account_details, TransactionOrigin::External);
|
|
|
|
|
let res4 = txq.add(tx4, &default_account_details, TransactionOrigin::External);
|
|
|
|
|
|
|
|
|
|
// then
|
|
|
|
|
assert_eq!(res1.unwrap(), TransactionImportResult::Current);
|
|
|
|
|
assert_eq!(res2.unwrap(), TransactionImportResult::Current);
|
|
|
|
|
assert_eq!(res3.unwrap(), TransactionImportResult::Current);
|
|
|
|
|
assert_eq!(res4.unwrap(), TransactionImportResult::Current);
|
|
|
|
|
let stats = txq.status();
|
|
|
|
|
assert_eq!(stats.pending, 4);
|
|
|
|
|
assert_eq!(txq.top_transactions()[0].gas, 30_000.into());
|
|
|
|
|
assert_eq!(txq.top_transactions()[1].gas, 150_000.into());
|
|
|
|
|
assert_eq!(txq.top_transactions()[2].gas, 40_000.into());
|
|
|
|
|
assert_eq!(txq.top_transactions()[3].gas, 150_000.into());
|
|
|
|
|
assert_eq!(txq.top_transactions()[0].gas_price, 15.into());
|
|
|
|
|
assert_eq!(txq.top_transactions()[1].gas_price, 62.into());
|
|
|
|
|
assert_eq!(txq.top_transactions()[2].gas_price, 16.into());
|
|
|
|
|
assert_eq!(txq.top_transactions()[3].gas_price, 40.into());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn gas_limit_should_never_overflow() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
txq.set_gas_limit(U256::zero());
|
|
|
|
|
assert_eq!(txq.gas_limit, U256::zero());
|
|
|
|
|
|
|
|
|
@ -1326,7 +1458,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_not_import_transaction_above_gas_limit() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let tx = new_tx_default();
|
|
|
|
|
let gas = tx.gas;
|
|
|
|
|
let limit = gas / U256::from(2);
|
|
|
|
@ -1349,7 +1481,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_drop_transactions_from_senders_without_balance() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let tx = new_tx_default();
|
|
|
|
|
let account = |a: &Address| AccountDetails {
|
|
|
|
|
nonce: default_account_details(a).nonce,
|
|
|
|
@ -1372,7 +1504,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_not_import_transaction_below_min_gas_price_threshold_if_external() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let tx = new_tx_default();
|
|
|
|
|
txq.set_minimal_gas_price(tx.gas_price + U256::one());
|
|
|
|
|
|
|
|
|
@ -1392,7 +1524,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_import_transaction_below_min_gas_price_threshold_if_local() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let tx = new_tx_default();
|
|
|
|
|
txq.set_minimal_gas_price(tx.gas_price + U256::one());
|
|
|
|
|
|
|
|
|
@ -1411,8 +1543,8 @@ mod test {
|
|
|
|
|
use rlp::{self, RlpStream, Stream};
|
|
|
|
|
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let tx = new_unsigned_tx(123.into(), 1.into());
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let tx = new_unsigned_tx(123.into(), 100.into(), 1.into());
|
|
|
|
|
let stx = {
|
|
|
|
|
let mut s = RlpStream::new_list(9);
|
|
|
|
|
s.append(&tx.nonce);
|
|
|
|
@ -1436,7 +1568,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_import_txs_from_same_sender() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
|
|
|
|
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
|
|
|
|
@ -1454,7 +1586,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_prioritize_local_transactions_within_same_nonce_height() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let tx = new_tx_default();
|
|
|
|
|
// the second one has same nonce but higher `gas_price`
|
|
|
|
|
let (_, tx2) = new_similar_tx_pair();
|
|
|
|
@ -1475,7 +1607,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_prioritize_reimported_transactions_within_same_nonce_height() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let tx = new_tx_default();
|
|
|
|
|
// the second one has same nonce but higher `gas_price`
|
|
|
|
|
let (_, tx2) = new_similar_tx_pair();
|
|
|
|
@ -1496,7 +1628,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_not_prioritize_local_transactions_with_different_nonce_height() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
|
|
|
|
|
// when
|
|
|
|
@ -1514,7 +1646,7 @@ mod test {
|
|
|
|
|
fn should_penalize_transactions_from_sender_in_future() {
|
|
|
|
|
// given
|
|
|
|
|
let prev_nonce = |a: &Address| AccountDetails{ nonce: default_account_details(a).nonce - U256::one(), balance: !U256::zero() };
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
// txa, txb - slightly bigger gas price to have consistent ordering
|
|
|
|
|
let (txa, txb) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
|
|
|
|
@ -1543,7 +1675,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_penalize_transactions_from_sender() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
// txa, txb - slightly bigger gas price to have consistent ordering
|
|
|
|
|
let (txa, txb) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
|
|
|
|
@ -1576,7 +1708,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_return_pending_hashes() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
|
|
|
|
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
|
|
|
|
@ -1594,7 +1726,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_put_transaction_to_futures_if_gap_detected() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
|
|
|
|
|
let (tx, tx2) = new_tx_pair_default(2.into(), 0.into());
|
|
|
|
|
|
|
|
|
@ -1620,7 +1752,7 @@ mod test {
|
|
|
|
|
!U256::zero() };
|
|
|
|
|
let next2_nonce = default_nonce() + U256::from(3);
|
|
|
|
|
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
|
|
|
|
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
txq.add(tx.clone(), &prev_nonce, TransactionOrigin::External).unwrap();
|
|
|
|
@ -1639,12 +1771,12 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_move_transactions_if_gap_filled() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let kp = Random.generate().unwrap();
|
|
|
|
|
let secret = kp.secret();
|
|
|
|
|
let tx = new_unsigned_tx(123.into(), 1.into()).sign(secret);
|
|
|
|
|
let tx1 = new_unsigned_tx(124.into(), 1.into()).sign(secret);
|
|
|
|
|
let tx2 = new_unsigned_tx(125.into(), 1.into()).sign(secret);
|
|
|
|
|
let tx = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(secret);
|
|
|
|
|
let tx1 = new_unsigned_tx(124.into(), default_gas_val(), 1.into()).sign(secret);
|
|
|
|
|
let tx2 = new_unsigned_tx(125.into(), default_gas_val(), 1.into()).sign(secret);
|
|
|
|
|
|
|
|
|
|
txq.add(tx, &default_account_details, TransactionOrigin::External).unwrap();
|
|
|
|
|
assert_eq!(txq.status().pending, 1);
|
|
|
|
@ -1666,7 +1798,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_remove_transaction() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq2 = TransactionQueue::new();
|
|
|
|
|
let mut txq2 = TransactionQueue::default();
|
|
|
|
|
let (tx, tx2) = new_tx_pair_default(3.into(), 0.into());
|
|
|
|
|
txq2.add(tx.clone(), &default_account_details, TransactionOrigin::External).unwrap();
|
|
|
|
|
txq2.add(tx2.clone(), &default_account_details, TransactionOrigin::External).unwrap();
|
|
|
|
@ -1687,7 +1819,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_move_transactions_to_future_if_gap_introduced() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
let tx3 = new_tx_default();
|
|
|
|
|
txq.add(tx2.clone(), &default_account_details, TransactionOrigin::External).unwrap();
|
|
|
|
@ -1708,7 +1840,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_clear_queue() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
|
|
|
|
|
// add
|
|
|
|
@ -1728,7 +1860,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_drop_old_transactions_when_hitting_the_limit() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::with_limits(1, !U256::zero(), !U256::zero());
|
|
|
|
|
let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 1, !U256::zero(), !U256::zero());
|
|
|
|
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
let sender = tx.sender().unwrap();
|
|
|
|
|
let nonce = tx.nonce;
|
|
|
|
@ -1749,7 +1881,7 @@ mod test {
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_limit_future_transactions() {
|
|
|
|
|
let mut txq = TransactionQueue::with_limits(1, !U256::zero(), !U256::zero());
|
|
|
|
|
let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 1, !U256::zero(), !U256::zero());
|
|
|
|
|
txq.current.set_limit(10);
|
|
|
|
|
let (tx1, tx2) = new_tx_pair_default(4.into(), 1.into());
|
|
|
|
|
let (tx3, tx4) = new_tx_pair_default(4.into(), 2.into());
|
|
|
|
@ -1768,19 +1900,20 @@ mod test {
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_limit_by_gas() {
|
|
|
|
|
let mut txq = TransactionQueue::with_limits(100, default_gas_val() * U256::from(2), !U256::zero());
|
|
|
|
|
let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 100, default_gas_val() * U256::from(2), !U256::zero());
|
|
|
|
|
let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1));
|
|
|
|
|
let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2));
|
|
|
|
|
txq.add(tx1.clone(), &default_account_details, TransactionOrigin::External).ok();
|
|
|
|
|
txq.add(tx2.clone(), &default_account_details, TransactionOrigin::External).ok();
|
|
|
|
|
txq.add(tx3.clone(), &default_account_details, TransactionOrigin::External).ok();
|
|
|
|
|
txq.add(tx4.clone(), &default_account_details, TransactionOrigin::External).ok();
|
|
|
|
|
txq.add(tx1.clone(), &default_account_details, TransactionOrigin::External).unwrap();
|
|
|
|
|
txq.add(tx2.clone(), &default_account_details, TransactionOrigin::External).unwrap();
|
|
|
|
|
txq.add(tx3.clone(), &default_account_details, TransactionOrigin::External).unwrap();
|
|
|
|
|
// limited by gas
|
|
|
|
|
txq.add(tx4.clone(), &default_account_details, TransactionOrigin::External).unwrap_err();
|
|
|
|
|
assert_eq!(txq.status().pending, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_keep_own_transactions_above_gas_limit() {
|
|
|
|
|
let mut txq = TransactionQueue::with_limits(100, default_gas_val() * U256::from(2), !U256::zero());
|
|
|
|
|
let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 100, default_gas_val() * U256::from(2), !U256::zero());
|
|
|
|
|
let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1));
|
|
|
|
|
let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2));
|
|
|
|
|
let (tx5, tx6) = new_tx_pair_default(U256::from(1), U256::from(2));
|
|
|
|
@ -1796,10 +1929,10 @@ mod test {
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_drop_transactions_with_old_nonces() {
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let tx = new_tx_default();
|
|
|
|
|
let last_nonce = tx.nonce + U256::one();
|
|
|
|
|
let fetch_last_nonce = |_a: &Address| AccountDetails{ nonce: last_nonce, balance: !U256::zero() };
|
|
|
|
|
let fetch_last_nonce = |_a: &Address| AccountDetails { nonce: last_nonce, balance: !U256::zero() };
|
|
|
|
|
|
|
|
|
|
// when
|
|
|
|
|
let res = txq.add(tx, &fetch_last_nonce, TransactionOrigin::External);
|
|
|
|
@ -1816,7 +1949,7 @@ mod test {
|
|
|
|
|
// given
|
|
|
|
|
let nonce = |a: &Address| AccountDetails { nonce: default_account_details(a).nonce + U256::one(),
|
|
|
|
|
balance: !U256::zero() };
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let (_tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
txq.add(tx2.clone(), &default_account_details, TransactionOrigin::External).unwrap();
|
|
|
|
|
assert_eq!(txq.status().future, 1);
|
|
|
|
@ -1835,7 +1968,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_accept_same_transaction_twice_if_removed() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
txq.add(tx1.clone(), &default_account_details, TransactionOrigin::External).unwrap();
|
|
|
|
|
txq.add(tx2.clone(), &default_account_details, TransactionOrigin::External).unwrap();
|
|
|
|
@ -1856,7 +1989,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_not_move_to_future_if_state_nonce_is_higher() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
let tx3 = new_tx_default();
|
|
|
|
|
txq.add(tx2.clone(), &default_account_details, TransactionOrigin::External).unwrap();
|
|
|
|
@ -1879,9 +2012,9 @@ mod test {
|
|
|
|
|
fn should_replace_same_transaction_when_has_higher_fee() {
|
|
|
|
|
init_log();
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let keypair = Random.generate().unwrap();
|
|
|
|
|
let tx = new_unsigned_tx(123.into(), 1.into()).sign(keypair.secret());
|
|
|
|
|
let tx = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(keypair.secret());
|
|
|
|
|
let tx2 = {
|
|
|
|
|
let mut tx2 = (*tx).clone();
|
|
|
|
|
tx2.gas_price = U256::from(200);
|
|
|
|
@ -1902,9 +2035,9 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_replace_same_transaction_when_importing_to_futures() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let keypair = Random.generate().unwrap();
|
|
|
|
|
let tx0 = new_unsigned_tx(123.into(), 1.into()).sign(keypair.secret());
|
|
|
|
|
let tx0 = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(keypair.secret());
|
|
|
|
|
let tx1 = {
|
|
|
|
|
let mut tx1 = (*tx0).clone();
|
|
|
|
|
tx1.nonce = U256::from(124);
|
|
|
|
@ -1936,7 +2069,7 @@ mod test {
|
|
|
|
|
!U256::zero() };
|
|
|
|
|
let next_nonce = |a: &Address| AccountDetails{ nonce: default_account_details(a).nonce + U256::one(), balance:
|
|
|
|
|
!U256::zero() };
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
txq.add(tx1.clone(), &previous_nonce, TransactionOrigin::External).unwrap();
|
|
|
|
|
txq.add(tx2, &previous_nonce, TransactionOrigin::External).unwrap();
|
|
|
|
@ -1954,7 +2087,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_return_none_when_transaction_from_given_address_does_not_exist() {
|
|
|
|
|
// given
|
|
|
|
|
let txq = TransactionQueue::new();
|
|
|
|
|
let txq = TransactionQueue::default();
|
|
|
|
|
|
|
|
|
|
// then
|
|
|
|
|
assert_eq!(txq.last_nonce(&Address::default()), None);
|
|
|
|
@ -1963,7 +2096,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_return_correct_nonce_when_transactions_from_given_address_exist() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let tx = new_tx_default();
|
|
|
|
|
let from = tx.sender().unwrap();
|
|
|
|
|
let nonce = tx.nonce;
|
|
|
|
@ -1979,7 +2112,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_remove_old_transaction_even_if_newer_transaction_was_not_known() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
let (nonce1, nonce2) = (tx1.nonce, tx2.nonce);
|
|
|
|
|
let details1 = |_a: &Address| AccountDetails { nonce: nonce1, balance: !U256::zero() };
|
|
|
|
@ -1997,7 +2130,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_return_valid_last_nonce_after_remove_all() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let (tx1, tx2) = new_tx_pair_default(4.into(), 0.into());
|
|
|
|
|
let sender = tx1.sender().unwrap();
|
|
|
|
|
let (nonce1, nonce2) = (tx1.nonce, tx2.nonce);
|
|
|
|
@ -2021,7 +2154,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_return_true_if_there_is_local_transaction_pending() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
assert_eq!(txq.has_local_pending_transactions(), false);
|
|
|
|
|
|
|
|
|
@ -2037,7 +2170,7 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_keep_right_order_in_future() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::with_limits(1, !U256::zero(), !U256::zero());
|
|
|
|
|
let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 1, !U256::zero(), !U256::zero());
|
|
|
|
|
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
|
|
|
|
|
let prev_nonce = |a: &Address| AccountDetails { nonce: default_account_details(a).nonce - U256::one(), balance:
|
|
|
|
|
default_account_details(a).balance };
|
|
|
|
@ -2054,15 +2187,16 @@ mod test {
|
|
|
|
|
#[test]
|
|
|
|
|
fn should_return_correct_last_nonce() {
|
|
|
|
|
// given
|
|
|
|
|
let mut txq = TransactionQueue::new();
|
|
|
|
|
let mut txq = TransactionQueue::default();
|
|
|
|
|
let (tx1, tx2, tx2_2, tx3) = {
|
|
|
|
|
let keypair = Random.generate().unwrap();
|
|
|
|
|
let secret = &keypair.secret();
|
|
|
|
|
let nonce = 123.into();
|
|
|
|
|
let tx = new_unsigned_tx(nonce, 1.into());
|
|
|
|
|
let tx2 = new_unsigned_tx(nonce + 1.into(), 1.into());
|
|
|
|
|
let tx2_2 = new_unsigned_tx(nonce + 1.into(), 5.into());
|
|
|
|
|
let tx3 = new_unsigned_tx(nonce + 2.into(), 1.into());
|
|
|
|
|
let gas = default_gas_val();
|
|
|
|
|
let tx = new_unsigned_tx(nonce, gas, 1.into());
|
|
|
|
|
let tx2 = new_unsigned_tx(nonce + 1.into(), gas, 1.into());
|
|
|
|
|
let tx2_2 = new_unsigned_tx(nonce + 1.into(), gas, 5.into());
|
|
|
|
|
let tx3 = new_unsigned_tx(nonce + 2.into(), gas, 1.into());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(tx.sign(secret), tx2.sign(secret), tx2_2.sign(secret), tx3.sign(secret))
|
|
|
|
|