diff --git a/zingo-rpc/src/blockcache/block.rs b/zingo-rpc/src/blockcache/block.rs index ddbacc9..6afa6a1 100644 --- a/zingo-rpc/src/blockcache/block.rs +++ b/zingo-rpc/src/blockcache/block.rs @@ -4,7 +4,8 @@ use crate::{ blockcache::{ transaction::FullTransaction, utils::{ - read_bytes, read_i32, read_u32, read_zcash_script_i64, ParseError, ParseFromSlice, + display_txids_to_server, read_bytes, read_i32, read_u32, read_zcash_script_i64, + ParseError, ParseFromSlice, }, }, jsonrpc::{connector::JsonRpcConnector, primitives::GetBlockResponse}, @@ -227,9 +228,6 @@ impl ParseFromSlice for FullBlock { let (remaining_data, block_header_data) = BlockHeaderData::parse_from_slice(&data[cursor.position() as usize..], None)?; cursor.set_position(data.len() as u64 - remaining_data.len() as u64); - - println!("\nBlockHeaderData: {:?}\n", block_header_data); - let tx_count = CompactSize::read(&mut cursor)?; if txid.len() != tx_count as usize { return Err(ParseError::InvalidData(format!( @@ -253,8 +251,6 @@ impl ParseFromSlice for FullBlock { transactions.push(tx); remaining_data = new_remaining_data; } - println!("\nTransactions: {:?}\n", transactions); - let block_height = Self::get_block_height(&transactions)?; let block_hash = block_header_data.get_hash()?; @@ -330,6 +326,7 @@ impl FullBlock { }) .collect::, _>>()?; + // NOTE: LightWalletD doesnt return a compact block header, however this could be used to return data if required. // let header = self.hdr.raw_block_header.to_binary()?; let header = Vec::new(); @@ -378,6 +375,14 @@ pub async fn get_block_from_node( Some("xxxxxx".to_string()), ) .await; + println!( + "\ntest get_block_response: {:?}\n", + zebrad_client + .get_block(height.to_string(), Some(1)) + .await + .unwrap() + ); + let block_1 = zebrad_client.get_block(height.to_string(), Some(1)).await; match block_1 { Ok(GetBlockResponse::Object { @@ -402,14 +407,12 @@ pub async fn get_block_from_node( "Received object block type, this should not be possible here.".to_string(), )); } - Ok(GetBlockResponse::Raw(block_hex)) => { - Ok(FullBlock::parse_to_compact( - block_hex.as_ref(), - Some(tx.into_iter().map(|s| s.into_bytes()).collect()), - 0, //trees.sapling as u32, - 2, //trees.orchard as u32, - )?) - } + Ok(GetBlockResponse::Raw(block_hex)) => Ok(FullBlock::parse_to_compact( + block_hex.as_ref(), + Some(display_txids_to_server(tx)), + trees.sapling.size as u32, + trees.orchard.size as u32, + )?), Err(e) => { return Err(e.into()); } diff --git a/zingo-rpc/src/blockcache/utils.rs b/zingo-rpc/src/blockcache/utils.rs index bf9b693..9d5d3b0 100644 --- a/zingo-rpc/src/blockcache/utils.rs +++ b/zingo-rpc/src/blockcache/utils.rs @@ -141,3 +141,20 @@ pub fn read_zcash_script_i64(cursor: &mut Cursor<&[u8]>) -> Result) -> Vec> { + txids + .iter() + .map(|txid| { + txid.as_bytes() + .chunks(2) + .map(|chunk| { + let hex_pair = std::str::from_utf8(chunk).unwrap(); + u8::from_str_radix(hex_pair, 16).unwrap() + }) + .rev() + .collect() + }) + .collect() +} diff --git a/zingo-rpc/src/jsonrpc/connector.rs b/zingo-rpc/src/jsonrpc/connector.rs index 8ca8c40..e6dff58 100644 --- a/zingo-rpc/src/jsonrpc/connector.rs +++ b/zingo-rpc/src/jsonrpc/connector.rs @@ -301,8 +301,6 @@ impl JsonRpcConnector { /// /// - `hash_or_height`: (string, required, example="1") The hash or height for the block to be returned. /// - `verbosity`: (number, optional, default=1, example=1) 0 for hex encoded data, 1 for a json object, and 2 for json object with transaction data. - /// - /// NOTE: Currently unused by Zingo-Proxy and untested! pub async fn get_block( &self, hash_or_height: String, diff --git a/zingo-rpc/src/jsonrpc/primitives.rs b/zingo-rpc/src/jsonrpc/primitives.rs index c3f7281..e2ffd38 100644 --- a/zingo-rpc/src/jsonrpc/primitives.rs +++ b/zingo-rpc/src/jsonrpc/primitives.rs @@ -177,13 +177,26 @@ impl AsRef<[u8]> for ProxySerializedBlock { } } +/// Sapling note commitment tree information. +#[derive(Copy, Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] +pub struct ProxyTrees { + /// Commitment tree size. + pub size: u64, +} + +// /// Orchard note commitment tree information. +// #[derive(Copy, Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] +// pub struct ProxyOrchardTrees { +// pub size: u64, +// } + /// Information about the note commitment trees. #[derive(Copy, Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] pub struct ProxyBlockTrees { /// Sapling commitment tree size. - pub sapling: u64, + pub sapling: ProxyTrees, /// Orchard commitment tree size. - pub orchard: u64, + pub orchard: ProxyTrees, } /// Contains the hex-encoded hash of the sent transaction. @@ -215,7 +228,7 @@ pub enum GetBlockResponse { tx: Vec, /// Information about the note commitment trees. - trees: zebra_rpc::methods::GetBlockTrees, + trees: ProxyBlockTrees, //zebra_rpc::methods::GetBlockTrees, }, } diff --git a/zingo-rpc/src/rpc/service.rs b/zingo-rpc/src/rpc/service.rs index 3b87fac..40acc30 100644 --- a/zingo-rpc/src/rpc/service.rs +++ b/zingo-rpc/src/rpc/service.rs @@ -203,82 +203,82 @@ impl CompactTxStreamer for ProxyClient { /// Server streaming response type for the GetBlockRange method. #[doc = "Server streaming response type for the GetBlockRange method."] - type GetBlockRangeStream = tonic::Streaming; - // type GetBlockRangeStream = std::pin::Pin>; - - // /// Return a list of consecutive compact blocks. - // /// - // /// TODO: This implementation is slow. An internal block cache should be implemented that this rpc, along with the get_block rpc, can rely on. - // /// - add get_block function that queries the block cache for block and calls get_block_from_node to fetch block if not present. - // fn get_block_range<'life0, 'async_trait>( - // &'life0 self, - // request: tonic::Request, - // ) -> core::pin::Pin< - // Box< - // dyn core::future::Future< - // Output = std::result::Result< - // tonic::Response, - // tonic::Status, - // >, - // > + core::marker::Send - // + 'async_trait, - // >, - // > - // where - // 'life0: 'async_trait, - // Self: 'async_trait, - // { - // println!("@zingoproxyd: Received call of get_block_range."); - // let zebrad_uri = self.zebrad_uri.clone(); - // Box::pin(async move { - // let blockrange = request.into_inner(); - // let mut start = blockrange - // .start - // .map(|s| s.height as u32) - // .ok_or(tonic::Status::invalid_argument("Start block not specified"))?; - // let mut end = blockrange - // .end - // .map(|e| e.height as u32) - // .ok_or(tonic::Status::invalid_argument("End block not specified"))?; - // if start > end { - // (start, end) = (end, start); - // } - - // let (channel_tx, channel_rx) = tokio::sync::mpsc::channel(32); - // tokio::spawn(async move { - // for height in start..end { - // let compact_block = get_block_from_node(&zebrad_uri, &height).await; - // match compact_block { - // Ok(block) => { - // println!("\nCompact Block:\n{:?}\n", block); - - // if channel_tx.send(Ok(block)).await.is_err() { - // break; - // } - // } - // Err(e) => { - // if channel_tx - // .send(Err(tonic::Status::internal(e.to_string()))) - // .await - // .is_err() - // { - // break; - // } - // } - // } - // } - // }); - // let output_stream = CompactBlockStream::new(channel_rx); - // let stream_boxed = Box::pin(output_stream); - // Ok(tonic::Response::new(stream_boxed)) - // }) - // } - define_grpc_passthrough!( - fn get_block_range( - &self, - request: tonic::Request, - ) -> Self::GetBlockRangeStream - ); + // type GetBlockRangeStream = tonic::Streaming; + type GetBlockRangeStream = std::pin::Pin>; + + /// Return a list of consecutive compact blocks. + /// + /// TODO: This implementation is slow. An internal block cache should be implemented that this rpc, along with the get_block rpc, can rely on. + /// - add get_block function that queries the block cache for block and calls get_block_from_node to fetch block if not present. + fn get_block_range<'life0, 'async_trait>( + &'life0 self, + request: tonic::Request, + ) -> core::pin::Pin< + Box< + dyn core::future::Future< + Output = std::result::Result< + tonic::Response, + tonic::Status, + >, + > + core::marker::Send + + 'async_trait, + >, + > + where + 'life0: 'async_trait, + Self: 'async_trait, + { + println!("@zingoproxyd: Received call of get_block_range."); + let zebrad_uri = self.zebrad_uri.clone(); + Box::pin(async move { + let blockrange = request.into_inner(); + let mut start = blockrange + .start + .map(|s| s.height as u32) + .ok_or(tonic::Status::invalid_argument("Start block not specified"))?; + let mut end = blockrange + .end + .map(|e| e.height as u32) + .ok_or(tonic::Status::invalid_argument("End block not specified"))?; + if start > end { + (start, end) = (end, start); + } + + let (channel_tx, channel_rx) = tokio::sync::mpsc::channel(32); + tokio::spawn(async move { + for height in start..end { + let compact_block = get_block_from_node(&zebrad_uri, &height).await; + match compact_block { + Ok(block) => { + println!("\nCompact Block:\n{:?}\n", block); + + if channel_tx.send(Ok(block)).await.is_err() { + break; + } + } + Err(e) => { + if channel_tx + .send(Err(tonic::Status::internal(e.to_string()))) + .await + .is_err() + { + break; + } + } + } + } + }); + let output_stream = CompactBlockStream::new(channel_rx); + let stream_boxed = Box::pin(output_stream); + Ok(tonic::Response::new(stream_boxed)) + }) + } + // define_grpc_passthrough!( + // fn get_block_range( + // &self, + // request: tonic::Request, + // ) -> Self::GetBlockRangeStream + // ); /// Server streaming response type for the GetBlockRangeNullifiers method. #[doc = " Server streaming response type for the GetBlockRangeNullifiers method."]