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

fix: try-runtime #343

Merged
merged 7 commits into from
Apr 23, 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
51 changes: 51 additions & 0 deletions .github/workflows/check-rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -352,3 +352,54 @@ jobs:

- name: Check features
run: zepter run check

check-finney-migrations:
name: check finney migrations
runs-on: ubuntu-22.04
steps:
- name: Checkout sources
uses: actions/checkout@v3

- name: Run Try Runtime Checks
uses: "paritytech/[email protected]"
with:
runtime-package: "node-subtensor-runtime"
node-uri: "wss://entrypoint-finney.opentensor.ai:443"
checks: "pre-and-post"
extra-args: "--disable-spec-version-check --no-weight-warnings --disable-idempotency-checks"

# ----
# We can enable devnet and finney migrations once Polkadot v1.0 is deployed to finney, after
# which time all future migrations should be idempotent and won't start failing after the
# upgrade is deployed.
# ----
# check-devnet-migrations:
# name: check devnet migrations
# runs-on: ubuntu-22.04
# steps:
# - name: Checkout sources
# uses: actions/checkout@v3
#
# - name: Run Try Runtime Checks
# uses: "paritytech/[email protected]"
# with:
# runtime-package: "node-subtensor-runtime"
# node-uri: "wss://dev.chain.opentensor.ai:443"
# checks: "pre-and-post"
# extra-args: "--disable-spec-version-check --no-weight-warnings --disable-idempotency-checks"
#
# check-testnet-migrations:
# name: check testnet migrations
# runs-on: ubuntu-22.04
# steps:
# - name: Checkout sources
# uses: actions/checkout@v3
#
# - name: Run Try Runtime Checks
# uses: "paritytech/[email protected]"
# with:
# runtime-package: "node-subtensor-runtime"
# node-uri: "wss://test.chain.opentensor.ai:443"
# checks: "pre-and-post"
# extra-args: "--disable-spec-version-check --no-weight-warnings --disable-idempotency-checks"
#
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@ panic = "unwind"

[profile.test]
opt-level = 3

[profile.production]
inherits = "release"
lto = true
codegen-units = 1
2 changes: 1 addition & 1 deletion pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub mod pallet {

// Tracks version for migrations. Should be monotonic with respect to the
// order of migrations. (i.e. always increasing)
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
const STORAGE_VERSION: StorageVersion = StorageVersion::new(6);

#[pallet::pallet]
#[pallet::without_storage_info]
Expand Down
9 changes: 7 additions & 2 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod migrations;

use codec::{Decode, Encode, MaxEncodedLen};

use migrations::account_data_migration;
use migrations::{account_data_migration, init_storage_versions};
use pallet_commitments::CanCommit;
use pallet_grandpa::{
fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
Expand Down Expand Up @@ -1150,7 +1150,12 @@ pub type SignedExtra = (
pallet_commitments::CommitmentsSignedExtension<Runtime>,
);

type Migrations = account_data_migration::Migration;
type Migrations = (
init_storage_versions::Migration,
account_data_migration::Migration,
pallet_multisig::migrations::v1::MigrateToV1<Runtime>,
pallet_preimage::migration::v1::Migration<Runtime>,
);

// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic =
Expand Down
113 changes: 79 additions & 34 deletions runtime/src/migrations/account_data_migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ use crate::*;
use frame_support::log;
use pallet_balances::ExtraFlags;

#[cfg(feature = "try-runtime")]
use sp_std::collections::btree_map::BTreeMap;

mod prev {
use super::*;
use frame_support::{pallet_prelude::ValueQuery, storage_alias, Blake2_128Concat};
Expand Down Expand Up @@ -37,15 +40,27 @@ mod prev {
>;
}

#[cfg(feature = "try-runtime")]
#[derive(Encode, Decode)]
enum PreUpgradeInfo {
MigrationAlreadyOccured,
MigrationShouldRun(
BTreeMap<AccountId, frame_system::AccountInfo<u32, pallet_balances::AccountData<Balance>>>,
),
}

const TARGET: &'static str = "runtime::account_data_migration";
pub struct Migration;
impl OnRuntimeUpgrade for Migration {
/// Save pre-upgrade account ids to check are decodable post-upgrade.
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
use sp_std::collections::btree_map::BTreeMap;
log::info!(target: TARGET, "pre-upgrade");
// Skip migration if it already took place.
if migration_already_occured() {
return Ok(PreUpgradeInfo::MigrationAlreadyOccured.encode());
}

log::info!(target: TARGET, "pre-upgrade");
// Save the expected post-migration account state.
let mut expected_account: BTreeMap<
AccountId,
Expand Down Expand Up @@ -77,11 +92,20 @@ impl OnRuntimeUpgrade for Migration {
expected_account.insert(acc_id, expected_acc);
}

Ok(expected_account.encode())
Ok(PreUpgradeInfo::MigrationShouldRun(expected_account).encode())
}

/// Migrates Account storage to the new format, and calls `ensure_upgraded` for them.
fn on_runtime_upgrade() -> Weight {
// Skip migration if it already took place.
if migration_already_occured() {
log::warn!(
target: TARGET,
"Migration already completed and can be removed.",
);
return <Runtime as frame_system::Config>::DbWeight::get().reads_writes(0u64, 0u64);
}

// Pull the storage in the previous format into memory
let accounts = prev::Account::<Runtime>::iter().collect::<Vec<_>>();
log::info!(target: TARGET, "Migrating {} accounts...", accounts.len());
Expand Down Expand Up @@ -119,42 +143,63 @@ impl OnRuntimeUpgrade for Migration {
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
use frame_support::ensure;
use sp_std::collections::btree_map::BTreeMap;

log::info!(target: TARGET, "Running post-upgrade...");

let expected_accounts: BTreeMap<
AccountId,
frame_system::AccountInfo<u32, pallet_balances::AccountData<Balance>>,
> = Decode::decode(&mut &state[..]).expect("decoding state failed");

// Ensure the actual post-migration state matches the expected
for (acc_id, acc) in frame_system::pallet::Account::<Runtime>::iter() {
let expected = expected_accounts.get(&acc_id).expect("account not found");

// New system logic nukes the account if no providers or sufficients.
if acc.providers > 0 || acc.sufficients > 0 {
ensure!(acc.nonce == expected.nonce, "nonce mismatch");
ensure!(acc.consumers == expected.consumers, "consumers mismatch");
ensure!(acc.providers == expected.providers, "providers mismatch");
ensure!(
acc.sufficients == expected.sufficients,
"sufficients mismatch"
);
ensure!(acc.data.free == expected.data.free, "data.free mismatch");
ensure!(
acc.data.reserved == expected.data.reserved,
"data.reserved mismatch"
);
ensure!(
acc.data.frozen == expected.data.frozen,
"data.frozen mismatch"
);
ensure!(acc.data.flags == expected.data.flags, "data.flags mismatch");
let pre_upgrade_data: PreUpgradeInfo =
Decode::decode(&mut &state[..]).expect("decoding state failed");

match pre_upgrade_data {
PreUpgradeInfo::MigrationAlreadyOccured => Ok(()),
PreUpgradeInfo::MigrationShouldRun(expected_accounts) => {
// Ensure the actual post-migration state matches the expected
for (acc_id, acc) in frame_system::pallet::Account::<Runtime>::iter() {
let expected = expected_accounts.get(&acc_id).expect("account not found");

// New system logic nukes the account if no providers or sufficients.
if acc.providers > 0 || acc.sufficients > 0 {
ensure!(acc.nonce == expected.nonce, "nonce mismatch");
ensure!(acc.consumers == expected.consumers, "consumers mismatch");
ensure!(acc.providers == expected.providers, "providers mismatch");
ensure!(
acc.sufficients == expected.sufficients,
"sufficients mismatch"
);
ensure!(acc.data.free == expected.data.free, "data.free mismatch");
ensure!(
acc.data.reserved == expected.data.reserved,
"data.reserved mismatch"
);
ensure!(
acc.data.frozen == expected.data.frozen,
"data.frozen mismatch"
);
ensure!(acc.data.flags == expected.data.flags, "data.flags mismatch");
}
}

log::info!(target: TARGET, "post-upgrade success ✅");
Ok(())
}
}
}
}

log::info!(target: TARGET, "post-upgrade success ✅");
Ok(())
/// Check if the migration already took place. The migration is all-or-nothing, so if one
/// account is migrated we know that the rest also must be migrated.
///
/// We can use the nonce to check if it's been migrated, because it being zero meant that
/// the decode succeeded and this account has been migrated already.
///
/// Performance note: While this may appear poor for performance due to touching all keys,
/// these keys will need to be touched anyway, so it's fine to just touch them loading them into
/// the storage overlay here.
fn migration_already_occured() -> bool {
for (_, acc) in frame_system::pallet::Account::<Runtime>::iter() {
if acc.nonce > 0 {
return true;
};
}

false
}
26 changes: 26 additions & 0 deletions runtime/src/migrations/init_storage_versions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use crate::*;

/// Init the on-chain storage versions of pallets added to the runtime prior to this being an automatic process.
pub struct Migration;

impl OnRuntimeUpgrade for Migration {
fn on_runtime_upgrade() -> Weight {
use frame_support::traits::GetStorageVersion;
use frame_support::traits::StorageVersion;

if Triumvirate::on_chain_storage_version() == StorageVersion::new(0) {
Triumvirate::current_storage_version().put::<Triumvirate>();
}
if TriumvirateMembers::on_chain_storage_version() == StorageVersion::new(0) {
TriumvirateMembers::current_storage_version().put::<TriumvirateMembers>();
}
if SenateMembers::on_chain_storage_version() == StorageVersion::new(0) {
SenateMembers::current_storage_version().put::<SenateMembers>();
}
if Scheduler::on_chain_storage_version() == StorageVersion::new(0) {
Scheduler::current_storage_version().put::<Scheduler>();
}

<Runtime as frame_system::Config>::DbWeight::get().reads_writes(4, 4)
}
}
1 change: 1 addition & 0 deletions runtime/src/migrations/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod account_data_migration;
pub mod init_storage_versions;
Loading