Mimic Core's ordering for equal-score transactions
This commit is contained in:
1
backend/rust-gbt/index.d.ts
vendored
1
backend/rust-gbt/index.d.ts
vendored
@@ -5,6 +5,7 @@
|
||||
|
||||
export interface ThreadTransaction {
|
||||
uid: number
|
||||
order: number
|
||||
fee: number
|
||||
weight: number
|
||||
sigops: number
|
||||
|
||||
@@ -12,6 +12,7 @@ use std::{
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AuditTransaction {
|
||||
pub uid: u32,
|
||||
order: u32,
|
||||
pub fee: u64,
|
||||
pub weight: u32,
|
||||
pub sigop_adjusted_vsize: u32,
|
||||
@@ -50,19 +51,24 @@ impl PartialEq for AuditTransaction {
|
||||
impl Eq for AuditTransaction {}
|
||||
|
||||
#[inline]
|
||||
pub fn partial_cmp_uid_score(a: (u32, f64), b: (u32, f64)) -> Option<Ordering> {
|
||||
pub fn partial_cmp_uid_score(a: (u32, u32, f64), b: (u32, u32, f64)) -> Option<Ordering> {
|
||||
// If either score is NaN, this is false,
|
||||
// and partial_cmp will return None
|
||||
if a.1 == b.1 {
|
||||
Some(a.0.cmp(&b.0))
|
||||
if a.2 != b.2 {
|
||||
a.2.partial_cmp(&b.2)
|
||||
} else if a.1 != b.1 {
|
||||
Some(b.1.cmp(&a.1))
|
||||
} else {
|
||||
a.1.partial_cmp(&b.1)
|
||||
Some(a.0.cmp(&b.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for AuditTransaction {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
partial_cmp_uid_score((self.uid, self.score), (other.uid, other.score))
|
||||
partial_cmp_uid_score(
|
||||
(self.uid, self.order, self.score),
|
||||
(other.uid, self.order, other.score),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +92,7 @@ impl AuditTransaction {
|
||||
let sigop_adjusted_vsize = ((tx.weight + 3) / 4).max(tx.sigops * 5);
|
||||
Self {
|
||||
uid: tx.uid,
|
||||
order: tx.order,
|
||||
fee: tx.fee as u64,
|
||||
weight: tx.weight,
|
||||
sigop_adjusted_vsize,
|
||||
@@ -113,6 +120,11 @@ impl AuditTransaction {
|
||||
self.score
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn order(&self) -> u32 {
|
||||
self.order
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn ancestor_sigop_adjusted_vsize(&self) -> u32 {
|
||||
self.ancestor_sigop_adjusted_vsize
|
||||
|
||||
@@ -25,6 +25,7 @@ type ModifiedQueue = PriorityQueue<u32, TxPriority, U32HasherState>;
|
||||
#[derive(Debug)]
|
||||
struct TxPriority {
|
||||
uid: u32,
|
||||
order: u32,
|
||||
score: f64,
|
||||
}
|
||||
impl PartialEq for TxPriority {
|
||||
@@ -35,10 +36,12 @@ impl PartialEq for TxPriority {
|
||||
impl Eq for TxPriority {}
|
||||
impl PartialOrd for TxPriority {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
if self.score == other.score {
|
||||
Some(self.uid.cmp(&other.uid))
|
||||
} else {
|
||||
if self.score != other.score {
|
||||
self.score.partial_cmp(&other.score)
|
||||
} else if self.order != other.order {
|
||||
Some(other.order.cmp(&self.order))
|
||||
} else {
|
||||
Some(self.uid.cmp(&other.uid))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,17 +83,17 @@ pub fn gbt(mempool: &mut ThreadTransactionsMap) -> GbtResult {
|
||||
trace!("Post relative graph Audit Pool: {:#?}", audit_pool);
|
||||
|
||||
info!("Sorting by descending ancestor score");
|
||||
let mut mempool_stack: Vec<(u32, f64)> = mempool_stack
|
||||
let mut mempool_stack: Vec<(u32, u32, f64)> = mempool_stack
|
||||
.into_iter()
|
||||
.map(|txid| {
|
||||
let atx = audit_pool
|
||||
.get(&txid)
|
||||
.expect("All txids are from audit_pool");
|
||||
(txid, atx.score())
|
||||
(txid, atx.order(), 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();
|
||||
let mut mempool_stack: Vec<u32> = mempool_stack.into_iter().map(|(txid, _, _)| txid).collect();
|
||||
|
||||
info!("Building blocks by greedily choosing the highest feerate package");
|
||||
info!("(i.e. the package rooted in the transaction with the best ancestor score)");
|
||||
@@ -212,6 +215,7 @@ pub fn gbt(mempool: &mut ThreadTransactionsMap) -> GbtResult {
|
||||
*overflowed,
|
||||
TxPriority {
|
||||
uid: *overflowed,
|
||||
order: overflowed_tx.order(),
|
||||
score: overflowed_tx.score(),
|
||||
},
|
||||
);
|
||||
@@ -376,6 +380,7 @@ fn update_descendants(
|
||||
descendant.uid,
|
||||
TxPriority {
|
||||
uid: descendant.uid,
|
||||
order: descendant.order(),
|
||||
score: descendant.score(),
|
||||
},
|
||||
);
|
||||
@@ -385,6 +390,7 @@ fn update_descendants(
|
||||
descendant.uid,
|
||||
TxPriority {
|
||||
uid: descendant.uid,
|
||||
order: descendant.order(),
|
||||
score: descendant.score(),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -23,7 +23,7 @@ mod u32_hasher_types;
|
||||
|
||||
use u32_hasher_types::{u32hashmap_with_capacity, U32HasherState};
|
||||
|
||||
/// This is the initial capacity of the GbtGenerator struct's inner HashMap.
|
||||
/// This is the initial capacity of the `GbtGenerator` struct's inner `HashMap`.
|
||||
///
|
||||
/// Note: This doesn't *have* to be a power of 2. (uwu)
|
||||
const STARTING_CAPACITY: usize = 1_048_576;
|
||||
|
||||
@@ -4,6 +4,7 @@ use napi_derive::napi;
|
||||
#[napi(object)]
|
||||
pub struct ThreadTransaction {
|
||||
pub uid: u32,
|
||||
pub order: u32,
|
||||
pub fee: f64,
|
||||
pub weight: u32,
|
||||
pub sigops: u32,
|
||||
|
||||
Reference in New Issue
Block a user