Return actual mempool fee histogram from RPC
Also, add this to the CLI tracker tool and improve logging.
This commit is contained in:
parent
b6d664c580
commit
30f892d76d
|
@ -5,7 +5,7 @@ extern crate log;
|
||||||
|
|
||||||
use indexrs::{daemon, mempool};
|
use indexrs::{daemon, mempool};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::Duration;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
use simplelog::*;
|
use simplelog::*;
|
||||||
|
@ -18,14 +18,23 @@ fn main() {
|
||||||
let daemon = daemon::Daemon::new("localhost:8332");
|
let daemon = daemon::Daemon::new("localhost:8332");
|
||||||
let mut tracker = mempool::Tracker::new();
|
let mut tracker = mempool::Tracker::new();
|
||||||
loop {
|
loop {
|
||||||
let t = Instant::now();
|
|
||||||
tracker.update(&daemon).unwrap();
|
tracker.update(&daemon).unwrap();
|
||||||
let dt = t.elapsed();
|
let h = tracker.fee_histogram();
|
||||||
|
let mut total_vsize = 0;
|
||||||
|
let mut limit = 0;
|
||||||
|
for (fee, vsize) in h {
|
||||||
|
total_vsize += vsize;
|
||||||
|
let new_limit = total_vsize as usize / 1_000_000;
|
||||||
|
if limit != new_limit {
|
||||||
|
limit = new_limit;
|
||||||
info!(
|
info!(
|
||||||
"update took {:.3} ms",
|
"{:.2}MB has fee >= {:.1} sat/vbyte",
|
||||||
(dt.as_secs() as f64 + 1e-9f64 * dt.subsec_nanos() as f64) * 1e3
|
total_vsize as f32 / 1e6,
|
||||||
|
fee
|
||||||
);
|
);
|
||||||
info!("histogram: {:?}", tracker.fee_histogram());
|
}
|
||||||
thread::sleep(Duration::from_secs(1));
|
}
|
||||||
|
info!("{:.2}MB total size", total_vsize as f32 / 1e6);
|
||||||
|
thread::sleep(Duration::from_secs(10));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use bitcoin::blockdata::transaction::Transaction;
|
use bitcoin::blockdata::transaction::Transaction;
|
||||||
use bitcoin::util::hash::Sha256dHash;
|
use bitcoin::util::hash::Sha256dHash;
|
||||||
use daemon::{Daemon, MempoolEntry};
|
use daemon::{Daemon, MempoolEntry};
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
error_chain!{}
|
error_chain!{}
|
||||||
|
|
||||||
|
@ -23,6 +25,16 @@ pub struct Tracker {
|
||||||
stats: HashMap<Sha256dHash, Stats>,
|
stats: HashMap<Sha256dHash, Stats>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait InSeconds {
|
||||||
|
fn in_seconds(&self) -> f64;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InSeconds for Duration {
|
||||||
|
fn in_seconds(&self) -> f64 {
|
||||||
|
self.as_secs() as f64 + (self.subsec_nanos() as f64) * 1e-9f64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Tracker {
|
impl Tracker {
|
||||||
pub fn new() -> Tracker {
|
pub fn new() -> Tracker {
|
||||||
Tracker {
|
Tracker {
|
||||||
|
@ -56,31 +68,36 @@ impl Tracker {
|
||||||
.getmempooltxids()
|
.getmempooltxids()
|
||||||
.chain_err(|| "failed to update mempool from daemon")?);
|
.chain_err(|| "failed to update mempool from daemon")?);
|
||||||
let old_txids = HashSet::from_iter(self.stats.keys().cloned());
|
let old_txids = HashSet::from_iter(self.stats.keys().cloned());
|
||||||
|
let t = Instant::now();
|
||||||
let mut to_add = Vec::new();
|
|
||||||
for &txid in new_txids.difference(&old_txids) {
|
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) {
|
let entry = match daemon.getmempoolentry(&txid) {
|
||||||
Ok(entry) => entry,
|
Ok(entry) => entry,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
// e.g. new block or RBF
|
||||||
warn!("no mempool entry {}: {}", txid, err);
|
warn!("no mempool entry {}: {}", txid, err);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
trace!("new tx: {}, {:.3}", txid, entry.fee_per_vbyte(),);
|
let tx = match daemon.gettransaction(&txid) {
|
||||||
to_add.push((txid, Stats::new(tx, entry)));
|
Ok(tx) => tx,
|
||||||
|
Err(err) => {
|
||||||
|
// e.g. new block or RBF
|
||||||
|
warn!("missing tx {}: {}", txid, err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
trace!("new tx: {}, {:.3}", txid, entry.fee_per_vbyte(),);
|
||||||
|
self.stats.insert(txid, Stats::new(tx, entry));
|
||||||
}
|
}
|
||||||
self.stats.extend(to_add);
|
|
||||||
for txid in old_txids.difference(&new_txids) {
|
for txid in old_txids.difference(&new_txids) {
|
||||||
self.stats.remove(txid);
|
self.stats.remove(txid);
|
||||||
}
|
}
|
||||||
assert_eq!(new_txids, HashSet::from_iter(self.stats.keys().cloned()));
|
let dt = t.elapsed();
|
||||||
|
debug!(
|
||||||
|
"mempool update took {:.1} ms ({} txns)",
|
||||||
|
dt.in_seconds() * 1e3,
|
||||||
|
self.stats.len()
|
||||||
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,4 +216,8 @@ impl<'a> Query<'a> {
|
||||||
.update(self.daemon)
|
.update(self.daemon)
|
||||||
.chain_err(|| "failed to update mempool")
|
.chain_err(|| "failed to update mempool")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_fee_histogram(&self) -> Vec<(f32, u32)> {
|
||||||
|
self.tracker.read().unwrap().fee_histogram()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ impl<'a> Handler<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mempool_get_fee_histogram(&self) -> Result<Value> {
|
fn mempool_get_fee_histogram(&self) -> Result<Value> {
|
||||||
Ok(json!([])) // TODO: consult with actual mempool
|
Ok(json!(self.query.get_fee_histogram()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blockchain_block_get_chunk(&self, params: &[Value]) -> Result<Value> {
|
fn blockchain_block_get_chunk(&self, params: &[Value]) -> Result<Value> {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user