Files
pezkuwi-sdk/vendor/pezkuwi-subxt/subxt/examples/zagros_upgrade.rs
T
pezkuwichain 0e809c3a74 sec: remove hardcoded mnemonics, add mainnet tools and subxt examples
- Replace all hardcoded wallet mnemonics with env variable reads
- Add comprehensive e2e test suite (tools/e2e-test/)
- Add zagros validator management tools
- Add subxt examples for mainnet operations
- Update CRITICAL_STATE with zagros testnet and mainnet status
- Fix people chain spec ID and chainspec build script
2026-02-16 08:18:26 +03:00

294 lines
8.4 KiB
Rust

//! Zagros Testnet: Runtime upgrade + ValidatorCount fix
//!
//! Step 1: Deploy new WASM via sudo(sudoUncheckedWeight(system.setCodeWithoutChecks))
//! Step 2: Set ValidatorCount=2 and ForceEra=ForceNew via sudo(system.setStorage)
//!
//! Run with:
//! SUDO_MNEMONIC="******" \
//! WASM_FILE="/home/mamostehp/pezkuwi-sdk/target/release/wbuild/pezkuwichain-runtime/pezkuwichain_runtime.compact.compressed.wasm" \
//! RPC_URL="ws://217.77.6.126:9948" \
//! cargo run --release --example zagros_upgrade -p pezkuwi-subxt
#![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;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== ZAGROS RUNTIME UPGRADE + VALIDATOR FIX ===\n");
let url = std::env::var("RPC_URL").unwrap_or_else(|_| "ws://217.77.6.126:9948".to_string());
let wasm_path = std::env::var("WASM_FILE").expect("WASM_FILE environment variable required");
let new_validator_count: u32 = std::env::var("VALIDATOR_COUNT")
.unwrap_or_else(|_| "2".to_string())
.parse()?;
println!("RPC: {}", url);
println!("WASM: {}", wasm_path);
println!("Target validator count: {}", new_validator_count);
// Load WASM
let wasm_data = std::fs::read(&wasm_path)?;
println!("WASM size: {} bytes ({:.2} MB)", wasm_data.len(), wasm_data.len() as f64 / 1_048_576.0);
// Connect
let api = OnlineClient::<PezkuwiConfig>::from_insecure_url(&url).await?;
let rv = api.runtime_version();
println!("Current on-chain specVersion: {}", rv.spec_version);
// 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 account: {}\n", sudo_keypair.public_key().to_account_id());
// ==========================================
// STEP 1: Runtime upgrade (deploy WASM)
// ==========================================
println!("=== STEP 1: RUNTIME UPGRADE ===");
println!("Deploying WASM via sudo(sudoUncheckedWeight(system.setCodeWithoutChecks))...");
let set_code = pezkuwi_subxt::dynamic::tx(
"System",
"set_code_without_checks",
vec![Value::from_bytes(&wasm_data)],
);
let sudo_upgrade = pezkuwi_subxt::dynamic::tx("Sudo", "sudo_unchecked_weight", vec![
set_code.into_value(),
Value::named_composite([
("ref_time", Value::u128(1u128)),
("proof_size", Value::u128(1u128)),
]),
]);
use pezkuwi_subxt::tx::TxStatus;
let tx_progress = api
.tx()
.sign_and_submit_then_watch_default(&sudo_upgrade, &sudo_keypair)
.await?;
println!(
" TX submitted: 0x{}",
hex::encode(tx_progress.extrinsic_hash().as_ref())
);
let mut progress = tx_progress;
let mut upgrade_ok = false;
loop {
let status = progress.next().await;
match status {
Some(Ok(TxStatus::InBestBlock(details))) => {
match details.wait_for_success().await {
Ok(events) => {
println!(" In best block! Events:");
for event in events.iter() {
if let Ok(ev) = event {
println!(" {}::{}", ev.pallet_name(), ev.variant_name());
if ev.pallet_name() == "System"
&& ev.variant_name() == "CodeUpdated"
{
upgrade_ok = true;
}
}
}
},
Err(e) => println!(" DISPATCH ERROR: {}", e),
}
break;
},
Some(Ok(TxStatus::Error { message })) => {
println!(" TX ERROR: {}", message);
break;
},
Some(Ok(TxStatus::Invalid { message })) => {
println!(" TX INVALID: {}", message);
break;
},
Some(Ok(TxStatus::Dropped { message })) => {
println!(" TX DROPPED: {}", message);
break;
},
Some(Err(e)) => {
println!(" STREAM ERROR: {}", e);
break;
},
None => {
println!(" STREAM ENDED");
break;
},
_ => {},
}
}
if !upgrade_ok {
println!("\n UPGRADE FAILED! Aborting.");
return Ok(());
}
println!(" UPGRADE SUCCESS!\n");
// Wait for next block to ensure new runtime is active
println!("Waiting 12 seconds for new runtime to activate...");
tokio::time::sleep(std::time::Duration::from_secs(12)).await;
// Reconnect with new runtime
let api2 = OnlineClient::<PezkuwiConfig>::from_insecure_url(&url).await?;
let rv2 = api2.runtime_version();
println!("New on-chain specVersion: {}\n", rv2.spec_version);
// ==========================================
// STEP 2: Set ValidatorCount + ForceEra
// ==========================================
println!("=== STEP 2: SET VALIDATOR COUNT + FORCE ERA ===");
// Storage keys (verified):
// Staking::ValidatorCount: 0x5f3e4907f716ac89b6347d15ececedca138e71612491192d68deab7e6f563fe1
// Staking::ForceEra: 0x5f3e4907f716ac89b6347d15ececedcaf7dad0317324aecae8744b87fc95f2f3
let validator_count_key =
hex::decode("5f3e4907f716ac89b6347d15ececedca138e71612491192d68deab7e6f563fe1")
.unwrap();
let force_era_key =
hex::decode("5f3e4907f716ac89b6347d15ececedcaf7dad0317324aecae8744b87fc95f2f3")
.unwrap();
// ValidatorCount is u32 LE
let validator_count_value = new_validator_count.to_le_bytes().to_vec();
// ForceEra::ForceNew = 0x01
let force_era_value = vec![0x01u8];
println!("Setting ValidatorCount = {}", new_validator_count);
println!("Setting ForceEra = ForceNew (0x01)");
let set_storage_tx = pezkuwi_subxt::dynamic::tx("System", "set_storage", vec![
Value::unnamed_composite(vec![
Value::unnamed_composite(vec![
Value::from_bytes(&validator_count_key),
Value::from_bytes(&validator_count_value),
]),
Value::unnamed_composite(vec![
Value::from_bytes(&force_era_key),
Value::from_bytes(&force_era_value),
]),
]),
]);
let sudo_storage = pezkuwi_subxt::dynamic::tx("Sudo", "sudo", vec![
set_storage_tx.into_value(),
]);
let tx_progress2 = api2
.tx()
.sign_and_submit_then_watch_default(&sudo_storage, &sudo_keypair)
.await?;
println!(
" TX submitted: 0x{}",
hex::encode(tx_progress2.extrinsic_hash().as_ref())
);
let mut progress2 = tx_progress2;
let mut storage_ok = false;
loop {
let status = progress2.next().await;
match status {
Some(Ok(TxStatus::InBestBlock(details))) => {
match details.wait_for_success().await {
Ok(events) => {
println!(" In best block! Events:");
for event in events.iter() {
if let Ok(ev) = event {
println!(" {}::{}", ev.pallet_name(), ev.variant_name());
if ev.pallet_name() == "Sudo" && ev.variant_name() == "Sudid" {
storage_ok = true;
}
}
}
},
Err(e) => println!(" DISPATCH ERROR: {}", e),
}
break;
},
Some(Ok(TxStatus::Error { message })) => {
println!(" TX ERROR: {}", message);
break;
},
Some(Ok(TxStatus::Invalid { message })) => {
println!(" TX INVALID: {}", message);
break;
},
Some(Ok(TxStatus::Dropped { message })) => {
println!(" TX DROPPED: {}", message);
break;
},
Some(Err(e)) => {
println!(" STREAM ERROR: {}", e);
break;
},
None => {
println!(" STREAM ENDED");
break;
},
_ => {},
}
}
if !storage_ok {
println!("\n STORAGE FIX FAILED!");
} else {
println!(" STORAGE FIX SUCCESS!");
}
// ==========================================
// STEP 3: Verify
// ==========================================
println!("\n=== VERIFICATION ===");
tokio::time::sleep(std::time::Duration::from_secs(6)).await;
let api3 = OnlineClient::<PezkuwiConfig>::from_insecure_url(&url).await?;
let rv3 = api3.runtime_version();
println!("specVersion: {}", rv3.spec_version);
// Read back storage to verify
let vc_bytes = api3
.storage()
.at_latest()
.await?
.fetch_raw(validator_count_key)
.await?;
if vc_bytes.len() >= 4 {
let vc = u32::from_le_bytes([vc_bytes[0], vc_bytes[1], vc_bytes[2], vc_bytes[3]]);
println!("ValidatorCount: {}", vc);
}
let fe_bytes = api3
.storage()
.at_latest()
.await?
.fetch_raw(force_era_key)
.await?;
if !fe_bytes.is_empty() {
let fe_name = match fe_bytes[0] {
0x00 => "NotForcing",
0x01 => "ForceNew",
0x02 => "ForceNone",
0x03 => "ForceAlways",
_ => "Unknown",
};
println!("ForceEra: {} (0x{:02x})", fe_name, fe_bytes[0]);
}
println!("\n=== DONE ===");
println!("Runtime upgraded and validator count set.");
println!("Next era should elect {} validators.", new_validator_count);
println!("Monitor: GRANDPA authorities should change within 1-2 sessions.");
Ok(())
}