Pending transactions subscription (#7906)
* Pending transactions subscription. * Pending transactions Pub-Sub * Add light client support. * Remove redundant Ok
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
//! accounts for which they create transactions, this queue is structured in an
|
||||
//! address-wise manner.
|
||||
|
||||
use std::fmt;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
@@ -99,25 +100,44 @@ impl AccountTransactions {
|
||||
}
|
||||
|
||||
// attempt to move transactions from the future queue into the current queue.
|
||||
fn adjust_future(&mut self) {
|
||||
fn adjust_future(&mut self) -> Vec<H256> {
|
||||
let mut promoted = Vec::new();
|
||||
let mut next_nonce = self.next_nonce();
|
||||
|
||||
loop {
|
||||
match self.future.remove(&next_nonce) {
|
||||
Some(tx) => self.current.push(tx),
|
||||
Some(tx) => {
|
||||
promoted.push(tx.hash);
|
||||
self.current.push(tx)
|
||||
},
|
||||
None => break,
|
||||
}
|
||||
|
||||
next_nonce = next_nonce + 1.into();
|
||||
}
|
||||
|
||||
promoted
|
||||
}
|
||||
}
|
||||
|
||||
type Listener = Box<Fn(&[H256]) + Send + Sync>;
|
||||
|
||||
/// Light transaction queue. See module docs for more details.
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
#[derive(Default)]
|
||||
pub struct TransactionQueue {
|
||||
by_account: HashMap<Address, AccountTransactions>,
|
||||
by_hash: H256FastMap<PendingTransaction>,
|
||||
listeners: Vec<Listener>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for TransactionQueue {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("TransactionQueue")
|
||||
.field("by_account", &self.by_account)
|
||||
.field("by_hash", &self.by_hash)
|
||||
.field("listeners", &self.listeners.len())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl TransactionQueue {
|
||||
@@ -130,7 +150,7 @@ impl TransactionQueue {
|
||||
|
||||
if self.by_hash.contains_key(&hash) { return Err(transaction::Error::AlreadyImported) }
|
||||
|
||||
let res = match self.by_account.entry(sender) {
|
||||
let (res, promoted) = match self.by_account.entry(sender) {
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(AccountTransactions {
|
||||
cur_nonce: CurrentNonce::Assumed(nonce),
|
||||
@@ -138,7 +158,7 @@ impl TransactionQueue {
|
||||
future: BTreeMap::new(),
|
||||
});
|
||||
|
||||
transaction::ImportResult::Current
|
||||
(transaction::ImportResult::Current, vec![hash])
|
||||
}
|
||||
Entry::Occupied(mut entry) => {
|
||||
let acct_txs = entry.get_mut();
|
||||
@@ -160,7 +180,7 @@ impl TransactionQueue {
|
||||
let old = ::std::mem::replace(&mut acct_txs.current[idx], tx_info);
|
||||
self.by_hash.remove(&old.hash);
|
||||
|
||||
transaction::ImportResult::Current
|
||||
(transaction::ImportResult::Current, vec![hash])
|
||||
}
|
||||
Err(idx) => {
|
||||
let cur_len = acct_txs.current.len();
|
||||
@@ -182,21 +202,22 @@ impl TransactionQueue {
|
||||
acct_txs.future.insert(future_nonce, future);
|
||||
}
|
||||
|
||||
transaction::ImportResult::Current
|
||||
(transaction::ImportResult::Current, vec![hash])
|
||||
} 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);
|
||||
let future_nonce = nonce;
|
||||
acct_txs.future.insert(future_nonce, tx_info);
|
||||
|
||||
transaction::ImportResult::Future
|
||||
(transaction::ImportResult::Future, vec![])
|
||||
} else {
|
||||
trace!(target: "txqueue", "Queued current transaction for {}, nonce={}", sender, nonce);
|
||||
|
||||
// insert, then check if we've filled any gaps.
|
||||
acct_txs.current.insert(idx, tx_info);
|
||||
acct_txs.adjust_future();
|
||||
let mut promoted = acct_txs.adjust_future();
|
||||
promoted.insert(0, hash);
|
||||
|
||||
transaction::ImportResult::Current
|
||||
(transaction::ImportResult::Current, promoted)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -204,6 +225,7 @@ impl TransactionQueue {
|
||||
};
|
||||
|
||||
self.by_hash.insert(hash, tx);
|
||||
self.notify(&promoted);
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
@@ -324,6 +346,18 @@ impl TransactionQueue {
|
||||
pub fn get(&self, hash: &H256) -> Option<&PendingTransaction> {
|
||||
self.by_hash.get(&hash)
|
||||
}
|
||||
|
||||
/// Add a transaction queue listener.
|
||||
pub fn add_listener(&mut self, f: Listener) {
|
||||
self.listeners.push(f);
|
||||
}
|
||||
|
||||
/// Notifies all listeners about new pending transaction.
|
||||
fn notify(&self, hashes: &[H256]) {
|
||||
for listener in &self.listeners {
|
||||
listener(hashes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user