diff --git a/CHANGELOG.md b/CHANGELOG.md index 9926c5631..631a4c470 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## v0.15.0 (TBD) + +- [BREAKING] Changed `GetBlockByNumber` to accept a `GetBlockByNumberRequest` (with optional `include_proof` flag) and returns a `GetBlockByNumberResponse` containing the block and an optional block proof ([#1864](https://github.com/0xMiden/node/pull/1864)). + ## v0.14.0 (TBD) ### Enhancements diff --git a/crates/rpc/src/server/api.rs b/crates/rpc/src/server/api.rs index f819054a2..f06efd021 100644 --- a/crates/rpc/src/server/api.rs +++ b/crates/rpc/src/server/api.rs @@ -233,8 +233,8 @@ impl api_server::Api for RpcService { async fn get_block_by_number( &self, - request: Request, - ) -> Result, Status> { + request: Request, + ) -> Result, Status> { let request = request.into_inner(); debug!(target: COMPONENT, ?request); diff --git a/crates/store/src/blocks.rs b/crates/store/src/blocks.rs index ad34ff0dd..dfb4d7e47 100644 --- a/crates/store/src/blocks.rs +++ b/crates/store/src/blocks.rs @@ -1,3 +1,12 @@ +//! File-based storage for raw block data and block proofs. +//! +//! Block data is stored under `{store_dir}/{epoch:04x}/block_{block_num:08x}.dat`, and proof data +//! for proven blocks is stored under `{store_dir}/{epoch:04x}/proof_{block_num:08x}.dat`. +//! +//! The epoch is derived from the 16 most significant bits of the block number (i.e., +//! `block_num >> 16`), and both the epoch and block number are formatted as zero-padded +//! hexadecimal strings. + use std::io::ErrorKind; use std::ops::Not; use std::path::PathBuf; @@ -96,6 +105,14 @@ impl BlockStore { fs_err::write(block_path, data) } + pub async fn load_proof(&self, block_num: BlockNumber) -> std::io::Result>> { + match tokio::fs::read(self.proof_path(block_num)).await { + Ok(data) => Ok(Some(data)), + Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(None), + Err(err) => Err(err), + } + } + // PROOF STORAGE // -------------------------------------------------------------------------------------------- diff --git a/crates/store/src/server/rpc_api.rs b/crates/store/src/server/rpc_api.rs index 2ef33295e..d5a913673 100644 --- a/crates/store/src/server/rpc_api.rs +++ b/crates/store/src/server/rpc_api.rs @@ -237,19 +237,24 @@ impl rpc_server::Rpc for StoreApi { async fn get_block_by_number( &self, - request: Request, - ) -> Result, Status> { + request: Request, + ) -> Result, Status> { let request = request.into_inner(); debug!(target: COMPONENT, ?request); - let block = self - .state - .load_block(request.block_num.into()) - .await - .map_err(GetBlockByNumberError::from)?; + // Load block from state. + let block_num = BlockNumber::from(request.block_num); + let block = self.state.load_block(block_num).await.map_err(GetBlockByNumberError::from)?; + + // Load proof from state. + let proof = if request.include_proof.unwrap_or_default() { + self.state.load_proof(block_num).await.map_err(GetBlockByNumberError::from)? + } else { + None + }; - Ok(Response::new(proto::blockchain::MaybeBlock { block })) + Ok(Response::new(proto::blockchain::GetBlockByNumberResponse { block, proof })) } async fn get_account( diff --git a/crates/store/src/state/mod.rs b/crates/store/src/state/mod.rs index 418c890de..91b1706d0 100644 --- a/crates/store/src/state/mod.rs +++ b/crates/store/src/state/mod.rs @@ -842,6 +842,17 @@ impl State { self.block_store.load_block(block_num).await.map_err(Into::into) } + /// Loads a block proof from the block store. Returns `Ok(None)` if the proof is not found. + pub async fn load_proof( + &self, + block_num: BlockNumber, + ) -> Result>, DatabaseError> { + if block_num > self.latest_block_num().await { + return Ok(None); + } + self.block_store.load_proof(block_num).await.map_err(Into::into) + } + /// Returns the latest block number. pub async fn latest_block_num(&self) -> BlockNumber { self.inner.read().await.latest_block_num() diff --git a/proto/proto/internal/store.proto b/proto/proto/internal/store.proto index 311c1482d..b13ac2368 100644 --- a/proto/proto/internal/store.proto +++ b/proto/proto/internal/store.proto @@ -34,8 +34,8 @@ service Rpc { // Returns the latest details the specified account. rpc GetAccount(rpc.AccountRequest) returns (rpc.AccountResponse) {} - // Returns raw block data for the specified block number. - rpc GetBlockByNumber(blockchain.BlockNumber) returns (blockchain.MaybeBlock) {} + // Returns raw block data for the specified block number, optionally including the block proof. + rpc GetBlockByNumber(blockchain.GetBlockByNumberRequest) returns (blockchain.GetBlockByNumberResponse) {} // Retrieves block header by given block number. Optionally, it also returns the MMR path // and current chain length to authenticate the block's inclusion. diff --git a/proto/proto/rpc.proto b/proto/proto/rpc.proto index 2823083d5..762134471 100644 --- a/proto/proto/rpc.proto +++ b/proto/proto/rpc.proto @@ -40,8 +40,8 @@ service Api { // Returns the latest details of the specified account. rpc GetAccount(AccountRequest) returns (AccountResponse) {} - // Returns raw block data for the specified block number. - rpc GetBlockByNumber(blockchain.BlockNumber) returns (blockchain.MaybeBlock) {} + // Returns raw block data for the specified block number, optionally including the block proof. + rpc GetBlockByNumber(blockchain.GetBlockByNumberRequest) returns (blockchain.GetBlockByNumberResponse) {} // Retrieves block header by given block number. Optionally, it also returns the MMR path // and current chain length to authenticate the block's inclusion. diff --git a/proto/proto/types/blockchain.proto b/proto/proto/types/blockchain.proto index e87a3648d..b0ae8c8ba 100644 --- a/proto/proto/types/blockchain.proto +++ b/proto/proto/types/blockchain.proto @@ -28,6 +28,24 @@ message MaybeBlock { optional bytes block = 1; } +// Request for retrieving a block by its number, optionally including the block proof. +message GetBlockByNumberRequest { + // The block number of the target block. + fixed32 block_num = 1; + // Whether to include the block proof in the response. + optional bool include_proof = 2; +} + +// Response containing the block data and optionally its proof. +message GetBlockByNumberResponse { + // The requested block data encoded using [miden_serde_utils::Serializable] implementation for + // [miden_protocol::block::Block]. + optional bytes block = 1; + // The block proof encoded using [miden_serde_utils::Serializable] implementation for + // [miden_protocol::block::BlockProof], if requested and available. + optional bytes proof = 2; +} + // Represents a block number. message BlockNumber { // The block number of the target block.