4c8f281051
- Remove nightly-only features from .rustfmt.toml and vendor/ss58-registry/rustfmt.toml - Removed features: imports_granularity, wrap_comments, comment_width, reorder_impl_items, spaces_around_ranges, binop_separator, match_arm_blocks, trailing_semicolon, trailing_comma - Format all 898 affected files with stable rustfmt - Ensures long-term reliability without nightly toolchain dependency
294 lines
8.4 KiB
Rust
294 lines
8.4 KiB
Rust
// Copyright (C) Parity Technologies (UK) Ltd.
|
|
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
|
// see LICENSE for license details.
|
|
|
|
#![allow(dead_code)]
|
|
#![allow(unused_variables)]
|
|
|
|
use bizinikiwi_txtesttool::{
|
|
block_monitor::BlockMonitor,
|
|
cli::{Cli, CliCommand},
|
|
execution_log::{journal::Journal, make_stats, STAT_TARGET},
|
|
init_logger,
|
|
runner::DefaultTxTask,
|
|
scenario::{AccountsDescription, ChainType, ScenarioBuilder, ScenarioType},
|
|
subxt_transaction::{
|
|
self, generate_ecdsa_keypair, generate_sr25519_keypair, BizinikiwTransaction,
|
|
BizinikiwTransactionsSink, EthRuntimeConfig, EthTransaction, EthTransactionsSink,
|
|
SENDER_SEED,
|
|
},
|
|
};
|
|
use clap::Parser;
|
|
use codec::Compact;
|
|
use pezkuwi_subxt::{ext::frame_metadata::RuntimeMetadataPrefixed, PezkuwiConfig};
|
|
use std::{fs, fs::File, io::BufReader, time::Duration};
|
|
use tracing::info;
|
|
|
|
macro_rules! populate_scenario_builder {
|
|
($scenario_builder:expr, $scenario_type:expr) => {{
|
|
match $scenario_type {
|
|
ScenarioType::OneShot { account, nonce } => {
|
|
$scenario_builder.with_account_id(account.clone()).with_nonce_from(*nonce)
|
|
},
|
|
ScenarioType::FromSingleAccount { account, from, count } => $scenario_builder
|
|
.with_account_id(account.clone())
|
|
.with_nonce_from(*from)
|
|
.with_txs_count(*count),
|
|
ScenarioType::FromManyAccounts { start_id, last_id, from, count } => $scenario_builder
|
|
.with_start_id(*start_id)
|
|
.with_last_id(*last_id)
|
|
.with_nonce_from(*from)
|
|
.with_txs_count(*count),
|
|
}
|
|
}};
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
init_logger();
|
|
|
|
let cli = Cli::parse();
|
|
|
|
match &cli.command {
|
|
CliCommand::Tx {
|
|
chain,
|
|
ws,
|
|
unwatched,
|
|
block_monitor,
|
|
mortal,
|
|
log_file,
|
|
scenario,
|
|
send_threshold,
|
|
remark,
|
|
tip,
|
|
use_legacy_backend,
|
|
} => match chain {
|
|
ChainType::Fake => {
|
|
unimplemented!()
|
|
},
|
|
ChainType::Eth => {
|
|
let mut scenario_builder = ScenarioBuilder::new()
|
|
.with_rpc_uri(ws.to_string())
|
|
.with_chain_type(chain.clone())
|
|
.with_send_threshold(*send_threshold as usize)
|
|
.with_block_monitoring(*block_monitor)
|
|
.with_watched_txs(!unwatched)
|
|
.with_installed_ctrlc_stop_hook(true)
|
|
.with_legacy_backend(*use_legacy_backend)
|
|
.with_tip(*tip);
|
|
|
|
scenario_builder = populate_scenario_builder!(scenario_builder, scenario);
|
|
|
|
if let Some(mortality) = mortal {
|
|
scenario_builder = scenario_builder.with_mortality(*mortality);
|
|
}
|
|
|
|
if let Some(inner) = remark {
|
|
scenario_builder = scenario_builder.with_remark_recipe(*inner);
|
|
}
|
|
|
|
let scenario_executor = scenario_builder.build().await;
|
|
let _ = scenario_executor.execute().await;
|
|
},
|
|
ChainType::Sub => {
|
|
let mut scenario_builder = ScenarioBuilder::new()
|
|
.with_rpc_uri(ws.to_string())
|
|
.with_chain_type(chain.clone())
|
|
.with_send_threshold(*send_threshold as usize)
|
|
.with_block_monitoring(*block_monitor)
|
|
.with_watched_txs(!unwatched)
|
|
.with_installed_ctrlc_stop_hook(true)
|
|
.with_legacy_backend(*use_legacy_backend)
|
|
.with_tip(*tip);
|
|
|
|
scenario_builder = populate_scenario_builder!(scenario_builder, scenario);
|
|
|
|
if let Some(mortality) = mortal {
|
|
scenario_builder = scenario_builder.with_mortality(*mortality);
|
|
}
|
|
|
|
if let Some(inner) = remark {
|
|
scenario_builder = scenario_builder.with_remark_recipe(*inner);
|
|
}
|
|
|
|
let scenario_executor = scenario_builder.build().await;
|
|
let _ = scenario_executor.execute().await;
|
|
},
|
|
},
|
|
CliCommand::CheckNonce { chain, ws, account } => {
|
|
match chain {
|
|
ChainType::Fake => {
|
|
panic!("check nonce not supported for fake chain");
|
|
},
|
|
ChainType::Eth => {
|
|
let desc = if let Ok(id) = account.parse::<u32>() {
|
|
AccountsDescription::Derived(id..id + 1)
|
|
} else {
|
|
AccountsDescription::Keyring(account.clone())
|
|
};
|
|
let sink = EthTransactionsSink::new_with_uri_with_accounts_description(
|
|
ws,
|
|
desc,
|
|
generate_ecdsa_keypair,
|
|
None,
|
|
false,
|
|
)
|
|
.await;
|
|
let account =
|
|
sink.get_from_account_id(account).ok_or("account shall be correct")?;
|
|
let nonce = sink.check_account_nonce(account).await?;
|
|
info!(target:STAT_TARGET, "{nonce:?}");
|
|
},
|
|
ChainType::Sub => {
|
|
let desc = if let Ok(id) = account.parse::<u32>() {
|
|
AccountsDescription::Derived(id..id + 1)
|
|
} else {
|
|
AccountsDescription::Keyring(account.clone())
|
|
};
|
|
let sink = BizinikiwTransactionsSink::new_with_uri_with_accounts_description(
|
|
ws,
|
|
desc,
|
|
generate_sr25519_keypair,
|
|
None,
|
|
false,
|
|
)
|
|
.await;
|
|
let account =
|
|
sink.get_from_account_id(account).ok_or("account shall be correct")?;
|
|
let nonce = sink.check_account_nonce(account).await?;
|
|
info!(target:STAT_TARGET, "{nonce:?}");
|
|
},
|
|
};
|
|
},
|
|
CliCommand::Metadata { ws } => {
|
|
// Handle metadata command
|
|
use codec::Decode;
|
|
let api =
|
|
pezkuwi_subxt::OnlineClient::<EthRuntimeConfig>::from_insecure_url(ws).await?;
|
|
let runtime_apis = api.runtime_api().at_latest().await?;
|
|
let raw_bytes: Vec<u8> = runtime_apis.call_raw("Metadata_metadata", None).await?;
|
|
let (_, meta): (Compact<u32>, RuntimeMetadataPrefixed) =
|
|
Decode::decode(&mut &raw_bytes[..]).map_err(|e| format!("Decode error: {e}"))?;
|
|
println!("{meta:#?}");
|
|
},
|
|
CliCommand::BlockMonitor { chain, ws, display } => {
|
|
match chain {
|
|
ChainType::Sub => {
|
|
let block_monitor =
|
|
BlockMonitor::<PezkuwiConfig>::new_with_options(ws, *display).await;
|
|
async {
|
|
loop {
|
|
tokio::time::sleep(Duration::from_secs(10)).await
|
|
}
|
|
}
|
|
.await;
|
|
},
|
|
ChainType::Eth => {
|
|
let block_monitor =
|
|
BlockMonitor::<EthRuntimeConfig>::new_with_options(ws, *display).await;
|
|
async {
|
|
loop {
|
|
tokio::time::sleep(Duration::from_secs(10)).await
|
|
}
|
|
}
|
|
.await;
|
|
},
|
|
ChainType::Fake => {
|
|
unimplemented!()
|
|
},
|
|
};
|
|
},
|
|
CliCommand::LoadLog { chain, log_file, show_graphs, out_csv_filename, .. } => match chain {
|
|
ChainType::Sub => {
|
|
let logs = Journal::<DefaultTxTask<BizinikiwTransaction>>::load_logs(
|
|
log_file,
|
|
out_csv_filename,
|
|
);
|
|
make_stats(logs.values().cloned(), *show_graphs);
|
|
},
|
|
ChainType::Eth => {
|
|
let logs =
|
|
Journal::<DefaultTxTask<EthTransaction>>::load_logs(log_file, out_csv_filename);
|
|
make_stats(logs.values().cloned(), *show_graphs);
|
|
},
|
|
ChainType::Fake => {
|
|
unimplemented!()
|
|
},
|
|
},
|
|
CliCommand::GenerateEndowedAccounts {
|
|
chain,
|
|
start_id,
|
|
last_id,
|
|
balance,
|
|
out_file_name,
|
|
chain_spec,
|
|
} => {
|
|
let accounts_description = AccountsDescription::Derived(*start_id..last_id + 1);
|
|
let funded_accounts = match chain {
|
|
ChainType::Sub => {
|
|
let accounts = subxt_transaction::derive_accounts::<PezkuwiConfig, _, _>(
|
|
accounts_description.clone(),
|
|
SENDER_SEED,
|
|
generate_sr25519_keypair,
|
|
);
|
|
accounts
|
|
.values()
|
|
.map(|keypair| {
|
|
serde_json::json!((
|
|
<PezkuwiConfig as pezkuwi_subxt::Config>::AccountId::from(
|
|
keypair.0.clone().public_key()
|
|
),
|
|
balance,
|
|
))
|
|
})
|
|
.collect::<Vec<_>>()
|
|
},
|
|
ChainType::Eth => {
|
|
let accounts = subxt_transaction::derive_accounts::<EthRuntimeConfig, _, _>(
|
|
accounts_description.clone(),
|
|
SENDER_SEED,
|
|
generate_ecdsa_keypair,
|
|
);
|
|
accounts
|
|
.values()
|
|
.map(|keypair| {
|
|
serde_json::json!((
|
|
"0x".to_string() + &hex::encode(keypair.0.clone().public_key()),
|
|
balance,
|
|
))
|
|
})
|
|
.collect::<Vec<_>>()
|
|
},
|
|
ChainType::Fake => Default::default(),
|
|
};
|
|
|
|
if let Some(chain_spec) = chain_spec {
|
|
let file = File::open(chain_spec)?;
|
|
let reader = BufReader::new(file);
|
|
let mut chain_spec: serde_json::Value = serde_json::from_reader(reader)?;
|
|
|
|
if let Some(balances) = chain_spec["genesis"]["runtimeGenesis"]["patch"]["balances"]
|
|
["balances"]
|
|
.as_array_mut()
|
|
{
|
|
balances.extend(funded_accounts);
|
|
} else {
|
|
return Err("Balances array not found in provided chain-spec".into());
|
|
}
|
|
|
|
fs::write(
|
|
out_file_name,
|
|
serde_json::to_string_pretty(&chain_spec)
|
|
.map_err(|e| format!("to pretty failed: {e}"))?,
|
|
)
|
|
.map_err(|err| err.to_string())?;
|
|
} else {
|
|
let json_object = serde_json::json!({"balances":{"balances":funded_accounts}});
|
|
fs::write(out_file_name, serde_json::to_string_pretty(&json_object)?.as_bytes())?;
|
|
}
|
|
},
|
|
};
|
|
|
|
Ok(())
|
|
}
|