Skip to content
This repository has been archived by the owner on Dec 28, 2023. It is now read-only.

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
garyyu authored Apr 25, 2019
2 parents d774272 + 12909c9 commit a63f2c7
Show file tree
Hide file tree
Showing 17 changed files with 772 additions and 26 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[![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/mimblewimble/grin-wallet/master.svg)](https://codecov.io/gh/mimblewimble/grin-wallet)
[![Build Status](https://img.shields.io/travis/gottstech/grin-wallet/master.svg)](https://travis-ci.org/gottstech/grin-wallet)
[![Coverage Status](https://img.shields.io/codecov/c/github/gottstech/grin-wallet/master.svg)](https://codecov.io/gh/gottstech/grin-wallet)
[![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)
[![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/mimblewimble/grin-wallet.svg)](https://github.com/mimblewimble/grin-wallet/releases)
[![License](https://img.shields.io/github/license/mimblewimble/grin-wallet.svg)](https://github.com/mimblewimble/grin-wallet/blob/master/LICENSE)
[![Release Version](https://img.shields.io/github/release/gottstech/grin-wallet.svg)](https://github.com/gottstech/grin-wallet/releases)
[![License](https://img.shields.io/github/license/gottstech/grin-wallet.svg)](https://github.com/gottstech/grin-wallet/blob/master/LICENSE)

# Grin Wallet
58 changes: 55 additions & 3 deletions api/src/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ use crate::core::core::Transaction;
use crate::impls::{HTTPWalletCommAdapter, KeybaseWalletCommAdapter};
use crate::keychain::{Identifier, Keychain};
use crate::libwallet::api_impl::owner;
use crate::libwallet::{
AcctPathMapping, Error, ErrorKind, InitTxArgs, NodeClient, NodeHeightResult,
OutputCommitMapping, Slate, TxLogEntry, WalletBackend, WalletInfo,

use crate::libwallet::slate::Slate;
use crate::libwallet::types::{
AcctPathMapping, Error, ErrorKind, InitTxArgs, NodeClient, NodeHeightResult, OutputCommitMapping,
PaymentCommitMapping, Slate, TxLogEntry, WalletBackend, WalletInfo,
};

/// Main interface into all wallet API functions.
Expand Down Expand Up @@ -302,6 +304,56 @@ where
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)
/// from the active account in the wallet.
///
Expand Down
2 changes: 2 additions & 0 deletions api/src/owner_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ pub trait OwnerRpc {
"mmr_index": null,
"n_child": 0,
"root_key_id": "0200000000000000000000000000000000",
"slate_id": null,
"status": "Unspent",
"tx_log_entry": 0,
"value": "60000000000"
Expand All @@ -176,6 +177,7 @@ pub trait OwnerRpc {
"mmr_index": null,
"n_child": 1,
"root_key_id": "0200000000000000000000000000000000",
"slate_id": null,
"status": "Unspent",
"tx_log_entry": 1,
"value": "60000000000"
Expand Down
32 changes: 30 additions & 2 deletions controller/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,20 @@ pub fn outputs(
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
pub struct TxsArgs {
pub id: Option<u32>,
Expand Down Expand Up @@ -462,8 +476,22 @@ pub fn txs(
let (_, outputs) = api.retrieve_outputs(true, false, args.id)?;
display::outputs(&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)?;
for tx in &txs {
let (_, outputs) = api.retrieve_payments(true, tx.tx_slate_id)?;
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(())
Expand Down
89 changes: 87 additions & 2 deletions controller/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@

use crate::core::core::{self, amount_to_hr_string};
use crate::core::global;
use crate::libwallet::{
AcctPathMapping, Error, OutputCommitMapping, OutputStatus, TxLogEntry, WalletInfo,

use crate::libwallet::types::{
AcctPathMapping, Error, OutputCommitMapping, OutputStatus, PaymentCommitMapping, TxLogEntry,
WalletInfo,
};
use crate::util;
use prettytable;
Expand Down Expand Up @@ -118,6 +120,89 @@ pub fn outputs(
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
pub fn txs(
account: &str,
Expand Down
20 changes: 20 additions & 0 deletions controller/tests/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,16 @@ fn tx_rollback(test_dir: &str) -> Result<(), libwallet::Error> {
assert_eq!(output_mappings.len(), 3);
assert_eq!(locked_count, 2);
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(())
})?;
Expand All @@ -449,6 +459,16 @@ fn tx_rollback(test_dir: &str) -> Result<(), libwallet::Error> {
}
assert_eq!(outputs.len(), 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)?;
assert!(refreshed);
assert_eq!(wallet2_info.amount_currently_spendable, 0,);
Expand Down
57 changes: 56 additions & 1 deletion impls/src/backends/lmdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ pub const DB_DIR: &'static str = "db";
pub const TX_SAVE_DIR: &'static str = "saved_txs";

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 CONFIRMED_HEIGHT_PREFIX: u8 = 'c' as u8;
const PRIVATE_TX_CONTEXT_PREFIX: u8 = 'p' as u8;
Expand Down Expand Up @@ -238,6 +240,20 @@ where
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> {
let key = to_key(TX_LOG_ENTRY_PREFIX, &mut u.as_bytes().to_vec());
self.db.get_ser(&key).map_err(|e| e.into())
Expand Down Expand Up @@ -380,7 +396,7 @@ where
}

fn save(&mut self, out: OutputData) -> Result<(), Error> {
// Save the output data to the db.
// Save the self output data to the db.
{
let key = match out.mmr_index {
Some(i) => to_key_u64(OUTPUT_PREFIX, &mut out.key_id.to_bytes().to_vec(), i),
Expand All @@ -392,6 +408,27 @@ where
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> {
let key = match mmr_index {
Some(i) => to_key_u64(OUTPUT_PREFIX, &mut id.to_bytes().to_vec(), *i),
Expand All @@ -404,6 +441,24 @@ where
.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>> {
Box::new(
self.db
Expand Down
Loading

0 comments on commit a63f2c7

Please sign in to comment.