Merge branch 'z-get-subtree-rpc' into z-get-subtree-rpc-and-data
This commit is contained in:
commit
7ca6974fb4
|
@ -25,13 +25,21 @@ use zebra_chain::{
|
||||||
parameters::{ConsensusBranchId, Network, NetworkUpgrade},
|
parameters::{ConsensusBranchId, Network, NetworkUpgrade},
|
||||||
sapling,
|
sapling,
|
||||||
serialization::{SerializationError, ZcashDeserialize},
|
serialization::{SerializationError, ZcashDeserialize},
|
||||||
|
subtree::NoteCommitmentSubtreeIndex,
|
||||||
transaction::{self, SerializedTransaction, Transaction, UnminedTx},
|
transaction::{self, SerializedTransaction, Transaction, UnminedTx},
|
||||||
transparent::{self, Address},
|
transparent::{self, Address},
|
||||||
};
|
};
|
||||||
use zebra_node_services::mempool;
|
use zebra_node_services::mempool;
|
||||||
use zebra_state::{HashOrHeight, MinedTx, OutputIndex, OutputLocation, TransactionLocation};
|
use zebra_state::{HashOrHeight, MinedTx, OutputIndex, OutputLocation, TransactionLocation};
|
||||||
|
|
||||||
use crate::{constants::MISSING_BLOCK_ERROR_CODE, queue::Queue};
|
use crate::{
|
||||||
|
constants::{INVALID_PARAMETERS_ERROR_CODE, MISSING_BLOCK_ERROR_CODE},
|
||||||
|
methods::trees::{GetSubtrees, SubtreeRpcData},
|
||||||
|
queue::Queue,
|
||||||
|
};
|
||||||
|
|
||||||
|
// We don't use a types/ module here, because it is redundant.
|
||||||
|
pub mod trees;
|
||||||
|
|
||||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||||
pub mod get_block_template_rpcs;
|
pub mod get_block_template_rpcs;
|
||||||
|
@ -172,6 +180,31 @@ pub trait Rpc {
|
||||||
#[rpc(name = "z_gettreestate")]
|
#[rpc(name = "z_gettreestate")]
|
||||||
fn z_get_treestate(&self, hash_or_height: String) -> BoxFuture<Result<GetTreestate>>;
|
fn z_get_treestate(&self, hash_or_height: String) -> BoxFuture<Result<GetTreestate>>;
|
||||||
|
|
||||||
|
/// Returns information about a range of Sapling or Orchard subtrees.
|
||||||
|
///
|
||||||
|
/// zcashd reference: [`z_getsubtreesbyindex`](https://zcash.github.io/rpc/z_getsubtreesbyindex.html)
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// - `pool`: (string, required) The pool from which subtrees should be returned.
|
||||||
|
/// Either "sapling" or "orchard".
|
||||||
|
/// - `start_index`: (numeric, required) The index of the first 2^16-leaf subtree to return.
|
||||||
|
/// - `limit`: (numeric, optional) The maximum number of subtree values to return.
|
||||||
|
///
|
||||||
|
/// # Notes
|
||||||
|
///
|
||||||
|
/// While Zebra is doing its initial subtree index rebuild, subtrees will become available
|
||||||
|
/// starting at the chain tip. This RPC will return an empty list if the `start_index` subtree
|
||||||
|
/// exists, but has not been rebuilt yet. This matches `zcashd`'s behaviour when subtrees aren't
|
||||||
|
/// available yet. (But `zcashd` does its rebuild before syncing any blocks.)
|
||||||
|
#[rpc(name = "z_getsubtreesbyindex")]
|
||||||
|
fn z_get_subtrees_by_index(
|
||||||
|
&self,
|
||||||
|
pool: String,
|
||||||
|
start_index: NoteCommitmentSubtreeIndex,
|
||||||
|
limit: Option<NoteCommitmentSubtreeIndex>,
|
||||||
|
) -> BoxFuture<Result<GetSubtrees>>;
|
||||||
|
|
||||||
/// Returns the raw transaction data, as a [`GetRawTransaction`] JSON string or structure.
|
/// Returns the raw transaction data, as a [`GetRawTransaction`] JSON string or structure.
|
||||||
///
|
///
|
||||||
/// zcashd reference: [`getrawtransaction`](https://zcash.github.io/rpc/getrawtransaction.html)
|
/// zcashd reference: [`getrawtransaction`](https://zcash.github.io/rpc/getrawtransaction.html)
|
||||||
|
@ -1108,6 +1141,88 @@ where
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn z_get_subtrees_by_index(
|
||||||
|
&self,
|
||||||
|
pool: String,
|
||||||
|
start_index: NoteCommitmentSubtreeIndex,
|
||||||
|
limit: Option<NoteCommitmentSubtreeIndex>,
|
||||||
|
) -> BoxFuture<Result<GetSubtrees>> {
|
||||||
|
let mut state = self.state.clone();
|
||||||
|
|
||||||
|
async move {
|
||||||
|
const POOL_LIST: &[&str] = &["sapling", "orchard"];
|
||||||
|
|
||||||
|
if pool == "sapling" {
|
||||||
|
let request = zebra_state::ReadRequest::SaplingSubtrees { start_index, limit };
|
||||||
|
let response = state
|
||||||
|
.ready()
|
||||||
|
.and_then(|service| service.call(request))
|
||||||
|
.await
|
||||||
|
.map_err(|error| Error {
|
||||||
|
code: ErrorCode::ServerError(0),
|
||||||
|
message: error.to_string(),
|
||||||
|
data: None,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let subtrees = match response {
|
||||||
|
zebra_state::ReadResponse::SaplingSubtrees(subtrees) => subtrees,
|
||||||
|
_ => unreachable!("unmatched response to a subtrees request"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let subtrees = subtrees
|
||||||
|
.values()
|
||||||
|
.map(|subtree| SubtreeRpcData {
|
||||||
|
node: subtree.node.encode_hex(),
|
||||||
|
end: subtree.end,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(GetSubtrees {
|
||||||
|
pool,
|
||||||
|
start_index,
|
||||||
|
subtrees,
|
||||||
|
})
|
||||||
|
} else if pool == "orchard" {
|
||||||
|
let request = zebra_state::ReadRequest::OrchardSubtrees { start_index, limit };
|
||||||
|
let response = state
|
||||||
|
.ready()
|
||||||
|
.and_then(|service| service.call(request))
|
||||||
|
.await
|
||||||
|
.map_err(|error| Error {
|
||||||
|
code: ErrorCode::ServerError(0),
|
||||||
|
message: error.to_string(),
|
||||||
|
data: None,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let subtrees = match response {
|
||||||
|
zebra_state::ReadResponse::OrchardSubtrees(subtrees) => subtrees,
|
||||||
|
_ => unreachable!("unmatched response to a subtrees request"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let subtrees = subtrees
|
||||||
|
.values()
|
||||||
|
.map(|subtree| SubtreeRpcData {
|
||||||
|
node: subtree.node.encode_hex(),
|
||||||
|
end: subtree.end,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(GetSubtrees {
|
||||||
|
pool,
|
||||||
|
start_index,
|
||||||
|
subtrees,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(Error {
|
||||||
|
code: INVALID_PARAMETERS_ERROR_CODE,
|
||||||
|
message: format!("invalid pool name, must be one of: {:?}", POOL_LIST),
|
||||||
|
data: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.boxed()
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: use a generic error constructor (#5548)
|
// TODO: use a generic error constructor (#5548)
|
||||||
fn get_address_tx_ids(
|
fn get_address_tx_ids(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
//! Types and functions for note commitment tree RPCs.
|
||||||
|
//
|
||||||
|
// TODO: move the *Tree and *Commitment types into this module.
|
||||||
|
|
||||||
|
use zebra_chain::subtree::{NoteCommitmentSubtreeData, NoteCommitmentSubtreeIndex};
|
||||||
|
|
||||||
|
/// A subtree data type that can hold Sapling or Orchard subtree roots.
|
||||||
|
pub type SubtreeRpcData = NoteCommitmentSubtreeData<String>;
|
||||||
|
|
||||||
|
/// Response to a `z_getsubtreesbyindex` RPC request.
|
||||||
|
///
|
||||||
|
/// Contains the Sapling or Orchard pool label, the index of the first subtree in the list,
|
||||||
|
/// and a list of subtree roots and end heights.
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
|
||||||
|
pub struct GetSubtrees {
|
||||||
|
/// The shielded pool to which the subtrees belong.
|
||||||
|
//
|
||||||
|
// TODO: consider an enum with a string conversion?
|
||||||
|
pub pool: String,
|
||||||
|
|
||||||
|
/// The index of the first subtree.
|
||||||
|
pub start_index: NoteCommitmentSubtreeIndex,
|
||||||
|
|
||||||
|
/// A sequential list of complete subtrees, in `index` order.
|
||||||
|
///
|
||||||
|
/// The generic subtree root type is a hex-encoded Sapling or Orchard subtree root string.
|
||||||
|
//
|
||||||
|
// TODO: is this needed?
|
||||||
|
//#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub subtrees: Vec<SubtreeRpcData>,
|
||||||
|
}
|
Loading…
Reference in New Issue