store pending transactions only once

This commit is contained in:
Robert Habermeier 2017-02-14 12:12:26 +01:00
parent e911fc2db9
commit 63ad8cb086

View File

@ -63,13 +63,30 @@ impl CurrentNonce {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq)]
struct TransactionInfo {
hash: H256,
nonce: U256,
condition: Option<Condition>,
}
impl<'a> From<&'a PendingTransaction> for TransactionInfo {
fn from(tx: &'a PendingTransaction) -> Self {
TransactionInfo {
hash: tx.hash(),
nonce: tx.nonce.clone(),
condition: tx.condition.clone(),
}
}
}
// transactions associated with a specific account. // transactions associated with a specific account.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
struct AccountTransactions { struct AccountTransactions {
// believed current nonce (gotten from initial given TX or `cull` calls). // believed current nonce (gotten from initial given TX or `cull` calls).
cur_nonce: CurrentNonce, cur_nonce: CurrentNonce,
current: Vec<PendingTransaction>, // ordered "current" transactions (cur_nonce onwards) current: Vec<TransactionInfo>, // ordered "current" transactions (cur_nonce onwards)
future: BTreeMap<U256, PendingTransaction>, // "future" transactions. future: BTreeMap<U256, TransactionInfo>, // "future" transactions.
} }
impl AccountTransactions { impl AccountTransactions {
@ -110,6 +127,7 @@ impl TransactionQueue {
let sender = tx.sender(); let sender = tx.sender();
let hash = tx.hash(); let hash = tx.hash();
let nonce = tx.nonce; let nonce = tx.nonce;
let tx_info = TransactionInfo::from(&tx);
if self.by_hash.contains_key(&hash) { return Err(TransactionError::AlreadyImported) } if self.by_hash.contains_key(&hash) { return Err(TransactionError::AlreadyImported) }
@ -117,7 +135,7 @@ impl TransactionQueue {
Entry::Vacant(entry) => { Entry::Vacant(entry) => {
entry.insert(AccountTransactions { entry.insert(AccountTransactions {
cur_nonce: CurrentNonce::Assumed(nonce), cur_nonce: CurrentNonce::Assumed(nonce),
current: vec![tx.clone()], current: vec![tx_info],
future: BTreeMap::new(), future: BTreeMap::new(),
}); });
@ -140,8 +158,8 @@ impl TransactionQueue {
trace!(target: "txqueue", "Replacing existing transaction from {} with nonce {}", trace!(target: "txqueue", "Replacing existing transaction from {} with nonce {}",
sender, nonce); sender, nonce);
let old = ::std::mem::replace(&mut acct_txs.current[idx], tx.clone()); let old = ::std::mem::replace(&mut acct_txs.current[idx], tx_info);
self.by_hash.remove(&old.hash()); self.by_hash.remove(&old.hash);
TransactionImportResult::Current TransactionImportResult::Current
} }
@ -155,7 +173,7 @@ impl TransactionQueue {
assert!(idx == 0 || idx == cur_len); assert!(idx == 0 || idx == cur_len);
if idx == 0 && acct_txs.current.first().map_or(false, |f| f.nonce != incr_nonce) { if idx == 0 && acct_txs.current.first().map_or(false, |f| f.nonce != incr_nonce) {
let old_cur = ::std::mem::replace(&mut acct_txs.current, vec![tx.clone()]); let old_cur = ::std::mem::replace(&mut acct_txs.current, vec![tx_info]);
trace!(target: "txqueue", "Moving {} transactions with nonce > {} to future", trace!(target: "txqueue", "Moving {} transactions with nonce > {} to future",
old_cur.len(), incr_nonce); old_cur.len(), incr_nonce);
@ -169,14 +187,14 @@ impl TransactionQueue {
} else if idx == cur_len && acct_txs.current.last().map_or(false, |f| f.nonce + 1.into() != nonce) { } else if idx == cur_len && acct_txs.current.last().map_or(false, |f| f.nonce + 1.into() != nonce) {
trace!(target: "txqueue", "Queued future transaction for {}, nonce={}", sender, nonce); trace!(target: "txqueue", "Queued future transaction for {}, nonce={}", sender, nonce);
let future_nonce = nonce; let future_nonce = nonce;
acct_txs.future.insert(future_nonce, tx.clone()); acct_txs.future.insert(future_nonce, tx_info);
TransactionImportResult::Future TransactionImportResult::Future
} else { } else {
trace!(target: "txqueue", "Queued current transaction for {}, nonce={}", sender, nonce); trace!(target: "txqueue", "Queued current transaction for {}, nonce={}", sender, nonce);
// insert, then check if we've filled any gaps. // insert, then check if we've filled any gaps.
acct_txs.current.insert(idx, tx.clone()); acct_txs.current.insert(idx, tx_info);
acct_txs.adjust_future(); acct_txs.adjust_future();
TransactionImportResult::Current TransactionImportResult::Current
@ -206,13 +224,17 @@ impl TransactionQueue {
/// `best_block_number` and `best_block_timestamp` are used to filter out conditionally /// `best_block_number` and `best_block_timestamp` are used to filter out conditionally
/// propagated transactions. /// propagated transactions.
pub fn ready_transactions(&self, best_block_number: u64, best_block_timestamp: u64) -> Vec<PendingTransaction> { pub fn ready_transactions(&self, best_block_number: u64, best_block_timestamp: u64) -> Vec<PendingTransaction> {
self.by_account.values().flat_map(|acct_txs| { self.by_account.values()
.flat_map(|acct_txs| {
acct_txs.current.iter().take_while(|tx| match tx.condition { acct_txs.current.iter().take_while(|tx| match tx.condition {
None => true, None => true,
Some(Condition::Number(blk_num)) => blk_num <= best_block_number, Some(Condition::Number(blk_num)) => blk_num <= best_block_number,
Some(Condition::Timestamp(time)) => time <= best_block_timestamp, Some(Condition::Timestamp(time)) => time <= best_block_timestamp,
}).cloned() }).map(|info| info.hash)
}).collect() })
.filter_map(|hash| self.by_hash.get(&hash))
.cloned()
.collect()
} }
/// Addresses for which we store transactions. /// Addresses for which we store transactions.
@ -234,7 +256,7 @@ impl TransactionQueue {
for old in old_future { for old in old_future {
let hash = acct_txs.future.remove(&old) let hash = acct_txs.future.remove(&old)
.expect("key extracted from keys iterator; known to exist; qed") .expect("key extracted from keys iterator; known to exist; qed")
.hash(); .hash;
removed_hashes.push(hash); removed_hashes.push(hash);
} }
@ -242,9 +264,9 @@ impl TransactionQueue {
let valid_pos = acct_txs.current.iter().position(|tx| tx.nonce >= cur_nonce); let valid_pos = acct_txs.current.iter().position(|tx| tx.nonce >= cur_nonce);
match valid_pos { match valid_pos {
None => None =>
removed_hashes.extend(acct_txs.current.drain(..).map(|tx| tx.hash())), removed_hashes.extend(acct_txs.current.drain(..).map(|tx| tx.hash)),
Some(valid) => Some(valid) =>
removed_hashes.extend(acct_txs.current.drain(..valid).map(|tx| tx.hash())), removed_hashes.extend(acct_txs.current.drain(..valid).map(|tx| tx.hash)),
} }
// now try and move stuff out of future into current. // now try and move stuff out of future into current.