Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

View Wallet - fn rewind_hash & scan_rewind_hash #632

Merged
merged 3 commits into from
Dec 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 84 additions & 2 deletions api/src/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ use crate::libwallet::api_impl::owner_updater::{start_updater_log_thread, Status
use crate::libwallet::api_impl::{owner, owner_updater};
use crate::libwallet::{
AcctPathMapping, Error, InitTxArgs, IssueInvoiceTxArgs, NodeClient, NodeHeightResult,
OutputCommitMapping, PaymentProof, Slate, Slatepack, SlatepackAddress, TxLogEntry, WalletInfo,
WalletInst, WalletLCProvider,
OutputCommitMapping, PaymentProof, Slate, Slatepack, SlatepackAddress, TxLogEntry, ViewWallet,
WalletInfo, WalletInst, WalletLCProvider,
};
use crate::util::logger::LoggingConfig;
use crate::util::secp::key::SecretKey;
Expand Down Expand Up @@ -1181,6 +1181,88 @@ where
owner::get_stored_tx(&**w, tx_id, slate_id)
}

/// Return the rewind hash of the wallet.
/// The rewind hash when shared, help third-party to retrieve informations (outputs, balance, ...) that belongs to this wallet.
///
/// # Arguments
///
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
/// being used.
///
/// # Returns
/// * `Ok(String)` if successful
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered.

/// # 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 mut api_owner = Owner::new(wallet.clone(), None);
/// let result = api_owner.scan(
/// None,
/// Some(20000),
/// false,
/// );
///
/// if let Ok(_) = result {
/// // Wallet outputs should be consistent with what's on chain
/// // ...
/// }
/// ```

pub fn get_rewind_hash(&self, keychain_mask: Option<&SecretKey>) -> Result<String, Error> {
owner::get_rewind_hash(self.wallet_inst.clone(), keychain_mask)
}

/// Scans the entire UTXO set from the node, identify which outputs belong to the given rewind hash view wallet.
///
/// This function can be used to retrieve outputs informations (outputs, balance, ...) from a rewind hash view wallet.
///
/// This operation scans the entire chain, and is expected to be time intensive. It is imperative
/// that no other processes should be trying to use the wallet at the same time this function is
/// running.
///
/// # Arguments
///
/// * `rewind_hash` - Rewind hash of a wallet, used to retrieve the output of a third-party wallet.
/// * `start_height` - If provided, the height of the first block from which to start scanning.
/// The scan will start from block 1 if this is not provided.
///
/// # Returns
/// * `Ok(ViewWallet)` if successful
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered.

/// # 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 mut api_owner = Owner::new(wallet.clone(), None);
/// let result = api_owner.scan(
/// None,
/// Some(20000),
/// false,
/// );
///
/// if let Ok(_) = result {
/// // Wallet outputs should be consistent with what's on chain
/// // ...
/// }
/// ```

pub fn scan_rewind_hash(
&self,
rewind_hash: String,
start_height: Option<u64>,
) -> Result<ViewWallet, Error> {
let tx = {
let t = self.status_tx.lock();
t.clone()
};
owner::scan_rewind_hash(self.wallet_inst.clone(), rewind_hash, start_height, &tx)
}

/// Scans the entire UTXO set from the node, identify which outputs belong to the given wallet
/// update the wallet state to be consistent with what's currently in the UTXO set.
///
Expand Down
123 changes: 122 additions & 1 deletion api/src/owner_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::keychain::{Identifier, Keychain};
use crate::libwallet::{
AcctPathMapping, ErrorKind, InitTxArgs, IssueInvoiceTxArgs, NodeClient, NodeHeightResult,
OutputCommitMapping, PaymentProof, Slate, SlateVersion, Slatepack, SlatepackAddress,
StatusMessage, TxLogEntry, VersionedSlate, WalletInfo, WalletLCProvider,
StatusMessage, TxLogEntry, VersionedSlate, ViewWallet, WalletInfo, WalletLCProvider,
};
use crate::util::logger::LoggingConfig;
use crate::util::secp::key::{PublicKey, SecretKey};
Expand Down Expand Up @@ -840,6 +840,115 @@ pub trait OwnerRpc {
slate_id: Option<Uuid>,
) -> Result<Option<VersionedSlate>, ErrorKind>;

/**
Networked version of [Owner::get_rewind_hash](struct.Owner.html#method.get_rewind_hash).
```
# grin_wallet_api::doctest_helper_json_rpc_owner_assert_response!(
# r#"
{
"jsonrpc": "2.0",
"method": "get_rewind_hash",
"params": {
"token": "d202964900000000d302964900000000d402964900000000d502964900000000"
},
"id": 1
}
# "#
# ,
# r#"
{
"id":1,
"jsonrpc":"2.0",
"result":{
"Ok":"c820c52a492b7db511c752035483d0e50e8fd3ec62544f1b99638e220a4682de"
}
}
# "#
# , 0, false, false, false, false);
```
*/
fn get_rewind_hash(&self, token: Token) -> Result<String, ErrorKind>;

/**
Networked version of [Owner::scan_rewind_hash](struct.Owner.html#method.scan_rewind_hash).
```
# grin_wallet_api::doctest_helper_json_rpc_owner_assert_response!(
# r#"
{
"jsonrpc": "2.0",
"method": "scan_rewind_hash",
"params": {
"rewind_hash": "c820c52a492b7db511c752035483d0e50e8fd3ec62544f1b99638e220a4682de",
"start_height": 1
},
"id": 1
}
# "#
# ,
# r#"
{
"id":1,
"jsonrpc":"2.0",
"result":{
"Ok":{
"last_pmmr_index":8,
"output_result":[
{
"commit":"08e1da9e6dc4d6e808a718b2f110a991dd775d65ce5ae408a4e1f002a4961aa9e7",
"height":1,
"is_coinbase":true,
"lock_height":4,
"mmr_index":1,
"value":60000000000
},
{
"commit":"087df32304c5d4ae8b2af0bc31e700019d722910ef87dd4eec3197b80b207e3045",
"height":2,
"is_coinbase":true,
"lock_height":5,
"mmr_index":2,
"value":60000000000
},
{
"commit":"084219d64014223a205431acfa8f8cc3e8cb8c6d04df80b26713314becf83861c7",
"height":3,
"is_coinbase":true,
"lock_height":6,
"mmr_index":4,
"value":60000000000
},
{
"commit":"09c5efc4dab05d7d16fc90168c484c13f15a142ea4e1bf93c3fad12f5e8a402598",
"height":4,
"is_coinbase":true,
"lock_height":7,
"mmr_index":5,
"value":60000000000
},
{
"commit":"08fe198e525a5937d0c5d01fa354394d2679be6df5d42064a0f7550c332fce3d9d",
"height":5,
"is_coinbase":true,
"lock_height":8,
"mmr_index":8,
"value":60000000000
}
],
"rewind_hash":"c820c52a492b7db511c752035483d0e50e8fd3ec62544f1b99638e220a4682de",
"total_balance":300000000000
}
}
}
# "#
# , 5, false, false, false, false);
```
*/
fn scan_rewind_hash(
&self,
rewind_hash: String,
start_height: Option<u64>,
) -> Result<ViewWallet, ErrorKind>;

/**
Networked version of [Owner::scan](struct.Owner.html#method.scan).

Expand Down Expand Up @@ -1896,6 +2005,18 @@ where
.map_err(|e| e.kind())
}

fn get_rewind_hash(&self, token: Token) -> Result<String, ErrorKind> {
Owner::get_rewind_hash(self, (&token.keychain_mask).as_ref()).map_err(|e| e.kind())
}

fn scan_rewind_hash(
&self,
rewind_hash: String,
start_height: Option<u64>,
) -> Result<ViewWallet, ErrorKind> {
Owner::scan_rewind_hash(self, rewind_hash, start_height).map_err(|e| e.kind())
}

fn scan(
&self,
token: Token,
Expand Down
75 changes: 75 additions & 0 deletions controller/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use crate::libwallet::{
use crate::util::secp::key::SecretKey;
use crate::util::{Mutex, ZeroingString};
use crate::{controller, display};
use ::core::time;
use serde_json as json;
use std::convert::TryFrom;
use std::fs::File;
Expand Down Expand Up @@ -116,6 +117,80 @@ where
Ok(())
}

pub fn rewind_hash<'a, L, C, K>(
owner_api: &mut Owner<L, C, K>,
keychain_mask: Option<&SecretKey>,
) -> Result<(), Error>
where
L: WalletLCProvider<'static, C, K>,
C: NodeClient + 'static,
K: keychain::Keychain + 'static,
{
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
let rewind_hash = api.get_rewind_hash(m)?;
println!();
println!("Wallet Rewind Hash");
println!("-------------------------------------");
println!("{}", rewind_hash);
println!();
Ok(())
})?;
Ok(())
}

/// Arguments for rewind hash view wallet scan command
pub struct ViewWalletScanArgs {
pub rewind_hash: String,
pub start_height: Option<u64>,
pub backwards_from_tip: Option<u64>,
}

pub fn scan_rewind_hash<L, C, K>(
owner_api: &mut Owner<L, C, K>,
args: ViewWalletScanArgs,
dark_scheme: bool,
) -> Result<(), Error>
where
L: WalletLCProvider<'static, C, K> + 'static,
C: NodeClient + 'static,
K: keychain::Keychain + 'static,
{
controller::owner_single_use(None, None, Some(owner_api), |api, m| {
let rewind_hash = args.rewind_hash;
let tip_height = api.node_height(m)?.height;
let start_height = match args.backwards_from_tip {
Some(b) => tip_height.saturating_sub(b),
None => match args.start_height {
Some(s) => s,
None => 1,
},
};
warn!(
"Starting view wallet output scan from height {} ...",
start_height
);
let result = api.scan_rewind_hash(rewind_hash, Some(start_height));
let deci_sec = time::Duration::from_millis(100);
thread::sleep(deci_sec);
match result {
Ok(res) => {
warn!("View wallet check complete");
if res.total_balance != 0 {
display::view_wallet_output(res.clone(), tip_height, dark_scheme)?;
}
display::view_wallet_balance(res.clone(), tip_height, dark_scheme);
Ok(())
}
Err(e) => {
error!("View wallet check failed: {}", e);
error!("Backtrace: {}", e.backtrace().unwrap());
Err(e)
}
}
})?;
Ok(())
}

/// Arguments for listen command
pub struct ListenArgs {}

Expand Down
Loading