Skip to content

Commit 9b4012d

Browse files
committed
feat(node): apply_block commits UTXO + evicts mempool + indexes transactions
Op: extend
1 parent 84f95b6 commit 9b4012d

2 files changed

Lines changed: 67 additions & 3 deletions

File tree

crates/node/src/import.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,20 @@ mod tests {
7777
.ok_or_else(|| anyhow::anyhow!("missing chain tip after import"))?;
7878
assert_eq!(tip.height, 0);
7979
assert_eq!(tip.hash, genesis_hash);
80+
assert_eq!(
81+
state.utxo().len(),
82+
1,
83+
"genesis has one live coinbase output"
84+
);
85+
assert_eq!(
86+
state.transactions().read().len(),
87+
1,
88+
"genesis coinbase must be indexed"
89+
);
90+
assert!(
91+
state.mempool().read().is_empty(),
92+
"genesis import must leave mempool empty"
93+
);
8094
Ok(())
8195
}
8296

crates/node/src/state.rs

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ use std::sync::Arc;
1919

2020
use anyhow::{Context as _, Result, bail};
2121
use bitcoin_rs_mempool::{Mempool, MempoolLimits};
22-
use bitcoin_rs_utxo::UtxoSet;
22+
use bitcoin_rs_primitives::OutPoint;
23+
use bitcoin_rs_utxo::{BlockChanges, UtxoAdd, UtxoSet};
2324
use parking_lot::{Mutex, RwLock};
2425

2526
use crate::Config;
@@ -38,6 +39,9 @@ pub enum ApplyError {
3839
/// Height arithmetic overflowed `u32::MAX`.
3940
#[error("height overflow at tip {0}")]
4041
HeightOverflow(u32),
42+
/// UTXO commit failed during block apply.
43+
#[error("utxo commit: {0}")]
44+
UtxoCommit(#[from] bitcoin_rs_utxo::UtxoError),
4145
}
4246

4347
enum NodeStorage {
@@ -277,8 +281,8 @@ impl NodeState {
277281
/// tip is published yet), chainwork is approximated by accumulating the
278282
/// block header's own work onto the prior tip's chainwork, and the block
279283
/// is stored in `blocks` for RPC consumers. Real consensus validation,
280-
/// UTXO commit, BIP30 / BIP34 / soft-fork checks, BIP9 deployment state,
281-
/// and reorg planning land in follow-up turns.
284+
/// BIP30 / BIP34 / soft-fork checks, BIP9 deployment state, and reorg
285+
/// planning land in follow-up turns.
282286
///
283287
/// Returns the new `TipSnapshot` so callers can publish it elsewhere.
284288
pub fn apply_block(
@@ -313,6 +317,38 @@ impl NodeState {
313317
None => (0_u32, header_work),
314318
};
315319

320+
let mut changes = BlockChanges::default();
321+
for tx in &block.txdata {
322+
let txid = tx.compute_txid();
323+
for (vout_idx, txout) in tx.output.iter().enumerate() {
324+
let outpoint = OutPoint::new(
325+
bitcoin_rs_primitives::Hash256::from_le_bytes(txid.as_byte_array()),
326+
u32::try_from(vout_idx).map_err(|_| ApplyError::HeightOverflow(height))?,
327+
);
328+
changes.add(UtxoAdd::new(
329+
outpoint,
330+
txout.clone(),
331+
tx.is_coinbase(),
332+
height,
333+
));
334+
}
335+
336+
if !tx.is_coinbase() {
337+
for tx_input in &tx.input {
338+
let previous_output = tx_input.previous_output;
339+
changes.remove(OutPoint::new(
340+
bitcoin_rs_primitives::Hash256::from_le_bytes(
341+
previous_output.txid.as_byte_array(),
342+
),
343+
previous_output.vout,
344+
));
345+
}
346+
}
347+
}
348+
self.utxo
349+
.commit_block(&changes, &block_hash)
350+
.map_err(ApplyError::UtxoCommit)?;
351+
316352
let tip = bitcoin_rs_chain::TipSnapshot {
317353
tip_id: bitcoin_rs_chain::node::NodeId::new(height),
318354
height,
@@ -323,6 +359,20 @@ impl NodeState {
323359
self.blocks
324360
.write()
325361
.push(bitcoin_rs_rpc::BlockRecord::from_block(height, block));
362+
for tx in &block.txdata {
363+
let txid = tx.compute_txid();
364+
let evicted_count = self.mempool.write().remove_by_txid(&txid).len();
365+
tracing::debug!(%txid, evicted_count, "apply_block: evicted transaction from mempool");
366+
self.transactions.write().insert(txid, tx.clone());
367+
}
368+
tracing::info!(
369+
height,
370+
%block_hash,
371+
tx_count = block.txdata.len(),
372+
utxo_adds = changes.add_count(),
373+
utxo_removes = changes.remove_count(),
374+
"apply_block: synthetic chain advance committed"
375+
);
326376
Ok(tip)
327377
}
328378
}

0 commit comments

Comments
 (0)