Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pd: implement no op migration to v0.81.0 #4942

Merged
merged 3 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading