Merge branch 'master' into mononaut/fix-hardcoded-median-weight

This commit is contained in:
softsimon 2024-06-22 14:13:41 +09:00 committed by GitHub
commit 6b84dc2be4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 39 additions and 14 deletions

View File

@ -13,7 +13,7 @@ const vectorBuffer: Buffer = fs.readFileSync(path.join(__dirname, './', './test-
describe('Rust GBT', () => { describe('Rust GBT', () => {
test('should produce the same template as getBlockTemplate from Bitcoin Core', async () => { test('should produce the same template as getBlockTemplate from Bitcoin Core', async () => {
const rustGbt = new GbtGenerator(); const rustGbt = new GbtGenerator(4_000_000, 8);
const { mempool, maxUid } = mempoolFromArrayBuffer(vectorBuffer.buffer); const { mempool, maxUid } = mempoolFromArrayBuffer(vectorBuffer.buffer);
const result = await rustGbt.make(mempool, [], maxUid); const result = await rustGbt.make(mempool, [], maxUid);

View File

@ -16,7 +16,7 @@ class MempoolBlocks {
private mempoolBlockDeltas: MempoolBlockDelta[] = []; private mempoolBlockDeltas: MempoolBlockDelta[] = [];
private txSelectionWorker: Worker | null = null; private txSelectionWorker: Worker | null = null;
private rustInitialized: boolean = false; private rustInitialized: boolean = false;
private rustGbtGenerator: GbtGenerator = new GbtGenerator(); private rustGbtGenerator: GbtGenerator = new GbtGenerator(config.MEMPOOL.BLOCK_WEIGHT_UNITS, config.MEMPOOL.MEMPOOL_BLOCKS_AMOUNT);
private nextUid: number = 1; private nextUid: number = 1;
private uidMap: Map<number, string> = new Map(); // map short numerical uids to full txids private uidMap: Map<number, string> = new Map(); // map short numerical uids to full txids
@ -230,7 +230,7 @@ class MempoolBlocks {
private resetRustGbt(): void { private resetRustGbt(): void {
this.rustInitialized = false; this.rustInitialized = false;
this.rustGbtGenerator = new GbtGenerator(); this.rustGbtGenerator = new GbtGenerator(config.MEMPOOL.BLOCK_WEIGHT_UNITS, config.MEMPOOL.MEMPOOL_BLOCKS_AMOUNT);
} }
public async $rustMakeBlockTemplates(txids: string[], newMempool: { [txid: string]: MempoolTransactionExtended }, candidates: GbtCandidates | undefined, saveResults: boolean = false, useAccelerations: boolean = false, accelerationPool?: number): Promise<MempoolBlockWithTransactions[]> { public async $rustMakeBlockTemplates(txids: string[], newMempool: { [txid: string]: MempoolTransactionExtended }, candidates: GbtCandidates | undefined, saveResults: boolean = false, useAccelerations: boolean = false, accelerationPool?: number): Promise<MempoolBlockWithTransactions[]> {
@ -262,7 +262,7 @@ class MempoolBlocks {
}); });
// run the block construction algorithm in a separate thread, and wait for a result // run the block construction algorithm in a separate thread, and wait for a result
const rustGbt = saveResults ? this.rustGbtGenerator : new GbtGenerator(); const rustGbt = saveResults ? this.rustGbtGenerator : new GbtGenerator(config.MEMPOOL.BLOCK_WEIGHT_UNITS, config.MEMPOOL.MEMPOOL_BLOCKS_AMOUNT);
try { try {
const { blocks, blockWeights, rates, clusters, overflow } = this.convertNapiResultTxids( const { blocks, blockWeights, rates, clusters, overflow } = this.convertNapiResultTxids(
await rustGbt.make(transactions as RustThreadTransaction[], convertedAccelerations as RustThreadAcceleration[], this.nextUid), await rustGbt.make(transactions as RustThreadTransaction[], convertedAccelerations as RustThreadAcceleration[], this.nextUid),

View File

@ -8,11 +8,9 @@ use crate::{
GbtResult, ThreadTransactionsMap, thread_acceleration::ThreadAcceleration, GbtResult, ThreadTransactionsMap, thread_acceleration::ThreadAcceleration,
}; };
const MAX_BLOCK_WEIGHT_UNITS: u32 = 4_000_000 - 4_000;
const BLOCK_SIGOPS: u32 = 80_000; const BLOCK_SIGOPS: u32 = 80_000;
const BLOCK_RESERVED_WEIGHT: u32 = 4_000; const BLOCK_RESERVED_WEIGHT: u32 = 4_000;
const BLOCK_RESERVED_SIGOPS: u32 = 400; const BLOCK_RESERVED_SIGOPS: u32 = 400;
const MAX_BLOCKS: usize = 8;
type AuditPool = Vec<Option<ManuallyDrop<AuditTransaction>>>; type AuditPool = Vec<Option<ManuallyDrop<AuditTransaction>>>;
type ModifiedQueue = PriorityQueue<u32, TxPriority, U32HasherState>; type ModifiedQueue = PriorityQueue<u32, TxPriority, U32HasherState>;
@ -53,7 +51,13 @@ impl Ord for TxPriority {
// TODO: Make gbt smaller to fix these lints. // TODO: Make gbt smaller to fix these lints.
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
#[allow(clippy::cognitive_complexity)] #[allow(clippy::cognitive_complexity)]
pub fn gbt(mempool: &mut ThreadTransactionsMap, accelerations: &[ThreadAcceleration], max_uid: usize) -> GbtResult { pub fn gbt(
mempool: &mut ThreadTransactionsMap,
accelerations: &[ThreadAcceleration],
max_uid: usize,
max_block_weight: u32,
max_blocks: usize,
) -> GbtResult {
let mut indexed_accelerations = Vec::with_capacity(max_uid + 1); let mut indexed_accelerations = Vec::with_capacity(max_uid + 1);
indexed_accelerations.resize(max_uid + 1, None); indexed_accelerations.resize(max_uid + 1, None);
for acceleration in accelerations { for acceleration in accelerations {
@ -146,9 +150,9 @@ pub fn gbt(mempool: &mut ThreadTransactionsMap, accelerations: &[ThreadAccelerat
modified.pop(); modified.pop();
} }
if blocks.len() < (MAX_BLOCKS - 1) if blocks.len() < (max_blocks - 1)
&& ((block_weight + (4 * next_tx.ancestor_sigop_adjusted_vsize()) && ((block_weight + (4 * next_tx.ancestor_sigop_adjusted_vsize())
>= MAX_BLOCK_WEIGHT_UNITS) >= max_block_weight - 4_000)
|| (block_sigops + next_tx.ancestor_sigops() > BLOCK_SIGOPS)) || (block_sigops + next_tx.ancestor_sigops() > BLOCK_SIGOPS))
{ {
// hold this package in an overflow list while we check for smaller options // hold this package in an overflow list while we check for smaller options
@ -201,9 +205,9 @@ pub fn gbt(mempool: &mut ThreadTransactionsMap, accelerations: &[ThreadAccelerat
// this block is full // this block is full
let exceeded_package_tries = let exceeded_package_tries =
failures > 1000 && block_weight > (MAX_BLOCK_WEIGHT_UNITS - BLOCK_RESERVED_WEIGHT); failures > 1000 && block_weight > (max_block_weight - 4_000 - BLOCK_RESERVED_WEIGHT);
let queue_is_empty = mempool_stack.is_empty() && modified.is_empty(); let queue_is_empty = mempool_stack.is_empty() && modified.is_empty();
if (exceeded_package_tries || queue_is_empty) && blocks.len() < (MAX_BLOCKS - 1) { if (exceeded_package_tries || queue_is_empty) && blocks.len() < (max_blocks - 1) {
// finalize this block // finalize this block
if transactions.is_empty() { if transactions.is_empty() {
info!("trying to push an empty block! breaking loop! mempool {:#?} | modified {:#?} | overflow {:#?}", mempool_stack.len(), modified.len(), overflow.len()); info!("trying to push an empty block! breaking loop! mempool {:#?} | modified {:#?} | overflow {:#?}", mempool_stack.len(), modified.len(), overflow.len());

View File

@ -35,6 +35,8 @@ type ThreadTransactionsMap = HashMap<u32, ThreadTransaction, U32HasherState>;
#[napi] #[napi]
pub struct GbtGenerator { pub struct GbtGenerator {
thread_transactions: Arc<Mutex<ThreadTransactionsMap>>, thread_transactions: Arc<Mutex<ThreadTransactionsMap>>,
max_block_weight: u32,
max_blocks: usize,
} }
#[napi::module_init] #[napi::module_init]
@ -65,10 +67,12 @@ impl GbtGenerator {
#[napi(constructor)] #[napi(constructor)]
#[allow(clippy::new_without_default)] #[allow(clippy::new_without_default)]
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new(max_block_weight: u32, max_blocks: u32) -> Self {
debug!("Created new GbtGenerator"); debug!("Created new GbtGenerator");
Self { Self {
thread_transactions: Arc::new(Mutex::new(u32hashmap_with_capacity(STARTING_CAPACITY))), thread_transactions: Arc::new(Mutex::new(u32hashmap_with_capacity(STARTING_CAPACITY))),
max_block_weight,
max_blocks: max_blocks as usize,
} }
} }
@ -76,12 +80,19 @@ impl GbtGenerator {
/// ///
/// Rejects if the thread panics or if the Mutex is poisoned. /// Rejects if the thread panics or if the Mutex is poisoned.
#[napi] #[napi]
pub async fn make(&self, mempool: Vec<ThreadTransaction>, accelerations: Vec<ThreadAcceleration>, 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); trace!("make: Current State {:#?}", self.thread_transactions);
run_task( run_task(
Arc::clone(&self.thread_transactions), Arc::clone(&self.thread_transactions),
accelerations, accelerations,
max_uid as usize, max_uid as usize,
self.max_block_weight,
self.max_blocks,
move |map| { move |map| {
for tx in mempool { for tx in mempool {
map.insert(tx.uid, tx); map.insert(tx.uid, tx);
@ -107,6 +118,8 @@ impl GbtGenerator {
Arc::clone(&self.thread_transactions), Arc::clone(&self.thread_transactions),
accelerations, accelerations,
max_uid as usize, max_uid as usize,
self.max_block_weight,
self.max_blocks,
move |map| { move |map| {
for tx in new_txs { for tx in new_txs {
map.insert(tx.uid, tx); map.insert(tx.uid, tx);
@ -149,6 +162,8 @@ async fn run_task<F>(
thread_transactions: Arc<Mutex<ThreadTransactionsMap>>, thread_transactions: Arc<Mutex<ThreadTransactionsMap>>,
accelerations: Vec<ThreadAcceleration>, accelerations: Vec<ThreadAcceleration>,
max_uid: usize, max_uid: usize,
max_block_weight: u32,
max_blocks: usize,
callback: F, callback: F,
) -> Result<GbtResult> ) -> Result<GbtResult>
where where
@ -166,7 +181,13 @@ where
callback(&mut map); callback(&mut map);
info!("Starting gbt algorithm for {} elements...", map.len()); info!("Starting gbt algorithm for {} elements...", map.len());
let result = gbt::gbt(&mut map, &accelerations, max_uid); let result = gbt::gbt(
&mut map,
&accelerations,
max_uid,
max_block_weight,
max_blocks as usize,
);
info!("Finished gbt algorithm for {} elements...", map.len()); info!("Finished gbt algorithm for {} elements...", map.len());
debug!( debug!(