mirror of
https://github.com/jwinterm/grin-wallet.git
synced 2026-10-17 15:21:39 +02:00
Compact slate merge (#404)
* Add support for sending compact slates (#366) * WIP add support for sending compact slates * add repopulate_tx function to internal API * first pass at compacted slate working * move slate compaction to separate function * test fixes * support compact slate inits in invoice workflow * add compress flags to send and invoice * attempting to remove is_compact and assume all V4 slates begin as compact * attempting to calculate offsets when full tx data isn't available * update calc_commit to use participant blind data * update doctests for compact slates * start to remove unneeded fields from serialization * make num_participants optional * remove other_version from slate * use grin master branch * remove message field * lock height assumed to be 0 if it doesn't exist * don't serialise receiver signature when null * don't serialize payment_info if not needed * remove participant id from participant info * add note on id field * fix finalize and receive doctests * finalize_tx tests, init_send_tx tests * doctests for process_invoice_tx, retrieve_tx, tx_lock_outputs * finished test changes * update from grin master * rebuild PR from diff (#380) * recreate PR from diff (#381) * serialize tx struct into top level coms object (#382) * remove height (#383) * Add State Slate (#384) * add state field to slate and SlateV4 * set slate state at each transaction stage, add check to tests * serialize slate status properly * V4 Slate field tweaks (#386) * various tweaks to V4 slate * field renaming * serialize slate v4 ID as base64 (#387) * remove amount and fee where not needed (#388) * Final Changes for compact Slate (#389) * add tests for all types of file output, remove message args * default range proof serialization * shorten output features serialization * rename payment proof fields in slate v4 * v4 payment proof serialization * Binary Slates (#385) * start test implementation * add experimental binary serialization to slate * serialize id * serialize fields that can be skipped as a separate struct * factor out sigs serialization * clean up sigs and coms serialization * completed v4 bin serialization * add manual de/ser traits for V4 bin slate * add simple byte array serializer * complete wiring in of bin slate serialization * clarify comment * clarify comment * update version * test output dir name fix * update slate v4 change description * add binary output to command line * Remove unneeded signature data during S2 and I2 stages (#390) * remove unneeded return signature data during S2 * remove unneeded sig data from I2 * Doctest Fixes for compact slate branch (#392) * begin to fix doctests * more doctest fixes * fix receive_tx * update get_stored_tx to accept an UUID instead of a tx object, and operate on a raw Transaction object (#394) * Fixes to async transaction posting (#395) * unstash post_tx changes * add offset during S3 and I3 * Revert slate id serialization to hex-string uuid (#396) * update from master (#397) * v3.x.x - v4.0.0 wallet compatibility fixes (#398) * changes to support http sending to v3 wallets * sending via http/tor TO 3.0.0 wallet works * receiving FROM 3.0.0 wallets works over http/tor * output converted V3 slate when needed * paying invoices from 3.0.0 wallets working * handle all participant info in slate states * sending and receiving standard file transactions between v3 and 4 wallets confirmed working * all file-based workflows working * fixes resulting from tests * remove reminder warnings * remove lock_height, add kernel_features + arguments (#399) * grin-wallet master now building against grin master (#402) (#403) Co-authored-by: Antioch Peverell <apeverell@protonmail.com> * Enhanced offset creation (#407) * initial tests reworking offset creation * invoice flow fixing + tests * further test fixes * change offset name in v4 slate, base64 serialize * logic optimisation * changes based on review feedback Co-authored-by: Antioch Peverell <apeverell@protonmail.com>
This commit is contained in:
co-authored by
Antioch Peverell
parent
19da1e4aec
commit
9450d2a3b8
+117
-62
@@ -20,10 +20,11 @@ use crate::config::{TorConfig, WalletConfig, WALLET_CONFIG_FILE_NAME};
|
||||
use crate::core::{core, global};
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use crate::impls::{create_sender, KeybaseAllChannels, SlateGetter as _, SlateReceiver as _};
|
||||
use crate::impls::{PathToSlate, SlatePutter};
|
||||
use crate::impls::{HttpSlateSender, PathToSlate, SlatePutter};
|
||||
use crate::keychain;
|
||||
use crate::libwallet::{
|
||||
self, InitTxArgs, IssueInvoiceTxArgs, NodeClient, PaymentProof, WalletLCProvider,
|
||||
self, InitTxArgs, IssueInvoiceTxArgs, NodeClient, PaymentProof, Slate, SlateVersion,
|
||||
WalletLCProvider,
|
||||
};
|
||||
use crate::util::secp::key::SecretKey;
|
||||
use crate::util::{Mutex, ZeroingString};
|
||||
@@ -266,7 +267,6 @@ where
|
||||
/// Arguments for the send command
|
||||
pub struct SendArgs {
|
||||
pub amount: u64,
|
||||
pub message: Option<String>,
|
||||
pub minimum_confirmations: u64,
|
||||
pub selection_strategy: String,
|
||||
pub estimate_selection_strategies: bool,
|
||||
@@ -278,6 +278,8 @@ pub struct SendArgs {
|
||||
pub target_slate_version: Option<u16>,
|
||||
pub payment_proof_address: Option<OnionV3Address>,
|
||||
pub ttl_blocks: Option<u64>,
|
||||
//TODO: Remove HF3
|
||||
pub output_v4_slate: bool,
|
||||
}
|
||||
|
||||
pub fn send<L, C, K>(
|
||||
@@ -293,6 +295,60 @@ where
|
||||
K: keychain::Keychain + 'static,
|
||||
{
|
||||
let wallet_inst = owner_api.wallet_inst.clone();
|
||||
// Check other version, and if it only supports 3 set the target slate
|
||||
// version to 3 to avoid removing the transaction object
|
||||
// TODO: This block is temporary, for the period between the release of v4.0.0 and HF3,
|
||||
// after which this should be removable
|
||||
let mut args = args;
|
||||
{
|
||||
let invalid = || {
|
||||
ErrorKind::GenericError(format!(
|
||||
"Invalid wallet comm type and destination. method: {}, dest: {}",
|
||||
args.method, args.dest
|
||||
))
|
||||
};
|
||||
let trailing = match args.dest.ends_with('/') {
|
||||
true => "",
|
||||
false => "/",
|
||||
};
|
||||
let url_str = format!("{}{}v2/foreign", args.dest, trailing);
|
||||
match args.method.as_ref() {
|
||||
"http" => {
|
||||
let v_sender = HttpSlateSender::new(&args.dest).map_err(|_| invalid())?;
|
||||
let other_version = v_sender.check_other_version(&url_str)?;
|
||||
if other_version == SlateVersion::V3 {
|
||||
args.target_slate_version = Some(3);
|
||||
}
|
||||
}
|
||||
"tor" => {
|
||||
let v_sender = HttpSlateSender::with_socks_proxy(
|
||||
&args.dest,
|
||||
&tor_config.as_ref().unwrap().socks_proxy_addr,
|
||||
&tor_config.as_ref().unwrap().send_config_dir,
|
||||
)
|
||||
.map_err(|_| invalid())?;
|
||||
let other_version = v_sender.check_other_version(&url_str)?;
|
||||
if other_version == SlateVersion::V3 {
|
||||
args.target_slate_version = Some(3);
|
||||
}
|
||||
}
|
||||
"file" => {
|
||||
// For files spit out a V3 Slate if we're before HF3,
|
||||
// Or V4 slate otherwise
|
||||
let cur_height = {
|
||||
libwallet::wallet_lock!(wallet_inst, w);
|
||||
w.w2n_client().get_chain_tip()?.0
|
||||
};
|
||||
// TODO: Floonet HF4
|
||||
if cur_height < 786240 && !args.output_v4_slate {
|
||||
args.target_slate_version = Some(3);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
// end block to delete post HF3
|
||||
|
||||
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
|
||||
if args.estimate_selection_strategies {
|
||||
let strategies = vec!["smallest", "all"]
|
||||
@@ -321,7 +377,6 @@ where
|
||||
max_outputs: args.max_outputs as u32,
|
||||
num_change_outputs: args.change_outputs as u32,
|
||||
selection_strategy_is_use_all: args.selection_strategy == "all",
|
||||
message: args.message.clone(),
|
||||
target_slate_version: args.target_slate_version,
|
||||
payment_proof_recipient_address: args.payment_proof_address.clone(),
|
||||
ttl_blocks: args.ttl_blocks,
|
||||
@@ -347,34 +402,35 @@ where
|
||||
|
||||
match args.method.as_str() {
|
||||
"file" => {
|
||||
PathToSlate((&args.dest).into()).put_tx(&slate)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
PathToSlate((&args.dest).into()).put_tx(&slate, false)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
return Ok(());
|
||||
}
|
||||
"binfile" => {
|
||||
PathToSlate((&args.dest).into()).put_tx(&slate, true)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
return Ok(());
|
||||
}
|
||||
"self" => {
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
let km = match keychain_mask.as_ref() {
|
||||
None => None,
|
||||
Some(&m) => Some(m.to_owned()),
|
||||
};
|
||||
controller::foreign_single_use(wallet_inst, km, |api| {
|
||||
slate = api.receive_tx(&slate, Some(&args.dest), None)?;
|
||||
slate = api.receive_tx(&slate, Some(&args.dest))?;
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
method => {
|
||||
let sender = create_sender(method, &args.dest, tor_config)?;
|
||||
slate = sender.send_tx(&slate)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
}
|
||||
}
|
||||
|
||||
api.verify_slate_messages(m, &slate).map_err(|e| {
|
||||
error!("Error validating participant messages: {}", e);
|
||||
e
|
||||
})?;
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
let result = api.post_tx(m, slate.tx_or_err()?, args.fluff);
|
||||
let result = api.post_tx(m, &slate, args.fluff);
|
||||
match result {
|
||||
Ok(_) => {
|
||||
info!("Tx sent ok",);
|
||||
@@ -394,7 +450,6 @@ where
|
||||
/// Receive command argument
|
||||
pub struct ReceiveArgs {
|
||||
pub input: String,
|
||||
pub message: Option<String>,
|
||||
}
|
||||
|
||||
pub fn receive<L, C, K>(
|
||||
@@ -408,20 +463,16 @@ where
|
||||
C: NodeClient + 'static,
|
||||
K: keychain::Keychain + 'static,
|
||||
{
|
||||
let mut slate = PathToSlate((&args.input).into()).get_tx()?;
|
||||
let (mut slate, was_bin) = PathToSlate((&args.input).into()).get_tx()?;
|
||||
let km = match keychain_mask.as_ref() {
|
||||
None => None,
|
||||
Some(&m) => Some(m.to_owned()),
|
||||
};
|
||||
controller::foreign_single_use(owner_api.wallet_inst.clone(), km, |api| {
|
||||
if let Err(e) = api.verify_slate_messages(&slate) {
|
||||
error!("Error validating participant messages: {}", e);
|
||||
return Err(e);
|
||||
}
|
||||
slate = api.receive_tx(&slate, Some(&g_args.account), args.message.clone())?;
|
||||
slate = api.receive_tx(&slate, Some(&g_args.account))?;
|
||||
Ok(())
|
||||
})?;
|
||||
PathToSlate(format!("{}.response", args.input).into()).put_tx(&slate)?;
|
||||
PathToSlate(format!("{}.response", args.input).into()).put_tx(&slate, was_bin)?;
|
||||
info!(
|
||||
"Response file {}.response generated, and can be sent back to the transaction originator.",
|
||||
args.input
|
||||
@@ -447,25 +498,18 @@ where
|
||||
C: NodeClient + 'static,
|
||||
K: keychain::Keychain + 'static,
|
||||
{
|
||||
let mut slate = PathToSlate((&args.input).into()).get_tx()?;
|
||||
let (mut slate, was_bin) = PathToSlate((&args.input).into()).get_tx()?;
|
||||
|
||||
// Rather than duplicating the entire command, we'll just
|
||||
// try to determine what kind of finalization this is
|
||||
// based on the slate contents
|
||||
// for now, we can tell this is an invoice transaction
|
||||
// if the receipient (participant 1) hasn't completed sigs
|
||||
let part_data = slate.participant_with_id(1);
|
||||
let is_invoice = {
|
||||
match part_data {
|
||||
None => {
|
||||
error!("Expected slate participant data missing");
|
||||
return Err(ErrorKind::ArgumentError(
|
||||
"Expected Slate participant data missing".into(),
|
||||
))?;
|
||||
}
|
||||
Some(p) => !p.is_complete(),
|
||||
}
|
||||
};
|
||||
let mut is_invoice = false;
|
||||
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
|
||||
is_invoice = api.context_is_invoice(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
if is_invoice {
|
||||
let km = match keychain_mask.as_ref() {
|
||||
@@ -473,19 +517,11 @@ where
|
||||
Some(&m) => Some(m.to_owned()),
|
||||
};
|
||||
controller::foreign_single_use(owner_api.wallet_inst.clone(), km, |api| {
|
||||
if let Err(e) = api.verify_slate_messages(&slate) {
|
||||
error!("Error validating participant messages: {}", e);
|
||||
return Err(e);
|
||||
}
|
||||
slate = api.finalize_invoice_tx(&slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
} else {
|
||||
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
|
||||
if let Err(e) = api.verify_slate_messages(m, &slate) {
|
||||
error!("Error validating participant messages: {}", e);
|
||||
return Err(e);
|
||||
}
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
@@ -493,7 +529,7 @@ where
|
||||
|
||||
if !args.nopost {
|
||||
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
|
||||
let result = api.post_tx(m, slate.tx_or_err()?, args.fluff);
|
||||
let result = api.post_tx(m, &slate, args.fluff);
|
||||
match result {
|
||||
Ok(_) => {
|
||||
info!(
|
||||
@@ -510,7 +546,7 @@ where
|
||||
}
|
||||
|
||||
if args.dest.is_some() {
|
||||
PathToSlate((&args.dest.unwrap()).into()).put_tx(&slate)?;
|
||||
PathToSlate((&args.dest.unwrap()).into()).put_tx(&slate, was_bin)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -522,6 +558,11 @@ pub struct IssueInvoiceArgs {
|
||||
pub dest: String,
|
||||
/// issue invoice tx args
|
||||
pub issue_args: IssueInvoiceTxArgs,
|
||||
/// whether to output as bin
|
||||
pub bin: bool,
|
||||
// TODO: Remove HF3
|
||||
/// whether to output a V4 slate
|
||||
pub output_v4_slate: bool,
|
||||
}
|
||||
|
||||
pub fn issue_invoice_tx<L, C, K>(
|
||||
@@ -534,9 +575,23 @@ where
|
||||
C: NodeClient + 'static,
|
||||
K: keychain::Keychain + 'static,
|
||||
{
|
||||
//TODO: Remove block HF3
|
||||
let args = {
|
||||
let mut a = args;
|
||||
let wallet_inst = owner_api.wallet_inst.clone();
|
||||
let cur_height = {
|
||||
libwallet::wallet_lock!(wallet_inst, w);
|
||||
w.w2n_client().get_chain_tip()?.0
|
||||
};
|
||||
// TODO: Floonet HF4
|
||||
if cur_height < 786240 && !a.output_v4_slate && !a.bin {
|
||||
a.issue_args.target_slate_version = Some(3);
|
||||
}
|
||||
a
|
||||
};
|
||||
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
|
||||
let slate = api.issue_invoice_tx(m, args.issue_args)?;
|
||||
PathToSlate((&args.dest).into()).put_tx(&slate)?;
|
||||
PathToSlate((&args.dest).into()).put_tx(&slate, args.bin)?;
|
||||
Ok(())
|
||||
})?;
|
||||
Ok(())
|
||||
@@ -544,7 +599,6 @@ where
|
||||
|
||||
/// Arguments for the process_invoice command
|
||||
pub struct ProcessInvoiceArgs {
|
||||
pub message: Option<String>,
|
||||
pub minimum_confirmations: u64,
|
||||
pub selection_strategy: String,
|
||||
pub method: String,
|
||||
@@ -568,7 +622,7 @@ where
|
||||
C: NodeClient + 'static,
|
||||
K: keychain::Keychain + 'static,
|
||||
{
|
||||
let slate = PathToSlate((&args.input).into()).get_tx()?;
|
||||
let (slate, _) = PathToSlate((&args.input).into()).get_tx()?;
|
||||
let wallet_inst = owner_api.wallet_inst.clone();
|
||||
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
|
||||
if args.estimate_selection_strategies {
|
||||
@@ -598,15 +652,10 @@ where
|
||||
max_outputs: args.max_outputs as u32,
|
||||
num_change_outputs: 1u32,
|
||||
selection_strategy_is_use_all: args.selection_strategy == "all",
|
||||
message: args.message.clone(),
|
||||
ttl_blocks: args.ttl_blocks,
|
||||
send_args: None,
|
||||
..Default::default()
|
||||
};
|
||||
if let Err(e) = api.verify_slate_messages(m, &slate) {
|
||||
error!("Error validating participant messages: {}", e);
|
||||
return Err(e);
|
||||
}
|
||||
let result = api.process_invoice_tx(m, &slate, init_args);
|
||||
let mut slate = match result {
|
||||
Ok(s) => {
|
||||
@@ -627,11 +676,16 @@ where
|
||||
match args.method.as_str() {
|
||||
"file" => {
|
||||
let slate_putter = PathToSlate((&args.dest).into());
|
||||
slate_putter.put_tx(&slate)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
slate_putter.put_tx(&slate, false)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
}
|
||||
"filebin" => {
|
||||
let slate_putter = PathToSlate((&args.dest).into());
|
||||
slate_putter.put_tx(&slate, true)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
}
|
||||
"self" => {
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
let km = match keychain_mask.as_ref() {
|
||||
None => None,
|
||||
Some(&m) => Some(m.to_owned()),
|
||||
@@ -644,7 +698,7 @@ where
|
||||
method => {
|
||||
let sender = create_sender(method, &args.dest, tor_config)?;
|
||||
slate = sender.send_tx(&slate)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -769,7 +823,6 @@ where
|
||||
)?;
|
||||
// should only be one here, but just in case
|
||||
for tx in txs {
|
||||
display::tx_messages(&tx, dark_scheme)?;
|
||||
display::payment_proof(&tx)?;
|
||||
}
|
||||
}
|
||||
@@ -795,10 +848,10 @@ where
|
||||
C: NodeClient + 'static,
|
||||
K: keychain::Keychain + 'static,
|
||||
{
|
||||
let slate = PathToSlate((&args.input).into()).get_tx()?;
|
||||
let slate = PathToSlate((&args.input).into()).get_tx()?.0;
|
||||
|
||||
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
|
||||
api.post_tx(m, slate.tx_or_err()?, args.fluff)?;
|
||||
api.post_tx(m, &slate, args.fluff)?;
|
||||
info!("Posted transaction");
|
||||
return Ok(());
|
||||
})?;
|
||||
@@ -824,7 +877,7 @@ where
|
||||
{
|
||||
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
|
||||
let (_, txs) = api.retrieve_txs(m, true, Some(args.id), None)?;
|
||||
let stored_tx = api.get_stored_tx(m, &txs[0])?;
|
||||
let stored_tx = api.get_stored_tx(m, txs[0].tx_slate_id.unwrap())?;
|
||||
if stored_tx.is_none() {
|
||||
error!(
|
||||
"Transaction with id {} does not have transaction data. Not reposting.",
|
||||
@@ -841,7 +894,9 @@ where
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
api.post_tx(m, &stored_tx.unwrap(), args.fluff)?;
|
||||
let mut slate = Slate::blank(2, false);
|
||||
slate.tx = Some(stored_tx.unwrap());
|
||||
api.post_tx(m, &slate, args.fluff)?;
|
||||
info!("Reposted transaction at {}", args.id);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019 The Grin Developers
|
||||
// Copyright 2020 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,7 @@ use crate::core::global;
|
||||
use crate::libwallet::{
|
||||
AcctPathMapping, Error, OutputCommitMapping, OutputStatus, TxLogEntry, WalletInfo,
|
||||
};
|
||||
use crate::util::{static_secp_instance, ToHex};
|
||||
use crate::util::ToHex;
|
||||
use grin_wallet_util::OnionV3Address;
|
||||
use prettytable;
|
||||
use std::io::prelude::Write;
|
||||
@@ -448,81 +448,6 @@ pub fn accounts(acct_mappings: Vec<AcctPathMapping>) {
|
||||
println!();
|
||||
}
|
||||
|
||||
/// Display transaction log messages
|
||||
pub fn tx_messages(tx: &TxLogEntry, dark_background_color_scheme: bool) -> Result<(), Error> {
|
||||
let title = format!("Transaction Messages - Transaction '{}'", tx.id,);
|
||||
println!();
|
||||
if term::stdout().is_none() {
|
||||
println!("Could not open terminal");
|
||||
return Ok(());
|
||||
}
|
||||
let mut t = term::stdout().unwrap();
|
||||
t.fg(term::color::MAGENTA).unwrap();
|
||||
writeln!(t, "{}", title).unwrap();
|
||||
t.reset().unwrap();
|
||||
|
||||
let msgs = match tx.messages.clone() {
|
||||
None => {
|
||||
writeln!(t, "None").unwrap();
|
||||
t.reset().unwrap();
|
||||
return Ok(());
|
||||
}
|
||||
Some(m) => m.clone(),
|
||||
};
|
||||
|
||||
if msgs.messages.is_empty() {
|
||||
writeln!(t, "None").unwrap();
|
||||
t.reset().unwrap();
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut table = table!();
|
||||
|
||||
table.set_titles(row![
|
||||
bMG->"Participant Id",
|
||||
bMG->"Message",
|
||||
bMG->"Public Key",
|
||||
bMG->"Signature",
|
||||
]);
|
||||
|
||||
let secp = static_secp_instance();
|
||||
let secp_lock = secp.lock();
|
||||
|
||||
for m in msgs.messages {
|
||||
let id = format!("{}", m.id);
|
||||
let public_key = format!("{}", m.public_key.serialize_vec(&secp_lock, true).to_hex());
|
||||
let message = match m.message {
|
||||
Some(m) => format!("{}", m),
|
||||
None => "None".to_owned(),
|
||||
};
|
||||
let message_sig = match m.message_sig {
|
||||
Some(s) => format!("{}", s.serialize_der(&secp_lock).to_hex()),
|
||||
None => "None".to_owned(),
|
||||
};
|
||||
if dark_background_color_scheme {
|
||||
table.add_row(row![
|
||||
bFC->id,
|
||||
bFC->message,
|
||||
bFC->public_key,
|
||||
bFB->message_sig,
|
||||
]);
|
||||
} else {
|
||||
table.add_row(row![
|
||||
bFD->id,
|
||||
bFb->message,
|
||||
bFD->public_key,
|
||||
bFB->message_sig,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
table.set_format(*prettytable::format::consts::FORMAT_NO_COLSEP);
|
||||
table.printstd();
|
||||
println!();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Display individual Payment Proof
|
||||
pub fn payment_proof(tx: &TxLogEntry) -> Result<(), Error> {
|
||||
let title = format!("Payment Proof - Transaction '{}'", tx.id,);
|
||||
|
||||
@@ -200,9 +200,9 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
};
|
||||
let mut slate = api.init_send_tx(m, args)?;
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
api.post_tx(m, slate.tx_or_err()?, false)?;
|
||||
api.post_tx(m, &slate, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
||||
@@ -190,8 +190,8 @@ fn scan_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
let slate = api.init_send_tx(m, args)?;
|
||||
// output tx file
|
||||
let send_file = format!("{}/part_tx_1.tx", test_dir);
|
||||
PathToSlate(send_file.into()).put_tx(&slate)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
PathToSlate(send_file.into()).put_tx(&slate, false)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
||||
+144
-54
@@ -19,6 +19,7 @@ extern crate grin_wallet_impls as impls;
|
||||
|
||||
use grin_wallet_libwallet as libwallet;
|
||||
use grin_wallet_util::grin_core as core;
|
||||
use grin_wallet_util::OnionV3Address;
|
||||
|
||||
use impls::test_framework::{self, LocalWalletClient};
|
||||
use impls::{PathToSlate, SlateGetter as _, SlatePutter as _};
|
||||
@@ -26,16 +27,14 @@ use std::sync::atomic::Ordering;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use grin_wallet_libwallet::InitTxArgs;
|
||||
|
||||
use serde_json;
|
||||
use grin_wallet_libwallet::{InitTxArgs, IssueInvoiceTxArgs, Slate};
|
||||
|
||||
#[macro_use]
|
||||
mod common;
|
||||
use common::{clean_output_dir, create_wallet_proxy, setup};
|
||||
|
||||
/// self send impl
|
||||
fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
fn file_exchange_test_impl(test_dir: &'static str, use_bin: bool) -> Result<(), libwallet::Error> {
|
||||
// Create a new proxy to simulate server and wallet responses
|
||||
let mut wallet_proxy = create_wallet_proxy(test_dir);
|
||||
let chain = wallet_proxy.chain.clone();
|
||||
@@ -99,11 +98,18 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Erro
|
||||
let _ =
|
||||
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
|
||||
|
||||
let send_file = format!("{}/part_tx_1.tx", test_dir);
|
||||
let receive_file = format!("{}/part_tx_2.tx", test_dir);
|
||||
|
||||
// test optional message
|
||||
let message = "sender test message, sender test message";
|
||||
let (send_file, receive_file, final_file) = match use_bin {
|
||||
false => (
|
||||
format!("{}/standard_S1.tx", test_dir),
|
||||
format!("{}/standard_S2.tx", test_dir),
|
||||
format!("{}/standard_S3.tx", test_dir),
|
||||
),
|
||||
true => (
|
||||
format!("{}/standard_S1.txbin", test_dir),
|
||||
format!("{}/standard_S2.txbin", test_dir),
|
||||
format!("{}/standard_S3.txbin", test_dir),
|
||||
),
|
||||
};
|
||||
|
||||
// Should have 5 in account1 (5 spendable), 5 in account (2 spendable)
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
@@ -119,13 +125,12 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Erro
|
||||
max_outputs: 500,
|
||||
num_change_outputs: 1,
|
||||
selection_strategy_is_use_all: true,
|
||||
message: Some(message.to_owned()),
|
||||
..Default::default()
|
||||
};
|
||||
let slate = api.init_send_tx(m, args)?;
|
||||
// output tx file
|
||||
PathToSlate((&send_file).into()).put_tx(&slate)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
PathToSlate((&send_file).into()).put_tx(&slate, use_bin)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -135,32 +140,22 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Erro
|
||||
w.set_parent_key_id_by_name("account1")?;
|
||||
}
|
||||
|
||||
let mut slate = PathToSlate((&send_file).into()).get_tx()?;
|
||||
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(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
api.verify_slate_messages(m, &slate)?;
|
||||
assert!(api.verify_slate_messages(m, &naughty_slate).is_err());
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let sender2_message = "And this is sender 2's message".to_owned();
|
||||
let mut slate = PathToSlate((&send_file).into()).get_tx()?.0;
|
||||
|
||||
// wallet 2 receives file, completes, sends file back
|
||||
wallet::controller::foreign_single_use(wallet2.clone(), mask2_i.clone(), |api| {
|
||||
slate = api.receive_tx(&slate, None, Some(sender2_message.clone()))?;
|
||||
PathToSlate((&receive_file).into()).put_tx(&slate)?;
|
||||
slate = api.receive_tx(&slate, None)?;
|
||||
PathToSlate((&receive_file).into()).put_tx(&slate, use_bin)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// wallet 1 finalises and posts
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
let mut slate = PathToSlate(receive_file.into()).get_tx()?;
|
||||
api.verify_slate_messages(m, &slate)?;
|
||||
let mut slate = PathToSlate(receive_file.into()).get_tx()?.0;
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
api.post_tx(m, slate.tx_or_err()?, false)?;
|
||||
// Output final file for reference
|
||||
PathToSlate((&final_file).into()).put_tx(&slate, use_bin)?;
|
||||
api.post_tx(m, &slate, false)?;
|
||||
bh += 1;
|
||||
Ok(())
|
||||
})?;
|
||||
@@ -186,33 +181,117 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Erro
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Check messages, all participants should have both
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
let (_, tx) = api.retrieve_txs(m, true, None, Some(slate.id))?;
|
||||
assert_eq!(
|
||||
tx[0].clone().messages.unwrap().messages[0].message,
|
||||
Some(message.to_owned())
|
||||
);
|
||||
assert_eq!(
|
||||
tx[0].clone().messages.unwrap().messages[1].message,
|
||||
Some(sender2_message.to_owned())
|
||||
);
|
||||
// Now other types of exchange, for reference
|
||||
// Invoice transaction
|
||||
let (send_file, receive_file, final_file) = match use_bin {
|
||||
false => (
|
||||
format!("{}/invoice_I1.tx", test_dir),
|
||||
format!("{}/invoice_I2.tx", test_dir),
|
||||
format!("{}/invoice_I3.tx", test_dir),
|
||||
),
|
||||
true => (
|
||||
format!("{}/invoice_I1.txbin", test_dir),
|
||||
format!("{}/invoice_I2.txbin", test_dir),
|
||||
format!("{}/invoice_I3.txbin", test_dir),
|
||||
),
|
||||
};
|
||||
|
||||
let msg_json = serde_json::to_string_pretty(&tx[0].clone().messages.unwrap()).unwrap();
|
||||
println!("{}", msg_json);
|
||||
let mut slate = Slate::blank(2, true);
|
||||
|
||||
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
|
||||
let args = IssueInvoiceTxArgs {
|
||||
amount: 1000000000,
|
||||
..Default::default()
|
||||
};
|
||||
slate = api.issue_invoice_tx(m, args)?;
|
||||
PathToSlate((&send_file).into()).put_tx(&slate, use_bin)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
amount: slate.amount,
|
||||
minimum_confirmations: 2,
|
||||
max_outputs: 500,
|
||||
num_change_outputs: 1,
|
||||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
slate = PathToSlate((&send_file).into()).get_tx()?.0;
|
||||
slate = api.process_invoice_tx(m, &slate, args)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
PathToSlate((&receive_file).into()).put_tx(&slate, use_bin)?;
|
||||
Ok(())
|
||||
})?;
|
||||
wallet::controller::foreign_single_use(wallet2.clone(), mask2_i.clone(), |api| {
|
||||
// Wallet 2 receives the invoice transaction
|
||||
slate = PathToSlate((&receive_file).into()).get_tx()?.0;
|
||||
slate = api.finalize_invoice_tx(&slate)?;
|
||||
PathToSlate((&final_file).into()).put_tx(&slate, use_bin)?;
|
||||
Ok(())
|
||||
})?;
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
api.post_tx(m, &slate, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Standard, with payment proof
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
let (send_file, receive_file, final_file) = match use_bin {
|
||||
false => (
|
||||
format!("{}/standard_pp_S1.tx", test_dir),
|
||||
format!("{}/standard_pp_S2.tx", test_dir),
|
||||
format!("{}/standard_pp_S3.tx", test_dir),
|
||||
),
|
||||
true => (
|
||||
format!("{}/standard_pp_S1.txbin", test_dir),
|
||||
format!("{}/standard_pp_S2.txbin", test_dir),
|
||||
format!("{}/standard_pp_S3.txbin", test_dir),
|
||||
),
|
||||
};
|
||||
let mut slate = Slate::blank(2, true);
|
||||
let mut address = None;
|
||||
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
|
||||
let (_, tx) = api.retrieve_txs(m, true, None, Some(slate.id))?;
|
||||
assert_eq!(
|
||||
tx[0].clone().messages.unwrap().messages[0].message,
|
||||
Some(message.to_owned())
|
||||
);
|
||||
assert_eq!(
|
||||
tx[0].clone().messages.unwrap().messages[1].message,
|
||||
Some(sender2_message)
|
||||
);
|
||||
address = Some(api.get_public_proof_address(m, 0)?);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let address = OnionV3Address::from_bytes(address.as_ref().unwrap().to_bytes());
|
||||
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
// send to send
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: Some("mining".to_owned()),
|
||||
amount: reward,
|
||||
minimum_confirmations: 2,
|
||||
max_outputs: 500,
|
||||
num_change_outputs: 1,
|
||||
selection_strategy_is_use_all: true,
|
||||
payment_proof_recipient_address: Some(address.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
let slate = api.init_send_tx(m, args)?;
|
||||
PathToSlate((&send_file).into()).put_tx(&slate, use_bin)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::foreign_single_use(wallet2.clone(), mask2_i.clone(), |api| {
|
||||
slate = PathToSlate((&send_file).into()).get_tx()?.0;
|
||||
slate = api.receive_tx(&slate, None)?;
|
||||
PathToSlate((&receive_file).into()).put_tx(&slate, use_bin)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// wallet 1 finalises and posts
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
slate = PathToSlate(receive_file.into()).get_tx()?.0;
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
// Output final file for reference
|
||||
PathToSlate((&final_file).into()).put_tx(&slate, use_bin)?;
|
||||
api.post_tx(m, &slate, false)?;
|
||||
bh += 1;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -223,10 +302,21 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Erro
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wallet_file_exchange() {
|
||||
let test_dir = "test_output/file_exchange";
|
||||
fn wallet_file_exchange_json() {
|
||||
let test_dir = "test_output/file_exchange_json";
|
||||
setup(test_dir);
|
||||
if let Err(e) = file_exchange_test_impl(test_dir) {
|
||||
// Json output
|
||||
if let Err(e) = file_exchange_test_impl(test_dir, false) {
|
||||
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
|
||||
}
|
||||
clean_output_dir(test_dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wallet_file_exchange_bin() {
|
||||
let test_dir = "test_output/file_exchange_bin";
|
||||
setup(test_dir);
|
||||
if let Err(e) = file_exchange_test_impl(test_dir, true) {
|
||||
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
|
||||
}
|
||||
clean_output_dir(test_dir);
|
||||
|
||||
@@ -21,7 +21,7 @@ use grin_wallet_libwallet as libwallet;
|
||||
use grin_wallet_util::grin_core as core;
|
||||
|
||||
use impls::test_framework::{self, LocalWalletClient};
|
||||
use libwallet::{InitTxArgs, IssueInvoiceTxArgs, Slate};
|
||||
use libwallet::{InitTxArgs, IssueInvoiceTxArgs, Slate, SlateState};
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
@@ -95,7 +95,7 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let mut slate = Slate::blank(2);
|
||||
let mut slate = Slate::blank(2, true);
|
||||
|
||||
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
|
||||
// Wallet 2 inititates an invoice transaction, requesting payment
|
||||
@@ -106,6 +106,7 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
slate = api.issue_invoice_tx(m, args)?;
|
||||
Ok(())
|
||||
})?;
|
||||
assert_eq!(slate.state, SlateState::Invoice1);
|
||||
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
// Wallet 1 receives the invoice transaction
|
||||
@@ -119,9 +120,10 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
..Default::default()
|
||||
};
|
||||
slate = api.process_invoice_tx(m, &slate, args)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
assert_eq!(slate.state, SlateState::Invoice2);
|
||||
|
||||
// wallet 2 finalizes and posts
|
||||
wallet::controller::foreign_single_use(wallet2.clone(), mask2_i.clone(), |api| {
|
||||
@@ -129,10 +131,11 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
slate = api.finalize_invoice_tx(&slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
assert_eq!(slate.state, SlateState::Invoice3);
|
||||
|
||||
// wallet 1 posts so wallet 2 doesn't get the mined amount
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
api.post_tx(m, slate.tx_or_err()?, false)?;
|
||||
api.post_tx(m, &slate, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
bh += 1;
|
||||
@@ -151,7 +154,6 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
wallet2_info.last_confirmed_height, bh
|
||||
);
|
||||
assert!(refreshed);
|
||||
assert_eq!(wallet2_info.amount_currently_spendable, slate.amount);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -187,11 +189,14 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
println!("Self invoice slate init: {}", slate);
|
||||
slate = api.process_invoice_tx(m, &slate, args)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
println!("Self invoice slate after process: {}", slate);
|
||||
|
||||
// wallet 1 finalizes and posts
|
||||
wallet::controller::foreign_single_use(wallet1.clone(), mask1_i.clone(), |api| {
|
||||
// Wallet 2 receives the invoice transaction
|
||||
|
||||
@@ -76,7 +76,8 @@ fn no_change_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
let fee = core::libtx::tx_fee(1, 1, 1, None);
|
||||
|
||||
// send a single block's worth of transactions with minimal strategy
|
||||
let mut slate = Slate::blank(2);
|
||||
let mut slate = Slate::blank(2, false);
|
||||
let mut stored_excess = None;
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
@@ -89,19 +90,42 @@ fn no_change_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
};
|
||||
slate = api.init_send_tx(m, args)?;
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
api.post_tx(m, slate.tx_or_err()?, false)?;
|
||||
println!("Posted Slate: {:?}", slate);
|
||||
println!("Posted TX: {}", slate);
|
||||
stored_excess = Some(slate.tx.as_ref().unwrap().body.kernels[0].excess);
|
||||
api.post_tx(m, &slate, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// ensure stored excess is correct in both wallets
|
||||
// Wallet 1 calculated the excess with the full slate // Wallet 2 only had the excess provided by
|
||||
// wallet 1
|
||||
|
||||
// Refresh and check transaction log for wallet 1
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask2, None, |api, m| {
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
let (refreshed, txs) = api.retrieve_txs(m, true, None, Some(slate.id))?;
|
||||
assert!(refreshed);
|
||||
let tx = txs[0].clone();
|
||||
println!("SIMPLE SEND - SENDING WALLET");
|
||||
println!("{:?}", tx);
|
||||
println!();
|
||||
assert!(tx.confirmed);
|
||||
assert_eq!(stored_excess, tx.kernel_excess);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Refresh and check transaction log for wallet 2
|
||||
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
|
||||
let (refreshed, txs) = api.retrieve_txs(m, true, None, Some(slate.id))?;
|
||||
assert!(refreshed);
|
||||
let tx = txs[0].clone();
|
||||
println!("SIMPLE SEND - RECEIVING WALLET");
|
||||
println!("{:?}", tx);
|
||||
println!();
|
||||
assert!(tx.confirmed);
|
||||
assert_eq!(stored_excess, tx.kernel_excess);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -128,7 +152,7 @@ fn no_change_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
..Default::default()
|
||||
};
|
||||
slate = api.process_invoice_tx(m, &slate, args)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -139,16 +163,34 @@ fn no_change_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
Ok(())
|
||||
})?;
|
||||
wallet::controller::owner_single_use(Some(wallet2.clone()), mask1, None, |api, m| {
|
||||
api.post_tx(m, slate.tx_or_err()?, false)?;
|
||||
println!("Invoice Posted TX: {}", slate);
|
||||
stored_excess = Some(slate.tx.as_ref().unwrap().body.kernels[0].excess);
|
||||
api.post_tx(m, &slate, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// check wallet 2's version
|
||||
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
|
||||
let (refreshed, txs) = api.retrieve_txs(m, true, None, Some(slate.id))?;
|
||||
assert!(refreshed);
|
||||
for tx in txs {
|
||||
stored_excess = tx.kernel_excess;
|
||||
println!("Wallet 2: {:?}", tx);
|
||||
println!();
|
||||
assert!(tx.confirmed);
|
||||
assert_eq!(stored_excess, tx.kernel_excess);
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Refresh and check transaction log for wallet 1
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask2, None, |api, m| {
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
let (refreshed, txs) = api.retrieve_txs(m, true, None, Some(slate.id))?;
|
||||
assert!(refreshed);
|
||||
for tx in txs {
|
||||
println!("{:?}", tx);
|
||||
println!("Wallet 1: {:?}", tx);
|
||||
println!();
|
||||
assert_eq!(stored_excess, tx.kernel_excess);
|
||||
assert!(tx.confirmed);
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -87,7 +87,7 @@ fn payment_proofs_test_impl(test_dir: &'static str) -> Result<(), libwallet::Err
|
||||
let address = OnionV3Address::from_bytes(address.as_ref().unwrap().to_bytes());
|
||||
println!("Public address is: {:?}", address);
|
||||
let amount = 60_000_000_000;
|
||||
let mut slate = Slate::blank(1);
|
||||
let mut slate = Slate::blank(1, false);
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |sender_api, m| {
|
||||
// note this will increment the block count as part of the transaction "Posting"
|
||||
let args = InitTxArgs {
|
||||
@@ -111,12 +111,12 @@ fn payment_proofs_test_impl(test_dir: &'static str) -> Result<(), libwallet::Err
|
||||
slate_i.payment_proof.as_ref().unwrap().sender_address
|
||||
);
|
||||
|
||||
// Check we are creating a tx with the expected lock_height of 0.
|
||||
// Check we are creating a tx with kernel features 0
|
||||
// We will check this produces a Plain kernel later.
|
||||
assert_eq!(0, slate.lock_height);
|
||||
assert_eq!(0, slate.kernel_features);
|
||||
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(m, &slate, 0)?;
|
||||
sender_api.tx_lock_outputs(m, &slate)?;
|
||||
|
||||
// Ensure what's stored in TX log for payment proof is correct
|
||||
let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id))?;
|
||||
@@ -135,7 +135,7 @@ fn payment_proofs_test_impl(test_dir: &'static str) -> Result<(), libwallet::Err
|
||||
assert!(pp.is_err());
|
||||
|
||||
slate = sender_api.finalize_tx(m, &slate)?;
|
||||
sender_api.post_tx(m, slate.tx_or_err()?, true)?;
|
||||
sender_api.post_tx(m, &slate, true)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -145,7 +145,7 @@ fn payment_proofs_test_impl(test_dir: &'static str) -> Result<(), libwallet::Err
|
||||
// Check payment proof here
|
||||
let mut pp = sender_api.retrieve_payment_proof(m, true, None, Some(slate.id))?;
|
||||
|
||||
println!("{:?}", pp);
|
||||
println!("Payment proof: {:?}", pp);
|
||||
|
||||
// verify, should be good
|
||||
let res = sender_api.verify_payment_proof(m, &pp)?;
|
||||
|
||||
+16
-13
@@ -99,7 +99,7 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
let send_file = format!("{}/part_tx_1.tx", test_dir);
|
||||
let receive_file = format!("{}/part_tx_2.tx", test_dir);
|
||||
|
||||
let mut slate = Slate::blank(2);
|
||||
let mut slate = Slate::blank(2, false);
|
||||
|
||||
// Should have 5 in account1 (5 spendable), 5 in account (2 spendable)
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
@@ -118,8 +118,8 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
..Default::default()
|
||||
};
|
||||
let slate = api.init_send_tx(m, args)?;
|
||||
PathToSlate((&send_file).into()).put_tx(&slate)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
PathToSlate((&send_file).into()).put_tx(&slate, false)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -133,9 +133,9 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
}
|
||||
|
||||
wallet::controller::foreign_single_use(wallet1.clone(), mask1_i.clone(), |api| {
|
||||
slate = PathToSlate((&send_file).into()).get_tx()?;
|
||||
slate = api.receive_tx(&slate, None, None)?;
|
||||
PathToSlate((&receive_file).into()).put_tx(&slate)?;
|
||||
slate = PathToSlate((&send_file).into()).get_tx()?.0;
|
||||
slate = api.receive_tx(&slate, None)?;
|
||||
PathToSlate((&receive_file).into()).put_tx(&slate, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -147,7 +147,7 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
|
||||
// wallet 1 finalize
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
slate = PathToSlate((&receive_file).into()).get_tx()?;
|
||||
slate = PathToSlate((&receive_file).into()).get_tx()?.0;
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
@@ -155,8 +155,10 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
// Now repost from cached
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id))?;
|
||||
let stored_tx = api.get_stored_tx(m, &txs[0])?;
|
||||
api.post_tx(m, &stored_tx.unwrap(), false)?;
|
||||
println!("TXS[0]: {:?}", txs[0]);
|
||||
let stored_tx = api.get_stored_tx(m, txs[0].tx_slate_id.unwrap())?;
|
||||
println!("Stored tx: {:?}", stored_tx);
|
||||
api.post_tx(m, &slate, false)?;
|
||||
bh += 1;
|
||||
Ok(())
|
||||
})?;
|
||||
@@ -196,7 +198,7 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
w.set_parent_key_id_by_name("account1")?;
|
||||
}
|
||||
|
||||
let mut slate = Slate::blank(2);
|
||||
let mut slate = Slate::blank(2, false);
|
||||
let amount = 60_000_000_000;
|
||||
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |sender_api, m| {
|
||||
@@ -212,7 +214,7 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
};
|
||||
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(m, &slate, 0)?;
|
||||
sender_api.tx_lock_outputs(m, &slate)?;
|
||||
slate = sender_api.finalize_tx(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
@@ -223,8 +225,9 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
// Now repost from cached
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id))?;
|
||||
let stored_tx = api.get_stored_tx(m, &txs[0])?;
|
||||
api.post_tx(m, &stored_tx.unwrap(), false)?;
|
||||
let stored_tx = api.get_stored_tx(m, txs[0].tx_slate_id.unwrap())?;
|
||||
slate.tx = stored_tx;
|
||||
api.post_tx(m, &slate, false)?;
|
||||
bh += 1;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -169,8 +169,8 @@ fn revert(
|
||||
let slate = api.init_send_tx(m, args)?;
|
||||
// output tx file
|
||||
let send_file = format!("{}/part_tx_1.tx", test_dir);
|
||||
PathToSlate(send_file.into()).put_tx(&slate)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
PathToSlate(send_file.into()).put_tx(&slate, false)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
let slate = client1.send_tx_slate_direct("wallet2", &slate)?;
|
||||
let slate = api.finalize_tx(m, &slate)?;
|
||||
tx = Some(slate.tx);
|
||||
|
||||
@@ -94,14 +94,14 @@ fn self_send_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
..Default::default()
|
||||
};
|
||||
let mut slate = api.init_send_tx(m, args)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
// Send directly to self
|
||||
wallet::controller::foreign_single_use(wallet1.clone(), mask1_i.clone(), |api| {
|
||||
slate = api.receive_tx(&slate, Some("listener"), None)?;
|
||||
slate = api.receive_tx(&slate, Some("listener"))?;
|
||||
Ok(())
|
||||
})?;
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
api.post_tx(m, slate.tx_or_err()?, false)?; // mines a block
|
||||
api.post_tx(m, &slate, false)?; // mines a block
|
||||
bh += 1;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -22,7 +22,7 @@ use grin_wallet_util::grin_core as core;
|
||||
|
||||
use self::core::core::transaction;
|
||||
use self::core::global;
|
||||
use self::libwallet::{InitTxArgs, OutputStatus, Slate};
|
||||
use self::libwallet::{InitTxArgs, OutputStatus, Slate, SlateState};
|
||||
use impls::test_framework::{self, LocalWalletClient};
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::thread;
|
||||
@@ -97,7 +97,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
// assert wallet contents
|
||||
// and a single use api for a send command
|
||||
let amount = 60_000_000_000;
|
||||
let mut slate = Slate::blank(1);
|
||||
let mut slate = Slate::blank(1, false);
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |sender_api, m| {
|
||||
// note this will increment the block count as part of the transaction "Posting"
|
||||
let args = InitTxArgs {
|
||||
@@ -111,13 +111,17 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
};
|
||||
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||
|
||||
assert_eq!(slate_i.state, SlateState::Standard1);
|
||||
|
||||
// Check we are creating a tx with the expected lock_height of 0.
|
||||
// We will check this produces a Plain kernel later.
|
||||
assert_eq!(0, slate.lock_height);
|
||||
assert_eq!(0, slate.kernel_features);
|
||||
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(m, &slate, 0)?;
|
||||
assert_eq!(slate.state, SlateState::Standard2);
|
||||
sender_api.tx_lock_outputs(m, &slate)?;
|
||||
slate = sender_api.finalize_tx(m, &slate)?;
|
||||
assert_eq!(slate.state, SlateState::Standard3);
|
||||
|
||||
// Check we have a single kernel and that it is a Plain kernel (no lock_height).
|
||||
assert_eq!(slate.tx_or_err()?.kernels().len(), 1);
|
||||
@@ -175,7 +179,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
|
||||
// post transaction
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
api.post_tx(m, slate.tx_or_err()?, false)?;
|
||||
api.post_tx(m, &slate, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -299,7 +303,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
};
|
||||
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(m, &slate, 0)?;
|
||||
sender_api.tx_lock_outputs(m, &slate)?;
|
||||
slate = sender_api.finalize_tx(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
@@ -313,8 +317,9 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
.iter()
|
||||
.find(|t| t.tx_slate_id == Some(slate.id))
|
||||
.unwrap();
|
||||
let stored_tx = sender_api.get_stored_tx(m, &tx)?;
|
||||
sender_api.post_tx(m, &stored_tx.unwrap(), false)?;
|
||||
let stored_tx = sender_api.get_stored_tx(m, tx.tx_slate_id.unwrap())?;
|
||||
slate.tx = stored_tx;
|
||||
sender_api.post_tx(m, &slate, false)?;
|
||||
let (_, wallet1_info) = sender_api.retrieve_summary_info(m, true, 1)?;
|
||||
// should be mined now
|
||||
assert_eq!(
|
||||
@@ -395,7 +400,7 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 5, false);
|
||||
|
||||
let amount = 30_000_000_000;
|
||||
let mut slate = Slate::blank(1);
|
||||
let mut slate = Slate::blank(1, false);
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |sender_api, m| {
|
||||
// note this will increment the block count as part of the transaction "Posting"
|
||||
let args = InitTxArgs {
|
||||
@@ -410,7 +415,7 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
|
||||
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(m, &slate, 0)?;
|
||||
sender_api.tx_lock_outputs(m, &slate)?;
|
||||
slate = sender_api.finalize_tx(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -77,7 +77,7 @@ fn ttl_cutoff_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
|
||||
|
||||
let amount = 60_000_000_000;
|
||||
let mut slate = Slate::blank(1);
|
||||
let mut slate = Slate::blank(1, false);
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |sender_api, m| {
|
||||
// note this will increment the block count as part of the transaction "Posting"
|
||||
let args = InitTxArgs {
|
||||
@@ -93,7 +93,7 @@ fn ttl_cutoff_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(m, &slate, 0)?;
|
||||
sender_api.tx_lock_outputs(m, &slate)?;
|
||||
|
||||
let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id))?;
|
||||
let tx = txs[0].clone();
|
||||
@@ -127,7 +127,7 @@ fn ttl_cutoff_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
})?;
|
||||
|
||||
// try again, except try and send off the transaction for completion beyond the expiry
|
||||
let mut slate = Slate::blank(1);
|
||||
let mut slate = Slate::blank(1, false);
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |sender_api, m| {
|
||||
// note this will increment the block count as part of the transaction "Posting"
|
||||
let args = InitTxArgs {
|
||||
@@ -141,7 +141,7 @@ fn ttl_cutoff_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
||||
..Default::default()
|
||||
};
|
||||
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||
sender_api.tx_lock_outputs(m, &slate_i, 0)?;
|
||||
sender_api.tx_lock_outputs(m, &slate_i)?;
|
||||
slate = slate_i;
|
||||
|
||||
let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id))?;
|
||||
|
||||
Reference in New Issue
Block a user