From 0e0088182680d66eb63e0f5b1e751574a4ae3f60 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 23 Jun 2023 20:41:39 -0400 Subject: [PATCH] Refactor rust code for style --- backend/rust-gbt/src/audit_transaction.rs | 74 +-- backend/rust-gbt/src/gbt.rs | 566 +++++++++++---------- backend/rust-gbt/src/lib.rs | 170 ++++--- backend/rust-gbt/src/thread_transaction.rs | 76 ++- backend/rust-gbt/src/utils.rs | 19 +- 5 files changed, 480 insertions(+), 425 deletions(-) diff --git a/backend/rust-gbt/src/audit_transaction.rs b/backend/rust-gbt/src/audit_transaction.rs index 4b23b9a21..df6371456 100644 --- a/backend/rust-gbt/src/audit_transaction.rs +++ b/backend/rust-gbt/src/audit_transaction.rs @@ -1,53 +1,57 @@ -use std::{collections::{HashSet}, hash::{Hash, Hasher}, cmp::Ordering}; +use std::{ + cmp::Ordering, + collections::HashSet, + hash::{Hash, Hasher}, +}; #[derive(Clone)] pub struct AuditTransaction { - pub uid: u32, - pub fee: u64, - pub weight: u32, - pub sigops: u32, - pub fee_per_vsize: f64, - pub effective_fee_per_vsize: f64, - pub dependency_rate: f64, - pub inputs: Vec, - pub is_relatives_set: bool, - pub ancestors: HashSet, - pub children: HashSet, - pub ancestor_fee: u64, - pub ancestor_weight: u32, - pub ancestor_sigops: u32, - pub score: f64, - pub used: bool, - pub modified: bool, - pub dirty: bool, + pub uid: u32, + pub fee: u64, + pub weight: u32, + pub sigops: u32, + pub fee_per_vsize: f64, + pub effective_fee_per_vsize: f64, + pub dependency_rate: f64, + pub inputs: Vec, + pub relatives_set_flag: bool, + pub ancestors: HashSet, + pub children: HashSet, + pub ancestor_fee: u64, + pub ancestor_weight: u32, + pub ancestor_sigops: u32, + pub score: f64, + pub used: bool, + pub modified: bool, + pub dirty: bool, } impl Hash for AuditTransaction { - fn hash(&self, state: &mut H) { - self.uid.hash(state); - } + fn hash(&self, state: &mut H) { + self.uid.hash(state); + } } impl PartialEq for AuditTransaction { - fn eq(&self, other: &Self) -> bool { - self.uid == other.uid - } + fn eq(&self, other: &Self) -> bool { + self.uid == other.uid + } } impl Eq for AuditTransaction {} impl PartialOrd for AuditTransaction { - fn partial_cmp(&self, other: &AuditTransaction) -> Option { - if self.score == other.score { - return Some(self.uid.cmp(&other.uid)); - } else { - return self.score.partial_cmp(&other.score); + fn partial_cmp(&self, other: &AuditTransaction) -> Option { + if self.score == other.score { + return Some(self.uid.cmp(&other.uid)); + } else { + return self.score.partial_cmp(&other.score); + } } - } } impl Ord for AuditTransaction { - fn cmp(&self, other: &AuditTransaction) -> Ordering { - self.partial_cmp(other).unwrap() - } -} \ No newline at end of file + fn cmp(&self, other: &AuditTransaction) -> Ordering { + self.partial_cmp(other).unwrap() + } +} diff --git a/backend/rust-gbt/src/gbt.rs b/backend/rust-gbt/src/gbt.rs index aecf2bff0..ff491d52c 100644 --- a/backend/rust-gbt/src/gbt.rs +++ b/backend/rust-gbt/src/gbt.rs @@ -1,41 +1,45 @@ +use priority_queue::PriorityQueue; use std::cmp::Ordering; use std::collections::{HashMap, HashSet, VecDeque}; use std::f64::INFINITY; -use priority_queue::PriorityQueue; -use crate::thread_transaction::{ThreadTransaction}; -use crate::audit_transaction::{AuditTransaction}; +use crate::audit_transaction::AuditTransaction; +use crate::thread_transaction::ThreadTransaction; const BLOCK_WEIGHT_UNITS: u32 = 4_000_000; const BLOCK_SIGOPS: u32 = 80_000; +const BLOCK_RESERVED_WEIGHT: u32 = 4_000; +const MAX_BLOCKS: usize = 8; struct TxPriority { - uid: u32, - score: f64, + uid: u32, + score: f64, } impl PartialEq for TxPriority { - fn eq(&self, other: &Self) -> bool { - self.uid == other.uid - } + fn eq(&self, other: &Self) -> bool { + self.uid == other.uid + } } impl Eq for TxPriority {} impl PartialOrd for TxPriority { - fn partial_cmp(&self, other: &TxPriority) -> Option { - if self.score == other.score { - return Some(self.uid.cmp(&other.uid)); - } else { - return other.score.partial_cmp(&self.score); + fn partial_cmp(&self, other: &TxPriority) -> Option { + if self.score == other.score { + return Some(self.uid.cmp(&other.uid)); + } else { + return other.score.partial_cmp(&self.score); + } } - } } impl Ord for TxPriority { - fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other).unwrap() - } + fn cmp(&self, other: &Self) -> Ordering { + self.partial_cmp(other).unwrap() + } } -pub fn gbt(mempool: &mut HashMap) -> (Vec>, Vec<(u32, f64)>, Vec>) { - return make_block_templates(mempool); +pub fn gbt( + mempool: &mut HashMap, +) -> Option<(Vec>, Vec<(u32, f64)>, Vec>)> { + make_block_templates(mempool) } /* @@ -43,264 +47,310 @@ pub fn gbt(mempool: &mut HashMap) -> (Vec>, Vec< * (see BlockAssembler in https://github.com/bitcoin/bitcoin/blob/master/src/node/miner.cpp) * Ported from https://github.com/mempool/mempool/blob/master/backend/src/api/tx-selection-worker.ts */ -fn make_block_templates(mempool: &mut HashMap) -> (Vec>, Vec<(u32, f64)>, Vec>) { - let mut audit_pool: HashMap = HashMap::new(); - let mut mempool_array: VecDeque = VecDeque::new(); - let mut cluster_array: Vec> = Vec::new(); +fn make_block_templates( + mempool: &mut HashMap, +) -> Option<(Vec>, Vec<(u32, f64)>, Vec>)> { + let mut audit_pool: HashMap = HashMap::new(); + let mut mempool_array: VecDeque = VecDeque::new(); + let mut cluster_array: Vec> = Vec::new(); - // Initialize working structs - for (uid, tx) in mempool { - let audit_tx = AuditTransaction { - uid: tx.uid, - fee: tx.fee, - weight: tx.weight, - sigops: tx.sigops, - fee_per_vsize: tx.fee_per_vsize, - effective_fee_per_vsize: tx.effective_fee_per_vsize, - dependency_rate: INFINITY, - inputs: tx.inputs.clone(), - is_relatives_set: false, - ancestors: HashSet::new(), - children: HashSet::new(), - ancestor_fee: tx.fee, - ancestor_weight: tx.weight, - ancestor_sigops: tx.sigops, - score: 0.0, - used: false, - modified: false, - dirty: false, - }; - audit_pool.insert(audit_tx.uid, audit_tx); - mempool_array.push_back(*uid); - } - - // Build relatives graph & calculate ancestor scores - for txid in &mempool_array { - set_relatives(*txid, &mut audit_pool); - } - - // Sort by descending ancestor score - mempool_array.make_contiguous().sort_unstable_by(|a, b| { - let a_tx = audit_pool.get(a).unwrap(); - let b_tx = audit_pool.get(b).unwrap(); - b_tx.cmp(a_tx) - }); - - // Build blocks by greedily choosing the highest feerate package - // (i.e. the package rooted in the transaction with the best ancestor score) - let mut blocks: Vec> = Vec::new(); - let mut block_weight: u32 = 4000; - let mut block_sigops: u32 = 0; - let mut transactions: Vec = Vec::new(); - let mut modified: PriorityQueue = PriorityQueue::new(); - let mut overflow: Vec = Vec::new(); - let mut failures = 0; - while mempool_array.len() > 0 || !modified.is_empty() { - let next_txid: u32; - if modified.is_empty() { - next_txid = mempool_array.pop_front().unwrap(); - } else if mempool_array.len() == 0 { - next_txid = modified.pop().unwrap().0; - } else { - let next_array_txid = mempool_array.front().unwrap(); - let next_modified_txid = modified.peek().unwrap().0; - let array_tx: &AuditTransaction = audit_pool.get(next_array_txid).unwrap(); - let modified_tx: &AuditTransaction = audit_pool.get(next_modified_txid).unwrap(); - match array_tx.cmp(&modified_tx) { - std::cmp::Ordering::Equal | std::cmp::Ordering::Greater => { - next_txid = mempool_array.pop_front().unwrap(); - } - std::cmp::Ordering::Less => { - next_txid = modified.pop().unwrap().0; - } - } - } - let next_tx: AuditTransaction = audit_pool.get(&next_txid).unwrap().clone(); - - if next_tx.used { - continue; + // Initialize working structs + for (uid, tx) in mempool { + let audit_tx = AuditTransaction { + uid: tx.uid, + fee: tx.fee, + weight: tx.weight, + sigops: tx.sigops, + fee_per_vsize: tx.fee_per_vsize, + effective_fee_per_vsize: tx.effective_fee_per_vsize, + dependency_rate: INFINITY, + inputs: tx.inputs.clone(), + relatives_set_flag: false, + ancestors: HashSet::new(), + children: HashSet::new(), + ancestor_fee: tx.fee, + ancestor_weight: tx.weight, + ancestor_sigops: tx.sigops, + score: 0.0, + used: false, + modified: false, + dirty: false, + }; + audit_pool.insert(audit_tx.uid, audit_tx); + mempool_array.push_back(*uid); } - if blocks.len() < 7 && ((block_weight + next_tx.ancestor_weight >= BLOCK_WEIGHT_UNITS) || (block_sigops + next_tx.ancestor_sigops > BLOCK_SIGOPS)) { - // hold this package in an overflow list while we check for smaller options - overflow.push(next_txid); - failures += 1; - } else { - let mut package: Vec<(u32, usize, u32)> = Vec::new(); - let mut cluster: Vec = Vec::new(); - let is_cluster: bool = next_tx.ancestors.len() > 0; - package.push((next_tx.uid, next_tx.ancestors.len(), next_tx.weight)); - cluster.push(next_tx.uid); - for ancestor_id in &next_tx.ancestors { - if let Some(ancestor) = audit_pool.get(ancestor_id) { - package.push((*ancestor_id, ancestor.ancestors.len(), ancestor.weight)); - cluster.push(*ancestor_id); - } - } - package.sort_unstable_by_key(|a| 0 - a.1); - - if is_cluster { - cluster_array.push(cluster); - } - - let cluster_rate = next_tx.dependency_rate.min(next_tx.ancestor_fee as f64 / (next_tx.ancestor_weight as f64 / 4.0)); - - for package_entry in &package { - if let Some(tx) = audit_pool.get_mut(&package_entry.0) { - tx.used = true; - if tx.effective_fee_per_vsize != cluster_rate { - tx.effective_fee_per_vsize = cluster_rate; - tx.dirty = true; - } - transactions.push(tx.uid); - block_weight += tx.weight; - block_sigops += tx.sigops; - } - update_descendants(package_entry.0, &mut audit_pool, &mut modified, cluster_rate); - } - - failures = 0; + // Build relatives graph & calculate ancestor scores + for txid in &mempool_array { + set_relatives(*txid, &mut audit_pool); } - // this block is full - let exceeded_package_tries = failures > 1000 && block_weight > (BLOCK_WEIGHT_UNITS - 4000); - let queue_is_empty = mempool_array.len() == 0 && modified.is_empty(); - if (exceeded_package_tries || queue_is_empty) && blocks.len() < 7 { - // finalize this block - if transactions.len() > 0 { + // Sort by descending ancestor score + mempool_array.make_contiguous().sort_unstable_by(|a, b| { + let a_tx = audit_pool.get(a).unwrap(); + let b_tx = audit_pool.get(b).unwrap(); + b_tx.cmp(a_tx) + }); + + // Build blocks by greedily choosing the highest feerate package + // (i.e. the package rooted in the transaction with the best ancestor score) + let mut blocks: Vec> = Vec::new(); + let mut block_weight: u32 = BLOCK_RESERVED_WEIGHT; + let mut block_sigops: u32 = 0; + let mut transactions: Vec = Vec::new(); + let mut modified: PriorityQueue = PriorityQueue::new(); + let mut overflow: Vec = Vec::new(); + let mut failures = 0; + while mempool_array.len() > 0 || !modified.is_empty() { + let next_txid: u32; + if modified.is_empty() { + next_txid = mempool_array.pop_front()?; + } else if mempool_array.len() == 0 { + next_txid = modified.pop()?.0; + } else { + let next_array_txid = mempool_array.front()?; + let next_modified_txid = modified.peek()?.0; + let array_tx: &AuditTransaction = audit_pool.get(next_array_txid)?; + let modified_tx: &AuditTransaction = audit_pool.get(next_modified_txid)?; + match array_tx.cmp(&modified_tx) { + std::cmp::Ordering::Equal | std::cmp::Ordering::Greater => { + next_txid = mempool_array.pop_front()?; + } + std::cmp::Ordering::Less => { + next_txid = modified.pop()?.0; + } + } + } + + let next_tx = audit_pool.get(&next_txid)?; + + if next_tx.used { + continue; + } + + if blocks.len() < (MAX_BLOCKS - 1) + && ((block_weight + next_tx.ancestor_weight >= BLOCK_WEIGHT_UNITS) + || (block_sigops + next_tx.ancestor_sigops > BLOCK_SIGOPS)) + { + // hold this package in an overflow list while we check for smaller options + overflow.push(next_txid); + failures += 1; + } else { + let mut package: Vec<(u32, usize, u32)> = Vec::new(); + let mut cluster: Vec = Vec::new(); + let is_cluster: bool = next_tx.ancestors.len() > 0; + package.push((next_txid, next_tx.ancestors.len(), next_tx.weight)); + cluster.push(next_txid); + for ancestor_id in &next_tx.ancestors { + if let Some(ancestor) = audit_pool.get(ancestor_id) { + package.push((*ancestor_id, ancestor.ancestors.len(), ancestor.weight)); + cluster.push(*ancestor_id); + } + } + package.sort_unstable_by_key(|a| 0 - a.1); + + if is_cluster { + cluster_array.push(cluster); + } + + let cluster_rate = next_tx + .dependency_rate + .min(next_tx.ancestor_fee as f64 / (next_tx.ancestor_weight as f64 / 4.0)); + + for package_entry in &package { + if let Some(tx) = audit_pool.get_mut(&package_entry.0) { + tx.used = true; + if tx.effective_fee_per_vsize != cluster_rate { + tx.effective_fee_per_vsize = cluster_rate; + tx.dirty = true; + } + transactions.push(tx.uid); + block_weight += tx.weight; + block_sigops += tx.sigops; + } + update_descendants( + package_entry.0, + &mut audit_pool, + &mut modified, + cluster_rate, + ); + } + + failures = 0; + } + + // this block is full + let exceeded_package_tries = + failures > 1000 && block_weight > (BLOCK_WEIGHT_UNITS - BLOCK_RESERVED_WEIGHT); + let queue_is_empty = mempool_array.len() == 0 && modified.is_empty(); + if (exceeded_package_tries || queue_is_empty) && blocks.len() < (MAX_BLOCKS - 1) { + // finalize this block + if transactions.len() > 0 { + blocks.push(transactions); + } + // reset for the next block + transactions = Vec::new(); + block_weight = 4000; + // 'overflow' packages didn't fit in this block, but are valid candidates for the next + overflow.reverse(); + for overflowed in &overflow { + if let Some(overflowed_tx) = audit_pool.get(overflowed) { + if overflowed_tx.modified { + modified.push( + *overflowed, + TxPriority { + uid: *overflowed, + score: overflowed_tx.score, + }, + ); + } else { + mempool_array.push_front(*overflowed); + } + } + } + overflow = Vec::new(); + } + } + // add the final unbounded block if it contains any transactions + if transactions.len() > 0 { blocks.push(transactions); - } - // reset for the next block - transactions = Vec::new(); - block_weight = 4000; - // 'overflow' packages didn't fit in this block, but are valid candidates for the next - overflow.reverse(); - for overflowed in &overflow { - if let Some(overflowed_tx) = audit_pool.get(overflowed) { - if overflowed_tx.modified { - modified.push(*overflowed, TxPriority{ uid: *overflowed, score: overflowed_tx.score}); - } else { - mempool_array.push_front(*overflowed); - } + } + + // make a list of dirty transactions and their new rates + let mut rates: Vec<(u32, f64)> = Vec::new(); + for (txid, tx) in audit_pool { + if tx.dirty { + rates.push((txid, tx.effective_fee_per_vsize)); } - } - overflow = Vec::new(); } - } - // add the final unbounded block if it contains any transactions - if transactions.len() > 0 { - blocks.push(transactions); - } - // make a list of dirty transactions and their new rates - let mut rates: Vec<(u32, f64)> = Vec::new(); - for (txid, tx) in audit_pool { - if tx.dirty { - rates.push((txid, tx.effective_fee_per_vsize)); - } - } - - return (blocks, rates, cluster_array); + Some((blocks, rates, cluster_array)) } fn set_relatives(txid: u32, audit_pool: &mut HashMap) { - let mut parents: HashSet = HashSet::new(); - if let Some(tx) = audit_pool.get(&txid) { - if tx.is_relatives_set { - return; - } - for input in &tx.inputs { - parents.insert(*input); - } - } else { - return; - } - - let mut ancestors: HashSet = HashSet::new(); - for parent_id in &parents { - set_relatives(*parent_id, audit_pool); - - let parent_entry: Option<&mut AuditTransaction> = audit_pool.get_mut(&parent_id); - match parent_entry { - Some(parent) => { - ancestors.insert(*parent_id); - parent.children.insert(txid); - for ancestor in &parent.ancestors { - ancestors.insert(*ancestor); + let mut parents: HashSet = HashSet::new(); + if let Some(tx) = audit_pool.get(&txid) { + if tx.relatives_set_flag { + return; } - } - - None => {} + for input in &tx.inputs { + parents.insert(*input); + } + } else { + return; } - } - let mut total_fee: u64 = 0; - let mut total_weight: u32 = 0; - let mut total_sigops: u32 = 0; + let mut ancestors: HashSet = HashSet::new(); + for parent_id in &parents { + set_relatives(*parent_id, audit_pool); - for ancestor_id in &ancestors { - let ancestor = audit_pool.get(&ancestor_id).unwrap(); - total_fee += ancestor.fee; - total_weight += ancestor.weight; - total_sigops += ancestor.sigops; - } + match audit_pool.get_mut(&parent_id) { + Some(parent) => { + ancestors.insert(*parent_id); + parent.children.insert(txid); + for ancestor in &parent.ancestors { + ancestors.insert(*ancestor); + } + } - if let Some(tx) = audit_pool.get_mut(&txid) { - tx.ancestors = ancestors; - tx.ancestor_fee = tx.fee + total_fee; - tx.ancestor_weight = tx.weight + total_weight; - tx.ancestor_sigops = tx.sigops + total_sigops; - tx.score = (tx.ancestor_fee as f64) / (if tx.ancestor_weight != 0 {tx.ancestor_weight as f64 / 4.0} else { 1.0 }); - tx.is_relatives_set = true; - } + None => {} + } + } + + let mut total_fee: u64 = 0; + let mut total_weight: u32 = 0; + let mut total_sigops: u32 = 0; + + for ancestor_id in &ancestors { + let ancestor = audit_pool.get(&ancestor_id).unwrap(); + total_fee += ancestor.fee; + total_weight += ancestor.weight; + total_sigops += ancestor.sigops; + } + + if let Some(tx) = audit_pool.get_mut(&txid) { + tx.ancestors = ancestors; + tx.ancestor_fee = tx.fee + total_fee; + tx.ancestor_weight = tx.weight + total_weight; + tx.ancestor_sigops = tx.sigops + total_sigops; + tx.score = (tx.ancestor_fee as f64) + / (if tx.ancestor_weight != 0 { + tx.ancestor_weight as f64 / 4.0 + } else { + 1.0 + }); + tx.relatives_set_flag = true; + } } // iterate over remaining descendants, removing the root as a valid ancestor & updating the ancestor score -fn update_descendants(root_txid: u32, audit_pool: &mut HashMap, modified: &mut PriorityQueue, cluster_rate: f64) { - let mut visited: HashSet = HashSet::new(); - let mut descendant_stack: Vec = Vec::new(); - let root_fee: u64; - let root_weight: u32; - let root_sigops: u32; - if let Some(root_tx) = audit_pool.get(&root_txid) { - for descendant_id in &root_tx.children { - if !visited.contains(descendant_id) { - descendant_stack.push(*descendant_id); - visited.insert(*descendant_id); - } - } - root_fee = root_tx.fee; - root_weight = root_tx.weight; - root_sigops = root_tx.sigops; - } else { - return; - } - while descendant_stack.len() > 0 { - let next_txid: u32 = descendant_stack.pop().unwrap(); - if let Some(descendant) = audit_pool.get_mut(&next_txid) { - // remove root tx as ancestor - descendant.ancestors.remove(&root_txid); - descendant.ancestor_fee -= root_fee; - descendant.ancestor_weight -= root_weight; - descendant.ancestor_sigops -= root_sigops; - let current_score = descendant.score; - descendant.score = (descendant.ancestor_fee as f64) / (if descendant.ancestor_weight != 0 {descendant.ancestor_weight as f64 / 4.0} else { 1.0 }); - descendant.dependency_rate = descendant.dependency_rate.min(cluster_rate); - descendant.modified = true; - // update modified priority if score has changed - if !descendant.modified || descendant.score < current_score { - modified.push_decrease(descendant.uid, TxPriority { uid: descendant.uid, score: descendant.score}); - } else if descendant.score > current_score { - modified.push_increase(descendant.uid, TxPriority { uid: descendant.uid, score: descendant.score}); - } - - // add this node's children to the stack - for child_id in &descendant.children { - if !visited.contains(child_id) { - descendant_stack.push(*child_id); - visited.insert(*child_id); +fn update_descendants( + root_txid: u32, + audit_pool: &mut HashMap, + modified: &mut PriorityQueue, + cluster_rate: f64, +) { + let mut visited: HashSet = HashSet::new(); + let mut descendant_stack: Vec = Vec::new(); + let root_fee: u64; + let root_weight: u32; + let root_sigops: u32; + if let Some(root_tx) = audit_pool.get(&root_txid) { + for descendant_id in &root_tx.children { + if !visited.contains(descendant_id) { + descendant_stack.push(*descendant_id); + visited.insert(*descendant_id); + } } - } + root_fee = root_tx.fee; + root_weight = root_tx.weight; + root_sigops = root_tx.sigops; + } else { + return; } - } -} \ No newline at end of file + while descendant_stack.len() > 0 { + let next_txid: u32 = descendant_stack.pop().unwrap(); + if let Some(descendant) = audit_pool.get_mut(&next_txid) { + // remove root tx as ancestor + descendant.ancestors.remove(&root_txid); + descendant.ancestor_fee -= root_fee; + descendant.ancestor_weight -= root_weight; + descendant.ancestor_sigops -= root_sigops; + let current_score = descendant.score; + descendant.score = (descendant.ancestor_fee as f64) + / (if descendant.ancestor_weight != 0 { + descendant.ancestor_weight as f64 / 4.0 + } else { + 1.0 + }); + descendant.dependency_rate = descendant.dependency_rate.min(cluster_rate); + descendant.modified = true; + // update modified priority if score has changed + if !descendant.modified || descendant.score < current_score { + modified.push_decrease( + descendant.uid, + TxPriority { + uid: descendant.uid, + score: descendant.score, + }, + ); + } else if descendant.score > current_score { + modified.push_increase( + descendant.uid, + TxPriority { + uid: descendant.uid, + score: descendant.score, + }, + ); + } + + // add this node's children to the stack + for child_id in &descendant.children { + if !visited.contains(child_id) { + descendant_stack.push(*child_id); + visited.insert(*child_id); + } + } + } + } +} diff --git a/backend/rust-gbt/src/lib.rs b/backend/rust-gbt/src/lib.rs index 12583300a..375575908 100644 --- a/backend/rust-gbt/src/lib.rs +++ b/backend/rust-gbt/src/lib.rs @@ -1,123 +1,127 @@ use neon::{prelude::*, types::buffer::TypedArray}; +use once_cell::sync::Lazy; use std::collections::HashMap; use std::ops::DerefMut; use std::sync::Mutex; -use once_cell::sync::Lazy; +mod audit_transaction; mod gbt; mod thread_transaction; -mod audit_transaction; mod utils; use thread_transaction::ThreadTransaction; -static THREAD_TRANSACTIONS: Lazy>> = Lazy::new(|| { - Mutex::new(HashMap::new()) -}); +static THREAD_TRANSACTIONS: Lazy>> = + Lazy::new(|| Mutex::new(HashMap::new())); fn make(mut cx: FunctionContext) -> JsResult { - let mempool_arg = cx.argument::(0)?.root(&mut cx).into_inner(&mut cx); - let callback = cx.argument::(1)?.root(&mut cx); - let channel = cx.channel(); + let mempool_arg = cx + .argument::(0)? + .root(&mut cx) + .into_inner(&mut cx); + let callback = cx.argument::(1)?.root(&mut cx); + let channel = cx.channel(); - let buffer = mempool_arg.as_slice(&mut cx); - let thread_transactions = ThreadTransaction::batch_from_buffer(buffer); + let buffer = mempool_arg.as_slice(&mut cx); - let mut map = THREAD_TRANSACTIONS.lock().unwrap(); - map.clear(); - for tx in thread_transactions { - map.insert(tx.uid, tx); - } - drop(map); + let mut map = HashMap::new(); + for tx in ThreadTransaction::batch_from_buffer(buffer) { + map.insert(tx.uid, tx); + } - run_in_thread(channel, callback); + let mut global_map = THREAD_TRANSACTIONS.lock().unwrap(); + *global_map = map; - Ok(cx.undefined()) + run_in_thread(channel, callback); + + Ok(cx.undefined()) } fn update(mut cx: FunctionContext) -> JsResult { - let new_txs_arg = cx.argument::(0)?.root(&mut cx).into_inner(&mut cx); - let remove_txs_arg = cx.argument::(1)?.root(&mut cx).into_inner(&mut cx); - let callback = cx.argument::(2)?.root(&mut cx); - let channel = cx.channel(); + let new_txs_arg = cx + .argument::(0)? + .root(&mut cx) + .into_inner(&mut cx); + let remove_txs_arg = cx + .argument::(1)? + .root(&mut cx) + .into_inner(&mut cx); + let callback = cx.argument::(2)?.root(&mut cx); + let channel = cx.channel(); - let mut map = THREAD_TRANSACTIONS.lock().unwrap(); - let new_tx_buffer = new_txs_arg.as_slice(&mut cx); - let thread_transactions = ThreadTransaction::batch_from_buffer(new_tx_buffer); - for tx in thread_transactions { - map.insert(tx.uid, tx); - } + let mut map = THREAD_TRANSACTIONS.lock().unwrap(); + let new_tx_buffer = new_txs_arg.as_slice(&mut cx); + for tx in ThreadTransaction::batch_from_buffer(new_tx_buffer) { + map.insert(tx.uid, tx); + } - let remove_tx_buffer = remove_txs_arg.as_slice(&mut cx); - let remove_ids = utils::txids_from_buffer(remove_tx_buffer); - for txid in &remove_ids { - map.remove(txid); - } - drop(map); + let remove_tx_buffer = remove_txs_arg.as_slice(&mut cx); + for txid in &utils::txids_from_buffer(remove_tx_buffer) { + map.remove(txid); + } + drop(map); - run_in_thread(channel, callback); + run_in_thread(channel, callback); - Ok(cx.undefined()) + Ok(cx.undefined()) } fn run_in_thread(channel: Channel, callback: Root) { - std::thread::spawn(move || { - let mut map = THREAD_TRANSACTIONS.lock().unwrap(); - let (blocks, rates, clusters) = gbt::gbt(map.deref_mut()); - drop(map); + std::thread::spawn(move || { + let mut map = THREAD_TRANSACTIONS.lock().unwrap(); + let (blocks, rates, clusters) = gbt::gbt(map.deref_mut()).unwrap(); + drop(map); - channel.send(move |mut cx| { - let result = JsObject::new(&mut cx); + channel.send(move |mut cx| { + let result = JsObject::new(&mut cx); - let js_blocks = JsArray::new(&mut cx, blocks.len() as u32); - for (i, block) in blocks.iter().enumerate() { - let inner = JsArray::new(&mut cx, block.len() as u32); - for (j, uid) in block.iter().enumerate() { - let v = cx.number(*uid); - inner.set(&mut cx, j as u32, v)?; - } - js_blocks.set(&mut cx, i as u32, inner)?; - } + let js_blocks = JsArray::new(&mut cx, blocks.len() as u32); + for (i, block) in blocks.iter().enumerate() { + let inner = JsArray::new(&mut cx, block.len() as u32); + for (j, uid) in block.iter().enumerate() { + let v = cx.number(*uid); + inner.set(&mut cx, j as u32, v)?; + } + js_blocks.set(&mut cx, i as u32, inner)?; + } - let js_clusters = JsArray::new(&mut cx, clusters.len() as u32); - for (i, cluster) in clusters.iter().enumerate() { - let inner = JsArray::new(&mut cx, cluster.len() as u32); - for (j, uid) in cluster.iter().enumerate() { - let v = cx.number(*uid); - inner.set(&mut cx, j as u32, v)?; - } - js_clusters.set(&mut cx, i as u32, inner)?; - } + let js_clusters = JsArray::new(&mut cx, clusters.len() as u32); + for (i, cluster) in clusters.iter().enumerate() { + let inner = JsArray::new(&mut cx, cluster.len() as u32); + for (j, uid) in cluster.iter().enumerate() { + let v = cx.number(*uid); + inner.set(&mut cx, j as u32, v)?; + } + js_clusters.set(&mut cx, i as u32, inner)?; + } - let js_rates = JsArray::new(&mut cx, rates.len() as u32); - for (i, (uid, rate)) in rates.iter().enumerate() { - let inner = JsArray::new(&mut cx, 2); - let js_uid = cx.number(*uid); - let js_rate = cx.number(*rate); - inner.set(&mut cx, 0, js_uid)?; - inner.set(&mut cx, 1, js_rate)?; - js_rates.set(&mut cx, i as u32, inner)?; - } + let js_rates = JsArray::new(&mut cx, rates.len() as u32); + for (i, (uid, rate)) in rates.iter().enumerate() { + let inner = JsArray::new(&mut cx, 2); + let js_uid = cx.number(*uid); + let js_rate = cx.number(*rate); + inner.set(&mut cx, 0, js_uid)?; + inner.set(&mut cx, 1, js_rate)?; + js_rates.set(&mut cx, i as u32, inner)?; + } - result.set(&mut cx, "blocks", js_blocks)?; - result.set(&mut cx, "clusters", js_clusters)?; - result.set(&mut cx, "rates", js_rates)?; + result.set(&mut cx, "blocks", js_blocks)?; + result.set(&mut cx, "clusters", js_clusters)?; + result.set(&mut cx, "rates", js_rates)?; - let callback = callback.into_inner(&mut cx); - let this = cx.undefined(); - let args = vec![ - result.upcast() - ]; + let callback = callback.into_inner(&mut cx); + let this = cx.undefined(); + let args = vec![result.upcast()]; - callback.call(&mut cx, this, args)?; + callback.call(&mut cx, this, args)?; - Ok(()) + Ok(()) + }); }); - }); } #[neon::main] fn main(mut cx: ModuleContext) -> NeonResult<()> { - cx.export_function("make", make)?; - cx.export_function("update", update)?; - Ok(()) + cx.export_function("make", make)?; + cx.export_function("update", update)?; + Ok(()) } diff --git a/backend/rust-gbt/src/thread_transaction.rs b/backend/rust-gbt/src/thread_transaction.rs index f429613a6..bfcd17932 100644 --- a/backend/rust-gbt/src/thread_transaction.rs +++ b/backend/rust-gbt/src/thread_transaction.rs @@ -1,46 +1,44 @@ -// use neon::{types::{JsObject, JsNumber, JsArray, JsValue, JsBoolean, JsArrayBuffer, buffer::TypedArray}, prelude::{Object, FunctionContext, Handle}}; -extern crate bytes; -use std::io::Cursor; use bytes::buf::Buf; +use std::io::Cursor; pub struct ThreadTransaction { - pub uid: u32, - pub fee: u64, - pub weight: u32, - pub sigops: u32, - pub fee_per_vsize: f64, - pub effective_fee_per_vsize: f64, - pub inputs: Vec, + pub uid: u32, + pub fee: u64, + pub weight: u32, + pub sigops: u32, + pub fee_per_vsize: f64, + pub effective_fee_per_vsize: f64, + pub inputs: Vec, } impl ThreadTransaction { - pub fn batch_from_buffer(buffer: &[u8]) -> Vec { - let mut transactions: Vec = Vec::new(); - let mut cursor = Cursor::new(buffer); - let size = cursor.get_u32(); - for _ in 0..size { - let uid = cursor.get_u32(); - let fee = cursor.get_f64() as u64; - let weight = cursor.get_u32(); - let sigops = cursor.get_u32(); - let fee_per_vsize = cursor.get_f64(); - let effective_fee_per_vsize = cursor.get_f64(); - let input_count = cursor.get_u32(); - let mut inputs: Vec = Vec::new(); - for _ in 0..input_count { - inputs.push(cursor.get_u32()); - } - transactions.push(ThreadTransaction { - uid, - fee, - weight, - sigops, - fee_per_vsize, - effective_fee_per_vsize, - inputs, - }) - } + pub fn batch_from_buffer(buffer: &[u8]) -> Vec { + let mut transactions: Vec = Vec::new(); + let mut cursor = Cursor::new(buffer); + let size = cursor.get_u32(); + for _ in 0..size { + let uid = cursor.get_u32(); + let fee = cursor.get_f64().round() as u64; + let weight = cursor.get_u32(); + let sigops = cursor.get_u32(); + let fee_per_vsize = cursor.get_f64(); + let effective_fee_per_vsize = cursor.get_f64(); + let input_count = cursor.get_u32(); + let mut inputs: Vec = Vec::new(); + for _ in 0..input_count { + inputs.push(cursor.get_u32()); + } + transactions.push(ThreadTransaction { + uid, + fee, + weight, + sigops, + fee_per_vsize, + effective_fee_per_vsize, + inputs, + }) + } - return transactions; - } -} \ No newline at end of file + transactions + } +} diff --git a/backend/rust-gbt/src/utils.rs b/backend/rust-gbt/src/utils.rs index 569b858e8..c1b6063a1 100644 --- a/backend/rust-gbt/src/utils.rs +++ b/backend/rust-gbt/src/utils.rs @@ -1,14 +1,13 @@ -extern crate bytes; -use std::io::Cursor; use bytes::buf::Buf; +use std::io::Cursor; pub fn txids_from_buffer(buffer: &[u8]) -> Vec { - let mut txids: Vec = Vec::new(); - let mut cursor = Cursor::new(buffer); - let size = cursor.get_u32(); - for _ in 0..size { - txids.push(cursor.get_u32()); - } + let mut txids: Vec = Vec::new(); + let mut cursor: Cursor<&[u8]> = Cursor::new(buffer); + let size: u32 = cursor.get_u32(); + for _ in 0..size { + txids.push(cursor.get_u32()); + } - return txids; -} \ No newline at end of file + txids +}