add value pools to getblock rpc method in verbosity = 2 mode
This commit is contained in:
parent
a57557625a
commit
5c265da745
|
@ -10,6 +10,7 @@ use std::{collections::HashSet, fmt::Debug, sync::Arc};
|
||||||
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use futures::{stream::FuturesOrdered, FutureExt, StreamExt, TryFutureExt};
|
use futures::{stream::FuturesOrdered, FutureExt, StreamExt, TryFutureExt};
|
||||||
|
use get_block_template_rpcs::types::zec::Zec;
|
||||||
use hex::{FromHex, ToHex};
|
use hex::{FromHex, ToHex};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use jsonrpc_core::{self, BoxFuture, Error, ErrorCode, Result};
|
use jsonrpc_core::{self, BoxFuture, Error, ErrorCode, Result};
|
||||||
|
@ -20,6 +21,7 @@ use tracing::Instrument;
|
||||||
|
|
||||||
use zcash_primitives::consensus::Parameters;
|
use zcash_primitives::consensus::Parameters;
|
||||||
use zebra_chain::{
|
use zebra_chain::{
|
||||||
|
amount::{Amount, NegativeAllowed},
|
||||||
block::{self, Height, SerializedBlock},
|
block::{self, Height, SerializedBlock},
|
||||||
chain_tip::ChainTip,
|
chain_tip::ChainTip,
|
||||||
parameters::{ConsensusBranchId, Network, NetworkUpgrade},
|
parameters::{ConsensusBranchId, Network, NetworkUpgrade},
|
||||||
|
@ -27,6 +29,7 @@ use zebra_chain::{
|
||||||
subtree::NoteCommitmentSubtreeIndex,
|
subtree::NoteCommitmentSubtreeIndex,
|
||||||
transaction::{self, SerializedTransaction, Transaction, UnminedTx},
|
transaction::{self, SerializedTransaction, Transaction, UnminedTx},
|
||||||
transparent::{self, Address},
|
transparent::{self, Address},
|
||||||
|
value_balance::ValueBalance,
|
||||||
};
|
};
|
||||||
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};
|
||||||
|
@ -724,6 +727,7 @@ where
|
||||||
// later discovered to be on a side chain.
|
// later discovered to be on a side chain.
|
||||||
|
|
||||||
let should_read_block_header = verbosity == 2;
|
let should_read_block_header = verbosity == 2;
|
||||||
|
let should_read_value_pools = verbosity == 2;
|
||||||
|
|
||||||
let hash = match hash_or_height {
|
let hash = match hash_or_height {
|
||||||
HashOrHeight::Hash(hash) => hash,
|
HashOrHeight::Hash(hash) => hash,
|
||||||
|
@ -786,6 +790,11 @@ where
|
||||||
requests.push(zebra_state::ReadRequest::BlockHeader(hash.into()))
|
requests.push(zebra_state::ReadRequest::BlockHeader(hash.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if should_read_value_pools {
|
||||||
|
// Value pools
|
||||||
|
requests.push(zebra_state::ReadRequest::ValuePools(hash.into()))
|
||||||
|
}
|
||||||
|
|
||||||
let mut futs = FuturesOrdered::new();
|
let mut futs = FuturesOrdered::new();
|
||||||
|
|
||||||
for request in requests {
|
for request in requests {
|
||||||
|
@ -847,6 +856,18 @@ where
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let value_pools = if should_read_value_pools {
|
||||||
|
let value_pools_response =
|
||||||
|
futs.next().await.expect("`futs` should not be empty");
|
||||||
|
|
||||||
|
match value_pools_response.map_server_error()? {
|
||||||
|
zebra_state::ReadResponse::ValuePools(pools) => create_value_pools(pools),
|
||||||
|
_ => unreachable!("unmatched response to a ValuePools request"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
let sapling = SaplingTrees {
|
let sapling = SaplingTrees {
|
||||||
size: sapling_note_commitment_tree_count,
|
size: sapling_note_commitment_tree_count,
|
||||||
};
|
};
|
||||||
|
@ -864,6 +885,7 @@ where
|
||||||
time,
|
time,
|
||||||
tx,
|
tx,
|
||||||
trees,
|
trees,
|
||||||
|
value_pools,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(Error {
|
Err(Error {
|
||||||
|
@ -1536,6 +1558,10 @@ pub enum GetBlock {
|
||||||
|
|
||||||
/// Information about the note commitment trees.
|
/// Information about the note commitment trees.
|
||||||
trees: GetBlockTrees,
|
trees: GetBlockTrees,
|
||||||
|
|
||||||
|
/// Information about the value pools of the requested block.
|
||||||
|
#[serde(skip_serializing_if = "Vec::is_empty", rename = "valuePools")]
|
||||||
|
value_pools: Vec<ValuePool>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1548,6 +1574,7 @@ impl Default for GetBlock {
|
||||||
time: None,
|
time: None,
|
||||||
tx: Vec::new(),
|
tx: Vec::new(),
|
||||||
trees: GetBlockTrees::default(),
|
trees: GetBlockTrees::default(),
|
||||||
|
value_pools: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1746,6 +1773,16 @@ impl OrchardTrees {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The value pool section of a block in response to `getblock` RPC.
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||||
|
pub struct ValuePool {
|
||||||
|
id: String,
|
||||||
|
#[serde(rename = "valueDelta")]
|
||||||
|
value_delta: Zec<NegativeAllowed>,
|
||||||
|
#[serde(rename = "valueDeltaZat")]
|
||||||
|
value_delta_zat: Amount<NegativeAllowed>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if provided height range is valid for address indexes.
|
/// Check if provided height range is valid for address indexes.
|
||||||
fn check_height_range(start: Height, end: Height, chain_height: Height) -> Result<()> {
|
fn check_height_range(start: Height, end: Height, chain_height: Height) -> Result<()> {
|
||||||
if start == Height(0) || end == Height(0) {
|
if start == Height(0) || end == Height(0) {
|
||||||
|
@ -1812,3 +1849,34 @@ pub fn height_from_signed_int(index: i32, tip_height: Height) -> Result<Height>
|
||||||
Ok(Height(sanitized_height))
|
Ok(Height(sanitized_height))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a list of `ValuePool` objects from a `ValueBalance`.
|
||||||
|
pub fn create_value_pools(value_balance: ValueBalance<NegativeAllowed>) -> Vec<ValuePool> {
|
||||||
|
vec![
|
||||||
|
ValuePool {
|
||||||
|
id: "lockbox".to_string(),
|
||||||
|
value_delta: Zec::from(value_balance.deferred_amount()),
|
||||||
|
value_delta_zat: value_balance.deferred_amount(),
|
||||||
|
},
|
||||||
|
ValuePool {
|
||||||
|
id: "orchard".to_string(),
|
||||||
|
value_delta: Zec::from(value_balance.orchard_amount()),
|
||||||
|
value_delta_zat: value_balance.orchard_amount(),
|
||||||
|
},
|
||||||
|
ValuePool {
|
||||||
|
id: "sapling".to_string(),
|
||||||
|
value_delta: Zec::from(value_balance.sapling_amount()),
|
||||||
|
value_delta_zat: value_balance.sapling_amount(),
|
||||||
|
},
|
||||||
|
ValuePool {
|
||||||
|
id: "sprout".to_string(),
|
||||||
|
value_delta: Zec::from(value_balance.sprout_amount()),
|
||||||
|
value_delta_zat: value_balance.sprout_amount(),
|
||||||
|
},
|
||||||
|
ValuePool {
|
||||||
|
id: "transparent".to_string(),
|
||||||
|
value_delta: Zec::from(value_balance.transparent_amount()),
|
||||||
|
value_delta_zat: value_balance.transparent_amount(),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
|
@ -9,5 +9,32 @@ expression: block
|
||||||
"tx": [
|
"tx": [
|
||||||
"851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609"
|
"851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609"
|
||||||
],
|
],
|
||||||
"trees": {}
|
"trees": {},
|
||||||
|
"valuePools": [
|
||||||
|
{
|
||||||
|
"id": "lockbox",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "orchard",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "sapling",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "sprout",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "transparent",
|
||||||
|
"valueDelta": 0.000625,
|
||||||
|
"valueDeltaZat": 62500
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,5 +9,32 @@ expression: block
|
||||||
"tx": [
|
"tx": [
|
||||||
"f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75"
|
"f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75"
|
||||||
],
|
],
|
||||||
"trees": {}
|
"trees": {},
|
||||||
|
"valuePools": [
|
||||||
|
{
|
||||||
|
"id": "lockbox",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "orchard",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "sapling",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "sprout",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "transparent",
|
||||||
|
"valueDelta": 0.000625,
|
||||||
|
"valueDeltaZat": 62500
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,5 +10,32 @@ expression: block
|
||||||
"tx": [
|
"tx": [
|
||||||
"851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609"
|
"851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609"
|
||||||
],
|
],
|
||||||
"trees": {}
|
"trees": {},
|
||||||
|
"valuePools": [
|
||||||
|
{
|
||||||
|
"id": "lockbox",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "orchard",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "sapling",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "sprout",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "transparent",
|
||||||
|
"valueDelta": 0.000625,
|
||||||
|
"valueDeltaZat": 62500
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,5 +10,32 @@ expression: block
|
||||||
"tx": [
|
"tx": [
|
||||||
"f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75"
|
"f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75"
|
||||||
],
|
],
|
||||||
"trees": {}
|
"trees": {},
|
||||||
|
"valuePools": [
|
||||||
|
{
|
||||||
|
"id": "lockbox",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "orchard",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "sapling",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "sprout",
|
||||||
|
"valueDelta": 0.0,
|
||||||
|
"valueDeltaZat": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "transparent",
|
||||||
|
"valueDelta": 0.000625,
|
||||||
|
"valueDeltaZat": 62500
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,6 +145,7 @@ async fn rpc_getblock() {
|
||||||
.map(|tx| tx.hash().encode_hex())
|
.map(|tx| tx.hash().encode_hex())
|
||||||
.collect(),
|
.collect(),
|
||||||
trees,
|
trees,
|
||||||
|
value_pools: vec![],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -169,6 +170,7 @@ async fn rpc_getblock() {
|
||||||
.map(|tx| tx.hash().encode_hex())
|
.map(|tx| tx.hash().encode_hex())
|
||||||
.collect(),
|
.collect(),
|
||||||
trees,
|
trees,
|
||||||
|
value_pools: vec![],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -193,6 +195,11 @@ async fn rpc_getblock() {
|
||||||
.map(|tx| tx.hash().encode_hex())
|
.map(|tx| tx.hash().encode_hex())
|
||||||
.collect(),
|
.collect(),
|
||||||
trees,
|
trees,
|
||||||
|
value_pools: create_value_pools(
|
||||||
|
block
|
||||||
|
.chain_value_pool_change(&std::collections::HashMap::new(), None)
|
||||||
|
.unwrap()
|
||||||
|
),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -217,6 +224,11 @@ async fn rpc_getblock() {
|
||||||
.map(|tx| tx.hash().encode_hex())
|
.map(|tx| tx.hash().encode_hex())
|
||||||
.collect(),
|
.collect(),
|
||||||
trees,
|
trees,
|
||||||
|
value_pools: create_value_pools(
|
||||||
|
block
|
||||||
|
.chain_value_pool_change(&std::collections::HashMap::new(), None)
|
||||||
|
.unwrap()
|
||||||
|
),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -241,6 +253,7 @@ async fn rpc_getblock() {
|
||||||
.map(|tx| tx.hash().encode_hex())
|
.map(|tx| tx.hash().encode_hex())
|
||||||
.collect(),
|
.collect(),
|
||||||
trees,
|
trees,
|
||||||
|
value_pools: vec![],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -265,6 +278,7 @@ async fn rpc_getblock() {
|
||||||
.map(|tx| tx.hash().encode_hex())
|
.map(|tx| tx.hash().encode_hex())
|
||||||
.collect(),
|
.collect(),
|
||||||
trees,
|
trees,
|
||||||
|
value_pools: vec![],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1059,6 +1059,9 @@ pub enum ReadRequest {
|
||||||
/// Returns [`ReadResponse::ValidBlockProposal`] when successful, or an error if
|
/// Returns [`ReadResponse::ValidBlockProposal`] when successful, or an error if
|
||||||
/// the block fails contextual validation.
|
/// the block fails contextual validation.
|
||||||
CheckBlockProposalValidity(SemanticallyVerifiedBlock),
|
CheckBlockProposalValidity(SemanticallyVerifiedBlock),
|
||||||
|
|
||||||
|
/// Get the value pools for a given block.
|
||||||
|
ValuePools(HashOrHeight),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReadRequest {
|
impl ReadRequest {
|
||||||
|
@ -1093,6 +1096,7 @@ impl ReadRequest {
|
||||||
ReadRequest::SolutionRate { .. } => "solution_rate",
|
ReadRequest::SolutionRate { .. } => "solution_rate",
|
||||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||||
ReadRequest::CheckBlockProposalValidity(_) => "check_block_proposal_validity",
|
ReadRequest::CheckBlockProposalValidity(_) => "check_block_proposal_validity",
|
||||||
|
ReadRequest::ValuePools(_) => "value_pools",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
use std::{collections::BTreeMap, sync::Arc};
|
use std::{collections::BTreeMap, sync::Arc};
|
||||||
|
|
||||||
use zebra_chain::{
|
use zebra_chain::{
|
||||||
amount::{Amount, NonNegative},
|
amount::{Amount, NegativeAllowed, NonNegative},
|
||||||
block::{self, Block},
|
block::{self, Block},
|
||||||
orchard, sapling,
|
orchard, sapling,
|
||||||
serialization::DateTime32,
|
serialization::DateTime32,
|
||||||
subtree::{NoteCommitmentSubtreeData, NoteCommitmentSubtreeIndex},
|
subtree::{NoteCommitmentSubtreeData, NoteCommitmentSubtreeIndex},
|
||||||
transaction::{self, Transaction},
|
transaction::{self, Transaction},
|
||||||
transparent,
|
transparent,
|
||||||
|
value_balance::ValueBalance,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||||
|
@ -217,6 +218,9 @@ pub enum ReadResponse {
|
||||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||||
/// Response to [`ReadRequest::CheckBlockProposalValidity`]
|
/// Response to [`ReadRequest::CheckBlockProposalValidity`]
|
||||||
ValidBlockProposal,
|
ValidBlockProposal,
|
||||||
|
|
||||||
|
/// Response to [`ReadRequest::ValuePools`]
|
||||||
|
ValuePools(ValueBalance<NegativeAllowed>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A structure with the information needed from the state to build a `getblocktemplate` RPC response.
|
/// A structure with the information needed from the state to build a `getblocktemplate` RPC response.
|
||||||
|
@ -294,7 +298,8 @@ impl TryFrom<ReadResponse> for Response {
|
||||||
| ReadResponse::OrchardSubtrees(_)
|
| ReadResponse::OrchardSubtrees(_)
|
||||||
| ReadResponse::AddressBalance(_)
|
| ReadResponse::AddressBalance(_)
|
||||||
| ReadResponse::AddressesTransactionIds(_)
|
| ReadResponse::AddressesTransactionIds(_)
|
||||||
| ReadResponse::AddressUtxos(_) => {
|
| ReadResponse::AddressUtxos(_)
|
||||||
|
| ReadResponse::ValuePools(_) => {
|
||||||
Err("there is no corresponding Response for this ReadResponse")
|
Err("there is no corresponding Response for this ReadResponse")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ use zebra_chain::{
|
||||||
diagnostic::{task::WaitForPanics, CodeTimer},
|
diagnostic::{task::WaitForPanics, CodeTimer},
|
||||||
parameters::{Network, NetworkUpgrade},
|
parameters::{Network, NetworkUpgrade},
|
||||||
subtree::NoteCommitmentSubtreeIndex,
|
subtree::NoteCommitmentSubtreeIndex,
|
||||||
|
value_balance::ValueBalance,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -1873,6 +1874,33 @@ impl Service<ReadRequest> for ReadStateService {
|
||||||
})
|
})
|
||||||
.wait_for_panics()
|
.wait_for_panics()
|
||||||
}
|
}
|
||||||
|
ReadRequest::ValuePools(hash_or_height) => {
|
||||||
|
let state = self.clone();
|
||||||
|
|
||||||
|
tokio::task::spawn_blocking(move || {
|
||||||
|
span.in_scope(move || {
|
||||||
|
let block = state.non_finalized_state_receiver.with_watch_data(
|
||||||
|
|non_finalized_state| {
|
||||||
|
read::block(
|
||||||
|
non_finalized_state.best_chain(),
|
||||||
|
&state.db,
|
||||||
|
hash_or_height,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let value_pool_change = block
|
||||||
|
.map(|b| b.chain_value_pool_change(&HashMap::new(), None))
|
||||||
|
.unwrap_or(Ok(ValueBalance::zero()));
|
||||||
|
|
||||||
|
// The work is done in the future.
|
||||||
|
timer.finish(module_path!(), line!(), "ReadRequest::ValuePools");
|
||||||
|
|
||||||
|
Ok(ReadResponse::ValuePools(value_pool_change?))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.wait_for_panics()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue