2023-06-23 20:41:39 -04:00
|
|
|
use priority_queue::PriorityQueue;
|
2023-06-24 11:21:58 -07:00
|
|
|
use std::{
|
|
|
|
cmp::Ordering,
|
2023-06-26 21:07:14 -04:00
|
|
|
collections::{HashMap, HashSet},
|
2023-06-24 11:21:58 -07:00
|
|
|
};
|
2023-06-26 19:29:32 -07:00
|
|
|
use tracing::{info, trace};
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-24 23:42:18 -07:00
|
|
|
use crate::{
|
2023-06-27 22:48:22 -07:00
|
|
|
audit_transaction::{partial_cmp_uid_score, AuditTransaction},
|
2023-06-25 19:04:01 -07:00
|
|
|
u32_hasher_types::{
|
|
|
|
u32hashmap_with_capacity, u32hashset_new, u32priority_queue_with_capacity, U32HasherState,
|
|
|
|
},
|
2023-06-25 00:29:03 -07:00
|
|
|
GbtResult, ThreadTransactionsMap, STARTING_CAPACITY,
|
2023-06-24 23:42:18 -07:00
|
|
|
};
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-27 17:44:52 -04:00
|
|
|
const MAX_BLOCK_WEIGHT_UNITS: u32 = 4_000_000 - 4_000;
|
2023-06-23 16:42:58 -04:00
|
|
|
const BLOCK_SIGOPS: u32 = 80_000;
|
2023-06-23 20:41:39 -04:00
|
|
|
const BLOCK_RESERVED_WEIGHT: u32 = 4_000;
|
2023-06-27 17:44:52 -04:00
|
|
|
const BLOCK_RESERVED_SIGOPS: u32 = 400;
|
2023-06-23 20:41:39 -04:00
|
|
|
const MAX_BLOCKS: usize = 8;
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-24 23:42:18 -07:00
|
|
|
type AuditPool = HashMap<u32, AuditTransaction, U32HasherState>;
|
2023-06-25 08:17:30 -07:00
|
|
|
type ModifiedQueue = PriorityQueue<u32, TxPriority, U32HasherState>;
|
2023-06-24 23:42:18 -07:00
|
|
|
|
2023-06-26 19:29:32 -07:00
|
|
|
#[derive(Debug)]
|
2023-06-23 16:42:58 -04:00
|
|
|
struct TxPriority {
|
2023-06-23 20:41:39 -04:00
|
|
|
uid: u32,
|
|
|
|
score: f64,
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
|
|
|
impl PartialEq for TxPriority {
|
2023-06-23 20:41:39 -04:00
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.uid == other.uid
|
|
|
|
}
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
|
|
|
impl Eq for TxPriority {}
|
|
|
|
impl PartialOrd for TxPriority {
|
2023-06-25 16:08:16 -07:00
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
2023-06-23 20:41:39 -04:00
|
|
|
if self.score == other.score {
|
2023-06-23 21:51:03 -07:00
|
|
|
Some(self.uid.cmp(&other.uid))
|
2023-06-23 20:41:39 -04:00
|
|
|
} else {
|
2023-06-26 17:35:33 -04:00
|
|
|
self.score.partial_cmp(&other.score)
|
2023-06-23 20:41:39 -04:00
|
|
|
}
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Ord for TxPriority {
|
2023-06-23 20:41:39 -04:00
|
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
2023-06-24 16:41:53 -07:00
|
|
|
self.partial_cmp(other).expect("score will never be NaN")
|
2023-06-23 20:41:39 -04:00
|
|
|
}
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
|
|
|
|
2023-06-25 16:08:16 -07:00
|
|
|
/// Build projected mempool blocks using an approximation of the transaction selection algorithm from Bitcoin Core
|
|
|
|
///
|
|
|
|
/// See `BlockAssembler` in Bitcoin Core's
|
|
|
|
/// [miner.cpp](https://github.com/bitcoin/bitcoin/blob/master/src/node/miner.cpp).
|
|
|
|
/// Ported from mempool backend's
|
|
|
|
/// [tx-selection-worker.ts](https://github.com/mempool/mempool/blob/master/backend/src/api/tx-selection-worker.ts).
|
|
|
|
//
|
|
|
|
// TODO: Make gbt smaller to fix these lints.
|
|
|
|
#[allow(clippy::too_many_lines)]
|
|
|
|
#[allow(clippy::cognitive_complexity)]
|
2023-06-26 21:13:02 -04:00
|
|
|
pub fn gbt(mempool: &mut ThreadTransactionsMap) -> GbtResult {
|
2023-06-25 00:29:03 -07:00
|
|
|
let mut audit_pool: AuditPool = u32hashmap_with_capacity(STARTING_CAPACITY);
|
2023-06-26 21:07:14 -04:00
|
|
|
let mut mempool_stack: Vec<u32> = Vec::with_capacity(STARTING_CAPACITY);
|
2023-06-24 11:21:58 -07:00
|
|
|
let mut clusters: Vec<Vec<u32>> = Vec::new();
|
2023-06-26 14:22:10 -04:00
|
|
|
let mut block_weights: Vec<u32> = Vec::new();
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-26 19:29:32 -07:00
|
|
|
info!("Initializing working structs");
|
2023-06-23 20:41:39 -04:00
|
|
|
for (uid, tx) in mempool {
|
2023-06-23 23:06:13 -07:00
|
|
|
let audit_tx = AuditTransaction::from_thread_transaction(tx);
|
2023-06-26 21:07:14 -04:00
|
|
|
// Safety: audit_pool and mempool_stack must always contain the same transactions
|
2023-06-23 20:41:39 -04:00
|
|
|
audit_pool.insert(audit_tx.uid, audit_tx);
|
2023-06-26 21:07:14 -04:00
|
|
|
mempool_stack.push(*uid);
|
2023-06-23 20:41:39 -04:00
|
|
|
}
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-26 19:29:32 -07:00
|
|
|
info!("Building relatives graph & calculate ancestor scores");
|
2023-06-26 21:07:14 -04:00
|
|
|
for txid in &mempool_stack {
|
2023-06-23 20:41:39 -04:00
|
|
|
set_relatives(*txid, &mut audit_pool);
|
|
|
|
}
|
2023-06-26 19:29:32 -07:00
|
|
|
trace!("Post relative graph Audit Pool: {:#?}", audit_pool);
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-26 19:29:32 -07:00
|
|
|
info!("Sorting by descending ancestor score");
|
2023-06-27 22:48:22 -07:00
|
|
|
let mut mempool_stack: Vec<(u32, f64)> = mempool_stack
|
|
|
|
.into_iter()
|
|
|
|
.map(|txid| {
|
|
|
|
let atx = audit_pool
|
|
|
|
.get(&txid)
|
|
|
|
.expect("All txids are from audit_pool");
|
|
|
|
(txid, atx.score())
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
mempool_stack.sort_unstable_by(|a, b| partial_cmp_uid_score(*a, *b).expect("Not NaN"));
|
|
|
|
let mut mempool_stack: Vec<u32> = mempool_stack.into_iter().map(|(txid, _)| txid).collect();
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-26 19:29:32 -07:00
|
|
|
info!("Building blocks by greedily choosing the highest feerate package");
|
|
|
|
info!("(i.e. the package rooted in the transaction with the best ancestor score)");
|
2023-06-23 20:41:39 -04:00
|
|
|
let mut blocks: Vec<Vec<u32>> = Vec::new();
|
|
|
|
let mut block_weight: u32 = BLOCK_RESERVED_WEIGHT;
|
2023-06-27 17:44:52 -04:00
|
|
|
let mut block_sigops: u32 = BLOCK_RESERVED_SIGOPS;
|
2023-06-24 23:42:18 -07:00
|
|
|
let mut transactions: Vec<u32> = Vec::with_capacity(STARTING_CAPACITY);
|
2023-06-25 08:17:30 -07:00
|
|
|
let mut modified: ModifiedQueue = u32priority_queue_with_capacity(STARTING_CAPACITY);
|
2023-06-23 20:41:39 -04:00
|
|
|
let mut overflow: Vec<u32> = Vec::new();
|
|
|
|
let mut failures = 0;
|
2023-06-26 21:07:14 -04:00
|
|
|
while !mempool_stack.is_empty() || !modified.is_empty() {
|
2023-06-26 19:29:32 -07:00
|
|
|
// This trace log storm is big, so to make scrolling through
|
|
|
|
// Each iteration easier, leaving a bunch of empty rows
|
|
|
|
// And a header of ======
|
|
|
|
trace!("\n\n\n\n\n\n\n\n\n\n==================================");
|
|
|
|
trace!("mempool_array: {:#?}", mempool_stack);
|
|
|
|
trace!("clusters: {:#?}", clusters);
|
|
|
|
trace!("modified: {:#?}", modified);
|
|
|
|
trace!("audit_pool: {:#?}", audit_pool);
|
|
|
|
trace!("blocks: {:#?}", blocks);
|
|
|
|
trace!("block_weight: {:#?}", block_weight);
|
|
|
|
trace!("block_sigops: {:#?}", block_sigops);
|
|
|
|
trace!("transactions: {:#?}", transactions);
|
|
|
|
trace!("overflow: {:#?}", overflow);
|
|
|
|
trace!("failures: {:#?}", failures);
|
|
|
|
trace!("\n==================================");
|
|
|
|
|
2023-06-26 21:11:08 -04:00
|
|
|
let next_from_stack = next_valid_from_stack(&mut mempool_stack, &audit_pool);
|
|
|
|
let next_from_queue = next_valid_from_queue(&mut modified, &audit_pool);
|
|
|
|
if next_from_stack.is_none() && next_from_queue.is_none() {
|
|
|
|
continue;
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
2023-06-26 21:11:08 -04:00
|
|
|
let (next_tx, from_stack) = match (next_from_stack, next_from_queue) {
|
|
|
|
(Some(stack_tx), Some(queue_tx)) => match queue_tx.cmp(stack_tx) {
|
|
|
|
std::cmp::Ordering::Less => (stack_tx, true),
|
|
|
|
_ => (queue_tx, false),
|
|
|
|
},
|
|
|
|
(Some(stack_tx), None) => (stack_tx, true),
|
|
|
|
(None, Some(queue_tx)) => (queue_tx, false),
|
|
|
|
(None, None) => unreachable!(),
|
|
|
|
};
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-26 21:11:08 -04:00
|
|
|
if from_stack {
|
|
|
|
mempool_stack.pop();
|
|
|
|
} else {
|
|
|
|
modified.pop();
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
|
|
|
|
2023-06-23 20:41:39 -04:00
|
|
|
if blocks.len() < (MAX_BLOCKS - 1)
|
2023-06-27 22:48:22 -07:00
|
|
|
&& ((block_weight + (4 * next_tx.ancestor_sigop_adjusted_vsize())
|
|
|
|
>= MAX_BLOCK_WEIGHT_UNITS)
|
2023-06-26 21:04:10 -04:00
|
|
|
|| (block_sigops + next_tx.ancestor_sigops() > BLOCK_SIGOPS))
|
2023-06-23 20:41:39 -04:00
|
|
|
{
|
|
|
|
// hold this package in an overflow list while we check for smaller options
|
2023-06-26 21:11:08 -04:00
|
|
|
overflow.push(next_tx.uid);
|
2023-06-23 20:41:39 -04:00
|
|
|
failures += 1;
|
|
|
|
} else {
|
2023-06-26 17:37:00 -04:00
|
|
|
let mut package: Vec<(u32, usize)> = Vec::new();
|
2023-06-23 20:41:39 -04:00
|
|
|
let mut cluster: Vec<u32> = Vec::new();
|
2023-06-23 21:51:03 -07:00
|
|
|
let is_cluster: bool = !next_tx.ancestors.is_empty();
|
2023-06-23 20:41:39 -04:00
|
|
|
for ancestor_id in &next_tx.ancestors {
|
|
|
|
if let Some(ancestor) = audit_pool.get(ancestor_id) {
|
2023-06-26 17:37:00 -04:00
|
|
|
package.push((*ancestor_id, ancestor.ancestors.len()));
|
2023-06-23 20:41:39 -04:00
|
|
|
}
|
|
|
|
}
|
2023-06-27 17:44:52 -04:00
|
|
|
package.sort_unstable_by(|a, b| -> Ordering {
|
|
|
|
if a.1 == b.1 {
|
|
|
|
b.0.cmp(&a.0)
|
|
|
|
} else {
|
|
|
|
a.1.cmp(&b.1)
|
|
|
|
}
|
|
|
|
});
|
2023-06-26 21:11:08 -04:00
|
|
|
package.push((next_tx.uid, next_tx.ancestors.len()));
|
2023-06-23 20:41:39 -04:00
|
|
|
|
2023-06-26 19:29:32 -07:00
|
|
|
let cluster_rate = next_tx.cluster_rate();
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-26 17:37:00 -04:00
|
|
|
for (txid, _) in &package {
|
|
|
|
cluster.push(*txid);
|
2023-06-25 16:08:16 -07:00
|
|
|
if let Some(tx) = audit_pool.get_mut(txid) {
|
2023-06-23 20:41:39 -04:00
|
|
|
tx.used = true;
|
2023-06-26 19:29:32 -07:00
|
|
|
tx.set_dirty_if_different(cluster_rate);
|
2023-06-23 20:41:39 -04:00
|
|
|
transactions.push(tx.uid);
|
|
|
|
block_weight += tx.weight;
|
|
|
|
block_sigops += tx.sigops;
|
|
|
|
}
|
2023-06-25 16:08:16 -07:00
|
|
|
update_descendants(*txid, &mut audit_pool, &mut modified, cluster_rate);
|
2023-06-23 20:41:39 -04:00
|
|
|
}
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-26 17:37:00 -04:00
|
|
|
if is_cluster {
|
|
|
|
clusters.push(cluster);
|
|
|
|
}
|
|
|
|
|
2023-06-23 20:41:39 -04:00
|
|
|
failures = 0;
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
|
|
|
|
2023-06-23 20:41:39 -04:00
|
|
|
// this block is full
|
|
|
|
let exceeded_package_tries =
|
2023-06-27 17:44:52 -04:00
|
|
|
failures > 1000 && block_weight > (MAX_BLOCK_WEIGHT_UNITS - BLOCK_RESERVED_WEIGHT);
|
2023-06-26 21:07:14 -04:00
|
|
|
let queue_is_empty = mempool_stack.is_empty() && modified.is_empty();
|
2023-06-23 20:41:39 -04:00
|
|
|
if (exceeded_package_tries || queue_is_empty) && blocks.len() < (MAX_BLOCKS - 1) {
|
|
|
|
// finalize this block
|
2023-06-23 21:51:03 -07:00
|
|
|
if !transactions.is_empty() {
|
2023-06-23 20:41:39 -04:00
|
|
|
blocks.push(transactions);
|
2023-06-26 14:22:10 -04:00
|
|
|
block_weights.push(block_weight);
|
2023-06-23 20:41:39 -04:00
|
|
|
}
|
|
|
|
// reset for the next block
|
2023-06-24 23:42:18 -07:00
|
|
|
transactions = Vec::with_capacity(STARTING_CAPACITY);
|
2023-06-27 17:44:52 -04:00
|
|
|
block_weight = BLOCK_RESERVED_WEIGHT;
|
|
|
|
block_sigops = BLOCK_RESERVED_SIGOPS;
|
2023-06-26 17:37:00 -04:00
|
|
|
failures = 0;
|
2023-06-23 20:41:39 -04:00
|
|
|
// 'overflow' packages didn't fit in this block, but are valid candidates for the next
|
|
|
|
overflow.reverse();
|
|
|
|
for overflowed in &overflow {
|
|
|
|
if let Some(overflowed_tx) = audit_pool.get(overflowed) {
|
|
|
|
if overflowed_tx.modified {
|
|
|
|
modified.push(
|
|
|
|
*overflowed,
|
|
|
|
TxPriority {
|
|
|
|
uid: *overflowed,
|
2023-06-25 11:19:33 -07:00
|
|
|
score: overflowed_tx.score(),
|
2023-06-23 20:41:39 -04:00
|
|
|
},
|
|
|
|
);
|
|
|
|
} else {
|
2023-06-26 21:07:14 -04:00
|
|
|
mempool_stack.push(*overflowed);
|
2023-06-23 20:41:39 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
overflow = Vec::new();
|
|
|
|
}
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
2023-06-27 22:48:22 -07:00
|
|
|
info!("add the final unbounded block if it contains any transactions");
|
2023-06-23 21:51:03 -07:00
|
|
|
if !transactions.is_empty() {
|
2023-06-23 16:42:58 -04:00
|
|
|
blocks.push(transactions);
|
2023-06-26 14:22:10 -04:00
|
|
|
block_weights.push(block_weight);
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
|
|
|
|
2023-06-27 22:48:22 -07:00
|
|
|
info!("make a list of dirty transactions and their new rates");
|
2023-06-24 11:21:58 -07:00
|
|
|
let mut rates: Vec<Vec<f64>> = Vec::new();
|
2023-06-23 20:41:39 -04:00
|
|
|
for (txid, tx) in audit_pool {
|
2023-06-26 19:29:32 -07:00
|
|
|
trace!("txid: {}, is_dirty: {}", txid, tx.dirty);
|
2023-06-23 20:41:39 -04:00
|
|
|
if tx.dirty {
|
2023-06-25 16:08:16 -07:00
|
|
|
rates.push(vec![f64::from(txid), tx.effective_fee_per_vsize]);
|
2023-06-23 20:41:39 -04:00
|
|
|
}
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
2023-06-26 19:29:32 -07:00
|
|
|
trace!("\n\n\n\n\n====================");
|
|
|
|
trace!("blocks: {:#?}", blocks);
|
|
|
|
trace!("clusters: {:#?}", clusters);
|
|
|
|
trace!("rates: {:#?}\n====================\n\n\n\n\n", rates);
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-26 21:13:02 -04:00
|
|
|
GbtResult {
|
2023-06-24 11:21:58 -07:00
|
|
|
blocks,
|
2023-06-26 14:22:10 -04:00
|
|
|
block_weights,
|
2023-06-24 11:21:58 -07:00
|
|
|
clusters,
|
2023-06-25 16:08:16 -07:00
|
|
|
rates,
|
2023-06-26 21:13:02 -04:00
|
|
|
}
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
|
|
|
|
2023-06-26 19:29:32 -07:00
|
|
|
fn next_valid_from_stack<'a>(
|
|
|
|
mempool_stack: &mut Vec<u32>,
|
|
|
|
audit_pool: &'a AuditPool,
|
|
|
|
) -> Option<&'a AuditTransaction> {
|
2023-06-26 21:11:08 -04:00
|
|
|
let mut next_txid = mempool_stack.last()?;
|
|
|
|
let mut tx: &AuditTransaction = audit_pool.get(next_txid)?;
|
|
|
|
while tx.used || tx.modified {
|
|
|
|
mempool_stack.pop();
|
|
|
|
next_txid = mempool_stack.last()?;
|
|
|
|
tx = audit_pool.get(next_txid)?;
|
|
|
|
}
|
|
|
|
Some(tx)
|
|
|
|
}
|
|
|
|
|
2023-06-26 19:29:32 -07:00
|
|
|
fn next_valid_from_queue<'a>(
|
|
|
|
queue: &mut ModifiedQueue,
|
|
|
|
audit_pool: &'a AuditPool,
|
|
|
|
) -> Option<&'a AuditTransaction> {
|
2023-06-26 21:11:08 -04:00
|
|
|
let mut next_txid = queue.peek()?.0;
|
|
|
|
let mut tx: &AuditTransaction = audit_pool.get(next_txid)?;
|
|
|
|
while tx.used {
|
|
|
|
queue.pop();
|
|
|
|
next_txid = queue.peek()?.0;
|
|
|
|
tx = audit_pool.get(next_txid)?;
|
|
|
|
}
|
|
|
|
Some(tx)
|
|
|
|
}
|
|
|
|
|
2023-06-24 23:42:18 -07:00
|
|
|
fn set_relatives(txid: u32, audit_pool: &mut AuditPool) {
|
2023-06-25 19:04:01 -07:00
|
|
|
let mut parents: HashSet<u32, U32HasherState> = u32hashset_new();
|
2023-06-23 20:41:39 -04:00
|
|
|
if let Some(tx) = audit_pool.get(&txid) {
|
|
|
|
if tx.relatives_set_flag {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for input in &tx.inputs {
|
|
|
|
parents.insert(*input);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return;
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
|
|
|
|
2023-06-25 19:04:01 -07:00
|
|
|
let mut ancestors: HashSet<u32, U32HasherState> = u32hashset_new();
|
2023-06-23 20:41:39 -04:00
|
|
|
for parent_id in &parents {
|
|
|
|
set_relatives(*parent_id, audit_pool);
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-23 21:51:03 -07:00
|
|
|
if let Some(parent) = audit_pool.get_mut(parent_id) {
|
2023-06-24 16:41:53 -07:00
|
|
|
// Safety: ancestors must always contain only txes in audit_pool
|
2023-06-23 21:51:03 -07:00
|
|
|
ancestors.insert(*parent_id);
|
|
|
|
parent.children.insert(txid);
|
|
|
|
for ancestor in &parent.ancestors {
|
|
|
|
ancestors.insert(*ancestor);
|
2023-06-23 20:41:39 -04:00
|
|
|
}
|
|
|
|
}
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
|
|
|
|
2023-06-23 20:41:39 -04:00
|
|
|
let mut total_fee: u64 = 0;
|
|
|
|
let mut total_weight: u32 = 0;
|
2023-06-27 18:51:18 -04:00
|
|
|
let mut total_sigop_adjusted_vsize: u32 = 0;
|
2023-06-23 20:41:39 -04:00
|
|
|
let mut total_sigops: u32 = 0;
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-23 20:41:39 -04:00
|
|
|
for ancestor_id in &ancestors {
|
2023-06-24 16:41:53 -07:00
|
|
|
let ancestor = audit_pool
|
|
|
|
.get(ancestor_id)
|
|
|
|
.expect("audit_pool contains all ancestors");
|
2023-06-23 20:41:39 -04:00
|
|
|
total_fee += ancestor.fee;
|
|
|
|
total_weight += ancestor.weight;
|
2023-06-27 18:51:18 -04:00
|
|
|
total_sigop_adjusted_vsize += ancestor.sigop_adjusted_vsize;
|
2023-06-23 20:41:39 -04:00
|
|
|
total_sigops += ancestor.sigops;
|
|
|
|
}
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-23 20:41:39 -04:00
|
|
|
if let Some(tx) = audit_pool.get_mut(&txid) {
|
2023-06-27 22:48:22 -07:00
|
|
|
tx.set_ancestors(
|
|
|
|
ancestors,
|
|
|
|
total_fee,
|
|
|
|
total_weight,
|
|
|
|
total_sigop_adjusted_vsize,
|
|
|
|
total_sigops,
|
|
|
|
);
|
2023-06-23 20:41:39 -04:00
|
|
|
}
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// iterate over remaining descendants, removing the root as a valid ancestor & updating the ancestor score
|
2023-06-23 20:41:39 -04:00
|
|
|
fn update_descendants(
|
|
|
|
root_txid: u32,
|
2023-06-24 23:42:18 -07:00
|
|
|
audit_pool: &mut AuditPool,
|
2023-06-25 08:17:30 -07:00
|
|
|
modified: &mut ModifiedQueue,
|
2023-06-23 20:41:39 -04:00
|
|
|
cluster_rate: f64,
|
|
|
|
) {
|
2023-06-25 19:04:01 -07:00
|
|
|
let mut visited: HashSet<u32, U32HasherState> = u32hashset_new();
|
2023-06-23 20:41:39 -04:00
|
|
|
let mut descendant_stack: Vec<u32> = Vec::new();
|
|
|
|
let root_fee: u64;
|
|
|
|
let root_weight: u32;
|
2023-06-27 18:51:18 -04:00
|
|
|
let root_sigop_adjusted_vsize: u32;
|
2023-06-23 20:41:39 -04:00
|
|
|
let root_sigops: u32;
|
|
|
|
if let Some(root_tx) = audit_pool.get(&root_txid) {
|
|
|
|
for descendant_id in &root_tx.children {
|
|
|
|
if !visited.contains(descendant_id) {
|
|
|
|
descendant_stack.push(*descendant_id);
|
|
|
|
visited.insert(*descendant_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
root_fee = root_tx.fee;
|
|
|
|
root_weight = root_tx.weight;
|
2023-06-27 18:51:18 -04:00
|
|
|
root_sigop_adjusted_vsize = root_tx.sigop_adjusted_vsize;
|
2023-06-23 20:41:39 -04:00
|
|
|
root_sigops = root_tx.sigops;
|
|
|
|
} else {
|
|
|
|
return;
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
2023-06-24 16:41:53 -07:00
|
|
|
while let Some(next_txid) = descendant_stack.pop() {
|
2023-06-23 20:41:39 -04:00
|
|
|
if let Some(descendant) = audit_pool.get_mut(&next_txid) {
|
|
|
|
// remove root tx as ancestor
|
2023-06-27 22:48:22 -07:00
|
|
|
let old_score = descendant.remove_root(
|
|
|
|
root_txid,
|
|
|
|
root_fee,
|
|
|
|
root_weight,
|
|
|
|
root_sigop_adjusted_vsize,
|
|
|
|
root_sigops,
|
|
|
|
cluster_rate,
|
|
|
|
);
|
2023-06-26 17:35:33 -04:00
|
|
|
// add to priority queue or update priority if score has changed
|
2023-06-25 16:08:16 -07:00
|
|
|
if descendant.score() < old_score {
|
2023-06-26 17:35:33 -04:00
|
|
|
descendant.modified = true;
|
2023-06-23 20:41:39 -04:00
|
|
|
modified.push_decrease(
|
|
|
|
descendant.uid,
|
|
|
|
TxPriority {
|
|
|
|
uid: descendant.uid,
|
2023-06-25 11:19:33 -07:00
|
|
|
score: descendant.score(),
|
2023-06-23 20:41:39 -04:00
|
|
|
},
|
|
|
|
);
|
2023-06-25 16:08:16 -07:00
|
|
|
} else if descendant.score() > old_score {
|
2023-06-26 17:35:33 -04:00
|
|
|
descendant.modified = true;
|
2023-06-23 20:41:39 -04:00
|
|
|
modified.push_increase(
|
|
|
|
descendant.uid,
|
|
|
|
TxPriority {
|
|
|
|
uid: descendant.uid,
|
2023-06-25 11:19:33 -07:00
|
|
|
score: descendant.score(),
|
2023-06-23 20:41:39 -04:00
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-23 20:41:39 -04:00
|
|
|
// add this node's children to the stack
|
|
|
|
for child_id in &descendant.children {
|
|
|
|
if !visited.contains(child_id) {
|
|
|
|
descendant_stack.push(*child_id);
|
|
|
|
visited.insert(*child_id);
|
|
|
|
}
|
|
|
|
}
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|
|
|
|
}
|
2023-06-23 20:41:39 -04:00
|
|
|
}
|