diff --git a/storage/blockchain/src/ops/alt_block/block.rs b/storage/blockchain/src/ops/alt_block/block.rs index a6ad1da36..3e45a4b68 100644 --- a/storage/blockchain/src/ops/alt_block/block.rs +++ b/storage/blockchain/src/ops/alt_block/block.rs @@ -94,7 +94,7 @@ pub fn add_alt_block( /// /// This function will look at only the blocks with the given [`AltBlockHeight::chain_id`], no others /// even if they are technically part of this chain. -pub fn get_alt_block( +pub fn get_alt_block_information( db: &BlockchainDatabase, alt_block_height: &AltBlockHeight, tx_ro: &fjall::Snapshot, @@ -134,6 +134,22 @@ pub fn get_alt_block( }) } +/// Retrieve an alt [`Block`] via its [`AltBlockHeight`]. +/// +/// This function will look at only the blocks with the given [`AltBlockHeight::chain_id`], no others +/// even if they are technically part of this chain. +pub fn get_alt_block( + db: &BlockchainDatabase, + alt_block_height: &AltBlockHeight, + tx_ro: &fjall::Snapshot, +) -> DbResult { + let block_blob = tx_ro + .get(&db.alt_block_blobs, bytemuck::bytes_of(alt_block_height))? + .ok_or(BlockchainError::NotFound)?; + + Ok(Block::read(&mut block_blob.as_ref()).unwrap()) +} + /// Retrieves the hash of the block at the given `block_height` on the alt chain with /// the given [`ChainId`]. /// @@ -227,3 +243,16 @@ pub fn get_alt_block_extended_header_from_height( long_term_weight: block_info.long_term_weight, }) } + +/// Returns the [`AltBlockHeight`] of a block from its hash, only if it is in an alt chain. +pub(crate) fn alt_block_height( + db: &BlockchainDatabase, + tx_ro: &fjall::Snapshot, + hash: &BlockHash, +) -> DbResult> { + let Some(bytes) = tx_ro.get(&db.alt_block_heights, hash)? else { + return Ok(None); + }; + + Ok(Some(bytemuck::pod_read_unaligned(bytes.as_ref()))) +} diff --git a/storage/blockchain/src/ops/alt_block/mod.rs b/storage/blockchain/src/ops/alt_block/mod.rs index 4d57f29ad..cc8339209 100644 --- a/storage/blockchain/src/ops/alt_block/mod.rs +++ b/storage/blockchain/src/ops/alt_block/mod.rs @@ -51,9 +51,10 @@ mod block; mod chain; mod tx; +pub(crate) use block::alt_block_height; pub use block::{ add_alt_block, flush_alt_blocks, get_alt_block, get_alt_block_extended_header_from_height, - get_alt_block_hash, + get_alt_block_hash, get_alt_block_information, }; pub use chain::{get_alt_chain_history_ranges, update_alt_chain_info}; pub use tx::{add_alt_transaction_blob, get_alt_transaction}; diff --git a/storage/blockchain/src/ops/block.rs b/storage/blockchain/src/ops/block.rs index 15c27e96b..709524093 100644 --- a/storage/blockchain/src/ops/block.rs +++ b/storage/blockchain/src/ops/block.rs @@ -779,7 +779,7 @@ pub fn block_exists( pub(crate) fn block_height( db: &BlockchainDatabase, tx_ro: &fjall::Snapshot, - hash: &[u8; 32], + hash: &BlockHash, ) -> DbResult> { let Some(block_height) = tx_ro.get(&db.block_heights, hash)? else { return Ok(None); diff --git a/storage/blockchain/src/service/read.rs b/storage/blockchain/src/service/read.rs index 621b00d5a..f2df6aa09 100644 --- a/storage/blockchain/src/service/read.rs +++ b/storage/blockchain/src/service/read.rs @@ -44,8 +44,8 @@ use crate::{ error::{BlockchainError, DbResult}, ops::{ alt_block::{ - get_alt_block, get_alt_block_extended_header_from_height, get_alt_block_hash, - get_alt_chain_history_ranges, + alt_block_height, get_alt_block, get_alt_block_extended_header_from_height, + get_alt_block_hash, get_alt_block_information, get_alt_chain_history_ranges, }, block::{ block_exists, block_height, get_block, get_block_by_hash, get_block_complete_entry, @@ -290,22 +290,15 @@ fn block_hash_in_range( fn find_block(db: &BlockchainDatabase, block_hash: BlockHash) -> ResponseResult { let tx_ro = db.fjall.snapshot(); - // Check the main chain first. - if let Some(height) = block_height(db, &tx_ro, &block_hash)? { - return Ok(BlockchainResponse::FindBlock(Some((Chain::Main, height)))); - } - - match tx_ro.get(&db.alt_block_heights, block_hash)? { - Some(height) => { - let height: AltBlockHeight = bytemuck::pod_read_unaligned(height.as_ref()); + // Check the main chain first, then alt chains. + let location = if let Some(height) = block_height(db, &tx_ro, &block_hash)? { + Some((Chain::Main, height)) + } else { + alt_block_height(db, &tx_ro, &block_hash)? + .map(|alt| (Chain::Alt(alt.chain_id.into()), alt.height)) + }; - Ok(BlockchainResponse::FindBlock(Some(( - Chain::Alt(height.chain_id.into()), - height.height, - )))) - } - None => Ok(BlockchainResponse::FindBlock(None)), - } + Ok(BlockchainResponse::FindBlock(location)) } /// [`BlockchainReadRequest::FilterUnknownHashes`]. @@ -704,36 +697,58 @@ fn find_first_unknown(db: &BlockchainDatabase, block_ids: &[BlockHash]) -> Respo /// [`BlockchainReadRequest::TxsInBlock`] fn txs_in_block( db: &BlockchainDatabase, - block_hash: [u8; 32], + block_hash: BlockHash, missing_txs: Vec, ) -> ResponseResult { let tx_ro = db.fjall.snapshot(); let tapes = db.linear_tapes.reader(); - let block_height = usize::from_le_bytes( - tx_ro - .get(&db.block_heights, block_hash)? - .ok_or(BlockchainError::NotFound)? - .as_ref() - .try_into() - .unwrap(), - ); + // Check the main chain first, fall back to alt blocks if not found. + let (block, txs) = if let Some(block_height) = block_height(db, &tx_ro, &block_hash)? { + let block_info = tapes + .read_entry(&db.block_infos, usize_to_u64(block_height))? + .ok_or(BlockchainError::NotFound)?; - let block_info = tapes - .read_entry(&db.block_infos, usize_to_u64(block_height))? - .ok_or(BlockchainError::NotFound)?; + let block = get_block(&block_height, Some(&block_info), &tapes, db)?; + let first_tx_index = block_info.mining_tx_index + 1; - let block = get_block(&block_height, None, &tapes, db)?; - let first_tx_index = block_info.mining_tx_index + 1; + if block.transactions.len() < missing_txs.len() { + return Ok(BlockchainResponse::TxsInBlock(None)); + } - if block.transactions.len() < missing_txs.len() { - return Ok(BlockchainResponse::TxsInBlock(None)); - } + let txs = missing_txs + .into_iter() + .map(|index_offset| get_tx_blob_from_id(&(first_tx_index + index_offset), &tapes, db)) + .collect::>()?; - let txs = missing_txs - .into_iter() - .map(|index_offset| get_tx_blob_from_id(&(first_tx_index + index_offset), &tapes, db)) - .collect::>()?; + (block, txs) + } else { + let alt_block_height = + alt_block_height(db, &tx_ro, &block_hash)?.ok_or(BlockchainError::NotFound)?; + + let block = get_alt_block(db, &alt_block_height, &tx_ro)?; + + if block.transactions.len() < missing_txs.len() { + return Ok(BlockchainResponse::TxsInBlock(None)); + } + + let txs = missing_txs + .into_iter() + .map(|index_offset| { + let tx_hash = block + .transactions + .get(u64_to_usize(index_offset)) + .ok_or(BlockchainError::NotFound)?; + + tx_ro + .get(&db.alt_transaction_blobs, tx_hash)? + .map(|blob| blob.to_vec()) + .ok_or(BlockchainError::NotFound) + }) + .collect::>()?; + + (block, txs) + }; Ok(BlockchainResponse::TxsInBlock(Some(TxsInBlock { block: block.serialize(), @@ -759,7 +774,7 @@ fn alt_blocks_in_chain(db: &BlockchainDatabase, chain_id: ChainId) -> ResponseRe }; range.clone().map(|height| { - get_alt_block( + get_alt_block_information( db, &AltBlockHeight { chain_id: (*chain_id).into(),