2018-12-06 15:04:02 +03:00
|
|
|
// Copyright 2018 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.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2019-01-11 02:58:37 +03:00
|
|
|
use crate::util::{Mutex, ZeroingString};
|
2018-12-06 15:04:02 +03:00
|
|
|
use std::collections::HashMap;
|
|
|
|
/// Grin wallet command-line function implementations
|
|
|
|
use std::fs::File;
|
|
|
|
use std::io::Write;
|
|
|
|
use std::sync::Arc;
|
|
|
|
use std::thread;
|
|
|
|
use std::time::Duration;
|
|
|
|
|
|
|
|
use serde_json as json;
|
|
|
|
use uuid::Uuid;
|
|
|
|
|
2018-12-08 02:59:40 +03:00
|
|
|
use crate::api::TLSConfig;
|
|
|
|
use crate::core::core;
|
|
|
|
use crate::keychain;
|
2018-12-06 15:04:02 +03:00
|
|
|
|
2018-12-08 02:59:40 +03:00
|
|
|
use crate::error::{Error, ErrorKind};
|
|
|
|
use crate::{controller, display, HTTPNodeClient, WalletConfig, WalletInst, WalletSeed};
|
|
|
|
use crate::{
|
2018-12-06 20:51:53 +03:00
|
|
|
FileWalletCommAdapter, HTTPWalletCommAdapter, KeybaseWalletCommAdapter, LMDBBackend,
|
2018-12-07 18:06:28 +03:00
|
|
|
NodeClient, NullWalletCommAdapter,
|
2018-12-06 20:51:53 +03:00
|
|
|
};
|
2018-12-06 15:04:02 +03:00
|
|
|
|
|
|
|
/// Arguments common to all wallet commands
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct GlobalArgs {
|
|
|
|
pub account: String,
|
|
|
|
pub node_api_secret: Option<String>,
|
|
|
|
pub show_spent: bool,
|
2019-01-11 02:58:37 +03:00
|
|
|
pub password: Option<ZeroingString>,
|
2018-12-06 15:04:02 +03:00
|
|
|
pub tls_conf: Option<TLSConfig>,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Arguments for init command
|
|
|
|
pub struct InitArgs {
|
|
|
|
/// BIP39 recovery phrase length
|
|
|
|
pub list_length: usize,
|
2019-01-11 02:58:37 +03:00
|
|
|
pub password: ZeroingString,
|
2018-12-06 15:04:02 +03:00
|
|
|
pub config: WalletConfig,
|
2019-01-11 02:58:37 +03:00
|
|
|
pub recovery_phrase: Option<ZeroingString>,
|
2019-01-10 15:06:12 +03:00
|
|
|
pub restore: bool,
|
2018-12-06 15:04:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn init(g_args: &GlobalArgs, args: InitArgs) -> Result<(), Error> {
|
2019-01-10 15:06:12 +03:00
|
|
|
WalletSeed::init_file(
|
|
|
|
&args.config,
|
|
|
|
args.list_length,
|
|
|
|
args.recovery_phrase,
|
|
|
|
&args.password,
|
|
|
|
)?;
|
2018-12-06 15:04:02 +03:00
|
|
|
info!("Wallet seed file created");
|
|
|
|
let client_n = HTTPNodeClient::new(
|
|
|
|
&args.config.check_node_api_http_addr,
|
|
|
|
g_args.node_api_secret.clone(),
|
|
|
|
);
|
|
|
|
let _: LMDBBackend<HTTPNodeClient, keychain::ExtKeychain> =
|
|
|
|
LMDBBackend::new(args.config.clone(), &args.password, client_n)?;
|
|
|
|
info!("Wallet database backend created");
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Argument for recover
|
|
|
|
pub struct RecoverArgs {
|
2019-01-11 02:58:37 +03:00
|
|
|
pub recovery_phrase: Option<ZeroingString>,
|
|
|
|
pub passphrase: ZeroingString,
|
2018-12-06 15:04:02 +03:00
|
|
|
}
|
|
|
|
|
2019-01-09 19:13:05 +03:00
|
|
|
/// Check whether seed file exists
|
|
|
|
pub fn wallet_seed_exists(config: &WalletConfig) -> Result<(), Error> {
|
|
|
|
let res = WalletSeed::seed_file_exists(&config)?;
|
|
|
|
Ok(res)
|
|
|
|
}
|
|
|
|
|
2018-12-06 15:04:02 +03:00
|
|
|
pub fn recover(config: &WalletConfig, args: RecoverArgs) -> Result<(), Error> {
|
|
|
|
if args.recovery_phrase.is_none() {
|
|
|
|
let res = WalletSeed::from_file(config, &args.passphrase);
|
|
|
|
if let Err(e) = res {
|
|
|
|
error!("Error loading wallet seed (check password): {}", e);
|
|
|
|
return Err(e);
|
|
|
|
}
|
|
|
|
let _ = res.unwrap().show_recovery_phrase();
|
|
|
|
} else {
|
|
|
|
let res = WalletSeed::recover_from_phrase(
|
|
|
|
&config,
|
|
|
|
&args.recovery_phrase.as_ref().unwrap(),
|
|
|
|
&args.passphrase,
|
|
|
|
);
|
|
|
|
if let Err(e) = res {
|
2019-01-02 23:10:07 +03:00
|
|
|
error!("Error recovering seed - {}", e);
|
2018-12-06 15:04:02 +03:00
|
|
|
return Err(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Arguments for listen command
|
|
|
|
pub struct ListenArgs {
|
2018-12-06 20:51:53 +03:00
|
|
|
pub method: String,
|
2018-12-06 15:04:02 +03:00
|
|
|
}
|
|
|
|
|
2018-12-06 20:51:53 +03:00
|
|
|
pub fn listen(config: &WalletConfig, args: &ListenArgs, g_args: &GlobalArgs) -> Result<(), Error> {
|
2018-12-06 15:04:02 +03:00
|
|
|
let mut params = HashMap::new();
|
|
|
|
params.insert("api_listen_addr".to_owned(), config.api_listen_addr());
|
|
|
|
if let Some(t) = g_args.tls_conf.as_ref() {
|
|
|
|
params.insert("certificate".to_owned(), t.certificate.clone());
|
|
|
|
params.insert("private_key".to_owned(), t.private_key.clone());
|
|
|
|
}
|
2018-12-06 20:51:53 +03:00
|
|
|
let adapter = match args.method.as_str() {
|
|
|
|
"http" => HTTPWalletCommAdapter::new(),
|
|
|
|
"keybase" => KeybaseWalletCommAdapter::new(),
|
|
|
|
_ => NullWalletCommAdapter::new(),
|
|
|
|
};
|
|
|
|
|
2018-12-06 15:04:02 +03:00
|
|
|
let res = adapter.listen(
|
|
|
|
params,
|
|
|
|
config.clone(),
|
|
|
|
&g_args.password.clone().unwrap(),
|
|
|
|
&g_args.account,
|
|
|
|
g_args.node_api_secret.clone(),
|
|
|
|
);
|
|
|
|
if let Err(e) = res {
|
|
|
|
return Err(ErrorKind::LibWallet(e.kind(), e.cause_string()).into());
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2018-12-07 18:06:28 +03:00
|
|
|
pub fn owner_api(
|
|
|
|
wallet: Arc<Mutex<WalletInst<impl NodeClient + 'static, keychain::ExtKeychain>>>,
|
2019-01-07 13:00:52 +03:00
|
|
|
config: &WalletConfig,
|
2018-12-07 18:06:28 +03:00
|
|
|
g_args: &GlobalArgs,
|
|
|
|
) -> Result<(), Error> {
|
2018-12-06 15:04:02 +03:00
|
|
|
let res = controller::owner_listener(
|
|
|
|
wallet,
|
|
|
|
"127.0.0.1:13420",
|
|
|
|
g_args.node_api_secret.clone(),
|
|
|
|
g_args.tls_conf.clone(),
|
2019-01-07 13:00:52 +03:00
|
|
|
config.owner_api_include_foreign.clone(),
|
2018-12-06 15:04:02 +03:00
|
|
|
);
|
|
|
|
if let Err(e) = res {
|
|
|
|
return Err(ErrorKind::LibWallet(e.kind(), e.cause_string()).into());
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Arguments for account command
|
|
|
|
pub struct AccountArgs {
|
|
|
|
pub create: Option<String>,
|
|
|
|
}
|
|
|
|
|
2018-12-07 18:06:28 +03:00
|
|
|
pub fn account(
|
|
|
|
wallet: Arc<Mutex<WalletInst<impl NodeClient + 'static, keychain::ExtKeychain>>>,
|
|
|
|
args: AccountArgs,
|
|
|
|
) -> Result<(), Error> {
|
2018-12-06 15:04:02 +03:00
|
|
|
if args.create.is_none() {
|
|
|
|
let res = controller::owner_single_use(wallet, |api| {
|
|
|
|
let acct_mappings = api.accounts()?;
|
|
|
|
// give logging thread a moment to catch up
|
|
|
|
thread::sleep(Duration::from_millis(200));
|
|
|
|
display::accounts(acct_mappings);
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
if let Err(e) = res {
|
|
|
|
error!("Error listing accounts: {}", e);
|
|
|
|
return Err(ErrorKind::LibWallet(e.kind(), e.cause_string()).into());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let label = args.create.unwrap();
|
|
|
|
let res = controller::owner_single_use(wallet, |api| {
|
|
|
|
api.create_account_path(&label)?;
|
|
|
|
thread::sleep(Duration::from_millis(200));
|
|
|
|
info!("Account: '{}' Created!", label);
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
if let Err(e) = res {
|
|
|
|
thread::sleep(Duration::from_millis(200));
|
|
|
|
error!("Error creating account '{}': {}", label, e);
|
|
|
|
return Err(ErrorKind::LibWallet(e.kind(), e.cause_string()).into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Arguments for the send command
|
|
|
|
pub struct SendArgs {
|
|
|
|
pub amount: u64,
|
|
|
|
pub message: Option<String>,
|
|
|
|
pub minimum_confirmations: u64,
|
|
|
|
pub selection_strategy: String,
|
|
|
|
pub method: String,
|
|
|
|
pub dest: String,
|
|
|
|
pub change_outputs: usize,
|
|
|
|
pub fluff: bool,
|
|
|
|
pub max_outputs: usize,
|
|
|
|
}
|
|
|
|
|
2018-12-07 18:06:28 +03:00
|
|
|
pub fn send(
|
|
|
|
wallet: Arc<Mutex<WalletInst<impl NodeClient + 'static, keychain::ExtKeychain>>>,
|
|
|
|
args: SendArgs,
|
|
|
|
) -> Result<(), Error> {
|
2018-12-06 15:04:02 +03:00
|
|
|
controller::owner_single_use(wallet.clone(), |api| {
|
|
|
|
let result = api.initiate_tx(
|
|
|
|
None,
|
|
|
|
args.amount,
|
|
|
|
args.minimum_confirmations,
|
|
|
|
args.max_outputs,
|
|
|
|
args.change_outputs,
|
|
|
|
args.selection_strategy == "all",
|
|
|
|
args.message.clone(),
|
|
|
|
);
|
|
|
|
let (mut slate, lock_fn) = match result {
|
|
|
|
Ok(s) => {
|
|
|
|
info!(
|
|
|
|
"Tx created: {} grin to {} (strategy '{}')",
|
|
|
|
core::amount_to_hr_string(args.amount, false),
|
|
|
|
args.dest,
|
|
|
|
args.selection_strategy,
|
|
|
|
);
|
|
|
|
s
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
info!("Tx not created: {}", e);
|
|
|
|
return Err(e);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let adapter = match args.method.as_str() {
|
|
|
|
"http" => HTTPWalletCommAdapter::new(),
|
|
|
|
"file" => FileWalletCommAdapter::new(),
|
2018-12-06 20:51:53 +03:00
|
|
|
"keybase" => KeybaseWalletCommAdapter::new(),
|
2018-12-06 15:04:02 +03:00
|
|
|
"self" => NullWalletCommAdapter::new(),
|
|
|
|
_ => NullWalletCommAdapter::new(),
|
|
|
|
};
|
|
|
|
if adapter.supports_sync() {
|
|
|
|
slate = adapter.send_tx_sync(&args.dest, &slate)?;
|
2018-12-12 16:38:29 +03:00
|
|
|
api.tx_lock_outputs(&slate, lock_fn)?;
|
2018-12-06 15:04:02 +03:00
|
|
|
if args.method == "self" {
|
|
|
|
controller::foreign_single_use(wallet, |api| {
|
|
|
|
api.receive_tx(&mut slate, Some(&args.dest), None)?;
|
|
|
|
Ok(())
|
|
|
|
})?;
|
|
|
|
}
|
|
|
|
if let Err(e) = api.verify_slate_messages(&slate) {
|
|
|
|
error!("Error validating participant messages: {}", e);
|
|
|
|
return Err(e);
|
|
|
|
}
|
|
|
|
api.finalize_tx(&mut slate)?;
|
|
|
|
} else {
|
|
|
|
adapter.send_tx_async(&args.dest, &slate)?;
|
|
|
|
api.tx_lock_outputs(&slate, lock_fn)?;
|
|
|
|
}
|
|
|
|
if adapter.supports_sync() {
|
|
|
|
let result = api.post_tx(&slate.tx, args.fluff);
|
|
|
|
match result {
|
|
|
|
Ok(_) => {
|
2018-12-25 03:05:24 +03:00
|
|
|
info!("Tx sent ok",);
|
2018-12-06 15:04:02 +03:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
Err(e) => {
|
2018-12-25 03:05:24 +03:00
|
|
|
error!("Tx sent fail: {}", e);
|
2018-12-06 15:04:02 +03:00
|
|
|
return Err(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
})?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Receive command argument
|
|
|
|
pub struct ReceiveArgs {
|
|
|
|
pub input: String,
|
|
|
|
pub message: Option<String>,
|
|
|
|
}
|
|
|
|
|
2018-12-07 18:06:28 +03:00
|
|
|
pub fn receive(
|
|
|
|
wallet: Arc<Mutex<WalletInst<impl NodeClient + 'static, keychain::ExtKeychain>>>,
|
|
|
|
g_args: &GlobalArgs,
|
|
|
|
args: ReceiveArgs,
|
|
|
|
) -> Result<(), Error> {
|
2018-12-06 15:04:02 +03:00
|
|
|
let adapter = FileWalletCommAdapter::new();
|
|
|
|
let mut slate = adapter.receive_tx_async(&args.input)?;
|
|
|
|
controller::foreign_single_use(wallet, |api| {
|
2018-12-23 02:25:02 +03:00
|
|
|
if let Err(e) = api.verify_slate_messages(&slate) {
|
|
|
|
error!("Error validating participant messages: {}", e);
|
|
|
|
return Err(e);
|
|
|
|
}
|
2018-12-06 15:04:02 +03:00
|
|
|
api.receive_tx(&mut slate, Some(&g_args.account), args.message.clone())?;
|
|
|
|
Ok(())
|
|
|
|
})?;
|
|
|
|
let send_tx = format!("{}.response", args.input);
|
|
|
|
adapter.send_tx_async(&send_tx, &slate)?;
|
|
|
|
info!(
|
|
|
|
"Response file {}.response generated, sending it back to the transaction originator.",
|
|
|
|
args.input
|
|
|
|
);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Finalize command args
|
|
|
|
pub struct FinalizeArgs {
|
|
|
|
pub input: String,
|
|
|
|
pub fluff: bool,
|
|
|
|
}
|
|
|
|
|
2018-12-07 18:06:28 +03:00
|
|
|
pub fn finalize(
|
|
|
|
wallet: Arc<Mutex<WalletInst<impl NodeClient + 'static, keychain::ExtKeychain>>>,
|
|
|
|
args: FinalizeArgs,
|
|
|
|
) -> Result<(), Error> {
|
2018-12-06 15:04:02 +03:00
|
|
|
let adapter = FileWalletCommAdapter::new();
|
|
|
|
let mut slate = adapter.receive_tx_async(&args.input)?;
|
|
|
|
controller::owner_single_use(wallet.clone(), |api| {
|
|
|
|
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 result = api.post_tx(&slate.tx, args.fluff);
|
|
|
|
match result {
|
|
|
|
Ok(_) => {
|
|
|
|
info!("Transaction sent successfully, check the wallet again for confirmation.");
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
error!("Tx not sent: {}", e);
|
|
|
|
Err(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Info command args
|
|
|
|
pub struct InfoArgs {
|
|
|
|
pub minimum_confirmations: u64,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn info(
|
2018-12-07 18:06:28 +03:00
|
|
|
wallet: Arc<Mutex<WalletInst<impl NodeClient + 'static, keychain::ExtKeychain>>>,
|
2018-12-06 15:04:02 +03:00
|
|
|
g_args: &GlobalArgs,
|
|
|
|
args: InfoArgs,
|
|
|
|
dark_scheme: bool,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
controller::owner_single_use(wallet.clone(), |api| {
|
|
|
|
let (validated, wallet_info) =
|
|
|
|
api.retrieve_summary_info(true, args.minimum_confirmations)?;
|
|
|
|
display::info(&g_args.account, &wallet_info, validated, dark_scheme);
|
|
|
|
Ok(())
|
|
|
|
})?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2018-12-07 18:06:28 +03:00
|
|
|
pub fn outputs(
|
|
|
|
wallet: Arc<Mutex<WalletInst<impl NodeClient + 'static, keychain::ExtKeychain>>>,
|
|
|
|
g_args: &GlobalArgs,
|
|
|
|
dark_scheme: bool,
|
|
|
|
) -> Result<(), Error> {
|
2018-12-06 15:04:02 +03:00
|
|
|
controller::owner_single_use(wallet.clone(), |api| {
|
|
|
|
let (height, _) = api.node_height()?;
|
|
|
|
let (validated, outputs) = api.retrieve_outputs(g_args.show_spent, true, None)?;
|
|
|
|
display::outputs(&g_args.account, height, validated, outputs, dark_scheme)?;
|
|
|
|
Ok(())
|
|
|
|
})?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Txs command args
|
|
|
|
pub struct TxsArgs {
|
|
|
|
pub id: Option<u32>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn txs(
|
2018-12-07 18:06:28 +03:00
|
|
|
wallet: Arc<Mutex<WalletInst<impl NodeClient + 'static, keychain::ExtKeychain>>>,
|
2018-12-06 15:04:02 +03:00
|
|
|
g_args: &GlobalArgs,
|
|
|
|
args: TxsArgs,
|
|
|
|
dark_scheme: bool,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
controller::owner_single_use(wallet.clone(), |api| {
|
|
|
|
let (height, _) = api.node_height()?;
|
|
|
|
let (validated, txs) = api.retrieve_txs(true, args.id, None)?;
|
|
|
|
let include_status = !args.id.is_some();
|
|
|
|
display::txs(
|
|
|
|
&g_args.account,
|
|
|
|
height,
|
|
|
|
validated,
|
|
|
|
txs,
|
|
|
|
include_status,
|
|
|
|
dark_scheme,
|
|
|
|
)?;
|
|
|
|
// if given a particular transaction id, also get and display associated
|
|
|
|
// inputs/outputs
|
|
|
|
if args.id.is_some() {
|
|
|
|
let (_, outputs) = api.retrieve_outputs(true, false, args.id)?;
|
|
|
|
display::outputs(&g_args.account, height, validated, outputs, dark_scheme)?;
|
|
|
|
};
|
|
|
|
Ok(())
|
|
|
|
})?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Repost
|
|
|
|
pub struct RepostArgs {
|
|
|
|
pub id: u32,
|
|
|
|
pub dump_file: Option<String>,
|
|
|
|
pub fluff: bool,
|
|
|
|
}
|
|
|
|
|
2018-12-07 18:06:28 +03:00
|
|
|
pub fn repost(
|
|
|
|
wallet: Arc<Mutex<WalletInst<impl NodeClient + 'static, keychain::ExtKeychain>>>,
|
|
|
|
args: RepostArgs,
|
|
|
|
) -> Result<(), Error> {
|
2018-12-06 15:04:02 +03:00
|
|
|
controller::owner_single_use(wallet.clone(), |api| {
|
|
|
|
let (_, txs) = api.retrieve_txs(true, Some(args.id), None)?;
|
2018-12-14 19:24:53 +03:00
|
|
|
let stored_tx = api.get_stored_tx(&txs[0])?;
|
2018-12-06 15:04:02 +03:00
|
|
|
if stored_tx.is_none() {
|
|
|
|
error!(
|
|
|
|
"Transaction with id {} does not have transaction data. Not reposting.",
|
|
|
|
args.id
|
|
|
|
);
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
match args.dump_file {
|
|
|
|
None => {
|
|
|
|
if txs[0].confirmed {
|
|
|
|
error!(
|
|
|
|
"Transaction with id {} is confirmed. Not reposting.",
|
|
|
|
args.id
|
|
|
|
);
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
api.post_tx(&stored_tx.unwrap(), args.fluff)?;
|
|
|
|
info!("Reposted transaction at {}", args.id);
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
Some(f) => {
|
|
|
|
let mut tx_file = File::create(f.clone())?;
|
|
|
|
tx_file.write_all(json::to_string(&stored_tx).unwrap().as_bytes())?;
|
|
|
|
tx_file.sync_all()?;
|
|
|
|
info!("Dumped transaction data for tx {} to {}", args.id, f);
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Cancel
|
|
|
|
pub struct CancelArgs {
|
|
|
|
pub tx_id: Option<u32>,
|
|
|
|
pub tx_slate_id: Option<Uuid>,
|
|
|
|
pub tx_id_string: String,
|
|
|
|
}
|
|
|
|
|
2018-12-07 18:06:28 +03:00
|
|
|
pub fn cancel(
|
|
|
|
wallet: Arc<Mutex<WalletInst<impl NodeClient + 'static, keychain::ExtKeychain>>>,
|
|
|
|
args: CancelArgs,
|
|
|
|
) -> Result<(), Error> {
|
2018-12-06 15:04:02 +03:00
|
|
|
controller::owner_single_use(wallet.clone(), |api| {
|
|
|
|
let result = api.cancel_tx(args.tx_id, args.tx_slate_id);
|
|
|
|
match result {
|
|
|
|
Ok(_) => {
|
|
|
|
info!("Transaction {} Cancelled", args.tx_id_string);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
error!("TX Cancellation failed: {}", e);
|
|
|
|
Err(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2018-12-07 18:06:28 +03:00
|
|
|
pub fn restore(
|
|
|
|
wallet: Arc<Mutex<WalletInst<impl NodeClient + 'static, keychain::ExtKeychain>>>,
|
|
|
|
) -> Result<(), Error> {
|
2018-12-06 15:04:02 +03:00
|
|
|
controller::owner_single_use(wallet.clone(), |api| {
|
|
|
|
let result = api.restore();
|
|
|
|
match result {
|
|
|
|
Ok(_) => {
|
2018-12-30 19:32:00 +03:00
|
|
|
warn!("Wallet restore complete",);
|
2018-12-06 15:04:02 +03:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
error!("Wallet restore failed: {}", e);
|
|
|
|
error!("Backtrace: {}", e.backtrace().unwrap());
|
|
|
|
Err(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})?;
|
|
|
|
Ok(())
|
|
|
|
}
|
2018-12-30 19:32:00 +03:00
|
|
|
|
|
|
|
pub fn check_repair(
|
|
|
|
wallet: Arc<Mutex<WalletInst<impl NodeClient + 'static, keychain::ExtKeychain>>>,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
controller::owner_single_use(wallet.clone(), |api| {
|
2019-01-10 14:17:35 +03:00
|
|
|
warn!("Starting wallet check...",);
|
|
|
|
warn!("Updating all wallet outputs, please wait ...",);
|
2018-12-30 19:32:00 +03:00
|
|
|
let result = api.check_repair();
|
|
|
|
match result {
|
|
|
|
Ok(_) => {
|
2019-01-10 14:17:35 +03:00
|
|
|
warn!("Wallet check complete",);
|
2018-12-30 19:32:00 +03:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
Err(e) => {
|
2019-01-10 14:17:35 +03:00
|
|
|
error!("Wallet check failed: {}", e);
|
2018-12-30 19:32:00 +03:00
|
|
|
error!("Backtrace: {}", e.backtrace().unwrap());
|
|
|
|
Err(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})?;
|
|
|
|
Ok(())
|
|
|
|
}
|