Protect score from outside assignment and document the requirements

This commit is contained in:
junderw 2023-06-25 11:19:33 -07:00 committed by Mononaut
parent af4919a98b
commit e3f4c33f03
No known key found for this signature in database
GPG Key ID: A3F058E41374C04E
2 changed files with 29 additions and 19 deletions

View File

@ -21,7 +21,8 @@ pub struct AuditTransaction {
pub ancestor_fee: u64, pub ancestor_fee: u64,
pub ancestor_weight: u32, pub ancestor_weight: u32,
pub ancestor_sigops: u32, pub ancestor_sigops: u32,
pub score: f64, // Safety: Must be private to prevent NaN breaking Ord impl.
score: f64,
pub used: bool, pub used: bool,
pub modified: bool, pub modified: bool,
pub dirty: bool, pub dirty: bool,
@ -53,6 +54,9 @@ impl PartialOrd for AuditTransaction {
impl Ord for AuditTransaction { impl Ord for AuditTransaction {
fn cmp(&self, other: &AuditTransaction) -> Ordering { fn cmp(&self, other: &AuditTransaction) -> Ordering {
// Safety: The only possible values for score are f64
// that are not NaN. This is because outside code can not
// freely assign score. Also, calc_new_score guarantees no NaN.
self.partial_cmp(other).expect("score will never be NaN") self.partial_cmp(other).expect("score will never be NaN")
} }
} }
@ -80,4 +84,20 @@ impl AuditTransaction {
dirty: false, dirty: false,
} }
} }
#[inline]
pub fn score(&self) -> f64 {
self.score
}
/// Safety: This function must NEVER set score to NaN.
#[inline]
pub fn calc_new_score(&mut self) {
self.score = (self.ancestor_fee as f64)
/ (if self.ancestor_weight == 0 {
1.0
} else {
self.ancestor_weight as f64 / 4.0
});
}
} }

View File

@ -185,7 +185,7 @@ pub fn gbt(mempool: &mut ThreadTransactionsMap) -> Option<GbtResult> {
*overflowed, *overflowed,
TxPriority { TxPriority {
uid: *overflowed, uid: *overflowed,
score: overflowed_tx.score, score: overflowed_tx.score(),
}, },
); );
} else { } else {
@ -261,12 +261,7 @@ fn set_relatives(txid: u32, audit_pool: &mut AuditPool) {
tx.ancestor_fee = tx.fee + total_fee; tx.ancestor_fee = tx.fee + total_fee;
tx.ancestor_weight = tx.weight + total_weight; tx.ancestor_weight = tx.weight + total_weight;
tx.ancestor_sigops = tx.sigops + total_sigops; tx.ancestor_sigops = tx.sigops + total_sigops;
tx.score = (tx.ancestor_fee as f64) tx.calc_new_score();
/ (if tx.ancestor_weight == 0 {
1.0
} else {
tx.ancestor_weight as f64 / 4.0
});
tx.relatives_set_flag = true; tx.relatives_set_flag = true;
} }
} }
@ -303,30 +298,25 @@ fn update_descendants(
descendant.ancestor_fee -= root_fee; descendant.ancestor_fee -= root_fee;
descendant.ancestor_weight -= root_weight; descendant.ancestor_weight -= root_weight;
descendant.ancestor_sigops -= root_sigops; descendant.ancestor_sigops -= root_sigops;
let current_score = descendant.score; let current_score = descendant.score();
descendant.score = (descendant.ancestor_fee as f64) descendant.calc_new_score();
/ (if descendant.ancestor_weight == 0 {
1.0
} else {
descendant.ancestor_weight as f64 / 4.0
});
descendant.dependency_rate = descendant.dependency_rate.min(cluster_rate); descendant.dependency_rate = descendant.dependency_rate.min(cluster_rate);
descendant.modified = true; descendant.modified = true;
// update modified priority if score has changed // update modified priority if score has changed
if !descendant.modified || descendant.score < current_score { if !descendant.modified || descendant.score() < current_score {
modified.push_decrease( modified.push_decrease(
descendant.uid, descendant.uid,
TxPriority { TxPriority {
uid: descendant.uid, uid: descendant.uid,
score: descendant.score, score: descendant.score(),
}, },
); );
} else if descendant.score > current_score { } else if descendant.score() > current_score {
modified.push_increase( modified.push_increase(
descendant.uid, descendant.uid,
TxPriority { TxPriority {
uid: descendant.uid, uid: descendant.uid,
score: descendant.score, score: descendant.score(),
}, },
); );
} }