Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(rpc): Use populated state in more RPC snapshot tests #6700

Merged
merged 10 commits into from
May 17, 2023
2 changes: 1 addition & 1 deletion zebra-rpc/src/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -977,7 +977,7 @@ where
zebra_state::ReadResponse::Block(Some(block)) => block,
zebra_state::ReadResponse::Block(None) => {
return Err(Error {
code: ErrorCode::ServerError(0),
code: MISSING_BLOCK_ERROR_CODE,
message: "the requested block was not found".to_string(),
data: None,
})
Expand Down
123 changes: 110 additions & 13 deletions zebra-rpc/src/methods/tests/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@ use zebra_chain::{
parameters::Network::{Mainnet, Testnet},
serialization::ZcashDeserializeInto,
};
use zebra_state::MAX_ON_DISK_HEIGHT;
use zebra_test::mock_service::MockService;

use super::super::*;

#[cfg(feature = "getblocktemplate-rpcs")]
mod get_block_template_rpcs;

/// The first block height in the state that can never be stored in the database,
/// due to optimisations in the disk format.
pub const EXCESSIVE_BLOCK_HEIGHT: u32 = MAX_ON_DISK_HEIGHT.0 + 1;

/// Snapshot test for RPC methods responses.
#[tokio::test(flavor = "multi_thread")]
async fn test_rpc_response_data() {
Expand Down Expand Up @@ -104,7 +109,9 @@ async fn test_rpc_response_data_for_network(network: Network) {
snapshot_rpc_getaddressbalance(get_address_balance, &settings);

// `getblock` variants
// A valid block height in the populated state
const BLOCK_HEIGHT: u32 = 1;

let block_hash = blocks[BLOCK_HEIGHT as usize].hash();

// `getblock`, verbosity=0, height
Expand All @@ -119,6 +126,11 @@ async fn test_rpc_response_data_for_network(network: Network) {
&settings,
);

let get_block = rpc
.get_block(EXCESSIVE_BLOCK_HEIGHT.to_string(), Some(0u8))
.await;
snapshot_rpc_getblock_invalid("excessive_height_verbosity_0", get_block, &settings);

// `getblock`, verbosity=0, hash
let get_block = rpc
.get_block(block_hash.to_string(), Some(0u8))
Expand All @@ -138,6 +150,11 @@ async fn test_rpc_response_data_for_network(network: Network) {
.expect("We should have a GetBlock struct");
snapshot_rpc_getblock_verbose("height_verbosity_1", get_block, &settings);

let get_block = rpc
.get_block(EXCESSIVE_BLOCK_HEIGHT.to_string(), Some(1u8))
.await;
snapshot_rpc_getblock_invalid("excessive_height_verbosity_1", get_block, &settings);

// `getblock`, verbosity=1, hash
let get_block = rpc
.get_block(block_hash.to_string(), Some(1u8))
Expand All @@ -152,6 +169,11 @@ async fn test_rpc_response_data_for_network(network: Network) {
.expect("We should have a GetBlock struct");
snapshot_rpc_getblock_verbose("height_verbosity_default", get_block, &settings);

let get_block = rpc
.get_block(EXCESSIVE_BLOCK_HEIGHT.to_string(), None)
.await;
snapshot_rpc_getblock_invalid("excessive_height_verbosity_default", get_block, &settings);

// `getblock`, no verbosity - defaults to 1, hash
let get_block = rpc
.get_block(block_hash.to_string(), None)
Expand Down Expand Up @@ -202,7 +224,12 @@ async fn test_rpc_response_data_for_network(network: Network) {
.z_get_treestate(BLOCK_HEIGHT.to_string())
.await
.expect("We should have a GetTreestate struct");
snapshot_rpc_z_gettreestate(tree_state, &settings);
snapshot_rpc_z_gettreestate_valid(tree_state, &settings);

let tree_state = rpc
.z_get_treestate(EXCESSIVE_BLOCK_HEIGHT.to_string())
.await;
snapshot_rpc_z_gettreestate_invalid("excessive_height", tree_state, &settings);

// `getrawtransaction` verbosity=0
//
Expand Down Expand Up @@ -250,7 +277,35 @@ async fn test_rpc_response_data_for_network(network: Network) {
})
.await
.expect("We should have a vector of strings");
snapshot_rpc_getaddresstxids(get_address_tx_ids, &settings);
snapshot_rpc_getaddresstxids_valid("multi_block", get_address_tx_ids, &settings);

let get_address_tx_ids = rpc
.get_address_tx_ids(GetAddressTxIdsRequest {
addresses: addresses.clone(),
start: 2,
end: 2,
})
.await
.expect("We should have a vector of strings");
snapshot_rpc_getaddresstxids_valid("single_block", get_address_tx_ids, &settings);

let get_address_tx_ids = rpc
.get_address_tx_ids(GetAddressTxIdsRequest {
addresses: addresses.clone(),
start: 3,
end: EXCESSIVE_BLOCK_HEIGHT,
})
.await;
snapshot_rpc_getaddresstxids_invalid("excessive_end", get_address_tx_ids, &settings);

let get_address_tx_ids = rpc
.get_address_tx_ids(GetAddressTxIdsRequest {
addresses: addresses.clone(),
start: EXCESSIVE_BLOCK_HEIGHT,
end: EXCESSIVE_BLOCK_HEIGHT + 1,
})
.await;
snapshot_rpc_getaddresstxids_invalid("excessive_start", get_address_tx_ids, &settings);

// `getaddressutxos`
let get_address_utxos = rpc
Expand Down Expand Up @@ -293,30 +348,31 @@ fn snapshot_rpc_getaddressbalance(address_balance: AddressBalance, settings: &in
settings.bind(|| insta::assert_json_snapshot!("get_address_balance", address_balance));
}

/// Check `getblock` response, using `cargo insta`, JSON serialization, and block test vectors.
/// Check valid `getblock` data response with verbosity=0, using `cargo insta`, JSON serialization,
/// and block test vectors.
///
/// The snapshot file does not contain any data, but it does enforce the response format.
fn snapshot_rpc_getblock_data(
variant: &'static str,
block: GetBlock,
block_data: &[u8],
expected_block_data: &[u8],
settings: &insta::Settings,
) {
let block_data = hex::encode(block_data);
let expected_block_data = hex::encode(expected_block_data);

settings.bind(|| {
insta::assert_json_snapshot!(format!("get_block_data_{variant}"), block, {
"." => dynamic_redaction(move |value, _path| {
// assert that the block data matches, without creating a 1.5 kB snapshot file
assert_eq!(value.as_str().unwrap(), block_data);
assert_eq!(value.as_str().unwrap(), expected_block_data);
// replace with:
"[BlockData]"
}),
})
});
}

/// Check `getblock` response with verbosity=1, using `cargo insta` and JSON serialization.
/// Check valid `getblock` response with verbosity=1, using `cargo insta` and JSON serialization.
fn snapshot_rpc_getblock_verbose(
variant: &'static str,
block: GetBlock,
Expand All @@ -325,6 +381,16 @@ fn snapshot_rpc_getblock_verbose(
settings.bind(|| insta::assert_json_snapshot!(format!("get_block_verbose_{variant}"), block));
}

/// Check invalid height `getblock` response using `cargo insta`.
fn snapshot_rpc_getblock_invalid(
variant: &'static str,
response: Result<GetBlock>,
settings: &insta::Settings,
) {
settings
.bind(|| insta::assert_json_snapshot!(format!("get_block_invalid_{variant}"), response));
}

/// Snapshot `getbestblockhash` response, using `cargo insta` and JSON serialization.
fn snapshot_rpc_getbestblockhash(tip_hash: GetBlockHash, settings: &insta::Settings) {
settings.bind(|| insta::assert_json_snapshot!("get_best_block_hash", tip_hash));
Expand All @@ -335,9 +401,20 @@ fn snapshot_rpc_getrawmempool(raw_mempool: Vec<String>, settings: &insta::Settin
settings.bind(|| insta::assert_json_snapshot!("get_raw_mempool", raw_mempool));
}

/// Snapshot `z_gettreestate` response, using `cargo insta` and JSON serialization.
fn snapshot_rpc_z_gettreestate(tree_state: GetTreestate, settings: &insta::Settings) {
settings.bind(|| insta::assert_json_snapshot!("z_get_treestate", tree_state));
/// Snapshot a valid `z_gettreestate` response, using `cargo insta` and JSON serialization.
fn snapshot_rpc_z_gettreestate_valid(tree_state: GetTreestate, settings: &insta::Settings) {
settings.bind(|| insta::assert_json_snapshot!(format!("z_get_treestate_valid"), tree_state));
}

/// Snapshot an invalid `z_gettreestate` response, using `cargo insta` and JSON serialization.
fn snapshot_rpc_z_gettreestate_invalid(
variant: &'static str,
tree_state: Result<GetTreestate>,
settings: &insta::Settings,
) {
settings.bind(|| {
insta::assert_json_snapshot!(format!("z_get_treestate_invalid_{variant}"), tree_state)
});
}

/// Snapshot `getrawtransaction` response, using `cargo insta` and JSON serialization.
Expand All @@ -351,9 +428,29 @@ fn snapshot_rpc_getrawtransaction(
});
}

/// Snapshot `getaddressbalance` response, using `cargo insta` and JSON serialization.
fn snapshot_rpc_getaddresstxids(transactions: Vec<String>, settings: &insta::Settings) {
settings.bind(|| insta::assert_json_snapshot!("get_address_tx_ids", transactions));
/// Snapshot valid `getaddressbalance` response, using `cargo insta` and JSON serialization.
fn snapshot_rpc_getaddresstxids_valid(
variant: &'static str,
transactions: Vec<String>,
settings: &insta::Settings,
) {
settings.bind(|| {
insta::assert_json_snapshot!(format!("get_address_tx_ids_valid_{variant}"), transactions)
});
}

/// Snapshot invalid `getaddressbalance` response, using `cargo insta` and JSON serialization.
fn snapshot_rpc_getaddresstxids_invalid(
variant: &'static str,
transactions: Result<Vec<String>>,
settings: &insta::Settings,
) {
settings.bind(|| {
insta::assert_json_snapshot!(
format!("get_address_tx_ids_invalid_{variant}"),
transactions
)
});
}

/// Snapshot `getaddressutxos` response, using `cargo insta` and JSON serialization.
Expand Down
Loading