mirror of
https://github.com/mimblewimble/grin-wallet.git
synced 2025-01-21 03:21:08 +03:00
Revert "Merge branch 'master' into master"
This reverts commita63f2c7cea
, reversing changes made tod774272fee
.
This commit is contained in:
parent
a63f2c7cea
commit
e509405b8a
17 changed files with 26 additions and 772 deletions
|
@ -1,9 +1,9 @@
|
||||||
[![Build Status](https://img.shields.io/travis/gottstech/grin-wallet/master.svg)](https://travis-ci.org/gottstech/grin-wallet)
|
[![Build Status](https://img.shields.io/travis/mimblewimble/grin-wallet/master.svg)](https://travis-ci.org/mimblewimble/grin-wallet)
|
||||||
[![Coverage Status](https://img.shields.io/codecov/c/github/gottstech/grin-wallet/master.svg)](https://codecov.io/gh/gottstech/grin-wallet)
|
[![Coverage Status](https://img.shields.io/codecov/c/github/mimblewimble/grin-wallet/master.svg)](https://codecov.io/gh/mimblewimble/grin-wallet)
|
||||||
[![Chat](https://img.shields.io/gitter/room/grin_community/Lobby.svg)](https://gitter.im/grin_community/Lobby)
|
[![Chat](https://img.shields.io/gitter/room/grin_community/Lobby.svg)](https://gitter.im/grin_community/Lobby)
|
||||||
[![Support](https://img.shields.io/badge/support-on%20gitter-brightgreen.svg)](https://gitter.im/grin_community/support)
|
[![Support](https://img.shields.io/badge/support-on%20gitter-brightgreen.svg)](https://gitter.im/grin_community/support)
|
||||||
[![Documentation Wiki](https://img.shields.io/badge/doc-wiki-blue.svg)](https://github.com/mimblewimble/docs/wiki)
|
[![Documentation Wiki](https://img.shields.io/badge/doc-wiki-blue.svg)](https://github.com/mimblewimble/docs/wiki)
|
||||||
[![Release Version](https://img.shields.io/github/release/gottstech/grin-wallet.svg)](https://github.com/gottstech/grin-wallet/releases)
|
[![Release Version](https://img.shields.io/github/release/mimblewimble/grin-wallet.svg)](https://github.com/mimblewimble/grin-wallet/releases)
|
||||||
[![License](https://img.shields.io/github/license/gottstech/grin-wallet.svg)](https://github.com/gottstech/grin-wallet/blob/master/LICENSE)
|
[![License](https://img.shields.io/github/license/mimblewimble/grin-wallet.svg)](https://github.com/mimblewimble/grin-wallet/blob/master/LICENSE)
|
||||||
|
|
||||||
# Grin Wallet
|
# Grin Wallet
|
||||||
|
|
|
@ -24,11 +24,9 @@ use crate::core::core::Transaction;
|
||||||
use crate::impls::{HTTPWalletCommAdapter, KeybaseWalletCommAdapter};
|
use crate::impls::{HTTPWalletCommAdapter, KeybaseWalletCommAdapter};
|
||||||
use crate::keychain::{Identifier, Keychain};
|
use crate::keychain::{Identifier, Keychain};
|
||||||
use crate::libwallet::api_impl::owner;
|
use crate::libwallet::api_impl::owner;
|
||||||
|
use crate::libwallet::{
|
||||||
use crate::libwallet::slate::Slate;
|
AcctPathMapping, Error, ErrorKind, InitTxArgs, NodeClient, NodeHeightResult,
|
||||||
use crate::libwallet::types::{
|
OutputCommitMapping, Slate, TxLogEntry, WalletBackend, WalletInfo,
|
||||||
AcctPathMapping, Error, ErrorKind, InitTxArgs, NodeClient, NodeHeightResult, OutputCommitMapping,
|
|
||||||
PaymentCommitMapping, Slate, TxLogEntry, WalletBackend, WalletInfo,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Main interface into all wallet API functions.
|
/// Main interface into all wallet API functions.
|
||||||
|
@ -304,56 +302,6 @@ where
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of payment outputs from the active account in the wallet.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
/// * `refresh_from_node` - If true, the wallet will attempt to contact
|
|
||||||
/// a node (via the [`NodeClient`](../grin_wallet_libwallet/types/trait.NodeClient.html)
|
|
||||||
/// provided during wallet instantiation). If `false`, the results will
|
|
||||||
/// contain output information that may be out-of-date (from the last time
|
|
||||||
/// the wallet's output set was refreshed against the node).
|
|
||||||
/// * `tx_id` - If `Some(i)`, only return the outputs associated with
|
|
||||||
/// the transaction log entry of id `i`.
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
/// * `(bool, Vec<PaymentCommitMapping>)` - A tuple:
|
|
||||||
/// * The first `bool` element indicates whether the data was successfully
|
|
||||||
/// refreshed from the node (note this may be false even if the `refresh_from_node`
|
|
||||||
/// argument was set to `true`.
|
|
||||||
/// * The second element contains a vector of
|
|
||||||
/// [PaymentCommitMapping](../grin_wallet_libwallet/types/struct.PaymentCommitMapping.html)
|
|
||||||
/// of which each element is a mapping between the wallet's internal
|
|
||||||
/// [PaymentData](../grin_wallet_libwallet/types/struct.Output.html)
|
|
||||||
/// and the Output commitment
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// Set up as in [`new`](struct.Owner.html#method.new) method above.
|
|
||||||
/// ```
|
|
||||||
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
|
||||||
///
|
|
||||||
/// let api_owner = Owner::new(wallet.clone());
|
|
||||||
/// let update_from_node = true;
|
|
||||||
/// let tx_id = None;
|
|
||||||
///
|
|
||||||
/// let result = api_owner.retrieve_payments(update_from_node, tx_id);
|
|
||||||
///
|
|
||||||
/// if let Ok((was_updated, payment_mappings)) = result {
|
|
||||||
/// //...
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
pub fn retrieve_payments(
|
|
||||||
&self,
|
|
||||||
refresh_from_node: bool,
|
|
||||||
tx_id: Option<Uuid>,
|
|
||||||
) -> Result<(bool, Vec<PaymentCommitMapping>), Error> {
|
|
||||||
let mut w = self.wallet.lock();
|
|
||||||
w.open_with_credentials()?;
|
|
||||||
let res = owner::retrieve_payments(&mut *w, refresh_from_node, tx_id);
|
|
||||||
w.close()?;
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a list of [Transaction Log Entries](../grin_wallet_libwallet/types/struct.TxLogEntry.html)
|
/// Returns a list of [Transaction Log Entries](../grin_wallet_libwallet/types/struct.TxLogEntry.html)
|
||||||
/// from the active account in the wallet.
|
/// from the active account in the wallet.
|
||||||
///
|
///
|
||||||
|
|
|
@ -160,7 +160,6 @@ pub trait OwnerRpc {
|
||||||
"mmr_index": null,
|
"mmr_index": null,
|
||||||
"n_child": 0,
|
"n_child": 0,
|
||||||
"root_key_id": "0200000000000000000000000000000000",
|
"root_key_id": "0200000000000000000000000000000000",
|
||||||
"slate_id": null,
|
|
||||||
"status": "Unspent",
|
"status": "Unspent",
|
||||||
"tx_log_entry": 0,
|
"tx_log_entry": 0,
|
||||||
"value": "60000000000"
|
"value": "60000000000"
|
||||||
|
@ -177,7 +176,6 @@ pub trait OwnerRpc {
|
||||||
"mmr_index": null,
|
"mmr_index": null,
|
||||||
"n_child": 1,
|
"n_child": 1,
|
||||||
"root_key_id": "0200000000000000000000000000000000",
|
"root_key_id": "0200000000000000000000000000000000",
|
||||||
"slate_id": null,
|
|
||||||
"status": "Unspent",
|
"status": "Unspent",
|
||||||
"tx_log_entry": 1,
|
"tx_log_entry": 1,
|
||||||
"value": "60000000000"
|
"value": "60000000000"
|
||||||
|
|
|
@ -433,20 +433,6 @@ pub fn outputs(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn payments(
|
|
||||||
wallet: Arc<Mutex<WalletInst<impl NodeClient + 'static, keychain::ExtKeychain>>>,
|
|
||||||
g_args: &GlobalArgs,
|
|
||||||
dark_scheme: bool,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
controller::owner_single_use(wallet.clone(), |api| {
|
|
||||||
let res = api.node_height()?;
|
|
||||||
let (validated, outputs) = api.retrieve_payments(true, None)?;
|
|
||||||
display::payments(&g_args.account, res.height, validated, outputs, dark_scheme)?;
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Txs command args
|
/// Txs command args
|
||||||
pub struct TxsArgs {
|
pub struct TxsArgs {
|
||||||
pub id: Option<u32>,
|
pub id: Option<u32>,
|
||||||
|
@ -476,22 +462,8 @@ pub fn txs(
|
||||||
let (_, outputs) = api.retrieve_outputs(true, false, args.id)?;
|
let (_, outputs) = api.retrieve_outputs(true, false, args.id)?;
|
||||||
display::outputs(&g_args.account, res.height, validated, outputs, dark_scheme)?;
|
display::outputs(&g_args.account, res.height, validated, outputs, dark_scheme)?;
|
||||||
// should only be one here, but just in case
|
// should only be one here, but just in case
|
||||||
for tx in &txs {
|
for tx in txs {
|
||||||
let (_, outputs) = api.retrieve_payments(true, tx.tx_slate_id)?;
|
display::tx_messages(&tx, dark_scheme)?;
|
||||||
if outputs.len() > 0 {
|
|
||||||
display::payments(
|
|
||||||
&g_args.account,
|
|
||||||
res.height,
|
|
||||||
validated,
|
|
||||||
outputs,
|
|
||||||
dark_scheme,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// should only be one here, but just in case
|
|
||||||
for tx in &txs {
|
|
||||||
display::tx_messages(tx, dark_scheme)?;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -14,10 +14,8 @@
|
||||||
|
|
||||||
use crate::core::core::{self, amount_to_hr_string};
|
use crate::core::core::{self, amount_to_hr_string};
|
||||||
use crate::core::global;
|
use crate::core::global;
|
||||||
|
use crate::libwallet::{
|
||||||
use crate::libwallet::types::{
|
AcctPathMapping, Error, OutputCommitMapping, OutputStatus, TxLogEntry, WalletInfo,
|
||||||
AcctPathMapping, Error, OutputCommitMapping, OutputStatus, PaymentCommitMapping, TxLogEntry,
|
|
||||||
WalletInfo,
|
|
||||||
};
|
};
|
||||||
use crate::util;
|
use crate::util;
|
||||||
use prettytable;
|
use prettytable;
|
||||||
|
@ -120,89 +118,6 @@ pub fn outputs(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Display payments in a pretty way
|
|
||||||
pub fn payments(
|
|
||||||
account: &str,
|
|
||||||
cur_height: u64,
|
|
||||||
validated: bool,
|
|
||||||
outputs: Vec<PaymentCommitMapping>,
|
|
||||||
dark_background_color_scheme: bool,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let title = format!(
|
|
||||||
"Wallet Payments - Account '{}' - Block Height: {}",
|
|
||||||
account, cur_height
|
|
||||||
);
|
|
||||||
println!();
|
|
||||||
let mut t = term::stdout().unwrap();
|
|
||||||
t.fg(term::color::MAGENTA).unwrap();
|
|
||||||
writeln!(t, "{}", title).unwrap();
|
|
||||||
t.reset().unwrap();
|
|
||||||
|
|
||||||
let mut table = table!();
|
|
||||||
|
|
||||||
table.set_titles(row![
|
|
||||||
bMG->"Output Commitment",
|
|
||||||
bMG->"Block Height",
|
|
||||||
bMG->"Locked Until",
|
|
||||||
bMG->"Status",
|
|
||||||
bMG->"# Confirms",
|
|
||||||
bMG->"Value",
|
|
||||||
bMG->"Shared Transaction Id"
|
|
||||||
]);
|
|
||||||
|
|
||||||
for payment in outputs {
|
|
||||||
let commit = format!("{}", util::to_hex(payment.commit.as_ref().to_vec()));
|
|
||||||
let out = payment.output;
|
|
||||||
|
|
||||||
let height = format!("{}", out.height);
|
|
||||||
let lock_height = format!("{}", out.lock_height);
|
|
||||||
let status = format!("{}", out.status);
|
|
||||||
|
|
||||||
let num_confirmations = format!("{}", out.num_confirmations(cur_height));
|
|
||||||
let value = if out.value == 0 {
|
|
||||||
"unknown".to_owned()
|
|
||||||
} else {
|
|
||||||
format!("{}", core::amount_to_hr_string(out.value, false))
|
|
||||||
};
|
|
||||||
let slate_id = format!("{}", out.slate_id);
|
|
||||||
|
|
||||||
if dark_background_color_scheme {
|
|
||||||
table.add_row(row![
|
|
||||||
bFC->commit,
|
|
||||||
bFB->height,
|
|
||||||
bFB->lock_height,
|
|
||||||
bFR->status,
|
|
||||||
bFB->num_confirmations,
|
|
||||||
bFG->value,
|
|
||||||
bFC->slate_id,
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
table.add_row(row![
|
|
||||||
bFD->commit,
|
|
||||||
bFB->height,
|
|
||||||
bFB->lock_height,
|
|
||||||
bFR->status,
|
|
||||||
bFB->num_confirmations,
|
|
||||||
bFG->value,
|
|
||||||
bFD->slate_id,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
table.set_format(*prettytable::format::consts::FORMAT_NO_COLSEP);
|
|
||||||
table.printstd();
|
|
||||||
println!();
|
|
||||||
|
|
||||||
if !validated {
|
|
||||||
println!(
|
|
||||||
"\nWARNING: Wallet failed to verify data. \
|
|
||||||
The above is from local cache and possibly invalid! \
|
|
||||||
(is your `grin server` offline or broken?)"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Display transaction log in a pretty way
|
/// Display transaction log in a pretty way
|
||||||
pub fn txs(
|
pub fn txs(
|
||||||
account: &str,
|
account: &str,
|
||||||
|
|
|
@ -429,16 +429,6 @@ fn tx_rollback(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
assert_eq!(output_mappings.len(), 3);
|
assert_eq!(output_mappings.len(), 3);
|
||||||
assert_eq!(locked_count, 2);
|
assert_eq!(locked_count, 2);
|
||||||
assert_eq!(unconfirmed_count, 1);
|
assert_eq!(unconfirmed_count, 1);
|
||||||
// check the payments are as expected
|
|
||||||
unconfirmed_count = 0;
|
|
||||||
let (_, payments) = api.retrieve_payments(false, tx.unwrap().tx_slate_id)?;
|
|
||||||
for p in &payments {
|
|
||||||
if p.output.status == OutputStatus::Unconfirmed {
|
|
||||||
unconfirmed_count = unconfirmed_count + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert_eq!(payments.len(), 1);
|
|
||||||
assert_eq!(unconfirmed_count, 1);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
@ -459,16 +449,6 @@ fn tx_rollback(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
}
|
}
|
||||||
assert_eq!(outputs.len(), 1);
|
assert_eq!(outputs.len(), 1);
|
||||||
assert_eq!(unconfirmed_count, 1);
|
assert_eq!(unconfirmed_count, 1);
|
||||||
// check the payments are as expected: receiver don't have this.
|
|
||||||
unconfirmed_count = 0;
|
|
||||||
let (_, payments) = api.retrieve_payments(false, tx.unwrap().tx_slate_id)?;
|
|
||||||
for p in &payments {
|
|
||||||
if p.output.status == OutputStatus::Unconfirmed {
|
|
||||||
unconfirmed_count = unconfirmed_count + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert_eq!(payments.len(), 0);
|
|
||||||
assert_eq!(unconfirmed_count, 0);
|
|
||||||
let (refreshed, wallet2_info) = api.retrieve_summary_info(true, 1)?;
|
let (refreshed, wallet2_info) = api.retrieve_summary_info(true, 1)?;
|
||||||
assert!(refreshed);
|
assert!(refreshed);
|
||||||
assert_eq!(wallet2_info.amount_currently_spendable, 0,);
|
assert_eq!(wallet2_info.amount_currently_spendable, 0,);
|
||||||
|
|
|
@ -42,8 +42,6 @@ pub const DB_DIR: &'static str = "db";
|
||||||
pub const TX_SAVE_DIR: &'static str = "saved_txs";
|
pub const TX_SAVE_DIR: &'static str = "saved_txs";
|
||||||
|
|
||||||
const OUTPUT_PREFIX: u8 = 'o' as u8;
|
const OUTPUT_PREFIX: u8 = 'o' as u8;
|
||||||
const PAYMENT_PREFIX: u8 = 'P' as u8;
|
|
||||||
const PAYMENT_COMMITS_PREFIX: u8 = 'Q' as u8;
|
|
||||||
const DERIV_PREFIX: u8 = 'd' as u8;
|
const DERIV_PREFIX: u8 = 'd' as u8;
|
||||||
const CONFIRMED_HEIGHT_PREFIX: u8 = 'c' as u8;
|
const CONFIRMED_HEIGHT_PREFIX: u8 = 'c' as u8;
|
||||||
const PRIVATE_TX_CONTEXT_PREFIX: u8 = 'p' as u8;
|
const PRIVATE_TX_CONTEXT_PREFIX: u8 = 'p' as u8;
|
||||||
|
@ -240,20 +238,6 @@ where
|
||||||
Box::new(self.db.iter(&[OUTPUT_PREFIX]).unwrap())
|
Box::new(self.db.iter(&[OUTPUT_PREFIX]).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_payment_log_commits(&self, u: &Uuid) -> Result<Option<PaymentCommits>, Error> {
|
|
||||||
let key = to_key(PAYMENT_COMMITS_PREFIX, &mut u.as_bytes().to_vec());
|
|
||||||
self.db.get_ser(&key).map_err(|e| e.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_payment_log_entry(&self, commit: String) -> Result<Option<PaymentData>, Error> {
|
|
||||||
let key = to_key(PAYMENT_PREFIX, &mut commit.as_bytes().to_vec());
|
|
||||||
self.db.get_ser(&key).map_err(|e| e.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn payment_log_iter<'a>(&'a self) -> Box<dyn Iterator<Item = PaymentData> + 'a> {
|
|
||||||
Box::new(self.db.iter(&[PAYMENT_PREFIX]).unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_tx_log_entry(&self, u: &Uuid) -> Result<Option<TxLogEntry>, Error> {
|
fn get_tx_log_entry(&self, u: &Uuid) -> Result<Option<TxLogEntry>, Error> {
|
||||||
let key = to_key(TX_LOG_ENTRY_PREFIX, &mut u.as_bytes().to_vec());
|
let key = to_key(TX_LOG_ENTRY_PREFIX, &mut u.as_bytes().to_vec());
|
||||||
self.db.get_ser(&key).map_err(|e| e.into())
|
self.db.get_ser(&key).map_err(|e| e.into())
|
||||||
|
@ -396,7 +380,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save(&mut self, out: OutputData) -> Result<(), Error> {
|
fn save(&mut self, out: OutputData) -> Result<(), Error> {
|
||||||
// Save the self output data to the db.
|
// Save the output data to the db.
|
||||||
{
|
{
|
||||||
let key = match out.mmr_index {
|
let key = match out.mmr_index {
|
||||||
Some(i) => to_key_u64(OUTPUT_PREFIX, &mut out.key_id.to_bytes().to_vec(), i),
|
Some(i) => to_key_u64(OUTPUT_PREFIX, &mut out.key_id.to_bytes().to_vec(), i),
|
||||||
|
@ -408,27 +392,6 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_payment_commits(&mut self, u: &Uuid, commits: PaymentCommits) -> Result<(), Error> {
|
|
||||||
// Save the payment commits list data to the db.
|
|
||||||
{
|
|
||||||
let key = to_key(PAYMENT_COMMITS_PREFIX, &mut u.as_bytes().to_vec());
|
|
||||||
self.db.borrow().as_ref().unwrap().put_ser(&key, &commits)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn save_payment(&mut self, out: PaymentData) -> Result<(), Error> {
|
|
||||||
// Save the payment output data to the db.
|
|
||||||
{
|
|
||||||
let commit = out.commit.clone();
|
|
||||||
let key = to_key(PAYMENT_PREFIX, &mut commit.as_bytes().to_vec());
|
|
||||||
self.db.borrow().as_ref().unwrap().put_ser(&key, &out)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, id: &Identifier, mmr_index: &Option<u64>) -> Result<OutputData, Error> {
|
fn get(&self, id: &Identifier, mmr_index: &Option<u64>) -> Result<OutputData, Error> {
|
||||||
let key = match mmr_index {
|
let key = match mmr_index {
|
||||||
Some(i) => to_key_u64(OUTPUT_PREFIX, &mut id.to_bytes().to_vec(), *i),
|
Some(i) => to_key_u64(OUTPUT_PREFIX, &mut id.to_bytes().to_vec(), *i),
|
||||||
|
@ -441,24 +404,6 @@ where
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_payment_commits(&self, u: &Uuid) -> Result<PaymentCommits, Error> {
|
|
||||||
let key = to_key(PAYMENT_COMMITS_PREFIX, &mut u.as_bytes().to_vec());
|
|
||||||
option_to_not_found(
|
|
||||||
self.db.borrow().as_ref().unwrap().get_ser(&key),
|
|
||||||
&format!("slate_id: {}", u.to_string()),
|
|
||||||
)
|
|
||||||
.map_err(|e| e.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_payment_log_entry(&self, commit: String) -> Result<PaymentData, Error> {
|
|
||||||
let key = to_key(PAYMENT_PREFIX, &mut commit.as_bytes().to_vec());
|
|
||||||
option_to_not_found(
|
|
||||||
self.db.borrow().as_ref().unwrap().get_ser(&key),
|
|
||||||
&format!("key: {:?}", commit),
|
|
||||||
)
|
|
||||||
.map_err(|e| e.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn iter(&self) -> Box<dyn Iterator<Item = OutputData>> {
|
fn iter(&self) -> Box<dyn Iterator<Item = OutputData>> {
|
||||||
Box::new(
|
Box::new(
|
||||||
self.db
|
self.db
|
||||||
|
|
|
@ -45,8 +45,6 @@ pub const DB_DIR: &'static str = "db";
|
||||||
pub const TX_SAVE_DIR: &'static str = "saved_txs";
|
pub const TX_SAVE_DIR: &'static str = "saved_txs";
|
||||||
|
|
||||||
const OUTPUT_PREFIX: u8 = 'o' as u8;
|
const OUTPUT_PREFIX: u8 = 'o' as u8;
|
||||||
const PAYMENT_PREFIX: u8 = 'P' as u8;
|
|
||||||
const PAYMENT_COMMITS_PREFIX: u8 = 'Q' as u8;
|
|
||||||
const DERIV_PREFIX: u8 = 'd' as u8;
|
const DERIV_PREFIX: u8 = 'd' as u8;
|
||||||
const CONFIRMED_HEIGHT_PREFIX: u8 = 'c' as u8;
|
const CONFIRMED_HEIGHT_PREFIX: u8 = 'c' as u8;
|
||||||
const PRIVATE_TX_CONTEXT_PREFIX: u8 = 'p' as u8;
|
const PRIVATE_TX_CONTEXT_PREFIX: u8 = 'p' as u8;
|
||||||
|
@ -243,20 +241,6 @@ where
|
||||||
Box::new(self.db.iter(&[OUTPUT_PREFIX]).unwrap().map(|o| o.1))
|
Box::new(self.db.iter(&[OUTPUT_PREFIX]).unwrap().map(|o| o.1))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_payment_log_commits(&self, u: &Uuid) -> Result<Option<PaymentCommits>, Error> {
|
|
||||||
let key = to_key(PAYMENT_COMMITS_PREFIX, &mut u.as_bytes().to_vec());
|
|
||||||
self.db.get_ser(&key).map_err(|e| e.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_payment_log_entry(&self, commit: String) -> Result<Option<PaymentData>, Error> {
|
|
||||||
let key = to_key(PAYMENT_PREFIX, &mut commit.as_bytes().to_vec());
|
|
||||||
self.db.get_ser(&key).map_err(|e| e.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn payment_log_iter<'a>(&'a self) -> Box<dyn Iterator<Item = PaymentData> + 'a> {
|
|
||||||
Box::new(self.db.iter(&[PAYMENT_PREFIX]).unwrap().map(|o| o.1))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_tx_log_entry(&self, u: &Uuid) -> Result<Option<TxLogEntry>, Error> {
|
fn get_tx_log_entry(&self, u: &Uuid) -> Result<Option<TxLogEntry>, Error> {
|
||||||
let key = to_key(TX_LOG_ENTRY_PREFIX, &mut u.as_bytes().to_vec());
|
let key = to_key(TX_LOG_ENTRY_PREFIX, &mut u.as_bytes().to_vec());
|
||||||
self.db.get_ser(&key).map_err(|e| e.into())
|
self.db.get_ser(&key).map_err(|e| e.into())
|
||||||
|
@ -404,7 +388,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save(&mut self, out: OutputData) -> Result<(), Error> {
|
fn save(&mut self, out: OutputData) -> Result<(), Error> {
|
||||||
// Save the self output data to the db.
|
// Save the output data to the db.
|
||||||
{
|
{
|
||||||
let key = match out.mmr_index {
|
let key = match out.mmr_index {
|
||||||
Some(i) => to_key_u64(OUTPUT_PREFIX, &mut out.key_id.to_bytes().to_vec(), i),
|
Some(i) => to_key_u64(OUTPUT_PREFIX, &mut out.key_id.to_bytes().to_vec(), i),
|
||||||
|
@ -416,27 +400,6 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_payment_commits(&mut self, u: &Uuid, commits: PaymentCommits) -> Result<(), Error> {
|
|
||||||
// Save the payment commits list data to the db.
|
|
||||||
{
|
|
||||||
let key = to_key(PAYMENT_COMMITS_PREFIX, &mut u.as_bytes().to_vec());
|
|
||||||
self.db.borrow().as_ref().unwrap().put_ser(&key, &commits)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn save_payment(&mut self, out: PaymentData) -> Result<(), Error> {
|
|
||||||
// Save the payment output data to the db.
|
|
||||||
{
|
|
||||||
let commit = out.commit.clone();
|
|
||||||
let key = to_key(PAYMENT_PREFIX, &mut commit.as_bytes().to_vec());
|
|
||||||
self.db.borrow().as_ref().unwrap().put_ser(&key, &out)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, id: &Identifier, mmr_index: &Option<u64>) -> Result<OutputData, Error> {
|
fn get(&self, id: &Identifier, mmr_index: &Option<u64>) -> Result<OutputData, Error> {
|
||||||
let key = match mmr_index {
|
let key = match mmr_index {
|
||||||
Some(i) => to_key_u64(OUTPUT_PREFIX, &mut id.to_bytes().to_vec(), *i),
|
Some(i) => to_key_u64(OUTPUT_PREFIX, &mut id.to_bytes().to_vec(), *i),
|
||||||
|
@ -449,24 +412,6 @@ where
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_payment_commits(&self, u: &Uuid) -> Result<PaymentCommits, Error> {
|
|
||||||
let key = to_key(PAYMENT_COMMITS_PREFIX, &mut u.as_bytes().to_vec());
|
|
||||||
option_to_not_found(
|
|
||||||
self.db.borrow().as_ref().unwrap().get_ser(&key),
|
|
||||||
&format!("slate_id: {}", u.to_string()),
|
|
||||||
)
|
|
||||||
.map_err(|e| e.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_payment_log_entry(&self, commit: String) -> Result<PaymentData, Error> {
|
|
||||||
let key = to_key(PAYMENT_PREFIX, &mut commit.as_bytes().to_vec());
|
|
||||||
option_to_not_found(
|
|
||||||
self.db.borrow().as_ref().unwrap().get_ser(&key),
|
|
||||||
&format!("key: {:?}", commit),
|
|
||||||
)
|
|
||||||
.map_err(|e| e.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn iter(&self) -> Box<dyn Iterator<Item = OutputData>> {
|
fn iter(&self) -> Box<dyn Iterator<Item = OutputData>> {
|
||||||
Box::new(
|
Box::new(
|
||||||
self.db
|
self.db
|
||||||
|
|
|
@ -24,11 +24,9 @@ use crate::grin_util;
|
||||||
use crate::grin_keychain::{Identifier, Keychain};
|
use crate::grin_keychain::{Identifier, Keychain};
|
||||||
use crate::internal::{keys, selection, tx, updater};
|
use crate::internal::{keys, selection, tx, updater};
|
||||||
use crate::slate::Slate;
|
use crate::slate::Slate;
|
||||||
use crate::types::{
|
use crate::types::{AcctPathMapping, NodeClient, TxLogEntry, TxWrapper, WalletBackend, WalletInfo};
|
||||||
AcctPathMapping, NodeClient, TxLogEntry, TxWrapper, WalletBackend, WalletInfo,
|
|
||||||
};
|
|
||||||
use crate::{Error, ErrorKind};
|
use crate::{Error, ErrorKind};
|
||||||
use crate::{InitTxArgs, NodeHeightResult, OutputCommitMapping, PaymentCommitMapping};
|
use crate::{InitTxArgs, NodeHeightResult, OutputCommitMapping};
|
||||||
|
|
||||||
const USER_MESSAGE_MAX_LEN: usize = 256;
|
const USER_MESSAGE_MAX_LEN: usize = 256;
|
||||||
|
|
||||||
|
@ -83,29 +81,10 @@ where
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
validated,
|
validated,
|
||||||
updater::retrieve_outputs(&mut *w, include_spent, tx_id, None, Some(&parent_key_id))?,
|
updater::retrieve_outputs(&mut *w, include_spent, tx_id, Some(&parent_key_id))?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of payment outputs from the active account in the wallet.
|
|
||||||
pub fn retrieve_payments<T: ?Sized, C, K>(
|
|
||||||
w: &mut T,
|
|
||||||
refresh_from_node: bool,
|
|
||||||
tx_id: Option<Uuid>,
|
|
||||||
) -> Result<(bool, Vec<PaymentCommitMapping>), Error>
|
|
||||||
where
|
|
||||||
T: WalletBackend<C, K>,
|
|
||||||
C: NodeClient,
|
|
||||||
K: Keychain,
|
|
||||||
{
|
|
||||||
let mut validated = false;
|
|
||||||
if refresh_from_node {
|
|
||||||
validated = update_outputs(w, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((validated, updater::retrieve_payments(w, tx_id)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve txs
|
/// Retrieve txs
|
||||||
pub fn retrieve_txs<T: ?Sized, C, K>(
|
pub fn retrieve_txs<T: ?Sized, C, K>(
|
||||||
w: &mut T,
|
w: &mut T,
|
||||||
|
|
|
@ -215,7 +215,6 @@ where
|
||||||
lock_height: output.lock_height,
|
lock_height: output.lock_height,
|
||||||
is_coinbase: output.is_coinbase,
|
is_coinbase: output.is_coinbase,
|
||||||
tx_log_entry: Some(log_id),
|
tx_log_entry: Some(log_id),
|
||||||
slate_id: None,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let max_child_index = found_parents.get(&parent_key_id).unwrap().clone();
|
let max_child_index = found_parents.get(&parent_key_id).unwrap().clone();
|
||||||
|
@ -284,7 +283,7 @@ where
|
||||||
|
|
||||||
// Now, get all outputs owned by this wallet (regardless of account)
|
// Now, get all outputs owned by this wallet (regardless of account)
|
||||||
let wallet_outputs = {
|
let wallet_outputs = {
|
||||||
let res = updater::retrieve_outputs(&mut *wallet, true, None, None, None)?;
|
let res = updater::retrieve_outputs(&mut *wallet, true, None, None)?;
|
||||||
res
|
res
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,6 @@ where
|
||||||
lock_height: 0,
|
lock_height: 0,
|
||||||
is_coinbase: false,
|
is_coinbase: false,
|
||||||
tx_log_entry: Some(log_id),
|
tx_log_entry: Some(log_id),
|
||||||
slate_id: Some(slate_id.clone()),
|
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
batch.save_tx_log_entry(t.clone(), &parent_key_id)?;
|
batch.save_tx_log_entry(t.clone(), &parent_key_id)?;
|
||||||
|
@ -225,7 +224,6 @@ where
|
||||||
lock_height: 0,
|
lock_height: 0,
|
||||||
is_coinbase: false,
|
is_coinbase: false,
|
||||||
tx_log_entry: Some(log_id),
|
tx_log_entry: Some(log_id),
|
||||||
slate_id: Some(slate_id),
|
|
||||||
})?;
|
})?;
|
||||||
batch.save_tx_log_entry(t, &parent_key_id)?;
|
batch.save_tx_log_entry(t, &parent_key_id)?;
|
||||||
batch.commit()?;
|
batch.commit()?;
|
||||||
|
|
|
@ -17,14 +17,10 @@
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::grin_keychain::{Identifier, Keychain};
|
use crate::grin_keychain::{Identifier, Keychain};
|
||||||
use crate::grin_util::secp::pedersen;
|
|
||||||
use crate::grin_util::to_hex;
|
|
||||||
use crate::grin_util::Mutex;
|
use crate::grin_util::Mutex;
|
||||||
use crate::internal::{selection, updater};
|
use crate::internal::{selection, updater};
|
||||||
use crate::slate::Slate;
|
use crate::slate::Slate;
|
||||||
use crate::types::{
|
use crate::types::{Context, NodeClient, TxLogEntryType, WalletBackend};
|
||||||
Context, NodeClient, OutputStatus, PaymentCommits, PaymentData, TxLogEntryType, WalletBackend,
|
|
||||||
};
|
|
||||||
use crate::{Error, ErrorKind};
|
use crate::{Error, ErrorKind};
|
||||||
|
|
||||||
/// static for incrementing test UUIDs
|
/// static for incrementing test UUIDs
|
||||||
|
@ -224,63 +220,6 @@ where
|
||||||
)?;
|
)?;
|
||||||
// Final transaction can be built by anyone at this stage
|
// Final transaction can be built by anyone at this stage
|
||||||
slate.finalize(wallet.keychain())?;
|
slate.finalize(wallet.keychain())?;
|
||||||
|
|
||||||
let parent_key_id = Some(&context.parent_key_id);
|
|
||||||
|
|
||||||
// Get the change output/s from database
|
|
||||||
let changes = updater::retrieve_outputs(wallet, false, None, Some(slate.id), parent_key_id)?;
|
|
||||||
let change_commits = changes
|
|
||||||
.iter()
|
|
||||||
.map(|oc| oc.commit.clone())
|
|
||||||
.collect::<Vec<pedersen::Commitment>>();
|
|
||||||
|
|
||||||
// Find the payment output/s
|
|
||||||
let mut outputs: Vec<pedersen::Commitment> = Vec::new();
|
|
||||||
for output in slate.tx.outputs() {
|
|
||||||
if !change_commits.contains(&output.commit) {
|
|
||||||
outputs.insert(0, output.commit.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sender save the payment output
|
|
||||||
let mut batch = wallet.batch()?;
|
|
||||||
batch.save_payment_commits(
|
|
||||||
&slate.id,
|
|
||||||
PaymentCommits {
|
|
||||||
commits: outputs
|
|
||||||
.iter()
|
|
||||||
.map(|c| to_hex(c.as_ref().to_vec()))
|
|
||||||
.collect::<Vec<String>>(),
|
|
||||||
slate_id: slate.id,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
// todo: multiple receivers transaction
|
|
||||||
if outputs.len() > 1 {
|
|
||||||
for output in outputs {
|
|
||||||
let payment_output = to_hex(output.clone().as_ref().to_vec());
|
|
||||||
batch.save_payment(PaymentData {
|
|
||||||
commit: payment_output,
|
|
||||||
value: 0, // '0' means unknown here, since '0' value is impossible for an output.
|
|
||||||
status: OutputStatus::Unconfirmed,
|
|
||||||
height: slate.height,
|
|
||||||
lock_height: 0,
|
|
||||||
slate_id: slate.id,
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
} else if outputs.len() == 1 {
|
|
||||||
let payment_output = to_hex(outputs.first().clone().unwrap().as_ref().to_vec());
|
|
||||||
batch.save_payment(PaymentData {
|
|
||||||
commit: payment_output,
|
|
||||||
value: slate.amount,
|
|
||||||
status: OutputStatus::Unconfirmed,
|
|
||||||
height: slate.height,
|
|
||||||
lock_height: 0,
|
|
||||||
slate_id: slate.id,
|
|
||||||
})?;
|
|
||||||
} else {
|
|
||||||
warn!("complete_tx - no 'payment' output! is this a sending to self for test purpose?");
|
|
||||||
}
|
|
||||||
batch.commit()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +253,7 @@ where
|
||||||
return Err(ErrorKind::TransactionNotCancellable(tx_id_string))?;
|
return Err(ErrorKind::TransactionNotCancellable(tx_id_string))?;
|
||||||
}
|
}
|
||||||
// get outputs associated with tx
|
// get outputs associated with tx
|
||||||
let res = updater::retrieve_outputs(wallet, false, Some(tx.id), None, Some(&parent_key_id))?;
|
let res = updater::retrieve_outputs(wallet, false, Some(tx.id), Some(&parent_key_id))?;
|
||||||
let outputs = res.iter().map(|m| m.output.clone()).collect();
|
let outputs = res.iter().map(|m| m.output.clone()).collect();
|
||||||
updater::cancel_tx_and_outputs(wallet, tx, outputs, parent_key_id)?;
|
updater::cancel_tx_and_outputs(wallet, tx, outputs, parent_key_id)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -30,14 +30,13 @@ use crate::internal::keys;
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
NodeClient, OutputData, OutputStatus, TxLogEntry, TxLogEntryType, WalletBackend, WalletInfo,
|
NodeClient, OutputData, OutputStatus, TxLogEntry, TxLogEntryType, WalletBackend, WalletInfo,
|
||||||
};
|
};
|
||||||
use crate::{BlockFees, CbData, OutputCommitMapping, PaymentCommitMapping};
|
use crate::{BlockFees, CbData, OutputCommitMapping};
|
||||||
|
|
||||||
/// Retrieve all of the self outputs (doesn't attempt to update from node)
|
/// Retrieve all of the outputs (doesn't attempt to update from node)
|
||||||
pub fn retrieve_outputs<T: ?Sized, C, K>(
|
pub fn retrieve_outputs<T: ?Sized, C, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
show_spent: bool,
|
show_spent: bool,
|
||||||
tx_id: Option<u32>,
|
tx_id: Option<u32>,
|
||||||
slate_id: Option<Uuid>,
|
|
||||||
parent_key_id: Option<&Identifier>,
|
parent_key_id: Option<&Identifier>,
|
||||||
) -> Result<Vec<OutputCommitMapping>, Error>
|
) -> Result<Vec<OutputCommitMapping>, Error>
|
||||||
where
|
where
|
||||||
|
@ -59,14 +58,6 @@ where
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// only include outputs with a given slate_id if provided
|
|
||||||
if let Some(id) = slate_id {
|
|
||||||
outputs = outputs
|
|
||||||
.into_iter()
|
|
||||||
.filter(|out| out.slate_id == Some(id))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(k) = parent_key_id {
|
if let Some(k) = parent_key_id {
|
||||||
outputs = outputs
|
outputs = outputs
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -91,38 +82,6 @@ where
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve all of the payment outputs (doesn't attempt to update from node)
|
|
||||||
pub fn retrieve_payments<T: ?Sized, C, K>(
|
|
||||||
wallet: &mut T,
|
|
||||||
tx_id: Option<Uuid>,
|
|
||||||
) -> Result<Vec<PaymentCommitMapping>, Error>
|
|
||||||
where
|
|
||||||
T: WalletBackend<C, K>,
|
|
||||||
C: NodeClient,
|
|
||||||
K: Keychain,
|
|
||||||
{
|
|
||||||
// just read the wallet here, no need for a write lock
|
|
||||||
let mut outputs = wallet.payment_log_iter().collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// only include outputs with a given tx_id if provided
|
|
||||||
if let Some(id) = tx_id {
|
|
||||||
outputs = outputs
|
|
||||||
.into_iter()
|
|
||||||
.filter(|out| out.slate_id == id)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
let res = outputs
|
|
||||||
.into_iter()
|
|
||||||
.map(|output| {
|
|
||||||
let commit =
|
|
||||||
pedersen::Commitment::from_vec(util::from_hex(output.commit.clone()).unwrap());
|
|
||||||
PaymentCommitMapping { output, commit }
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve all of the transaction entries, or a particular entry
|
/// Retrieve all of the transaction entries, or a particular entry
|
||||||
/// if `parent_key_id` is set, only return entries from that key
|
/// if `parent_key_id` is set, only return entries from that key
|
||||||
pub fn retrieve_txs<T: ?Sized, C, K>(
|
pub fn retrieve_txs<T: ?Sized, C, K>(
|
||||||
|
@ -332,21 +291,6 @@ where
|
||||||
t.confirmed = true;
|
t.confirmed = true;
|
||||||
batch.save_tx_log_entry(t, &parent_key_id)?;
|
batch.save_tx_log_entry(t, &parent_key_id)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there's a related payment output being confirmed, refresh that payment log
|
|
||||||
if let Some(slate_id) = output.slate_id {
|
|
||||||
if let Ok(commits) = batch.get_payment_commits(&slate_id) {
|
|
||||||
for commit in commits.commits {
|
|
||||||
if let Ok(mut payment) =
|
|
||||||
batch.get_payment_log_entry(commit.clone())
|
|
||||||
{
|
|
||||||
payment.height = o.1;
|
|
||||||
payment.mark_confirmed();
|
|
||||||
batch.save_payment(payment)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
output.height = o.1;
|
output.height = o.1;
|
||||||
output.mark_unspent();
|
output.mark_unspent();
|
||||||
|
@ -469,7 +413,6 @@ where
|
||||||
locked_total += out.value;
|
locked_total += out.value;
|
||||||
}
|
}
|
||||||
OutputStatus::Spent => {}
|
OutputStatus::Spent => {}
|
||||||
OutputStatus::Confirmed => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,7 +490,6 @@ where
|
||||||
lock_height: lock_height,
|
lock_height: lock_height,
|
||||||
is_coinbase: true,
|
is_coinbase: true,
|
||||||
tx_log_entry: None,
|
tx_log_entry: None,
|
||||||
slate_id: None,
|
|
||||||
})?;
|
})?;
|
||||||
batch.commit()?;
|
batch.commit()?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,19 +85,10 @@ where
|
||||||
/// return the parent path
|
/// return the parent path
|
||||||
fn parent_key_id(&mut self) -> Identifier;
|
fn parent_key_id(&mut self) -> Identifier;
|
||||||
|
|
||||||
/// Iterate over all self output data stored by the backend
|
/// Iterate over all output data stored by the backend
|
||||||
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = OutputData> + 'a>;
|
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = OutputData> + 'a>;
|
||||||
|
|
||||||
/// Get payment commits list by slate id
|
/// Get output data by id
|
||||||
fn get_payment_log_commits(&self, u: &Uuid) -> Result<Option<PaymentCommits>, Error>;
|
|
||||||
|
|
||||||
/// Get payment output data by commit
|
|
||||||
fn get_payment_log_entry(&self, commit: String) -> Result<Option<PaymentData>, Error>;
|
|
||||||
|
|
||||||
/// Iterate over all payment output data stored by the backend
|
|
||||||
fn payment_log_iter<'a>(&'a self) -> Box<dyn Iterator<Item = PaymentData> + 'a>;
|
|
||||||
|
|
||||||
/// Get self owned output data by id
|
|
||||||
fn get(&self, id: &Identifier, mmr_index: &Option<u64>) -> Result<OutputData, Error>;
|
fn get(&self, id: &Identifier, mmr_index: &Option<u64>) -> Result<OutputData, Error>;
|
||||||
|
|
||||||
/// Get an (Optional) tx log entry by uuid
|
/// Get an (Optional) tx log entry by uuid
|
||||||
|
@ -149,24 +140,12 @@ where
|
||||||
/// Return the keychain being used
|
/// Return the keychain being used
|
||||||
fn keychain(&mut self) -> &mut K;
|
fn keychain(&mut self) -> &mut K;
|
||||||
|
|
||||||
/// Add or update data about a self owned output to the backend
|
/// Add or update data about an output to the backend
|
||||||
fn save(&mut self, out: OutputData) -> Result<(), Error>;
|
fn save(&mut self, out: OutputData) -> Result<(), Error>;
|
||||||
|
|
||||||
/// Add or update data about a payment output to the backend
|
/// Gets output data by id
|
||||||
fn save_payment(&mut self, out: PaymentData) -> Result<(), Error>;
|
|
||||||
|
|
||||||
/// Add or update data about a payment commits list to the backend
|
|
||||||
fn save_payment_commits(&mut self, u: &Uuid, commits: PaymentCommits) -> Result<(), Error>;
|
|
||||||
|
|
||||||
/// Gets self owned output data by id
|
|
||||||
fn get(&self, id: &Identifier, mmr_index: &Option<u64>) -> Result<OutputData, Error>;
|
fn get(&self, id: &Identifier, mmr_index: &Option<u64>) -> Result<OutputData, Error>;
|
||||||
|
|
||||||
/// Gets payment commits list by slate id
|
|
||||||
fn get_payment_commits(&self, u: &Uuid) -> Result<PaymentCommits, Error>;
|
|
||||||
|
|
||||||
/// Gets payment output data by commit
|
|
||||||
fn get_payment_log_entry(&self, commit: String) -> Result<PaymentData, Error>;
|
|
||||||
|
|
||||||
/// Iterate over all output data stored by the backend
|
/// Iterate over all output data stored by the backend
|
||||||
fn iter(&self) -> Box<dyn Iterator<Item = OutputData>>;
|
fn iter(&self) -> Box<dyn Iterator<Item = OutputData>>;
|
||||||
|
|
||||||
|
@ -291,8 +270,6 @@ pub struct OutputData {
|
||||||
pub is_coinbase: bool,
|
pub is_coinbase: bool,
|
||||||
/// Optional corresponding internal entry in tx entry log
|
/// Optional corresponding internal entry in tx entry log
|
||||||
pub tx_log_entry: Option<u32>,
|
pub tx_log_entry: Option<u32>,
|
||||||
/// Unique transaction ID, selected by sender
|
|
||||||
pub slate_id: Option<Uuid>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ser::Writeable for OutputData {
|
impl ser::Writeable for OutputData {
|
||||||
|
@ -369,94 +346,6 @@ impl OutputData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about a payment output that's being tracked by the wallet.
|
|
||||||
/// It belongs to the receiver, and it's paid by this wallet.
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
|
|
||||||
pub struct PaymentData {
|
|
||||||
/// The actual commit
|
|
||||||
pub commit: String,
|
|
||||||
/// Value of the output
|
|
||||||
pub value: u64,
|
|
||||||
/// Current status of the output
|
|
||||||
pub status: OutputStatus,
|
|
||||||
/// Height of the output
|
|
||||||
pub height: u64,
|
|
||||||
/// Height we are locked until
|
|
||||||
pub lock_height: u64,
|
|
||||||
/// Unique transaction ID, selected by sender
|
|
||||||
pub slate_id: Uuid,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ser::Writeable for PaymentData {
|
|
||||||
fn write<W: ser::Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
|
||||||
writer.write_bytes(&serde_json::to_vec(self).map_err(|_| ser::Error::CorruptedData)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ser::Readable for PaymentData {
|
|
||||||
fn read(reader: &mut dyn ser::Reader) -> Result<PaymentData, ser::Error> {
|
|
||||||
let data = reader.read_bytes_len_prefix()?;
|
|
||||||
serde_json::from_slice(&data[..]).map_err(|_| ser::Error::CorruptedData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PaymentData {
|
|
||||||
/// How many confirmations has this output received?
|
|
||||||
/// If height == 0 then we are either Unconfirmed or the output was
|
|
||||||
/// cut-through
|
|
||||||
/// so we do not actually know how many confirmations this output had (and
|
|
||||||
/// never will).
|
|
||||||
pub fn num_confirmations(&self, current_height: u64) -> u64 {
|
|
||||||
if self.height > current_height {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if self.status == OutputStatus::Unconfirmed {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
// if an output has height n and we are at block n
|
|
||||||
// then we have a single confirmation (the block it originated in)
|
|
||||||
1 + (current_height - self.height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Marks this output as confirmed if it was previously unconfirmed
|
|
||||||
pub fn mark_confirmed(&mut self) {
|
|
||||||
match self.status {
|
|
||||||
OutputStatus::Unconfirmed => self.status = OutputStatus::Confirmed,
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Information about the payment commit/s in one tx that's being tracked by the wallet.
|
|
||||||
/// They belong to the receiver/s, and they're paid by this wallet.
|
|
||||||
///
|
|
||||||
/// Note: because lmdb can't have multiple keys to same value, we have to use this to find
|
|
||||||
/// the commit lists by the slate id, in case we support multiple receivers in one tx in the future.
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
pub struct PaymentCommits {
|
|
||||||
/// The actual commit/s
|
|
||||||
pub commits: Vec<String>,
|
|
||||||
/// Unique transaction ID, selected by sender
|
|
||||||
pub slate_id: Uuid,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ser::Writeable for PaymentCommits {
|
|
||||||
fn write<W: ser::Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
|
||||||
writer.write_bytes(&serde_json::to_vec(self).map_err(|_| ser::Error::CorruptedData)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ser::Readable for PaymentCommits {
|
|
||||||
fn read(reader: &mut dyn ser::Reader) -> Result<PaymentCommits, ser::Error> {
|
|
||||||
let data = reader.read_bytes_len_prefix()?;
|
|
||||||
serde_json::from_slice(&data[..]).map_err(|_| ser::Error::CorruptedData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Status of an output that's being tracked by the wallet. Can either be
|
/// Status of an output that's being tracked by the wallet. Can either be
|
||||||
/// unconfirmed, spent, unspent, or locked (when it's been used to generate
|
/// unconfirmed, spent, unspent, or locked (when it's been used to generate
|
||||||
/// a transaction but we don't have confirmation that the transaction was
|
/// a transaction but we don't have confirmation that the transaction was
|
||||||
|
@ -471,8 +360,6 @@ pub enum OutputStatus {
|
||||||
Locked,
|
Locked,
|
||||||
/// Spent
|
/// Spent
|
||||||
Spent,
|
Spent,
|
||||||
/// Confirmed
|
|
||||||
Confirmed,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for OutputStatus {
|
impl fmt::Display for OutputStatus {
|
||||||
|
@ -482,7 +369,6 @@ impl fmt::Display for OutputStatus {
|
||||||
OutputStatus::Unspent => write!(f, "Unspent"),
|
OutputStatus::Unspent => write!(f, "Unspent"),
|
||||||
OutputStatus::Locked => write!(f, "Locked"),
|
OutputStatus::Locked => write!(f, "Locked"),
|
||||||
OutputStatus::Spent => write!(f, "Spent"),
|
OutputStatus::Spent => write!(f, "Spent"),
|
||||||
OutputStatus::Confirmed => write!(f, "Confirmed"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -811,181 +697,3 @@ pub struct TxWrapper {
|
||||||
/// hex representation of transaction
|
/// hex representation of transaction
|
||||||
pub tx_hex: String,
|
pub tx_hex: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Types to facilitate API arguments and serialization
|
|
||||||
|
|
||||||
/// Send TX API Args
|
|
||||||
// TODO: This is here to ensure the legacy V1 API remains intact
|
|
||||||
// remove this when v1 api is removed
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
|
||||||
pub struct SendTXArgs {
|
|
||||||
/// amount to send
|
|
||||||
pub amount: u64,
|
|
||||||
/// minimum confirmations
|
|
||||||
pub minimum_confirmations: u64,
|
|
||||||
/// payment method
|
|
||||||
pub method: String,
|
|
||||||
/// destination url
|
|
||||||
pub dest: String,
|
|
||||||
/// Max number of outputs
|
|
||||||
pub max_outputs: usize,
|
|
||||||
/// Number of change outputs to generate
|
|
||||||
pub num_change_outputs: usize,
|
|
||||||
/// whether to use all outputs (combine)
|
|
||||||
pub selection_strategy_is_use_all: bool,
|
|
||||||
/// Optional message, that will be signed
|
|
||||||
pub message: Option<String>,
|
|
||||||
/// Optional slate version to target when sending
|
|
||||||
pub target_slate_version: Option<u16>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// V2 Init / Send TX API Args
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
|
||||||
pub struct InitTxArgs {
|
|
||||||
/// The human readable account name from which to draw outputs
|
|
||||||
/// for the transaction, overriding whatever the active account is as set via the
|
|
||||||
/// [`set_active_account`](../grin_wallet_api/owner/struct.Owner.html#method.set_active_account) method.
|
|
||||||
pub src_acct_name: Option<String>,
|
|
||||||
#[serde(with = "secp_ser::string_or_u64")]
|
|
||||||
/// The amount to send, in nanogrins. (`1 G = 1_000_000_000nG`)
|
|
||||||
pub amount: u64,
|
|
||||||
#[serde(with = "secp_ser::string_or_u64")]
|
|
||||||
/// The minimum number of confirmations an output
|
|
||||||
/// should have in order to be included in the transaction.
|
|
||||||
pub minimum_confirmations: u64,
|
|
||||||
/// By default, the wallet selects as many inputs as possible in a
|
|
||||||
/// transaction, to reduce the Output set and the fees. The wallet will attempt to spend
|
|
||||||
/// include up to `max_outputs` in a transaction, however if this is not enough to cover
|
|
||||||
/// the whole amount, the wallet will include more outputs. This parameter should be considered
|
|
||||||
/// a soft limit.
|
|
||||||
pub max_outputs: u32,
|
|
||||||
/// The target number of change outputs to create in the transaction.
|
|
||||||
/// The actual number created will be `num_change_outputs` + whatever remainder is needed.
|
|
||||||
pub num_change_outputs: u32,
|
|
||||||
/// If `true`, attempt to use up as many outputs as
|
|
||||||
/// possible to create the transaction, up the 'soft limit' of `max_outputs`. This helps
|
|
||||||
/// to reduce the size of the UTXO set and the amount of data stored in the wallet, and
|
|
||||||
/// minimizes fees. This will generally result in many inputs and a large change output(s),
|
|
||||||
/// usually much larger than the amount being sent. If `false`, the transaction will include
|
|
||||||
/// as many outputs as are needed to meet the amount, (and no more) starting with the smallest
|
|
||||||
/// value outputs.
|
|
||||||
pub selection_strategy_is_use_all: bool,
|
|
||||||
/// An optional participant message to include alongside the sender's public
|
|
||||||
/// ParticipantData within the slate. This message will include a signature created with the
|
|
||||||
/// sender's private excess value, and will be publically verifiable. Note this message is for
|
|
||||||
/// the convenience of the participants during the exchange; it is not included in the final
|
|
||||||
/// transaction sent to the chain. The message will be truncated to 256 characters.
|
|
||||||
pub message: Option<String>,
|
|
||||||
/// Optionally set the output target slate version (acceptable
|
|
||||||
/// down to the minimum slate version compatible with the current. If `None` the slate
|
|
||||||
/// is generated with the latest version.
|
|
||||||
pub target_slate_version: Option<u16>,
|
|
||||||
/// If true, just return an estimate of the resulting slate, containing fees and amounts
|
|
||||||
/// locked without actually locking outputs or creating the transaction. Note if this is set to
|
|
||||||
/// 'true', the amount field in the slate will contain the total amount locked, not the provided
|
|
||||||
/// transaction amount
|
|
||||||
pub estimate_only: Option<bool>,
|
|
||||||
/// Sender arguments. If present, the underlying function will also attempt to send the
|
|
||||||
/// transaction to a destination and optionally finalize the result
|
|
||||||
pub send_args: Option<InitTxSendArgs>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send TX API Args, for convenience functionality that inits the transaction and sends
|
|
||||||
/// in one go
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
|
||||||
pub struct InitTxSendArgs {
|
|
||||||
/// The transaction method. Can currently be 'http' or 'keybase'.
|
|
||||||
pub method: String,
|
|
||||||
/// The destination, contents will depend on the particular method
|
|
||||||
pub dest: String,
|
|
||||||
/// Whether to finalize the result immediately if the send was successful
|
|
||||||
pub finalize: bool,
|
|
||||||
/// Whether to post the transasction if the send and finalize were successful
|
|
||||||
pub post_tx: bool,
|
|
||||||
/// Whether to use dandelion when posting. If false, skip the dandelion relay
|
|
||||||
pub fluff: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for InitTxArgs {
|
|
||||||
fn default() -> InitTxArgs {
|
|
||||||
InitTxArgs {
|
|
||||||
src_acct_name: None,
|
|
||||||
amount: 0,
|
|
||||||
minimum_confirmations: 10,
|
|
||||||
max_outputs: 500,
|
|
||||||
num_change_outputs: 1,
|
|
||||||
selection_strategy_is_use_all: true,
|
|
||||||
message: None,
|
|
||||||
target_slate_version: None,
|
|
||||||
estimate_only: Some(false),
|
|
||||||
send_args: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fees in block to use for coinbase amount calculation
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
pub struct BlockFees {
|
|
||||||
/// fees
|
|
||||||
#[serde(with = "secp_ser::string_or_u64")]
|
|
||||||
pub fees: u64,
|
|
||||||
/// height
|
|
||||||
#[serde(with = "secp_ser::string_or_u64")]
|
|
||||||
pub height: u64,
|
|
||||||
/// key id
|
|
||||||
pub key_id: Option<Identifier>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BlockFees {
|
|
||||||
/// return key id
|
|
||||||
pub fn key_id(&self) -> Option<Identifier> {
|
|
||||||
self.key_id.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Response to build a coinbase output.
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
pub struct CbData {
|
|
||||||
/// Output
|
|
||||||
pub output: Output,
|
|
||||||
/// Kernel
|
|
||||||
pub kernel: TxKernel,
|
|
||||||
/// Key Id
|
|
||||||
pub key_id: Option<Identifier>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Map Outputdata to commits
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
pub struct OutputCommitMapping {
|
|
||||||
/// Output Data
|
|
||||||
pub output: OutputData,
|
|
||||||
/// The commit
|
|
||||||
#[serde(
|
|
||||||
serialize_with = "secp_ser::as_hex",
|
|
||||||
deserialize_with = "secp_ser::commitment_from_hex"
|
|
||||||
)]
|
|
||||||
pub commit: pedersen::Commitment,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Map PaymentData to commits
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
pub struct PaymentCommitMapping {
|
|
||||||
/// Payment Data
|
|
||||||
pub output: PaymentData,
|
|
||||||
/// The commit
|
|
||||||
#[serde(
|
|
||||||
serialize_with = "secp_ser::as_hex",
|
|
||||||
deserialize_with = "secp_ser::commitment_from_hex"
|
|
||||||
)]
|
|
||||||
pub commit: pedersen::Commitment,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Node height result
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
pub struct NodeHeightResult {
|
|
||||||
/// Last known height
|
|
||||||
#[serde(with = "secp_ser::string_or_u64")]
|
|
||||||
pub height: u64,
|
|
||||||
/// Whether this height was updated from the node
|
|
||||||
pub updated_from_node: bool,
|
|
||||||
}
|
|
||||||
|
|
|
@ -624,14 +624,6 @@ pub fn wallet_command(
|
||||||
&global_wallet_args,
|
&global_wallet_args,
|
||||||
wallet_config.dark_background_color_scheme.unwrap_or(true),
|
wallet_config.dark_background_color_scheme.unwrap_or(true),
|
||||||
),
|
),
|
||||||
("payments", Some(_)) => {
|
|
||||||
info!("payments command received");
|
|
||||||
command::payments(
|
|
||||||
inst_wallet(),
|
|
||||||
&global_wallet_args,
|
|
||||||
wallet_config.dark_background_color_scheme.unwrap_or(true),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
("txs", Some(args)) => {
|
("txs", Some(args)) => {
|
||||||
let a = arg_parse!(parse_txs_args(&args));
|
let a = arg_parse!(parse_txs_args(&args));
|
||||||
command::txs(
|
command::txs(
|
||||||
|
|
|
@ -501,10 +501,6 @@ mod wallet_tests {
|
||||||
let arg_vec = vec!["grin-wallet", "-p", "password", "-a", "mining", "outputs"];
|
let arg_vec = vec!["grin-wallet", "-p", "password", "-a", "mining", "outputs"];
|
||||||
execute_command(&app, test_dir, "wallet1", &client1, arg_vec)?;
|
execute_command(&app, test_dir, "wallet1", &client1, arg_vec)?;
|
||||||
|
|
||||||
// payments
|
|
||||||
let arg_vec = vec!["grin-wallet", "-p", "password", "-a", "mining", "payments"];
|
|
||||||
execute_command(&app, test_dir, "wallet1", &client1, arg_vec)?;
|
|
||||||
|
|
||||||
// let logging finish
|
// let logging finish
|
||||||
thread::sleep(Duration::from_millis(200));
|
thread::sleep(Duration::from_millis(200));
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -163,9 +163,7 @@ subcommands:
|
||||||
short: f
|
short: f
|
||||||
long: fluff
|
long: fluff
|
||||||
- outputs:
|
- outputs:
|
||||||
about: Raw wallet self owned output info (list of outputs)
|
about: Raw wallet output info (list of outputs)
|
||||||
- payments:
|
|
||||||
about: Raw wallet payment output info (list of outputs)
|
|
||||||
- txs:
|
- txs:
|
||||||
about: Display transaction information
|
about: Display transaction information
|
||||||
args:
|
args:
|
||||||
|
|
Loading…
Reference in a new issue