Skip to content

Commit

Permalink
use OnceLock for BlockExtra::block
Browse files Browse the repository at this point in the history
  • Loading branch information
RCasatta committed Jan 16, 2025
1 parent e18af46 commit 06c9c5d
Show file tree
Hide file tree
Showing 9 changed files with 19 additions and 23 deletions.
2 changes: 1 addition & 1 deletion cli/examples/signatures_in_witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn main() -> Result<(), Box<dyn Error>> {
);
}

for tx in &block_extra.block().expect("block is not loaded").txdata {
for tx in &block_extra.block().txdata {
for input in &tx.input {
for witness in input.witness.iter() {
if let Ok(_sig) = deserialize::<ParsedSignature>(witness) {
Expand Down
2 changes: 1 addition & 1 deletion cli/examples/with_pipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fn main() -> Result<(), Box<dyn Error>> {

for block_extra in iter {
let txs_fee = block_extra.fee().expect("launch without `--skip-prevout`");
let block = block_extra.block().expect("block is not loaded");
let block = block_extra.block();
let coinbase = &block.txdata[0];
let coinbase_sum_outputs: u64 = coinbase
.output
Expand Down
25 changes: 11 additions & 14 deletions lib/src/block_extra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::collections::HashMap;
use std::convert::TryFrom;
use std::io::{Read, Seek, SeekFrom};
use std::ops::DerefMut;
use std::sync::OnceLock;

/// The bitcoin block and additional metadata returned by the [crate::iter()] method
#[derive(Debug, Eq, PartialEq)]
Expand All @@ -22,7 +23,7 @@ pub struct BlockExtra {
/// avoiding the performance costs and use visitor directly on the bytes with [`bitcoin_slices`]
block_bytes: Vec<u8>,

block: Option<Block>,
block: OnceLock<Block>,

/// The bitcoin block hash, same as `block.block_hash()` but result from hashing is cached
pub(crate) block_hash: BlockHash,
Expand Down Expand Up @@ -77,7 +78,7 @@ impl TryFrom<FsBlock> for BlockExtra {
Ok(BlockExtra {
version: fs_block.serialization_version,
block_bytes,
block: None,
block: OnceLock::new(),
block_hash: fs_block.hash,
size: (fs_block.end - fs_block.start) as u32,
next: fs_block.next,
Expand All @@ -98,13 +99,10 @@ impl BlockExtra {

/// Returns the block from the bytes
///
/// This is an expensive operations, re-use the results instead of calling it multiple times
pub fn block(&self) -> Option<&Block> {
self.block.as_ref()
}

pub fn init_block(&mut self) {
self.block = Some(Block::consensus_decode(&mut &self.block_bytes[..]).unwrap());
/// This is an expensive operation, re-use the results instead of calling it multiple times
pub fn block(&self) -> &Block {
self.block
.get_or_init(|| Block::consensus_decode(&mut &self.block_bytes[..]).unwrap())
}

pub fn block_bytes(&self) -> &[u8] {
Expand Down Expand Up @@ -180,9 +178,7 @@ impl BlockExtra {
///
/// requires serializing the block bytes, consider using a visitor on the bytes for performance
pub fn iter_tx(&self) -> impl Iterator<Item = (&Txid, &Transaction)> {
self.txids
.iter()
.zip(self.block().expect("block not loaded").txdata.iter())
self.txids.iter().zip(self.block().txdata.iter())
}
}

Expand Down Expand Up @@ -246,7 +242,7 @@ impl Decodable for BlockExtra {
let mut b = BlockExtra {
version,
block_bytes,
block: None,
block: OnceLock::new(),
block_hash,
size,
next: Decodable::consensus_decode(d)?,
Expand Down Expand Up @@ -325,6 +321,7 @@ pub mod test {
use bitcoin::hashes::Hash;
use bitcoin::{BlockHash, CompactTarget};
use std::collections::HashMap;
use std::sync::OnceLock;

#[test]
fn block_extra_round_trip() {
Expand Down Expand Up @@ -358,7 +355,7 @@ pub mod test {
BlockExtra {
version: 0,
block_bytes,
block: None,
block: OnceLock::new(),
block_hash: BlockHash::all_zeros(),
size,
next: vec![BlockHash::all_zeros()],
Expand Down
2 changes: 1 addition & 1 deletion lib/src/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ mod inner_test {
let genesis = genesis_block(Network::Testnet);
let mut current = genesis.clone();
for b in iter(test_conf()).skip(1) {
let block = b.block().unwrap();
let block = b.block();
assert_eq!(current.block_hash(), block.header.prev_blockhash);
current = block.clone();
}
Expand Down
2 changes: 1 addition & 1 deletion lib/src/stages/fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl Fee {

let mut outpoint_values =
HashMap::with_capacity(block_extra.block_total_inputs());
let block = block_extra.block().expect("block is not loaded");
let block = block_extra.block();

for tx in block.txdata.iter().skip(1) {
for input in tx.input.iter() {
Expand Down
3 changes: 1 addition & 2 deletions lib/src/stages/reorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,11 @@ impl Reorder {
while let Some(block_to_send) = blocks.remove(&next) {
let mut block_extra: BlockExtra =
block_to_send.try_into().unwrap();
block_extra.init_block();
busy_time += now.elapsed().as_nanos();
next = block_extra.next[0];
block_extra.height = height;
blocks.follows.remove(&block_extra.block_hash);
let block = block_extra.block().expect("block is not loaded");
let block = block_extra.block();

blocks.blocks.remove(&block.header.prev_blockhash);

Expand Down
2 changes: 1 addition & 1 deletion lib/src/utxo/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl UtxoStore for DbUtxo {
height, self.updated_up_to_height
);
if height > self.updated_up_to_height {
let block = block_extra.block().expect("block is not loaded");
let block = block_extra.block();

// since we can spend outputs created in this same block, we first put outputs in memory...
let total_outputs = block_extra.block_total_outputs();
Expand Down
2 changes: 1 addition & 1 deletion lib/src/utxo/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl MemUtxo {

impl UtxoStore for MemUtxo {
fn add_outputs_get_inputs(&mut self, block_extra: &BlockExtra, _height: u32) -> Vec<TxOut> {
let block = block_extra.block().expect("block is not loaded");
let block = block_extra.block();
for (txid, tx) in block_extra.iter_tx() {
self.add_tx_outputs(txid, &tx);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/src/utxo/redb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl RedbUtxo {

impl UtxoStore for RedbUtxo {
fn add_outputs_get_inputs(&mut self, block_extra: &BlockExtra, height: u32) -> Vec<TxOut> {
let block = block_extra.block().expect("block is not loaded");
let block = block_extra.block();
// let mut outpoint_buffer = [0u8; 36]; // txid (32) + vout (4)

// max script size for spendable output is 10k https://bitcoin.stackexchange.com/a/35881/6693 ...
Expand Down

0 comments on commit 06c9c5d

Please sign in to comment.