Optional Slate Message (#2047)

* add optional signed message to slate

* rustfmt
This commit is contained in:
Yeastplume 2018-11-29 12:49:00 +00:00 committed by GitHub
parent b9cfcc777b
commit 16aa64bfab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 185 additions and 43 deletions

View file

@ -268,6 +268,15 @@ Other flags here are:
[host]$ grin wallet send -f -d "http://192.168.0.10:13415" 60.00 [host]$ grin wallet send -f -d "http://192.168.0.10:13415" 60.00
``` ```
* `-g` 'Message' - You can specify an optional message to include alongside your transaction data. This message is purely for informational
purposes between all transacting participants, and is not included in transaction data sent to the chain. Each participant message includes
a signature that can be verified with the participant's public key. A message can also be specified by the recipient during a `grin wallet receive`
command.
```sh
[host]$ grin wallet send -f -d "http://192.168.0.10:13415" -g "This is from Dave" 60.00
```
### outputs ### outputs
Simply displays all the the outputs in your wallet: e.g: Simply displays all the the outputs in your wallet: e.g:
@ -322,7 +331,6 @@ Transaction Log - Account 'default' - Block Height: 49
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6 Received Tx 03715cf6-f29b-4a3a-bda5-b02cba6bf0d9 2018-07-20 19:46:46.120244904 UTC false None 0 1 60.000000000 0.000000000 None 60.000000000 6 Received Tx 03715cf6-f29b-4a3a-bda5-b02cba6bf0d9 2018-07-20 19:46:46.120244904 UTC false None 0 1 60.000000000 0.000000000 None 60.000000000
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>>>>>>> master
To see the inputs/outputs associated with a particular transaction, use the `-i` switch providing the Id of the given transaction, e.g: To see the inputs/outputs associated with a particular transaction, use the `-i` switch providing the Id of the given transaction, e.g:

View file

@ -352,6 +352,7 @@ impl LocalServerContainer {
max_outputs, max_outputs,
change_outputs, change_outputs,
selection_strategy == "all", selection_strategy == "all",
None,
)?; )?;
slate = client_w.send_tx_sync(dest, &slate)?; slate = client_w.send_tx_sync(dest, &slate)?;
api.finalize_tx(&mut slate)?; api.finalize_tx(&mut slate)?;

View file

@ -969,6 +969,7 @@ fn replicate_tx_fluff_failure() {
500, // max outputs 500, // max outputs
1000, // num change outputs 1000, // num change outputs
true, // select all outputs true, // select all outputs
None,
)?; )?;
slate = client1_w.send_tx_sync(dest, &slate)?; slate = client1_w.send_tx_sync(dest, &slate)?;
api.finalize_tx(&mut slate)?; api.finalize_tx(&mut slate)?;

View file

@ -355,6 +355,10 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
e e
)) ))
})?; })?;
let message = match send_args.is_present("message") {
true => Some(send_args.value_of("message").unwrap().to_owned()),
false => None,
};
let minimum_confirmations: u64 = send_args let minimum_confirmations: u64 = send_args
.value_of("minimum_confirmations") .value_of("minimum_confirmations")
.ok_or_else(|| { .ok_or_else(|| {
@ -417,6 +421,7 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
max_outputs, max_outputs,
change_outputs, change_outputs,
selection_strategy == "all", selection_strategy == "all",
message,
); );
let (mut slate, lock_fn) = match result { let (mut slate, lock_fn) = match result {
Ok(s) => { Ok(s) => {
@ -453,11 +458,15 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
slate = adapter.send_tx_sync(dest, &slate)?; slate = adapter.send_tx_sync(dest, &slate)?;
if method == "self" { if method == "self" {
controller::foreign_single_use(wallet, |api| { controller::foreign_single_use(wallet, |api| {
api.receive_tx(&mut slate, Some(dest))?; api.receive_tx(&mut slate, Some(dest), None)?;
Ok(()) Ok(())
})?; })?;
} }
api.tx_lock_outputs(&slate, lock_fn)?; api.tx_lock_outputs(&slate, lock_fn)?;
if let Err(e) = api.verify_slate_messages(&slate) {
error!("Error validating participant messages: {}", e);
return Err(e);
}
api.finalize_tx(&mut slate)?; api.finalize_tx(&mut slate)?;
} else { } else {
adapter.send_tx_async(dest, &slate)?; adapter.send_tx_async(dest, &slate)?;
@ -481,6 +490,10 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
} }
("receive", Some(send_args)) => { ("receive", Some(send_args)) => {
let mut receive_result: Result<(), grin_wallet::libwallet::Error> = Ok(()); let mut receive_result: Result<(), grin_wallet::libwallet::Error> = Ok(());
let message = match send_args.is_present("message") {
true => Some(send_args.value_of("message").unwrap().to_owned()),
false => None,
};
let tx_file = send_args.value_of("input").ok_or_else(|| { let tx_file = send_args.value_of("input").ok_or_else(|| {
ErrorKind::GenericError("Transaction file required".to_string()) ErrorKind::GenericError("Transaction file required".to_string())
})?; })?;
@ -492,7 +505,7 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
let adapter = FileWalletCommAdapter::new(); let adapter = FileWalletCommAdapter::new();
let mut slate = adapter.receive_tx_async(tx_file)?; let mut slate = adapter.receive_tx_async(tx_file)?;
controller::foreign_single_use(wallet, |api| { controller::foreign_single_use(wallet, |api| {
api.receive_tx(&mut slate, Some(account))?; api.receive_tx(&mut slate, Some(account), message)?;
Ok(()) Ok(())
})?; })?;
let send_tx = format!("{}.response", tx_file); let send_tx = format!("{}.response", tx_file);
@ -515,6 +528,10 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
} }
let adapter = FileWalletCommAdapter::new(); let adapter = FileWalletCommAdapter::new();
let mut slate = adapter.receive_tx_async(tx_file)?; let mut slate = adapter.receive_tx_async(tx_file)?;
if let Err(e) = api.verify_slate_messages(&slate) {
error!("Error validating participant messages: {}", e);
return Err(e);
}
let _ = api.finalize_tx(&mut slate).expect("Finalize failed"); let _ = api.finalize_tx(&mut slate).expect("Finalize failed");
let result = api.post_tx(&slate.tx, fluff); let result = api.post_tx(&slate.tx, fluff);

View file

@ -246,15 +246,25 @@ fn real_main() -> i32 {
.arg(Arg::with_name("fluff") .arg(Arg::with_name("fluff")
.help("Fluff the transaction (ignore Dandelion relay protocol)") .help("Fluff the transaction (ignore Dandelion relay protocol)")
.short("f") .short("f")
.long("fluff"))) .long("fluff"))
.arg(Arg::with_name("message")
.help("Optional participant message to include")
.short("g")
.long("message")
.takes_value(true))
.arg(Arg::with_name("stored_tx") .arg(Arg::with_name("stored_tx")
.help("If present, use the previously stored Unconfirmed transaction with given id.") .help("If present, use the previously stored Unconfirmed transaction with given id.")
.short("t") .short("t")
.long("stored_tx") .long("stored_tx")
.takes_value(true)) .takes_value(true)))
.subcommand(SubCommand::with_name("receive") .subcommand(SubCommand::with_name("receive")
.about("Processes a transaction file to accept a transfer from a sender.") .about("Processes a transaction file to accept a transfer from a sender.")
.arg(Arg::with_name("message")
.help("Optional participant message to include")
.short("g")
.long("message")
.takes_value(true))
.arg(Arg::with_name("input") .arg(Arg::with_name("input")
.help("Partial transaction to process, expects the sender's transaction file.") .help("Partial transaction to process, expects the sender's transaction file.")
.short("i") .short("i")

View file

@ -171,7 +171,7 @@ where
} }
} }
fn retrieve_outputs( pub fn retrieve_outputs(
&self, &self,
req: &Request<Body>, req: &Request<Body>,
api: APIOwner<T, C, K>, api: APIOwner<T, C, K>,
@ -195,7 +195,7 @@ where
api.retrieve_outputs(show_spent, update_from_node, id) api.retrieve_outputs(show_spent, update_from_node, id)
} }
fn retrieve_txs( pub fn retrieve_txs(
&self, &self,
req: &Request<Body>, req: &Request<Body>,
api: APIOwner<T, C, K>, api: APIOwner<T, C, K>,
@ -222,7 +222,7 @@ where
api.retrieve_txs(update_from_node, tx_id, tx_slate_id) api.retrieve_txs(update_from_node, tx_id, tx_slate_id)
} }
fn retrieve_stored_tx( pub fn retrieve_stored_tx(
&self, &self,
req: &Request<Body>, req: &Request<Body>,
api: APIOwner<T, C, K>, api: APIOwner<T, C, K>,
@ -251,7 +251,7 @@ where
} }
} }
fn retrieve_summary_info( pub fn retrieve_summary_info(
&self, &self,
req: &Request<Body>, req: &Request<Body>,
mut api: APIOwner<T, C, K>, mut api: APIOwner<T, C, K>,
@ -269,7 +269,7 @@ where
api.retrieve_summary_info(update_from_node, minimum_confirmations) api.retrieve_summary_info(update_from_node, minimum_confirmations)
} }
fn node_height( pub fn node_height(
&self, &self,
_req: &Request<Body>, _req: &Request<Body>,
mut api: APIOwner<T, C, K>, mut api: APIOwner<T, C, K>,
@ -297,7 +297,7 @@ where
}) })
} }
fn issue_send_tx( pub fn issue_send_tx(
&self, &self,
req: Request<Body>, req: Request<Body>,
mut api: APIOwner<T, C, K>, mut api: APIOwner<T, C, K>,
@ -310,6 +310,7 @@ where
args.max_outputs, args.max_outputs,
args.num_change_outputs, args.num_change_outputs,
args.selection_strategy_is_use_all, args.selection_strategy_is_use_all,
args.message,
); );
let (mut slate, lock_fn) = match result { let (mut slate, lock_fn) = match result {
Ok(s) => { Ok(s) => {
@ -353,7 +354,7 @@ where
})) }))
} }
fn finalize_tx( pub fn finalize_tx(
&self, &self,
req: Request<Body>, req: Request<Body>,
mut api: APIOwner<T, C, K>, mut api: APIOwner<T, C, K>,
@ -369,7 +370,7 @@ where
) )
} }
fn cancel_tx( pub fn cancel_tx(
&self, &self,
req: Request<Body>, req: Request<Body>,
mut api: APIOwner<T, C, K>, mut api: APIOwner<T, C, K>,
@ -414,7 +415,7 @@ where
} }
} }
fn post_tx( pub fn post_tx(
&self, &self,
req: Request<Body>, req: Request<Body>,
api: APIOwner<T, C, K>, api: APIOwner<T, C, K>,
@ -548,7 +549,8 @@ where
mut api: APIForeign<T, C, K>, mut api: APIForeign<T, C, K>,
) -> Box<Future<Item = Slate, Error = Error> + Send> { ) -> Box<Future<Item = Slate, Error = Error> + Send> {
Box::new(parse_body(req).and_then( Box::new(parse_body(req).and_then(
move |mut slate| match api.receive_tx(&mut slate, None) { //TODO: No way to insert a message from the params
move |mut slate| match api.receive_tx(&mut slate, None, None) {
Ok(_) => ok(slate.clone()), Ok(_) => ok(slate.clone()),
Err(e) => { Err(e) => {
error!("receive_tx: failed with error: {}", e); error!("receive_tx: failed with error: {}", e);

View file

@ -420,6 +420,28 @@ pub fn verify_completed_sig(
Ok(()) Ok(())
} }
/// Adds signatures
pub fn add_signatures(
secp: &Secp256k1,
part_sigs: Vec<&Signature>,
nonce_sum: &PublicKey,
) -> Result<Signature, Error> {
// Add public nonces kR*G + kS*G
let sig = aggsig::add_signatures_single(&secp, part_sigs, &nonce_sum)?;
Ok(sig)
}
/// Just a simple sig, creates its own nonce, etc
pub fn sign_single(
secp: &Secp256k1,
msg: &Message,
skey: &SecretKey,
pubkey_sum: Option<&PublicKey>,
) -> Result<Signature, Error> {
let sig = aggsig::sign_single(secp, &msg, skey, None, None, None, pubkey_sum, None)?;
Ok(sig)
}
/// Verifies an aggsig signature /// Verifies an aggsig signature
pub fn verify_single( pub fn verify_single(
secp: &Secp256k1, secp: &Secp256k1,
@ -435,17 +457,6 @@ pub fn verify_single(
) )
} }
/// Adds signatures
pub fn add_signatures(
secp: &Secp256k1,
part_sigs: Vec<&Signature>,
nonce_sum: &PublicKey,
) -> Result<Signature, Error> {
// Add public nonces kR*G + kS*G
let sig = aggsig::add_signatures_single(&secp, part_sigs, &nonce_sum)?;
Ok(sig)
}
/// Just a simple sig, creates its own nonce, etc /// Just a simple sig, creates its own nonce, etc
pub fn sign_with_blinding( pub fn sign_with_blinding(
secp: &Secp256k1, secp: &Secp256k1,

View file

@ -32,6 +32,8 @@ use util::secp::key::{PublicKey, SecretKey};
use util::secp::Signature; use util::secp::Signature;
use util::RwLock; use util::RwLock;
use blake2::blake2b::blake2b;
/// Public data for each participant in the slate /// Public data for each participant in the slate
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
@ -44,6 +46,10 @@ pub struct ParticipantData {
pub public_nonce: PublicKey, pub public_nonce: PublicKey,
/// Public partial signature /// Public partial signature
pub part_sig: Option<Signature>, pub part_sig: Option<Signature>,
/// A message for other participants
pub message: Option<String>,
/// Signature, created with private key corresponding to 'public_blind_excess'
pub message_sig: Option<Signature>,
} }
impl ParticipantData { impl ParticipantData {
@ -133,6 +139,7 @@ impl Slate {
sec_key: &mut SecretKey, sec_key: &mut SecretKey,
sec_nonce: &SecretKey, sec_nonce: &SecretKey,
participant_id: usize, participant_id: usize,
message: Option<String>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
K: Keychain, K: Keychain,
@ -141,7 +148,14 @@ impl Slate {
if self.tx.offset == BlindingFactor::zero() { if self.tx.offset == BlindingFactor::zero() {
self.generate_offset(keychain, sec_key)?; self.generate_offset(keychain, sec_key)?;
} }
self.add_participant_info(keychain, &sec_key, &sec_nonce, participant_id, None)?; self.add_participant_info(
keychain,
&sec_key,
&sec_nonce,
participant_id,
None,
message,
)?;
Ok(()) Ok(())
} }
@ -234,6 +248,7 @@ impl Slate {
sec_nonce: &SecretKey, sec_nonce: &SecretKey,
id: usize, id: usize,
part_sig: Option<Signature>, part_sig: Option<Signature>,
message: Option<String>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
K: Keychain, K: Keychain,
@ -241,11 +256,24 @@ impl Slate {
// Add our public key and nonce to the slate // Add our public key and nonce to the slate
let pub_key = PublicKey::from_secret_key(keychain.secp(), &sec_key)?; let pub_key = PublicKey::from_secret_key(keychain.secp(), &sec_key)?;
let pub_nonce = PublicKey::from_secret_key(keychain.secp(), &sec_nonce)?; let pub_nonce = PublicKey::from_secret_key(keychain.secp(), &sec_nonce)?;
// Sign the provided message
let message_sig = {
if let Some(m) = message.clone() {
let hashed = blake2b(secp::constants::MESSAGE_SIZE, &[], &m.as_bytes()[..]);
let m = secp::Message::from_slice(&hashed.as_bytes())?;
let res = aggsig::sign_single(&keychain.secp(), &m, &sec_key, None)?;
Some(res)
} else {
None
}
};
self.participant_data.push(ParticipantData { self.participant_data.push(ParticipantData {
id: id as u64, id: id as u64,
public_blind_excess: pub_key, public_blind_excess: pub_key,
public_nonce: pub_nonce, public_nonce: pub_nonce,
part_sig: part_sig, part_sig: part_sig,
message: message,
message_sig: message_sig,
}); });
Ok(()) Ok(())
@ -321,6 +349,30 @@ impl Slate {
Ok(()) Ok(())
} }
/// Verifies any messages in the slate's participant data match their signatures
pub fn verify_messages(&self, secp: &secp::Secp256k1) -> Result<(), Error> {
for p in self.participant_data.iter() {
if let Some(m) = p.message.clone() {
let hashed = blake2b(secp::constants::MESSAGE_SIZE, &[], &m.as_bytes()[..]);
let m = secp::Message::from_slice(&hashed.as_bytes())?;
if !aggsig::verify_single(
secp,
&p.message_sig.as_ref().unwrap(),
&m,
None,
&p.public_blind_excess,
None,
false,
) {
return Err(ErrorKind::Signature(
"Optional participant messages do not match signatures".to_owned(),
))?;
}
}
}
Ok(())
}
/// This should be callable by either the sender or receiver /// This should be callable by either the sender or receiver
/// once phase 3 is done /// once phase 3 is done
/// ///

View file

@ -462,6 +462,7 @@ where
max_outputs: usize, max_outputs: usize,
num_change_outputs: usize, num_change_outputs: usize,
selection_strategy_is_use_all: bool, selection_strategy_is_use_all: bool,
message: Option<String>,
) -> Result<(Slate, impl FnOnce(&mut W, &str) -> Result<(), Error>), Error> { ) -> Result<(Slate, impl FnOnce(&mut W, &str) -> Result<(), Error>), Error> {
let mut w = self.wallet.lock(); let mut w = self.wallet.lock();
w.open_with_credentials()?; w.open_with_credentials()?;
@ -485,6 +486,7 @@ where
selection_strategy_is_use_all, selection_strategy_is_use_all,
&parent_key_id, &parent_key_id,
false, false,
message,
)?; )?;
// Save the aggsig context in our DB for when we // Save the aggsig context in our DB for when we
@ -577,6 +579,13 @@ where
} }
} }
/// Verifies all messages in the slate match their public keys
pub fn verify_slate_messages(&mut self, slate: &Slate) -> Result<(), Error> {
let mut w = self.wallet.lock();
slate.verify_messages(w.keychain().secp())?;
Ok(())
}
/// Attempt to restore contents of wallet /// Attempt to restore contents of wallet
pub fn restore(&mut self) -> Result<(), Error> { pub fn restore(&mut self) -> Result<(), Error> {
let mut w = self.wallet.lock(); let mut w = self.wallet.lock();
@ -660,6 +669,7 @@ where
&mut self, &mut self,
slate: &mut Slate, slate: &mut Slate,
dest_acct_name: Option<&str>, dest_acct_name: Option<&str>,
message: Option<String>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut w = self.wallet.lock(); let mut w = self.wallet.lock();
w.open_with_credentials()?; w.open_with_credentials()?;
@ -673,7 +683,7 @@ where
} }
None => w.parent_key_id(), None => w.parent_key_id(),
}; };
let res = tx::receive_tx(&mut *w, slate, &parent_key_id, false); let res = tx::receive_tx(&mut *w, slate, &parent_key_id, false, message);
w.close()?; w.close()?;
if let Err(e) = res { if let Err(e) = res {

View file

@ -31,6 +31,7 @@ pub fn receive_tx<T: ?Sized, C, K>(
slate: &mut Slate, slate: &mut Slate,
parent_key_id: &Identifier, parent_key_id: &Identifier,
is_self: bool, is_self: bool,
message: Option<String>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
T: WalletBackend<C, K>, T: WalletBackend<C, K>,
@ -51,6 +52,7 @@ where
&mut context.sec_key, &mut context.sec_key,
&context.sec_nonce, &context.sec_nonce,
1, 1,
message,
)?; )?;
// perform partial sig // perform partial sig
@ -73,6 +75,7 @@ pub fn create_send_tx<T: ?Sized, C, K>(
selection_strategy_is_use_all: bool, selection_strategy_is_use_all: bool,
parent_key_id: &Identifier, parent_key_id: &Identifier,
is_self: bool, is_self: bool,
message: Option<String>,
) -> Result< ) -> Result<
( (
Slate, Slate,
@ -122,6 +125,7 @@ where
&mut context.sec_key, &mut context.sec_key,
&context.sec_nonce, &context.sec_nonce,
0, 0,
message,
)?; )?;
Ok((slate, context, sender_lock_fn)) Ok((slate, context, sender_lock_fn))

View file

@ -700,4 +700,6 @@ pub struct SendTXArgs {
pub num_change_outputs: usize, pub num_change_outputs: usize,
/// whether to use all outputs (combine) /// whether to use all outputs (combine)
pub selection_strategy_is_use_all: bool, pub selection_strategy_is_use_all: bool,
/// Optional message, that will be signed
pub message: Option<String>,
} }

View file

@ -190,6 +190,7 @@ fn accounts_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
500, // max outputs 500, // max outputs
1, // num change outputs 1, // num change outputs
true, // select all outputs true, // select all outputs
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, lock_fn)?;

View file

@ -211,7 +211,7 @@ where
let w = dest_wallet.unwrap().1.clone(); let w = dest_wallet.unwrap().1.clone();
let mut slate = serde_json::from_str(&m.body).unwrap(); let mut slate = serde_json::from_str(&m.body).unwrap();
controller::foreign_single_use(w.clone(), |listener_api| { controller::foreign_single_use(w.clone(), |listener_api| {
listener_api.receive_tx(&mut slate, None)?; listener_api.receive_tx(&mut slate, None, None)?;
Ok(()) Ok(())
})?; })?;
Ok(WalletProxyMessage { Ok(WalletProxyMessage {

View file

@ -97,6 +97,9 @@ fn file_exchange_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
let send_file = format!("{}/part_tx_1.tx", test_dir); let send_file = format!("{}/part_tx_1.tx", test_dir);
let receive_file = format!("{}/part_tx_2.tx", test_dir); let receive_file = format!("{}/part_tx_2.tx", test_dir);
// test optional message
let message = "sender test message, sender test message";
// Should have 5 in account1 (5 spendable), 5 in account (2 spendable) // Should have 5 in account1 (5 spendable), 5 in account (2 spendable)
wallet::controller::owner_single_use(wallet1.clone(), |api| { wallet::controller::owner_single_use(wallet1.clone(), |api| {
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?; let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
@ -106,13 +109,12 @@ fn file_exchange_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
// send to send // send to send
let (mut slate, lock_fn) = api.initiate_tx( let (mut slate, lock_fn) = api.initiate_tx(
Some("mining"), Some("mining"),
reward * 2, // amount reward * 2, // amount
2, // minimum confirmations 2, // minimum confirmations
500, // max outputs 500, // max outputs
1, // num change outputs 1, // num change outputs
true, // select all outputs true, // select all outputs
//"mining", Some(message.to_owned()), // optional message
//"listener",
)?; )?;
// output tx file // output tx file
let file_adapter = FileWalletCommAdapter::new(); let file_adapter = FileWalletCommAdapter::new();
@ -127,11 +129,23 @@ fn file_exchange_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
w.set_parent_key_id_by_name("account1")?; w.set_parent_key_id_by_name("account1")?;
} }
let adapter = FileWalletCommAdapter::new();
let mut slate = adapter.receive_tx_async(&send_file)?;
let mut naughty_slate = slate.clone();
naughty_slate.participant_data[0].message = Some("I changed the message".to_owned());
// verify messages on slate match
wallet::controller::owner_single_use(wallet1.clone(), |api| {
api.verify_slate_messages(&slate)?;
assert!(api.verify_slate_messages(&naughty_slate).is_err());
Ok(())
})?;
let sender2_message = "And this is sender 2's message".to_owned();
// wallet 2 receives file, completes, sends file back // wallet 2 receives file, completes, sends file back
wallet::controller::foreign_single_use(wallet2.clone(), |api| { wallet::controller::foreign_single_use(wallet2.clone(), |api| {
let adapter = FileWalletCommAdapter::new(); api.receive_tx(&mut slate, None, Some(sender2_message))?;
let mut slate = adapter.receive_tx_async(&send_file)?;
api.receive_tx(&mut slate, None)?;
adapter.send_tx_async(&receive_file, &mut slate)?; adapter.send_tx_async(&receive_file, &mut slate)?;
Ok(()) Ok(())
})?; })?;
@ -140,6 +154,7 @@ fn file_exchange_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 adapter = FileWalletCommAdapter::new(); let adapter = FileWalletCommAdapter::new();
let mut slate = adapter.receive_tx_async(&receive_file)?; let mut slate = adapter.receive_tx_async(&receive_file)?;
api.verify_slate_messages(&slate)?;
api.finalize_tx(&mut slate)?; api.finalize_tx(&mut slate)?;
api.post_tx(&slate.tx, false)?; api.post_tx(&slate.tx, false)?;
bh += 1; bh += 1;

View file

@ -112,6 +112,7 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
500, // max outputs 500, // max outputs
1, // num change outputs 1, // num change outputs
true, // select all outputs true, // select all outputs
None,
)?; )?;
// output tx file // output tx file
let file_adapter = FileWalletCommAdapter::new(); let file_adapter = FileWalletCommAdapter::new();
@ -132,7 +133,7 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
wallet::controller::foreign_single_use(wallet1.clone(), |api| { wallet::controller::foreign_single_use(wallet1.clone(), |api| {
let adapter = FileWalletCommAdapter::new(); let adapter = FileWalletCommAdapter::new();
let mut slate = adapter.receive_tx_async(&send_file)?; let mut slate = adapter.receive_tx_async(&send_file)?;
api.receive_tx(&mut slate, None)?; api.receive_tx(&mut slate, None, None)?;
adapter.send_tx_async(&receive_file, &mut slate)?; adapter.send_tx_async(&receive_file, &mut slate)?;
Ok(()) Ok(())
})?; })?;
@ -207,6 +208,7 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
500, // max outputs 500, // max outputs
1, // num change outputs 1, // num change outputs
true, // select all outputs true, // select all outputs
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, lock_fn)?;

View file

@ -236,6 +236,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
500, // max outputs 500, // max outputs
1, // num change outputs 1, // num change outputs
true, // select all outputs true, // select all outputs
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, lock_fn)?;
@ -257,6 +258,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
500, // max outputs 500, // max outputs
1, // num change outputs 1, // num change outputs
true, // select all outputs true, // select all outputs
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, lock_fn)?;
@ -278,6 +280,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
500, // max outputs 500, // max outputs
1, // num change outputs 1, // num change outputs
true, // select all outputs true, // select all outputs
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, lock_fn)?;
@ -305,6 +308,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
500, // max outputs 500, // max outputs
1, // num change outputs 1, // num change outputs
true, // select all outputs true, // select all outputs
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, lock_fn)?;

View file

@ -99,12 +99,11 @@ fn self_send_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
500, // max outputs 500, // max outputs
1, // num change outputs 1, // num change outputs
true, // select all outputs true, // select all outputs
//"mining", None,
//"listener",
)?; )?;
// 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"))?; api.receive_tx(&mut slate, Some("listener"), None)?;
Ok(()) Ok(())
})?; })?;
api.finalize_tx(&mut slate)?; api.finalize_tx(&mut slate)?;

View file

@ -110,6 +110,7 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> {
500, // max outputs 500, // max outputs
1, // num change outputs 1, // num change outputs
true, // select all outputs true, // select all outputs
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, lock_fn)?;
@ -244,6 +245,7 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> {
500, // max outputs 500, // max outputs
1, // num change outputs 1, // num change outputs
true, // select all outputs true, // select all outputs
None,
)?; )?;
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
sender_api.finalize_tx(&mut slate)?; sender_api.finalize_tx(&mut slate)?;
@ -337,6 +339,7 @@ fn tx_rollback(test_dir: &str) -> Result<(), libwallet::Error> {
500, // max outputs 500, // max outputs
1, // num change outputs 1, // num change outputs
true, // select all outputs true, // select all outputs
None,
)?; )?;
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
sender_api.finalize_tx(&mut slate)?; sender_api.finalize_tx(&mut slate)?;