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

change(rpc): Add value pool balances to getblockchaininfo RPC method response #8769

Merged
merged 9 commits into from
Aug 16, 2024
2 changes: 1 addition & 1 deletion zebra-chain/src/chain_tip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub mod mock;
#[cfg(test)]
mod tests;

use network_chain_tip_height_estimator::NetworkChainTipHeightEstimator;
pub use network_chain_tip_height_estimator::NetworkChainTipHeightEstimator;

/// An interface for querying the chain tip.
///
Expand Down
185 changes: 105 additions & 80 deletions zebra-rpc/src/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use tracing::Instrument;
use zcash_primitives::consensus::Parameters;
use zebra_chain::{
block::{self, Height, SerializedBlock},
chain_tip::ChainTip,
chain_tip::{ChainTip, NetworkChainTipHeightEstimator},
parameters::{ConsensusBranchId, Network, NetworkUpgrade},
serialization::ZcashDeserialize,
subtree::NoteCommitmentSubtreeIndex,
Expand All @@ -45,6 +45,8 @@ use errors::{MapServerError, OkOrServerError};
// We don't use a types/ module here, because it is redundant.
pub mod trees;

pub mod types;

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

Expand Down Expand Up @@ -85,7 +87,7 @@ pub trait Rpc {
/// Some fields from the zcashd reference are missing from Zebra's [`GetBlockChainInfo`]. It only contains the fields
/// [required for lightwalletd support.](https://github.com/zcash/lightwalletd/blob/v0.4.9/common/common.go#L72-L89)
#[rpc(name = "getblockchaininfo")]
fn get_blockchain_info(&self) -> Result<GetBlockChainInfo>;
fn get_blockchain_info(&self) -> BoxFuture<Result<GetBlockChainInfo>>;

/// Returns the total balance of a provided `addresses` in an [`AddressBalance`] instance.
///
Expand Down Expand Up @@ -500,98 +502,120 @@ where
Ok(response)
}

// TODO: use a generic error constructor (#5548)
#[allow(clippy::unwrap_in_result)]
fn get_blockchain_info(&self) -> Result<GetBlockChainInfo> {
let network = &self.network;
fn get_blockchain_info(&self) -> BoxFuture<Result<GetBlockChainInfo>> {
let network = self.network.clone();
let debug_force_finished_sync = self.debug_force_finished_sync;
let mut state = self.state.clone();

// `chain` field
let chain = self.network.bip70_network_name();
async move {
// `chain` field
let chain = network.bip70_network_name();

// `blocks` and `best_block_hash` fields
let (tip_height, tip_hash) = self
.latest_chain_tip
.best_tip_height_and_hash()
.ok_or_server_error("No Chain tip available yet")?;
let request = zebra_state::ReadRequest::TipPoolValues;
let response: zebra_state::ReadResponse = state
.ready()
.and_then(|service| service.call(request))
.await
.map_server_error()?;

let zebra_state::ReadResponse::TipPoolValues {
tip_height,
tip_hash,
value_balance,
} = response
else {
unreachable!("unmatched response to a TipPoolValues request")
};

// `estimated_height` field
let current_block_time = self
.latest_chain_tip
.best_tip_block_time()
.ok_or_server_error("No Chain tip available yet")?;
let request = zebra_state::ReadRequest::BlockHeader(tip_hash.into());
let response: zebra_state::ReadResponse = state
.ready()
.and_then(|service| service.call(request))
.await
.map_server_error()?;

let zebra_estimated_height = self
.latest_chain_tip
.estimate_network_chain_tip_height(network, Utc::now())
.ok_or_server_error("No Chain tip available yet")?;
let zebra_state::ReadResponse::BlockHeader(block_header) = response else {
unreachable!("unmatched response to a BlockHeader request")
};

let mut estimated_height =
if current_block_time > Utc::now() || zebra_estimated_height < tip_height {
let tip_block_time = block_header
.ok_or_server_error("unexpectedly could not read best chain tip block header")?
.time;

let now = Utc::now();
let zebra_estimated_height =
NetworkChainTipHeightEstimator::new(tip_block_time, tip_height, &network)
.estimate_height_at(now);

// If we're testing the mempool, force the estimated height to be the actual tip height, otherwise,
// check if the estimated height is below Zebra's latest tip height, or if the latest tip's block time is
// later than the current time on the local clock.
let estimated_height = if tip_block_time > now
|| zebra_estimated_height < tip_height
|| debug_force_finished_sync
{
tip_height
} else {
zebra_estimated_height
};

// If we're testing the mempool, force the estimated height to be the actual tip height.
if self.debug_force_finished_sync {
estimated_height = tip_height;
}

// `upgrades` object
//
// Get the network upgrades in height order, like `zcashd`.
let mut upgrades = IndexMap::new();
for (activation_height, network_upgrade) in network.full_activation_list() {
// Zebra defines network upgrades based on incompatible consensus rule changes,
// but zcashd defines them based on ZIPs.
// `upgrades` object
//
// All the network upgrades with a consensus branch ID are the same in Zebra and zcashd.
if let Some(branch_id) = network_upgrade.branch_id() {
// zcashd's RPC seems to ignore Disabled network upgrades, so Zebra does too.
let status = if tip_height >= activation_height {
NetworkUpgradeStatus::Active
} else {
NetworkUpgradeStatus::Pending
};
// Get the network upgrades in height order, like `zcashd`.
let mut upgrades = IndexMap::new();
for (activation_height, network_upgrade) in network.full_activation_list() {
// Zebra defines network upgrades based on incompatible consensus rule changes,
// but zcashd defines them based on ZIPs.
//
// All the network upgrades with a consensus branch ID are the same in Zebra and zcashd.
if let Some(branch_id) = network_upgrade.branch_id() {
// zcashd's RPC seems to ignore Disabled network upgrades, so Zebra does too.
let status = if tip_height >= activation_height {
NetworkUpgradeStatus::Active
} else {
NetworkUpgradeStatus::Pending
};

let upgrade = NetworkUpgradeInfo {
name: network_upgrade,
activation_height,
status,
};
upgrades.insert(ConsensusBranchIdHex(branch_id), upgrade);
let upgrade = NetworkUpgradeInfo {
name: network_upgrade,
activation_height,
status,
};
upgrades.insert(ConsensusBranchIdHex(branch_id), upgrade);
}
}
}

// `consensus` object
let next_block_height =
(tip_height + 1).expect("valid chain tips are a lot less than Height::MAX");
let consensus = TipConsensusBranch {
chain_tip: ConsensusBranchIdHex(
NetworkUpgrade::current(network, tip_height)
.branch_id()
.unwrap_or(ConsensusBranchId::RPC_MISSING_ID),
),
next_block: ConsensusBranchIdHex(
NetworkUpgrade::current(network, next_block_height)
.branch_id()
.unwrap_or(ConsensusBranchId::RPC_MISSING_ID),
),
};
// `consensus` object
let next_block_height =
(tip_height + 1).expect("valid chain tips are a lot less than Height::MAX");
let consensus = TipConsensusBranch {
chain_tip: ConsensusBranchIdHex(
NetworkUpgrade::current(&network, tip_height)
.branch_id()
.unwrap_or(ConsensusBranchId::RPC_MISSING_ID),
),
next_block: ConsensusBranchIdHex(
NetworkUpgrade::current(&network, next_block_height)
.branch_id()
.unwrap_or(ConsensusBranchId::RPC_MISSING_ID),
),
};

let response = GetBlockChainInfo {
chain,
blocks: tip_height,
best_block_hash: tip_hash,
estimated_height,
upgrades,
consensus,
};
let response = GetBlockChainInfo {
chain,
blocks: tip_height,
best_block_hash: tip_hash,
estimated_height,
value_pools: types::ValuePoolBalance::from_value_balance(value_balance),
upgrades,
consensus,
};

Ok(response)
Ok(response)
}
.boxed()
}

// TODO: use a generic error constructor (#5548)
fn get_address_balance(
&self,
address_strings: AddressStrings,
Expand All @@ -615,7 +639,6 @@ where
}

// TODO: use HexData or GetRawTransaction::Bytes to handle the transaction data argument
// use a generic error constructor (#5548)
fn send_raw_transaction(
&self,
raw_transaction_hex: String,
Expand Down Expand Up @@ -963,7 +986,6 @@ where
}

// TODO: use HexData or SentTransactionHash to handle the transaction ID
// use a generic error constructor (#5548)
fn get_raw_transaction(
&self,
txid_hex: String,
Expand Down Expand Up @@ -1197,7 +1219,6 @@ where
.boxed()
}

// TODO: use a generic error constructor (#5548)
fn get_address_tx_ids(
&self,
request: GetAddressTxIdsRequest,
Expand Down Expand Up @@ -1258,7 +1279,6 @@ where
.boxed()
}

// TODO: use a generic error constructor (#5548)
fn get_address_utxos(
&self,
address_strings: AddressStrings,
Expand Down Expand Up @@ -1372,6 +1392,10 @@ pub struct GetBlockChainInfo {
#[serde(rename = "estimatedheight")]
estimated_height: Height,

/// Value pool balances
#[serde(rename = "valuePools")]
value_pools: [types::ValuePoolBalance; 5],

/// Status of network upgrades
upgrades: IndexMap<ConsensusBranchIdHex, NetworkUpgradeInfo>,

Expand All @@ -1386,6 +1410,7 @@ impl Default for GetBlockChainInfo {
blocks: Height(1),
best_block_hash: block::Hash([0; 32]),
estimated_height: Height(1),
value_pools: types::ValuePoolBalance::zero_pools(),
upgrades: IndexMap::new(),
consensus: TipConsensusBranch {
chain_tip: ConsensusBranchIdHex(ConsensusBranchId::default()),
Expand Down
14 changes: 2 additions & 12 deletions zebra-rpc/src/methods/get_block_template_rpcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,6 @@ where
best_chain_tip_height(&self.latest_chain_tip).map(|height| height.0)
}

// TODO: use a generic error constructor (#5548)
fn get_block_hash(&self, index: i32) -> BoxFuture<Result<GetBlockHash>> {
let mut state = self.state.clone();
let latest_chain_tip = self.latest_chain_tip.clone();
Expand All @@ -567,11 +566,7 @@ where
.ready()
.and_then(|service| service.call(request))
.await
.map_err(|error| Error {
code: ErrorCode::ServerError(0),
message: error.to_string(),
data: None,
})?;
.map_server_error()?;

match response {
zebra_state::ReadResponse::BlockHash(Some(hash)) => Ok(GetBlockHash(hash)),
Expand All @@ -586,7 +581,6 @@ where
.boxed()
}

// TODO: use a generic error constructor (#5548)
fn get_block_template(
&self,
parameters: Option<get_block_template::JsonParameters>,
Expand Down Expand Up @@ -830,11 +824,7 @@ where
Is Zebra shutting down?"
);

return Err(Error {
code: ErrorCode::ServerError(0),
message: recv_error.to_string(),
data: None,
});
return Err(recv_error).map_server_error();
}
}
}
Expand Down
1 change: 0 additions & 1 deletion zebra-rpc/src/methods/get_block_template_rpcs/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@ pub mod transaction;
pub mod unified_address;
pub mod validate_address;
pub mod z_validate_address;
pub mod zec;
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use zebra_chain::{
transparent,
};

use crate::methods::get_block_template_rpcs::types::zec::Zec;
use crate::methods::types::Zec;

/// A response to a `getblocksubsidy` RPC request
#[derive(Clone, Debug, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
Expand Down
Loading
Loading