pd/migrate/
testnet77.rs

1//! Contains functions related to the migration script of Testnet77.
2//! The Testnet 77 release included several consensus-breaking changes,
3//! but no state-breaking changes, so the migration is essentially a no-op,
4//! other than resetting the halt bit.
5use anyhow::Context;
6use cnidarium::{StateDelta, Storage};
7use jmt::RootHash;
8use penumbra_sdk_app::app::StateReadExt as _;
9use penumbra_sdk_governance::StateWriteExt;
10use penumbra_sdk_sct::component::clock::EpochManager;
11use penumbra_sdk_sct::component::clock::EpochRead;
12use std::path::PathBuf;
13use tracing::instrument;
14
15use crate::network::generate::NetworkConfig;
16
17/// Run the full migration, given an export path and a start time for genesis.
18///
19/// Menu:
20/// - Reconstruct a correct VCB balance for the auction component.
21#[instrument]
22pub async fn migrate(
23    storage: Storage,
24    pd_home: PathBuf,
25    genesis_start: Option<tendermint::time::Time>,
26) -> anyhow::Result<()> {
27    // Setup:
28    let initial_state = storage.latest_snapshot();
29    let chain_id = initial_state.get_chain_id().await?;
30    let root_hash = initial_state
31        .root_hash()
32        .await
33        .expect("chain state has a root hash");
34    let pre_upgrade_root_hash: RootHash = root_hash.into();
35    let pre_upgrade_height = initial_state
36        .get_block_height()
37        .await
38        .expect("chain state has a block height");
39    let post_upgrade_height = pre_upgrade_height.wrapping_add(1);
40
41    // Set halt bit to 0, so chain can start again.
42    let mut delta = StateDelta::new(initial_state);
43    delta.ready_to_start();
44    delta.put_block_height(0u64);
45    let _ = storage
46        .commit_in_place(delta)
47        .await
48        .context("failed to reset halt bit")?;
49    storage.release().await;
50
51    // The migration is complete, now we need to generate a genesis file. To do this, we need
52    // to lookup a validator view from the chain, and specify the post-upgrade app hash and
53    // initial height.
54    let app_state = penumbra_sdk_app::genesis::Content {
55        chain_id,
56        ..Default::default()
57    };
58    let mut genesis = NetworkConfig::make_genesis(app_state.clone()).expect("can make genesis");
59    genesis.app_hash = pre_upgrade_root_hash
60        .0
61        .to_vec()
62        .try_into()
63        .expect("infallible conversion");
64
65    genesis.initial_height = post_upgrade_height as i64;
66    genesis.genesis_time = genesis_start.unwrap_or_else(|| {
67        let now = tendermint::time::Time::now();
68        tracing::info!(%now, "no genesis time provided, detecting a testing setup");
69        now
70    });
71    let checkpoint = pre_upgrade_root_hash.0.to_vec();
72    let genesis = NetworkConfig::make_checkpoint(genesis, Some(checkpoint));
73    let genesis_json = serde_json::to_string(&genesis).expect("can serialize genesis");
74    tracing::info!("genesis: {}", genesis_json);
75    let genesis_path = pd_home.join("genesis.json");
76    std::fs::write(genesis_path, genesis_json).expect("can write genesis");
77
78    let validator_state_path = pd_home.join("priv_validator_state.json");
79    let fresh_validator_state = crate::network::generate::NetworkValidator::initial_state();
80    std::fs::write(validator_state_path, fresh_validator_state).expect("can write validator state");
81
82    tracing::info!(
83        pre_upgrade_height,
84        ?pre_upgrade_root_hash,
85        "successful migration!"
86    );
87
88    Ok(())
89}