Add acceleration support to rust gbt
This commit is contained in:
		
							parent
							
								
									6494f890fe
								
							
						
					
					
						commit
						ffc2b6c53c
					
				
							
								
								
									
										8
									
								
								backend/rust-gbt/index.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								backend/rust-gbt/index.d.ts
									
									
									
									
										vendored
									
									
								
							@ -12,6 +12,10 @@ export interface ThreadTransaction {
 | 
			
		||||
  effectiveFeePerVsize: number
 | 
			
		||||
  inputs: Array<number>
 | 
			
		||||
}
 | 
			
		||||
export interface ThreadAcceleration {
 | 
			
		||||
  uid: number
 | 
			
		||||
  delta: number
 | 
			
		||||
}
 | 
			
		||||
export class GbtGenerator {
 | 
			
		||||
  constructor()
 | 
			
		||||
  /**
 | 
			
		||||
@ -19,13 +23,13 @@ export class GbtGenerator {
 | 
			
		||||
   *
 | 
			
		||||
   * Rejects if the thread panics or if the Mutex is poisoned.
 | 
			
		||||
   */
 | 
			
		||||
  make(mempool: Array<ThreadTransaction>, maxUid: number): Promise<GbtResult>
 | 
			
		||||
  make(mempool: Array<ThreadTransaction>, accelerations: Array<ThreadAcceleration>, maxUid: number): Promise<GbtResult>
 | 
			
		||||
  /**
 | 
			
		||||
   * # Errors
 | 
			
		||||
   *
 | 
			
		||||
   * Rejects if the thread panics or if the Mutex is poisoned.
 | 
			
		||||
   */
 | 
			
		||||
  update(newTxs: Array<ThreadTransaction>, removeTxs: Array<number>, maxUid: number): Promise<GbtResult>
 | 
			
		||||
  update(newTxs: Array<ThreadTransaction>, removeTxs: Array<number>, accelerations: Array<ThreadAcceleration>, maxUid: number): Promise<GbtResult>
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * The result from calling the gbt function.
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    u32_hasher_types::{u32hashset_new, U32HasherState},
 | 
			
		||||
    ThreadTransaction,
 | 
			
		||||
    ThreadTransaction, thread_acceleration::ThreadAcceleration,
 | 
			
		||||
};
 | 
			
		||||
use std::{
 | 
			
		||||
    cmp::Ordering,
 | 
			
		||||
@ -88,37 +88,42 @@ impl Ord for AuditTransaction {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[inline]
 | 
			
		||||
fn calc_fee_rate(fee: f64, vsize: f64) -> f64 {
 | 
			
		||||
    fee / (if vsize == 0.0 { 1.0 } else { vsize })
 | 
			
		||||
fn calc_fee_rate(fee: u64, vsize: f64) -> f64 {
 | 
			
		||||
    (fee as f64) / (if vsize == 0.0 { 1.0 } else { vsize })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl AuditTransaction {
 | 
			
		||||
    pub fn from_thread_transaction(tx: &ThreadTransaction) -> Self {
 | 
			
		||||
    pub fn from_thread_transaction(tx: &ThreadTransaction, maybe_acceleration: Option<Option<&ThreadAcceleration>>) -> Self {
 | 
			
		||||
        let fee_delta = match maybe_acceleration {
 | 
			
		||||
            Some(Some(acceleration)) => acceleration.delta,
 | 
			
		||||
            _ => 0.0
 | 
			
		||||
        };
 | 
			
		||||
        let fee = (tx.fee as u64) + (fee_delta as u64);
 | 
			
		||||
        // rounded up to the nearest integer
 | 
			
		||||
        let is_adjusted = tx.weight < (tx.sigops * 20);
 | 
			
		||||
        let sigop_adjusted_vsize = ((tx.weight + 3) / 4).max(tx.sigops * 5);
 | 
			
		||||
        let sigop_adjusted_weight = tx.weight.max(tx.sigops * 20);
 | 
			
		||||
        let effective_fee_per_vsize = if is_adjusted {
 | 
			
		||||
            calc_fee_rate(tx.fee, f64::from(sigop_adjusted_weight) / 4.0)
 | 
			
		||||
        let effective_fee_per_vsize = if is_adjusted || fee_delta > 0.0 {
 | 
			
		||||
            calc_fee_rate(fee, f64::from(sigop_adjusted_weight) / 4.0)
 | 
			
		||||
        } else {
 | 
			
		||||
            tx.effective_fee_per_vsize
 | 
			
		||||
        };
 | 
			
		||||
        Self {
 | 
			
		||||
            uid: tx.uid,
 | 
			
		||||
            order: tx.order,
 | 
			
		||||
            fee: tx.fee as u64,
 | 
			
		||||
            fee,
 | 
			
		||||
            weight: tx.weight,
 | 
			
		||||
            sigop_adjusted_weight,
 | 
			
		||||
            sigop_adjusted_vsize,
 | 
			
		||||
            sigops: tx.sigops,
 | 
			
		||||
            adjusted_fee_per_vsize: calc_fee_rate(tx.fee, f64::from(sigop_adjusted_vsize)),
 | 
			
		||||
            adjusted_fee_per_vsize: calc_fee_rate(fee, f64::from(sigop_adjusted_vsize)),
 | 
			
		||||
            effective_fee_per_vsize,
 | 
			
		||||
            dependency_rate: f64::INFINITY,
 | 
			
		||||
            inputs: tx.inputs.clone(),
 | 
			
		||||
            relatives_set_flag: false,
 | 
			
		||||
            ancestors: u32hashset_new(),
 | 
			
		||||
            children: u32hashset_new(),
 | 
			
		||||
            ancestor_fee: tx.fee as u64,
 | 
			
		||||
            ancestor_fee: fee,
 | 
			
		||||
            ancestor_sigop_adjusted_weight: sigop_adjusted_weight,
 | 
			
		||||
            ancestor_sigop_adjusted_vsize: sigop_adjusted_vsize,
 | 
			
		||||
            ancestor_sigops: tx.sigops,
 | 
			
		||||
@ -156,7 +161,7 @@ impl AuditTransaction {
 | 
			
		||||
        // grows, so if we think of 0 as "grew infinitely" then dependency_rate would be
 | 
			
		||||
        // the smaller of the two. If either side is NaN, the other side is returned.
 | 
			
		||||
        self.dependency_rate.min(calc_fee_rate(
 | 
			
		||||
            self.ancestor_fee as f64,
 | 
			
		||||
            self.ancestor_fee,
 | 
			
		||||
            f64::from(self.ancestor_sigop_adjusted_weight) / 4.0,
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
@ -172,7 +177,7 @@ impl AuditTransaction {
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn calc_new_score(&mut self) {
 | 
			
		||||
        self.score = self.adjusted_fee_per_vsize.min(calc_fee_rate(
 | 
			
		||||
            self.ancestor_fee as f64,
 | 
			
		||||
            self.ancestor_fee,
 | 
			
		||||
            f64::from(self.ancestor_sigop_adjusted_vsize),
 | 
			
		||||
        ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ use tracing::{info, trace};
 | 
			
		||||
use crate::{
 | 
			
		||||
    audit_transaction::{partial_cmp_uid_score, AuditTransaction},
 | 
			
		||||
    u32_hasher_types::{u32hashset_new, u32priority_queue_with_capacity, U32HasherState},
 | 
			
		||||
    GbtResult, ThreadTransactionsMap,
 | 
			
		||||
    GbtResult, ThreadTransactionsMap, thread_acceleration::ThreadAcceleration,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const MAX_BLOCK_WEIGHT_UNITS: u32 = 4_000_000 - 4_000;
 | 
			
		||||
@ -53,7 +53,13 @@ impl Ord for TxPriority {
 | 
			
		||||
// TODO: Make gbt smaller to fix these lints.
 | 
			
		||||
#[allow(clippy::too_many_lines)]
 | 
			
		||||
#[allow(clippy::cognitive_complexity)]
 | 
			
		||||
pub fn gbt(mempool: &mut ThreadTransactionsMap, max_uid: usize) -> GbtResult {
 | 
			
		||||
pub fn gbt(mempool: &mut ThreadTransactionsMap, accelerations: &[ThreadAcceleration], max_uid: usize) -> GbtResult {
 | 
			
		||||
    let mut indexed_accelerations = Vec::with_capacity(max_uid + 1);
 | 
			
		||||
    indexed_accelerations.resize(max_uid + 1, None);
 | 
			
		||||
    for acceleration in accelerations {
 | 
			
		||||
        indexed_accelerations[acceleration.uid as usize] = Some(acceleration);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let mempool_len = mempool.len();
 | 
			
		||||
    let mut audit_pool: AuditPool = Vec::with_capacity(max_uid + 1);
 | 
			
		||||
    audit_pool.resize(max_uid + 1, None);
 | 
			
		||||
@ -63,7 +69,8 @@ pub fn gbt(mempool: &mut ThreadTransactionsMap, max_uid: usize) -> GbtResult {
 | 
			
		||||
 | 
			
		||||
    info!("Initializing working structs");
 | 
			
		||||
    for (uid, tx) in &mut *mempool {
 | 
			
		||||
        let audit_tx = AuditTransaction::from_thread_transaction(tx);
 | 
			
		||||
        let acceleration = indexed_accelerations.get(*uid as usize);
 | 
			
		||||
        let audit_tx = AuditTransaction::from_thread_transaction(tx, acceleration.copied());
 | 
			
		||||
        // Safety: audit_pool and mempool_stack must always contain the same transactions
 | 
			
		||||
        audit_pool[*uid as usize] = Some(ManuallyDrop::new(audit_tx));
 | 
			
		||||
        mempool_stack.push(*uid);
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@
 | 
			
		||||
use napi::bindgen_prelude::Result;
 | 
			
		||||
use napi_derive::napi;
 | 
			
		||||
use thread_transaction::ThreadTransaction;
 | 
			
		||||
use thread_acceleration::ThreadAcceleration;
 | 
			
		||||
use tracing::{debug, info, trace};
 | 
			
		||||
use tracing_log::LogTracer;
 | 
			
		||||
use tracing_subscriber::{EnvFilter, FmtSubscriber};
 | 
			
		||||
@ -19,6 +20,7 @@ use std::sync::{Arc, Mutex};
 | 
			
		||||
mod audit_transaction;
 | 
			
		||||
mod gbt;
 | 
			
		||||
mod thread_transaction;
 | 
			
		||||
mod thread_acceleration;
 | 
			
		||||
mod u32_hasher_types;
 | 
			
		||||
 | 
			
		||||
use u32_hasher_types::{u32hashmap_with_capacity, U32HasherState};
 | 
			
		||||
@ -74,10 +76,11 @@ impl GbtGenerator {
 | 
			
		||||
    ///
 | 
			
		||||
    /// Rejects if the thread panics or if the Mutex is poisoned.
 | 
			
		||||
    #[napi]
 | 
			
		||||
    pub async fn make(&self, mempool: Vec<ThreadTransaction>, max_uid: u32) -> Result<GbtResult> {
 | 
			
		||||
    pub async fn make(&self, mempool: Vec<ThreadTransaction>, accelerations: Vec<ThreadAcceleration>, max_uid: u32) -> Result<GbtResult> {
 | 
			
		||||
        trace!("make: Current State {:#?}", self.thread_transactions);
 | 
			
		||||
        run_task(
 | 
			
		||||
            Arc::clone(&self.thread_transactions),
 | 
			
		||||
            accelerations,
 | 
			
		||||
            max_uid as usize,
 | 
			
		||||
            move |map| {
 | 
			
		||||
                for tx in mempool {
 | 
			
		||||
@ -96,11 +99,13 @@ impl GbtGenerator {
 | 
			
		||||
        &self,
 | 
			
		||||
        new_txs: Vec<ThreadTransaction>,
 | 
			
		||||
        remove_txs: Vec<u32>,
 | 
			
		||||
        accelerations: Vec<ThreadAcceleration>,
 | 
			
		||||
        max_uid: u32,
 | 
			
		||||
    ) -> Result<GbtResult> {
 | 
			
		||||
        trace!("update: Current State {:#?}", self.thread_transactions);
 | 
			
		||||
        run_task(
 | 
			
		||||
            Arc::clone(&self.thread_transactions),
 | 
			
		||||
            accelerations,
 | 
			
		||||
            max_uid as usize,
 | 
			
		||||
            move |map| {
 | 
			
		||||
                for tx in new_txs {
 | 
			
		||||
@ -141,6 +146,7 @@ pub struct GbtResult {
 | 
			
		||||
/// to the `HashMap` as the only argument. (A move closure is recommended to meet the bounds)
 | 
			
		||||
async fn run_task<F>(
 | 
			
		||||
    thread_transactions: Arc<Mutex<ThreadTransactionsMap>>,
 | 
			
		||||
    accelerations: Vec<ThreadAcceleration>,
 | 
			
		||||
    max_uid: usize,
 | 
			
		||||
    callback: F,
 | 
			
		||||
) -> Result<GbtResult>
 | 
			
		||||
@ -159,7 +165,7 @@ where
 | 
			
		||||
        callback(&mut map);
 | 
			
		||||
 | 
			
		||||
        info!("Starting gbt algorithm for {} elements...", map.len());
 | 
			
		||||
        let result = gbt::gbt(&mut map, max_uid);
 | 
			
		||||
        let result = gbt::gbt(&mut map, &accelerations, max_uid);
 | 
			
		||||
        info!("Finished gbt algorithm for {} elements...", map.len());
 | 
			
		||||
 | 
			
		||||
        debug!(
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import { GbtGenerator, GbtResult, ThreadTransaction as RustThreadTransaction } from '../../rust-gbt';
 | 
			
		||||
import { GbtGenerator, GbtResult, ThreadTransaction as RustThreadTransaction, ThreadAcceleration as RustThreadAcceleration } from '../../rust-gbt';
 | 
			
		||||
import logger from '../logger';
 | 
			
		||||
import { MempoolBlock, MempoolTransactionExtended, TransactionStripped, MempoolBlockWithTransactions, MempoolBlockDelta, Ancestor, CompactThreadTransaction, EffectiveFeeStats, PoolTag } from '../mempool.interfaces';
 | 
			
		||||
import { Common, OnlineFeeStatsCalculator } from './common';
 | 
			
		||||
@ -171,7 +171,7 @@ class MempoolBlocks {
 | 
			
		||||
    for (let i = 0; i < Math.max(mempoolBlocks.length, prevBlocks.length); i++) {
 | 
			
		||||
      let added: TransactionStripped[] = [];
 | 
			
		||||
      let removed: string[] = [];
 | 
			
		||||
      const changed: { txid: string, rate: number | undefined, acc: number | undefined }[] = [];
 | 
			
		||||
      const changed: { txid: string, rate: number | undefined, acc: boolean | undefined }[] = [];
 | 
			
		||||
      if (mempoolBlocks[i] && !prevBlocks[i]) {
 | 
			
		||||
        added = mempoolBlocks[i].transactions;
 | 
			
		||||
      } else if (!mempoolBlocks[i] && prevBlocks[i]) {
 | 
			
		||||
@ -265,7 +265,7 @@ class MempoolBlocks {
 | 
			
		||||
      // clean up thread error listener
 | 
			
		||||
      this.txSelectionWorker?.removeListener('error', threadErrorListener);
 | 
			
		||||
 | 
			
		||||
      const processed = this.processBlockTemplates(newMempool, blocks, null, Object.entries(rates), Object.values(clusters), accelerations, saveResults);
 | 
			
		||||
      const processed = this.processBlockTemplates(newMempool, blocks, null, Object.entries(rates), Object.values(clusters), accelerations, accelerationPool, saveResults);
 | 
			
		||||
 | 
			
		||||
      logger.debug(`makeBlockTemplates completed in ${(Date.now() - start)/1000} seconds`);
 | 
			
		||||
 | 
			
		||||
@ -325,7 +325,7 @@ class MempoolBlocks {
 | 
			
		||||
      // clean up thread error listener
 | 
			
		||||
      this.txSelectionWorker?.removeListener('error', threadErrorListener);
 | 
			
		||||
 | 
			
		||||
      this.processBlockTemplates(newMempool, blocks, null, Object.entries(rates), Object.values(clusters), accelerations, saveResults);
 | 
			
		||||
      this.processBlockTemplates(newMempool, blocks, null, Object.entries(rates), Object.values(clusters), accelerations, null, saveResults);
 | 
			
		||||
      logger.debug(`updateBlockTemplates completed in ${(Date.now() - start) / 1000} seconds`);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      logger.err('updateBlockTemplates failed. ' + (e instanceof Error ? e.message : e));
 | 
			
		||||
@ -337,7 +337,7 @@ class MempoolBlocks {
 | 
			
		||||
    this.rustGbtGenerator = new GbtGenerator();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async $rustMakeBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }, saveResults: boolean = false): Promise<MempoolBlockWithTransactions[]> {
 | 
			
		||||
  private async $rustMakeBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }, saveResults: boolean = false, useAccelerations: boolean = false, accelerationPool?: number): Promise<MempoolBlockWithTransactions[]> {
 | 
			
		||||
    const start = Date.now();
 | 
			
		||||
 | 
			
		||||
    // reset mempool short ids
 | 
			
		||||
@ -353,16 +353,25 @@ class MempoolBlocks {
 | 
			
		||||
      tx.inputs = tx.vin.map(v => this.getUid(newMempool[v.txid])).filter(uid => (uid !== null && uid !== undefined)) as number[];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const accelerations = useAccelerations ? mempool.getAccelerations() : {};
 | 
			
		||||
    const acceleratedList = accelerationPool ? Object.values(accelerations).filter(acc => newMempool[acc.txid] && acc.pools.includes(accelerationPool)) : Object.values(accelerations).filter(acc => newMempool[acc.txid]);
 | 
			
		||||
    const convertedAccelerations = acceleratedList.map(acc => {
 | 
			
		||||
      return {
 | 
			
		||||
        uid: this.getUid(newMempool[acc.txid]),
 | 
			
		||||
        delta: acc.feeDelta,
 | 
			
		||||
      };
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // run the block construction algorithm in a separate thread, and wait for a result
 | 
			
		||||
    const rustGbt = saveResults ? this.rustGbtGenerator : new GbtGenerator();
 | 
			
		||||
    try {
 | 
			
		||||
      const { blocks, blockWeights, rates, clusters } = this.convertNapiResultTxids(
 | 
			
		||||
        await rustGbt.make(Object.values(newMempool) as RustThreadTransaction[], this.nextUid),
 | 
			
		||||
        await rustGbt.make(Object.values(newMempool) as RustThreadTransaction[], convertedAccelerations as RustThreadAcceleration[], this.nextUid),
 | 
			
		||||
      );
 | 
			
		||||
      if (saveResults) {
 | 
			
		||||
        this.rustInitialized = true;
 | 
			
		||||
      }
 | 
			
		||||
      const processed = this.processBlockTemplates(newMempool, blocks, blockWeights, rates, clusters, {}, saveResults);
 | 
			
		||||
      const processed = this.processBlockTemplates(newMempool, blocks, blockWeights, rates, clusters, accelerations, accelerationPool, saveResults);
 | 
			
		||||
      logger.debug(`RUST makeBlockTemplates completed in ${(Date.now() - start)/1000} seconds`);
 | 
			
		||||
      return processed;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
@ -374,19 +383,20 @@ class MempoolBlocks {
 | 
			
		||||
    return this.mempoolBlocks;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $oneOffRustBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }): Promise<MempoolBlockWithTransactions[]> {
 | 
			
		||||
    return this.$rustMakeBlockTemplates(newMempool, false);
 | 
			
		||||
  public async $oneOffRustBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }, useAccelerations: boolean, accelerationPool?: number): Promise<MempoolBlockWithTransactions[]> {
 | 
			
		||||
    return this.$rustMakeBlockTemplates(newMempool, false, useAccelerations, accelerationPool);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $rustUpdateBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }, mempoolSize: number, added: MempoolTransactionExtended[], removed: MempoolTransactionExtended[]): Promise<void> {
 | 
			
		||||
  public async $rustUpdateBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }, mempoolSize: number, added: MempoolTransactionExtended[], removed: MempoolTransactionExtended[], useAccelerations: boolean, accelerationPool?: number): Promise<void> {
 | 
			
		||||
    // GBT optimization requires that uids never get too sparse
 | 
			
		||||
    // as a sanity check, we should also explicitly prevent uint32 uid overflow
 | 
			
		||||
    if (this.nextUid + added.length >= Math.min(Math.max(262144, 2 * mempoolSize), MAX_UINT32)) {
 | 
			
		||||
      this.resetRustGbt();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!this.rustInitialized) {
 | 
			
		||||
      // need to reset the worker
 | 
			
		||||
      await this.$rustMakeBlockTemplates(newMempool, true);
 | 
			
		||||
      await this.$rustMakeBlockTemplates(newMempool, true, useAccelerations, accelerationPool);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -401,12 +411,22 @@ class MempoolBlocks {
 | 
			
		||||
    }
 | 
			
		||||
    const removedUids = removed.map(tx => this.getUid(tx)).filter(uid => (uid !== null && uid !== undefined)) as number[];
 | 
			
		||||
 | 
			
		||||
    const accelerations = useAccelerations ? mempool.getAccelerations() : {};
 | 
			
		||||
    const acceleratedList = accelerationPool ? Object.values(accelerations).filter(acc => newMempool[acc.txid] && acc.pools.includes(accelerationPool)) : Object.values(accelerations).filter(acc => newMempool[acc.txid]);
 | 
			
		||||
    const convertedAccelerations = acceleratedList.map(acc => {
 | 
			
		||||
      return {
 | 
			
		||||
        uid: this.getUid(newMempool[acc.txid]),
 | 
			
		||||
        delta: acc.feeDelta,
 | 
			
		||||
      };
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // run the block construction algorithm in a separate thread, and wait for a result
 | 
			
		||||
    try {
 | 
			
		||||
      const { blocks, blockWeights, rates, clusters } = this.convertNapiResultTxids(
 | 
			
		||||
        await this.rustGbtGenerator.update(
 | 
			
		||||
          added as RustThreadTransaction[],
 | 
			
		||||
          removedUids,
 | 
			
		||||
          convertedAccelerations as RustThreadAcceleration[],
 | 
			
		||||
          this.nextUid,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
@ -414,7 +434,7 @@ class MempoolBlocks {
 | 
			
		||||
      if (mempoolSize !== resultMempoolSize) {
 | 
			
		||||
        throw new Error('GBT returned wrong number of transactions, cache is probably out of sync');
 | 
			
		||||
      } else {
 | 
			
		||||
        this.processBlockTemplates(newMempool, blocks, blockWeights, rates, clusters, {}, true);
 | 
			
		||||
        this.processBlockTemplates(newMempool, blocks, blockWeights, rates, clusters, accelerations, accelerationPool, true);
 | 
			
		||||
      }
 | 
			
		||||
      this.removeUids(removedUids);
 | 
			
		||||
      logger.debug(`RUST updateBlockTemplates completed in ${(Date.now() - start)/1000} seconds`);
 | 
			
		||||
@ -424,7 +444,7 @@ class MempoolBlocks {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private processBlockTemplates(mempool: { [txid: string]: MempoolTransactionExtended }, blocks: string[][], blockWeights: number[] | null, rates: [string, number][], clusters: string[][], accelerations, saveResults): MempoolBlockWithTransactions[] {
 | 
			
		||||
  private processBlockTemplates(mempool: { [txid: string]: MempoolTransactionExtended }, blocks: string[][], blockWeights: number[] | null, rates: [string, number][], clusters: string[][], accelerations, accelerationPool, saveResults): MempoolBlockWithTransactions[] {
 | 
			
		||||
    for (const [txid, rate] of rates) {
 | 
			
		||||
      if (txid in mempool) {
 | 
			
		||||
        mempool[txid].effectiveFeePerVsize = rate;
 | 
			
		||||
@ -503,7 +523,15 @@ class MempoolBlocks {
 | 
			
		||||
            mempoolTx.cpfpChecked = true;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          mempoolTx.acceleration = accelerations[txid];
 | 
			
		||||
          const acceleration = accelerations[txid];
 | 
			
		||||
          if (acceleration && (!accelerationPool || acceleration.pools.includes(accelerationPool))) {
 | 
			
		||||
            mempoolTx.acceleration = true;
 | 
			
		||||
            for (const ancestor of mempoolTx.ancestors || []) {
 | 
			
		||||
              mempool[ancestor.txid].acceleration = true;
 | 
			
		||||
            }
 | 
			
		||||
          } else {
 | 
			
		||||
            delete mempoolTx.acceleration;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          // online calculation of stack-of-blocks fee stats
 | 
			
		||||
          if (hasBlockStack && blockIndex === lastBlockIndex && feeStatsCalculator) {
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@ import loadingIndicators from './loading-indicators';
 | 
			
		||||
import bitcoinClient from './bitcoin/bitcoin-client';
 | 
			
		||||
import bitcoinSecondClient from './bitcoin/bitcoin-second-client';
 | 
			
		||||
import rbfCache from './rbf-cache';
 | 
			
		||||
import accelerationApi from './services/acceleration';
 | 
			
		||||
import accelerationApi, { Acceleration } from './services/acceleration';
 | 
			
		||||
 | 
			
		||||
class Mempool {
 | 
			
		||||
  private inSync: boolean = false;
 | 
			
		||||
 | 
			
		||||
@ -174,7 +174,7 @@ class WebsocketHandler {
 | 
			
		||||
              }
 | 
			
		||||
              const tx = memPool.getMempool()[trackTxid];
 | 
			
		||||
              if (tx && tx.position) {
 | 
			
		||||
                const position: { block: number, vsize: number, accelerated?: number } = {
 | 
			
		||||
                const position: { block: number, vsize: number, accelerated?: boolean } = {
 | 
			
		||||
                  ...tx.position
 | 
			
		||||
                };
 | 
			
		||||
                if (tx.acceleration) {
 | 
			
		||||
@ -397,7 +397,7 @@ class WebsocketHandler {
 | 
			
		||||
 | 
			
		||||
    if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) {
 | 
			
		||||
      if (config.MEMPOOL.RUST_GBT) {
 | 
			
		||||
        await mempoolBlocks.$rustUpdateBlockTemplates(newMempool, mempoolSize, newTransactions, deletedTransactions);
 | 
			
		||||
        await mempoolBlocks.$rustUpdateBlockTemplates(newMempool, mempoolSize, newTransactions, deletedTransactions, true,);
 | 
			
		||||
      } else {
 | 
			
		||||
        await mempoolBlocks.$updateBlockTemplates(newMempool, newTransactions, deletedTransactions, accelerationDelta, true, config.MEMPOOL_SERVICES.ACCELERATIONS);
 | 
			
		||||
      }
 | 
			
		||||
@ -666,7 +666,7 @@ class WebsocketHandler {
 | 
			
		||||
        auditMempool = deepClone(_memPool);
 | 
			
		||||
        if (config.MEMPOOL.ADVANCED_GBT_AUDIT) {
 | 
			
		||||
          if (config.MEMPOOL.RUST_GBT) {
 | 
			
		||||
            projectedBlocks = await mempoolBlocks.$oneOffRustBlockTemplates(auditMempool);
 | 
			
		||||
            projectedBlocks = await mempoolBlocks.$oneOffRustBlockTemplates(auditMempool, isAccelerated, block.extras.pool.id);
 | 
			
		||||
          } else {
 | 
			
		||||
            projectedBlocks = await mempoolBlocks.$makeBlockTemplates(auditMempool, false, isAccelerated, block.extras.pool.id);
 | 
			
		||||
          }
 | 
			
		||||
@ -739,7 +739,7 @@ class WebsocketHandler {
 | 
			
		||||
 | 
			
		||||
    if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) {
 | 
			
		||||
      if (config.MEMPOOL.RUST_GBT) {
 | 
			
		||||
        await mempoolBlocks.$rustUpdateBlockTemplates(_memPool, Object.keys(_memPool).length, [], transactions);
 | 
			
		||||
        await mempoolBlocks.$rustUpdateBlockTemplates(_memPool, Object.keys(_memPool).length, [], transactions, true);
 | 
			
		||||
      } else {
 | 
			
		||||
        await mempoolBlocks.$makeBlockTemplates(_memPool, true, config.MEMPOOL_SERVICES.ACCELERATIONS);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -92,7 +92,7 @@ export interface TransactionExtended extends IEsploraApi.Transaction {
 | 
			
		||||
    block: number,
 | 
			
		||||
    vsize: number,
 | 
			
		||||
  };
 | 
			
		||||
  acceleration?: number;
 | 
			
		||||
  acceleration?: boolean;
 | 
			
		||||
  uid?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -184,7 +184,7 @@ export interface TransactionStripped {
 | 
			
		||||
  fee: number;
 | 
			
		||||
  vsize: number;
 | 
			
		||||
  value: number;
 | 
			
		||||
  acc?: number;
 | 
			
		||||
  acc?: boolean;
 | 
			
		||||
  rate?: number; // effective fee rate
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -116,6 +116,7 @@ class AuditReplication {
 | 
			
		||||
      freshTxs: auditSummary.freshTxs || [],
 | 
			
		||||
      sigopTxs: auditSummary.sigopTxs || [],
 | 
			
		||||
      fullrbfTxs: auditSummary.fullrbfTxs || [],
 | 
			
		||||
      acceleratedTxs: auditSummary.acceleratedTxs || [],
 | 
			
		||||
      matchRate: auditSummary.matchRate,
 | 
			
		||||
      expectedFees: auditSummary.expectedFees,
 | 
			
		||||
      expectedWeight: auditSummary.expectedWeight,
 | 
			
		||||
 | 
			
		||||
@ -147,7 +147,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  update(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: number | undefined }[], direction: string = 'left', resetLayout: boolean = false): void {
 | 
			
		||||
  update(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: boolean | undefined }[], direction: string = 'left', resetLayout: boolean = false): void {
 | 
			
		||||
    if (this.scene) {
 | 
			
		||||
      this.scene.update(add, remove, change, direction, resetLayout);
 | 
			
		||||
      this.start();
 | 
			
		||||
 | 
			
		||||
@ -150,7 +150,7 @@ export default class BlockScene {
 | 
			
		||||
    this.updateAll(startTime, 200, direction);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  update(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: number | undefined }[], direction: string = 'left', resetLayout: boolean = false): void {
 | 
			
		||||
  update(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: boolean | undefined }[], direction: string = 'left', resetLayout: boolean = false): void {
 | 
			
		||||
    const startTime = performance.now();
 | 
			
		||||
    const removed = this.removeBatch(remove, startTime, direction);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -38,7 +38,7 @@ export default class TxView implements TransactionStripped {
 | 
			
		||||
  vsize: number;
 | 
			
		||||
  value: number;
 | 
			
		||||
  feerate: number;
 | 
			
		||||
  acc?: number;
 | 
			
		||||
  acc?: boolean;
 | 
			
		||||
  rate?: number;
 | 
			
		||||
  status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'freshcpfp' | 'added' | 'censored' | 'selected' | 'rbf' | 'accelerated';
 | 
			
		||||
  context?: 'projected' | 'actual';
 | 
			
		||||
 | 
			
		||||
@ -64,7 +64,7 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const samples = [];
 | 
			
		||||
    const txs = this.transactions.map(tx => { return { vsize: tx.vsize, rate: tx.rate || (tx.fee / tx.vsize) }; }).sort((a, b) => { return b.rate - a.rate; });
 | 
			
		||||
    const txs = this.transactions.filter(tx => !tx.acc).map(tx => { return { vsize: tx.vsize, rate: tx.rate || (tx.fee / tx.vsize) }; }).sort((a, b) => { return b.rate - a.rate; });
 | 
			
		||||
    const maxBlockVSize = this.stateService.env.BLOCK_WEIGHT_UNITS / 4;
 | 
			
		||||
    const sampleInterval = maxBlockVSize / this.numSamples;
 | 
			
		||||
    let cumVSize = 0;
 | 
			
		||||
 | 
			
		||||
@ -70,7 +70,7 @@ export interface MempoolBlockWithTransactions extends MempoolBlock {
 | 
			
		||||
export interface MempoolBlockDelta {
 | 
			
		||||
  added: TransactionStripped[],
 | 
			
		||||
  removed: string[],
 | 
			
		||||
  changed?: { txid: string, rate: number | undefined, acc: number | undefined }[];
 | 
			
		||||
  changed?: { txid: string, rate: number | undefined, acc: boolean | undefined }[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MempoolInfo {
 | 
			
		||||
@ -88,7 +88,7 @@ export interface TransactionStripped {
 | 
			
		||||
  fee: number;
 | 
			
		||||
  vsize: number;
 | 
			
		||||
  value: number;
 | 
			
		||||
  acc?: number; // acceleration delta
 | 
			
		||||
  acc?: boolean; // is accelerated?
 | 
			
		||||
  rate?: number; // effective fee rate
 | 
			
		||||
  status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'freshcpfp' | 'added' | 'censored' | 'selected' | 'rbf' | 'accelerated';
 | 
			
		||||
  context?: 'projected' | 'actual';
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user