1use 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#[instrument]
21pub async fn migrate(
22 storage: Storage,
23 pd_home: PathBuf,
24 genesis_start: Option<tendermint::time::Time>,
25) -> anyhow::Result<()> {
26 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 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 delta.ready_to_start();
49 delta.put_block_height(0u64);
50
51 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 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}