conform to core's gbt quirks

This commit is contained in:
Mononaut 2023-06-27 17:44:52 -04:00
parent 71f150b587
commit 10beb76585
No known key found for this signature in database
GPG Key ID: A3F058E41374C04E
3 changed files with 33 additions and 14 deletions

View File

@ -14,6 +14,7 @@ pub struct AuditTransaction {
pub uid: u32, pub uid: u32,
pub fee: u64, pub fee: u64,
pub weight: u32, pub weight: u32,
pub vsize: u32,
pub sigops: u32, pub sigops: u32,
pub fee_per_vsize: f64, pub fee_per_vsize: f64,
pub effective_fee_per_vsize: f64, pub effective_fee_per_vsize: f64,
@ -24,6 +25,7 @@ pub struct AuditTransaction {
pub children: HashSet<u32, U32HasherState>, pub children: HashSet<u32, U32HasherState>,
ancestor_fee: u64, ancestor_fee: u64,
ancestor_weight: u32, ancestor_weight: u32,
ancestor_vsize: u32,
ancestor_sigops: u32, ancestor_sigops: u32,
// Safety: Must be private to prevent NaN breaking Ord impl. // Safety: Must be private to prevent NaN breaking Ord impl.
score: f64, score: f64,
@ -74,6 +76,7 @@ impl AuditTransaction {
uid: tx.uid, uid: tx.uid,
fee: tx.fee, fee: tx.fee,
weight: tx.weight, weight: tx.weight,
vsize: ((tx.weight + 3) / 4).max(tx.sigops * 5), // rounded up to the nearest integer
sigops: tx.sigops, sigops: tx.sigops,
fee_per_vsize: tx.fee_per_vsize, fee_per_vsize: tx.fee_per_vsize,
effective_fee_per_vsize: tx.effective_fee_per_vsize, effective_fee_per_vsize: tx.effective_fee_per_vsize,
@ -84,6 +87,7 @@ impl AuditTransaction {
children: u32hashset_new(), children: u32hashset_new(),
ancestor_fee: tx.fee, ancestor_fee: tx.fee,
ancestor_weight: tx.weight, ancestor_weight: tx.weight,
ancestor_vsize: ((tx.weight + 3) / 4).max(tx.sigops * 5), // rounded up to the nearest integer
ancestor_sigops: tx.sigops, ancestor_sigops: tx.sigops,
score: 0.0, score: 0.0,
used: false, used: false,
@ -98,8 +102,8 @@ impl AuditTransaction {
} }
#[inline] #[inline]
pub const fn ancestor_weight(&self) -> u32 { pub const fn ancestor_vsize(&self) -> u32 {
self.ancestor_weight self.ancestor_vsize
} }
#[inline] #[inline]
@ -128,10 +132,10 @@ impl AuditTransaction {
#[inline] #[inline]
fn calc_new_score(&mut self) { fn calc_new_score(&mut self) {
self.score = (self.ancestor_fee as f64) self.score = (self.ancestor_fee as f64)
/ (if self.ancestor_weight == 0 { / (if self.ancestor_vsize == 0 {
1.0 1.0
} else { } else {
f64::from(self.ancestor_weight) / 4.0 f64::from(self.ancestor_vsize)
}); });
} }
@ -141,11 +145,13 @@ impl AuditTransaction {
ancestors: HashSet<u32, U32HasherState>, ancestors: HashSet<u32, U32HasherState>,
total_fee: u64, total_fee: u64,
total_weight: u32, total_weight: u32,
total_vsize: u32,
total_sigops: u32, total_sigops: u32,
) { ) {
self.ancestors = ancestors; self.ancestors = ancestors;
self.ancestor_fee = self.fee + total_fee; self.ancestor_fee = self.fee + total_fee;
self.ancestor_weight = self.weight + total_weight; self.ancestor_weight = self.weight + total_weight;
self.ancestor_vsize = self.vsize + total_vsize;
self.ancestor_sigops = self.sigops + total_sigops; self.ancestor_sigops = self.sigops + total_sigops;
self.calc_new_score(); self.calc_new_score();
self.relatives_set_flag = true; self.relatives_set_flag = true;
@ -157,6 +163,7 @@ impl AuditTransaction {
root_txid: u32, root_txid: u32,
root_fee: u64, root_fee: u64,
root_weight: u32, root_weight: u32,
root_vsize: u32,
root_sigops: u32, root_sigops: u32,
cluster_rate: f64, cluster_rate: f64,
) -> f64 { ) -> f64 {
@ -165,6 +172,7 @@ impl AuditTransaction {
if self.ancestors.remove(&root_txid) { if self.ancestors.remove(&root_txid) {
self.ancestor_fee -= root_fee; self.ancestor_fee -= root_fee;
self.ancestor_weight -= root_weight; self.ancestor_weight -= root_weight;
self.ancestor_vsize -= root_vsize;
self.ancestor_sigops -= root_sigops; self.ancestor_sigops -= root_sigops;
self.calc_new_score(); self.calc_new_score();
} }

View File

@ -13,9 +13,10 @@ use crate::{
GbtResult, ThreadTransactionsMap, STARTING_CAPACITY, GbtResult, ThreadTransactionsMap, STARTING_CAPACITY,
}; };
const BLOCK_WEIGHT_UNITS: u32 = 4_000_000; const MAX_BLOCK_WEIGHT_UNITS: u32 = 4_000_000 - 4_000;
const BLOCK_SIGOPS: u32 = 80_000; const BLOCK_SIGOPS: u32 = 80_000;
const BLOCK_RESERVED_WEIGHT: u32 = 4_000; const BLOCK_RESERVED_WEIGHT: u32 = 4_000;
const BLOCK_RESERVED_SIGOPS: u32 = 400;
const MAX_BLOCKS: usize = 8; const MAX_BLOCKS: usize = 8;
type AuditPool = HashMap<u32, AuditTransaction, U32HasherState>; type AuditPool = HashMap<u32, AuditTransaction, U32HasherState>;
@ -91,7 +92,7 @@ pub fn gbt(mempool: &mut ThreadTransactionsMap) -> GbtResult {
info!("(i.e. the package rooted in the transaction with the best ancestor score)"); info!("(i.e. the package rooted in the transaction with the best ancestor score)");
let mut blocks: Vec<Vec<u32>> = Vec::new(); let mut blocks: Vec<Vec<u32>> = Vec::new();
let mut block_weight: u32 = BLOCK_RESERVED_WEIGHT; let mut block_weight: u32 = BLOCK_RESERVED_WEIGHT;
let mut block_sigops: u32 = 0; let mut block_sigops: u32 = BLOCK_RESERVED_SIGOPS;
let mut transactions: Vec<u32> = Vec::with_capacity(STARTING_CAPACITY); let mut transactions: Vec<u32> = Vec::with_capacity(STARTING_CAPACITY);
let mut modified: ModifiedQueue = u32priority_queue_with_capacity(STARTING_CAPACITY); let mut modified: ModifiedQueue = u32priority_queue_with_capacity(STARTING_CAPACITY);
let mut overflow: Vec<u32> = Vec::new(); let mut overflow: Vec<u32> = Vec::new();
@ -135,7 +136,7 @@ pub fn gbt(mempool: &mut ThreadTransactionsMap) -> GbtResult {
} }
if blocks.len() < (MAX_BLOCKS - 1) if blocks.len() < (MAX_BLOCKS - 1)
&& ((block_weight + next_tx.ancestor_weight() >= BLOCK_WEIGHT_UNITS) && ((block_weight + (4 * next_tx.ancestor_vsize()) >= MAX_BLOCK_WEIGHT_UNITS)
|| (block_sigops + next_tx.ancestor_sigops() > BLOCK_SIGOPS)) || (block_sigops + next_tx.ancestor_sigops() > BLOCK_SIGOPS))
{ {
// hold this package in an overflow list while we check for smaller options // hold this package in an overflow list while we check for smaller options
@ -150,7 +151,13 @@ pub fn gbt(mempool: &mut ThreadTransactionsMap) -> GbtResult {
package.push((*ancestor_id, ancestor.ancestors.len())); package.push((*ancestor_id, ancestor.ancestors.len()));
} }
} }
package.sort_unstable_by_key(|a| a.1); package.sort_unstable_by(|a, b| -> Ordering {
if a.1 == b.1 {
b.0.cmp(&a.0)
} else {
a.1.cmp(&b.1)
}
});
package.push((next_tx.uid, next_tx.ancestors.len())); package.push((next_tx.uid, next_tx.ancestors.len()));
let cluster_rate = next_tx.cluster_rate(); let cluster_rate = next_tx.cluster_rate();
@ -176,7 +183,7 @@ pub fn gbt(mempool: &mut ThreadTransactionsMap) -> GbtResult {
// this block is full // this block is full
let exceeded_package_tries = let exceeded_package_tries =
failures > 1000 && block_weight > (BLOCK_WEIGHT_UNITS - BLOCK_RESERVED_WEIGHT); failures > 1000 && block_weight > (MAX_BLOCK_WEIGHT_UNITS - BLOCK_RESERVED_WEIGHT);
let queue_is_empty = mempool_stack.is_empty() && modified.is_empty(); let queue_is_empty = mempool_stack.is_empty() && modified.is_empty();
if (exceeded_package_tries || queue_is_empty) && blocks.len() < (MAX_BLOCKS - 1) { if (exceeded_package_tries || queue_is_empty) && blocks.len() < (MAX_BLOCKS - 1) {
// finalize this block // finalize this block
@ -185,8 +192,8 @@ pub fn gbt(mempool: &mut ThreadTransactionsMap) -> GbtResult {
} }
// reset for the next block // reset for the next block
transactions = Vec::with_capacity(STARTING_CAPACITY); transactions = Vec::with_capacity(STARTING_CAPACITY);
block_weight = 4000; block_weight = BLOCK_RESERVED_WEIGHT;
block_sigops = 0; block_sigops = BLOCK_RESERVED_SIGOPS;
failures = 0; failures = 0;
// 'overflow' packages didn't fit in this block, but are valid candidates for the next // 'overflow' packages didn't fit in this block, but are valid candidates for the next
overflow.reverse(); overflow.reverse();
@ -290,6 +297,7 @@ fn set_relatives(txid: u32, audit_pool: &mut AuditPool) {
let mut total_fee: u64 = 0; let mut total_fee: u64 = 0;
let mut total_weight: u32 = 0; let mut total_weight: u32 = 0;
let mut total_vsize: u32 = 0;
let mut total_sigops: u32 = 0; let mut total_sigops: u32 = 0;
for ancestor_id in &ancestors { for ancestor_id in &ancestors {
@ -298,11 +306,12 @@ fn set_relatives(txid: u32, audit_pool: &mut AuditPool) {
.expect("audit_pool contains all ancestors"); .expect("audit_pool contains all ancestors");
total_fee += ancestor.fee; total_fee += ancestor.fee;
total_weight += ancestor.weight; total_weight += ancestor.weight;
total_vsize += ancestor.vsize;
total_sigops += ancestor.sigops; total_sigops += ancestor.sigops;
} }
if let Some(tx) = audit_pool.get_mut(&txid) { if let Some(tx) = audit_pool.get_mut(&txid) {
tx.set_ancestors(ancestors, total_fee, total_weight, total_sigops); tx.set_ancestors(ancestors, total_fee, total_weight, total_vsize, total_sigops);
} }
} }
@ -317,6 +326,7 @@ fn update_descendants(
let mut descendant_stack: Vec<u32> = Vec::new(); let mut descendant_stack: Vec<u32> = Vec::new();
let root_fee: u64; let root_fee: u64;
let root_weight: u32; let root_weight: u32;
let root_vsize: u32;
let root_sigops: u32; let root_sigops: u32;
if let Some(root_tx) = audit_pool.get(&root_txid) { if let Some(root_tx) = audit_pool.get(&root_txid) {
for descendant_id in &root_tx.children { for descendant_id in &root_tx.children {
@ -327,6 +337,7 @@ fn update_descendants(
} }
root_fee = root_tx.fee; root_fee = root_tx.fee;
root_weight = root_tx.weight; root_weight = root_tx.weight;
root_vsize = root_tx.vsize;
root_sigops = root_tx.sigops; root_sigops = root_tx.sigops;
} else { } else {
return; return;
@ -335,7 +346,7 @@ fn update_descendants(
if let Some(descendant) = audit_pool.get_mut(&next_txid) { if let Some(descendant) = audit_pool.get_mut(&next_txid) {
// remove root tx as ancestor // remove root tx as ancestor
let old_score = let old_score =
descendant.remove_root(root_txid, root_fee, root_weight, root_sigops, cluster_rate); descendant.remove_root(root_txid, root_fee, root_weight, root_vsize, root_sigops, cluster_rate);
// add to priority queue or update priority if score has changed // add to priority queue or update priority if score has changed
if descendant.score() < old_score { if descendant.score() < old_score {
descendant.modified = true; descendant.modified = true;

View File

@ -657,7 +657,7 @@ class MempoolBlocks {
if (tx.uid !== null && tx.uid !== undefined) { if (tx.uid !== null && tx.uid !== undefined) {
view.setUint32(offset, tx.uid, false); view.setUint32(offset, tx.uid, false);
view.setFloat64(offset + 4, tx.fee, false); view.setFloat64(offset + 4, tx.fee, false);
view.setUint32(offset + 12, (tx.adjustedVsize * 4), false); view.setUint32(offset + 12, tx.weight, false);
view.setUint32(offset + 16, tx.sigops, false); view.setUint32(offset + 16, tx.sigops, false);
view.setFloat64(offset + 20, (tx.adjustedFeePerVsize || tx.feePerVsize), false); view.setFloat64(offset + 20, (tx.adjustedFeePerVsize || tx.feePerVsize), false);
view.setFloat64(offset + 28, (tx.effectiveFeePerVsize || tx.adjustedFeePerVsize || tx.feePerVsize), false); view.setFloat64(offset + 28, (tx.effectiveFeePerVsize || tx.adjustedFeePerVsize || tx.feePerVsize), false);