add support for getblock with verbosity=1 (#4511)
This commit is contained in:
parent
c50ee7e478
commit
95f14ffdcd
|
@ -162,3 +162,9 @@ impl AsRef<[u8]> for SerializedBlock {
|
|||
self.bytes.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for SerializedBlock {
|
||||
fn from(bytes: Vec<u8>) -> Self {
|
||||
Self { bytes }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,16 +126,18 @@ pub trait Rpc {
|
|||
/// # Parameters
|
||||
///
|
||||
/// - `height`: (string, required) The height number for the block to be returned.
|
||||
/// - `verbosity`: (numeric, optional, default=1) 0 for hex encoded data, 1 for a json object,
|
||||
/// and 2 for json object with transaction data.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// We only expose the `data` field as lightwalletd uses the non-verbose
|
||||
/// mode for all getblock calls: <https://github.com/zcash/lightwalletd/blob/v0.4.9/common/common.go#L232>
|
||||
/// With verbosity=1, [`lightwalletd` only reads the `tx` field of the
|
||||
/// result](https://github.com/zcash/lightwalletd/blob/dfac02093d85fb31fb9a8475b884dd6abca966c7/common/common.go#L152),
|
||||
/// so we only return that for now.
|
||||
///
|
||||
/// `lightwalletd` only requests blocks by height, so we don't support
|
||||
/// getting blocks by hash. (But we parse the height as a JSON string, not an integer).
|
||||
///
|
||||
/// The `verbosity` parameter is ignored but required in the call.
|
||||
/// `lightwalletd` also does not use verbosity=2, so we don't support it.
|
||||
#[rpc(name = "getblock")]
|
||||
fn get_block(&self, height: String, verbosity: u8) -> BoxFuture<Result<GetBlock>>;
|
||||
|
||||
|
@ -515,7 +517,7 @@ where
|
|||
.boxed()
|
||||
}
|
||||
|
||||
fn get_block(&self, height: String, _verbosity: u8) -> BoxFuture<Result<GetBlock>> {
|
||||
fn get_block(&self, height: String, verbosity: u8) -> BoxFuture<Result<GetBlock>> {
|
||||
let mut state = self.state.clone();
|
||||
|
||||
async move {
|
||||
|
@ -538,7 +540,21 @@ where
|
|||
})?;
|
||||
|
||||
match response {
|
||||
zebra_state::ReadResponse::Block(Some(block)) => Ok(GetBlock(block.into())),
|
||||
zebra_state::ReadResponse::Block(Some(block)) => match verbosity {
|
||||
0 => Ok(GetBlock::Raw(block.into())),
|
||||
1 => Ok(GetBlock::Object {
|
||||
tx: block
|
||||
.transactions
|
||||
.iter()
|
||||
.map(|tx| tx.hash().encode_hex())
|
||||
.collect(),
|
||||
}),
|
||||
_ => Err(Error {
|
||||
code: ErrorCode::InvalidParams,
|
||||
message: "Invalid verbosity value".to_string(),
|
||||
data: None,
|
||||
}),
|
||||
},
|
||||
zebra_state::ReadResponse::Block(None) => Err(Error {
|
||||
code: MISSING_BLOCK_ERROR_CODE,
|
||||
message: "Block not found".to_string(),
|
||||
|
@ -1070,7 +1086,16 @@ pub struct SentTransactionHash(#[serde(with = "hex")] transaction::Hash);
|
|||
///
|
||||
/// See the notes for the [`Rpc::get_block` method].
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
|
||||
pub struct GetBlock(#[serde(with = "hex")] SerializedBlock);
|
||||
#[serde(untagged)]
|
||||
pub enum GetBlock {
|
||||
/// The request block, hex-encoded.
|
||||
Raw(#[serde(with = "hex")] SerializedBlock),
|
||||
/// The block object.
|
||||
Object {
|
||||
/// Vector of hex-encoded TXIDs of the transactions of the block
|
||||
tx: Vec<String>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Response to a `getbestblockhash` RPC request.
|
||||
///
|
||||
|
|
|
@ -82,7 +82,7 @@ async fn test_rpc_response_data_for_network(network: Network) {
|
|||
.expect("We should have an AddressBalance struct");
|
||||
snapshot_rpc_getaddressbalance(get_address_balance, &settings);
|
||||
|
||||
// `getblock`
|
||||
// `getblock`, verbosity=0
|
||||
const BLOCK_HEIGHT: u32 = 1;
|
||||
let get_block = rpc
|
||||
.get_block(BLOCK_HEIGHT.to_string(), 0u8)
|
||||
|
@ -90,6 +90,13 @@ async fn test_rpc_response_data_for_network(network: Network) {
|
|||
.expect("We should have a GetBlock struct");
|
||||
snapshot_rpc_getblock(get_block, block_data.get(&BLOCK_HEIGHT).unwrap(), &settings);
|
||||
|
||||
// `getblock`, verbosity=1
|
||||
let get_block = rpc
|
||||
.get_block(BLOCK_HEIGHT.to_string(), 1u8)
|
||||
.await
|
||||
.expect("We should have a GetBlock struct");
|
||||
snapshot_rpc_getblock_verbose(get_block, &settings);
|
||||
|
||||
// `getbestblockhash`
|
||||
let get_best_block_hash = rpc
|
||||
.get_best_block_hash()
|
||||
|
@ -211,6 +218,11 @@ fn snapshot_rpc_getblock(block: GetBlock, block_data: &[u8], settings: &insta::S
|
|||
});
|
||||
}
|
||||
|
||||
/// Check `getblock` response with verbosity=1, using `cargo insta` and JSON serialization.
|
||||
fn snapshot_rpc_getblock_verbose(block: GetBlock, settings: &insta::Settings) {
|
||||
settings.bind(|| insta::assert_json_snapshot!("get_block_verbose", block));
|
||||
}
|
||||
|
||||
/// Snapshot `getbestblockhash` response, using `cargo insta` and JSON serialization.
|
||||
fn snapshot_rpc_getbestblockhash(tip_hash: GetBestBlockHash, settings: &insta::Settings) {
|
||||
settings.bind(|| insta::assert_json_snapshot!("get_best_block_hash", tip_hash));
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
source: zebra-rpc/src/methods/tests/snapshot.rs
|
||||
expression: block
|
||||
---
|
||||
{
|
||||
"tx": [
|
||||
"851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
source: zebra-rpc/src/methods/tests/snapshot.rs
|
||||
expression: block
|
||||
---
|
||||
{
|
||||
"tx": [
|
||||
"f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75"
|
||||
]
|
||||
}
|
|
@ -77,14 +77,33 @@ async fn rpc_getblock() {
|
|||
Mainnet,
|
||||
);
|
||||
|
||||
// Make calls and check response
|
||||
for (i, block) in blocks.into_iter().enumerate() {
|
||||
// Make calls with verbosity=0 and check response
|
||||
for (i, block) in blocks.iter().enumerate() {
|
||||
let get_block = rpc
|
||||
.get_block(i.to_string(), 0u8)
|
||||
.await
|
||||
.expect("We should have a GetBlock struct");
|
||||
|
||||
assert_eq!(get_block.0, block.into());
|
||||
assert_eq!(get_block, GetBlock::Raw(block.clone().into()));
|
||||
}
|
||||
|
||||
// Make calls with verbosity=1 and check response
|
||||
for (i, block) in blocks.iter().enumerate() {
|
||||
let get_block = rpc
|
||||
.get_block(i.to_string(), 1u8)
|
||||
.await
|
||||
.expect("We should have a GetBlock struct");
|
||||
|
||||
assert_eq!(
|
||||
get_block,
|
||||
GetBlock::Object {
|
||||
tx: block
|
||||
.transactions
|
||||
.iter()
|
||||
.map(|tx| tx.hash().encode_hex())
|
||||
.collect()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
mempool.expect_no_requests().await;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::methods::GetRawTransaction;
|
||||
use crate::methods::{GetBlock, GetRawTransaction};
|
||||
|
||||
#[test]
|
||||
pub fn test_transaction_serialization() {
|
||||
|
@ -17,3 +17,20 @@ pub fn test_transaction_serialization() {
|
|||
|
||||
assert_eq!(j, expected_json);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_block_serialization() {
|
||||
let expected_tx = GetBlock::Raw(vec![0x42].into());
|
||||
let expected_json = r#""42""#;
|
||||
let j = serde_json::to_string(&expected_tx).unwrap();
|
||||
|
||||
assert_eq!(j, expected_json);
|
||||
|
||||
let expected_tx = GetBlock::Object {
|
||||
tx: vec!["42".into()],
|
||||
};
|
||||
let expected_json = r#"{"tx":["42"]}"#;
|
||||
let j = serde_json::to_string(&expected_tx).unwrap();
|
||||
|
||||
assert_eq!(j, expected_json);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue