2023-06-24 19:28:19 -07:00
|
|
|
use napi::bindgen_prelude::*;
|
2023-06-24 11:21:58 -07:00
|
|
|
use napi_derive::napi;
|
|
|
|
|
2023-06-23 18:37:03 -04:00
|
|
|
use std::collections::HashMap;
|
2023-06-24 23:05:43 -07:00
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use utils::U32HasherState;
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-23 20:41:39 -04:00
|
|
|
mod audit_transaction;
|
2023-06-23 16:42:58 -04:00
|
|
|
mod gbt;
|
|
|
|
mod thread_transaction;
|
2023-06-23 18:37:03 -04:00
|
|
|
mod utils;
|
|
|
|
use thread_transaction::ThreadTransaction;
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-24 23:05:43 -07:00
|
|
|
type ThreadTransactionsMap = HashMap<u32, ThreadTransaction, U32HasherState>;
|
2023-06-23 18:37:03 -04:00
|
|
|
|
2023-06-24 23:05:43 -07:00
|
|
|
#[napi]
|
|
|
|
pub struct GbtGenerator {
|
|
|
|
thread_transactions: Arc<Mutex<ThreadTransactionsMap>>,
|
2023-06-23 18:37:03 -04:00
|
|
|
}
|
|
|
|
|
2023-06-24 23:05:43 -07:00
|
|
|
#[napi]
|
|
|
|
impl GbtGenerator {
|
|
|
|
#[napi(constructor)]
|
|
|
|
#[allow(clippy::new_without_default)]
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
thread_transactions: Arc::new(Mutex::new(HashMap::with_capacity_and_hasher(
|
|
|
|
2048,
|
|
|
|
U32HasherState,
|
|
|
|
))),
|
2023-06-24 19:28:19 -07:00
|
|
|
}
|
2023-06-23 20:41:39 -04:00
|
|
|
}
|
2023-06-23 16:42:58 -04:00
|
|
|
|
2023-06-24 23:05:43 -07:00
|
|
|
#[napi]
|
|
|
|
pub async fn make(&self, mempool_buffer: Uint8Array) -> Result<GbtResult> {
|
|
|
|
run_task(Arc::clone(&self.thread_transactions), move |map| {
|
|
|
|
for tx in ThreadTransaction::batch_from_buffer(&mempool_buffer) {
|
|
|
|
map.insert(tx.uid, tx);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
#[napi]
|
|
|
|
pub async fn update(&self, new_txs: Uint8Array, remove_txs: Uint8Array) -> Result<GbtResult> {
|
|
|
|
run_task(Arc::clone(&self.thread_transactions), move |map| {
|
|
|
|
for tx in ThreadTransaction::batch_from_buffer(&new_txs) {
|
|
|
|
map.insert(tx.uid, tx);
|
|
|
|
}
|
|
|
|
for txid in &utils::txids_from_buffer(&remove_txs) {
|
|
|
|
map.remove(txid);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.await
|
|
|
|
}
|
2023-06-23 20:41:39 -04:00
|
|
|
}
|
|
|
|
|
2023-06-24 11:21:58 -07:00
|
|
|
/// The result from calling the gbt function.
|
|
|
|
///
|
|
|
|
/// This tuple contains the following:
|
|
|
|
/// blocks: A 2D Vector of transaction IDs (u32), the inner Vecs each represent a block.
|
|
|
|
/// clusters: A 2D Vector of transaction IDs representing clusters of dependent mempool transactions
|
|
|
|
/// rates: A Vector of tuples containing transaction IDs (u32) and effective fee per vsize (f64)
|
|
|
|
#[napi(constructor)]
|
|
|
|
pub struct GbtResult {
|
|
|
|
pub blocks: Vec<Vec<u32>>,
|
|
|
|
pub clusters: Vec<Vec<u32>>,
|
|
|
|
pub rates: Vec<Vec<f64>>, // Tuples not supported. u32 fits inside f64
|
|
|
|
}
|
2023-06-23 20:41:39 -04:00
|
|
|
|
2023-06-24 23:05:43 -07:00
|
|
|
/// All on another thread, this runs an arbitrary task in between
|
|
|
|
/// taking the lock and running gbt.
|
|
|
|
///
|
|
|
|
/// Rather than filling / updating the HashMap on the main thread,
|
|
|
|
/// this allows for HashMap modifying tasks to be run before running and returning gbt results.
|
|
|
|
///
|
|
|
|
/// `thread_transactions` is a cloned Arc of the Mutex for the HashMap state.
|
|
|
|
/// `callback` is a `'static + Send` `FnOnce` closure/function that takes a mutable reference
|
|
|
|
/// 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>>,
|
|
|
|
callback: F,
|
|
|
|
) -> Result<GbtResult>
|
|
|
|
where
|
|
|
|
F: FnOnce(&mut ThreadTransactionsMap) + Send + 'static,
|
|
|
|
{
|
2023-06-24 19:28:19 -07:00
|
|
|
let handle = napi::tokio::task::spawn_blocking(move || {
|
2023-06-24 23:05:43 -07:00
|
|
|
let mut map = thread_transactions
|
2023-06-24 19:28:19 -07:00
|
|
|
.lock()
|
|
|
|
.map_err(|_| napi::Error::from_reason("THREAD_TRANSACTIONS Mutex poisoned"))?;
|
2023-06-24 23:05:43 -07:00
|
|
|
callback(&mut map);
|
2023-06-24 19:28:19 -07:00
|
|
|
gbt::gbt(&mut map).ok_or_else(|| napi::Error::from_reason("gbt failed"))
|
2023-06-23 16:42:58 -04:00
|
|
|
});
|
|
|
|
|
2023-06-24 12:21:33 -07:00
|
|
|
handle
|
2023-06-24 19:28:19 -07:00
|
|
|
.await
|
2023-06-24 12:21:33 -07:00
|
|
|
.map_err(|_| napi::Error::from_reason("thread panicked"))?
|
2023-06-23 16:42:58 -04:00
|
|
|
}
|