extern crate esplora_tapyrus;
#[macro_use]
extern crate log;
fn main() {
use std::collections::HashSet;
use std::sync::Arc;
use esplora_tapyrus::{
chain::Transaction,
config::Config,
daemon::Daemon,
metrics::Metrics,
new_index::{ChainQuery, FetchFrom, Indexer, Store},
signal::Waiter,
util::has_prevout,
};
use tapyrus::blockdata::script::Script;
use tapyrus::consensus::encode::deserialize;
let signal = Waiter::start();
let config = Config::from_args();
let store = Arc::new(Store::open(&config.db_path.join("newindex"), &config));
let metrics = Metrics::new(config.monitoring_addr);
metrics.start();
let daemon = Arc::new(
Daemon::new(
&config.daemon_dir,
&config.blocks_dir,
config.daemon_rpc_addr,
config.cookie_getter(),
config.network,
signal,
&metrics,
)
.unwrap(),
);
let chain = ChainQuery::new(Arc::clone(&store), Arc::clone(&daemon), &config, &metrics);
let mut indexer = Indexer::open(Arc::clone(&store), FetchFrom::Tapyrusd, &config, &metrics);
indexer.update(&daemon).unwrap();
let mut iter = store.txstore_db().raw_iterator();
iter.seek(b"T");
let mut total = 0;
let mut uih_totals = vec![0, 0, 0];
while iter.valid() {
let key = iter.key().unwrap();
let value = iter.value().unwrap();
if !key.starts_with(b"T") {
break;
}
let tx: Transaction = deserialize(&value).expect("failed to parse Transaction");
let txid = tx.malfix_txid();
iter.next();
if tx.output.len() != 2 {
continue;
}
if tx.is_coin_base() {
continue;
}
let blockid = match chain.tx_confirming_block(&txid) {
Some(blockid) => blockid,
None => continue,
};
let prevouts = chain.lookup_txos(
&tx.input
.iter()
.filter(|txin| has_prevout(txin))
.map(|txin| txin.previous_output)
.collect(),
);
let total_out: u64 = tx.output.iter().map(|out| out.value).sum();
let small_out = tx.output.iter().map(|out| out.value).min().unwrap();
let large_out = tx.output.iter().map(|out| out.value).max().unwrap();
let total_in: u64 = prevouts.values().map(|out| out.value).sum();
let smallest_in = prevouts.values().map(|out| out.value).min().unwrap();
let fee = total_in - total_out;
let uih = if total_in - smallest_in > large_out + fee {
2
} else if total_in - smallest_in > small_out + fee {
1
} else {
0
};
let is_multi_spend = {
let mut seen_spks = HashSet::new();
prevouts
.values()
.any(|out| !seen_spks.insert(&out.script_pubkey))
};
let has_reuse = {
let prev_spks: HashSet<Script> = prevouts
.values()
.map(|out| out.script_pubkey.clone())
.collect();
tx.output
.iter()
.any(|out| prev_spks.contains(&out.script_pubkey))
};
println!(
"{},{},{},{},{},{}",
txid, blockid.height, tx.lock_time, uih, is_multi_spend as u8, has_reuse as u8
);
total += 1;
uih_totals[uih] += 1;
}
info!(
"processed {} total txs, UIH counts: {:?}",
total, uih_totals
);
}