Files
pezkuwi-sdk/vendor/pezkuwi-subxt/subxt/examples/zagros_sudo.rs
T

165 lines
5.3 KiB
Rust

//! Zagros Testnet: Generic sudo call sender
//!
//! Run with:
//! SUDO_MNEMONIC="..." RPC_URL="ws://..." CALL=setValidatorCount|forceNewEra \
//! cargo run --release --example zagros_sudo
#![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>> {
let url = std::env::var("RPC_URL").unwrap_or_else(|_| "ws://217.77.6.126:9948".to_string());
let call_name = std::env::var("CALL").unwrap_or_else(|_| "setValidatorCount".to_string());
println!("RPC: {}", url);
println!("Call: {}", call_name);
let api = OnlineClient::<PezkuwiConfig>::from_insecure_url(&url).await?;
println!("Connected!");
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 inner_call = match call_name.as_str() {
"setValidatorCount" => {
let count: u32 = std::env::var("COUNT").unwrap_or_else(|_| "4".to_string()).parse()?;
println!("Setting validator count to {}", count);
pezkuwi_subxt::dynamic::tx(
"Staking",
"set_validator_count",
vec![Value::u128(count as u128)],
)
},
"forceNewEra" => {
println!("Forcing new era");
pezkuwi_subxt::dynamic::tx("Staking", "force_new_era", Vec::<Value>::new())
},
"forceNewEraAlways" => {
println!("Forcing new era always");
pezkuwi_subxt::dynamic::tx("Staking", "force_new_era_always", Vec::<Value>::new())
},
"setStakingConfigs" => {
// Deprecated: use setMinValidatorCount instead
eprintln!("Use setMinValidatorCount instead");
std::process::exit(1);
},
"setMinValidatorCount" => {
let min_count: u32 =
std::env::var("MIN_COUNT").unwrap_or_else(|_| "1".to_string()).parse().unwrap();
println!("Setting minimum validator count to {}", min_count);
let noop = Value::unnamed_variant("Noop", Vec::<Value>::new());
let set_min = Value::unnamed_variant("Set", vec![Value::u128(min_count as u128)]);
pezkuwi_subxt::dynamic::tx(
"Staking",
"set_staking_configs",
vec![
noop.clone(), // min_nominator_bond
noop.clone(), // min_validator_bond
noop.clone(), // max_nominator_count
noop.clone(), // max_validator_count
noop.clone(), // chill_threshold
set_min, // min_commission (used as min_validator_count proxy)
noop.clone(), // max_staked_rewards
],
)
},
"setStorage" => {
// Set arbitrary storage via sudo(system.setStorage)
let key_hex = std::env::var("STORAGE_KEY").expect("STORAGE_KEY env var required");
let value_hex = std::env::var("STORAGE_VALUE").expect("STORAGE_VALUE env var required");
println!("Setting storage key={} value={}", key_hex, value_hex);
let key_bytes = hex::decode(key_hex.trim_start_matches("0x")).unwrap();
let value_bytes = hex::decode(value_hex.trim_start_matches("0x")).unwrap();
// system.setStorage takes Vec<(Key, Value)>
let item = Value::unnamed_composite([
Value::from_bytes(&key_bytes),
Value::from_bytes(&value_bytes),
]);
pezkuwi_subxt::dynamic::tx(
"System",
"set_storage",
vec![Value::unnamed_composite([item])],
)
},
_ => {
eprintln!("Unknown call: {}", call_name);
std::process::exit(1);
},
};
let sudo_tx = pezkuwi_subxt::dynamic::tx("Sudo", "sudo", vec![inner_call.into_value()]);
println!("\nSubmitting...");
// Use sign_and_submit_then_watch to see TX lifecycle
let tx_progress = api.tx().sign_and_submit_then_watch_default(&sudo_tx, &sudo_keypair).await?;
println!("TX hash: 0x{}", hex::encode(tx_progress.extrinsic_hash().as_ref()));
println!("Watching TX status (Ctrl+C to abort)...");
// Don't wait for finalization - just wait for in_block
use pezkuwi_subxt::tx::TxStatus;
let mut progress = tx_progress;
loop {
let status = progress.next().await;
match status {
Some(Ok(TxStatus::Validated)) => println!(" Status: Validated (in tx pool)"),
Some(Ok(TxStatus::Broadcasted)) => println!(" Status: Broadcasted"),
Some(Ok(TxStatus::InBestBlock(details))) => {
println!(" Status: InBestBlock {:?}", details.block_hash());
match details.wait_for_success().await {
Ok(events) => {
println!(" TX SUCCESS!");
for ev in events.iter().flatten() {
println!(" Event: {}::{}", ev.pallet_name(), ev.variant_name());
}
},
Err(e) => println!(" TX dispatch error: {}", e),
}
break;
},
Some(Ok(TxStatus::InFinalizedBlock(details))) => {
println!(" Status: Finalized {:?}", details.block_hash());
break;
},
Some(Ok(TxStatus::Error { message })) => {
println!(" Status: ERROR - {}", message);
break;
},
Some(Ok(TxStatus::Invalid { message })) => {
println!(" Status: INVALID - {}", message);
break;
},
Some(Ok(TxStatus::Dropped { message })) => {
println!(" Status: DROPPED - {}", message);
break;
},
Some(Ok(TxStatus::NoLongerInBestBlock)) => {
println!(" Status: No longer in best block");
},
Some(Err(e)) => {
println!(" Stream error: {}", e);
break;
},
None => {
println!(" Stream ended");
break;
},
}
}
println!("\nDone.");
Ok(())
}