Skip to content

Commit

Permalink
Output shuffling on Generator (missing tests and mod.rs considerations)
Browse files Browse the repository at this point in the history
  • Loading branch information
KaffinPX committed Sep 24, 2024
1 parent 29e32c9 commit ec41727
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 13 deletions.
26 changes: 21 additions & 5 deletions wallet/core/src/account/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ pub trait Account: AnySync + Send + Sync + 'static {
self.clone().as_dyn_arc(),
PaymentDestination::Change,
fee_rate,
None,
Fees::None,
None,
)?;
Expand Down Expand Up @@ -351,8 +352,14 @@ pub trait Account: AnySync + Send + Sync + 'static {
let keydata = self.prv_key_data(wallet_secret).await?;
let signer = Arc::new(Signer::new(self.clone().as_dyn_arc(), keydata, payment_secret));

let settings =
GeneratorSettings::try_new_with_account(self.clone().as_dyn_arc(), destination, fee_rate, priority_fee_sompi, payload)?;
let settings = GeneratorSettings::try_new_with_account(
self.clone().as_dyn_arc(),
destination,
fee_rate,
None,
priority_fee_sompi,
payload,
)?;

let generator = Generator::try_new(settings, Some(signer), Some(abortable))?;

Expand Down Expand Up @@ -381,8 +388,14 @@ pub trait Account: AnySync + Send + Sync + 'static {
payment_secret: Option<Secret>,
abortable: &Abortable,
) -> Result<Bundle, Error> {
let settings =
GeneratorSettings::try_new_with_account(self.clone().as_dyn_arc(), destination, fee_rate, priority_fee_sompi, payload)?;
let settings = GeneratorSettings::try_new_with_account(
self.clone().as_dyn_arc(),
destination,
fee_rate,
None,
priority_fee_sompi,
payload,
)?;
let keydata = self.prv_key_data(wallet_secret).await?;
let signer = Arc::new(PSKBSigner::new(self.clone().as_dyn_arc(), keydata, payment_secret));
let generator = Generator::try_new(settings, None, Some(abortable))?;
Expand Down Expand Up @@ -463,6 +476,7 @@ pub trait Account: AnySync + Send + Sync + 'static {
self.clone().as_dyn_arc(),
final_transaction_destination,
fee_rate,
None,
priority_fee_sompi,
final_transaction_payload,
)?
Expand Down Expand Up @@ -493,7 +507,8 @@ pub trait Account: AnySync + Send + Sync + 'static {
payload: Option<Vec<u8>>,
abortable: &Abortable,
) -> Result<GeneratorSummary> {
let settings = GeneratorSettings::try_new_with_account(self.as_dyn_arc(), destination, fee_rate, priority_fee_sompi, payload)?;
let settings =
GeneratorSettings::try_new_with_account(self.as_dyn_arc(), destination, fee_rate, None, priority_fee_sompi, payload)?;

let generator = Generator::try_new(settings, None, Some(abortable))?;

Expand Down Expand Up @@ -620,6 +635,7 @@ pub trait DerivationCapableAccount: Account {
1,
PaymentDestination::Change,
fee_rate,
None,
Fees::None,
None,
None,
Expand Down
1 change: 1 addition & 0 deletions wallet/core/src/account/pskb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ pub fn pskt_to_pending_transaction(
source_utxo_context: None,
destination_utxo_context: None,
fee_rate: None,
shuffle_outputs: None,
final_transaction_priority_fee: fee_u.into(),
final_transaction_destination,
final_transaction_payload: None,
Expand Down
29 changes: 24 additions & 5 deletions wallet/core/src/tx/generator/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ use kaspa_consensus_core::mass::Kip9Version;
use kaspa_consensus_core::subnets::SUBNETWORK_ID_NATIVE;
use kaspa_consensus_core::tx::{Transaction, TransactionInput, TransactionOutpoint, TransactionOutput};
use kaspa_txscript::pay_to_address_script;
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::collections::VecDeque;

use super::SignerT;
Expand Down Expand Up @@ -296,6 +298,8 @@ struct Inner {
signature_mass_per_input: u64,
// fee rate
fee_rate: Option<f64>,
// shuffle outputs of final transaction
shuffle_outputs: Option<bool>,
// final transaction amount and fees
// `None` is used for sweep transactions
final_transaction: Option<FinalTransaction>,
Expand Down Expand Up @@ -362,6 +366,7 @@ impl Generator {
minimum_signatures,
change_address,
fee_rate,
shuffle_outputs,
final_transaction_priority_fee,
final_transaction_destination,
final_transaction_payload,
Expand Down Expand Up @@ -469,6 +474,7 @@ impl Generator {
standard_change_output_compute_mass: standard_change_output_mass,
signature_mass_per_input,
fee_rate,
shuffle_outputs,
final_transaction,
final_transaction_priority_fee,
final_transaction_outputs,
Expand Down Expand Up @@ -1069,7 +1075,7 @@ impl Generator {

let change_output_value = change_output_value.unwrap_or(0);

let mut final_outputs = self.inner.final_transaction_outputs.clone();
let mut final_outputs: Vec<TransactionOutput> = self.inner.final_transaction_outputs.clone();

if self.inner.final_transaction_priority_fee.receiver_pays() {
let output = final_outputs.get_mut(0).expect("include fees requires one output");
Expand All @@ -1080,10 +1086,23 @@ impl Generator {
}
}

let change_output_index = if change_output_value > 0 {
let change_output_index = Some(final_outputs.len());
final_outputs.push(TransactionOutput::new(change_output_value, pay_to_address_script(&self.inner.change_address)));
change_output_index
// Cache the change output (if any) before shuffling so we can find its index.
let change_output = if change_output_value > 0 {
let change_output = TransactionOutput::new(change_output_value, pay_to_address_script(&self.inner.change_address));
final_outputs.push(change_output.clone());
Some(change_output)
} else {
None
};

// Shuffle the outputs if required for extra privacy.
if self.inner.shuffle_outputs.unwrap_or(true) {
final_outputs.shuffle(&mut thread_rng());
}

// Find the new change_output_index after shuffling if there was a change output.
let change_output_index = if let Some(change_output) = change_output {
final_outputs.iter().position(|output| output == &change_output)
} else {
None
};
Expand Down
12 changes: 9 additions & 3 deletions wallet/core/src/tx/generator/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub struct GeneratorSettings {
pub change_address: Address,
// fee rate
pub fee_rate: Option<f64>,
// Whether to shuffle the outputs of the final transaction for privacy reasons.
pub shuffle_outputs: Option<bool>,
// applies only to the final transaction
pub final_transaction_priority_fee: Fees,
// final transaction outputs
Expand Down Expand Up @@ -63,6 +65,7 @@ impl GeneratorSettings {
account: Arc<dyn Account>,
final_transaction_destination: PaymentDestination,
fee_rate: Option<f64>,
shuffle_outputs: Option<bool>,
final_priority_fee: Fees,
final_transaction_payload: Option<Vec<u8>>,
) -> Result<Self> {
Expand All @@ -83,8 +86,8 @@ impl GeneratorSettings {
utxo_iterator: Box::new(utxo_iterator),
source_utxo_context: Some(account.utxo_context().clone()),
priority_utxo_entries: None,

fee_rate,
shuffle_outputs,
final_transaction_priority_fee: final_priority_fee,
final_transaction_destination,
final_transaction_payload,
Expand All @@ -94,6 +97,7 @@ impl GeneratorSettings {
Ok(settings)
}

#[allow(clippy::too_many_arguments)]
pub fn try_new_with_context(
utxo_context: UtxoContext,
priority_utxo_entries: Option<Vec<UtxoEntryReference>>,
Expand All @@ -102,6 +106,7 @@ impl GeneratorSettings {
minimum_signatures: u16,
final_transaction_destination: PaymentDestination,
fee_rate: Option<f64>,
shuffle_outputs: Option<bool>,
final_priority_fee: Fees,
final_transaction_payload: Option<Vec<u8>>,
multiplexer: Option<Multiplexer<Box<Events>>>,
Expand All @@ -118,8 +123,8 @@ impl GeneratorSettings {
utxo_iterator: Box::new(utxo_iterator),
source_utxo_context: Some(utxo_context),
priority_utxo_entries,

fee_rate,
shuffle_outputs,
final_transaction_priority_fee: final_priority_fee,
final_transaction_destination,
final_transaction_payload,
Expand All @@ -139,6 +144,7 @@ impl GeneratorSettings {
minimum_signatures: u16,
final_transaction_destination: PaymentDestination,
fee_rate: Option<f64>,
shuffle_outputs: Option<bool>,
final_priority_fee: Fees,
final_transaction_payload: Option<Vec<u8>>,
multiplexer: Option<Multiplexer<Box<Events>>>,
Expand All @@ -152,8 +158,8 @@ impl GeneratorSettings {
utxo_iterator: Box::new(utxo_iterator),
source_utxo_context: None,
priority_utxo_entries,

fee_rate,
shuffle_outputs,
final_transaction_priority_fee: final_priority_fee,
final_transaction_destination,
final_transaction_payload,
Expand Down
1 change: 1 addition & 0 deletions wallet/core/src/tx/generator/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ where
priority_utxo_entries,
destination_utxo_context,
fee_rate,
shuffle_outputs: None,
final_transaction_priority_fee: final_priority_fee,
final_transaction_destination,
final_transaction_payload,
Expand Down
7 changes: 7 additions & 0 deletions wallet/core/src/wasm/tx/generator/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ impl Generator {
final_transaction_destination,
change_address,
fee_rate,
shuffle_outputs,
final_priority_fee,
sig_op_count,
minimum_signatures,
Expand All @@ -192,6 +193,7 @@ impl Generator {
minimum_signatures,
final_transaction_destination,
fee_rate,
shuffle_outputs,
final_priority_fee,
payload,
multiplexer,
Expand All @@ -209,6 +211,7 @@ impl Generator {
minimum_signatures,
final_transaction_destination,
fee_rate,
shuffle_outputs,
final_priority_fee,
payload,
multiplexer,
Expand Down Expand Up @@ -272,6 +275,7 @@ struct GeneratorSettings {
pub final_transaction_destination: PaymentDestination,
pub change_address: Option<Address>,
pub fee_rate: Option<f64>,
pub shuffle_outputs: Option<bool>,
pub final_priority_fee: Fees,
pub sig_op_count: u8,
pub minimum_signatures: u16,
Expand All @@ -292,6 +296,8 @@ impl TryFrom<IGeneratorSettingsObject> for GeneratorSettings {

let fee_rate = args.get_f64("feeRate").ok().and_then(|v| (v.is_finite() && !v.is_nan() && v >= 1e-8).then_some(v));

let shuffle_outputs = args.get_bool("shuffleOutputs").ok();

let final_priority_fee = args.get::<IFees>("priorityFee")?.try_into()?;

let generator_source = if let Ok(Some(context)) = args.try_cast_into::<UtxoContext>("entries") {
Expand Down Expand Up @@ -325,6 +331,7 @@ impl TryFrom<IGeneratorSettingsObject> for GeneratorSettings {
final_transaction_destination,
change_address,
fee_rate,
shuffle_outputs,
final_priority_fee,
sig_op_count,
minimum_signatures,
Expand Down

0 comments on commit ec41727

Please sign in to comment.