1
0
Fork 0
mirror of https://github.com/romanz/electrs.git synced 2025-02-24 06:57:53 +01:00

Refactor mempool tracker to use HashSet difference

This commit is contained in:
Roman Zeyde 2018-05-17 10:29:22 +03:00
parent eea7f7fc1d
commit 5674f4f997
No known key found for this signature in database
GPG key ID: 87CAE5FA46917CBB
3 changed files with 61 additions and 45 deletions

View file

@ -16,10 +16,10 @@ fn main() {
]).unwrap();
let daemon = daemon::Daemon::new("localhost:8332");
let mut tracker = mempool::Tracker::new(&daemon);
let mut tracker = mempool::Tracker::new();
loop {
let t = Instant::now();
tracker.update_from_daemon().unwrap();
tracker.update(&daemon).unwrap();
let dt = t.elapsed();
info!(
"update took {:.3} ms",

View file

@ -38,11 +38,20 @@ pub struct Daemon {
pub struct MempoolEntry {
fee: u64, // in satoshis
vsize: u32, // in virtual bytes (= weight/4)
fee_per_vbyte: f32,
}
impl MempoolEntry {
fn new(fee: u64, vsize: u32) -> MempoolEntry {
MempoolEntry {
fee,
vsize,
fee_per_vbyte: fee as f32 / vsize as f32,
}
}
pub fn fee_per_vbyte(&self) -> f32 {
self.fee as f32 / self.vsize as f32
self.fee_per_vbyte
}
pub fn fee(&self) -> u64 {
@ -201,17 +210,16 @@ impl Daemon {
.chain_err(|| "missing fees section")?
.as_object()
.chain_err(|| "non-object fees")?;
Ok(MempoolEntry {
fee: (fees.get("base")
.chain_err(|| "missing base fee")?
.as_f64()
.chain_err(|| "non-float fee")? * 100_000_000f64) as u64,
vsize: entry
.get("size")
.chain_err(|| "missing size")?
.as_u64()
.chain_err(|| "non-integer size")? as u32,
})
let fee = (fees.get("base")
.chain_err(|| "missing base fee")?
.as_f64()
.chain_err(|| "non-float fee")? * 100_000_000f64) as u64;
let vsize = entry
.get("size")
.chain_err(|| "missing size")?
.as_u64()
.chain_err(|| "non-integer size")? as u32;
Ok(MempoolEntry::new(fee, vsize))
}
pub fn get_all_headers(&self) -> Result<HeaderMap> {

View file

@ -1,7 +1,6 @@
use bitcoin::blockdata::transaction::Transaction;
use bitcoin::util::hash::Sha256dHash;
use daemon::{Daemon, MempoolEntry};
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::iter::FromIterator;
@ -14,16 +13,20 @@ pub struct Stats {
entry: MempoolEntry,
}
pub struct Tracker<'a> {
txids: HashMap<Sha256dHash, Stats>,
daemon: &'a Daemon,
impl Stats {
pub fn new(tx: Transaction, entry: MempoolEntry) -> Stats {
Stats { tx, entry }
}
}
impl<'a> Tracker<'a> {
pub fn new(daemon: &Daemon) -> Tracker {
pub struct Tracker {
stats: HashMap<Sha256dHash, Stats>,
}
impl Tracker {
pub fn new() -> Tracker {
Tracker {
txids: HashMap::new(),
daemon: daemon,
stats: HashMap::new(),
}
}
@ -31,7 +34,7 @@ impl<'a> Tracker<'a> {
/// cumulative virtual size of mempool transaction with fee in the interval [fee_{n-1}, fee_n].
/// Note: fee_0 is implied to be infinity.
pub fn fee_histogram(&self) -> Vec<(f32, u32)> {
let mut entries: Vec<&MempoolEntry> = self.txids.values().map(|stat| &stat.entry).collect();
let mut entries: Vec<&MempoolEntry> = self.stats.values().map(|stat| &stat.entry).collect();
entries.sort_unstable_by(|e1, e2| {
e2.fee_per_vbyte().partial_cmp(&e1.fee_per_vbyte()).unwrap()
});
@ -48,31 +51,36 @@ impl<'a> Tracker<'a> {
histogram
}
pub fn update_from_daemon(&mut self) -> Result<()> {
let new_txids = HashSet::<Sha256dHash>::from_iter(self.daemon
pub fn update(&mut self, daemon: &Daemon) -> Result<()> {
let new_txids = HashSet::<Sha256dHash>::from_iter(daemon
.getmempooltxids()
.chain_err(|| "failed to update mempool from daemon")?);
self.txids.retain(|txid, _| new_txids.contains(txid)); // remove old TXNs
for txid in new_txids {
if let Entry::Vacant(map_entry) = self.txids.entry(txid) {
let tx = match self.daemon.gettransaction(&txid) {
Ok(tx) => tx,
Err(err) => {
warn!("missing tx {}: {}", txid, err);
continue;
}
};
let entry = match self.daemon.getmempoolentry(&txid) {
Ok(entry) => entry,
Err(err) => {
warn!("no mempool entry {}: {}", txid, err);
continue;
}
};
debug!("new tx: {}, {:.3}", txid, entry.fee_per_vbyte(),);
map_entry.insert(Stats { tx, entry });
}
let old_txids = HashSet::from_iter(self.stats.keys().cloned());
let mut to_add = Vec::new();
for &txid in new_txids.difference(&old_txids) {
let tx = match daemon.gettransaction(&txid) {
Ok(tx) => tx,
Err(err) => {
warn!("missing tx {}: {}", txid, err);
continue;
}
};
let entry = match daemon.getmempoolentry(&txid) {
Ok(entry) => entry,
Err(err) => {
warn!("no mempool entry {}: {}", txid, err);
continue;
}
};
debug!("new tx: {}, {:.3}", txid, entry.fee_per_vbyte(),);
to_add.push((txid, Stats::new(tx, entry)));
}
self.stats.extend(to_add);
for txid in old_txids.difference(&new_txids) {
self.stats.remove(txid);
}
assert_eq!(new_txids, HashSet::from_iter(self.stats.keys().cloned()));
Ok(())
}
}