zebra/zebra-chain/src/chain_tip.rs

193 lines
6.3 KiB
Rust
Raw Normal View History

//! Zebra interfaces for access to chain tip information.
use std::{future, sync::Arc};
Estimate network chain tip height based on local node time and current best tip (#3492) * Remove redundant documentation The documentation was exactly the same as the documentation from the trait. * Calculate a mock time block delta for tests Simulate a block being added to the chain with a random block time based on the previous block time and the target spacing time. * Add a `time` field to `ChainTipBlock` Store the block time so that it's ready for a future chain that allows obtaining the chain tip's block time. * Add `ChainTip::best_tip_block_time` method Allow obtaining the bes chain tip's block time. * Add method to obtain both height and block time Prevent any data races by returning both values so that they refer to the same chain tip. * Add `NetworkUpgrade::all_target_spacings` method Returns all the target spacings defined for a network. * Create a `NetworkChainTipEstimator` helper type Isolate the code to calculate the height estimation in a new type, so that it's easier to understand and doesn't decrease the readability of the `chain_tip.rs` file. * Add `ChainTip::estimate_network_chain_tip_height` This is more of an extension method than a trait method. It uses the `NetworkChainTipHeightEstimator` to actually perform the estimation, but obtains the initial information from the current best chain tip. * Fix typo in documentation There was an extra closing bracket in the summary line. * Refactor `MockChainTipSender` into a separate type Prepare to allow mocking the block time of the best tip as well as the block height. * Allow sending mock best tip block times Add a separate `watch` channel to send the best tip block times from a `MockChainTipSender` to a `MockChainTip`. The `best_tip_height_and_block_time` implementation will only return a value if there's a height and a block time value for the best tip. * Fix off-by-one height estimation error Use Euclidean division to force the division result to round down instead of rounding towards zero. This fixes an off-by-one error when estimating a height that is lower than the current height, because the fractionary result was being discarded, and it should have forced the height to go one block back. * Fix panics on local times very far in the past Detect situations that might cause the block height estimate to underflow, and return the genesis height instead. * Fix another off-by-one height estimation error The implementation of `chrono::Duration::num_seconds` adds one to the number of seconds if it's negative. This breaks the division calculation, so it has to be compensated for. * Test network chain tip height estimation Generate pairs of block heights and check that it's possible to estimate the larger height from the smaller height and a displaced time difference.
2022-02-10 17:27:02 -08:00
use chrono::{DateTime, Utc};
use futures::{future::BoxFuture, Future, FutureExt};
Estimate network chain tip height based on local node time and current best tip (#3492) * Remove redundant documentation The documentation was exactly the same as the documentation from the trait. * Calculate a mock time block delta for tests Simulate a block being added to the chain with a random block time based on the previous block time and the target spacing time. * Add a `time` field to `ChainTipBlock` Store the block time so that it's ready for a future chain that allows obtaining the chain tip's block time. * Add `ChainTip::best_tip_block_time` method Allow obtaining the bes chain tip's block time. * Add method to obtain both height and block time Prevent any data races by returning both values so that they refer to the same chain tip. * Add `NetworkUpgrade::all_target_spacings` method Returns all the target spacings defined for a network. * Create a `NetworkChainTipEstimator` helper type Isolate the code to calculate the height estimation in a new type, so that it's easier to understand and doesn't decrease the readability of the `chain_tip.rs` file. * Add `ChainTip::estimate_network_chain_tip_height` This is more of an extension method than a trait method. It uses the `NetworkChainTipHeightEstimator` to actually perform the estimation, but obtains the initial information from the current best chain tip. * Fix typo in documentation There was an extra closing bracket in the summary line. * Refactor `MockChainTipSender` into a separate type Prepare to allow mocking the block time of the best tip as well as the block height. * Allow sending mock best tip block times Add a separate `watch` channel to send the best tip block times from a `MockChainTipSender` to a `MockChainTip`. The `best_tip_height_and_block_time` implementation will only return a value if there's a height and a block time value for the best tip. * Fix off-by-one height estimation error Use Euclidean division to force the division result to round down instead of rounding towards zero. This fixes an off-by-one error when estimating a height that is lower than the current height, because the fractionary result was being discarded, and it should have forced the height to go one block back. * Fix panics on local times very far in the past Detect situations that might cause the block height estimate to underflow, and return the genesis height instead. * Fix another off-by-one height estimation error The implementation of `chrono::Duration::num_seconds` adds one to the number of seconds if it's negative. This breaks the division calculation, so it has to be compensated for. * Test network chain tip height estimation Generate pairs of block heights and check that it's possible to estimate the larger height from the smaller height and a displaced time difference.
2022-02-10 17:27:02 -08:00
use crate::{block, parameters::Network, transaction, BoxError};
mod network_chain_tip_height_estimator;
#[cfg(any(test, feature = "proptest-impl"))]
pub mod mock;
Estimate network chain tip height based on local node time and current best tip (#3492) * Remove redundant documentation The documentation was exactly the same as the documentation from the trait. * Calculate a mock time block delta for tests Simulate a block being added to the chain with a random block time based on the previous block time and the target spacing time. * Add a `time` field to `ChainTipBlock` Store the block time so that it's ready for a future chain that allows obtaining the chain tip's block time. * Add `ChainTip::best_tip_block_time` method Allow obtaining the bes chain tip's block time. * Add method to obtain both height and block time Prevent any data races by returning both values so that they refer to the same chain tip. * Add `NetworkUpgrade::all_target_spacings` method Returns all the target spacings defined for a network. * Create a `NetworkChainTipEstimator` helper type Isolate the code to calculate the height estimation in a new type, so that it's easier to understand and doesn't decrease the readability of the `chain_tip.rs` file. * Add `ChainTip::estimate_network_chain_tip_height` This is more of an extension method than a trait method. It uses the `NetworkChainTipHeightEstimator` to actually perform the estimation, but obtains the initial information from the current best chain tip. * Fix typo in documentation There was an extra closing bracket in the summary line. * Refactor `MockChainTipSender` into a separate type Prepare to allow mocking the block time of the best tip as well as the block height. * Allow sending mock best tip block times Add a separate `watch` channel to send the best tip block times from a `MockChainTipSender` to a `MockChainTip`. The `best_tip_height_and_block_time` implementation will only return a value if there's a height and a block time value for the best tip. * Fix off-by-one height estimation error Use Euclidean division to force the division result to round down instead of rounding towards zero. This fixes an off-by-one error when estimating a height that is lower than the current height, because the fractionary result was being discarded, and it should have forced the height to go one block back. * Fix panics on local times very far in the past Detect situations that might cause the block height estimate to underflow, and return the genesis height instead. * Fix another off-by-one height estimation error The implementation of `chrono::Duration::num_seconds` adds one to the number of seconds if it's negative. This breaks the division calculation, so it has to be compensated for. * Test network chain tip height estimation Generate pairs of block heights and check that it's possible to estimate the larger height from the smaller height and a displaced time difference.
2022-02-10 17:27:02 -08:00
#[cfg(test)]
mod tests;
use network_chain_tip_height_estimator::NetworkChainTipHeightEstimator;
/// An interface for querying the chain tip.
///
/// This trait helps avoid dependencies between:
/// * `zebra-chain` and `tokio`
/// * `zebra-network` and `zebra-state`
pub trait ChainTip {
/// Returns the height of the best chain tip.
///
/// Does not mark the best tip as seen.
fn best_tip_height(&self) -> Option<block::Height>;
/// Returns the block hash of the best chain tip.
///
/// Does not mark the best tip as seen.
fn best_tip_hash(&self) -> Option<block::Hash>;
/// Returns the height and the hash of the best chain tip.
///
/// Does not mark the best tip as seen.
feat(rpc): Implement `getblockchaininfo` RPC method (#3891) * Implement `getblockchaininfo` RPC method * add a test for `get_blockchain_info` * fix tohex/fromhex * move comment * Update lightwalletd acceptance test for getblockchaininfo RPC (#3914) * change(rpc): Return getblockchaininfo network upgrades in height order (#3915) * Update lightwalletd acceptance test for getblockchaininfo RPC * Update some doc comments for network upgrades * List network upgrades in order in the getblockchaininfo RPC Also: - Use a constant for the "missing consensus branch ID" RPC value - Simplify fetching consensus branch IDs - Make RPC type derives consistent - Update RPC type documentation * Make RPC type derives consistent * Fix a confusing test comment * get hashand height at the same time * fix estimated_height * fix lint * add extra check Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com> * fix typo Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com> * split test Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com> * fix(rpc): ignore an expected error in the RPC acceptance tests (#3961) * Add ignored regexes to test command failure regex methods * Ignore empty chain error in getblockchaininfo We expect this error when zebrad starts up with an empty state. Co-authored-by: teor <teor@riseup.net> Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2022-03-25 05:25:31 -07:00
fn best_tip_height_and_hash(&self) -> Option<(block::Height, block::Hash)>;
/// Returns the block time of the best chain tip.
///
/// Does not mark the best tip as seen.
Estimate network chain tip height based on local node time and current best tip (#3492) * Remove redundant documentation The documentation was exactly the same as the documentation from the trait. * Calculate a mock time block delta for tests Simulate a block being added to the chain with a random block time based on the previous block time and the target spacing time. * Add a `time` field to `ChainTipBlock` Store the block time so that it's ready for a future chain that allows obtaining the chain tip's block time. * Add `ChainTip::best_tip_block_time` method Allow obtaining the bes chain tip's block time. * Add method to obtain both height and block time Prevent any data races by returning both values so that they refer to the same chain tip. * Add `NetworkUpgrade::all_target_spacings` method Returns all the target spacings defined for a network. * Create a `NetworkChainTipEstimator` helper type Isolate the code to calculate the height estimation in a new type, so that it's easier to understand and doesn't decrease the readability of the `chain_tip.rs` file. * Add `ChainTip::estimate_network_chain_tip_height` This is more of an extension method than a trait method. It uses the `NetworkChainTipHeightEstimator` to actually perform the estimation, but obtains the initial information from the current best chain tip. * Fix typo in documentation There was an extra closing bracket in the summary line. * Refactor `MockChainTipSender` into a separate type Prepare to allow mocking the block time of the best tip as well as the block height. * Allow sending mock best tip block times Add a separate `watch` channel to send the best tip block times from a `MockChainTipSender` to a `MockChainTip`. The `best_tip_height_and_block_time` implementation will only return a value if there's a height and a block time value for the best tip. * Fix off-by-one height estimation error Use Euclidean division to force the division result to round down instead of rounding towards zero. This fixes an off-by-one error when estimating a height that is lower than the current height, because the fractionary result was being discarded, and it should have forced the height to go one block back. * Fix panics on local times very far in the past Detect situations that might cause the block height estimate to underflow, and return the genesis height instead. * Fix another off-by-one height estimation error The implementation of `chrono::Duration::num_seconds` adds one to the number of seconds if it's negative. This breaks the division calculation, so it has to be compensated for. * Test network chain tip height estimation Generate pairs of block heights and check that it's possible to estimate the larger height from the smaller height and a displaced time difference.
2022-02-10 17:27:02 -08:00
fn best_tip_block_time(&self) -> Option<DateTime<Utc>>;
/// Returns the height and the block time of the best chain tip.
Estimate network chain tip height based on local node time and current best tip (#3492) * Remove redundant documentation The documentation was exactly the same as the documentation from the trait. * Calculate a mock time block delta for tests Simulate a block being added to the chain with a random block time based on the previous block time and the target spacing time. * Add a `time` field to `ChainTipBlock` Store the block time so that it's ready for a future chain that allows obtaining the chain tip's block time. * Add `ChainTip::best_tip_block_time` method Allow obtaining the bes chain tip's block time. * Add method to obtain both height and block time Prevent any data races by returning both values so that they refer to the same chain tip. * Add `NetworkUpgrade::all_target_spacings` method Returns all the target spacings defined for a network. * Create a `NetworkChainTipEstimator` helper type Isolate the code to calculate the height estimation in a new type, so that it's easier to understand and doesn't decrease the readability of the `chain_tip.rs` file. * Add `ChainTip::estimate_network_chain_tip_height` This is more of an extension method than a trait method. It uses the `NetworkChainTipHeightEstimator` to actually perform the estimation, but obtains the initial information from the current best chain tip. * Fix typo in documentation There was an extra closing bracket in the summary line. * Refactor `MockChainTipSender` into a separate type Prepare to allow mocking the block time of the best tip as well as the block height. * Allow sending mock best tip block times Add a separate `watch` channel to send the best tip block times from a `MockChainTipSender` to a `MockChainTip`. The `best_tip_height_and_block_time` implementation will only return a value if there's a height and a block time value for the best tip. * Fix off-by-one height estimation error Use Euclidean division to force the division result to round down instead of rounding towards zero. This fixes an off-by-one error when estimating a height that is lower than the current height, because the fractionary result was being discarded, and it should have forced the height to go one block back. * Fix panics on local times very far in the past Detect situations that might cause the block height estimate to underflow, and return the genesis height instead. * Fix another off-by-one height estimation error The implementation of `chrono::Duration::num_seconds` adds one to the number of seconds if it's negative. This breaks the division calculation, so it has to be compensated for. * Test network chain tip height estimation Generate pairs of block heights and check that it's possible to estimate the larger height from the smaller height and a displaced time difference.
2022-02-10 17:27:02 -08:00
/// Returning both values at the same time guarantees that they refer to the same chain tip.
///
/// Does not mark the best tip as seen.
Estimate network chain tip height based on local node time and current best tip (#3492) * Remove redundant documentation The documentation was exactly the same as the documentation from the trait. * Calculate a mock time block delta for tests Simulate a block being added to the chain with a random block time based on the previous block time and the target spacing time. * Add a `time` field to `ChainTipBlock` Store the block time so that it's ready for a future chain that allows obtaining the chain tip's block time. * Add `ChainTip::best_tip_block_time` method Allow obtaining the bes chain tip's block time. * Add method to obtain both height and block time Prevent any data races by returning both values so that they refer to the same chain tip. * Add `NetworkUpgrade::all_target_spacings` method Returns all the target spacings defined for a network. * Create a `NetworkChainTipEstimator` helper type Isolate the code to calculate the height estimation in a new type, so that it's easier to understand and doesn't decrease the readability of the `chain_tip.rs` file. * Add `ChainTip::estimate_network_chain_tip_height` This is more of an extension method than a trait method. It uses the `NetworkChainTipHeightEstimator` to actually perform the estimation, but obtains the initial information from the current best chain tip. * Fix typo in documentation There was an extra closing bracket in the summary line. * Refactor `MockChainTipSender` into a separate type Prepare to allow mocking the block time of the best tip as well as the block height. * Allow sending mock best tip block times Add a separate `watch` channel to send the best tip block times from a `MockChainTipSender` to a `MockChainTip`. The `best_tip_height_and_block_time` implementation will only return a value if there's a height and a block time value for the best tip. * Fix off-by-one height estimation error Use Euclidean division to force the division result to round down instead of rounding towards zero. This fixes an off-by-one error when estimating a height that is lower than the current height, because the fractionary result was being discarded, and it should have forced the height to go one block back. * Fix panics on local times very far in the past Detect situations that might cause the block height estimate to underflow, and return the genesis height instead. * Fix another off-by-one height estimation error The implementation of `chrono::Duration::num_seconds` adds one to the number of seconds if it's negative. This breaks the division calculation, so it has to be compensated for. * Test network chain tip height estimation Generate pairs of block heights and check that it's possible to estimate the larger height from the smaller height and a displaced time difference.
2022-02-10 17:27:02 -08:00
fn best_tip_height_and_block_time(&self) -> Option<(block::Height, DateTime<Utc>)>;
/// Returns the mined transaction IDs of the transactions in the best chain tip block.
///
/// All transactions with these mined IDs should be rejected from the mempool,
/// even if their authorizing data is different.
///
/// Does not mark the best tip as seen.
fn best_tip_mined_transaction_ids(&self) -> Arc<[transaction::Hash]>;
Estimate network chain tip height based on local node time and current best tip (#3492) * Remove redundant documentation The documentation was exactly the same as the documentation from the trait. * Calculate a mock time block delta for tests Simulate a block being added to the chain with a random block time based on the previous block time and the target spacing time. * Add a `time` field to `ChainTipBlock` Store the block time so that it's ready for a future chain that allows obtaining the chain tip's block time. * Add `ChainTip::best_tip_block_time` method Allow obtaining the bes chain tip's block time. * Add method to obtain both height and block time Prevent any data races by returning both values so that they refer to the same chain tip. * Add `NetworkUpgrade::all_target_spacings` method Returns all the target spacings defined for a network. * Create a `NetworkChainTipEstimator` helper type Isolate the code to calculate the height estimation in a new type, so that it's easier to understand and doesn't decrease the readability of the `chain_tip.rs` file. * Add `ChainTip::estimate_network_chain_tip_height` This is more of an extension method than a trait method. It uses the `NetworkChainTipHeightEstimator` to actually perform the estimation, but obtains the initial information from the current best chain tip. * Fix typo in documentation There was an extra closing bracket in the summary line. * Refactor `MockChainTipSender` into a separate type Prepare to allow mocking the block time of the best tip as well as the block height. * Allow sending mock best tip block times Add a separate `watch` channel to send the best tip block times from a `MockChainTipSender` to a `MockChainTip`. The `best_tip_height_and_block_time` implementation will only return a value if there's a height and a block time value for the best tip. * Fix off-by-one height estimation error Use Euclidean division to force the division result to round down instead of rounding towards zero. This fixes an off-by-one error when estimating a height that is lower than the current height, because the fractionary result was being discarded, and it should have forced the height to go one block back. * Fix panics on local times very far in the past Detect situations that might cause the block height estimate to underflow, and return the genesis height instead. * Fix another off-by-one height estimation error The implementation of `chrono::Duration::num_seconds` adds one to the number of seconds if it's negative. This breaks the division calculation, so it has to be compensated for. * Test network chain tip height estimation Generate pairs of block heights and check that it's possible to estimate the larger height from the smaller height and a displaced time difference.
2022-02-10 17:27:02 -08:00
/// A future that returns when the best chain tip changes.
/// Can return immediately if the latest value in this [`ChainTip`] has not been seen yet.
///
/// Marks the best tip as seen.
///
/// Returns an error if Zebra is shutting down, or the state has permanently failed.
///
/// See [`tokio::watch::Receiver::changed()`](https://docs.rs/tokio/latest/tokio/sync/watch/struct.Receiver.html#method.changed) for details.
//
// TODO:
// Use async_fn_in_trait or return_position_impl_trait_in_trait when one of them stabilises:
// https://github.com/rust-lang/rust/issues/91611
fn best_tip_changed(&mut self) -> BestTipChanged;
/// Mark the current best tip as seen.
///
/// Later calls to [`ChainTip::best_tip_changed()`] will wait for the next change
/// before returning.
fn mark_best_tip_seen(&mut self);
// Provided methods
//
Estimate network chain tip height based on local node time and current best tip (#3492) * Remove redundant documentation The documentation was exactly the same as the documentation from the trait. * Calculate a mock time block delta for tests Simulate a block being added to the chain with a random block time based on the previous block time and the target spacing time. * Add a `time` field to `ChainTipBlock` Store the block time so that it's ready for a future chain that allows obtaining the chain tip's block time. * Add `ChainTip::best_tip_block_time` method Allow obtaining the bes chain tip's block time. * Add method to obtain both height and block time Prevent any data races by returning both values so that they refer to the same chain tip. * Add `NetworkUpgrade::all_target_spacings` method Returns all the target spacings defined for a network. * Create a `NetworkChainTipEstimator` helper type Isolate the code to calculate the height estimation in a new type, so that it's easier to understand and doesn't decrease the readability of the `chain_tip.rs` file. * Add `ChainTip::estimate_network_chain_tip_height` This is more of an extension method than a trait method. It uses the `NetworkChainTipHeightEstimator` to actually perform the estimation, but obtains the initial information from the current best chain tip. * Fix typo in documentation There was an extra closing bracket in the summary line. * Refactor `MockChainTipSender` into a separate type Prepare to allow mocking the block time of the best tip as well as the block height. * Allow sending mock best tip block times Add a separate `watch` channel to send the best tip block times from a `MockChainTipSender` to a `MockChainTip`. The `best_tip_height_and_block_time` implementation will only return a value if there's a height and a block time value for the best tip. * Fix off-by-one height estimation error Use Euclidean division to force the division result to round down instead of rounding towards zero. This fixes an off-by-one error when estimating a height that is lower than the current height, because the fractionary result was being discarded, and it should have forced the height to go one block back. * Fix panics on local times very far in the past Detect situations that might cause the block height estimate to underflow, and return the genesis height instead. * Fix another off-by-one height estimation error The implementation of `chrono::Duration::num_seconds` adds one to the number of seconds if it's negative. This breaks the division calculation, so it has to be compensated for. * Test network chain tip height estimation Generate pairs of block heights and check that it's possible to estimate the larger height from the smaller height and a displaced time difference.
2022-02-10 17:27:02 -08:00
/// Return an estimate of the network chain tip's height.
///
/// The estimate is calculated based on the current local time, the block time of the best tip
/// and the height of the best tip.
fn estimate_network_chain_tip_height(
&self,
change(chain): Remove `Copy` trait impl from `Network` (#8354) * removed derive copy from network, address and ledgerstate * changed is_max_block_time_enforced to accept ref * changed NetworkUpgrade::Current to accept ref * changed NetworkUpgrade::Next to accept ref * changed NetworkUpgrade::IsActivationHeight to accept ref * changed NetworkUpgrade::TargetSpacingForHeight to accept ref * changed NetworkUpgrade::TargetSpacings to accept ref * changed NetworkUpgrade::MinimumDifficultySpacing_forHeight to accept ref * changed NetworkUpgrade::IsTestnetMinDifficultyBlock to accept ref * changed NetworkUpgrade::AveragingWindowTimespanForHeight to accept ref * changed NetworkUpgrade::ActivationHeight to accept ref * changed sapling_activation_height to accept ref * fixed lifetime for target_spacings * fixed sapling_activation_height * changed transaction_to_fake_v5 and fake_v5_transactions_for_network to accept ref to network * changed Input::vec_strategy to accept ref to network * changed functions in zebra-chain/src/primitives/zcash_history.rs to accept ref to network * changed functions in zebra-chain/src/history_tree.rs to accept ref to network * changed functions in zebra-chain/src/history_tree.rs to accept ref to network * changed functions in zebra-chain/src/primitives/address.rs to accept ref to network * changed functions in zebra-chain/src/primitives/viewing_key* to accept ref to network * changed functions in zebra-chain/src/transparent/address.rs to accept ref to network * changed functions in zebra-chain/src/primitives/zcash_primitives.rs to accept ref to network * changed functions in zebra-chain/src/primitives/zcash_note_encryption.rs to accept ref to network * changed functions in zebra-chain/src/primitives/history_tree* to accept ref to network * changed functions in zebra-chain/src/block* to accept ref to network * fixed errors in zebra-chain::parameters::network * fixed errors in zebra-chain::parameters::network * fixed errors in zebra-chain * changed NonEmptyHistoryTree and InnerHistoryTree to hold value instead of ref * changed NonEmptyHistoryTree and InnerHistoryTree to hold value instead of ref * fixed errors in zebra-chain/src/block/arbitrary.rs * finished fixing errors in zebra-chain - all crate tests pass * changed functions in zebra-state::service::finalized_state to accept &Network * changed functions in zebra-state::service::non_finalized_state to accept &Network * zebra-state tests run but fail with overflow error * zebra-state tests all pass * converted zebra-network -- all crate tests pass * applied all requested changes from review * converted zebra-consensus -- all crate tests pass * converted zebra-scan -- all crate tests pass * converted zebra-rpc -- all crate tests pass * converted zebra-grpc -- all crate tests pass * converted zebrad -- all crate tests pass * applied all requested changes from review * fixed all clippy errors * fixed build error in zebrad/src/components/mempool/crawler.rs
2024-03-19 13:45:27 -07:00
network: &Network,
Estimate network chain tip height based on local node time and current best tip (#3492) * Remove redundant documentation The documentation was exactly the same as the documentation from the trait. * Calculate a mock time block delta for tests Simulate a block being added to the chain with a random block time based on the previous block time and the target spacing time. * Add a `time` field to `ChainTipBlock` Store the block time so that it's ready for a future chain that allows obtaining the chain tip's block time. * Add `ChainTip::best_tip_block_time` method Allow obtaining the bes chain tip's block time. * Add method to obtain both height and block time Prevent any data races by returning both values so that they refer to the same chain tip. * Add `NetworkUpgrade::all_target_spacings` method Returns all the target spacings defined for a network. * Create a `NetworkChainTipEstimator` helper type Isolate the code to calculate the height estimation in a new type, so that it's easier to understand and doesn't decrease the readability of the `chain_tip.rs` file. * Add `ChainTip::estimate_network_chain_tip_height` This is more of an extension method than a trait method. It uses the `NetworkChainTipHeightEstimator` to actually perform the estimation, but obtains the initial information from the current best chain tip. * Fix typo in documentation There was an extra closing bracket in the summary line. * Refactor `MockChainTipSender` into a separate type Prepare to allow mocking the block time of the best tip as well as the block height. * Allow sending mock best tip block times Add a separate `watch` channel to send the best tip block times from a `MockChainTipSender` to a `MockChainTip`. The `best_tip_height_and_block_time` implementation will only return a value if there's a height and a block time value for the best tip. * Fix off-by-one height estimation error Use Euclidean division to force the division result to round down instead of rounding towards zero. This fixes an off-by-one error when estimating a height that is lower than the current height, because the fractionary result was being discarded, and it should have forced the height to go one block back. * Fix panics on local times very far in the past Detect situations that might cause the block height estimate to underflow, and return the genesis height instead. * Fix another off-by-one height estimation error The implementation of `chrono::Duration::num_seconds` adds one to the number of seconds if it's negative. This breaks the division calculation, so it has to be compensated for. * Test network chain tip height estimation Generate pairs of block heights and check that it's possible to estimate the larger height from the smaller height and a displaced time difference.
2022-02-10 17:27:02 -08:00
now: DateTime<Utc>,
) -> Option<block::Height> {
let (current_height, current_block_time) = self.best_tip_height_and_block_time()?;
let estimator =
NetworkChainTipHeightEstimator::new(current_block_time, current_height, network);
Some(estimator.estimate_height_at(now))
}
/// Return an estimate of how many blocks there are ahead of Zebra's best chain tip until the
/// network chain tip, and Zebra's best chain tip height.
///
/// The first element in the returned tuple is the estimate.
/// The second element in the returned tuple is the current best chain tip.
///
/// The estimate is calculated based on the current local time, the block time of the best tip
/// and the height of the best tip.
///
/// This estimate may be negative if the current local time is behind the chain tip block's
/// timestamp.
///
/// Returns `None` if the state is empty.
fn estimate_distance_to_network_chain_tip(
&self,
change(chain): Remove `Copy` trait impl from `Network` (#8354) * removed derive copy from network, address and ledgerstate * changed is_max_block_time_enforced to accept ref * changed NetworkUpgrade::Current to accept ref * changed NetworkUpgrade::Next to accept ref * changed NetworkUpgrade::IsActivationHeight to accept ref * changed NetworkUpgrade::TargetSpacingForHeight to accept ref * changed NetworkUpgrade::TargetSpacings to accept ref * changed NetworkUpgrade::MinimumDifficultySpacing_forHeight to accept ref * changed NetworkUpgrade::IsTestnetMinDifficultyBlock to accept ref * changed NetworkUpgrade::AveragingWindowTimespanForHeight to accept ref * changed NetworkUpgrade::ActivationHeight to accept ref * changed sapling_activation_height to accept ref * fixed lifetime for target_spacings * fixed sapling_activation_height * changed transaction_to_fake_v5 and fake_v5_transactions_for_network to accept ref to network * changed Input::vec_strategy to accept ref to network * changed functions in zebra-chain/src/primitives/zcash_history.rs to accept ref to network * changed functions in zebra-chain/src/history_tree.rs to accept ref to network * changed functions in zebra-chain/src/history_tree.rs to accept ref to network * changed functions in zebra-chain/src/primitives/address.rs to accept ref to network * changed functions in zebra-chain/src/primitives/viewing_key* to accept ref to network * changed functions in zebra-chain/src/transparent/address.rs to accept ref to network * changed functions in zebra-chain/src/primitives/zcash_primitives.rs to accept ref to network * changed functions in zebra-chain/src/primitives/zcash_note_encryption.rs to accept ref to network * changed functions in zebra-chain/src/primitives/history_tree* to accept ref to network * changed functions in zebra-chain/src/block* to accept ref to network * fixed errors in zebra-chain::parameters::network * fixed errors in zebra-chain::parameters::network * fixed errors in zebra-chain * changed NonEmptyHistoryTree and InnerHistoryTree to hold value instead of ref * changed NonEmptyHistoryTree and InnerHistoryTree to hold value instead of ref * fixed errors in zebra-chain/src/block/arbitrary.rs * finished fixing errors in zebra-chain - all crate tests pass * changed functions in zebra-state::service::finalized_state to accept &Network * changed functions in zebra-state::service::non_finalized_state to accept &Network * zebra-state tests run but fail with overflow error * zebra-state tests all pass * converted zebra-network -- all crate tests pass * applied all requested changes from review * converted zebra-consensus -- all crate tests pass * converted zebra-scan -- all crate tests pass * converted zebra-rpc -- all crate tests pass * converted zebra-grpc -- all crate tests pass * converted zebrad -- all crate tests pass * applied all requested changes from review * fixed all clippy errors * fixed build error in zebrad/src/components/mempool/crawler.rs
2024-03-19 13:45:27 -07:00
network: &Network,
) -> Option<(block::HeightDiff, block::Height)> {
let (current_height, current_block_time) = self.best_tip_height_and_block_time()?;
let estimator =
NetworkChainTipHeightEstimator::new(current_block_time, current_height, network);
let distance_to_tip = estimator.estimate_height_at(Utc::now()) - current_height;
Some((distance_to_tip, current_height))
}
}
/// A future for the [`ChainTip::best_tip_changed()`] method.
/// See that method for details.
pub struct BestTipChanged<'f> {
fut: BoxFuture<'f, Result<(), BoxError>>,
}
impl<'f> BestTipChanged<'f> {
/// Returns a new [`BestTipChanged`] containing `fut`.
pub fn new<Fut>(fut: Fut) -> Self
where
Fut: Future<Output = Result<(), BoxError>> + Send + 'f,
{
Self { fut: Box::pin(fut) }
}
}
impl<'f> Future for BestTipChanged<'f> {
type Output = Result<(), BoxError>;
fn poll(
mut self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
self.fut.poll_unpin(cx)
}
}
/// A chain tip that is always empty and never changes.
///
/// Used in production for isolated network connections,
/// and as a mock chain tip in tests.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct NoChainTip;
impl ChainTip for NoChainTip {
fn best_tip_height(&self) -> Option<block::Height> {
None
}
fn best_tip_hash(&self) -> Option<block::Hash> {
None
}
feat(rpc): Implement `getblockchaininfo` RPC method (#3891) * Implement `getblockchaininfo` RPC method * add a test for `get_blockchain_info` * fix tohex/fromhex * move comment * Update lightwalletd acceptance test for getblockchaininfo RPC (#3914) * change(rpc): Return getblockchaininfo network upgrades in height order (#3915) * Update lightwalletd acceptance test for getblockchaininfo RPC * Update some doc comments for network upgrades * List network upgrades in order in the getblockchaininfo RPC Also: - Use a constant for the "missing consensus branch ID" RPC value - Simplify fetching consensus branch IDs - Make RPC type derives consistent - Update RPC type documentation * Make RPC type derives consistent * Fix a confusing test comment * get hashand height at the same time * fix estimated_height * fix lint * add extra check Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com> * fix typo Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com> * split test Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com> * fix(rpc): ignore an expected error in the RPC acceptance tests (#3961) * Add ignored regexes to test command failure regex methods * Ignore empty chain error in getblockchaininfo We expect this error when zebrad starts up with an empty state. Co-authored-by: teor <teor@riseup.net> Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2022-03-25 05:25:31 -07:00
fn best_tip_height_and_hash(&self) -> Option<(block::Height, block::Hash)> {
None
}
Estimate network chain tip height based on local node time and current best tip (#3492) * Remove redundant documentation The documentation was exactly the same as the documentation from the trait. * Calculate a mock time block delta for tests Simulate a block being added to the chain with a random block time based on the previous block time and the target spacing time. * Add a `time` field to `ChainTipBlock` Store the block time so that it's ready for a future chain that allows obtaining the chain tip's block time. * Add `ChainTip::best_tip_block_time` method Allow obtaining the bes chain tip's block time. * Add method to obtain both height and block time Prevent any data races by returning both values so that they refer to the same chain tip. * Add `NetworkUpgrade::all_target_spacings` method Returns all the target spacings defined for a network. * Create a `NetworkChainTipEstimator` helper type Isolate the code to calculate the height estimation in a new type, so that it's easier to understand and doesn't decrease the readability of the `chain_tip.rs` file. * Add `ChainTip::estimate_network_chain_tip_height` This is more of an extension method than a trait method. It uses the `NetworkChainTipHeightEstimator` to actually perform the estimation, but obtains the initial information from the current best chain tip. * Fix typo in documentation There was an extra closing bracket in the summary line. * Refactor `MockChainTipSender` into a separate type Prepare to allow mocking the block time of the best tip as well as the block height. * Allow sending mock best tip block times Add a separate `watch` channel to send the best tip block times from a `MockChainTipSender` to a `MockChainTip`. The `best_tip_height_and_block_time` implementation will only return a value if there's a height and a block time value for the best tip. * Fix off-by-one height estimation error Use Euclidean division to force the division result to round down instead of rounding towards zero. This fixes an off-by-one error when estimating a height that is lower than the current height, because the fractionary result was being discarded, and it should have forced the height to go one block back. * Fix panics on local times very far in the past Detect situations that might cause the block height estimate to underflow, and return the genesis height instead. * Fix another off-by-one height estimation error The implementation of `chrono::Duration::num_seconds` adds one to the number of seconds if it's negative. This breaks the division calculation, so it has to be compensated for. * Test network chain tip height estimation Generate pairs of block heights and check that it's possible to estimate the larger height from the smaller height and a displaced time difference.
2022-02-10 17:27:02 -08:00
fn best_tip_block_time(&self) -> Option<DateTime<Utc>> {
None
}
fn best_tip_height_and_block_time(&self) -> Option<(block::Height, DateTime<Utc>)> {
None
}
fn best_tip_mined_transaction_ids(&self) -> Arc<[transaction::Hash]> {
Arc::new([])
}
/// The [`NoChainTip`] best tip never changes, so this never returns.
fn best_tip_changed(&mut self) -> BestTipChanged {
BestTipChanged::new(future::pending())
}
/// The [`NoChainTip`] best tip never changes, so this does nothing.
fn mark_best_tip_seen(&mut self) {}
}