From caecb67a160ae16ec0ccb46d66183c1ee2d9732d Mon Sep 17 00:00:00 2001 From: Dmitry Perchanov Date: Sun, 2 Jun 2024 17:52:55 +0300 Subject: [PATCH 1/4] rothschild: donate funds to external address Signed-off-by: Dmitry Perchanov --- rothschild/src/main.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/rothschild/src/main.rs b/rothschild/src/main.rs index bbabca71b..0ac2a2a17 100644 --- a/rothschild/src/main.rs +++ b/rothschild/src/main.rs @@ -40,6 +40,7 @@ pub struct Args { pub rpc_server: String, pub threads: u8, pub unleashed: bool, + pub addr: Option, } impl Args { @@ -51,6 +52,7 @@ impl Args { rpc_server: m.get_one::("rpcserver").cloned().unwrap_or("localhost:16210".to_owned()), threads: m.get_one::("threads").cloned().unwrap(), unleashed: m.get_one::("unleashed").cloned().unwrap_or(false), + addr: m.get_one::("addr").cloned(), } } } @@ -85,6 +87,7 @@ pub fn cli() -> Command { .help("The number of threads to use for TX generation. Set to 0 to use 1 thread per core. Default is 2."), ) .arg(Arg::new("unleashed").long("unleashed").action(ArgAction::SetTrue).hide(true).help("Allow higher TPS")) + .arg(Arg::new("addr").long("to-addr").short('a').value_name("addr").help("address to send to")) } async fn new_rpc_client(subscription_context: &SubscriptionContext, address: &str) -> GrpcClient { @@ -150,9 +153,15 @@ async fn main() { let kaspa_addr = Address::new(ADDRESS_PREFIX, ADDRESS_VERSION, &schnorr_key.x_only_public_key().0.serialize()); + let kaspa_to_addr = if let Some(addr_str) = args.addr { + Address::try_from(addr_str).unwrap() + } else { + kaspa_addr.clone() + }; + rayon::ThreadPoolBuilder::new().num_threads(args.threads as usize).build_global().unwrap(); - info!("Using Rothschild with private key {} and address {}", schnorr_key.display_secret(), String::from(&kaspa_addr)); + info!("Using Rothschild with private key {} and address {}\n\tspend to {}", schnorr_key.display_secret(), String::from(&kaspa_addr), String::from(&kaspa_to_addr)); let info = rpc_client.get_block_dag_info().await.unwrap(); let coinbase_maturity = match info.network.suffix { Some(11) => TESTNET11_PARAMS.coinbase_maturity, @@ -249,7 +258,7 @@ async fn main() { let has_funds = maybe_send_tx( txs_to_send, &tx_sender, - kaspa_addr.clone(), + kaspa_to_addr.clone(), &mut utxos, &mut pending, schnorr_key, From 318494ed3909cc0355ea45d5412b57ebb7b44afd Mon Sep 17 00:00:00 2001 From: Dmitry Perchanov Date: Tue, 27 Aug 2024 12:28:41 +0300 Subject: [PATCH 2/4] rothschild: Append priority fee to txs. Signed-off-by: Dmitry Perchanov --- rothschild/src/main.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rothschild/src/main.rs b/rothschild/src/main.rs index 0ac2a2a17..24a48ab96 100644 --- a/rothschild/src/main.rs +++ b/rothschild/src/main.rs @@ -17,7 +17,7 @@ use kaspa_rpc_core::{api::rpc::RpcApi, notify::mode::NotificationMode}; use kaspa_txscript::pay_to_address_script; use parking_lot::Mutex; use rayon::prelude::*; -use secp256k1::{rand::thread_rng, Keypair}; +use secp256k1::{rand::thread_rng, rand::random, Keypair}; use tokio::time::{interval, MissedTickBehavior}; const DEFAULT_SEND_AMOUNT: u64 = 10 * SOMPI_PER_KASPA; @@ -493,11 +493,12 @@ fn select_utxos( selected.push((outpoint, entry)); let fee = required_fee(selected.len(), num_outs); + let priority_fee = (random::() * SOMPI_PER_KASPA as f32) as u64; *next_available_utxo_index += 1; - if selected_amount >= min_amount + fee && (!maximize_utxos || selected.len() == MAX_UTXOS) { - return (selected, selected_amount - fee); + if selected_amount >= min_amount + fee + priority_fee && (!maximize_utxos || selected.len() == MAX_UTXOS) { + return (selected, selected_amount - fee - priority_fee); } if selected.len() > MAX_UTXOS { From 947d9b757f7ffd49e55396e2c46c9159963cd771 Mon Sep 17 00:00:00 2001 From: Dmitry Perchanov Date: Fri, 20 Sep 2024 16:38:05 +0300 Subject: [PATCH 3/4] rothschild: add option to choose and randomize fee Signed-off-by: Dmitry Perchanov --- rothschild/src/main.rs | 76 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/rothschild/src/main.rs b/rothschild/src/main.rs index 7a0c205fa..c7d15a93c 100644 --- a/rothschild/src/main.rs +++ b/rothschild/src/main.rs @@ -17,7 +17,7 @@ use kaspa_rpc_core::{api::rpc::RpcApi, notify::mode::NotificationMode, RpcUtxoEn use kaspa_txscript::pay_to_address_script; use parking_lot::Mutex; use rayon::prelude::*; -use secp256k1::{rand::thread_rng, rand::random, Keypair}; +use secp256k1::{rand::{thread_rng, Rng}, Keypair}; use tokio::time::{interval, MissedTickBehavior}; const DEFAULT_SEND_AMOUNT: u64 = 10 * SOMPI_PER_KASPA; @@ -41,6 +41,8 @@ pub struct Args { pub threads: u8, pub unleashed: bool, pub addr: Option, + pub priority_fee: u64, + pub randomize_fee: bool, } impl Args { @@ -53,6 +55,8 @@ impl Args { threads: m.get_one::("threads").cloned().unwrap(), unleashed: m.get_one::("unleashed").cloned().unwrap_or(false), addr: m.get_one::("addr").cloned(), + priority_fee: m.get_one::("priority-fee").cloned().unwrap_or(0), + randomize_fee: m.get_one::("randomize-fee").cloned().unwrap_or(false), } } } @@ -88,6 +92,24 @@ pub fn cli() -> Command { ) .arg(Arg::new("unleashed").long("unleashed").action(ArgAction::SetTrue).hide(true).help("Allow higher TPS")) .arg(Arg::new("addr").long("to-addr").short('a').value_name("addr").help("address to send to")) + .arg( + Arg::new("priority-fee") + .long("priority-fee") + .short('f') + .value_name("priority-fee") + .default_value("0") + .value_parser(clap::value_parser!(u64)) + .help("Transaction priority fee"), + ) + .arg( + Arg::new("randomize-fee") + .long("randomize-fee") + .short('r') + .value_name("randomize-fee") + .action(ArgAction::SetTrue) + .default_value("false") + .help("Randomize transaction priority fee") + ) } async fn new_rpc_client(subscription_context: &SubscriptionContext, address: &str) -> GrpcClient { @@ -153,15 +175,33 @@ async fn main() { let kaspa_addr = Address::new(ADDRESS_PREFIX, ADDRESS_VERSION, &schnorr_key.x_only_public_key().0.serialize()); - let kaspa_to_addr = if let Some(addr_str) = args.addr { - Address::try_from(addr_str).unwrap() - } else { - kaspa_addr.clone() - }; + let kaspa_to_addr = if let Some(ref addr_str) = args.addr { + Address::try_from(addr_str.clone()).unwrap() + } else { + kaspa_addr.clone() + }; rayon::ThreadPoolBuilder::new().num_threads(args.threads as usize).build_global().unwrap(); - info!("Using Rothschild with private key {} and address {}\n\tspend to {}", schnorr_key.display_secret(), String::from(&kaspa_addr), String::from(&kaspa_to_addr)); + let mut log_message = format!( + "Using Rothschild with:\n\ + \tprivate key: {}\n\ + \tfrom address: {}", + schnorr_key.display_secret(), + String::from(&kaspa_addr) + ); + if args.addr.is_some() { + log_message.push_str(&format!("\n\tto address: {}", String::from(&kaspa_to_addr))); + } + if args.priority_fee != 0 { + log_message.push_str(&format!( + "\n\tpriority fee: {} SOMPS {}", + args.priority_fee, + if args.randomize_fee { "[randomize]" } else { "" } + )); + } + info!("{}", log_message); + let info = rpc_client.get_block_dag_info().await.unwrap(); let coinbase_maturity = match info.network.suffix { Some(11) => TESTNET11_PARAMS.coinbase_maturity, @@ -265,6 +305,8 @@ async fn main() { stats.clone(), maximize_inputs, &mut next_available_utxo_index, + args.priority_fee, + args.randomize_fee, ) .await; if !has_funds { @@ -378,6 +420,8 @@ async fn maybe_send_tx( stats: Arc>, maximize_inputs: bool, next_available_utxo_index: &mut usize, + priority_fee: u64, + randomize_fee: bool, ) -> bool { let num_outs = if maximize_inputs { 1 } else { 2 }; @@ -386,7 +430,14 @@ async fn maybe_send_tx( let selected_utxos_groups = (0..txs_to_send) .map(|_| { let (selected_utxos, selected_amount) = - select_utxos(utxos, DEFAULT_SEND_AMOUNT, num_outs, maximize_inputs, next_available_utxo_index); + select_utxos(utxos, + DEFAULT_SEND_AMOUNT, + num_outs, + maximize_inputs, + next_available_utxo_index, + priority_fee, + randomize_fee + ); if selected_amount == 0 { return None; } @@ -482,10 +533,13 @@ fn select_utxos( num_outs: u64, maximize_utxos: bool, next_available_utxo_index: &mut usize, + priority_fee: u64, + randomize_fee: bool, ) -> (Vec<(TransactionOutpoint, UtxoEntry)>, u64) { const MAX_UTXOS: usize = 84; let mut selected_amount: u64 = 0; let mut selected = Vec::new(); + let mut rng = thread_rng(); while next_available_utxo_index < &mut utxos.len() { let (outpoint, entry) = utxos[*next_available_utxo_index].clone(); @@ -493,7 +547,11 @@ fn select_utxos( selected.push((outpoint, entry)); let fee = required_fee(selected.len(), num_outs); - let priority_fee = (random::() * SOMPI_PER_KASPA as f32) as u64; + let priority_fee = if randomize_fee && priority_fee > 0 { + rng.gen_range(0..priority_fee) + } else { + priority_fee + }; *next_available_utxo_index += 1; From 80034745283dcd40224403e6e7de550b73457126 Mon Sep 17 00:00:00 2001 From: Dmitry Perchanov Date: Sat, 21 Sep 2024 13:14:02 +0300 Subject: [PATCH 4/4] rothschild: address clippy formatting issues Signed-off-by: Dmitry Perchanov --- rothschild/src/main.rs | 50 +++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/rothschild/src/main.rs b/rothschild/src/main.rs index c7d15a93c..35d08493b 100644 --- a/rothschild/src/main.rs +++ b/rothschild/src/main.rs @@ -17,7 +17,10 @@ use kaspa_rpc_core::{api::rpc::RpcApi, notify::mode::NotificationMode, RpcUtxoEn use kaspa_txscript::pay_to_address_script; use parking_lot::Mutex; use rayon::prelude::*; -use secp256k1::{rand::{thread_rng, Rng}, Keypair}; +use secp256k1::{ + rand::{thread_rng, Rng}, + Keypair, +}; use tokio::time::{interval, MissedTickBehavior}; const DEFAULT_SEND_AMOUNT: u64 = 10 * SOMPI_PER_KASPA; @@ -108,8 +111,8 @@ pub fn cli() -> Command { .value_name("randomize-fee") .action(ArgAction::SetTrue) .default_value("false") - .help("Randomize transaction priority fee") - ) + .help("Randomize transaction priority fee"), + ) } async fn new_rpc_client(subscription_context: &SubscriptionContext, address: &str) -> GrpcClient { @@ -136,6 +139,11 @@ struct ClientPoolArg { utxos_len: usize, } +struct TxsFeeConfig { + priority_fee: u64, + randomize_fee: bool, +} + #[tokio::main] async fn main() { kaspa_core::log::init_logger(None, ""); @@ -175,11 +183,9 @@ async fn main() { let kaspa_addr = Address::new(ADDRESS_PREFIX, ADDRESS_VERSION, &schnorr_key.x_only_public_key().0.serialize()); - let kaspa_to_addr = if let Some(ref addr_str) = args.addr { - Address::try_from(addr_str.clone()).unwrap() - } else { - kaspa_addr.clone() - }; + let kaspa_to_addr = args.addr.as_ref().map_or_else(|| kaspa_addr.clone(), |addr_str| Address::try_from(addr_str.clone()).unwrap()); + + let fee_config = TxsFeeConfig { priority_fee: args.priority_fee, randomize_fee: args.randomize_fee }; rayon::ThreadPoolBuilder::new().num_threads(args.threads as usize).build_global().unwrap(); @@ -196,8 +202,8 @@ async fn main() { if args.priority_fee != 0 { log_message.push_str(&format!( "\n\tpriority fee: {} SOMPS {}", - args.priority_fee, - if args.randomize_fee { "[randomize]" } else { "" } + fee_config.priority_fee, + if fee_config.randomize_fee { "[randomize]" } else { "" } )); } info!("{}", log_message); @@ -305,8 +311,7 @@ async fn main() { stats.clone(), maximize_inputs, &mut next_available_utxo_index, - args.priority_fee, - args.randomize_fee, + &fee_config, ) .await; if !has_funds { @@ -420,8 +425,7 @@ async fn maybe_send_tx( stats: Arc>, maximize_inputs: bool, next_available_utxo_index: &mut usize, - priority_fee: u64, - randomize_fee: bool, + fee_config: &TxsFeeConfig, ) -> bool { let num_outs = if maximize_inputs { 1 } else { 2 }; @@ -430,14 +434,7 @@ async fn maybe_send_tx( let selected_utxos_groups = (0..txs_to_send) .map(|_| { let (selected_utxos, selected_amount) = - select_utxos(utxos, - DEFAULT_SEND_AMOUNT, - num_outs, - maximize_inputs, - next_available_utxo_index, - priority_fee, - randomize_fee - ); + select_utxos(utxos, DEFAULT_SEND_AMOUNT, num_outs, maximize_inputs, next_available_utxo_index, fee_config); if selected_amount == 0 { return None; } @@ -533,8 +530,7 @@ fn select_utxos( num_outs: u64, maximize_utxos: bool, next_available_utxo_index: &mut usize, - priority_fee: u64, - randomize_fee: bool, + fee_config: &TxsFeeConfig, ) -> (Vec<(TransactionOutpoint, UtxoEntry)>, u64) { const MAX_UTXOS: usize = 84; let mut selected_amount: u64 = 0; @@ -547,10 +543,10 @@ fn select_utxos( selected.push((outpoint, entry)); let fee = required_fee(selected.len(), num_outs); - let priority_fee = if randomize_fee && priority_fee > 0 { - rng.gen_range(0..priority_fee) + let priority_fee = if fee_config.randomize_fee && fee_config.priority_fee > 0 { + rng.gen_range(0..fee_config.priority_fee) } else { - priority_fee + fee_config.priority_fee }; *next_available_utxo_index += 1;