Remove callbacks from transaction API functions (#22)

* remove callbacks from transaction creation

* rustfmt

* add missing functions to owner api rpc

* comment fix
This commit is contained in:
Yeastplume 2019-03-14 15:05:13 +00:00 committed by GitHub
parent baa5e46d7d
commit 8cca9821bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 300 additions and 180 deletions

View file

@ -119,9 +119,7 @@ where
None => None, None => None,
}; };
let (_, mut create_fn) = tx::add_output_to_slate(&mut *w, slate, &parent_key_id, 1, message)?;
tx::add_output_to_slate(&mut *w, slate, &parent_key_id, 1, message)?;
create_fn(&mut *w, &slate.tx, PhantomData, PhantomData)?;
tx::update_message(&mut *w, slate)?; tx::update_message(&mut *w, slate)?;
w.close()?; w.close()?;
Ok(()) Ok(())

View file

@ -35,11 +35,10 @@ use crate::core::core::hash::Hashed;
use crate::core::core::Transaction; use crate::core::core::Transaction;
use crate::core::ser; use crate::core::ser;
use crate::keychain::{Identifier, Keychain}; use crate::keychain::{Identifier, Keychain};
use crate::libwallet::internal::{keys, tx, updater}; use crate::libwallet::internal::{keys, selection, tx, updater};
use crate::libwallet::slate::Slate; use crate::libwallet::slate::Slate;
use crate::libwallet::types::{ use crate::libwallet::types::{
AcctPathMapping, NodeClient, OutputData, OutputLockFn, TxLogEntry, TxWrapper, WalletBackend, AcctPathMapping, NodeClient, OutputData, TxLogEntry, TxWrapper, WalletBackend, WalletInfo,
WalletInfo,
}; };
use crate::libwallet::{Error, ErrorKind}; use crate::libwallet::{Error, ErrorKind};
use crate::util; use crate::util;
@ -625,7 +624,7 @@ where
selection_strategy_is_use_all: bool, selection_strategy_is_use_all: bool,
message: Option<String>, message: Option<String>,
target_slate_version: Option<u16>, target_slate_version: Option<u16>,
) -> Result<(Slate, OutputLockFn<W, C, K>), Error> { ) -> Result<Slate, Error> {
let mut w = self.wallet.lock(); let mut w = self.wallet.lock();
w.open_with_credentials()?; w.open_with_credentials()?;
let parent_key_id = match src_acct_name { let parent_key_id = match src_acct_name {
@ -649,7 +648,7 @@ where
let mut slate = tx::new_tx_slate(&mut *w, amount, 2)?; let mut slate = tx::new_tx_slate(&mut *w, amount, 2)?;
let (context, lock_fn) = tx::add_inputs_to_slate( let context = tx::add_inputs_to_slate(
&mut *w, &mut *w,
&mut slate, &mut slate,
minimum_confirmations, minimum_confirmations,
@ -674,7 +673,7 @@ where
if let Some(v) = target_slate_version { if let Some(v) = target_slate_version {
slate.version_info.orig_version = v; slate.version_info.orig_version = v;
} }
Ok((slate, lock_fn)) Ok(slate)
} }
/// Estimates the amount to be locked and fee for the transaction without creating one /// Estimates the amount to be locked and fee for the transaction without creating one
@ -746,14 +745,14 @@ where
} }
/// Lock outputs associated with a given slate/transaction /// Lock outputs associated with a given slate/transaction
pub fn tx_lock_outputs( /// and create any outputs needed
&self, pub fn tx_lock_outputs(&self, slate: &Slate) -> Result<(), Error> {
slate: &Slate,
mut lock_fn: OutputLockFn<W, C, K>,
) -> Result<(), Error> {
let mut w = self.wallet.lock(); let mut w = self.wallet.lock();
w.open_with_credentials()?; w.open_with_credentials()?;
lock_fn(&mut *w, &slate.tx, PhantomData, PhantomData)?; let context = w.get_private_context(slate.id.as_bytes())?;
w.open_with_credentials()?;
selection::lock_tx_context(&mut *w, slate, &context)?;
w.close()?;
Ok(()) Ok(())
} }

View file

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//! JSON-RPC Stub generation for the Foreign API //! JSON-RPC Stub generation for the Owner API
use uuid::Uuid; use uuid::Uuid;
@ -202,6 +202,42 @@ pub trait OwnerRpc {
minimum_confirmations: u64, minimum_confirmations: u64,
) -> Result<(bool, WalletInfo), ErrorKind>; ) -> Result<(bool, WalletInfo), ErrorKind>;
/**
Networked version of [Owner::estimate_initiate_tx](struct.Owner.html#method.initiate_tx).
```
# grin_wallet_api::doctest_helper_json_rpc_owner_assert_response!(
{
"jsonrpc": "2.0",
"method": "initiate_tx",
"params": [null, 0, 0, 10, 0, false, "my message", null],
"id": 1
},
{
"jsonrpc": "2.0",
"result": {
"Err": {
"CallbackImpl": "Error opening wallet"
}
},
"id": 1
}
# );
```
*/
fn initiate_tx(
&self,
src_acct_name: Option<String>,
amount: u64,
minimum_confirmations: u64,
max_outputs: usize,
num_change_outputs: usize,
selection_strategy_is_use_all: bool,
message: Option<String>,
target_slate_version: Option<u16>,
) -> Result<Slate, ErrorKind>;
/** /**
Networked version of [Owner::estimate_initiate_tx](struct.Owner.html#method.estimate_initiate_tx). Networked version of [Owner::estimate_initiate_tx](struct.Owner.html#method.estimate_initiate_tx).
@ -236,6 +272,53 @@ pub trait OwnerRpc {
selection_strategy_is_use_all: bool, selection_strategy_is_use_all: bool,
) -> Result<(/* total */ u64, /* fee */ u64), ErrorKind>; ) -> Result<(/* total */ u64, /* fee */ u64), ErrorKind>;
/**
Networked version of [Owner::tx_lock_outputs](struct.Owner.html#method.tx_lock_outputs).
```
# grin_wallet_api::doctest_helper_json_rpc_owner_assert_response!(
{
"jsonrpc": "2.0",
"method": "tx_lock_outputs",
"params": [{
"version_info": {
"version": 2,
"orig_version": 2,
"min_compat_version": 0
},
"amount": 0,
"fee": 0,
"height": 0,
"id": "414bad48-3386-4fa7-8483-72384c886ba3",
"lock_height": 0,
"num_participants": 2,
"participant_data": [],
"tx": {
"body": {
"inputs": [],
"kernels": [],
"outputs": []
},
"offset": "0000000000000000000000000000000000000000000000000000000000000000"
}
}],
"id": 1
},
{
"jsonrpc": "2.0",
"result": {
"Err": {
"CallbackImpl": "Error opening wallet"
}
},
"id": 1
}
# );
```
*/
fn tx_lock_outputs(&self, slate: Slate) -> Result<(), ErrorKind>;
/** /**
Networked version of [Owner::finalize_tx](struct.Owner.html#method.finalize_tx). Networked version of [Owner::finalize_tx](struct.Owner.html#method.finalize_tx).
@ -555,6 +638,31 @@ where
.map_err(|e| e.kind()) .map_err(|e| e.kind())
} }
fn initiate_tx(
&self,
src_acct_name: Option<String>,
amount: u64,
minimum_confirmations: u64,
max_outputs: usize,
num_change_outputs: usize,
selection_strategy_is_use_all: bool,
message: Option<String>,
target_slate_version: Option<u16>,
) -> Result<Slate, ErrorKind> {
Owner::initiate_tx(
self,
src_acct_name.as_ref().map(String::as_str),
amount,
minimum_confirmations,
max_outputs,
num_change_outputs,
selection_strategy_is_use_all,
message,
target_slate_version,
)
.map_err(|e| e.kind())
}
fn estimate_initiate_tx( fn estimate_initiate_tx(
&self, &self,
src_acct_name: Option<String>, src_acct_name: Option<String>,
@ -581,6 +689,10 @@ where
Ok(slate) Ok(slate)
} }
fn tx_lock_outputs(&self, mut slate: Slate) -> Result<(), ErrorKind> {
Owner::tx_lock_outputs(self, &mut slate).map_err(|e| e.kind())
}
fn cancel_tx(&self, tx_id: Option<u32>, tx_slate_id: Option<Uuid>) -> Result<(), ErrorKind> { fn cancel_tx(&self, tx_id: Option<u32>, tx_slate_id: Option<Uuid>) -> Result<(), ErrorKind> {
Owner::cancel_tx(self, tx_id, tx_slate_id).map_err(|e| e.kind()) Owner::cancel_tx(self, tx_id, tx_slate_id).map_err(|e| e.kind())
} }

View file

@ -14,7 +14,7 @@
//! Selection of inputs for building transactions //! Selection of inputs for building transactions
use crate::core::core::{amount_to_hr_string, Transaction}; use crate::core::core::amount_to_hr_string;
use crate::core::libtx::{build, tx_fee}; use crate::core::libtx::{build, tx_fee};
use crate::error::{Error, ErrorKind}; use crate::error::{Error, ErrorKind};
use crate::internal::keys; use crate::internal::keys;
@ -22,7 +22,6 @@ use crate::keychain::{Identifier, Keychain};
use crate::slate::Slate; use crate::slate::Slate;
use crate::types::*; use crate::types::*;
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData;
/// Initialize a transaction on the sender side, returns a corresponding /// Initialize a transaction on the sender side, returns a corresponding
/// libwallet transaction slate with the appropriate inputs selected, /// libwallet transaction slate with the appropriate inputs selected,
@ -37,7 +36,7 @@ pub fn build_send_tx<T: ?Sized, C, K>(
change_outputs: usize, change_outputs: usize,
selection_strategy_is_use_all: bool, selection_strategy_is_use_all: bool,
parent_key_id: Identifier, parent_key_id: Identifier,
) -> Result<(Context, OutputLockFn<T, C, K>), Error> ) -> Result<Context, Error>
where where
T: WalletBackend<C, K>, T: WalletBackend<C, K>,
C: NodeClient, C: NodeClient,
@ -64,87 +63,104 @@ where
let mut context = Context::new( let mut context = Context::new(
wallet.keychain().secp(), wallet.keychain().secp(),
blinding.secret_key(&keychain.secp()).unwrap(), blinding.secret_key(&keychain.secp()).unwrap(),
&parent_key_id,
); );
context.fee = fee;
// Store our private identifiers for each input // Store our private identifiers for each input
for input in inputs { for input in inputs {
context.add_input(&input.key_id, &input.mmr_index); context.add_input(&input.key_id, &input.mmr_index, input.value);
} }
let mut commits: HashMap<Identifier, Option<String>> = HashMap::new(); let mut commits: HashMap<Identifier, Option<String>> = HashMap::new();
// Store change output(s) and cached commits // Store change output(s) and cached commits
for (change_amount, id, mmr_index) in &change_amounts_derivations { for (change_amount, id, mmr_index) in &change_amounts_derivations {
context.add_output(&id, &mmr_index); context.add_output(&id, &mmr_index, *change_amount);
commits.insert( commits.insert(
id.clone(), id.clone(),
wallet.calc_commit_for_cache(*change_amount, &id)?, wallet.calc_commit_for_cache(*change_amount, &id)?,
); );
} }
let lock_inputs_in = context.get_inputs().clone(); Ok(context)
let _lock_outputs = context.get_outputs().clone(); }
let messages_in = Some(slate.participant_messages());
let slate_id_in = slate.id.clone();
let height_in = slate.height;
// Return a closure to acquire wallet lock and lock the coins being spent /// Locks all corresponding outputs in the context, creates
// so we avoid accidental double spend attempt. /// change outputs and tx log entry
let update_sender_wallet_fn = pub fn lock_tx_context<T: ?Sized, C, K>(
move |wallet: &mut T, tx: &Transaction, _: PhantomData<C>, _: PhantomData<K>| { wallet: &mut T,
let tx_entry = { slate: &Slate,
// These ensure the closure remains FnMut context: &Context,
let lock_inputs = lock_inputs_in.clone(); ) -> Result<(), Error>
let messages = messages_in.clone(); where
let slate_id = slate_id_in.clone(); T: WalletBackend<C, K>,
let height = height_in.clone(); C: NodeClient,
let mut batch = wallet.batch()?; K: Keychain,
let log_id = batch.next_tx_log_id(&parent_key_id)?; {
let mut t = TxLogEntry::new(parent_key_id.clone(), TxLogEntryType::TxSent, log_id); let mut output_commits: HashMap<Identifier, (Option<String>, u64)> = HashMap::new();
t.tx_slate_id = Some(slate_id.clone()); // Store cached commits before locking wallet
let filename = format!("{}.grintx", slate_id); for (id, _, change_amount) in &context.get_outputs() {
t.stored_tx = Some(filename); output_commits.insert(
t.fee = Some(fee); id.clone(),
let mut amount_debited = 0; (
t.num_inputs = lock_inputs.len(); wallet.calc_commit_for_cache(*change_amount, &id)?,
for id in lock_inputs { *change_amount,
let mut coin = batch.get(&id.0, &id.1).unwrap(); ),
coin.tx_log_entry = Some(log_id); );
amount_debited = amount_debited + coin.value; }
batch.lock_output(&mut coin)?;
}
t.amount_debited = amount_debited; let tx_entry = {
t.messages = messages; let lock_inputs = context.get_inputs().clone();
let messages = Some(slate.participant_messages());
let slate_id = slate.id;
let height = slate.height;
let parent_key_id = context.parent_key_id.clone();
let mut batch = wallet.batch()?;
let log_id = batch.next_tx_log_id(&parent_key_id)?;
let mut t = TxLogEntry::new(parent_key_id.clone(), TxLogEntryType::TxSent, log_id);
t.tx_slate_id = Some(slate_id.clone());
let filename = format!("{}.grintx", slate_id);
t.stored_tx = Some(filename);
t.fee = Some(slate.fee);
let mut amount_debited = 0;
t.num_inputs = lock_inputs.len();
for id in lock_inputs {
let mut coin = batch.get(&id.0, &id.1).unwrap();
coin.tx_log_entry = Some(log_id);
amount_debited = amount_debited + coin.value;
batch.lock_output(&mut coin)?;
}
// write the output representing our change t.amount_debited = amount_debited;
for (change_amount, id, _) in &change_amounts_derivations { t.messages = messages;
t.num_outputs += 1;
t.amount_credited += change_amount;
let commit = commits.get(&id).unwrap().clone();
batch.save(OutputData {
root_key_id: parent_key_id.clone(),
key_id: id.clone(),
n_child: id.to_path().last_path_index(),
commit: commit,
mmr_index: None,
value: change_amount.clone(),
status: OutputStatus::Unconfirmed,
height: height,
lock_height: 0,
is_coinbase: false,
tx_log_entry: Some(log_id),
})?;
}
batch.save_tx_log_entry(t.clone(), &parent_key_id)?;
batch.commit()?;
t
};
wallet.store_tx(&format!("{}", tx_entry.tx_slate_id.unwrap()), tx)?;
Ok(())
};
Ok((context, Box::new(update_sender_wallet_fn))) // write the output representing our change
for (id, _, _) in &context.get_outputs() {
t.num_outputs += 1;
let (commit, change_amount) = output_commits.get(&id).unwrap().clone();
t.amount_credited += change_amount;
batch.save(OutputData {
root_key_id: parent_key_id.clone(),
key_id: id.clone(),
n_child: id.to_path().last_path_index(),
commit: commit,
mmr_index: None,
value: change_amount.clone(),
status: OutputStatus::Unconfirmed,
height: height,
lock_height: 0,
is_coinbase: false,
tx_log_entry: Some(log_id),
})?;
}
batch.save_tx_log_entry(t.clone(), &parent_key_id)?;
batch.commit()?;
t
};
wallet.store_tx(&format!("{}", tx_entry.tx_slate_id.unwrap()), &slate.tx)?;
Ok(())
} }
/// Creates a new output in the wallet for the recipient, /// Creates a new output in the wallet for the recipient,
@ -155,7 +171,7 @@ pub fn build_recipient_output<T: ?Sized, C, K>(
wallet: &mut T, wallet: &mut T,
slate: &mut Slate, slate: &mut Slate,
parent_key_id: Identifier, parent_key_id: Identifier,
) -> Result<(Identifier, Context, OutputLockFn<T, C, K>), Error> ) -> Result<(Identifier, Context), Error>
where where
T: WalletBackend<C, K>, T: WalletBackend<C, K>,
C: NodeClient, C: NodeClient,
@ -179,45 +195,36 @@ where
blinding blinding
.secret_key(wallet.keychain().clone().secp()) .secret_key(wallet.keychain().clone().secp())
.unwrap(), .unwrap(),
&parent_key_id,
); );
context.add_output(&key_id, &None); context.add_output(&key_id, &None, amount);
let messages_in = Some(slate.participant_messages()); let messages = Some(slate.participant_messages());
let commit = wallet.calc_commit_for_cache(amount, &key_id_inner)?;
let mut batch = wallet.batch()?;
let log_id = batch.next_tx_log_id(&parent_key_id)?;
let mut t = TxLogEntry::new(parent_key_id.clone(), TxLogEntryType::TxReceived, log_id);
t.tx_slate_id = Some(slate_id);
t.amount_credited = amount;
t.num_outputs = 1;
t.messages = messages;
batch.save(OutputData {
root_key_id: parent_key_id.clone(),
key_id: key_id_inner.clone(),
mmr_index: None,
n_child: key_id_inner.to_path().last_path_index(),
commit: commit,
value: amount,
status: OutputStatus::Unconfirmed,
height: height,
lock_height: 0,
is_coinbase: false,
tx_log_entry: Some(log_id),
})?;
batch.save_tx_log_entry(t, &parent_key_id)?;
batch.commit()?;
// Create closure that adds the output to recipient's wallet Ok((key_id, context))
// (up to the caller to decide when to do)
let wallet_add_fn =
move |wallet: &mut T, _tx: &Transaction, _: PhantomData<C>, _: PhantomData<K>| {
// Ensure closure remains FnMut
let messages = messages_in.clone();
let commit = wallet.calc_commit_for_cache(amount, &key_id_inner)?;
let mut batch = wallet.batch()?;
let log_id = batch.next_tx_log_id(&parent_key_id)?;
let mut t = TxLogEntry::new(parent_key_id.clone(), TxLogEntryType::TxReceived, log_id);
t.tx_slate_id = Some(slate_id);
t.amount_credited = amount;
t.num_outputs = 1;
t.messages = messages;
batch.save(OutputData {
root_key_id: parent_key_id.clone(),
key_id: key_id_inner.clone(),
mmr_index: None,
n_child: key_id_inner.to_path().last_path_index(),
commit: commit,
value: amount,
status: OutputStatus::Unconfirmed,
height: height,
lock_height: 0,
is_coinbase: false,
tx_log_entry: Some(log_id),
})?;
batch.save_tx_log_entry(t, &parent_key_id)?;
batch.commit()?;
//TODO: Check whether we want to call this
//wallet.store_tx(&format!("{}", t.tx_slate_id.unwrap()), tx)?;
Ok(())
};
Ok((key_id, context, Box::new(wallet_add_fn)))
} }
/// Builds a transaction to send to someone from the HD seed associated with the /// Builds a transaction to send to someone from the HD seed associated with the

View file

@ -19,7 +19,7 @@ use uuid::Uuid;
use crate::internal::{selection, updater}; use crate::internal::{selection, updater};
use crate::keychain::{Identifier, Keychain}; use crate::keychain::{Identifier, Keychain};
use crate::slate::Slate; use crate::slate::Slate;
use crate::types::{Context, NodeClient, OutputLockFn, TxLogEntryType, WalletBackend}; use crate::types::{Context, NodeClient, TxLogEntryType, WalletBackend};
use crate::{Error, ErrorKind}; use crate::{Error, ErrorKind};
/// Creates a new slate for a transaction, can be called by anyone involved in /// Creates a new slate for a transaction, can be called by anyone involved in
@ -99,7 +99,7 @@ pub fn add_inputs_to_slate<T: ?Sized, C, K>(
parent_key_id: &Identifier, parent_key_id: &Identifier,
participant_id: usize, participant_id: usize,
message: Option<String>, message: Option<String>,
) -> Result<(Context, OutputLockFn<T, C, K>), Error> ) -> Result<Context, Error>
where where
T: WalletBackend<C, K>, T: WalletBackend<C, K>,
C: NodeClient, C: NodeClient,
@ -115,7 +115,7 @@ where
// according to plan // according to plan
// This function is just a big helper to do all of that, in theory // This function is just a big helper to do all of that, in theory
// this process can be split up in any way // this process can be split up in any way
let (mut context, sender_lock_fn) = selection::build_send_tx( let mut context = selection::build_send_tx(
wallet, wallet,
slate, slate,
minimum_confirmations, minimum_confirmations,
@ -136,7 +136,7 @@ where
message, message,
)?; )?;
Ok((context, sender_lock_fn)) Ok(context)
} }
/// Add outputs to the slate, becoming the recipient /// Add outputs to the slate, becoming the recipient
@ -146,15 +146,14 @@ pub fn add_output_to_slate<T: ?Sized, C, K>(
parent_key_id: &Identifier, parent_key_id: &Identifier,
participant_id: usize, participant_id: usize,
message: Option<String>, message: Option<String>,
) -> Result<(Context, OutputLockFn<T, C, K>), Error> ) -> Result<Context, Error>
where where
T: WalletBackend<C, K>, T: WalletBackend<C, K>,
C: NodeClient, C: NodeClient,
K: Keychain, K: Keychain,
{ {
// create an output using the amount in the slate // create an output using the amount in the slate
let (_, mut context, create_fn) = let (_, mut context) = selection::build_recipient_output(wallet, slate, parent_key_id.clone())?;
selection::build_recipient_output(wallet, slate, parent_key_id.clone())?;
// fill public keys // fill public keys
let _ = slate.fill_round_1( let _ = slate.fill_round_1(
@ -173,7 +172,7 @@ where
participant_id, participant_id,
)?; )?;
Ok((context, create_fn)) Ok(context)
} }
/// Complete a transaction as the sender /// Complete a transaction as the sender

View file

@ -30,13 +30,8 @@ use serde;
use serde_json; use serde_json;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::marker::PhantomData;
use uuid::Uuid; use uuid::Uuid;
/// Lock function type
pub type OutputLockFn<T, C, K> =
Box<dyn FnMut(&mut T, &Transaction, PhantomData<C>, PhantomData<K>) -> Result<(), Error>>;
/// Combined trait to allow dynamic wallet dispatch /// Combined trait to allow dynamic wallet dispatch
pub trait WalletInst<C, K>: WalletBackend<C, K> + Send + Sync + 'static pub trait WalletInst<C, K>: WalletBackend<C, K> + Send + Sync + 'static
where where
@ -377,23 +372,28 @@ impl fmt::Display for OutputStatus {
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
/// Holds the context for a single aggsig transaction /// Holds the context for a single aggsig transaction
pub struct Context { pub struct Context {
/// Parent key id
pub parent_key_id: Identifier,
/// Secret key (of which public is shared) /// Secret key (of which public is shared)
pub sec_key: SecretKey, pub sec_key: SecretKey,
/// Secret nonce (of which public is shared) /// Secret nonce (of which public is shared)
/// (basically a SecretKey) /// (basically a SecretKey)
pub sec_nonce: SecretKey, pub sec_nonce: SecretKey,
/// store my outputs between invocations /// store my outputs + amounts between invocations
pub output_ids: Vec<(Identifier, Option<u64>)>, /// Id, mmr_index (if known), amount
pub output_ids: Vec<(Identifier, Option<u64>, u64)>,
/// store my inputs /// store my inputs
pub input_ids: Vec<(Identifier, Option<u64>)>, /// Id, mmr_index (if known), amount
pub input_ids: Vec<(Identifier, Option<u64>, u64)>,
/// store the calculated fee /// store the calculated fee
pub fee: u64, pub fee: u64,
} }
impl Context { impl Context {
/// Create a new context with defaults /// Create a new context with defaults
pub fn new(secp: &secp::Secp256k1, sec_key: SecretKey) -> Context { pub fn new(secp: &secp::Secp256k1, sec_key: SecretKey, parent_key_id: &Identifier) -> Context {
Context { Context {
parent_key_id: parent_key_id.clone(),
sec_key: sec_key, sec_key: sec_key,
sec_nonce: aggsig::create_secnonce(secp).unwrap(), sec_nonce: aggsig::create_secnonce(secp).unwrap(),
input_ids: vec![], input_ids: vec![],
@ -406,23 +406,25 @@ impl Context {
impl Context { impl Context {
/// Tracks an output contributing to my excess value (if it needs to /// Tracks an output contributing to my excess value (if it needs to
/// be kept between invocations /// be kept between invocations
pub fn add_output(&mut self, output_id: &Identifier, mmr_index: &Option<u64>) { pub fn add_output(&mut self, output_id: &Identifier, mmr_index: &Option<u64>, amount: u64) {
self.output_ids.push((output_id.clone(), mmr_index.clone())); self.output_ids
.push((output_id.clone(), mmr_index.clone(), amount));
} }
/// Returns all stored outputs /// Returns all stored outputs
pub fn get_outputs(&self) -> Vec<(Identifier, Option<u64>)> { pub fn get_outputs(&self) -> Vec<(Identifier, Option<u64>, u64)> {
self.output_ids.clone() self.output_ids.clone()
} }
/// Tracks IDs of my inputs into the transaction /// Tracks IDs of my inputs into the transaction
/// be kept between invocations /// be kept between invocations
pub fn add_input(&mut self, input_id: &Identifier, mmr_index: &Option<u64>) { pub fn add_input(&mut self, input_id: &Identifier, mmr_index: &Option<u64>, amount: u64) {
self.input_ids.push((input_id.clone(), mmr_index.clone())); self.input_ids
.push((input_id.clone(), mmr_index.clone(), amount));
} }
/// Returns all stored input identifiers /// Returns all stored input identifiers
pub fn get_inputs(&self) -> Vec<(Identifier, Option<u64>)> { pub fn get_inputs(&self) -> Vec<(Identifier, Option<u64>, u64)> {
self.input_ids.clone() self.input_ids.clone()
} }

View file

@ -14,7 +14,7 @@
//! core::libtx specific tests //! core::libtx specific tests
use self::core::core::transaction; use self::core::core::transaction;
use self::core::libtx::{aggsig, proof}; use self::core::libtx::{aggsig, proof};
use self::keychain::{BlindSum, BlindingFactor, ExtKeychain, Keychain}; use self::keychain::{BlindSum, BlindingFactor, ExtKeychain, ExtKeychainPath, Keychain};
use self::util::secp; use self::util::secp;
use self::util::secp::key::{PublicKey, SecretKey}; use self::util::secp::key::{PublicKey, SecretKey};
use grin_core as core; use grin_core as core;
@ -29,6 +29,7 @@ fn kernel_sig_msg() -> secp::Message {
#[test] #[test]
fn aggsig_sender_receiver_interaction() { fn aggsig_sender_receiver_interaction() {
let parent = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
let sender_keychain = ExtKeychain::from_random_seed(true).unwrap(); let sender_keychain = ExtKeychain::from_random_seed(true).unwrap();
let receiver_keychain = ExtKeychain::from_random_seed(true).unwrap(); let receiver_keychain = ExtKeychain::from_random_seed(true).unwrap();
@ -71,7 +72,7 @@ fn aggsig_sender_receiver_interaction() {
let blind = blinding_factor.secret_key(&keychain.secp()).unwrap(); let blind = blinding_factor.secret_key(&keychain.secp()).unwrap();
s_cx = Context::new(&keychain.secp(), blind); s_cx = Context::new(&keychain.secp(), blind, &parent);
s_cx.get_public_keys(&keychain.secp()) s_cx.get_public_keys(&keychain.secp())
}; };
@ -85,9 +86,9 @@ fn aggsig_sender_receiver_interaction() {
// let blind = blind_sum.secret_key(&keychain.secp())?; // let blind = blind_sum.secret_key(&keychain.secp())?;
let blind = keychain.derive_key(0, &key_id).unwrap(); let blind = keychain.derive_key(0, &key_id).unwrap();
rx_cx = Context::new(&keychain.secp(), blind); rx_cx = Context::new(&keychain.secp(), blind, &parent);
let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp()); let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp());
rx_cx.add_output(&key_id, &None); rx_cx.add_output(&key_id, &None, 0);
pub_nonce_sum = PublicKey::from_combination( pub_nonce_sum = PublicKey::from_combination(
keychain.secp(), keychain.secp(),
@ -233,6 +234,7 @@ fn aggsig_sender_receiver_interaction() {
#[test] #[test]
fn aggsig_sender_receiver_interaction_offset() { fn aggsig_sender_receiver_interaction_offset() {
let parent = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
let sender_keychain = ExtKeychain::from_random_seed(true).unwrap(); let sender_keychain = ExtKeychain::from_random_seed(true).unwrap();
let receiver_keychain = ExtKeychain::from_random_seed(true).unwrap(); let receiver_keychain = ExtKeychain::from_random_seed(true).unwrap();
@ -288,7 +290,7 @@ fn aggsig_sender_receiver_interaction_offset() {
let blind = blinding_factor.secret_key(&keychain.secp()).unwrap(); let blind = blinding_factor.secret_key(&keychain.secp()).unwrap();
s_cx = Context::new(&keychain.secp(), blind); s_cx = Context::new(&keychain.secp(), blind, &parent);
s_cx.get_public_keys(&keychain.secp()) s_cx.get_public_keys(&keychain.secp())
}; };
@ -301,9 +303,9 @@ fn aggsig_sender_receiver_interaction_offset() {
let blind = keychain.derive_key(0, &key_id).unwrap(); let blind = keychain.derive_key(0, &key_id).unwrap();
rx_cx = Context::new(&keychain.secp(), blind); rx_cx = Context::new(&keychain.secp(), blind, &parent);
let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp()); let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp());
rx_cx.add_output(&key_id, &None); rx_cx.add_output(&key_id, &None, 0);
pub_nonce_sum = PublicKey::from_combination( pub_nonce_sum = PublicKey::from_combination(
keychain.secp(), keychain.secp(),

View file

@ -244,7 +244,7 @@ pub fn send(
args.message.clone(), args.message.clone(),
args.target_slate_version, args.target_slate_version,
); );
let (mut slate, lock_fn) = match result { let mut slate = match result {
Ok(s) => { Ok(s) => {
info!( info!(
"Tx created: {} grin to {} (strategy '{}')", "Tx created: {} grin to {} (strategy '{}')",
@ -268,7 +268,7 @@ pub fn send(
}; };
if adapter.supports_sync() { if adapter.supports_sync() {
slate = adapter.send_tx_sync(&args.dest, &slate)?; slate = adapter.send_tx_sync(&args.dest, &slate)?;
api.tx_lock_outputs(&slate, lock_fn)?; api.tx_lock_outputs(&slate)?;
if args.method == "self" { if args.method == "self" {
controller::foreign_single_use(wallet, |api| { controller::foreign_single_use(wallet, |api| {
api.receive_tx(&mut slate, Some(&args.dest), None)?; api.receive_tx(&mut slate, Some(&args.dest), None)?;
@ -282,7 +282,7 @@ pub fn send(
api.finalize_tx(&mut slate)?; api.finalize_tx(&mut slate)?;
} else { } else {
adapter.send_tx_async(&args.dest, &slate)?; adapter.send_tx_async(&args.dest, &slate)?;
api.tx_lock_outputs(&slate, lock_fn)?; api.tx_lock_outputs(&slate)?;
} }
if adapter.supports_sync() { if adapter.supports_sync() {
let result = api.post_tx(&slate.tx, args.fluff); let result = api.post_tx(&slate.tx, args.fluff);

View file

@ -331,7 +331,7 @@ where
args.message, args.message,
args.target_slate_version, args.target_slate_version,
); );
let (mut slate, lock_fn) = match result { let mut slate = match result {
Ok(s) => { Ok(s) => {
info!( info!(
"Tx created: {} grin to {} (strategy '{}')", "Tx created: {} grin to {} (strategy '{}')",
@ -371,7 +371,7 @@ where
))?; ))?;
} }
} }
api.tx_lock_outputs(&slate, lock_fn)?; api.tx_lock_outputs(&slate)?;
if args.method != "file" { if args.method != "file" {
api.finalize_tx(&mut slate)?; api.finalize_tx(&mut slate)?;
} }

View file

@ -194,7 +194,7 @@ where
C: NodeClient, C: NodeClient,
K: keychain::Keychain, K: keychain::Keychain,
{ {
let (slate_i, lock_fn) = api.initiate_tx( let slate_i = api.initiate_tx(
None, // account None, // account
amount, // amount amount, // amount
2, // minimum confirmations 2, // minimum confirmations
@ -204,7 +204,7 @@ where
None, None, None, None,
)?; )?;
let mut slate = client.send_tx_slate_direct(dest, &slate_i)?; let mut slate = client.send_tx_slate_direct(dest, &slate_i)?;
api.tx_lock_outputs(&slate, lock_fn)?; api.tx_lock_outputs(&slate)?;
api.finalize_tx(&mut slate)?; api.finalize_tx(&mut slate)?;
api.post_tx(&slate.tx, false)?; // mines a block api.post_tx(&slate.tx, false)?; // mines a block
Ok(()) Ok(())

View file

@ -177,7 +177,7 @@ fn accounts_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
} }
wallet::controller::owner_single_use(wallet1.clone(), |api| { wallet::controller::owner_single_use(wallet1.clone(), |api| {
let (mut slate, lock_fn) = api.initiate_tx( let mut slate = api.initiate_tx(
None, reward, // amount None, reward, // amount
2, // minimum confirmations 2, // minimum confirmations
500, // max outputs 500, // max outputs
@ -186,7 +186,7 @@ fn accounts_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
None, None, None, None,
)?; )?;
slate = client1.send_tx_slate_direct("wallet2", &slate)?; slate = client1.send_tx_slate_direct("wallet2", &slate)?;
api.tx_lock_outputs(&slate, lock_fn)?; api.tx_lock_outputs(&slate)?;
api.finalize_tx(&mut slate)?; api.finalize_tx(&mut slate)?;
api.post_tx(&slate.tx, false)?; api.post_tx(&slate.tx, false)?;
Ok(()) Ok(())

View file

@ -155,7 +155,7 @@ fn check_repair_impl(test_dir: &str) -> Result<(), libwallet::Error> {
// perform a transaction, but don't let it finish // perform a transaction, but don't let it finish
wallet::controller::owner_single_use(wallet1.clone(), |api| { wallet::controller::owner_single_use(wallet1.clone(), |api| {
// send to send // send to send
let (mut slate, lock_fn) = api.initiate_tx( let mut slate = api.initiate_tx(
None, None,
reward * 2, // amount reward * 2, // amount
cm, // minimum confirmations cm, // minimum confirmations
@ -169,7 +169,7 @@ fn check_repair_impl(test_dir: &str) -> Result<(), libwallet::Error> {
let file_adapter = FileWalletCommAdapter::new(); let file_adapter = FileWalletCommAdapter::new();
let send_file = format!("{}/part_tx_1.tx", test_dir); let send_file = format!("{}/part_tx_1.tx", test_dir);
file_adapter.send_tx_async(&send_file, &mut slate)?; file_adapter.send_tx_async(&send_file, &mut slate)?;
api.tx_lock_outputs(&slate, lock_fn)?; api.tx_lock_outputs(&slate)?;
Ok(()) Ok(())
})?; })?;

View file

@ -103,7 +103,7 @@ fn file_exchange_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
assert_eq!(wallet1_info.last_confirmed_height, bh); assert_eq!(wallet1_info.last_confirmed_height, bh);
assert_eq!(wallet1_info.total, bh * reward); assert_eq!(wallet1_info.total, bh * reward);
// send to send // send to send
let (mut slate, lock_fn) = api.initiate_tx( let mut slate = api.initiate_tx(
Some("mining"), Some("mining"),
reward * 2, // amount reward * 2, // amount
2, // minimum confirmations 2, // minimum confirmations
@ -116,7 +116,7 @@ fn file_exchange_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
// output tx file // output tx file
let file_adapter = FileWalletCommAdapter::new(); let file_adapter = FileWalletCommAdapter::new();
file_adapter.send_tx_async(&send_file, &mut slate)?; file_adapter.send_tx_async(&send_file, &mut slate)?;
api.tx_lock_outputs(&slate, lock_fn)?; api.tx_lock_outputs(&slate)?;
Ok(()) Ok(())
})?; })?;

View file

@ -101,7 +101,7 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
assert_eq!(wallet1_info.last_confirmed_height, bh); assert_eq!(wallet1_info.last_confirmed_height, bh);
assert_eq!(wallet1_info.total, bh * reward); assert_eq!(wallet1_info.total, bh * reward);
// send to send // send to send
let (mut slate, lock_fn) = api.initiate_tx( let mut slate = api.initiate_tx(
Some("mining"), Some("mining"),
reward * 2, // amount reward * 2, // amount
2, // minimum confirmations 2, // minimum confirmations
@ -114,7 +114,7 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
// output tx file // output tx file
let file_adapter = FileWalletCommAdapter::new(); let file_adapter = FileWalletCommAdapter::new();
file_adapter.send_tx_async(&send_file, &mut slate)?; file_adapter.send_tx_async(&send_file, &mut slate)?;
api.tx_lock_outputs(&slate, lock_fn)?; api.tx_lock_outputs(&slate)?;
Ok(()) Ok(())
})?; })?;
@ -198,7 +198,7 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| { wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
// note this will increment the block count as part of the transaction "Posting" // note this will increment the block count as part of the transaction "Posting"
let (slate_i, lock_fn) = sender_api.initiate_tx( let slate_i = sender_api.initiate_tx(
None, None,
amount * 2, // amount amount * 2, // amount
2, // minimum confirmations 2, // minimum confirmations
@ -209,7 +209,7 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
None, None,
)?; )?;
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
sender_api.tx_lock_outputs(&slate, lock_fn)?; sender_api.tx_lock_outputs(&slate)?;
sender_api.finalize_tx(&mut slate)?; sender_api.finalize_tx(&mut slate)?;
Ok(()) Ok(())
})?; })?;

View file

@ -235,7 +235,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
let mut slate = Slate::blank(1); let mut slate = Slate::blank(1);
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| { wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
// note this will increment the block count as part of the transaction "Posting" // note this will increment the block count as part of the transaction "Posting"
let (slate_i, lock_fn) = sender_api.initiate_tx( let slate_i = sender_api.initiate_tx(
None, amount, // amount None, amount, // amount
2, // minimum confirmations 2, // minimum confirmations
500, // max outputs 500, // max outputs
@ -244,7 +244,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
None, None, None, None,
)?; )?;
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
sender_api.tx_lock_outputs(&slate, lock_fn)?; sender_api.tx_lock_outputs(&slate)?;
sender_api.finalize_tx(&mut slate)?; sender_api.finalize_tx(&mut slate)?;
sender_api.post_tx(&slate.tx, false)?; sender_api.post_tx(&slate.tx, false)?;
Ok(()) Ok(())
@ -256,7 +256,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
// Send some to wallet 3 // Send some to wallet 3
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| { wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
// note this will increment the block count as part of the transaction "Posting" // note this will increment the block count as part of the transaction "Posting"
let (slate_i, lock_fn) = sender_api.initiate_tx( let slate_i = sender_api.initiate_tx(
None, None,
amount * 2, // amount amount * 2, // amount
2, // minimum confirmations 2, // minimum confirmations
@ -267,7 +267,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
None, None,
)?; )?;
slate = client1.send_tx_slate_direct("wallet3", &slate_i)?; slate = client1.send_tx_slate_direct("wallet3", &slate_i)?;
sender_api.tx_lock_outputs(&slate, lock_fn)?; sender_api.tx_lock_outputs(&slate)?;
sender_api.finalize_tx(&mut slate)?; sender_api.finalize_tx(&mut slate)?;
sender_api.post_tx(&slate.tx, false)?; sender_api.post_tx(&slate.tx, false)?;
Ok(()) Ok(())
@ -279,7 +279,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
// Wallet3 to wallet 2 // Wallet3 to wallet 2
wallet::controller::owner_single_use(wallet3.clone(), |sender_api| { wallet::controller::owner_single_use(wallet3.clone(), |sender_api| {
// note this will increment the block count as part of the transaction "Posting" // note this will increment the block count as part of the transaction "Posting"
let (slate_i, lock_fn) = sender_api.initiate_tx( let slate_i = sender_api.initiate_tx(
None, None,
amount * 3, // amount amount * 3, // amount
2, // minimum confirmations 2, // minimum confirmations
@ -290,7 +290,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
None, None,
)?; )?;
slate = client3.send_tx_slate_direct("wallet2", &slate_i)?; slate = client3.send_tx_slate_direct("wallet2", &slate_i)?;
sender_api.tx_lock_outputs(&slate, lock_fn)?; sender_api.tx_lock_outputs(&slate)?;
sender_api.finalize_tx(&mut slate)?; sender_api.finalize_tx(&mut slate)?;
sender_api.post_tx(&slate.tx, false)?; sender_api.post_tx(&slate.tx, false)?;
Ok(()) Ok(())
@ -308,7 +308,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
// Wallet3 to wallet 2 again (to another account) // Wallet3 to wallet 2 again (to another account)
wallet::controller::owner_single_use(wallet3.clone(), |sender_api| { wallet::controller::owner_single_use(wallet3.clone(), |sender_api| {
// note this will increment the block count as part of the transaction "Posting" // note this will increment the block count as part of the transaction "Posting"
let (slate_i, lock_fn) = sender_api.initiate_tx( let slate_i = sender_api.initiate_tx(
None, None,
amount * 3, // amount amount * 3, // amount
2, // minimum confirmations 2, // minimum confirmations
@ -319,7 +319,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
None, None,
)?; )?;
slate = client3.send_tx_slate_direct("wallet2", &slate_i)?; slate = client3.send_tx_slate_direct("wallet2", &slate_i)?;
sender_api.tx_lock_outputs(&slate, lock_fn)?; sender_api.tx_lock_outputs(&slate)?;
sender_api.finalize_tx(&mut slate)?; sender_api.finalize_tx(&mut slate)?;
sender_api.post_tx(&slate.tx, false)?; sender_api.post_tx(&slate.tx, false)?;
Ok(()) Ok(())

View file

@ -84,7 +84,7 @@ fn self_send_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
assert_eq!(wallet1_info.last_confirmed_height, bh); assert_eq!(wallet1_info.last_confirmed_height, bh);
assert_eq!(wallet1_info.total, bh * reward); assert_eq!(wallet1_info.total, bh * reward);
// send to send // send to send
let (mut slate, lock_fn) = api.initiate_tx( let mut slate = api.initiate_tx(
Some("mining"), Some("mining"),
reward * 2, // amount reward * 2, // amount
2, // minimum confirmations 2, // minimum confirmations
@ -94,7 +94,7 @@ fn self_send_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
None, None,
None, None,
)?; )?;
api.tx_lock_outputs(&slate, lock_fn)?; api.tx_lock_outputs(&slate)?;
// Send directly to self // Send directly to self
wallet::controller::foreign_single_use(wallet1.clone(), |api| { wallet::controller::foreign_single_use(wallet1.clone(), |api| {
api.receive_tx(&mut slate, Some("listener"), None)?; api.receive_tx(&mut slate, Some("listener"), None)?;

View file

@ -97,7 +97,7 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> {
let mut slate = Slate::blank(1); let mut slate = Slate::blank(1);
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| { wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
// note this will increment the block count as part of the transaction "Posting" // note this will increment the block count as part of the transaction "Posting"
let (slate_i, lock_fn) = sender_api.initiate_tx( let slate_i = sender_api.initiate_tx(
None, amount, // amount None, amount, // amount
2, // minimum confirmations 2, // minimum confirmations
500, // max outputs 500, // max outputs
@ -106,7 +106,7 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> {
None, None, None, None,
)?; )?;
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
sender_api.tx_lock_outputs(&slate, lock_fn)?; sender_api.tx_lock_outputs(&slate)?;
sender_api.finalize_tx(&mut slate)?; sender_api.finalize_tx(&mut slate)?;
Ok(()) Ok(())
})?; })?;
@ -129,6 +129,7 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> {
assert!(!tx.confirmed); assert!(!tx.confirmed);
assert!(tx.confirmation_ts.is_none()); assert!(tx.confirmation_ts.is_none());
assert_eq!(tx.amount_debited - tx.amount_credited, fee + amount); assert_eq!(tx.amount_debited - tx.amount_credited, fee + amount);
println!("tx: {:?}", tx);
assert_eq!(Some(fee), tx.fee); assert_eq!(Some(fee), tx.fee);
Ok(()) Ok(())
})?; })?;
@ -258,7 +259,7 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> {
// the stored transaction instead // the stored transaction instead
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| { wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
// note this will increment the block count as part of the transaction "Posting" // note this will increment the block count as part of the transaction "Posting"
let (slate_i, lock_fn) = sender_api.initiate_tx( let slate_i = sender_api.initiate_tx(
None, None,
amount * 2, // amount amount * 2, // amount
2, // minimum confirmations 2, // minimum confirmations
@ -269,7 +270,7 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> {
None, None,
)?; )?;
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
sender_api.tx_lock_outputs(&slate, lock_fn)?; sender_api.tx_lock_outputs(&slate)?;
sender_api.finalize_tx(&mut slate)?; sender_api.finalize_tx(&mut slate)?;
Ok(()) Ok(())
})?; })?;
@ -357,7 +358,7 @@ fn tx_rollback(test_dir: &str) -> Result<(), libwallet::Error> {
let mut slate = Slate::blank(1); let mut slate = Slate::blank(1);
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| { wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
// note this will increment the block count as part of the transaction "Posting" // note this will increment the block count as part of the transaction "Posting"
let (slate_i, lock_fn) = sender_api.initiate_tx( let slate_i = sender_api.initiate_tx(
None, amount, // amount None, amount, // amount
2, // minimum confirmations 2, // minimum confirmations
500, // max outputs 500, // max outputs
@ -366,7 +367,7 @@ fn tx_rollback(test_dir: &str) -> Result<(), libwallet::Error> {
None, None, None, None,
)?; )?;
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
sender_api.tx_lock_outputs(&slate, lock_fn)?; sender_api.tx_lock_outputs(&slate)?;
sender_api.finalize_tx(&mut slate)?; sender_api.finalize_tx(&mut slate)?;
Ok(()) Ok(())
})?; })?;