Skip to content

Commit

Permalink
pd: implement no op migration to v0.81.0 (#4942)
Browse files Browse the repository at this point in the history
This implements a migration to version 0.81.0, which doesn't require any
logic.

This will break PD, but targets the new release branch. The APP_VERSION has been incremented to 9, in order to satisfy the safeguard version checks from UIP-6.

---------

Co-authored-by: Conor Schaefer <[email protected]>
  • Loading branch information
cronokirby and conorsch authored Nov 22, 2024
1 parent d87e9a1 commit 2b6503c
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 3 deletions.
1 change: 1 addition & 0 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
| 7 (Testnet 78) | v0.78.x | v0.37.5 | v1 |
| 7 (Mainnet) | v0.79.x | v0.37.x | v1 |
| 8 (Mainnet) | v0.80.x | v0.37.x | v1 |
| 9 (Mainnet) | v0.81.x | v0.37.x | v1 |
4 changes: 2 additions & 2 deletions crates/bin/pd/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use cnidarium::Storage;
use metrics_exporter_prometheus::PrometheusBuilder;
use pd::{
cli::{NetworkCommand, Opt, RootCommand},
migrate::Migration::{Mainnet1, ReadyToStart},
migrate::Migration::{Mainnet2, ReadyToStart},
network::{
config::{get_network_dir, parse_tm_address, url_has_necessary_parts},
generate::NetworkConfig,
Expand Down Expand Up @@ -472,7 +472,7 @@ async fn main() -> anyhow::Result<()> {

let genesis_start = pd::migrate::last_block_timestamp(pd_home.clone()).await?;
tracing::info!(?genesis_start, "last block timestamp");
Mainnet1
Mainnet2
.migrate(pd_home.clone(), comet_home, Some(genesis_start), force)
.instrument(pd_migrate_span)
.await
Expand Down
7 changes: 7 additions & 0 deletions crates/bin/pd/src/migrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//! This module declares how local `pd` state should be altered, if at all,
//! in order to be compatible with the network post-chain-upgrade.
mod mainnet1;
mod mainnet2;
mod reset_halt_bit;
mod simple;
mod testnet72;
Expand Down Expand Up @@ -56,6 +57,9 @@ pub enum Migration {
/// Mainnet-1 migration:
/// - Restore IBC packet commitments for improperly handled withdrawal attempts
Mainnet1,
/// Mainnet-2 migration:
/// - no-op
Mainnet2,
}

impl Migration {
Expand Down Expand Up @@ -94,6 +98,9 @@ impl Migration {
Migration::Mainnet1 => {
mainnet1::migrate(storage, pd_home.clone(), genesis_start).await?;
}
Migration::Mainnet2 => {
mainnet2::migrate(storage, pd_home.clone(), genesis_start).await?;
}
// We keep historical migrations around for now, this will help inform an abstracted
// design. Feel free to remove it if it's causing you trouble.
_ => unimplemented!("the specified migration is unimplemented"),
Expand Down
103 changes: 103 additions & 0 deletions crates/bin/pd/src/migrate/mainnet2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//! Migration for shipping consensus-breaking IBC changes, fixing
//! how withdrawals from Penumbra to Noble are handled, and ensures that IBC
//! error messages from counterparty chains are processed.
use cnidarium::{StateDelta, Storage};
use jmt::RootHash;
use penumbra_app::app::StateReadExt as _;
use penumbra_app::app_version::migrate_app_version;
use penumbra_governance::StateWriteExt;
use penumbra_sct::component::clock::EpochManager;
use penumbra_sct::component::clock::EpochRead;
use std::path::PathBuf;
use tracing::instrument;

use crate::network::generate::NetworkConfig;

/// Run the full migration, emitting a new genesis event, representing historical state.
///
/// This will have the effect of reinserting packets which had acknowledgements containing
/// errors, and erroneously removed from state, as if the acknowledgements had contained successes.
#[instrument]
pub async fn migrate(
storage: Storage,
pd_home: PathBuf,
genesis_start: Option<tendermint::time::Time>,
) -> anyhow::Result<()> {
// Setup:
let initial_state = storage.latest_snapshot();
let chain_id = initial_state.get_chain_id().await?;
let root_hash = initial_state
.root_hash()
.await
.expect("chain state has a root hash");
// We obtain the pre-upgrade hash solely to log it as a result.
let pre_upgrade_root_hash: RootHash = root_hash.into();
let pre_upgrade_height = initial_state
.get_block_height()
.await
.expect("chain state has a block height");
let post_upgrade_height = pre_upgrade_height.wrapping_add(1);

let mut delta = StateDelta::new(initial_state);
let (migration_duration, post_upgrade_root_hash) = {
let start_time = std::time::SystemTime::now();

migrate_app_version(&mut delta, 9).await?;

// Reset the application height and halt flag.
delta.ready_to_start();
delta.put_block_height(0u64);

// Finally, commit the changes to the chain state.
let post_upgrade_root_hash = storage.commit_in_place(delta).await?;
tracing::info!(?post_upgrade_root_hash, "post-migration root hash");

(
start_time.elapsed().expect("start is set"),
post_upgrade_root_hash,
)
};
storage.release().await;

// The migration is complete, now we need to generate a genesis file. To do this, we need
// to lookup a validator view from the chain, and specify the post-upgrade app hash and
// initial height.
let app_state = penumbra_app::genesis::Content {
chain_id,
..Default::default()
};
let mut genesis = NetworkConfig::make_genesis(app_state.clone()).expect("can make genesis");
genesis.app_hash = post_upgrade_root_hash
.0
.to_vec()
.try_into()
.expect("infallible conversion");

genesis.initial_height = post_upgrade_height as i64;
genesis.genesis_time = genesis_start.unwrap_or_else(|| {
let now = tendermint::time::Time::now();
tracing::info!(%now, "no genesis time provided, detecting a testing setup");
now
});
let checkpoint = post_upgrade_root_hash.0.to_vec();
let genesis = NetworkConfig::make_checkpoint(genesis, Some(checkpoint));
let genesis_json = serde_json::to_string(&genesis).expect("can serialize genesis");
tracing::info!("genesis: {}", genesis_json);
let genesis_path = pd_home.join("genesis.json");
std::fs::write(genesis_path, genesis_json).expect("can write genesis");

let validator_state_path = pd_home.join("priv_validator_state.json");
let fresh_validator_state = crate::network::generate::NetworkValidator::initial_state();
std::fs::write(validator_state_path, fresh_validator_state).expect("can write validator state");

tracing::info!(
pre_upgrade_height,
post_upgrade_height,
?pre_upgrade_root_hash,
?post_upgrade_root_hash,
duration = migration_duration.as_secs(),
"successful migration!"
);

Ok(())
}
2 changes: 1 addition & 1 deletion crates/core/app/src/app_version.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// Representation of the Penumbra application version. Notably, this is distinct
/// from the crate version(s). This number should only ever be incremented.
pub const APP_VERSION: u64 = 8;
pub const APP_VERSION: u64 = 9;

cfg_if::cfg_if! {
if #[cfg(feature="component")] {
Expand Down
1 change: 1 addition & 0 deletions crates/core/app/src/app_version/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ fn version_to_software_version(version: u64) -> &'static str {
6 => "v0.77.x",
7 => "v0.79.x",
8 => "v0.80.x",
9 => "v0.81.x",
_ => "unknown",
}
}
Expand Down

0 comments on commit 2b6503c

Please sign in to comment.