diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index d645a501..425d5366 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -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 diff --git a/Cargo.lock b/Cargo.lock index b9bd495e..dbe11239 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/pezkuwi/runtime/pezkuwichain/Cargo.toml b/pezkuwi/runtime/pezkuwichain/Cargo.toml index 095cdbb0..5616c8a4 100644 --- a/pezkuwi/runtime/pezkuwichain/Cargo.toml +++ b/pezkuwi/runtime/pezkuwichain/Cargo.toml @@ -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", diff --git a/pezkuwi/runtime/pezkuwichain/src/genesis_config_presets.rs b/pezkuwi/runtime/pezkuwichain/src/genesis_config_presets.rs index c4bf5f22..303aff0c 100644 --- a/pezkuwi/runtime/pezkuwichain/src/genesis_config_presets.rs +++ b/pezkuwi/runtime/pezkuwichain/src/genesis_config_presets.rs @@ -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::>(), }, - 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::::Validator)) - .collect::>(), - invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect::>(), - 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::>(), }, - 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::::Validator)) - .collect::>(), - invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect::>(), - 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() }, diff --git a/pezkuwi/runtime/pezkuwichain/src/lib.rs b/pezkuwi/runtime/pezkuwichain/src/lib.rs index 076da216..83619325 100644 --- a/pezkuwi/runtime/pezkuwichain/src/lib.rs +++ b/pezkuwi/runtime/pezkuwichain/src/lib.rs @@ -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>> for ExposureOfOrDefault { - fn convert(validator: AccountId) -> Option> { - Some( - >::convert(validator).unwrap_or_default(), - ) + fn convert(_validator: AccountId) -> Option> { + 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 for NoopFallback { + fn new_session(_: SessionIndex) -> Option> { + None + } + fn start_session(_: SessionIndex) {} + fn end_session(_: SessionIndex) {} +} + +impl pezsp_staking::offence::OnOffenceHandler< + AccountId, + (AccountId, pezsp_staking::Exposure), + Weight, +> for NoopFallback +{ + fn on_offence( + _offenders: &[pezsp_staking::offence::OffenceDetails< + AccountId, + (AccountId, pezsp_staking::Exposure), + >], + _slash_fraction: &[Perbill], + _session: SessionIndex, + ) -> Weight { + Weight::zero() + } +} + +impl pezframe_support::traits::RewardsReporter for NoopFallback { + fn reward_by_ids(_: impl IntoIterator) {} +} + +impl pezpallet_authorship::EventHandler for NoopFallback { + fn note_author(_: AccountId) {} +} + impl pezpallet_session::historical::Config for Runtime { type RuntimeEvent = RuntimeEvent; type FullIdentification = pezsp_staking::Exposure; @@ -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; - type System = Runtime; - type Solver = pezframe_election_provider_support::SequentialPhragmen; - type DataProvider = Staking; - type WeightInfo = pezframe_election_provider_support::weights::BizinikiwiWeight; - type MaxBackersPerWinner = MaxElectingVoters; - type MaxWinnersPerPage = MaxWinners; - type Bounds = ElectionBounds; -} - -/// Era payout calculation for staking rewards. -pub struct EraPayout; -impl pezpallet_staking::EraPayout 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; - type GenesisElectionProvider = - pezframe_election_provider_support::onchain::OnChainExecution; - type VoterList = VoterBagsList; - type TargetList = pezpallet_staking::UseValidatorsMap; - type MaxControllersInDeprecationBatch = ConstU32<5_900>; - type AdminOrigin = EnsureRoot; - type EventListeners = (); - type WeightInfo = pezpallet_staking::weights::BizinikiwiWeight; - 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; - type Staking = Staking; - type MaxErasToCheckPerBlock = ConstU32<1>; - type WeightInfo = pezpallet_fast_unstake::weights::BizinikiwiWeight; -} // ===================================================== // 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 for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pezpallet_bags_list::weights::BizinikiwiWeight; - 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; - 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:: = 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:: = 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::::force_unreserve(); pub BalanceTransferAllowDeath: Weight = weights::pezpallet_balances_balances::WeightInfo::::transfer_allow_death(); @@ -1874,6 +1770,19 @@ pub mod migrations { teyrchains_inclusion::migration::MigrateToV1, teyrchains_shared::migration::MigrateToV1, teyrchains_scheduler::migration::MigrateV2ToV3, + // Remove old staking ecosystem pallets (replaced by StakingAhClient + AH staking) + pezframe_support::migrations::RemovePallet< + StakingPalletName, + ::DbWeight, + >, + pezframe_support::migrations::RemovePallet< + FastUnstakePalletName, + ::DbWeight, + >, + pezframe_support::migrations::RemovePallet< + VoterBagsListPalletName, + ::DbWeight, + >, ); } diff --git a/vendor/pezkuwi-subxt/subxt/examples/ah_upgrade.rs b/vendor/pezkuwi-subxt/subxt/examples/ah_upgrade.rs index 96911528..b9bfce2a 100644 --- a/vendor/pezkuwi-subxt/subxt/examples/ah_upgrade.rs +++ b/vendor/pezkuwi-subxt/subxt/examples/ah_upgrade.rs @@ -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::(&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> { - 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::::from_url(&rc_url).await?; - println!("RC connected: {} (spec {})", rc_url, rc_api.runtime_version().spec_version); + let rc_api = OnlineClient::::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::::from_url(&ah_url).await?; - println!("AH connected: {} (spec {})\n", ah_url, ah_api.runtime_version().spec_version); + let ah_api = OnlineClient::::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> { 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> { "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> { ], ); - 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> { } } 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> { for attempt in 1..=30 { tokio::time::sleep(std::time::Duration::from_secs(6)).await; - // Reconnect to get fresh state - let ah_check = OnlineClient::::from_url(&ah_url).await?; + let ah_check = OnlineClient::::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::>(); - 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> { } // ═══════════════════════════════════════════ - // 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 = 100 HEZ = 100 * 10^18 - let mut fund_call: Vec = 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 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 = 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> { 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::::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::::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(()) } diff --git a/vendor/pezkuwi-subxt/subxt/examples/people_upgrade.rs b/vendor/pezkuwi-subxt/subxt/examples/people_upgrade.rs new file mode 100644 index 00000000..9bd3d268 --- /dev/null +++ b/vendor/pezkuwi-subxt/subxt/examples/people_upgrade.rs @@ -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::(&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> { + 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::::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::::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::::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::>(); + 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 = 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::::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(()) +} diff --git a/vendor/pezkuwi-subxt/subxt/examples/rc_upgrade.rs b/vendor/pezkuwi-subxt/subxt/examples/rc_upgrade.rs index dad09359..5b796627 100644 --- a/vendor/pezkuwi-subxt/subxt/examples/rc_upgrade.rs +++ b/vendor/pezkuwi-subxt/subxt/examples/rc_upgrade.rs @@ -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::(&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> { - 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::::from_url(&rc_url).await?; + let api = OnlineClient::::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> { ], ); - 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> { } // Verify - println!("\nWaiting 12 seconds for new runtime..."); - tokio::time::sleep(std::time::Duration::from_secs(12)).await; - - let api2 = OnlineClient::::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::::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(()) } diff --git a/vendor/pezkuwi-subxt/subxt/examples/set_ah_client_active.rs b/vendor/pezkuwi-subxt/subxt/examples/set_ah_client_active.rs index 95a908ea..8030a12a 100644 --- a/vendor/pezkuwi-subxt/subxt/examples/set_ah_client_active.rs +++ b/vendor/pezkuwi-subxt/subxt/examples/set_ah_client_active.rs @@ -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::(&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> { 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::::from_url(&rc_url).await?; + let api = OnlineClient::::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