add value pools to getblock rpc method in verbosity = 2 mode

This commit is contained in:
Alfredo Garcia 2024-08-14 19:40:36 -03:00
parent a57557625a
commit 5c265da745
9 changed files with 233 additions and 6 deletions

View File

@ -10,6 +10,7 @@ use std::{collections::HashSet, fmt::Debug, sync::Arc};
use chrono::Utc;
use futures::{stream::FuturesOrdered, FutureExt, StreamExt, TryFutureExt};
use get_block_template_rpcs::types::zec::Zec;
use hex::{FromHex, ToHex};
use indexmap::IndexMap;
use jsonrpc_core::{self, BoxFuture, Error, ErrorCode, Result};
@ -20,6 +21,7 @@ use tracing::Instrument;
use zcash_primitives::consensus::Parameters;
use zebra_chain::{
amount::{Amount, NegativeAllowed},
block::{self, Height, SerializedBlock},
chain_tip::ChainTip,
parameters::{ConsensusBranchId, Network, NetworkUpgrade},
@ -27,6 +29,7 @@ use zebra_chain::{
subtree::NoteCommitmentSubtreeIndex,
transaction::{self, SerializedTransaction, Transaction, UnminedTx},
transparent::{self, Address},
value_balance::ValueBalance,
};
use zebra_node_services::mempool;
use zebra_state::{HashOrHeight, MinedTx, OutputIndex, OutputLocation, TransactionLocation};
@ -724,6 +727,7 @@ where
// later discovered to be on a side chain.
let should_read_block_header = verbosity == 2;
let should_read_value_pools = verbosity == 2;
let hash = match hash_or_height {
HashOrHeight::Hash(hash) => hash,
@ -786,6 +790,11 @@ where
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();
for request in requests {
@ -847,6 +856,18 @@ where
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 {
size: sapling_note_commitment_tree_count,
};
@ -864,6 +885,7 @@ where
time,
tx,
trees,
value_pools,
})
} else {
Err(Error {
@ -1536,6 +1558,10 @@ pub enum GetBlock {
/// Information about the note commitment trees.
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,
tx: Vec::new(),
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.
fn check_height_range(start: Height, end: Height, chain_height: Height) -> Result<()> {
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))
}
}
/// 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(),
},
]
}

View File

@ -9,5 +9,32 @@ expression: block
"tx": [
"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
}
]
}

View File

@ -9,5 +9,32 @@ expression: block
"tx": [
"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
}
]
}

View File

@ -10,5 +10,32 @@ expression: block
"tx": [
"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
}
]
}

View File

@ -10,5 +10,32 @@ expression: block
"tx": [
"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
}
]
}

View File

@ -145,6 +145,7 @@ async fn rpc_getblock() {
.map(|tx| tx.hash().encode_hex())
.collect(),
trees,
value_pools: vec![],
}
);
}
@ -169,6 +170,7 @@ async fn rpc_getblock() {
.map(|tx| tx.hash().encode_hex())
.collect(),
trees,
value_pools: vec![],
}
);
}
@ -193,6 +195,11 @@ async fn rpc_getblock() {
.map(|tx| tx.hash().encode_hex())
.collect(),
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())
.collect(),
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())
.collect(),
trees,
value_pools: vec![],
}
);
}
@ -265,6 +278,7 @@ async fn rpc_getblock() {
.map(|tx| tx.hash().encode_hex())
.collect(),
trees,
value_pools: vec![],
}
);
}

View File

@ -1059,6 +1059,9 @@ pub enum ReadRequest {
/// Returns [`ReadResponse::ValidBlockProposal`] when successful, or an error if
/// the block fails contextual validation.
CheckBlockProposalValidity(SemanticallyVerifiedBlock),
/// Get the value pools for a given block.
ValuePools(HashOrHeight),
}
impl ReadRequest {
@ -1093,6 +1096,7 @@ impl ReadRequest {
ReadRequest::SolutionRate { .. } => "solution_rate",
#[cfg(feature = "getblocktemplate-rpcs")]
ReadRequest::CheckBlockProposalValidity(_) => "check_block_proposal_validity",
ReadRequest::ValuePools(_) => "value_pools",
}
}

View File

@ -3,13 +3,14 @@
use std::{collections::BTreeMap, sync::Arc};
use zebra_chain::{
amount::{Amount, NonNegative},
amount::{Amount, NegativeAllowed, NonNegative},
block::{self, Block},
orchard, sapling,
serialization::DateTime32,
subtree::{NoteCommitmentSubtreeData, NoteCommitmentSubtreeIndex},
transaction::{self, Transaction},
transparent,
value_balance::ValueBalance,
};
#[cfg(feature = "getblocktemplate-rpcs")]
@ -217,6 +218,9 @@ pub enum ReadResponse {
#[cfg(feature = "getblocktemplate-rpcs")]
/// Response to [`ReadRequest::CheckBlockProposalValidity`]
ValidBlockProposal,
/// Response to [`ReadRequest::ValuePools`]
ValuePools(ValueBalance<NegativeAllowed>),
}
/// 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::AddressBalance(_)
| ReadResponse::AddressesTransactionIds(_)
| ReadResponse::AddressUtxos(_) => {
| ReadResponse::AddressUtxos(_)
| ReadResponse::ValuePools(_) => {
Err("there is no corresponding Response for this ReadResponse")
}

View File

@ -37,6 +37,7 @@ use zebra_chain::{
diagnostic::{task::WaitForPanics, CodeTimer},
parameters::{Network, NetworkUpgrade},
subtree::NoteCommitmentSubtreeIndex,
value_balance::ValueBalance,
};
use crate::{
@ -1873,6 +1874,33 @@ impl Service<ReadRequest> for ReadStateService {
})
.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()
}
}
}
}