fix(rpc): Fix some RPC response formats to match `zcashd` (#4217)

* Match `zcashd`'s version format in `getinfo`

* Remove an incorrect array wrapper in getaddressbalance

* Use a stable sort order in getrawmempool

Because we can't match zcashd's arbitrary order,
and probably shouldn't try to.

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
teor 2022-04-28 20:19:02 +10:00 committed by GitHub
parent 83d26890f5
commit 7506655774
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 27 additions and 14 deletions

View File

@ -19,7 +19,6 @@ use tower::{buffer::Buffer, Service, ServiceExt};
use tracing::Instrument; use tracing::Instrument;
use zebra_chain::{ use zebra_chain::{
amount::{Amount, NonNegative},
block::{self, Height, SerializedBlock}, block::{self, Height, SerializedBlock},
chain_tip::ChainTip, chain_tip::ChainTip,
parameters::{ConsensusBranchId, Network, NetworkUpgrade}, parameters::{ConsensusBranchId, Network, NetworkUpgrade},
@ -273,8 +272,15 @@ where
{ {
let runner = Queue::start(); let runner = Queue::start();
let mut app_version = app_version.to_string();
// Match zcashd's version format, if the version string has anything in it
if !app_version.is_empty() && !app_version.starts_with('v') {
app_version.insert(0, 'v');
}
let rpc_impl = RpcImpl { let rpc_impl = RpcImpl {
app_version: app_version.to_string(), app_version,
mempool: mempool.clone(), mempool: mempool.clone(),
state: state.clone(), state: state.clone(),
latest_chain_tip: latest_chain_tip.clone(), latest_chain_tip: latest_chain_tip.clone(),
@ -431,9 +437,9 @@ where
})?; })?;
match response { match response {
zebra_state::ReadResponse::AddressBalance(balance) => { zebra_state::ReadResponse::AddressBalance(balance) => Ok(AddressBalance {
Ok(AddressBalance { balance }) balance: u64::from(balance),
} }),
_ => unreachable!("Unexpected response from state service: {response:?}"), _ => unreachable!("Unexpected response from state service: {response:?}"),
} }
} }
@ -556,10 +562,16 @@ where
match response { match response {
mempool::Response::TransactionIds(unmined_transaction_ids) => { mempool::Response::TransactionIds(unmined_transaction_ids) => {
Ok(unmined_transaction_ids let mut tx_ids: Vec<String> = unmined_transaction_ids
.iter() .iter()
.map(|id| id.mined_id().encode_hex()) .map(|id| id.mined_id().encode_hex())
.collect()) .collect();
// Sort returned transaction IDs in numeric/string order.
// (zcashd's sort order appears arbitrary.)
tx_ids.sort();
Ok(tx_ids)
} }
_ => unreachable!("unmatched response to a transactionids request"), _ => unreachable!("unmatched response to a transactionids request"),
} }
@ -730,7 +742,7 @@ where
let height = utxo_data.2.height().0; let height = utxo_data.2.height().0;
let output_index = utxo_data.2.output_index().as_usize(); let output_index = utxo_data.2.output_index().as_usize();
let script = utxo_data.3.lock_script.to_string(); let script = utxo_data.3.lock_script.to_string();
let satoshis = i64::from(utxo_data.3.value); let satoshis = u64::from(utxo_data.3.value);
let entry = GetAddressUtxos { let entry = GetAddressUtxos {
address, address,
@ -809,7 +821,7 @@ impl AddressStrings {
/// The transparent balance of a set of addresses. /// The transparent balance of a set of addresses.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, serde::Serialize)] #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, serde::Serialize)]
pub struct AddressBalance { pub struct AddressBalance {
balance: Amount<NonNegative>, balance: u64,
} }
/// A hex-encoded [`ConsensusBranchId`] string. /// A hex-encoded [`ConsensusBranchId`] string.
@ -899,7 +911,7 @@ pub struct GetAddressUtxos {
#[serde(rename = "outputIndex")] #[serde(rename = "outputIndex")]
output_index: usize, output_index: usize,
script: String, script: String,
satoshis: i64, satoshis: u64,
} }
impl GetRawTransaction { impl GetRawTransaction {

View File

@ -328,10 +328,11 @@ proptest! {
); );
let call_task = tokio::spawn(rpc.get_raw_mempool()); let call_task = tokio::spawn(rpc.get_raw_mempool());
let expected_response: Vec<String> = transaction_ids let mut expected_response: Vec<String> = transaction_ids
.iter() .iter()
.map(|id| id.mined_id().encode_hex()) .map(|id| id.mined_id().encode_hex())
.collect(); .collect();
expected_response.sort();
mempool mempool
.expect_request(mempool::Request::TransactionIds) .expect_request(mempool::Request::TransactionIds)
@ -632,7 +633,7 @@ proptest! {
// Check that response contains the expected balance // Check that response contains the expected balance
let received_balance = response?; let received_balance = response?;
prop_assert_eq!(received_balance, AddressBalance { balance }); prop_assert_eq!(received_balance, AddressBalance { balance: balance.into() });
// Check no further requests were made during this test // Check no further requests were made during this test
mempool.expect_no_requests().await?; mempool.expect_no_requests().await?;

View File

@ -38,8 +38,8 @@ async fn rpc_getinfo() {
let get_info = rpc.get_info().expect("We should have a GetInfo struct"); let get_info = rpc.get_info().expect("We should have a GetInfo struct");
// make sure there is a `build` field in the response, // make sure there is a `build` field in the response,
// and that is equal to the provided string. // and that is equal to the provided string, with an added 'v' version prefix.
assert_eq!(get_info.build, "RPC test"); assert_eq!(get_info.build, "vRPC test");
// make sure there is a `subversion` field, // make sure there is a `subversion` field,
// and that is equal to the Zebra user agent. // and that is equal to the Zebra user agent.