fix(rc-runtime): remove old pezpallet_staking and related pallets for RC 1_020_006
StakingAhClient (index 67) is now Active — old NPoS staking on RC is unused. Removed pallets: - Staking (pezpallet_staking, index 9) - FastUnstake (pezpallet_fast_unstake, index 15) - VoterBagsList (pezpallet_bags_list Instance1, index 100) Changes: - Added NoopFallback struct for ah_client::Config::Fallback - Updated validator_manager to use StakingAhClient - Added RemovePallet migrations for on-chain storage cleanup - Removed StakingConfig from genesis presets - Cleaned up unused imports and dependencies - Updated upgrade scripts (ah_upgrade, rc_upgrade, people_upgrade, set_ah_client_active)
This commit is contained in:
@@ -35,6 +35,7 @@ jobs:
|
||||
SKIP_WASM_BUILD: 1
|
||||
CARGO_INCREMENTAL: 0
|
||||
CARGO_TARGET_DIR: /cache/target
|
||||
WASM_BUILD_WORKSPACE_HINT: ${{ github.workspace }}
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4.1.7
|
||||
|
||||
|
||||
Generated
-3
@@ -14903,14 +14903,12 @@ dependencies = [
|
||||
"pezpallet-authority-discovery",
|
||||
"pezpallet-authorship",
|
||||
"pezpallet-babe",
|
||||
"pezpallet-bags-list",
|
||||
"pezpallet-balances",
|
||||
"pezpallet-beefy",
|
||||
"pezpallet-beefy-mmr",
|
||||
"pezpallet-collective",
|
||||
"pezpallet-conviction-voting",
|
||||
"pezpallet-election-provider-support-benchmarking",
|
||||
"pezpallet-fast-unstake",
|
||||
"pezpallet-grandpa",
|
||||
"pezpallet-indices",
|
||||
"pezpallet-message-queue",
|
||||
@@ -14930,7 +14928,6 @@ dependencies = [
|
||||
"pezpallet-scheduler",
|
||||
"pezpallet-session",
|
||||
"pezpallet-session-benchmarking",
|
||||
"pezpallet-staking",
|
||||
"pezpallet-staking-async-ah-client",
|
||||
"pezpallet-staking-async-rc-client",
|
||||
"pezpallet-staking-runtime-api",
|
||||
|
||||
@@ -54,7 +54,6 @@ pezframe-system-rpc-runtime-api = { workspace = true }
|
||||
pezpallet-authority-discovery = { workspace = true }
|
||||
pezpallet-authorship = { workspace = true }
|
||||
pezpallet-babe = { workspace = true }
|
||||
pezpallet-bags-list = { workspace = true }
|
||||
pezpallet-balances = { workspace = true }
|
||||
pezpallet-beefy = { workspace = true }
|
||||
pezpallet-beefy-mmr = { workspace = true }
|
||||
@@ -63,7 +62,6 @@ pezpallet-conviction-voting = { workspace = true }
|
||||
# pezpallet-democracy removed - pezpallet-welati implements custom governance
|
||||
# pezpallet-election-provider-multi-phase removed - using OnChain election
|
||||
# pezpallet-elections-phragmen removed - pezpallet-welati implements custom elections
|
||||
pezpallet-fast-unstake = { workspace = true }
|
||||
pezpallet-grandpa = { workspace = true }
|
||||
pezpallet-indices = { workspace = true }
|
||||
pezpallet-message-queue = { workspace = true }
|
||||
@@ -80,7 +78,6 @@ pezpallet-referenda = { workspace = true }
|
||||
pezpallet-root-testing = { workspace = true }
|
||||
pezpallet-scheduler = { workspace = true }
|
||||
pezpallet-session = { workspace = true }
|
||||
pezpallet-staking = { workspace = true }
|
||||
pezpallet-staking-async-ah-client = { workspace = true }
|
||||
pezpallet-staking-async-rc-client = { workspace = true }
|
||||
pezpallet-staking-runtime-api = { workspace = true }
|
||||
@@ -157,14 +154,12 @@ std = [
|
||||
"pezpallet-authority-discovery/std",
|
||||
"pezpallet-authorship/std",
|
||||
"pezpallet-babe/std",
|
||||
"pezpallet-bags-list/std",
|
||||
"pezpallet-balances/std",
|
||||
"pezpallet-beefy-mmr/std",
|
||||
"pezpallet-beefy/std",
|
||||
"pezpallet-collective/std",
|
||||
"pezpallet-conviction-voting/std",
|
||||
"pezpallet-election-provider-support-benchmarking?/std",
|
||||
"pezpallet-fast-unstake/std",
|
||||
"pezpallet-grandpa/std",
|
||||
"pezpallet-indices/std",
|
||||
"pezpallet-message-queue/std",
|
||||
@@ -187,7 +182,6 @@ std = [
|
||||
"pezpallet-staking-async-ah-client/std",
|
||||
"pezpallet-staking-async-rc-client/std",
|
||||
"pezpallet-staking-runtime-api/std",
|
||||
"pezpallet-staking/std",
|
||||
"pezpallet-state-trie-migration/std",
|
||||
"pezpallet-sudo/std",
|
||||
"pezpallet-timestamp/std",
|
||||
@@ -251,14 +245,12 @@ runtime-benchmarks = [
|
||||
"pezpallet-authority-discovery/runtime-benchmarks",
|
||||
"pezpallet-authorship/runtime-benchmarks",
|
||||
"pezpallet-babe/runtime-benchmarks",
|
||||
"pezpallet-bags-list/runtime-benchmarks",
|
||||
"pezpallet-balances/runtime-benchmarks",
|
||||
"pezpallet-beefy-mmr/runtime-benchmarks",
|
||||
"pezpallet-beefy/runtime-benchmarks",
|
||||
"pezpallet-collective/runtime-benchmarks",
|
||||
"pezpallet-conviction-voting/runtime-benchmarks",
|
||||
"pezpallet-election-provider-support-benchmarking/runtime-benchmarks",
|
||||
"pezpallet-fast-unstake/runtime-benchmarks",
|
||||
"pezpallet-grandpa/runtime-benchmarks",
|
||||
"pezpallet-indices/runtime-benchmarks",
|
||||
"pezpallet-message-queue/runtime-benchmarks",
|
||||
@@ -281,7 +273,6 @@ runtime-benchmarks = [
|
||||
"pezpallet-staking-async-ah-client/runtime-benchmarks",
|
||||
"pezpallet-staking-async-rc-client/runtime-benchmarks",
|
||||
"pezpallet-staking-runtime-api/runtime-benchmarks",
|
||||
"pezpallet-staking/runtime-benchmarks",
|
||||
"pezpallet-state-trie-migration/runtime-benchmarks",
|
||||
"pezpallet-sudo/runtime-benchmarks",
|
||||
"pezpallet-timestamp/runtime-benchmarks",
|
||||
@@ -336,14 +327,12 @@ try-runtime = [
|
||||
"pezpallet-authority-discovery/try-runtime",
|
||||
"pezpallet-authorship/try-runtime",
|
||||
"pezpallet-babe/try-runtime",
|
||||
"pezpallet-bags-list/try-runtime",
|
||||
"pezpallet-balances/try-runtime",
|
||||
"pezpallet-beefy-mmr/try-runtime",
|
||||
"pezpallet-beefy/try-runtime",
|
||||
"pezpallet-collective/try-runtime",
|
||||
"pezpallet-conviction-voting/try-runtime",
|
||||
"pezpallet-election-provider-support-benchmarking?/try-runtime",
|
||||
"pezpallet-fast-unstake/try-runtime",
|
||||
"pezpallet-grandpa/try-runtime",
|
||||
"pezpallet-indices/try-runtime",
|
||||
"pezpallet-message-queue/try-runtime",
|
||||
@@ -365,7 +354,6 @@ try-runtime = [
|
||||
"pezpallet-session/try-runtime",
|
||||
"pezpallet-staking-async-ah-client/try-runtime",
|
||||
"pezpallet-staking-async-rc-client/try-runtime",
|
||||
"pezpallet-staking/try-runtime",
|
||||
"pezpallet-state-trie-migration/try-runtime",
|
||||
"pezpallet-sudo/try-runtime",
|
||||
"pezpallet-timestamp/try-runtime",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
use crate::{
|
||||
BabeConfig, BalancesConfig, ConfigurationConfig, RegistrarConfig, RuntimeGenesisConfig,
|
||||
SessionConfig, SessionKeys, StakingConfig, SudoConfig, BABE_GENESIS_EPOCH_CONFIG,
|
||||
SessionConfig, SessionKeys, SudoConfig, BABE_GENESIS_EPOCH_CONFIG,
|
||||
};
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::format;
|
||||
@@ -37,7 +37,6 @@ use alloc::{vec, vec::Vec};
|
||||
use pezframe_support::build_struct_json_patch;
|
||||
use pezkuwi_primitives::{AccountId, AssignmentId, SchedulerParams, ValidatorId};
|
||||
use pezkuwichain_runtime_constants::currency::UNITS as TYR;
|
||||
use pezpallet_staking::{Forcing, StakerStatus};
|
||||
use pezsp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
|
||||
use pezsp_consensus_babe::AuthorityId as BabeId;
|
||||
use pezsp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId;
|
||||
@@ -45,7 +44,6 @@ use pezsp_consensus_grandpa::AuthorityId as GrandpaId;
|
||||
use pezsp_core::{crypto::get_public_from_string_or_panic, sr25519};
|
||||
use pezsp_genesis_builder::PresetId;
|
||||
use pezsp_keyring::Sr25519Keyring;
|
||||
use pezsp_runtime::Perbill;
|
||||
|
||||
// ============================================================================
|
||||
// HEZ TOKEN GENESIS CONSTANTS (Total Supply: 200 Million HEZ)
|
||||
@@ -1020,17 +1018,6 @@ fn pezkuwichain_genesis_config() -> serde_json::Value {
|
||||
))
|
||||
.collect::<Vec<_>>(),
|
||||
},
|
||||
staking: StakingConfig {
|
||||
minimum_validator_count: 1,
|
||||
validator_count: initial_authorities.len() as u32,
|
||||
stakers: initial_authorities
|
||||
.iter()
|
||||
.map(|x| (x.0.clone(), x.0.clone(), STASH, StakerStatus::<AccountId>::Validator))
|
||||
.collect::<Vec<_>>(),
|
||||
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect::<Vec<_>>(),
|
||||
force_era: Forcing::ForceAlways,
|
||||
slash_reward_fraction: Perbill::from_percent(10),
|
||||
},
|
||||
babe: BabeConfig { epoch_config: BABE_GENESIS_EPOCH_CONFIG },
|
||||
sudo: SudoConfig { key: Some(founder_account) },
|
||||
configuration: ConfigurationConfig { config: default_teyrchains_host_configuration() },
|
||||
@@ -1135,17 +1122,6 @@ fn pezkuwichain_mainnet_simulation_genesis() -> serde_json::Value {
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
},
|
||||
staking: StakingConfig {
|
||||
minimum_validator_count: 1,
|
||||
validator_count: initial_authorities.len() as u32,
|
||||
stakers: initial_authorities
|
||||
.iter()
|
||||
.map(|x| (x.0.clone(), x.0.clone(), STASH, StakerStatus::<AccountId>::Validator))
|
||||
.collect::<Vec<_>>(),
|
||||
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect::<Vec<_>>(),
|
||||
force_era: Forcing::ForceAlways,
|
||||
slash_reward_fraction: Perbill::from_percent(10),
|
||||
},
|
||||
babe: BabeConfig { epoch_config: BABE_GENESIS_EPOCH_CONFIG },
|
||||
sudo: SudoConfig { key: Some(founder_account) },
|
||||
configuration: ConfigurationConfig { config: default_teyrchains_host_configuration() },
|
||||
|
||||
@@ -93,7 +93,7 @@ use pezframe_support::{
|
||||
parameter_types,
|
||||
traits::{
|
||||
fungible::HoldConsideration, EitherOf, EitherOfDiverse, EnsureOriginWithArg,
|
||||
InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, Nothing, PrivilegeCmp,
|
||||
InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp,
|
||||
ProcessMessage, ProcessMessageError, WithdrawReasons,
|
||||
},
|
||||
weights::{ConstantMultiplier, WeightMeter},
|
||||
@@ -105,7 +105,7 @@ use pezpallet_session::historical as session_historical;
|
||||
use pezpallet_staking_async_ah_client as ah_client;
|
||||
use pezpallet_staking_async_rc_client as rc_client;
|
||||
use pezpallet_transaction_payment::{FeeDetails, FungibleAdapter, RuntimeDispatchInfo};
|
||||
use pezsp_core::{ConstBool, ConstU128, ConstUint, Get, OpaqueMetadata, H256};
|
||||
use pezsp_core::{ConstUint, Get, OpaqueMetadata, H256};
|
||||
use pezsp_runtime::{
|
||||
generic, impl_opaque_keys,
|
||||
traits::{
|
||||
@@ -174,7 +174,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: alloc::borrow::Cow::Borrowed("pezkuwichain"),
|
||||
impl_name: alloc::borrow::Cow::Borrowed("parity-pezkuwichain"),
|
||||
authoring_version: 0,
|
||||
spec_version: 1_020_005,
|
||||
spec_version: 1_020_006,
|
||||
impl_version: 0,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
transaction_version: 26,
|
||||
@@ -454,20 +454,55 @@ impl pezpallet_session::Config for Runtime {
|
||||
type KeyDeposit = ();
|
||||
}
|
||||
|
||||
/// Returns staking exposure for historical session tracking.
|
||||
/// Falls back to a default empty exposure when none exists yet (e.g. at genesis),
|
||||
/// preventing validators from being filtered out of the authority set.
|
||||
/// Returns a default empty exposure for historical session tracking.
|
||||
/// Exposure data is now on Asset Hub — RC returns default to keep validators in authority set.
|
||||
pub struct ExposureOfOrDefault;
|
||||
impl pezsp_runtime::traits::Convert<AccountId, Option<pezsp_staking::Exposure<AccountId, Balance>>>
|
||||
for ExposureOfOrDefault
|
||||
{
|
||||
fn convert(validator: AccountId) -> Option<pezsp_staking::Exposure<AccountId, Balance>> {
|
||||
Some(
|
||||
<pezpallet_staking::DefaultExposureOf<Runtime>>::convert(validator).unwrap_or_default(),
|
||||
)
|
||||
fn convert(_validator: AccountId) -> Option<pezsp_staking::Exposure<AccountId, Balance>> {
|
||||
Some(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
/// No-op fallback for StakingAhClient. Required at compile time but never called
|
||||
/// since Mode is Active — all session/offence/reward logic goes through StakingAhClient.
|
||||
pub struct NoopFallback;
|
||||
|
||||
impl pezpallet_session::SessionManager<AccountId> for NoopFallback {
|
||||
fn new_session(_: SessionIndex) -> Option<Vec<AccountId>> {
|
||||
None
|
||||
}
|
||||
fn start_session(_: SessionIndex) {}
|
||||
fn end_session(_: SessionIndex) {}
|
||||
}
|
||||
|
||||
impl pezsp_staking::offence::OnOffenceHandler<
|
||||
AccountId,
|
||||
(AccountId, pezsp_staking::Exposure<AccountId, Balance>),
|
||||
Weight,
|
||||
> for NoopFallback
|
||||
{
|
||||
fn on_offence(
|
||||
_offenders: &[pezsp_staking::offence::OffenceDetails<
|
||||
AccountId,
|
||||
(AccountId, pezsp_staking::Exposure<AccountId, Balance>),
|
||||
>],
|
||||
_slash_fraction: &[Perbill],
|
||||
_session: SessionIndex,
|
||||
) -> Weight {
|
||||
Weight::zero()
|
||||
}
|
||||
}
|
||||
|
||||
impl pezframe_support::traits::RewardsReporter<AccountId> for NoopFallback {
|
||||
fn reward_by_ids(_: impl IntoIterator<Item = (AccountId, u32)>) {}
|
||||
}
|
||||
|
||||
impl pezpallet_authorship::EventHandler<AccountId, BlockNumber> for NoopFallback {
|
||||
fn note_author(_: AccountId) {}
|
||||
}
|
||||
|
||||
impl pezpallet_session::historical::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type FullIdentification = pezsp_staking::Exposure<AccountId, Balance>;
|
||||
@@ -475,106 +510,11 @@ impl pezpallet_session::historical::Config for Runtime {
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// STAKING CONFIGURATION
|
||||
// STAKING CONFIGURATION (async — managed by StakingAhClient)
|
||||
// =====================================================
|
||||
|
||||
parameter_types! {
|
||||
pub const SessionsPerEra: SessionIndex = 6;
|
||||
pub const BondingDuration: pezsp_staking::EraIndex = 28;
|
||||
pub const SlashDeferDuration: pezsp_staking::EraIndex = 27;
|
||||
pub const HistoryDepth: u32 = 84;
|
||||
pub const MaxWinners: u32 = 100;
|
||||
pub const MaxElectingVoters: u32 = 22_500;
|
||||
pub const MaxActiveValidators: u32 = 1000;
|
||||
// Limits for election provider.
|
||||
pub const ElectionBounds: pezframe_election_provider_support::bounds::ElectionBounds =
|
||||
pezframe_election_provider_support::bounds::ElectionBounds {
|
||||
voters: pezframe_election_provider_support::bounds::DataProviderBounds {
|
||||
size: Some(pezframe_election_provider_support::bounds::SizeBound(20_000)),
|
||||
count: Some(pezframe_election_provider_support::bounds::CountBound(1_000)),
|
||||
},
|
||||
targets: pezframe_election_provider_support::bounds::DataProviderBounds {
|
||||
size: Some(pezframe_election_provider_support::bounds::SizeBound(1_500)),
|
||||
count: Some(pezframe_election_provider_support::bounds::CountBound(200)),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub struct OnChainSeqPhragmen;
|
||||
impl pezframe_election_provider_support::onchain::Config for OnChainSeqPhragmen {
|
||||
type Sort = ConstBool<true>;
|
||||
type System = Runtime;
|
||||
type Solver = pezframe_election_provider_support::SequentialPhragmen<AccountId, Perbill>;
|
||||
type DataProvider = Staking;
|
||||
type WeightInfo = pezframe_election_provider_support::weights::BizinikiwiWeight<Runtime>;
|
||||
type MaxBackersPerWinner = MaxElectingVoters;
|
||||
type MaxWinnersPerPage = MaxWinners;
|
||||
type Bounds = ElectionBounds;
|
||||
}
|
||||
|
||||
/// Era payout calculation for staking rewards.
|
||||
pub struct EraPayout;
|
||||
impl pezpallet_staking::EraPayout<Balance> for EraPayout {
|
||||
fn era_payout(
|
||||
_total_staked: Balance,
|
||||
_total_issuance: Balance,
|
||||
era_duration_millis: u64,
|
||||
) -> (Balance, Balance) {
|
||||
const MILLISECONDS_PER_YEAR: u64 = (1000 * 3600 * 24 * 36525) / 100;
|
||||
let relative_era_len =
|
||||
FixedU128::from_rational(era_duration_millis.into(), MILLISECONDS_PER_YEAR.into());
|
||||
// Fixed baseline: 200M HEZ (12 decimals) — prevents compound inflation
|
||||
let fixed_total_issuance: i128 = 200_000_000_000_000_000_000;
|
||||
let fixed_inflation_rate = FixedU128::from_rational(8, 100);
|
||||
let yearly_emission = fixed_inflation_rate.saturating_mul_int(fixed_total_issuance);
|
||||
let era_emission = relative_era_len.saturating_mul_int(yearly_emission);
|
||||
// 15% to treasury, 85% to stakers
|
||||
let to_treasury = FixedU128::from_rational(15, 100).saturating_mul_int(era_emission);
|
||||
let to_stakers = era_emission.saturating_sub(to_treasury);
|
||||
(to_stakers.saturated_into(), to_treasury.saturated_into())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PezkuwiStakingBenchmarkingConfig;
|
||||
impl pezpallet_staking::BenchmarkingConfig for PezkuwiStakingBenchmarkingConfig {
|
||||
type MaxValidators = ConstU32<1000>;
|
||||
type MaxNominators = ConstU32<1000>;
|
||||
}
|
||||
|
||||
impl pezpallet_staking::Config for Runtime {
|
||||
type Currency = Balances;
|
||||
type CurrencyBalance = Balance;
|
||||
type UnixTime = Timestamp;
|
||||
type CurrencyToVote = pezsp_staking::currency_to_vote::U128CurrencyToVote;
|
||||
type RewardRemainder = ();
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type Slash = ();
|
||||
type Reward = ();
|
||||
type SessionsPerEra = SessionsPerEra;
|
||||
type BondingDuration = BondingDuration;
|
||||
type SlashDeferDuration = SlashDeferDuration;
|
||||
type SessionInterface = ();
|
||||
type EraPayout = EraPayout;
|
||||
type NextNewSession = Session;
|
||||
type MaxExposurePageSize = ConstU32<512>;
|
||||
type MaxValidatorSet = MaxActiveValidators;
|
||||
type ElectionProvider =
|
||||
pezframe_election_provider_support::onchain::OnChainExecution<OnChainSeqPhragmen>;
|
||||
type GenesisElectionProvider =
|
||||
pezframe_election_provider_support::onchain::OnChainExecution<OnChainSeqPhragmen>;
|
||||
type VoterList = VoterBagsList;
|
||||
type TargetList = pezpallet_staking::UseValidatorsMap<Self>;
|
||||
type MaxControllersInDeprecationBatch = ConstU32<5_900>;
|
||||
type AdminOrigin = EnsureRoot<AccountId>;
|
||||
type EventListeners = ();
|
||||
type WeightInfo = pezpallet_staking::weights::BizinikiwiWeight<Runtime>;
|
||||
type RuntimeHoldReason = RuntimeHoldReason;
|
||||
type HistoryDepth = HistoryDepth;
|
||||
type NominationsQuota = pezpallet_staking::FixedNominationsQuota<16>;
|
||||
type MaxUnlockingChunks = ConstU32<32>;
|
||||
type Filter = Nothing;
|
||||
type OldCurrency = Balances;
|
||||
type BenchmarkingConfig = PezkuwiStakingBenchmarkingConfig;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
@@ -703,25 +643,11 @@ impl ah_client::Config for Runtime {
|
||||
type UnixTime = Timestamp;
|
||||
type PointsPerBlock = ConstU32<20>;
|
||||
type MaxOffenceBatchSize = ConstU32<50>;
|
||||
type Fallback = Staking;
|
||||
type Fallback = NoopFallback;
|
||||
type MaximumValidatorsWithPoints = ConstU32<{ MaxActiveValidators::get() * 4 }>;
|
||||
type MaxSessionReportRetries = ConstU32<64>;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// FAST UNSTAKE CONFIGURATION
|
||||
// =====================================================
|
||||
|
||||
impl pezpallet_fast_unstake::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type Currency = Balances;
|
||||
type BatchSize = ConstU32<64>;
|
||||
type Deposit = ConstU128<{ UNITS }>;
|
||||
type ControlOrigin = EnsureRoot<AccountId>;
|
||||
type Staking = Staking;
|
||||
type MaxErasToCheckPerBlock = ConstU32<1>;
|
||||
type WeightInfo = pezpallet_fast_unstake::weights::BizinikiwiWeight<Runtime>;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// VALIDATOR POOL CONFIGURATION (TNPoS Shadow Mode)
|
||||
@@ -782,35 +708,6 @@ impl pezpallet_validator_pool::Config for Runtime {
|
||||
type MinStakeAmount = ValidatorPoolMinStakeAmount;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// VOTER BAGS LIST CONFIGURATION
|
||||
// =====================================================
|
||||
|
||||
parameter_types! {
|
||||
pub const VoterBagThresholds: &'static [u64] = &[
|
||||
100 * UNITS as u64,
|
||||
200 * UNITS as u64,
|
||||
500 * UNITS as u64,
|
||||
1_000 * UNITS as u64,
|
||||
2_000 * UNITS as u64,
|
||||
5_000 * UNITS as u64,
|
||||
10_000 * UNITS as u64,
|
||||
20_000 * UNITS as u64,
|
||||
50_000 * UNITS as u64,
|
||||
100_000 * UNITS as u64,
|
||||
];
|
||||
}
|
||||
|
||||
pub type VoterBagsListInstance = pezpallet_bags_list::Instance1;
|
||||
impl pezpallet_bags_list::Config<VoterBagsListInstance> for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type WeightInfo = pezpallet_bags_list::weights::BizinikiwiWeight<Runtime>;
|
||||
type ScoreProvider = Staking;
|
||||
type BagThresholds = VoterBagThresholds;
|
||||
type Score = u64;
|
||||
type MaxAutoRebagPerBlock = ConstU32<10>;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// COUNCIL CONFIGURATION
|
||||
// =====================================================
|
||||
@@ -902,7 +799,8 @@ impl pezpallet_authority_discovery::Config for Runtime {
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const MaxSetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get();
|
||||
// BondingDuration(2) * SessionsPerEra(6) — matches AH staking config
|
||||
pub const MaxSetIdSessionEntries: u32 = 2 * 6;
|
||||
}
|
||||
|
||||
impl pezpallet_grandpa::Config for Runtime {
|
||||
@@ -1479,7 +1377,8 @@ impl pezpallet_parameters::Config for Runtime {
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub BeefySetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get();
|
||||
// BondingDuration(2) * SessionsPerEra(6) — matches AH staking config
|
||||
pub BeefySetIdSessionEntries: u32 = 2 * 6;
|
||||
}
|
||||
|
||||
impl pezpallet_beefy::Config for Runtime {
|
||||
@@ -1561,7 +1460,7 @@ impl assigned_slots::Config for Runtime {
|
||||
impl validator_manager::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type PrivilegedOrigin = EnsureRoot<AccountId>;
|
||||
type Staking = Staking;
|
||||
type Staking = StakingAhClient;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
@@ -1623,13 +1522,9 @@ construct_runtime! {
|
||||
Historical: session_historical = 34,
|
||||
|
||||
Session: pezpallet_session = 8,
|
||||
Staking: pezpallet_staking = 9,
|
||||
Grandpa: pezpallet_grandpa = 10,
|
||||
AuthorityDiscovery: pezpallet_authority_discovery = 12,
|
||||
|
||||
// Staking extensions.
|
||||
FastUnstake: pezpallet_fast_unstake = 15,
|
||||
|
||||
// Governance stuff; uncallable initially.
|
||||
Council: pezpallet_collective::<Instance1> = 17,
|
||||
Treasury: pezpallet_treasury = 18,
|
||||
@@ -1713,9 +1608,6 @@ construct_runtime! {
|
||||
// Root testing pezpallet.
|
||||
RootTesting: pezpallet_root_testing = 249,
|
||||
|
||||
// VoterBagsList pezpallet.
|
||||
VoterBagsList: pezpallet_bags_list::<Instance1> = 100,
|
||||
|
||||
// Sudo.
|
||||
Sudo: pezpallet_sudo = 255,
|
||||
}
|
||||
@@ -1799,6 +1691,10 @@ pub mod migrations {
|
||||
pub const TechnicalMembershipPalletName: &'static str = "TechnicalMembership";
|
||||
pub const TipsPalletName: &'static str = "Tips";
|
||||
pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect";
|
||||
// Old staking ecosystem pallets (replaced by StakingAhClient + AH staking)
|
||||
pub const StakingPalletName: &'static str = "Staking";
|
||||
pub const FastUnstakePalletName: &'static str = "FastUnstake";
|
||||
pub const VoterBagsListPalletName: &'static str = "VoterBagsList";
|
||||
/// Weight for balance unreservations
|
||||
pub BalanceUnreserveWeight: Weight = weights::pezpallet_balances_balances::WeightInfo::<Runtime>::force_unreserve();
|
||||
pub BalanceTransferAllowDeath: Weight = weights::pezpallet_balances_balances::WeightInfo::<Runtime>::transfer_allow_death();
|
||||
@@ -1874,6 +1770,19 @@ pub mod migrations {
|
||||
teyrchains_inclusion::migration::MigrateToV1<Runtime>,
|
||||
teyrchains_shared::migration::MigrateToV1<Runtime>,
|
||||
teyrchains_scheduler::migration::MigrateV2ToV3<Runtime>,
|
||||
// Remove old staking ecosystem pallets (replaced by StakingAhClient + AH staking)
|
||||
pezframe_support::migrations::RemovePallet<
|
||||
StakingPalletName,
|
||||
<Runtime as pezframe_system::Config>::DbWeight,
|
||||
>,
|
||||
pezframe_support::migrations::RemovePallet<
|
||||
FastUnstakePalletName,
|
||||
<Runtime as pezframe_system::Config>::DbWeight,
|
||||
>,
|
||||
pezframe_support::migrations::RemovePallet<
|
||||
VoterBagsListPalletName,
|
||||
<Runtime as pezframe_system::Config>::DbWeight,
|
||||
>,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+212
-127
@@ -1,11 +1,12 @@
|
||||
//! Asset Hub Runtime Upgrade (Local Simulation)
|
||||
//! Asset Hub Runtime Upgrade (Mainnet)
|
||||
//!
|
||||
//! Two-step process:
|
||||
//! 1. RC → XCM → AH: System.authorize_upgrade(blake2_256(wasm))
|
||||
//! 2. AH direct: System.apply_authorized_upgrade(wasm)
|
||||
//!
|
||||
//! Run:
|
||||
//! SUDO_MNEMONIC="..." \
|
||||
//! RC_RPC="ws://217.77.6.126:9944" \
|
||||
//! AH_RPC="ws://217.77.6.126:40944" \
|
||||
//! WASM_FILE="target/release/wbuild/asset-hub-pezkuwichain-runtime/asset_hub_pezkuwichain_runtime.compact.compressed.wasm" \
|
||||
//! cargo run --release -p pezkuwi-subxt --example ah_upgrade
|
||||
|
||||
@@ -16,35 +17,76 @@ use pezkuwi_subxt_signer::bip39::Mnemonic;
|
||||
use pezkuwi_subxt_signer::sr25519::Keypair;
|
||||
use std::str::FromStr;
|
||||
|
||||
const AH_PARA_ID: u128 = 1000;
|
||||
|
||||
fn load_sudo_keypair() -> Keypair {
|
||||
// 1. Try SUDO_MNEMONIC env var
|
||||
if let Ok(mnemonic_str) = std::env::var("SUDO_MNEMONIC") {
|
||||
if !mnemonic_str.is_empty() {
|
||||
if let Ok(mnemonic) = Mnemonic::from_str(&mnemonic_str) {
|
||||
if let Ok(kp) = Keypair::from_phrase(&mnemonic, None) {
|
||||
println!(" [sudo] Loaded from SUDO_MNEMONIC env var");
|
||||
return kp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fallback to seeds file
|
||||
let seeds_path = "/home/mamostehp/res/test_seeds.json";
|
||||
if let Ok(content) = std::fs::read_to_string(seeds_path) {
|
||||
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&content) {
|
||||
if let Some(mnemonic_str) = json["sudo_mnemonic"].as_str() {
|
||||
if let Ok(mnemonic) = Mnemonic::from_str(mnemonic_str) {
|
||||
if let Ok(kp) = Keypair::from_phrase(&mnemonic, None) {
|
||||
println!(" [sudo] Loaded from {}", seeds_path);
|
||||
return kp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
panic!("SUDO_MNEMONIC required! Set env var or create /home/mamostehp/res/test_seeds.json");
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("=== ASSET HUB RUNTIME UPGRADE ===\n");
|
||||
println!("╔══════════════════════════════════════════╗");
|
||||
println!("║ ASSET HUB RUNTIME UPGRADE ║");
|
||||
println!("╚══════════════════════════════════════════╝\n");
|
||||
|
||||
let rc_url = std::env::var("RC_RPC").unwrap_or_else(|_| "ws://127.0.0.1:9944".to_string());
|
||||
let ah_url = std::env::var("AH_RPC").unwrap_or_else(|_| "ws://127.0.0.1:40944".to_string());
|
||||
let wasm_path = std::env::var("WASM_FILE").expect("WASM_FILE environment variable required");
|
||||
|
||||
let mnemonic_str =
|
||||
std::env::var("SUDO_MNEMONIC").expect("SUDO_MNEMONIC environment variable required");
|
||||
let mnemonic = Mnemonic::from_str(&mnemonic_str)?;
|
||||
let sudo_keypair = Keypair::from_phrase(&mnemonic, None)?;
|
||||
println!("Sudo: {}", sudo_keypair.public_key().to_account_id());
|
||||
let sudo_keypair = load_sudo_keypair();
|
||||
println!(" Sudo: {}", sudo_keypair.public_key().to_account_id());
|
||||
|
||||
// Load WASM
|
||||
let wasm_data = std::fs::read(&wasm_path)?;
|
||||
println!("WASM: {} ({:.2} MB)", wasm_path, wasm_data.len() as f64 / 1_048_576.0);
|
||||
println!(
|
||||
" WASM: {} ({:.2} MB)",
|
||||
wasm_path,
|
||||
wasm_data.len() as f64 / 1_048_576.0
|
||||
);
|
||||
|
||||
// Blake2-256 hash of WASM
|
||||
let code_hash = pezsp_crypto_hashing::blake2_256(&wasm_data);
|
||||
println!("Code hash: 0x{}", hex::encode(code_hash));
|
||||
println!(" Code hash: 0x{}", hex::encode(code_hash));
|
||||
|
||||
// Connect to RC
|
||||
let rc_api = OnlineClient::<PezkuwiConfig>::from_url(&rc_url).await?;
|
||||
println!("RC connected: {} (spec {})", rc_url, rc_api.runtime_version().spec_version);
|
||||
let rc_api = OnlineClient::<PezkuwiConfig>::from_insecure_url(&rc_url).await?;
|
||||
println!(
|
||||
" RC connected: {} (spec {})",
|
||||
rc_url,
|
||||
rc_api.runtime_version().spec_version
|
||||
);
|
||||
|
||||
// Connect to AH
|
||||
let ah_api = OnlineClient::<PezkuwiConfig>::from_url(&ah_url).await?;
|
||||
println!("AH connected: {} (spec {})\n", ah_url, ah_api.runtime_version().spec_version);
|
||||
let ah_api = OnlineClient::<PezkuwiConfig>::from_insecure_url(&ah_url).await?;
|
||||
let old_spec = ah_api.runtime_version().spec_version;
|
||||
println!(" AH connected: {} (spec {})\n", ah_url, old_spec);
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// STEP 1: Authorize upgrade via XCM from RC
|
||||
@@ -52,10 +94,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("=== STEP 1: Authorize upgrade (RC → XCM → AH) ===");
|
||||
|
||||
// Encode System::authorize_upgrade_without_checks(code_hash)
|
||||
// System pallet index = 0, call_index = 10
|
||||
// System pallet index = 0, call_index = 10 (verified from source)
|
||||
let mut encoded_call = Vec::with_capacity(34);
|
||||
encoded_call.push(0x00); // System pallet
|
||||
encoded_call.push(0x0a); // authorize_upgrade_without_checks (10)
|
||||
encoded_call.push(0x0a); // authorize_upgrade_without_checks = call_index(10)
|
||||
encoded_call.extend_from_slice(&code_hash);
|
||||
println!(" Encoded call: {} bytes", encoded_call.len());
|
||||
|
||||
@@ -67,7 +109,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
"interior",
|
||||
Value::unnamed_variant(
|
||||
"X1",
|
||||
vec![Value::unnamed_variant("Teyrchain", vec![Value::u128(1000)])],
|
||||
vec![Value::unnamed_variant(
|
||||
"Teyrchain",
|
||||
vec![Value::u128(AH_PARA_ID)],
|
||||
)],
|
||||
),
|
||||
),
|
||||
])],
|
||||
@@ -113,7 +158,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
],
|
||||
);
|
||||
|
||||
let progress = rc_api.tx().sign_and_submit_then_watch_default(&sudo_tx, &sudo_keypair).await?;
|
||||
let progress = rc_api
|
||||
.tx()
|
||||
.sign_and_submit_then_watch_default(&sudo_tx, &sudo_keypair)
|
||||
.await?;
|
||||
let events = progress.wait_for_finalized_success().await?;
|
||||
|
||||
let mut sent = false;
|
||||
@@ -127,8 +175,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
}
|
||||
if !sent {
|
||||
println!(" WARNING: No XcmPallet::Sent event!");
|
||||
println!(" Aborting.");
|
||||
println!(" ERROR: No XcmPallet::Sent event! Aborting.");
|
||||
return Ok(());
|
||||
}
|
||||
println!(" XCM authorize_upgrade sent!\n");
|
||||
@@ -139,26 +186,26 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
for attempt in 1..=30 {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(6)).await;
|
||||
|
||||
// Reconnect to get fresh state
|
||||
let ah_check = OnlineClient::<PezkuwiConfig>::from_url(&ah_url).await?;
|
||||
let ah_check = OnlineClient::<PezkuwiConfig>::from_insecure_url(&ah_url).await?;
|
||||
let block = ah_check.blocks().at_latest().await?;
|
||||
let block_num = block.number();
|
||||
|
||||
// Check System::AuthorizedUpgrade storage via raw key
|
||||
// twox128("System") ++ twox128("AuthorizedUpgrade")
|
||||
let auth_key = pezsp_crypto_hashing::twox_128(b"System")
|
||||
.iter()
|
||||
.chain(pezsp_crypto_hashing::twox_128(b"AuthorizedUpgrade").iter())
|
||||
.copied()
|
||||
.collect::<Vec<u8>>();
|
||||
let result = ah_check.storage().at_latest().await?.fetch_raw(auth_key).await?;
|
||||
if !result.is_empty() {
|
||||
println!(
|
||||
" AuthorizedUpgrade found on AH at block {} (attempt {})!",
|
||||
block_num, attempt
|
||||
);
|
||||
authorized = true;
|
||||
break;
|
||||
let result = ah_check.storage().at_latest().await?.fetch_raw(auth_key).await;
|
||||
match result {
|
||||
Ok(data) if !data.is_empty() => {
|
||||
println!(
|
||||
" AuthorizedUpgrade found on AH at block {} (attempt {})!",
|
||||
block_num, attempt
|
||||
);
|
||||
authorized = true;
|
||||
break;
|
||||
},
|
||||
_ => {}, // NoValueFound or empty — not yet set
|
||||
}
|
||||
println!(
|
||||
" Attempt {}/30: AH block {} — AuthorizedUpgrade not yet set...",
|
||||
@@ -172,98 +219,119 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// STEP 1.5: Fund sudo account on AH via XCM
|
||||
// STEP 1.5: Fund sudo account on AH via XCM (if needed)
|
||||
// ═══════════════════════════════════════════
|
||||
println!("\n=== STEP 1.5: Fund sudo account on AH ===");
|
||||
let sudo_account_id = sudo_keypair.public_key().to_account_id();
|
||||
let account_bytes: [u8; 32] = *sudo_account_id.as_ref();
|
||||
|
||||
// Encode Balances::force_set_balance(who, new_free)
|
||||
// Balances pallet = 10, call_index = 8
|
||||
// who = MultiAddress::Id(AccountId32) = variant 0 + 32 bytes
|
||||
// new_free = Compact<u128> = 100 HEZ = 100 * 10^18
|
||||
let mut fund_call: Vec<u8> = Vec::new();
|
||||
fund_call.push(10u8); // Balances pallet
|
||||
fund_call.push(8u8); // force_set_balance
|
||||
fund_call.push(0u8); // MultiAddress::Id variant
|
||||
fund_call.extend_from_slice(&account_bytes);
|
||||
// Compact<u128> for 100_000_000_000_000_000_000 (100 HEZ)
|
||||
// For compact: values > 2^30 use BigInt mode: (byte_len - 4) << 2 | 0b11, then LE bytes
|
||||
let amount: u128 = 100_000_000_000_000_000_000u128; // 100 HEZ
|
||||
let amount_bytes = amount.to_le_bytes();
|
||||
// Trim trailing zeros for compact encoding
|
||||
let significant = amount_bytes.iter().rposition(|&b| b != 0).map(|i| i + 1).unwrap_or(1);
|
||||
let byte_len = significant.max(4); // minimum 4 bytes for BigInt mode
|
||||
fund_call.push(((byte_len as u8 - 4) << 2) | 0b11);
|
||||
fund_call.extend_from_slice(&amount_bytes[..byte_len]);
|
||||
// Check existing balance first
|
||||
let balance_key = {
|
||||
let mut key = Vec::new();
|
||||
key.extend_from_slice(&pezsp_crypto_hashing::twox_128(b"System"));
|
||||
key.extend_from_slice(&pezsp_crypto_hashing::twox_128(b"Account"));
|
||||
let hash = pezsp_crypto_hashing::blake2_128(&account_bytes);
|
||||
key.extend_from_slice(&hash);
|
||||
key.extend_from_slice(&account_bytes);
|
||||
key
|
||||
};
|
||||
let ah_storage = ah_api.storage().at_latest().await?;
|
||||
let has_balance = match ah_storage.fetch_raw(balance_key).await {
|
||||
Ok(data) => !data.is_empty(),
|
||||
Err(_) => false,
|
||||
};
|
||||
|
||||
println!(
|
||||
" Encoded force_set_balance ({} bytes): 0x{}",
|
||||
fund_call.len(),
|
||||
hex::encode(&fund_call)
|
||||
);
|
||||
|
||||
let fund_dest = Value::unnamed_variant(
|
||||
"V3",
|
||||
vec![Value::named_composite([
|
||||
("parents", Value::u128(0)),
|
||||
(
|
||||
"interior",
|
||||
Value::unnamed_variant(
|
||||
"X1",
|
||||
vec![Value::unnamed_variant("Teyrchain", vec![Value::u128(1000)])],
|
||||
),
|
||||
),
|
||||
])],
|
||||
);
|
||||
|
||||
let fund_msg = Value::unnamed_variant(
|
||||
"V3",
|
||||
vec![Value::unnamed_composite(vec![
|
||||
Value::named_variant(
|
||||
"UnpaidExecution",
|
||||
[
|
||||
("weight_limit", Value::unnamed_variant("Unlimited", vec![])),
|
||||
("check_origin", Value::unnamed_variant("None", vec![])),
|
||||
],
|
||||
),
|
||||
Value::named_variant(
|
||||
"Transact",
|
||||
[
|
||||
("origin_kind", Value::unnamed_variant("Superuser", vec![])),
|
||||
(
|
||||
"require_weight_at_most",
|
||||
Value::named_composite([
|
||||
("ref_time", Value::u128(5_000_000_000u128)),
|
||||
("proof_size", Value::u128(500_000u128)),
|
||||
]),
|
||||
),
|
||||
("call", Value::from_bytes(&fund_call)),
|
||||
],
|
||||
),
|
||||
])],
|
||||
);
|
||||
|
||||
let fund_xcm = pezkuwi_subxt::dynamic::tx("XcmPallet", "send", vec![fund_dest, fund_msg]);
|
||||
let fund_sudo = pezkuwi_subxt::dynamic::tx("Sudo", "sudo", vec![fund_xcm.into_value()]);
|
||||
|
||||
let progress = rc_api
|
||||
.tx()
|
||||
.sign_and_submit_then_watch_default(&fund_sudo, &sudo_keypair)
|
||||
.await?;
|
||||
let events = progress.wait_for_finalized_success().await?;
|
||||
let fund_sent = events
|
||||
.iter()
|
||||
.flatten()
|
||||
.any(|e| e.pallet_name() == "XcmPallet" && e.variant_name() == "Sent");
|
||||
if fund_sent {
|
||||
println!(" [OK] Force set balance XCM sent");
|
||||
if has_balance {
|
||||
println!(" Sudo account already has funds on AH — skipping funding");
|
||||
} else {
|
||||
println!(" [WARN] No XcmPallet::Sent event for funding");
|
||||
}
|
||||
println!(" Sudo account has no funds — funding via XCM...");
|
||||
|
||||
println!(" Waiting 12s for DMP processing...");
|
||||
tokio::time::sleep(std::time::Duration::from_secs(12)).await;
|
||||
// Encode Balances::force_set_balance(who, new_free)
|
||||
// Balances pallet = 10, call_index = 8 (verified from source)
|
||||
let mut fund_call: Vec<u8> = Vec::new();
|
||||
fund_call.push(10u8); // Balances pallet
|
||||
fund_call.push(8u8); // force_set_balance
|
||||
fund_call.push(0u8); // MultiAddress::Id variant
|
||||
fund_call.extend_from_slice(&account_bytes);
|
||||
// 10,000 HEZ = 10_000 * 10^12 (12 decimals, NOT 18)
|
||||
let amount: u128 = 10_000_000_000_000_000u128; // 10,000 HEZ
|
||||
let amount_bytes = amount.to_le_bytes();
|
||||
let significant = amount_bytes
|
||||
.iter()
|
||||
.rposition(|&b| b != 0)
|
||||
.map(|i| i + 1)
|
||||
.unwrap_or(1);
|
||||
let byte_len = significant.max(4);
|
||||
fund_call.push(((byte_len as u8 - 4) << 2) | 0b11);
|
||||
fund_call.extend_from_slice(&amount_bytes[..byte_len]);
|
||||
|
||||
let fund_dest = Value::unnamed_variant(
|
||||
"V3",
|
||||
vec![Value::named_composite([
|
||||
("parents", Value::u128(0)),
|
||||
(
|
||||
"interior",
|
||||
Value::unnamed_variant(
|
||||
"X1",
|
||||
vec![Value::unnamed_variant(
|
||||
"Teyrchain",
|
||||
vec![Value::u128(AH_PARA_ID)],
|
||||
)],
|
||||
),
|
||||
),
|
||||
])],
|
||||
);
|
||||
|
||||
let fund_msg = Value::unnamed_variant(
|
||||
"V3",
|
||||
vec![Value::unnamed_composite(vec![
|
||||
Value::named_variant(
|
||||
"UnpaidExecution",
|
||||
[
|
||||
("weight_limit", Value::unnamed_variant("Unlimited", vec![])),
|
||||
("check_origin", Value::unnamed_variant("None", vec![])),
|
||||
],
|
||||
),
|
||||
Value::named_variant(
|
||||
"Transact",
|
||||
[
|
||||
("origin_kind", Value::unnamed_variant("Superuser", vec![])),
|
||||
(
|
||||
"require_weight_at_most",
|
||||
Value::named_composite([
|
||||
("ref_time", Value::u128(5_000_000_000u128)),
|
||||
("proof_size", Value::u128(500_000u128)),
|
||||
]),
|
||||
),
|
||||
("call", Value::from_bytes(&fund_call)),
|
||||
],
|
||||
),
|
||||
])],
|
||||
);
|
||||
|
||||
let fund_xcm =
|
||||
pezkuwi_subxt::dynamic::tx("XcmPallet", "send", vec![fund_dest, fund_msg]);
|
||||
let fund_sudo =
|
||||
pezkuwi_subxt::dynamic::tx("Sudo", "sudo", vec![fund_xcm.into_value()]);
|
||||
|
||||
let progress = rc_api
|
||||
.tx()
|
||||
.sign_and_submit_then_watch_default(&fund_sudo, &sudo_keypair)
|
||||
.await?;
|
||||
let events = progress.wait_for_finalized_success().await?;
|
||||
let fund_sent = events
|
||||
.iter()
|
||||
.flatten()
|
||||
.any(|e| e.pallet_name() == "XcmPallet" && e.variant_name() == "Sent");
|
||||
if fund_sent {
|
||||
println!(" [OK] Force set balance XCM sent");
|
||||
} else {
|
||||
println!(" [WARN] No XcmPallet::Sent event for funding");
|
||||
}
|
||||
|
||||
println!(" Waiting 18s for DMP processing...");
|
||||
tokio::time::sleep(std::time::Duration::from_secs(18)).await;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// STEP 2: Enact upgrade on AH directly
|
||||
@@ -295,23 +363,40 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
if code_updated {
|
||||
println!("\n UPGRADE SUCCESS!");
|
||||
} else {
|
||||
println!("\n WARNING: No CodeUpdated event!");
|
||||
println!("\n ValidationFunctionStored — waiting for relay chain enactment...");
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// STEP 3: Verify
|
||||
// STEP 3: Verify (poll for spec change)
|
||||
// ═══════════════════════════════════════════
|
||||
println!("\nWaiting 6 seconds for new runtime...");
|
||||
tokio::time::sleep(std::time::Duration::from_secs(6)).await;
|
||||
println!("\nVerifying upgrade...");
|
||||
let mut verified = false;
|
||||
for attempt in 1..=10 {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(12)).await;
|
||||
let ah_api2 = OnlineClient::<PezkuwiConfig>::from_insecure_url(&ah_url).await?;
|
||||
let new_spec = ah_api2.runtime_version().spec_version;
|
||||
if new_spec > old_spec {
|
||||
println!(
|
||||
" AH spec_version: {} → {} — UPGRADE VERIFIED! (attempt {})",
|
||||
old_spec, new_spec, attempt
|
||||
);
|
||||
verified = true;
|
||||
break;
|
||||
}
|
||||
println!(
|
||||
" Attempt {}/10: spec still {} — waiting...",
|
||||
attempt, new_spec
|
||||
);
|
||||
}
|
||||
|
||||
let ah_api2 = OnlineClient::<PezkuwiConfig>::from_url(&ah_url).await?;
|
||||
println!(
|
||||
"AH spec_version: {} → {}",
|
||||
ah_api.runtime_version().spec_version,
|
||||
ah_api2.runtime_version().spec_version
|
||||
);
|
||||
if !verified {
|
||||
println!(" WARNING: spec_version did not increase after 2 minutes!");
|
||||
println!(" Check AH logs and relay chain for enactment status.");
|
||||
}
|
||||
|
||||
println!("\n=== DONE ===");
|
||||
println!("\n╔══════════════════════════════════════════╗");
|
||||
println!("║ ASSET HUB UPGRADE COMPLETE ║");
|
||||
println!("╚══════════════════════════════════════════╝");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,394 @@
|
||||
//! People Chain Runtime Upgrade (Mainnet)
|
||||
//!
|
||||
//! Two-step process:
|
||||
//! 1. RC → XCM → People: System.authorize_upgrade(blake2_256(wasm))
|
||||
//! 2. People direct: System.apply_authorized_upgrade(wasm)
|
||||
//!
|
||||
//! Run:
|
||||
//! SUDO_MNEMONIC="..." \
|
||||
//! RC_RPC="ws://217.77.6.126:9944" \
|
||||
//! PEOPLE_RPC="ws://217.77.6.126:41944" \
|
||||
//! WASM_FILE="target/release/wbuild/people-pezkuwichain-runtime/people_pezkuwichain_runtime.compact.compressed.wasm" \
|
||||
//! cargo run --release -p pezkuwi-subxt --example people_upgrade
|
||||
|
||||
#![allow(missing_docs)]
|
||||
use pezkuwi_subxt::dynamic::Value;
|
||||
use pezkuwi_subxt::{OnlineClient, PezkuwiConfig};
|
||||
use pezkuwi_subxt_signer::bip39::Mnemonic;
|
||||
use pezkuwi_subxt_signer::sr25519::Keypair;
|
||||
use std::str::FromStr;
|
||||
|
||||
const PEOPLE_PARA_ID: u128 = 1004;
|
||||
|
||||
fn load_sudo_keypair() -> Keypair {
|
||||
// 1. Try SUDO_MNEMONIC env var
|
||||
if let Ok(mnemonic_str) = std::env::var("SUDO_MNEMONIC") {
|
||||
if !mnemonic_str.is_empty() {
|
||||
if let Ok(mnemonic) = Mnemonic::from_str(&mnemonic_str) {
|
||||
if let Ok(kp) = Keypair::from_phrase(&mnemonic, None) {
|
||||
println!(" [sudo] Loaded from SUDO_MNEMONIC env var");
|
||||
return kp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fallback to seeds file
|
||||
let seeds_path = "/home/mamostehp/res/test_seeds.json";
|
||||
if let Ok(content) = std::fs::read_to_string(seeds_path) {
|
||||
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&content) {
|
||||
if let Some(mnemonic_str) = json["sudo_mnemonic"].as_str() {
|
||||
if let Ok(mnemonic) = Mnemonic::from_str(mnemonic_str) {
|
||||
if let Ok(kp) = Keypair::from_phrase(&mnemonic, None) {
|
||||
println!(" [sudo] Loaded from {}", seeds_path);
|
||||
return kp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
panic!("SUDO_MNEMONIC required! Set env var or create /home/mamostehp/res/test_seeds.json");
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("╔══════════════════════════════════════════╗");
|
||||
println!("║ PEOPLE CHAIN RUNTIME UPGRADE ║");
|
||||
println!("╚══════════════════════════════════════════╝\n");
|
||||
|
||||
let rc_url = std::env::var("RC_RPC").unwrap_or_else(|_| "ws://127.0.0.1:9944".to_string());
|
||||
let people_url =
|
||||
std::env::var("PEOPLE_RPC").unwrap_or_else(|_| "ws://127.0.0.1:41944".to_string());
|
||||
let wasm_path = std::env::var("WASM_FILE").expect("WASM_FILE environment variable required");
|
||||
|
||||
let sudo_keypair = load_sudo_keypair();
|
||||
println!(" Sudo: {}", sudo_keypair.public_key().to_account_id());
|
||||
|
||||
// Load WASM
|
||||
let wasm_data = std::fs::read(&wasm_path)?;
|
||||
println!(" WASM: {} ({:.2} MB)", wasm_path, wasm_data.len() as f64 / 1_048_576.0);
|
||||
|
||||
// Blake2-256 hash of WASM
|
||||
let code_hash = pezsp_crypto_hashing::blake2_256(&wasm_data);
|
||||
println!(" Code hash: 0x{}", hex::encode(code_hash));
|
||||
|
||||
// Connect to RC
|
||||
let rc_api = OnlineClient::<PezkuwiConfig>::from_insecure_url(&rc_url).await?;
|
||||
println!(
|
||||
" RC connected: {} (spec {})",
|
||||
rc_url,
|
||||
rc_api.runtime_version().spec_version
|
||||
);
|
||||
|
||||
// Connect to People Chain
|
||||
let people_api = OnlineClient::<PezkuwiConfig>::from_insecure_url(&people_url).await?;
|
||||
let old_spec = people_api.runtime_version().spec_version;
|
||||
println!(" People connected: {} (spec {})\n", people_url, old_spec);
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// STEP 1: Authorize upgrade via XCM from RC
|
||||
// ═══════════════════════════════════════════
|
||||
println!("=== STEP 1: Authorize upgrade (RC → XCM → People) ===");
|
||||
|
||||
// Encode System::authorize_upgrade_without_checks(code_hash)
|
||||
// System pallet index = 0, call_index = 10
|
||||
let mut encoded_call = Vec::with_capacity(34);
|
||||
encoded_call.push(0x00); // System pallet
|
||||
encoded_call.push(0x0a); // authorize_upgrade_without_checks (10)
|
||||
encoded_call.extend_from_slice(&code_hash);
|
||||
println!(" Encoded call: {} bytes", encoded_call.len());
|
||||
|
||||
let dest = Value::unnamed_variant(
|
||||
"V3",
|
||||
vec![Value::named_composite([
|
||||
("parents", Value::u128(0)),
|
||||
(
|
||||
"interior",
|
||||
Value::unnamed_variant(
|
||||
"X1",
|
||||
vec![Value::unnamed_variant(
|
||||
"Teyrchain",
|
||||
vec![Value::u128(PEOPLE_PARA_ID)],
|
||||
)],
|
||||
),
|
||||
),
|
||||
])],
|
||||
);
|
||||
|
||||
let message = Value::unnamed_variant(
|
||||
"V3",
|
||||
vec![Value::unnamed_composite(vec![
|
||||
Value::named_variant(
|
||||
"UnpaidExecution",
|
||||
[
|
||||
("weight_limit", Value::unnamed_variant("Unlimited", vec![])),
|
||||
("check_origin", Value::unnamed_variant("None", vec![])),
|
||||
],
|
||||
),
|
||||
Value::named_variant(
|
||||
"Transact",
|
||||
[
|
||||
("origin_kind", Value::unnamed_variant("Superuser", vec![])),
|
||||
(
|
||||
"require_weight_at_most",
|
||||
Value::named_composite([
|
||||
("ref_time", Value::u128(5_000_000_000u128)),
|
||||
("proof_size", Value::u128(500_000u128)),
|
||||
]),
|
||||
),
|
||||
("call", Value::from_bytes(&encoded_call)),
|
||||
],
|
||||
),
|
||||
])],
|
||||
);
|
||||
|
||||
let xcm_send = pezkuwi_subxt::dynamic::tx("XcmPallet", "send", vec![dest, message]);
|
||||
let sudo_tx = pezkuwi_subxt::dynamic::tx(
|
||||
"Sudo",
|
||||
"sudo_unchecked_weight",
|
||||
vec![
|
||||
xcm_send.into_value(),
|
||||
Value::named_composite([
|
||||
("ref_time", Value::u128(1u128)),
|
||||
("proof_size", Value::u128(1u128)),
|
||||
]),
|
||||
],
|
||||
);
|
||||
|
||||
let progress = rc_api
|
||||
.tx()
|
||||
.sign_and_submit_then_watch_default(&sudo_tx, &sudo_keypair)
|
||||
.await?;
|
||||
let events = progress.wait_for_finalized_success().await?;
|
||||
|
||||
let mut sent = false;
|
||||
for event in events.iter() {
|
||||
let event = event?;
|
||||
if event.pallet_name() == "XcmPallet" && event.variant_name() == "Sent" {
|
||||
sent = true;
|
||||
}
|
||||
if event.pallet_name() == "Sudo" || event.pallet_name() == "XcmPallet" {
|
||||
println!(" {}::{}", event.pallet_name(), event.variant_name());
|
||||
}
|
||||
}
|
||||
if !sent {
|
||||
println!(" ERROR: No XcmPallet::Sent event! Aborting.");
|
||||
return Ok(());
|
||||
}
|
||||
println!(" XCM authorize_upgrade sent!\n");
|
||||
|
||||
// Wait for People Chain to process the XCM — poll AuthorizedUpgrade storage
|
||||
println!("Waiting for People Chain to process XCM authorize_upgrade...");
|
||||
let mut authorized = false;
|
||||
for attempt in 1..=30 {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(6)).await;
|
||||
|
||||
let people_check = OnlineClient::<PezkuwiConfig>::from_insecure_url(&people_url).await?;
|
||||
let block = people_check.blocks().at_latest().await?;
|
||||
let block_num = block.number();
|
||||
|
||||
// Check System::AuthorizedUpgrade storage via raw key
|
||||
let auth_key = pezsp_crypto_hashing::twox_128(b"System")
|
||||
.iter()
|
||||
.chain(pezsp_crypto_hashing::twox_128(b"AuthorizedUpgrade").iter())
|
||||
.copied()
|
||||
.collect::<Vec<u8>>();
|
||||
let result = people_check.storage().at_latest().await?.fetch_raw(auth_key).await;
|
||||
match result {
|
||||
Ok(data) if !data.is_empty() => {
|
||||
println!(
|
||||
" AuthorizedUpgrade found on People at block {} (attempt {})!",
|
||||
block_num, attempt
|
||||
);
|
||||
authorized = true;
|
||||
break;
|
||||
},
|
||||
_ => {}, // NoValueFound or empty — not yet set, continue polling
|
||||
}
|
||||
println!(
|
||||
" Attempt {}/30: People block {} — AuthorizedUpgrade not yet set...",
|
||||
attempt, block_num
|
||||
);
|
||||
}
|
||||
|
||||
if !authorized {
|
||||
println!(" ERROR: AuthorizedUpgrade not set after 3 minutes. Aborting.");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// STEP 1.5: Fund sudo account on People via XCM (if needed)
|
||||
// ═══════════════════════════════════════════
|
||||
println!("\n=== STEP 1.5: Fund sudo account on People Chain ===");
|
||||
let sudo_account_id = sudo_keypair.public_key().to_account_id();
|
||||
let account_bytes: [u8; 32] = *sudo_account_id.as_ref();
|
||||
|
||||
// Check existing balance first
|
||||
let balance_key = {
|
||||
let mut key = Vec::new();
|
||||
key.extend_from_slice(&pezsp_crypto_hashing::twox_128(b"System"));
|
||||
key.extend_from_slice(&pezsp_crypto_hashing::twox_128(b"Account"));
|
||||
// Blake2_128Concat hasher for account
|
||||
let hash = pezsp_crypto_hashing::blake2_128(&account_bytes);
|
||||
key.extend_from_slice(&hash);
|
||||
key.extend_from_slice(&account_bytes);
|
||||
key
|
||||
};
|
||||
let people_storage = people_api.storage().at_latest().await?;
|
||||
let has_balance = match people_storage.fetch_raw(balance_key).await {
|
||||
Ok(data) => !data.is_empty(),
|
||||
Err(_) => false, // NoValueFound — account doesn't exist
|
||||
};
|
||||
|
||||
if has_balance {
|
||||
println!(" Sudo account already has funds on People Chain — skipping funding");
|
||||
} else {
|
||||
println!(" Sudo account has no funds — funding via XCM...");
|
||||
|
||||
// Encode Balances::force_set_balance(who, new_free)
|
||||
// Balances pallet = 10, call_index = 8
|
||||
let mut fund_call: Vec<u8> = Vec::new();
|
||||
fund_call.push(10u8); // Balances pallet
|
||||
fund_call.push(8u8); // force_set_balance
|
||||
fund_call.push(0u8); // MultiAddress::Id variant
|
||||
fund_call.extend_from_slice(&account_bytes);
|
||||
// 10,000 HEZ = 10_000 * 10^12 (12 decimals, NOT 18)
|
||||
// Generous amount to cover apply_authorized_upgrade fee (1.5MB extrinsic)
|
||||
let amount: u128 = 10_000_000_000_000_000u128; // 10,000 HEZ
|
||||
let amount_bytes = amount.to_le_bytes();
|
||||
let significant = amount_bytes
|
||||
.iter()
|
||||
.rposition(|&b| b != 0)
|
||||
.map(|i| i + 1)
|
||||
.unwrap_or(1);
|
||||
let byte_len = significant.max(4);
|
||||
fund_call.push(((byte_len as u8 - 4) << 2) | 0b11);
|
||||
fund_call.extend_from_slice(&amount_bytes[..byte_len]);
|
||||
|
||||
let fund_dest = Value::unnamed_variant(
|
||||
"V3",
|
||||
vec![Value::named_composite([
|
||||
("parents", Value::u128(0)),
|
||||
(
|
||||
"interior",
|
||||
Value::unnamed_variant(
|
||||
"X1",
|
||||
vec![Value::unnamed_variant(
|
||||
"Teyrchain",
|
||||
vec![Value::u128(PEOPLE_PARA_ID)],
|
||||
)],
|
||||
),
|
||||
),
|
||||
])],
|
||||
);
|
||||
|
||||
let fund_msg = Value::unnamed_variant(
|
||||
"V3",
|
||||
vec![Value::unnamed_composite(vec![
|
||||
Value::named_variant(
|
||||
"UnpaidExecution",
|
||||
[
|
||||
("weight_limit", Value::unnamed_variant("Unlimited", vec![])),
|
||||
("check_origin", Value::unnamed_variant("None", vec![])),
|
||||
],
|
||||
),
|
||||
Value::named_variant(
|
||||
"Transact",
|
||||
[
|
||||
("origin_kind", Value::unnamed_variant("Superuser", vec![])),
|
||||
(
|
||||
"require_weight_at_most",
|
||||
Value::named_composite([
|
||||
("ref_time", Value::u128(5_000_000_000u128)),
|
||||
("proof_size", Value::u128(500_000u128)),
|
||||
]),
|
||||
),
|
||||
("call", Value::from_bytes(&fund_call)),
|
||||
],
|
||||
),
|
||||
])],
|
||||
);
|
||||
|
||||
let fund_xcm =
|
||||
pezkuwi_subxt::dynamic::tx("XcmPallet", "send", vec![fund_dest, fund_msg]);
|
||||
let fund_sudo =
|
||||
pezkuwi_subxt::dynamic::tx("Sudo", "sudo", vec![fund_xcm.into_value()]);
|
||||
|
||||
let progress = rc_api
|
||||
.tx()
|
||||
.sign_and_submit_then_watch_default(&fund_sudo, &sudo_keypair)
|
||||
.await?;
|
||||
let events = progress.wait_for_finalized_success().await?;
|
||||
let fund_sent = events
|
||||
.iter()
|
||||
.flatten()
|
||||
.any(|e| e.pallet_name() == "XcmPallet" && e.variant_name() == "Sent");
|
||||
if fund_sent {
|
||||
println!(" [OK] Force set balance XCM sent");
|
||||
} else {
|
||||
println!(" [WARN] No XcmPallet::Sent event for funding");
|
||||
}
|
||||
|
||||
println!(" Waiting 18s for DMP processing...");
|
||||
tokio::time::sleep(std::time::Duration::from_secs(18)).await;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// STEP 2: Enact upgrade on People directly
|
||||
// ═══════════════════════════════════════════
|
||||
println!("\n=== STEP 2: Apply authorized upgrade on People Chain ===");
|
||||
println!(" Submitting {} bytes WASM...", wasm_data.len());
|
||||
|
||||
let enact_call = pezkuwi_subxt::dynamic::tx(
|
||||
"System",
|
||||
"apply_authorized_upgrade",
|
||||
vec![Value::from_bytes(&wasm_data)],
|
||||
);
|
||||
|
||||
let progress = people_api
|
||||
.tx()
|
||||
.sign_and_submit_then_watch_default(&enact_call, &sudo_keypair)
|
||||
.await?;
|
||||
let events = progress.wait_for_finalized_success().await?;
|
||||
|
||||
let mut code_updated = false;
|
||||
for event in events.iter() {
|
||||
let event = event?;
|
||||
println!(" {}::{}", event.pallet_name(), event.variant_name());
|
||||
if event.pallet_name() == "System" && event.variant_name() == "CodeUpdated" {
|
||||
code_updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if code_updated {
|
||||
println!("\n UPGRADE SUCCESS!");
|
||||
} else {
|
||||
println!("\n WARNING: No CodeUpdated event!");
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// STEP 3: Verify
|
||||
// ═══════════════════════════════════════════
|
||||
println!("\nWaiting 12 seconds for new runtime...");
|
||||
tokio::time::sleep(std::time::Duration::from_secs(12)).await;
|
||||
|
||||
let people_api2 = OnlineClient::<PezkuwiConfig>::from_insecure_url(&people_url).await?;
|
||||
let new_spec = people_api2.runtime_version().spec_version;
|
||||
println!(
|
||||
"\n People Chain spec_version: {} → {}",
|
||||
old_spec, new_spec
|
||||
);
|
||||
|
||||
if new_spec > old_spec {
|
||||
println!(" UPGRADE VERIFIED!");
|
||||
} else {
|
||||
println!(" WARNING: spec_version did not increase!");
|
||||
}
|
||||
|
||||
println!("\n╔══════════════════════════════════════════╗");
|
||||
println!("║ PEOPLE CHAIN UPGRADE COMPLETE ║");
|
||||
println!("╚══════════════════════════════════════════╝");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
+70
-29
@@ -1,15 +1,11 @@
|
||||
//! Relay Chain Runtime Upgrade
|
||||
//! Relay Chain Runtime Upgrade (Mainnet)
|
||||
//!
|
||||
//! Deploys new WASM via sudo(sudoUncheckedWeight(system.setCodeWithoutChecks)).
|
||||
//! Does NOTHING else — no storage changes, no validator count, no ForceEra.
|
||||
//!
|
||||
//! Run:
|
||||
//! SUDO_MNEMONIC="..." \
|
||||
//! RC_RPC="ws://217.77.6.126:9944" \
|
||||
//! WASM_FILE="target/release/wbuild/pezkuwichain-runtime/pezkuwichain_runtime.compact.compressed.wasm" \
|
||||
//! cargo run --release -p pezkuwi-subxt --example rc_upgrade
|
||||
//!
|
||||
//! Optional:
|
||||
//! RC_RPC="ws://127.0.0.1:9944" (default: ws://127.0.0.1:9944)
|
||||
|
||||
#![allow(missing_docs)]
|
||||
use pezkuwi_subxt::dynamic::Value;
|
||||
@@ -19,33 +15,65 @@ use pezkuwi_subxt_signer::bip39::Mnemonic;
|
||||
use pezkuwi_subxt_signer::sr25519::Keypair;
|
||||
use std::str::FromStr;
|
||||
|
||||
fn load_sudo_keypair() -> Keypair {
|
||||
if let Ok(mnemonic_str) = std::env::var("SUDO_MNEMONIC") {
|
||||
if !mnemonic_str.is_empty() {
|
||||
if let Ok(mnemonic) = Mnemonic::from_str(&mnemonic_str) {
|
||||
if let Ok(kp) = Keypair::from_phrase(&mnemonic, None) {
|
||||
println!(" [sudo] Loaded from SUDO_MNEMONIC env var");
|
||||
return kp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let seeds_path = "/home/mamostehp/res/test_seeds.json";
|
||||
if let Ok(content) = std::fs::read_to_string(seeds_path) {
|
||||
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&content) {
|
||||
if let Some(mnemonic_str) = json["sudo_mnemonic"].as_str() {
|
||||
if let Ok(mnemonic) = Mnemonic::from_str(mnemonic_str) {
|
||||
if let Ok(kp) = Keypair::from_phrase(&mnemonic, None) {
|
||||
println!(" [sudo] Loaded from {}", seeds_path);
|
||||
return kp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
panic!("SUDO_MNEMONIC required! Set env var or create /home/mamostehp/res/test_seeds.json");
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("=== RELAY CHAIN RUNTIME UPGRADE ===\n");
|
||||
println!("╔══════════════════════════════════════════╗");
|
||||
println!("║ RELAY CHAIN RUNTIME UPGRADE ║");
|
||||
println!("╚══════════════════════════════════════════╝\n");
|
||||
|
||||
let rc_url = std::env::var("RC_RPC").unwrap_or_else(|_| "ws://127.0.0.1:9944".to_string());
|
||||
let wasm_path = std::env::var("WASM_FILE").expect("WASM_FILE environment variable required");
|
||||
|
||||
// Load WASM
|
||||
let wasm_data = std::fs::read(&wasm_path)?;
|
||||
println!("WASM: {} ({:.2} MB)", wasm_path, wasm_data.len() as f64 / 1_048_576.0);
|
||||
println!(
|
||||
" WASM: {} ({:.2} MB)",
|
||||
wasm_path,
|
||||
wasm_data.len() as f64 / 1_048_576.0
|
||||
);
|
||||
let code_hash = pezsp_crypto_hashing::blake2_256(&wasm_data);
|
||||
println!("Code hash: 0x{}", hex::encode(code_hash));
|
||||
println!(" Code hash: 0x{}", hex::encode(code_hash));
|
||||
|
||||
// Connect
|
||||
let api = OnlineClient::<PezkuwiConfig>::from_url(&rc_url).await?;
|
||||
let api = OnlineClient::<PezkuwiConfig>::from_insecure_url(&rc_url).await?;
|
||||
let old_spec = api.runtime_version().spec_version;
|
||||
println!("RC connected: {} (spec {})", rc_url, old_spec);
|
||||
println!(" RC connected: {} (spec {})", rc_url, old_spec);
|
||||
|
||||
// Load sudo key
|
||||
let mnemonic_str =
|
||||
std::env::var("SUDO_MNEMONIC").expect("SUDO_MNEMONIC environment variable required");
|
||||
let mnemonic = Mnemonic::from_str(&mnemonic_str)?;
|
||||
let sudo_keypair = Keypair::from_phrase(&mnemonic, None)?;
|
||||
println!("Sudo: {}\n", sudo_keypair.public_key().to_account_id());
|
||||
let sudo_keypair = load_sudo_keypair();
|
||||
println!(" Sudo: {}\n", sudo_keypair.public_key().to_account_id());
|
||||
|
||||
// Deploy WASM via sudo(sudoUncheckedWeight(system.setCodeWithoutChecks))
|
||||
println!("Deploying WASM...");
|
||||
println!("=== Deploying WASM... ===");
|
||||
let set_code = pezkuwi_subxt::dynamic::tx(
|
||||
"System",
|
||||
"set_code_without_checks",
|
||||
@@ -63,7 +91,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
],
|
||||
);
|
||||
|
||||
let tx_progress = api.tx().sign_and_submit_then_watch_default(&sudo_tx, &sudo_keypair).await?;
|
||||
let tx_progress =
|
||||
api.tx().sign_and_submit_then_watch_default(&sudo_tx, &sudo_keypair).await?;
|
||||
println!(" TX: 0x{}", hex::encode(tx_progress.extrinsic_hash().as_ref()));
|
||||
|
||||
let mut progress = tx_progress;
|
||||
@@ -115,18 +144,30 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
|
||||
// Verify
|
||||
println!("\nWaiting 12 seconds for new runtime...");
|
||||
tokio::time::sleep(std::time::Duration::from_secs(12)).await;
|
||||
|
||||
let api2 = OnlineClient::<PezkuwiConfig>::from_url(&rc_url).await?;
|
||||
let new_spec = api2.runtime_version().spec_version;
|
||||
println!("spec_version: {} → {}", old_spec, new_spec);
|
||||
|
||||
if new_spec > old_spec {
|
||||
println!("\n=== UPGRADE SUCCESS ===");
|
||||
} else {
|
||||
println!("\n=== WARNING: spec_version did not increase ===");
|
||||
println!("\nVerifying upgrade...");
|
||||
let mut verified = false;
|
||||
for attempt in 1..=5 {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(12)).await;
|
||||
let api2 = OnlineClient::<PezkuwiConfig>::from_insecure_url(&rc_url).await?;
|
||||
let new_spec = api2.runtime_version().spec_version;
|
||||
if new_spec > old_spec {
|
||||
println!(
|
||||
" spec_version: {} → {} — UPGRADE VERIFIED! (attempt {})",
|
||||
old_spec, new_spec, attempt
|
||||
);
|
||||
verified = true;
|
||||
break;
|
||||
}
|
||||
println!(" Attempt {}/5: spec still {} — waiting...", attempt, new_spec);
|
||||
}
|
||||
|
||||
if !verified {
|
||||
println!(" WARNING: spec_version did not increase after 1 minute!");
|
||||
}
|
||||
|
||||
println!("\n╔══════════════════════════════════════════╗");
|
||||
println!("║ RELAY CHAIN UPGRADE COMPLETE ║");
|
||||
println!("╚══════════════════════════════════════════╝");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+29
-5
@@ -10,18 +10,42 @@ use pezkuwi_subxt_signer::bip39::Mnemonic;
|
||||
use pezkuwi_subxt_signer::sr25519::Keypair;
|
||||
use std::str::FromStr;
|
||||
|
||||
fn load_sudo_keypair() -> Keypair {
|
||||
if let Ok(mnemonic_str) = std::env::var("SUDO_MNEMONIC") {
|
||||
if !mnemonic_str.is_empty() {
|
||||
if let Ok(mnemonic) = Mnemonic::from_str(&mnemonic_str) {
|
||||
if let Ok(kp) = Keypair::from_phrase(&mnemonic, None) {
|
||||
println!(" [sudo] Loaded from SUDO_MNEMONIC env var");
|
||||
return kp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let seeds_path = "/home/mamostehp/res/test_seeds.json";
|
||||
if let Ok(content) = std::fs::read_to_string(seeds_path) {
|
||||
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&content) {
|
||||
if let Some(mnemonic_str) = json["sudo_mnemonic"].as_str() {
|
||||
if let Ok(mnemonic) = Mnemonic::from_str(mnemonic_str) {
|
||||
if let Ok(kp) = Keypair::from_phrase(&mnemonic, None) {
|
||||
println!(" [sudo] Loaded from {}", seeds_path);
|
||||
return kp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
panic!("SUDO_MNEMONIC required!");
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("=== SET StakingAhClient MODE → Active ===\n");
|
||||
|
||||
let rc_url = std::env::var("RC_RPC").unwrap_or_else(|_| "ws://127.0.0.1:9944".to_string());
|
||||
let api = OnlineClient::<PezkuwiConfig>::from_url(&rc_url).await?;
|
||||
let api = OnlineClient::<PezkuwiConfig>::from_insecure_url(&rc_url).await?;
|
||||
println!("RC connected: spec {}", api.runtime_version().spec_version);
|
||||
|
||||
let mnemonic_str =
|
||||
std::env::var("SUDO_MNEMONIC").expect("SUDO_MNEMONIC environment variable required");
|
||||
let mnemonic = Mnemonic::from_str(&mnemonic_str)?;
|
||||
let sudo_keypair = Keypair::from_phrase(&mnemonic, None)?;
|
||||
let sudo_keypair = load_sudo_keypair();
|
||||
println!("Sudo: {}\n", sudo_keypair.public_key().to_account_id());
|
||||
|
||||
// Check current mode first
|
||||
|
||||
Reference in New Issue
Block a user