Skip to main content

zebrad/components/sync/
end_of_support.rs

1//! End of support checking task.
2
3use std::time::Duration;
4
5use chrono::{DateTime, Utc};
6use color_eyre::Report;
7
8use zebra_chain::{
9    block::Height,
10    chain_tip::{ChainTip, NetworkChainTipHeightEstimator},
11    parameters::Network,
12};
13
14use crate::application::release_version;
15
16/// The estimated height that this release will be published.
17pub const ESTIMATED_RELEASE_HEIGHT: u32 = 3_444_000;
18
19/// The maximum number of days after `ESTIMATED_RELEASE_HEIGHT` where a Zebra server will run
20/// without halting.
21///
22/// Notes:
23///
24/// - Zebra will exit with a panic if the current tip height is bigger than the
25///   `ESTIMATED_RELEASE_HEIGHT` plus this number of days.
26/// - Currently set to 12 weeks.
27pub const EOS_PANIC_AFTER: u32 = 84;
28
29/// The number of days before the end of support where Zebra will display warnings.
30pub const EOS_WARN_AFTER: u32 = EOS_PANIC_AFTER - 14;
31
32/// A string which is part of the panic that will be displayed if Zebra halts.
33pub const EOS_PANIC_MESSAGE_HEADER: &str = "Zebra refuses to run";
34
35/// A string which is part of the warning that will be displayed if Zebra release is close to halting.
36pub const EOS_WARN_MESSAGE_HEADER: &str = "Your Zebra release is too old and it will stop running";
37
38/// The amount of time between end of support checks.
39const CHECK_INTERVAL: Duration = Duration::from_secs(60 * 60);
40
41/// Wait a few seconds at startup so `best_tip_height` is always `Some`.
42const INITIAL_WAIT: Duration = Duration::from_secs(10);
43
44/// Start the end of support checking task for Mainnet.
45pub async fn start(
46    network: Network,
47    latest_chain_tip: impl ChainTip + std::fmt::Debug,
48) -> Result<(), Report> {
49    info!("Starting end of support task");
50
51    tokio::time::sleep(INITIAL_WAIT).await;
52
53    loop {
54        if network == Network::Mainnet {
55            if let Some(tip_height) = latest_chain_tip.best_tip_height() {
56                check(tip_height, &network);
57            }
58        } else {
59            info!("Release always valid in Testnet");
60        }
61        tokio::time::sleep(CHECK_INTERVAL).await;
62    }
63}
64
65/// Returns the estimated last supported height for this release, or `None` on networks where
66/// end of support is not enforced.
67///
68/// The node runs up to and including this height, and halts with an end of support panic when
69/// the tip goes past it. This matches zcashd, where `end_of_service.block_height` is also the
70/// threshold rather than the first halted block.
71pub fn end_of_support_height(network: &Network) -> Option<Height> {
72    (network == &Network::Mainnet).then(|| estimated_height_after_release(network, EOS_PANIC_AFTER))
73}
74
75/// Returns the estimated height `days` after [`ESTIMATED_RELEASE_HEIGHT`] on `network`,
76/// following the target block spacing in force at each height.
77pub fn estimated_height_after_release(network: &Network, days: u32) -> Height {
78    // Only the elapsed time matters, so any reference time works.
79    let release_time = DateTime::<Utc>::UNIX_EPOCH;
80    NetworkChainTipHeightEstimator::new(release_time, Height(ESTIMATED_RELEASE_HEIGHT), network)
81        .estimate_height_at(release_time + chrono::Duration::days(days.into()))
82}
83
84/// Check if the current release is too old and panic if so.
85pub fn check(tip_height: Height, network: &Network) {
86    info!("Checking if Zebra release is inside support range ...");
87
88    let panic_height = estimated_height_after_release(network, EOS_PANIC_AFTER);
89    let warn_height = estimated_height_after_release(network, EOS_WARN_AFTER);
90
91    if tip_height > panic_height {
92        panic!(
93            "{EOS_PANIC_MESSAGE_HEADER} if the release date is older than {EOS_PANIC_AFTER} days. \
94            \nRelease name: {}, Estimated release height: {ESTIMATED_RELEASE_HEIGHT} \
95            \nHint: Download and install the latest Zebra release from: https://github.com/ZcashFoundation/zebra/releases/latest",
96            release_version()
97        );
98    } else if tip_height > warn_height {
99        warn!(
100            "{EOS_WARN_MESSAGE_HEADER} at block {}. \
101            \nRelease name: {}, Estimated release height: {ESTIMATED_RELEASE_HEIGHT} \
102            \nHint: Download and install the latest Zebra release from: https://github.com/ZcashFoundation/zebra/releases/latest", panic_height.0, release_version()
103        );
104    } else {
105        info!("Zebra release is supported until block {}, please report bugs at https://github.com/ZcashFoundation/zebra/issues", panic_height.0);
106    }
107}