From fc59cd09dc6cd87351121ab1c9247c4518376e8a Mon Sep 17 00:00:00 2001 From: Lance Vincent Salera Date: Thu, 15 May 2025 03:14:07 +0800 Subject: [PATCH 1/9] fix(serve): update BlockRef structure to use slot instead of index and add height field --- src/serve/grpc/sync.rs | 16 ++++++++++------ src/serve/grpc/watch.rs | 17 +++++++++++++---- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/serve/grpc/sync.rs b/src/serve/grpc/sync.rs index dd4aec402..1a2f4af96 100644 --- a/src/serve/grpc/sync.rs +++ b/src/serve/grpc/sync.rs @@ -17,7 +17,7 @@ use crate::wal::{self, ChainPoint, RawBlock, WalReader as _}; fn u5c_to_chain_point(block_ref: u5c::sync::BlockRef) -> Result { Ok(wal::ChainPoint::Specific( - block_ref.index, + block_ref.slot, super::convert::bytes_to_hash32(&block_ref.hash)?, )) } @@ -40,8 +40,9 @@ fn raw_to_blockref(raw: &wal::RawBlock) -> u5c::sync::BlockRef { let RawBlock { slot, hash, .. } = raw; u5c::sync::BlockRef { - index: *slot, + slot: *slot, hash: hash.to_vec().into(), + height: 0, } } @@ -69,15 +70,17 @@ fn point_to_reset_tip_response(point: ChainPoint) -> u5c::sync::FollowTipRespons match point { ChainPoint::Origin => u5c::sync::FollowTipResponse { action: u5c::sync::follow_tip_response::Action::Reset(BlockRef { + slot: 0, hash: vec![].into(), - index: 0, + height: 0, }) .into(), }, ChainPoint::Specific(slot, hash) => u5c::sync::FollowTipResponse { action: u5c::sync::follow_tip_response::Action::Reset(BlockRef { + slot, hash: hash.to_vec().into(), - index: slot, + height: 0, }) .into(), }, @@ -123,7 +126,7 @@ impl u5c::sync::sync_service_server::SyncService for SyncServiceImpl { .iter() .map(|br| { self.chain - .get_block_by_slot(&br.index) + .get_block_by_slot(&br.slot) .map_err(|_| Status::internal("Failed to query chain service."))? .map(|body| raw_to_anychain(&self.mapper, &body)) .ok_or(Status::not_found(format!("Failed to find block: {:?}", br))) @@ -228,8 +231,9 @@ impl u5c::sync::sync_service_server::SyncService for SyncServiceImpl { let response = u5c::sync::ReadTipResponse { tip: Some(BlockRef { - index: slot, + slot, hash: hash.to_vec().into(), + height: 0, }), }; diff --git a/src/serve/grpc/watch.rs b/src/serve/grpc/watch.rs index c2b6df113..322643acd 100644 --- a/src/serve/grpc/watch.rs +++ b/src/serve/grpc/watch.rs @@ -1,10 +1,9 @@ use crate::{ - state::LedgerStore, - wal::{self, ChainPoint, WalReader as _}, + model::BlockBody, state::LedgerStore, wal::{self, ChainPoint, WalReader as _} }; use futures_core::Stream; use futures_util::StreamExt; -use pallas::interop::utxorpc as interop; +use pallas::interop::utxorpc::{self as interop, Mapper}; use pallas::interop::utxorpc::spec as u5c; use pallas::{ interop::utxorpc::spec::watch::any_chain_tx_pattern::Chain, @@ -14,6 +13,15 @@ use std::pin::Pin; use tokio_util::sync::CancellationToken; use tonic::{Request, Response, Status}; +fn raw_to_anychain(mapper: &Mapper, body: &BlockBody) -> u5c::watch::AnyChainBlock { + let block = mapper.map_block_cbor(body); + + u5c::watch::AnyChainBlock { + native_bytes: body.to_vec().into(), + chain: u5c::watch::any_chain_block::Chain::Cardano(block).into(), + } +} + fn outputs_match_address( pattern: &u5c::cardano::AddressPattern, outputs: &[u5c::cardano::TxOutput], @@ -166,6 +174,7 @@ fn block_to_txs( .is_none_or(|predicate| apply_predicate(predicate, tx)) }) .map(|x| u5c::watch::AnyChainTx { + block: Some(raw_to_anychain(mapper, body)), chain: Some(u5c::watch::any_chain_tx::Chain::Cardano(x)), }) .collect() @@ -229,7 +238,7 @@ impl u5c::watch::watch_service_server::WatchService for WatchServiceImpl { let intersect = inner_req .intersect .iter() - .map(|x| ChainPoint::Specific(x.index, x.hash.to_vec().as_slice().into())) + .map(|x| ChainPoint::Specific(x.slot, x.hash.to_vec().as_slice().into())) .collect::>(); let from_seq = if intersect.is_empty() { From 00d9aeb16c7a342a698de7426b68d6894b3c00a4 Mon Sep 17 00:00:00 2001 From: Lance Vincent Salera Date: Mon, 19 May 2025 20:53:13 +0800 Subject: [PATCH 2/9] fix(sync): enhance block height retrieval in raw_to_blockref and ReadTipResponse --- src/serve/grpc/sync.rs | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/serve/grpc/sync.rs b/src/serve/grpc/sync.rs index 1a2f4af96..fbed28a8f 100644 --- a/src/serve/grpc/sync.rs +++ b/src/serve/grpc/sync.rs @@ -27,6 +27,19 @@ fn u5c_to_chain_point(block_ref: u5c::sync::BlockRef) -> Result Result { + let block_body = chain + .get_block_by_slot(&slot) + .map_err(|_| Status::internal("Failed to query chain service.".to_string()))? + .ok_or(Status::not_found("Failed to find block.".to_string()))?; + + let height = MultiEraBlock::decode(&block_body) + .map_err(|_| Status::internal("Failed to decode block."))? + .number(); + + Ok(height) +} + fn raw_to_anychain(mapper: &Mapper, body: &BlockBody) -> u5c::sync::AnyChainBlock { let block = mapper.map_block_cbor(body); @@ -36,13 +49,17 @@ fn raw_to_anychain(mapper: &Mapper, body: &BlockBody) -> u5c::sync: } } -fn raw_to_blockref(raw: &wal::RawBlock) -> u5c::sync::BlockRef { +fn raw_to_blockref(raw: &wal::RawBlock, chain: &ChainStore) -> u5c::sync::BlockRef { let RawBlock { slot, hash, .. } = raw; + let height = get_block_height(chain, *slot) + .map_err(|_| Status::internal("Failed to query chain service.".to_string())) + .unwrap_or(0); + u5c::sync::BlockRef { slot: *slot, hash: hash.to_vec().into(), - height: 0, + height, } } @@ -158,7 +175,7 @@ impl u5c::sync::sync_service_server::SyncService for SyncServiceImpl { if idx < len - 1 { Either::Left(raw_to_anychain(&self.mapper, &x.body)) } else { - Either::Right(raw_to_blockref(&x)) + Either::Right(raw_to_blockref(&x, &self.chain)) } }); @@ -229,11 +246,13 @@ impl u5c::sync::sync_service_server::SyncService for SyncServiceImpl { .map_err(|_| Status::internal("Failed to decode tip block."))? .hash(); + let height = get_block_height(&self.chain, slot)?; + let response = u5c::sync::ReadTipResponse { tip: Some(BlockRef { slot, hash: hash.to_vec().into(), - height: 0, + height, }), }; From eb4e6fbe00671b47e961de0162075b49d6b444b9 Mon Sep 17 00:00:00 2001 From: Lance Vincent Salera Date: Mon, 19 May 2025 21:21:22 +0800 Subject: [PATCH 3/9] fix(sync): update point_to_reset_tip_response to include chain parameter and handle block height retrieval --- src/serve/grpc/sync.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/serve/grpc/sync.rs b/src/serve/grpc/sync.rs index fbed28a8f..b83551380 100644 --- a/src/serve/grpc/sync.rs +++ b/src/serve/grpc/sync.rs @@ -83,7 +83,10 @@ fn wal_log_to_tip_response( } } -fn point_to_reset_tip_response(point: ChainPoint) -> u5c::sync::FollowTipResponse { +fn point_to_reset_tip_response( + point: ChainPoint, + chain: ChainStore, +) -> u5c::sync::FollowTipResponse { match point { ChainPoint::Origin => u5c::sync::FollowTipResponse { action: u5c::sync::follow_tip_response::Action::Reset(BlockRef { @@ -97,7 +100,9 @@ fn point_to_reset_tip_response(point: ChainPoint) -> u5c::sync::FollowTipRespons action: u5c::sync::follow_tip_response::Action::Reset(BlockRef { slot, hash: hash.to_vec().into(), - height: 0, + height: get_block_height(&chain, slot) + .map_err(|_| Status::internal("Failed to query chain service.".to_string())) + .unwrap_or(0), }) .into(), }, @@ -220,7 +225,8 @@ impl u5c::sync::sync_service_server::SyncService for SyncServiceImpl { // the consumer knows what intersection was found and can reset their state // This would also mimic ouroboros giving a `Rollback` as the first message. - let reset = once(async { Ok(point_to_reset_tip_response(point)) }); + let chain = self.chain.clone(); + let reset = once(async { Ok(point_to_reset_tip_response(point, chain)) }); let forward = wal::WalStream::start(self.wal.clone(), from_seq, self.cancellation_token.clone()) From 916ff00b4648eb90f0f87edf80260fc93448e3dd Mon Sep 17 00:00:00 2001 From: Lance Vincent Salera Date: Mon, 19 May 2025 21:42:14 +0800 Subject: [PATCH 4/9] fix(sync): reorder parameters in get_block_height and update error handling in related functions --- src/serve/grpc/sync.rs | 69 +++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/src/serve/grpc/sync.rs b/src/serve/grpc/sync.rs index b83551380..9ea344826 100644 --- a/src/serve/grpc/sync.rs +++ b/src/serve/grpc/sync.rs @@ -27,14 +27,14 @@ fn u5c_to_chain_point(block_ref: u5c::sync::BlockRef) -> Result Result { +fn get_block_height(slot: u64, chain: &ChainStore) -> Result { let block_body = chain .get_block_by_slot(&slot) .map_err(|_| Status::internal("Failed to query chain service.".to_string()))? - .ok_or(Status::not_found("Failed to find block.".to_string()))?; + .ok_or_else(|| Status::not_found(format!("No block at slot {}", slot)))?; let height = MultiEraBlock::decode(&block_body) - .map_err(|_| Status::internal("Failed to decode block."))? + .map_err(|e| Status::internal(format!("block decode error: {}", e)))? .number(); Ok(height) @@ -49,12 +49,15 @@ fn raw_to_anychain(mapper: &Mapper, body: &BlockBody) -> u5c::sync: } } -fn raw_to_blockref(raw: &wal::RawBlock, chain: &ChainStore) -> u5c::sync::BlockRef { - let RawBlock { slot, hash, .. } = raw; +fn raw_to_blockref(raw: &wal::RawBlock) -> u5c::sync::BlockRef { + let RawBlock { + slot, hash, body, .. + } = raw; - let height = get_block_height(chain, *slot) - .map_err(|_| Status::internal("Failed to query chain service.".to_string())) - .unwrap_or(0); + let height = MultiEraBlock::decode(body) + .map_err(|e| panic!("corrupt WAL entry: {:?}", e)) + .unwrap() + .number(); u5c::sync::BlockRef { slot: *slot, @@ -86,27 +89,31 @@ fn wal_log_to_tip_response( fn point_to_reset_tip_response( point: ChainPoint, chain: ChainStore, -) -> u5c::sync::FollowTipResponse { - match point { - ChainPoint::Origin => u5c::sync::FollowTipResponse { - action: u5c::sync::follow_tip_response::Action::Reset(BlockRef { - slot: 0, - hash: vec![].into(), - height: 0, +) -> Result { + let (slot, hash) = match point { + ChainPoint::Origin => { + return Ok(u5c::sync::FollowTipResponse { + action: u5c::sync::follow_tip_response::Action::Reset(BlockRef { + slot: 0, + hash: vec![].into(), + height: 0, + }) + .into(), }) - .into(), - }, - ChainPoint::Specific(slot, hash) => u5c::sync::FollowTipResponse { - action: u5c::sync::follow_tip_response::Action::Reset(BlockRef { - slot, - hash: hash.to_vec().into(), - height: get_block_height(&chain, slot) - .map_err(|_| Status::internal("Failed to query chain service.".to_string())) - .unwrap_or(0), - }) - .into(), - }, - } + } + ChainPoint::Specific(s, h) => (s, h.to_vec()), + }; + + let height = get_block_height(slot, &chain)?; + + Ok(u5c::sync::FollowTipResponse { + action: u5c::sync::follow_tip_response::Action::Reset(BlockRef { + slot, + hash: hash.into(), + height, + }) + .into(), + }) } pub struct SyncServiceImpl { @@ -180,7 +187,7 @@ impl u5c::sync::sync_service_server::SyncService for SyncServiceImpl { if idx < len - 1 { Either::Left(raw_to_anychain(&self.mapper, &x.body)) } else { - Either::Right(raw_to_blockref(&x, &self.chain)) + Either::Right(raw_to_blockref(&x)) } }); @@ -226,7 +233,7 @@ impl u5c::sync::sync_service_server::SyncService for SyncServiceImpl { // This would also mimic ouroboros giving a `Rollback` as the first message. let chain = self.chain.clone(); - let reset = once(async { Ok(point_to_reset_tip_response(point, chain)) }); + let reset = once(async { point_to_reset_tip_response(point, chain) }); let forward = wal::WalStream::start(self.wal.clone(), from_seq, self.cancellation_token.clone()) @@ -252,7 +259,7 @@ impl u5c::sync::sync_service_server::SyncService for SyncServiceImpl { .map_err(|_| Status::internal("Failed to decode tip block."))? .hash(); - let height = get_block_height(&self.chain, slot)?; + let height = get_block_height(slot, &self.chain)?; let response = u5c::sync::ReadTipResponse { tip: Some(BlockRef { From c0f5dbd417900734b5153acce2d9d3ec2fc158dd Mon Sep 17 00:00:00 2001 From: Lance Vincent Salera Date: Mon, 19 May 2025 22:13:25 +0800 Subject: [PATCH 5/9] fix(sync): replace get_block_height call with direct decoding of block body in ReadTipResponse --- src/serve/grpc/sync.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/serve/grpc/sync.rs b/src/serve/grpc/sync.rs index 9ea344826..76e8d71be 100644 --- a/src/serve/grpc/sync.rs +++ b/src/serve/grpc/sync.rs @@ -259,7 +259,9 @@ impl u5c::sync::sync_service_server::SyncService for SyncServiceImpl { .map_err(|_| Status::internal("Failed to decode tip block."))? .hash(); - let height = get_block_height(slot, &self.chain)?; + let height = MultiEraBlock::decode(&body) + .map_err(|_| Status::internal("Failed to decode tip block."))? + .number(); let response = u5c::sync::ReadTipResponse { tip: Some(BlockRef { From 0ca631b032e19fd7779376414f869f5751a666c9 Mon Sep 17 00:00:00 2001 From: Lance Vincent Salera Date: Mon, 19 May 2025 23:02:20 +0800 Subject: [PATCH 6/9] fix(sync): remove get_block_height function and update point_to_reset_tip_response to decode block height directly from RawBlock --- src/serve/grpc/sync.rs | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/src/serve/grpc/sync.rs b/src/serve/grpc/sync.rs index 76e8d71be..9d3cb8a01 100644 --- a/src/serve/grpc/sync.rs +++ b/src/serve/grpc/sync.rs @@ -27,19 +27,6 @@ fn u5c_to_chain_point(block_ref: u5c::sync::BlockRef) -> Result Result { - let block_body = chain - .get_block_by_slot(&slot) - .map_err(|_| Status::internal("Failed to query chain service.".to_string()))? - .ok_or_else(|| Status::not_found(format!("No block at slot {}", slot)))?; - - let height = MultiEraBlock::decode(&block_body) - .map_err(|e| Status::internal(format!("block decode error: {}", e)))? - .number(); - - Ok(height) -} - fn raw_to_anychain(mapper: &Mapper, body: &BlockBody) -> u5c::sync::AnyChainBlock { let block = mapper.map_block_cbor(body); @@ -88,7 +75,7 @@ fn wal_log_to_tip_response( fn point_to_reset_tip_response( point: ChainPoint, - chain: ChainStore, + raw: RawBlock, ) -> Result { let (slot, hash) = match point { ChainPoint::Origin => { @@ -104,7 +91,10 @@ fn point_to_reset_tip_response( ChainPoint::Specific(s, h) => (s, h.to_vec()), }; - let height = get_block_height(slot, &chain)?; + let height = MultiEraBlock::decode(&raw.body) + .map_err(|e| panic!("corrupt WAL entry: {:?}", e)) + .unwrap() + .number(); Ok(u5c::sync::FollowTipResponse { action: u5c::sync::follow_tip_response::Action::Reset(BlockRef { @@ -232,8 +222,12 @@ impl u5c::sync::sync_service_server::SyncService for SyncServiceImpl { // the consumer knows what intersection was found and can reset their state // This would also mimic ouroboros giving a `Rollback` as the first message. - let chain = self.chain.clone(); - let reset = once(async { point_to_reset_tip_response(point, chain) }); + let raw_block = self + .wal + .read_block(&point) + .map_err(|_err| Status::internal("can't read WAL"))?; + + let reset = once(async { point_to_reset_tip_response(point, raw_block) }); let forward = wal::WalStream::start(self.wal.clone(), from_seq, self.cancellation_token.clone()) @@ -255,13 +249,11 @@ impl u5c::sync::sync_service_server::SyncService for SyncServiceImpl { .map_err(|e| Status::internal(format!("Unable to read WAL: {:?}", e)))? .ok_or(Status::internal("chain has no data."))?; - let hash = MultiEraBlock::decode(&body) - .map_err(|_| Status::internal("Failed to decode tip block."))? - .hash(); + let block = MultiEraBlock::decode(&body) + .map_err(|_| Status::internal("Failed to decode tip block."))?; - let height = MultiEraBlock::decode(&body) - .map_err(|_| Status::internal("Failed to decode tip block."))? - .number(); + let hash = block.hash(); + let height = block.number(); let response = u5c::sync::ReadTipResponse { tip: Some(BlockRef { From 3b05dd13c1ec201c0caeae1bdfce58ddc89e4e2e Mon Sep 17 00:00:00 2001 From: Lance Vincent Salera Date: Tue, 20 May 2025 02:58:37 +0800 Subject: [PATCH 7/9] fix(sync): update point_to_reset_tip_response to use wal::RawBlock type and improve error handling for block decoding --- src/serve/grpc/sync.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/serve/grpc/sync.rs b/src/serve/grpc/sync.rs index 9d3cb8a01..c3ff6b19f 100644 --- a/src/serve/grpc/sync.rs +++ b/src/serve/grpc/sync.rs @@ -75,7 +75,7 @@ fn wal_log_to_tip_response( fn point_to_reset_tip_response( point: ChainPoint, - raw: RawBlock, + raw: wal::RawBlock, ) -> Result { let (slot, hash) = match point { ChainPoint::Origin => { @@ -92,8 +92,7 @@ fn point_to_reset_tip_response( }; let height = MultiEraBlock::decode(&raw.body) - .map_err(|e| panic!("corrupt WAL entry: {:?}", e)) - .unwrap() + .map_err(|_| Status::internal("Failed to decode block."))? .number(); Ok(u5c::sync::FollowTipResponse { From fcdd0918ad8d89cf8942012bbbdcc822cde373c1 Mon Sep 17 00:00:00 2001 From: Lance Vincent Salera Date: Wed, 21 May 2025 21:30:48 +0800 Subject: [PATCH 8/9] fix(serve): refactor point_to_reset_tip_response to accept block height directly and improve response handling --- src/serve/grpc/sync.rs | 53 ++++++++++++++++++----------------------- src/serve/grpc/watch.rs | 6 +++-- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/serve/grpc/sync.rs b/src/serve/grpc/sync.rs index c3ff6b19f..6018346ae 100644 --- a/src/serve/grpc/sync.rs +++ b/src/serve/grpc/sync.rs @@ -73,36 +73,25 @@ fn wal_log_to_tip_response( } } -fn point_to_reset_tip_response( - point: ChainPoint, - raw: wal::RawBlock, -) -> Result { - let (slot, hash) = match point { - ChainPoint::Origin => { - return Ok(u5c::sync::FollowTipResponse { - action: u5c::sync::follow_tip_response::Action::Reset(BlockRef { - slot: 0, - hash: vec![].into(), - height: 0, - }) - .into(), +fn point_to_reset_tip_response(point: ChainPoint, height: u64) -> u5c::sync::FollowTipResponse { + match point { + ChainPoint::Origin => u5c::sync::FollowTipResponse { + action: u5c::sync::follow_tip_response::Action::Reset(BlockRef { + slot: 0, + hash: vec![].into(), + height: 0, }) - } - ChainPoint::Specific(s, h) => (s, h.to_vec()), - }; - - let height = MultiEraBlock::decode(&raw.body) - .map_err(|_| Status::internal("Failed to decode block."))? - .number(); - - Ok(u5c::sync::FollowTipResponse { - action: u5c::sync::follow_tip_response::Action::Reset(BlockRef { - slot, - hash: hash.into(), - height, - }) - .into(), - }) + .into(), + }, + ChainPoint::Specific(slot, hash) => u5c::sync::FollowTipResponse { + action: u5c::sync::follow_tip_response::Action::Reset(BlockRef { + slot, + hash: hash.to_vec().into(), + height, + }) + .into(), + }, + } } pub struct SyncServiceImpl { @@ -226,7 +215,11 @@ impl u5c::sync::sync_service_server::SyncService for SyncServiceImpl { .read_block(&point) .map_err(|_err| Status::internal("can't read WAL"))?; - let reset = once(async { point_to_reset_tip_response(point, raw_block) }); + let height = MultiEraBlock::decode(&raw_block.body) + .map_err(|e| Status::internal(format!("corrupt WAL entry: {:?}", e)))? + .number(); + + let reset = once(async move { Ok(point_to_reset_tip_response(point, height)) }); let forward = wal::WalStream::start(self.wal.clone(), from_seq, self.cancellation_token.clone()) diff --git a/src/serve/grpc/watch.rs b/src/serve/grpc/watch.rs index 322643acd..2cacf0fb1 100644 --- a/src/serve/grpc/watch.rs +++ b/src/serve/grpc/watch.rs @@ -1,10 +1,12 @@ use crate::{ - model::BlockBody, state::LedgerStore, wal::{self, ChainPoint, WalReader as _} + model::BlockBody, + state::LedgerStore, + wal::{self, ChainPoint, WalReader as _}, }; use futures_core::Stream; use futures_util::StreamExt; -use pallas::interop::utxorpc::{self as interop, Mapper}; use pallas::interop::utxorpc::spec as u5c; +use pallas::interop::utxorpc::{self as interop, Mapper}; use pallas::{ interop::utxorpc::spec::watch::any_chain_tx_pattern::Chain, ledger::{addresses::Address, traverse::MultiEraBlock}, From cf8f8beb75ec7240da3b5040bd52902b16f1d3bb Mon Sep 17 00:00:00 2001 From: Lance Vincent Salera Date: Tue, 27 May 2025 19:11:55 +0800 Subject: [PATCH 9/9] fix: enhance block retrieval logic in SyncService implementation --- src/serve/grpc/sync.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/serve/grpc/sync.rs b/src/serve/grpc/sync.rs index 6018346ae..abe91a597 100644 --- a/src/serve/grpc/sync.rs +++ b/src/serve/grpc/sync.rs @@ -132,11 +132,18 @@ impl u5c::sync::sync_service_server::SyncService for SyncServiceImpl { .r#ref .iter() .map(|br| { - self.chain - .get_block_by_slot(&br.slot) - .map_err(|_| Status::internal("Failed to query chain service."))? - .map(|body| raw_to_anychain(&self.mapper, &body)) - .ok_or(Status::not_found(format!("Failed to find block: {:?}", br))) + let body = match br { + BlockRef { hash, .. } if !hash.is_empty() => self.chain.get_block_by_hash(hash), + BlockRef { slot, .. } if *slot != 0 => self.chain.get_block_by_slot(slot), + BlockRef { height, .. } if *height != 0 => { + self.chain.get_block_by_number(height) + } + _ => self.chain.get_block_by_slot(&br.slot), + } + .map_err(|_err| Status::internal("Failed to query chain service."))? + .ok_or(Status::not_found(format!("Failed to find block: {:?}", br)))?; + + Ok(raw_to_anychain(&self.mapper, &body)) }) .collect::, Status>>()?;