Prioritize and allow no change transaction (#1009)

Prioritize and allow no change transaction
This commit is contained in:
Quentin Le Sceller 2018-04-27 10:26:40 -04:00 committed by GitHub
parent 93b648fbc0
commit f8732d7621
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 83 additions and 56 deletions

View file

@ -69,7 +69,7 @@ fn handle_sender_initiation(
tx.input_proofs_count(), tx.input_proofs_count(),
None, None,
); );
if fee != tx.fee() { if fee > tx.fee() {
return Err(ErrorKind::FeeDispute { return Err(ErrorKind::FeeDispute {
sender_fee: tx.fee(), sender_fee: tx.fee(),
recipient_fee: fee, recipient_fee: fee,
@ -89,7 +89,7 @@ fn handle_sender_initiation(
})?; })?;
} }
let out_amount = amount - fee; let out_amount = amount - tx.fee();
// First step is just to get the excess sum of the outputs we're participating // First step is just to get the excess sum of the outputs we're participating
// in Output and key needs to be stored until transaction finalisation time, // in Output and key needs to be stored until transaction finalisation time,
@ -131,7 +131,12 @@ fn handle_sender_initiation(
keychain.aggsig_add_output(&partial_tx.id, &key_id); keychain.aggsig_add_output(&partial_tx.id, &key_id);
let sig_part = keychain let sig_part = keychain
.aggsig_calculate_partial_sig(&partial_tx.id, &sender_pub_nonce, fee, tx.lock_height()) .aggsig_calculate_partial_sig(
&partial_tx.id,
&sender_pub_nonce,
tx.fee(),
tx.lock_height(),
)
.unwrap(); .unwrap();
// Build the response, which should contain sR, blinding excess xR * G, public // Build the response, which should contain sR, blinding excess xR * G, public
@ -414,7 +419,7 @@ fn build_final_transaction(
tx.input_proofs_count(), tx.input_proofs_count(),
None, None,
); );
if fee != tx.fee() { if fee > tx.fee() {
return Err(ErrorKind::FeeDispute { return Err(ErrorKind::FeeDispute {
sender_fee: tx.fee(), sender_fee: tx.fee(),
recipient_fee: fee, recipient_fee: fee,
@ -434,7 +439,7 @@ fn build_final_transaction(
})?; })?;
} }
let out_amount = amount - fee; let out_amount = amount - tx.fee();
// Get output we created in earlier step // Get output we created in earlier step
// TODO: will just be one for now, support multiple later // TODO: will just be one for now, support multiple later

View file

@ -104,8 +104,13 @@ pub fn issue_send_tx(
// failure. // failure.
let rollback_wallet = || { let rollback_wallet = || {
WalletData::with_wallet(&config.data_file_dir, |wallet_data| { WalletData::with_wallet(&config.data_file_dir, |wallet_data| {
match change_key.clone() {
Some(change) => {
info!(LOGGER, "cleaning up unused change output from wallet"); info!(LOGGER, "cleaning up unused change output from wallet");
wallet_data.delete_output(&change_key); wallet_data.delete_output(&change);
}
None => info!(LOGGER, "No change output to clean from wallet"),
}
}) })
}; };
@ -120,8 +125,13 @@ pub fn issue_send_tx(
if &dest[..4] != "http" { if &dest[..4] != "http" {
WalletData::with_wallet(&config.data_file_dir, |wallet_data| { WalletData::with_wallet(&config.data_file_dir, |wallet_data| {
match change_key.clone() {
Some(change) => {
info!(LOGGER, "cleaning up unused change output from wallet"); info!(LOGGER, "cleaning up unused change output from wallet");
wallet_data.delete_output(&change_key); wallet_data.delete_output(&change);
}
None => info!(LOGGER, "No change output to clean from wallet"),
}
}).unwrap(); }).unwrap();
panic!( panic!(
"dest formatted as {} but send -d expected stdout or http://IP:port", "dest formatted as {} but send -d expected stdout or http://IP:port",
@ -229,7 +239,7 @@ fn build_send_tx(
Transaction, Transaction,
BlindingFactor, BlindingFactor,
Vec<OutputData>, Vec<OutputData>,
Identifier, Option<Identifier>,
u64, u64,
), ),
Error, Error,
@ -263,13 +273,20 @@ fn build_send_tx(
// sender is responsible for setting the fee on the partial tx // sender is responsible for setting the fee on the partial tx
// recipient should double check the fee calculation and not blindly trust the // recipient should double check the fee calculation and not blindly trust the
// sender // sender
let mut fee = tx_fee(coins.len(), 2, coins_proof_count(&coins), None); let mut fee;
// First attempt to spend without change
fee = tx_fee(coins.len(), 1, coins_proof_count(&coins), None);
let mut total: u64 = coins.iter().map(|c| c.value).sum(); let mut total: u64 = coins.iter().map(|c| c.value).sum();
let mut amount_with_fee = amount + fee; let mut amount_with_fee = amount + fee;
// Check if we need to use a change address
if total > amount_with_fee {
fee = tx_fee(coins.len(), 2, coins_proof_count(&coins), None);
amount_with_fee = amount + fee;
// Here check if we have enough outputs for the amount including fee otherwise // Here check if we have enough outputs for the amount including fee otherwise
// look for other outputs and check again // look for other outputs and check again
while total <= amount_with_fee { while total < amount_with_fee {
// End the loop if we have selected all the outputs and still not enough funds // End the loop if we have selected all the outputs and still not enough funds
if coins.len() == max_outputs { if coins.len() == max_outputs {
return Err(ErrorKind::NotEnoughFunds(total as u64))?; return Err(ErrorKind::NotEnoughFunds(total as u64))?;
@ -290,6 +307,7 @@ fn build_send_tx(
total = coins.iter().map(|c| c.value).sum(); total = coins.iter().map(|c| c.value).sum();
amount_with_fee = amount + fee; amount_with_fee = amount + fee;
} }
}
// build transaction skeleton with inputs and change // build transaction skeleton with inputs and change
let (mut parts, change_key) = inputs_and_change(&coins, config, keychain, amount, fee)?; let (mut parts, change_key) = inputs_and_change(&coins, config, keychain, amount, fee)?;
@ -360,7 +378,7 @@ fn inputs_and_change(
keychain: &Keychain, keychain: &Keychain,
amount: u64, amount: u64,
fee: u64, fee: u64,
) -> Result<(Vec<Box<build::Append>>, Identifier), Error> { ) -> Result<(Vec<Box<build::Append>>, Option<Identifier>), Error> {
let mut parts = vec![]; let mut parts = vec![];
// calculate the total across all inputs, and how much is left // calculate the total across all inputs, and how much is left
@ -393,9 +411,10 @@ fn inputs_and_change(
parts.push(build::input(coin.value, key_id)); parts.push(build::input(coin.value, key_id));
} }
} }
let change_key;
if change != 0 {
// track the output representing our change // track the output representing our change
let change_key = WalletData::with_wallet(&config.data_file_dir, |wallet_data| { change_key = WalletData::with_wallet(&config.data_file_dir, |wallet_data| {
let root_key_id = keychain.root_key_id(); let root_key_id = keychain.root_key_id();
let change_derivation = wallet_data.next_child(root_key_id.clone()); let change_derivation = wallet_data.next_child(root_key_id.clone());
let change_key = keychain.derive_key_id(change_derivation).unwrap(); let change_key = keychain.derive_key_id(change_derivation).unwrap();
@ -413,10 +432,13 @@ fn inputs_and_change(
merkle_proof: None, merkle_proof: None,
}); });
change_key Some(change_key)
})?; })?;
parts.push(build::output(change, change_key.clone())); parts.push(build::output(change, change_key.clone().unwrap()));
} else {
change_key = None
}
Ok((parts, change_key)) Ok((parts, change_key))
} }