Late locking (experimental) (#530)
* Late locking (experimental) * Error on fee change * Improve comments * Fix typo in comment * Add late locking flag to CLI command
This commit is contained in:
@@ -105,6 +105,9 @@ where
|
||||
use_test_rng,
|
||||
)?;
|
||||
|
||||
// Add our contribution to the offset
|
||||
ret_slate.adjust_offset(&keychain, &context)?;
|
||||
|
||||
let excess = ret_slate.calc_excess(keychain.secp())?;
|
||||
|
||||
if let Some(ref mut p) = ret_slate.payment_proof {
|
||||
@@ -143,6 +146,9 @@ where
|
||||
if sl.state == SlateState::Invoice2 {
|
||||
check_ttl(w, &sl)?;
|
||||
|
||||
// Add our contribution to the offset
|
||||
sl.adjust_offset(&w.keychain(keychain_mask)?, &context)?;
|
||||
|
||||
let mut temp_ctx = context.clone();
|
||||
temp_ctx.sec_key = context.initial_sec_key.clone();
|
||||
temp_ctx.sec_nonce = context.initial_sec_nonce.clone();
|
||||
|
||||
@@ -457,9 +457,9 @@ where
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let parent_key_id = match args.src_acct_name {
|
||||
let parent_key_id = match &args.src_acct_name {
|
||||
Some(d) => {
|
||||
let pm = w.get_acct_path(d)?;
|
||||
let pm = w.get_acct_path(d.clone())?;
|
||||
match pm {
|
||||
Some(p) => p.path,
|
||||
None => w.parent_key_id(),
|
||||
@@ -500,19 +500,31 @@ where
|
||||
}
|
||||
|
||||
let height = w.w2n_client().get_chain_tip()?.0;
|
||||
let mut context = tx::add_inputs_to_slate(
|
||||
&mut *w,
|
||||
keychain_mask,
|
||||
&mut slate,
|
||||
height,
|
||||
args.minimum_confirmations,
|
||||
args.max_outputs as usize,
|
||||
args.num_change_outputs as usize,
|
||||
args.selection_strategy_is_use_all,
|
||||
&parent_key_id,
|
||||
true,
|
||||
use_test_rng,
|
||||
)?;
|
||||
let mut context = if args.late_lock.unwrap_or(false) {
|
||||
tx::create_late_lock_context(
|
||||
&mut *w,
|
||||
keychain_mask,
|
||||
&mut slate,
|
||||
height,
|
||||
&args,
|
||||
&parent_key_id,
|
||||
use_test_rng,
|
||||
)?
|
||||
} else {
|
||||
tx::add_inputs_to_slate(
|
||||
&mut *w,
|
||||
keychain_mask,
|
||||
&mut slate,
|
||||
height,
|
||||
args.minimum_confirmations,
|
||||
args.max_outputs as usize,
|
||||
args.num_change_outputs as usize,
|
||||
args.selection_strategy_is_use_all,
|
||||
&parent_key_id,
|
||||
true,
|
||||
use_test_rng,
|
||||
)?
|
||||
};
|
||||
|
||||
// Payment Proof, add addresses to slate and save address
|
||||
// TODO: Note we only use single derivation path for now,
|
||||
@@ -667,6 +679,19 @@ where
|
||||
)?;
|
||||
|
||||
let keychain = w.keychain(keychain_mask)?;
|
||||
|
||||
// Add our contribution to the offset
|
||||
if context_res.is_ok() {
|
||||
// Self sending: don't correct for inputs and outputs
|
||||
// here, as we will do it during finalization.
|
||||
let mut tmp_context = context.clone();
|
||||
tmp_context.input_ids.clear();
|
||||
tmp_context.output_ids.clear();
|
||||
ret_slate.adjust_offset(&keychain, &tmp_context)?;
|
||||
} else {
|
||||
ret_slate.adjust_offset(&keychain, &context)?;
|
||||
}
|
||||
|
||||
// needs to be stored as we're removing sig data for return trip. this needs to be present
|
||||
// when locking transaction context and updating tx log with excess later
|
||||
context.calculated_excess = Some(ret_slate.calc_excess(keychain.secp())?);
|
||||
@@ -685,7 +710,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
tx::sub_inputs_from_offset(&mut *w, keychain_mask, &context, &mut ret_slate)?;
|
||||
selection::repopulate_tx(&mut *w, keychain_mask, &mut ret_slate, &context, false)?;
|
||||
|
||||
// Save the aggsig context in our DB for when we
|
||||
@@ -754,16 +778,51 @@ where
|
||||
{
|
||||
let mut sl = slate.clone();
|
||||
check_ttl(w, &sl)?;
|
||||
let context = w.get_private_context(keychain_mask, sl.id.as_bytes())?;
|
||||
let mut context = w.get_private_context(keychain_mask, sl.id.as_bytes())?;
|
||||
let keychain = w.keychain(keychain_mask)?;
|
||||
let parent_key_id = w.parent_key_id();
|
||||
|
||||
// since we're now actually inserting our inputs, pick an offset and adjust
|
||||
// our contribution to the excess by offset amount
|
||||
// TODO: Post HF3, this should allow for inputs to be picked at this stage
|
||||
// as opposed to locking them prior to this stage, as the excess to this point
|
||||
// will just be the change output
|
||||
if let Some(args) = context.late_lock_args.take() {
|
||||
// Transaction was late locked, select inputs+change now
|
||||
// and insert into original context
|
||||
|
||||
let current_height = w.w2n_client().get_chain_tip()?.0;
|
||||
let mut temp_sl =
|
||||
tx::new_tx_slate(&mut *w, context.amount, false, 2, false, args.ttl_blocks)?;
|
||||
let temp_context = selection::build_send_tx(
|
||||
w,
|
||||
&keychain,
|
||||
keychain_mask,
|
||||
&mut temp_sl,
|
||||
current_height,
|
||||
args.minimum_confirmations,
|
||||
args.max_outputs as usize,
|
||||
args.num_change_outputs as usize,
|
||||
args.selection_strategy_is_use_all,
|
||||
Some(context.fee),
|
||||
parent_key_id.clone(),
|
||||
false,
|
||||
true,
|
||||
)?;
|
||||
|
||||
// Add inputs and outputs to original context
|
||||
context.input_ids = temp_context.input_ids;
|
||||
context.output_ids = temp_context.output_ids;
|
||||
|
||||
// Store the updated context
|
||||
{
|
||||
let mut batch = w.batch(keychain_mask)?;
|
||||
batch.save_private_context(sl.id.as_bytes(), &context)?;
|
||||
batch.commit()?;
|
||||
}
|
||||
|
||||
// Now do the actual locking
|
||||
tx_lock_outputs(w, keychain_mask, &sl)?;
|
||||
}
|
||||
|
||||
// Add our contribution to the offset
|
||||
sl.adjust_offset(&keychain, &context)?;
|
||||
|
||||
tx::sub_inputs_from_offset(&mut *w, keychain_mask, &context, &mut sl)?;
|
||||
selection::repopulate_tx(&mut *w, keychain_mask, &mut sl, &context, true)?;
|
||||
|
||||
tx::complete_tx(&mut *w, keychain_mask, &mut sl, &context)?;
|
||||
|
||||
@@ -25,7 +25,7 @@ use crate::SlatepackAddress;
|
||||
use ed25519_dalek::Signature as DalekSignature;
|
||||
|
||||
/// V2 Init / Send TX API Args
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct InitTxArgs {
|
||||
/// The human readable account name from which to draw outputs
|
||||
/// for the transaction, overriding whatever the active account is as set via the
|
||||
@@ -71,6 +71,10 @@ pub struct InitTxArgs {
|
||||
/// 'true', the amount field in the slate will contain the total amount locked, not the provided
|
||||
/// transaction amount
|
||||
pub estimate_only: Option<bool>,
|
||||
/// EXPERIMENTAL: if flagged, create the transaction as late-locked, i.e. don't select actual
|
||||
/// inputs until just before finalization
|
||||
#[serde(default)]
|
||||
pub late_lock: Option<bool>,
|
||||
/// Sender arguments. If present, the underlying function will also attempt to send the
|
||||
/// transaction to a destination and optionally finalize the result
|
||||
pub send_args: Option<InitTxSendArgs>,
|
||||
@@ -78,7 +82,7 @@ pub struct InitTxArgs {
|
||||
|
||||
/// Send TX API Args, for convenience functionality that inits the transaction and sends
|
||||
/// in one go
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct InitTxSendArgs {
|
||||
/// The destination, contents will depend on the particular method
|
||||
pub dest: String,
|
||||
@@ -103,6 +107,7 @@ impl Default for InitTxArgs {
|
||||
ttl_blocks: None,
|
||||
estimate_only: Some(false),
|
||||
payment_proof_recipient_address: None,
|
||||
late_lock: Some(false),
|
||||
send_args: None,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user