pd/migrate/
mainnet2.rs

1//! Migration for shipping consensus-breaking IBC changes, fixing
2//! how withdrawals from Penumbra to Noble are handled, and ensures that IBC
3//! error messages from counterparty chains are processed.
4use cnidarium::{StateDelta, Storage};
5use jmt::RootHash;
6use penumbra_sdk_app::app::StateReadExt as _;
7use penumbra_sdk_app::app_version::migrate_app_version;
8use penumbra_sdk_governance::StateWriteExt;
9use penumbra_sdk_sct::component::clock::EpochManager;
10use penumbra_sdk_sct::component::clock::EpochRead;
11use std::path::PathBuf;
12use tracing::instrument;
13
14use crate::network::generate::NetworkConfig;
15
16/// Run the full migration, emitting a new genesis event, representing historical state.
17///
18/// This will have the effect of reinserting packets which had acknowledgements containing
19/// errors, and erroneously removed from state, as if the acknowledgements had contained successes.
20#[instrument]
21pub async fn migrate(
22    storage: Storage,
23    pd_home: PathBuf,
24    genesis_start: Option<tendermint::time::Time>,
25) -> anyhow::Result<()> {
26    // Setup:
27    let initial_state = storage.latest_snapshot();
28    let chain_id = initial_state.get_chain_id().await?;
29    let root_hash = initial_state
30        .root_hash()
31        .await
32        .expect("chain state has a root hash");
33    // We obtain the pre-upgrade hash solely to log it as a result.
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    let mut delta = StateDelta::new(initial_state);
42    let (migration_duration, post_upgrade_root_hash) = {
43        let start_time = std::time::SystemTime::now();
44
45        migrate_app_version(&mut delta, 9).await?;
46
47        // Reset the application height and halt flag.
48        delta.ready_to_start();
49        delta.put_block_height(0u64);
50
51        // Finally, commit the changes to the chain state.
52        let post_upgrade_root_hash = storage.commit_in_place(delta).await?;
53        tracing::info!(?post_upgrade_root_hash, "post-migration root hash");
54
55        (
56            start_time.elapsed().expect("start is set"),
57            post_upgrade_root_hash,
58        )
59    };
60    storage.release().await;
61
62    // The migration is complete, now we need to generate a genesis file. To do this, we need
63    // to lookup a validator view from the chain, and specify the post-upgrade app hash and
64    // initial height.
65    let app_state = penumbra_sdk_app::genesis::Content {
66        chain_id,
67        ..Default::default()
68    };
69    let mut genesis = NetworkConfig::make_genesis(app_state.clone()).expect("can make genesis");
70    genesis.app_hash = post_upgrade_root_hash
71        .0
72        .to_vec()
73        .try_into()
74        .expect("infallible conversion");
75
76    genesis.initial_height = post_upgrade_height as i64;
77    genesis.genesis_time = genesis_start.unwrap_or_else(|| {
78        let now = tendermint::time::Time::now();
79        tracing::info!(%now, "no genesis time provided, detecting a testing setup");
80        now
81    });
82    let checkpoint = post_upgrade_root_hash.0.to_vec();
83    let genesis = NetworkConfig::make_checkpoint(genesis, Some(checkpoint));
84    let genesis_json = serde_json::to_string(&genesis).expect("can serialize genesis");
85    tracing::info!("genesis: {}", genesis_json);
86    let genesis_path = pd_home.join("genesis.json");
87    std::fs::write(genesis_path, genesis_json).expect("can write genesis");
88
89    let validator_state_path = pd_home.join("priv_validator_state.json");
90    let fresh_validator_state = crate::network::generate::NetworkValidator::initial_state();
91    std::fs::write(validator_state_path, fresh_validator_state).expect("can write validator state");
92
93    tracing::info!(
94        pre_upgrade_height,
95        post_upgrade_height,
96        ?pre_upgrade_root_hash,
97        ?post_upgrade_root_hash,
98        duration = migration_duration.as_secs(),
99        "successful migration!"
100    );
101
102    Ok(())
103}