mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 17:01:09 +03:00
WalletClient trait refactor (#1238)
* refactor WalletClient * revert chain changes * missing files
This commit is contained in:
parent
c7d78446f3
commit
49cbab90f6
17 changed files with 432 additions and 433 deletions
|
@ -27,7 +27,7 @@ use std::default::Default;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::{fs, thread, time};
|
use std::{fs, thread, time};
|
||||||
|
|
||||||
use wallet::{FileWallet, WalletConfig};
|
use wallet::{HTTPWalletClient, FileWallet, WalletConfig};
|
||||||
|
|
||||||
/// Just removes all results from previous runs
|
/// Just removes all results from previous runs
|
||||||
pub fn clean_all_output(test_name_dir: &str) {
|
pub fn clean_all_output(test_name_dir: &str) {
|
||||||
|
@ -262,12 +262,14 @@ impl LocalServerContainer {
|
||||||
let _ = fs::create_dir_all(self.wallet_config.clone().data_file_dir);
|
let _ = fs::create_dir_all(self.wallet_config.clone().data_file_dir);
|
||||||
let r = wallet::WalletSeed::init_file(&self.wallet_config);
|
let r = wallet::WalletSeed::init_file(&self.wallet_config);
|
||||||
|
|
||||||
|
let client = HTTPWalletClient::new(&self.wallet_config.check_node_api_http_addr);
|
||||||
|
|
||||||
if let Err(e) = r {
|
if let Err(e) = r {
|
||||||
//panic!("Error initting wallet seed: {}", e);
|
//panic!("Error initting wallet seed: {}", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
let wallet: FileWallet<keychain::ExtKeychain> =
|
let wallet: FileWallet<HTTPWalletClient, keychain::ExtKeychain> =
|
||||||
FileWallet::new(self.wallet_config.clone(), "").unwrap_or_else(|e| {
|
FileWallet::new(self.wallet_config.clone(), "", client).unwrap_or_else(|e| {
|
||||||
panic!(
|
panic!(
|
||||||
"Error creating wallet: {:?} Config: {:?}",
|
"Error creating wallet: {:?} Config: {:?}",
|
||||||
e, self.wallet_config
|
e, self.wallet_config
|
||||||
|
@ -300,7 +302,8 @@ impl LocalServerContainer {
|
||||||
let keychain: keychain::ExtKeychain = wallet_seed
|
let keychain: keychain::ExtKeychain = wallet_seed
|
||||||
.derive_keychain("")
|
.derive_keychain("")
|
||||||
.expect("Failed to derive keychain from seed file and passphrase.");
|
.expect("Failed to derive keychain from seed file and passphrase.");
|
||||||
let mut wallet = FileWallet::new(config.clone(), "")
|
let client = HTTPWalletClient::new(&config.check_node_api_http_addr);
|
||||||
|
let mut wallet = FileWallet::new(config.clone(), "", client)
|
||||||
.unwrap_or_else(|e| panic!("Error creating wallet: {:?} Config: {:?}", e, config));
|
.unwrap_or_else(|e| panic!("Error creating wallet: {:?} Config: {:?}", e, config));
|
||||||
wallet.keychain = Some(keychain);
|
wallet.keychain = Some(keychain);
|
||||||
let _ = wallet::libwallet::internal::updater::refresh_outputs(&mut wallet);
|
let _ = wallet::libwallet::internal::updater::refresh_outputs(&mut wallet);
|
||||||
|
@ -324,9 +327,11 @@ impl LocalServerContainer {
|
||||||
let keychain: keychain::ExtKeychain = wallet_seed
|
let keychain: keychain::ExtKeychain = wallet_seed
|
||||||
.derive_keychain("")
|
.derive_keychain("")
|
||||||
.expect("Failed to derive keychain from seed file and passphrase.");
|
.expect("Failed to derive keychain from seed file and passphrase.");
|
||||||
|
|
||||||
|
let client = HTTPWalletClient::new(&config.check_node_api_http_addr);
|
||||||
let max_outputs = 500;
|
let max_outputs = 500;
|
||||||
|
|
||||||
let mut wallet = FileWallet::new(config.clone(), "")
|
let mut wallet = FileWallet::new(config.clone(), "", client)
|
||||||
.unwrap_or_else(|e| panic!("Error creating wallet: {:?} Config: {:?}", e, config));
|
.unwrap_or_else(|e| panic!("Error creating wallet: {:?} Config: {:?}", e, config));
|
||||||
wallet.keychain = Some(keychain);
|
wallet.keychain = Some(keychain);
|
||||||
let _ =
|
let _ =
|
||||||
|
|
|
@ -53,7 +53,8 @@ use core::core::amount_to_hr_string;
|
||||||
use core::global;
|
use core::global;
|
||||||
use tui::ui;
|
use tui::ui;
|
||||||
use util::{init_logger, LoggingConfig, LOGGER};
|
use util::{init_logger, LoggingConfig, LOGGER};
|
||||||
use wallet::{libwallet, wallet_db_exists, FileWallet, LMDBBackend, WalletConfig, WalletInst};
|
use wallet::{libwallet, wallet_db_exists, FileWallet,
|
||||||
|
HTTPWalletClient, LMDBBackend, WalletConfig, WalletInst};
|
||||||
|
|
||||||
// include build information
|
// include build information
|
||||||
pub mod built_info {
|
pub mod built_info {
|
||||||
|
@ -553,9 +554,10 @@ fn instantiate_wallet(
|
||||||
wallet_config: WalletConfig,
|
wallet_config: WalletConfig,
|
||||||
passphrase: &str,
|
passphrase: &str,
|
||||||
use_db: bool,
|
use_db: bool,
|
||||||
) -> Box<WalletInst<keychain::ExtKeychain>> {
|
) -> Box<WalletInst<HTTPWalletClient, keychain::ExtKeychain>> {
|
||||||
|
let client = HTTPWalletClient::new(&wallet_config.check_node_api_http_addr);
|
||||||
if use_db {
|
if use_db {
|
||||||
let db_wallet = LMDBBackend::new(wallet_config.clone(), "").unwrap_or_else(|e| {
|
let db_wallet = LMDBBackend::new(wallet_config.clone(), "", client).unwrap_or_else(|e| {
|
||||||
panic!(
|
panic!(
|
||||||
"Error creating DB wallet: {} Config: {:?}",
|
"Error creating DB wallet: {} Config: {:?}",
|
||||||
e, wallet_config
|
e, wallet_config
|
||||||
|
@ -564,7 +566,7 @@ fn instantiate_wallet(
|
||||||
info!(LOGGER, "Using LMDB Backend for wallet");
|
info!(LOGGER, "Using LMDB Backend for wallet");
|
||||||
Box::new(db_wallet)
|
Box::new(db_wallet)
|
||||||
} else {
|
} else {
|
||||||
let file_wallet = FileWallet::new(wallet_config.clone(), passphrase)
|
let file_wallet = FileWallet::new(wallet_config.clone(), passphrase, client)
|
||||||
.unwrap_or_else(|e| panic!("Error creating wallet: {} Config: {:?}", e, wallet_config));
|
.unwrap_or_else(|e| panic!("Error creating wallet: {} Config: {:?}", e, wallet_config));
|
||||||
info!(LOGGER, "Using File Backend for wallet");
|
info!(LOGGER, "Using File Backend for wallet");
|
||||||
Box::new(file_wallet)
|
Box::new(file_wallet)
|
||||||
|
@ -603,7 +605,8 @@ fn wallet_command(wallet_args: &ArgMatches, global_config: GlobalConfig) {
|
||||||
wallet::WalletSeed::init_file(&wallet_config).expect("Failed to init wallet seed file.");
|
wallet::WalletSeed::init_file(&wallet_config).expect("Failed to init wallet seed file.");
|
||||||
info!(LOGGER, "Wallet seed file created");
|
info!(LOGGER, "Wallet seed file created");
|
||||||
if use_db {
|
if use_db {
|
||||||
let _: LMDBBackend<keychain::ExtKeychain> = LMDBBackend::new(wallet_config.clone(), "")
|
let client = HTTPWalletClient::new(&wallet_config.check_node_api_http_addr);
|
||||||
|
let _: LMDBBackend<HTTPWalletClient, keychain::ExtKeychain> = LMDBBackend::new(wallet_config.clone(), "", client)
|
||||||
.unwrap_or_else(|e| {
|
.unwrap_or_else(|e| {
|
||||||
panic!(
|
panic!(
|
||||||
"Error creating DB wallet: {} Config: {:?}",
|
"Error creating DB wallet: {} Config: {:?}",
|
||||||
|
|
|
@ -28,10 +28,188 @@ use tokio_core::reactor;
|
||||||
|
|
||||||
use api;
|
use api;
|
||||||
use error::{Error, ErrorKind};
|
use error::{Error, ErrorKind};
|
||||||
|
use libwallet;
|
||||||
use libtx::slate::Slate;
|
use libtx::slate::Slate;
|
||||||
use util::secp::pedersen;
|
use util::secp::pedersen;
|
||||||
use util::{self, LOGGER};
|
use util::{self, LOGGER};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct HTTPWalletClient {
|
||||||
|
node_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HTTPWalletClient {
|
||||||
|
/// Create a new client that will communicate with the given grin node
|
||||||
|
pub fn new(node_url:&str) -> HTTPWalletClient {
|
||||||
|
HTTPWalletClient {
|
||||||
|
node_url: node_url.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WalletClient for HTTPWalletClient {
|
||||||
|
fn node_url(&self) -> &str {
|
||||||
|
&self.node_url
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call the wallet API to create a coinbase output for the given block_fees.
|
||||||
|
/// Will retry based on default "retry forever with backoff" behavior.
|
||||||
|
fn create_coinbase(&self, dest: &str, block_fees: &BlockFees) -> Result<CbData, libwallet::Error> {
|
||||||
|
let url = format!("{}/v1/wallet/foreign/build_coinbase", dest);
|
||||||
|
match single_create_coinbase(&url, &block_fees) {
|
||||||
|
Err(e) => {
|
||||||
|
error!(
|
||||||
|
LOGGER,
|
||||||
|
"Failed to get coinbase from {}. Run grin wallet listen?", url
|
||||||
|
);
|
||||||
|
error!(LOGGER, "Underlying Error: {}", e.cause().unwrap());
|
||||||
|
error!(LOGGER, "Backtrace: {}", e.backtrace().unwrap());
|
||||||
|
Err(libwallet::ErrorKind::ClientCallback("Failed to get coinbase"))?
|
||||||
|
}
|
||||||
|
Ok(res) => Ok(res),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send the slate to a listening wallet instance
|
||||||
|
fn send_tx_slate(&self, dest: &str, slate: &Slate) -> Result<Slate, libwallet::Error> {
|
||||||
|
if &dest[..4] != "http" {
|
||||||
|
let err_str = format!(
|
||||||
|
"dest formatted as {} but send -d expected stdout or http://IP:port",
|
||||||
|
dest
|
||||||
|
);
|
||||||
|
error!(LOGGER, "{}", err_str,);
|
||||||
|
Err(libwallet::ErrorKind::Uri)?
|
||||||
|
}
|
||||||
|
let url = format!("{}/v1/wallet/foreign/receive_tx", dest);
|
||||||
|
debug!(LOGGER, "Posting transaction slate to {}", url);
|
||||||
|
|
||||||
|
let mut core = reactor::Core::new()
|
||||||
|
.context(libwallet::ErrorKind::ClientCallback("Sending transaction: Initialise API"))?;
|
||||||
|
let client = hyper::Client::new(&core.handle());
|
||||||
|
|
||||||
|
let url_pool = url.to_owned();
|
||||||
|
|
||||||
|
let mut req = Request::new(
|
||||||
|
Method::Post,
|
||||||
|
url_pool.parse::<hyper::Uri>()
|
||||||
|
.context(libwallet::ErrorKind::ClientCallback("Sending transaction: parsing URL"))?
|
||||||
|
);
|
||||||
|
req.headers_mut().set(ContentType::json());
|
||||||
|
let json = serde_json::to_string(&slate)
|
||||||
|
.context(libwallet::ErrorKind::ClientCallback("Sending transaction: parsing response"))?;
|
||||||
|
req.set_body(json);
|
||||||
|
|
||||||
|
let work = client.request(req).and_then(|res| {
|
||||||
|
res.body().concat2().and_then(move |body| {
|
||||||
|
let slate: Slate =
|
||||||
|
serde_json::from_slice(&body).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||||
|
Ok(slate)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
let res = core.run(work)
|
||||||
|
.context(libwallet::ErrorKind::ClientCallback("Sending transaction: posting request"))?;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Posts a transaction to a grin node
|
||||||
|
fn post_tx(&self, tx: &TxWrapper, fluff: bool) -> Result<(), libwallet::Error> {
|
||||||
|
let url;
|
||||||
|
let dest = self.node_url();
|
||||||
|
if fluff {
|
||||||
|
url = format!("{}/v1/pool/push?fluff", dest);
|
||||||
|
} else {
|
||||||
|
url = format!("{}/v1/pool/push", dest);
|
||||||
|
}
|
||||||
|
api::client::post(url.as_str(), tx)
|
||||||
|
.context(libwallet::ErrorKind::ClientCallback("Posting transaction to node"))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the chain tip from a given node
|
||||||
|
fn get_chain_height(&self) -> Result<u64, libwallet::Error> {
|
||||||
|
let addr = self.node_url();
|
||||||
|
let url = format!("{}/v1/chain", addr);
|
||||||
|
let res = api::client::get::<api::Tip>(url.as_str())
|
||||||
|
.context(libwallet::ErrorKind::ClientCallback("Getting chain height from node"))?;
|
||||||
|
Ok(res.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve outputs from node
|
||||||
|
fn get_outputs_from_node(
|
||||||
|
&self,
|
||||||
|
wallet_outputs: Vec<pedersen::Commitment>,
|
||||||
|
) -> Result<HashMap<pedersen::Commitment, String>, libwallet::Error> {
|
||||||
|
let addr = self.node_url();
|
||||||
|
// build the necessary query params -
|
||||||
|
// ?id=xxx&id=yyy&id=zzz
|
||||||
|
let query_params: Vec<String> = wallet_outputs
|
||||||
|
.iter()
|
||||||
|
.map(|commit| format!("id={}", util::to_hex(commit.as_ref().to_vec())))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// build a map of api outputs by commit so we can look them up efficiently
|
||||||
|
let mut api_outputs: HashMap<pedersen::Commitment, String> = HashMap::new();
|
||||||
|
|
||||||
|
for query_chunk in query_params.chunks(1000) {
|
||||||
|
let url = format!("{}/v1/chain/outputs/byids?{}", addr, query_chunk.join("&"),);
|
||||||
|
|
||||||
|
match api::client::get::<Vec<api::Output>>(url.as_str()) {
|
||||||
|
Ok(outputs) => for out in outputs {
|
||||||
|
api_outputs.insert(out.commit.commit(), util::to_hex(out.commit.to_vec()));
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
// if we got anything other than 200 back from server, don't attempt to refresh
|
||||||
|
// the wallet data after
|
||||||
|
return Err(libwallet::ErrorKind::ClientCallback("Error from server"))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(api_outputs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_outputs_by_pmmr_index(
|
||||||
|
&self,
|
||||||
|
start_height: u64,
|
||||||
|
max_outputs: u64,
|
||||||
|
) -> Result<
|
||||||
|
(
|
||||||
|
u64,
|
||||||
|
u64,
|
||||||
|
Vec<(pedersen::Commitment, pedersen::RangeProof, bool)>,
|
||||||
|
),
|
||||||
|
libwallet::Error,
|
||||||
|
> {
|
||||||
|
let addr = self.node_url();
|
||||||
|
let query_param = format!("start_index={}&max={}", start_height, max_outputs);
|
||||||
|
|
||||||
|
let url = format!("{}/v1/txhashset/outputs?{}", addr, query_param,);
|
||||||
|
|
||||||
|
let mut api_outputs: Vec<(pedersen::Commitment, pedersen::RangeProof, bool)> = Vec::new();
|
||||||
|
|
||||||
|
match api::client::get::<api::OutputListing>(url.as_str()) {
|
||||||
|
Ok(o) => {
|
||||||
|
for out in o.outputs {
|
||||||
|
let is_coinbase = match out.output_type {
|
||||||
|
api::OutputType::Coinbase => true,
|
||||||
|
api::OutputType::Transaction => false,
|
||||||
|
};
|
||||||
|
api_outputs.push((out.commit, out.range_proof().unwrap(), is_coinbase));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((o.highest_index, o.last_retrieved_index, api_outputs))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// if we got anything other than 200 back from server, bye
|
||||||
|
error!(
|
||||||
|
LOGGER,
|
||||||
|
"get_outputs_by_pmmr_index: unable to contact API {}. Error: {}", addr, e
|
||||||
|
);
|
||||||
|
Err(libwallet::ErrorKind::ClientCallback("unable to contact api"))?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Call the wallet API to create a coinbase output for the given block_fees.
|
/// Call the wallet API to create a coinbase output for the given block_fees.
|
||||||
/// Will retry based on default "retry forever with backoff" behavior.
|
/// Will retry based on default "retry forever with backoff" behavior.
|
||||||
pub fn create_coinbase(dest: &str, block_fees: &BlockFees) -> Result<CbData, Error> {
|
pub fn create_coinbase(dest: &str, block_fees: &BlockFees) -> Result<CbData, Error> {
|
||||||
|
@ -44,49 +222,12 @@ pub fn create_coinbase(dest: &str, block_fees: &BlockFees) -> Result<CbData, Err
|
||||||
);
|
);
|
||||||
error!(LOGGER, "Underlying Error: {}", e.cause().unwrap());
|
error!(LOGGER, "Underlying Error: {}", e.cause().unwrap());
|
||||||
error!(LOGGER, "Backtrace: {}", e.backtrace().unwrap());
|
error!(LOGGER, "Backtrace: {}", e.backtrace().unwrap());
|
||||||
Err(e)
|
Err(e)?
|
||||||
}
|
}
|
||||||
Ok(res) => Ok(res),
|
Ok(res) => Ok(res),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send the slate to a listening wallet instance
|
|
||||||
pub fn send_tx_slate(dest: &str, slate: &Slate) -> Result<Slate, Error> {
|
|
||||||
if &dest[..4] != "http" {
|
|
||||||
let err_str = format!(
|
|
||||||
"dest formatted as {} but send -d expected stdout or http://IP:port",
|
|
||||||
dest
|
|
||||||
);
|
|
||||||
error!(LOGGER, "{}", err_str,);
|
|
||||||
Err(ErrorKind::Uri)?
|
|
||||||
}
|
|
||||||
let url = format!("{}/v1/wallet/foreign/receive_tx", dest);
|
|
||||||
debug!(LOGGER, "Posting transaction slate to {}", url);
|
|
||||||
|
|
||||||
let mut core = reactor::Core::new().context(ErrorKind::Hyper)?;
|
|
||||||
let client = hyper::Client::new(&core.handle());
|
|
||||||
|
|
||||||
let url_pool = url.to_owned();
|
|
||||||
|
|
||||||
let mut req = Request::new(
|
|
||||||
Method::Post,
|
|
||||||
url_pool.parse::<hyper::Uri>().context(ErrorKind::Hyper)?,
|
|
||||||
);
|
|
||||||
req.headers_mut().set(ContentType::json());
|
|
||||||
let json = serde_json::to_string(&slate).context(ErrorKind::Hyper)?;
|
|
||||||
req.set_body(json);
|
|
||||||
|
|
||||||
let work = client.request(req).and_then(|res| {
|
|
||||||
res.body().concat2().and_then(move |body| {
|
|
||||||
let slate: Slate =
|
|
||||||
serde_json::from_slice(&body).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
|
||||||
Ok(slate)
|
|
||||||
})
|
|
||||||
});
|
|
||||||
let res = core.run(work).context(ErrorKind::Hyper)?;
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a single request to the wallet API to create a new coinbase output.
|
/// Makes a single request to the wallet API to create a new coinbase output.
|
||||||
fn single_create_coinbase(url: &str, block_fees: &BlockFees) -> Result<CbData, Error> {
|
fn single_create_coinbase(url: &str, block_fees: &BlockFees) -> Result<CbData, Error> {
|
||||||
let mut core =
|
let mut core =
|
||||||
|
@ -116,94 +257,3 @@ fn single_create_coinbase(url: &str, block_fees: &BlockFees) -> Result<CbData, E
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Posts a transaction to a grin node
|
|
||||||
pub fn post_tx(dest: &str, tx: &TxWrapper, fluff: bool) -> Result<(), Error> {
|
|
||||||
let url;
|
|
||||||
if fluff {
|
|
||||||
url = format!("{}/v1/pool/push?fluff", dest);
|
|
||||||
} else {
|
|
||||||
url = format!("{}/v1/pool/push", dest);
|
|
||||||
}
|
|
||||||
api::client::post(url.as_str(), tx)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the chain tip from a given node
|
|
||||||
pub fn get_chain_height(addr: &str) -> Result<u64, Error> {
|
|
||||||
let url = format!("{}/v1/chain", addr);
|
|
||||||
let res = api::client::get::<api::Tip>(url.as_str())?;
|
|
||||||
Ok(res.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve outputs from node
|
|
||||||
pub fn get_outputs_from_node(
|
|
||||||
addr: &str,
|
|
||||||
wallet_outputs: Vec<pedersen::Commitment>,
|
|
||||||
) -> Result<HashMap<pedersen::Commitment, String>, Error> {
|
|
||||||
// build the necessary query params -
|
|
||||||
// ?id=xxx&id=yyy&id=zzz
|
|
||||||
let query_params: Vec<String> = wallet_outputs
|
|
||||||
.iter()
|
|
||||||
.map(|commit| format!("id={}", util::to_hex(commit.as_ref().to_vec())))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// build a map of api outputs by commit so we can look them up efficiently
|
|
||||||
let mut api_outputs: HashMap<pedersen::Commitment, String> = HashMap::new();
|
|
||||||
|
|
||||||
for query_chunk in query_params.chunks(1000) {
|
|
||||||
let url = format!("{}/v1/chain/outputs/byids?{}", addr, query_chunk.join("&"),);
|
|
||||||
|
|
||||||
match api::client::get::<Vec<api::Output>>(url.as_str()) {
|
|
||||||
Ok(outputs) => for out in outputs {
|
|
||||||
api_outputs.insert(out.commit.commit(), util::to_hex(out.commit.to_vec()));
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
// if we got anything other than 200 back from server, don't attempt to refresh
|
|
||||||
// the wallet data after
|
|
||||||
return Err(e)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(api_outputs)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_outputs_by_pmmr_index(
|
|
||||||
addr: &str,
|
|
||||||
start_height: u64,
|
|
||||||
max_outputs: u64,
|
|
||||||
) -> Result<
|
|
||||||
(
|
|
||||||
u64,
|
|
||||||
u64,
|
|
||||||
Vec<(pedersen::Commitment, pedersen::RangeProof, bool)>,
|
|
||||||
),
|
|
||||||
Error,
|
|
||||||
> {
|
|
||||||
let query_param = format!("start_index={}&max={}", start_height, max_outputs);
|
|
||||||
|
|
||||||
let url = format!("{}/v1/txhashset/outputs?{}", addr, query_param,);
|
|
||||||
|
|
||||||
let mut api_outputs: Vec<(pedersen::Commitment, pedersen::RangeProof, bool)> = Vec::new();
|
|
||||||
|
|
||||||
match api::client::get::<api::OutputListing>(url.as_str()) {
|
|
||||||
Ok(o) => {
|
|
||||||
for out in o.outputs {
|
|
||||||
let is_coinbase = match out.output_type {
|
|
||||||
api::OutputType::Coinbase => true,
|
|
||||||
api::OutputType::Transaction => false,
|
|
||||||
};
|
|
||||||
api_outputs.push((out.commit, out.range_proof().unwrap(), is_coinbase));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((o.highest_index, o.last_retrieved_index, api_outputs))
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
// if we got anything other than 200 back from server, bye
|
|
||||||
error!(
|
|
||||||
LOGGER,
|
|
||||||
"get_outputs_by_pmmr_index: unable to contact API {}. Error: {}", addr, e
|
|
||||||
);
|
|
||||||
Err(e)?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -139,9 +139,11 @@ impl<'a> Drop for FileBatch<'a> {
|
||||||
/// Wallet information tracking all our outputs. Based on HD derivation and
|
/// Wallet information tracking all our outputs. Based on HD derivation and
|
||||||
/// avoids storing any key data, only storing output amounts and child index.
|
/// avoids storing any key data, only storing output amounts and child index.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FileWallet<K> {
|
pub struct FileWallet<C, K> {
|
||||||
/// Keychain
|
/// Keychain
|
||||||
pub keychain: Option<K>,
|
pub keychain: Option<K>,
|
||||||
|
/// Client implementation
|
||||||
|
pub client: C,
|
||||||
/// Configuration
|
/// Configuration
|
||||||
pub config: WalletConfig,
|
pub config: WalletConfig,
|
||||||
/// passphrase: TODO better ways of dealing with this other than storing
|
/// passphrase: TODO better ways of dealing with this other than storing
|
||||||
|
@ -162,8 +164,9 @@ pub struct FileWallet<K> {
|
||||||
pub details_bak_path: String,
|
pub details_bak_path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K> WalletBackend<K> for FileWallet<K>
|
impl<C, K> WalletBackend<C, K> for FileWallet<C, K>
|
||||||
where
|
where
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Initialize with whatever stored credentials we have
|
/// Initialize with whatever stored credentials we have
|
||||||
|
@ -190,6 +193,11 @@ where
|
||||||
self.keychain.as_mut().unwrap()
|
self.keychain.as_mut().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the client being used
|
||||||
|
fn client(&mut self) -> &mut C {
|
||||||
|
&mut self.client
|
||||||
|
}
|
||||||
|
|
||||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = OutputData> + 'a> {
|
fn iter<'a>(&'a self) -> Box<Iterator<Item = OutputData> + 'a> {
|
||||||
Box::new(self.outputs.values().cloned())
|
Box::new(self.outputs.values().cloned())
|
||||||
}
|
}
|
||||||
|
@ -320,98 +328,16 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K> WalletClient for FileWallet<K> {
|
impl<C, K> FileWallet<C, K>
|
||||||
/// Return URL for check node
|
|
||||||
fn node_url(&self) -> &str {
|
|
||||||
&self.config.check_node_api_http_addr
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Call the wallet API to create a coinbase transaction
|
|
||||||
fn create_coinbase(&self, block_fees: &BlockFees) -> Result<CbData, libwallet::Error> {
|
|
||||||
let res = client::create_coinbase(self.node_url(), block_fees);
|
|
||||||
match res {
|
|
||||||
Ok(r) => Ok(r),
|
|
||||||
Err(e) => {
|
|
||||||
let message = format!("{}", e.cause().unwrap());
|
|
||||||
error!(
|
|
||||||
LOGGER,
|
|
||||||
"Create Coinbase: Communication error: {},{}",
|
|
||||||
e.cause().unwrap(),
|
|
||||||
e.backtrace().unwrap()
|
|
||||||
);
|
|
||||||
Err(libwallet::ErrorKind::WalletComms(message))?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send a transaction slate to another listening wallet and return result
|
|
||||||
fn send_tx_slate(&self, addr: &str, slate: &Slate) -> Result<Slate, libwallet::Error> {
|
|
||||||
let res = client::send_tx_slate(addr, slate);
|
|
||||||
match res {
|
|
||||||
Ok(r) => Ok(r),
|
|
||||||
Err(e) => {
|
|
||||||
let message = format!("{}", e.cause().unwrap());
|
|
||||||
error!(
|
|
||||||
LOGGER,
|
|
||||||
"Send TX Slate: Communication error: {},{}",
|
|
||||||
e.cause().unwrap(),
|
|
||||||
e.backtrace().unwrap()
|
|
||||||
);
|
|
||||||
Err(libwallet::ErrorKind::WalletComms(message))?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Posts a transaction to a grin node
|
|
||||||
fn post_tx(&self, tx: &TxWrapper, fluff: bool) -> Result<(), libwallet::Error> {
|
|
||||||
let res = client::post_tx(self.node_url(), tx, fluff).context(libwallet::ErrorKind::Node)?;
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// retrieves the current tip from the specified grin node
|
|
||||||
fn get_chain_height(&self) -> Result<u64, libwallet::Error> {
|
|
||||||
let res = client::get_chain_height(self.node_url()).context(libwallet::ErrorKind::Node)?;
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// retrieve a list of outputs from the specified grin node
|
|
||||||
/// need "by_height" and "by_id" variants
|
|
||||||
fn get_outputs_from_node(
|
|
||||||
&self,
|
|
||||||
wallet_outputs: Vec<pedersen::Commitment>,
|
|
||||||
) -> Result<HashMap<pedersen::Commitment, String>, libwallet::Error> {
|
|
||||||
let res = client::get_outputs_from_node(self.node_url(), wallet_outputs)
|
|
||||||
.context(libwallet::ErrorKind::Node)?;
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Outputs by PMMR index
|
|
||||||
fn get_outputs_by_pmmr_index(
|
|
||||||
&self,
|
|
||||||
start_height: u64,
|
|
||||||
max_outputs: u64,
|
|
||||||
) -> Result<
|
|
||||||
(
|
|
||||||
u64,
|
|
||||||
u64,
|
|
||||||
Vec<(pedersen::Commitment, pedersen::RangeProof, bool)>,
|
|
||||||
),
|
|
||||||
libwallet::Error,
|
|
||||||
> {
|
|
||||||
let res = client::get_outputs_by_pmmr_index(self.node_url(), start_height, max_outputs)
|
|
||||||
.context(libwallet::ErrorKind::Node)?;
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K> FileWallet<K>
|
|
||||||
where
|
where
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Create a new FileWallet instance
|
/// Create a new FileWallet instance
|
||||||
pub fn new(config: WalletConfig, passphrase: &str) -> Result<Self, Error> {
|
pub fn new(config: WalletConfig, passphrase: &str, client: C) -> Result<Self, Error> {
|
||||||
let mut retval = FileWallet {
|
let mut retval = FileWallet {
|
||||||
keychain: None,
|
keychain: None,
|
||||||
|
client: client,
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
passphrase: String::from(passphrase),
|
passphrase: String::from(passphrase),
|
||||||
outputs: HashMap::new(),
|
outputs: HashMap::new(),
|
||||||
|
|
|
@ -56,10 +56,10 @@ pub mod libwallet;
|
||||||
pub mod lmdb_wallet;
|
pub mod lmdb_wallet;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
pub use client::create_coinbase;
|
|
||||||
pub use error::{Error, ErrorKind};
|
pub use error::{Error, ErrorKind};
|
||||||
pub use file_wallet::FileWallet;
|
pub use file_wallet::FileWallet;
|
||||||
|
pub use client::{create_coinbase, HTTPWalletClient};
|
||||||
pub use libwallet::controller;
|
pub use libwallet::controller;
|
||||||
pub use libwallet::types::{BlockFees, CbData, WalletInfo, WalletInst};
|
pub use libwallet::types::{BlockFees, CbData, WalletBackend, WalletClient, WalletInfo, WalletInst};
|
||||||
pub use lmdb_wallet::{wallet_db_exists, LMDBBackend};
|
pub use lmdb_wallet::{wallet_db_exists, LMDBBackend};
|
||||||
pub use types::{WalletConfig, WalletSeed};
|
pub use types::{WalletConfig, WalletSeed};
|
||||||
|
|
|
@ -31,27 +31,31 @@ use util::{self, LOGGER};
|
||||||
|
|
||||||
/// Wrapper around internal API functions, containing a reference to
|
/// Wrapper around internal API functions, containing a reference to
|
||||||
/// the wallet/keychain that they're acting upon
|
/// the wallet/keychain that they're acting upon
|
||||||
pub struct APIOwner<'a, W: ?Sized, K>
|
pub struct APIOwner<'a, W: ?Sized, C, K>
|
||||||
where
|
where
|
||||||
W: 'a + WalletBackend<K> + WalletClient,
|
W: 'a + WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Wallet, contains its keychain (TODO: Split these up into 2 traits
|
/// Wallet, contains its keychain (TODO: Split these up into 2 traits
|
||||||
/// perhaps)
|
/// perhaps)
|
||||||
pub wallet: &'a mut Box<W>,
|
pub wallet: &'a mut Box<W>,
|
||||||
phantom: PhantomData<K>,
|
phantom: PhantomData<K>,
|
||||||
|
phantom_c: PhantomData<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, W: ?Sized, K> APIOwner<'a, W, K>
|
impl<'a, W: ?Sized, C, K> APIOwner<'a, W, C, K>
|
||||||
where
|
where
|
||||||
W: 'a + WalletBackend<K> + WalletClient,
|
W: 'a + WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Create new API instance
|
/// Create new API instance
|
||||||
pub fn new(wallet_in: &'a mut Box<W>) -> APIOwner<'a, W, K> {
|
pub fn new(wallet_in: &'a mut Box<W>) -> APIOwner<'a, W, C, K> {
|
||||||
APIOwner {
|
APIOwner {
|
||||||
wallet: wallet_in,
|
wallet: wallet_in,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
|
phantom_c: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +107,7 @@ where
|
||||||
selection_strategy_is_use_all,
|
selection_strategy_is_use_all,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut slate = match self.wallet.send_tx_slate(dest, &slate) {
|
let mut slate = match self.wallet.client().send_tx_slate(dest, &slate) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!(
|
error!(
|
||||||
|
@ -119,7 +123,7 @@ where
|
||||||
|
|
||||||
// All good here, so let's post it
|
// All good here, so let's post it
|
||||||
let tx_hex = util::to_hex(ser::ser_vec(&slate.tx).unwrap());
|
let tx_hex = util::to_hex(ser::ser_vec(&slate.tx).unwrap());
|
||||||
self.wallet.post_tx(&TxWrapper { tx_hex: tx_hex }, fluff)?;
|
self.wallet.client().post_tx(&TxWrapper { tx_hex: tx_hex }, fluff)?;
|
||||||
|
|
||||||
// All good here, lock our inputs
|
// All good here, lock our inputs
|
||||||
lock_fn(self.wallet)?;
|
lock_fn(self.wallet)?;
|
||||||
|
@ -140,7 +144,7 @@ where
|
||||||
max_outputs,
|
max_outputs,
|
||||||
)?;
|
)?;
|
||||||
let tx_hex = util::to_hex(ser::ser_vec(&tx_burn).unwrap());
|
let tx_hex = util::to_hex(ser::ser_vec(&tx_burn).unwrap());
|
||||||
self.wallet.post_tx(&TxWrapper { tx_hex: tx_hex }, false)?;
|
self.wallet.client().post_tx(&TxWrapper { tx_hex: tx_hex }, false)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +155,7 @@ where
|
||||||
|
|
||||||
/// Retrieve current height from node
|
/// Retrieve current height from node
|
||||||
pub fn node_height(&mut self) -> Result<(u64, bool), Error> {
|
pub fn node_height(&mut self) -> Result<(u64, bool), Error> {
|
||||||
match self.wallet.get_chain_height() {
|
match self.wallet.client().get_chain_height() {
|
||||||
Ok(height) => Ok((height, true)),
|
Ok(height) => Ok((height, true)),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let outputs = self.retrieve_outputs(true, false)?;
|
let outputs = self.retrieve_outputs(true, false)?;
|
||||||
|
@ -175,27 +179,31 @@ where
|
||||||
|
|
||||||
/// Wrapper around external API functions, intended to communicate
|
/// Wrapper around external API functions, intended to communicate
|
||||||
/// with other parties
|
/// with other parties
|
||||||
pub struct APIForeign<'a, W: ?Sized, K>
|
pub struct APIForeign<'a, W: ?Sized, C, K>
|
||||||
where
|
where
|
||||||
W: WalletBackend<K> + WalletClient + 'a,
|
W: 'a + WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Wallet, contains its keychain (TODO: Split these up into 2 traits
|
/// Wallet, contains its keychain (TODO: Split these up into 2 traits
|
||||||
/// perhaps)
|
/// perhaps)
|
||||||
pub wallet: &'a mut Box<W>,
|
pub wallet: &'a mut Box<W>,
|
||||||
phantom: PhantomData<K>,
|
phantom: PhantomData<K>,
|
||||||
|
phantom_c: PhantomData<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, W: ?Sized, K> APIForeign<'a, W, K>
|
impl<'a, W: ?Sized, C, K> APIForeign<'a, W, C, K>
|
||||||
where
|
where
|
||||||
W: WalletBackend<K> + WalletClient,
|
W: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Create new API instance
|
/// Create new API instance
|
||||||
pub fn new(wallet_in: &'a mut Box<W>) -> APIForeign<W, K> {
|
pub fn new(wallet_in: &'a mut Box<W>) -> APIForeign<W, C, K> {
|
||||||
APIForeign {
|
APIForeign {
|
||||||
wallet: wallet_in,
|
wallet: wallet_in,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
|
phantom_c: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ use keychain::Keychain;
|
||||||
use libtx::slate::Slate;
|
use libtx::slate::Slate;
|
||||||
use libwallet::api::{APIForeign, APIOwner};
|
use libwallet::api::{APIForeign, APIOwner};
|
||||||
use libwallet::types::{
|
use libwallet::types::{
|
||||||
BlockFees, CbData, OutputData, SendTXArgs, WalletBackend, WalletClient, WalletInfo, WalletInst,
|
BlockFees, CbData, OutputData, SendTXArgs, WalletBackend, WalletClient, WalletInfo
|
||||||
};
|
};
|
||||||
use libwallet::{Error, ErrorKind};
|
use libwallet::{Error, ErrorKind};
|
||||||
|
|
||||||
|
@ -40,10 +40,11 @@ use util::LOGGER;
|
||||||
|
|
||||||
/// Instantiate wallet Owner API for a single-use (command line) call
|
/// Instantiate wallet Owner API for a single-use (command line) call
|
||||||
/// Return a function containing a loaded API context to call
|
/// Return a function containing a loaded API context to call
|
||||||
pub fn owner_single_use<F, T: ?Sized, K>(wallet: Box<T>, f: F) -> Result<(), Error>
|
pub fn owner_single_use<F, T: ?Sized, C, K>(wallet: Box<T>, f: F) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<C, K>,
|
||||||
F: FnOnce(&mut APIOwner<T, K>) -> Result<(), Error>,
|
F: FnOnce(&mut APIOwner<T, C, K>) -> Result<(), Error>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let mut w = wallet;
|
let mut w = wallet;
|
||||||
|
@ -55,10 +56,11 @@ where
|
||||||
|
|
||||||
/// Instantiate wallet Foreign API for a single-use (command line) call
|
/// Instantiate wallet Foreign API for a single-use (command line) call
|
||||||
/// Return a function containing a loaded API context to call
|
/// Return a function containing a loaded API context to call
|
||||||
pub fn foreign_single_use<F, T: ?Sized, K>(wallet: &mut Box<T>, f: F) -> Result<(), Error>
|
pub fn foreign_single_use<F, T: ?Sized, C, K>(wallet: &mut Box<T>, f: F) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<C, K>,
|
||||||
F: FnOnce(&mut APIForeign<T, K>) -> Result<(), Error>,
|
F: FnOnce(&mut APIForeign<T, C, K>) -> Result<(), Error>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
wallet.open_with_credentials()?;
|
wallet.open_with_credentials()?;
|
||||||
|
@ -69,11 +71,12 @@ where
|
||||||
|
|
||||||
/// Listener version, providing same API but listening for requests on a
|
/// Listener version, providing same API but listening for requests on a
|
||||||
/// port and wrapping the calls
|
/// port and wrapping the calls
|
||||||
pub fn owner_listener<T: ?Sized, K>(wallet: Box<T>, addr: &str) -> Result<(), Error>
|
pub fn owner_listener<T: ?Sized, C, K>(wallet: Box<T>, addr: &str) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletInst<K>,
|
T: WalletBackend<C, K>,
|
||||||
OwnerAPIGetHandler<T, K>: Handler,
|
OwnerAPIGetHandler<T, C, K>: Handler,
|
||||||
OwnerAPIPostHandler<T, K>: Handler,
|
OwnerAPIPostHandler<T, C, K>: Handler,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let wallet_arc = Arc::new(Mutex::new(wallet));
|
let wallet_arc = Arc::new(Mutex::new(wallet));
|
||||||
|
@ -101,10 +104,11 @@ where
|
||||||
|
|
||||||
/// Listener version, providing same API but listening for requests on a
|
/// Listener version, providing same API but listening for requests on a
|
||||||
/// port and wrapping the calls
|
/// port and wrapping the calls
|
||||||
pub fn foreign_listener<T: ?Sized, K>(wallet: Box<T>, addr: &str) -> Result<(), Error>
|
pub fn foreign_listener<T: ?Sized, C, K>(wallet: Box<T>, addr: &str) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletInst<K>,
|
T: WalletBackend<C, K>,
|
||||||
ForeignAPIHandler<T, K>: Handler,
|
ForeignAPIHandler<T, C, K>: Handler,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let api_handler = ForeignAPIHandler::new(Arc::new(Mutex::new(wallet)));
|
let api_handler = ForeignAPIHandler::new(Arc::new(Mutex::new(wallet)));
|
||||||
|
@ -126,33 +130,37 @@ where
|
||||||
}
|
}
|
||||||
/// API Handler/Wrapper for owner functions
|
/// API Handler/Wrapper for owner functions
|
||||||
|
|
||||||
pub struct OwnerAPIGetHandler<T: ?Sized, K>
|
pub struct OwnerAPIGetHandler<T: ?Sized, C, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Wallet instance
|
/// Wallet instance
|
||||||
pub wallet: Arc<Mutex<Box<T>>>,
|
pub wallet: Arc<Mutex<Box<T>>>,
|
||||||
phantom: PhantomData<K>,
|
phantom: PhantomData<K>,
|
||||||
|
phantom_c: PhantomData<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized, K> OwnerAPIGetHandler<T, K>
|
impl<T: ?Sized, C, K> OwnerAPIGetHandler<T, C, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Create a new owner API handler for GET methods
|
/// Create a new owner API handler for GET methods
|
||||||
pub fn new(wallet: Arc<Mutex<Box<T>>>) -> OwnerAPIGetHandler<T, K> {
|
pub fn new(wallet: Arc<Mutex<Box<T>>>) -> OwnerAPIGetHandler<T, C, K> {
|
||||||
OwnerAPIGetHandler {
|
OwnerAPIGetHandler {
|
||||||
wallet,
|
wallet,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
|
phantom_c: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retrieve_outputs(
|
fn retrieve_outputs(
|
||||||
&self,
|
&self,
|
||||||
req: &mut Request,
|
req: &mut Request,
|
||||||
api: &mut APIOwner<T, K>,
|
api: &mut APIOwner<T, C, K>,
|
||||||
) -> Result<(bool, Vec<OutputData>), Error> {
|
) -> Result<(bool, Vec<OutputData>), Error> {
|
||||||
let mut update_from_node = false;
|
let mut update_from_node = false;
|
||||||
if let Ok(params) = req.get_ref::<UrlEncodedQuery>() {
|
if let Ok(params) = req.get_ref::<UrlEncodedQuery>() {
|
||||||
|
@ -166,7 +174,7 @@ where
|
||||||
fn retrieve_summary_info(
|
fn retrieve_summary_info(
|
||||||
&self,
|
&self,
|
||||||
req: &mut Request,
|
req: &mut Request,
|
||||||
api: &mut APIOwner<T, K>,
|
api: &mut APIOwner<T, C, K>,
|
||||||
) -> Result<(bool, WalletInfo), Error> {
|
) -> Result<(bool, WalletInfo), Error> {
|
||||||
let mut update_from_node = false;
|
let mut update_from_node = false;
|
||||||
if let Ok(params) = req.get_ref::<UrlEncodedQuery>() {
|
if let Ok(params) = req.get_ref::<UrlEncodedQuery>() {
|
||||||
|
@ -180,12 +188,12 @@ where
|
||||||
fn node_height(
|
fn node_height(
|
||||||
&self,
|
&self,
|
||||||
_req: &mut Request,
|
_req: &mut Request,
|
||||||
api: &mut APIOwner<T, K>,
|
api: &mut APIOwner<T, C, K>,
|
||||||
) -> Result<(u64, bool), Error> {
|
) -> Result<(u64, bool), Error> {
|
||||||
api.node_height()
|
api.node_height()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_request(&self, req: &mut Request, api: &mut APIOwner<T, K>) -> IronResult<Response> {
|
fn handle_request(&self, req: &mut Request, api: &mut APIOwner<T, C, K>) -> IronResult<Response> {
|
||||||
let url = req.url.clone();
|
let url = req.url.clone();
|
||||||
let path_elems = url.path();
|
let path_elems = url.path();
|
||||||
match *path_elems.last().unwrap() {
|
match *path_elems.last().unwrap() {
|
||||||
|
@ -203,9 +211,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized, K> Handler for OwnerAPIGetHandler<T, K>
|
impl<T: ?Sized, C, K> Handler for OwnerAPIGetHandler<T, C, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient + Send + Sync + 'static,
|
T: WalletBackend<C, K> + Send + Sync + 'static,
|
||||||
|
C: WalletClient + 'static,
|
||||||
K: Keychain + 'static,
|
K: Keychain + 'static,
|
||||||
{
|
{
|
||||||
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
||||||
|
@ -235,30 +244,34 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles all owner API POST requests
|
/// Handles all owner API POST requests
|
||||||
pub struct OwnerAPIPostHandler<T: ?Sized, K>
|
pub struct OwnerAPIPostHandler<T: ?Sized, C, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Wallet instance
|
/// Wallet instance
|
||||||
pub wallet: Arc<Mutex<Box<T>>>,
|
pub wallet: Arc<Mutex<Box<T>>>,
|
||||||
phantom: PhantomData<K>,
|
phantom: PhantomData<K>,
|
||||||
|
phantom_c: PhantomData<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized, K> OwnerAPIPostHandler<T, K>
|
impl<T: ?Sized, C, K> OwnerAPIPostHandler<T, C, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// New POST handler
|
/// New POST handler
|
||||||
pub fn new(wallet: Arc<Mutex<Box<T>>>) -> OwnerAPIPostHandler<T, K> {
|
pub fn new(wallet: Arc<Mutex<Box<T>>>) -> OwnerAPIPostHandler<T, C, K> {
|
||||||
OwnerAPIPostHandler {
|
OwnerAPIPostHandler {
|
||||||
wallet,
|
wallet,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
|
phantom_c: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn issue_send_tx(&self, req: &mut Request, api: &mut APIOwner<T, K>) -> Result<(), Error> {
|
fn issue_send_tx(&self, req: &mut Request, api: &mut APIOwner<T, C, K>) -> Result<(), Error> {
|
||||||
let struct_body = req.get::<bodyparser::Struct<SendTXArgs>>();
|
let struct_body = req.get::<bodyparser::Struct<SendTXArgs>>();
|
||||||
match struct_body {
|
match struct_body {
|
||||||
Ok(Some(args)) => api.issue_send_tx(
|
Ok(Some(args)) => api.issue_send_tx(
|
||||||
|
@ -284,12 +297,12 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn issue_burn_tx(&self, _req: &mut Request, api: &mut APIOwner<T, K>) -> Result<(), Error> {
|
fn issue_burn_tx(&self, _req: &mut Request, api: &mut APIOwner<T, C, K>) -> Result<(), Error> {
|
||||||
// TODO: Args
|
// TODO: Args
|
||||||
api.issue_burn_tx(60, 10, 1000)
|
api.issue_burn_tx(60, 10, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_request(&self, req: &mut Request, api: &mut APIOwner<T, K>) -> Result<String, Error> {
|
fn handle_request(&self, req: &mut Request, api: &mut APIOwner<T, C, K>) -> Result<String, Error> {
|
||||||
let url = req.url.clone();
|
let url = req.url.clone();
|
||||||
let path_elems = url.path();
|
let path_elems = url.path();
|
||||||
match *path_elems.last().unwrap() {
|
match *path_elems.last().unwrap() {
|
||||||
|
@ -323,9 +336,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized, K> Handler for OwnerAPIPostHandler<T, K>
|
impl<T: ?Sized, C, K> Handler for OwnerAPIPostHandler<T, C, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient + Send + Sync + 'static,
|
T: WalletBackend<C, K> + Send + Sync + 'static,
|
||||||
|
C: WalletClient + 'static,
|
||||||
K: Keychain + 'static,
|
K: Keychain + 'static,
|
||||||
{
|
{
|
||||||
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
||||||
|
@ -373,33 +387,37 @@ impl Handler for OwnerAPIOptionsHandler where {
|
||||||
}
|
}
|
||||||
/// API Handler/Wrapper for foreign functions
|
/// API Handler/Wrapper for foreign functions
|
||||||
|
|
||||||
pub struct ForeignAPIHandler<T: ?Sized, K>
|
pub struct ForeignAPIHandler<T: ?Sized, C, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Wallet instance
|
/// Wallet instance
|
||||||
pub wallet: Arc<Mutex<Box<T>>>,
|
pub wallet: Arc<Mutex<Box<T>>>,
|
||||||
phantom: PhantomData<K>,
|
phantom: PhantomData<K>,
|
||||||
|
phantom_c: PhantomData<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized, K> ForeignAPIHandler<T, K>
|
impl<T: ?Sized, C, K> ForeignAPIHandler<T, C, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// create a new api handler
|
/// create a new api handler
|
||||||
pub fn new(wallet: Arc<Mutex<Box<T>>>) -> ForeignAPIHandler<T, K> {
|
pub fn new(wallet: Arc<Mutex<Box<T>>>) -> ForeignAPIHandler<T, C, K> {
|
||||||
ForeignAPIHandler {
|
ForeignAPIHandler {
|
||||||
wallet,
|
wallet,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
|
phantom_c: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_coinbase(
|
fn build_coinbase(
|
||||||
&self,
|
&self,
|
||||||
req: &mut Request,
|
req: &mut Request,
|
||||||
api: &mut APIForeign<T, K>,
|
api: &mut APIForeign<T, C, K>,
|
||||||
) -> Result<CbData, Error> {
|
) -> Result<CbData, Error> {
|
||||||
let struct_body = req.get::<bodyparser::Struct<BlockFees>>();
|
let struct_body = req.get::<bodyparser::Struct<BlockFees>>();
|
||||||
match struct_body {
|
match struct_body {
|
||||||
|
@ -419,7 +437,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_tx(&self, req: &mut Request, api: &mut APIForeign<T, K>) -> Result<Slate, Error> {
|
fn receive_tx(&self, req: &mut Request, api: &mut APIForeign<T, C, K>) -> Result<Slate, Error> {
|
||||||
let struct_body = req.get::<bodyparser::Struct<Slate>>();
|
let struct_body = req.get::<bodyparser::Struct<Slate>>();
|
||||||
if let Ok(Some(mut slate)) = struct_body {
|
if let Ok(Some(mut slate)) = struct_body {
|
||||||
api.receive_tx(&mut slate)?;
|
api.receive_tx(&mut slate)?;
|
||||||
|
@ -432,7 +450,7 @@ where
|
||||||
fn handle_request(
|
fn handle_request(
|
||||||
&self,
|
&self,
|
||||||
req: &mut Request,
|
req: &mut Request,
|
||||||
api: &mut APIForeign<T, K>,
|
api: &mut APIForeign<T, C, K>,
|
||||||
) -> IronResult<Response> {
|
) -> IronResult<Response> {
|
||||||
let url = req.url.clone();
|
let url = req.url.clone();
|
||||||
let path_elems = url.path();
|
let path_elems = url.path();
|
||||||
|
@ -448,9 +466,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T: ?Sized, K> Handler for ForeignAPIHandler<T, K>
|
impl<T: ?Sized, C, K> Handler for ForeignAPIHandler<T, C, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient + Send + Sync + 'static,
|
T: WalletBackend<C, K> + Send + Sync + 'static,
|
||||||
|
C: WalletClient + Send + Sync + 'static,
|
||||||
K: Keychain + 'static,
|
K: Keychain + 'static,
|
||||||
{
|
{
|
||||||
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
||||||
|
|
|
@ -72,6 +72,10 @@ pub enum ErrorKind {
|
||||||
#[fail(display = "Transaction error")]
|
#[fail(display = "Transaction error")]
|
||||||
Transaction(transaction::Error),
|
Transaction(transaction::Error),
|
||||||
|
|
||||||
|
/// API Error
|
||||||
|
#[fail(display = "Client Callback Error: {}", _0)]
|
||||||
|
ClientCallback(&'static str),
|
||||||
|
|
||||||
/// Secp Error
|
/// Secp Error
|
||||||
#[fail(display = "Secp error")]
|
#[fail(display = "Secp error")]
|
||||||
Secp,
|
Secp,
|
||||||
|
|
|
@ -15,12 +15,13 @@
|
||||||
//! Wallet key management functions
|
//! Wallet key management functions
|
||||||
use keychain::{Identifier, Keychain};
|
use keychain::{Identifier, Keychain};
|
||||||
use libwallet::error::Error;
|
use libwallet::error::Error;
|
||||||
use libwallet::types::WalletBackend;
|
use libwallet::types::{WalletBackend, WalletClient};
|
||||||
|
|
||||||
/// Get next available key in the wallet
|
/// Get next available key in the wallet
|
||||||
pub fn next_available_key<T: ?Sized, K>(wallet: &mut T) -> Result<(Identifier, u32), Error>
|
pub fn next_available_key<T: ?Sized, C, K>(wallet: &mut T) -> Result<(Identifier, u32), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let root_key_id = wallet.keychain().root_key_id();
|
let root_key_id = wallet.keychain().root_key_id();
|
||||||
|
@ -30,12 +31,13 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve an existing key from a wallet
|
/// Retrieve an existing key from a wallet
|
||||||
pub fn retrieve_existing_key<T: ?Sized, K>(
|
pub fn retrieve_existing_key<T: ?Sized, C, K>(
|
||||||
wallet: &T,
|
wallet: &T,
|
||||||
key_id: Identifier,
|
key_id: Identifier,
|
||||||
) -> Result<(Identifier, u32), Error>
|
) -> Result<(Identifier, u32), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let existing = wallet.get(&key_id)?;
|
let existing = wallet.get(&key_id)?;
|
||||||
|
|
|
@ -41,12 +41,13 @@ struct OutputResult {
|
||||||
pub blinding: SecretKey,
|
pub blinding: SecretKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn identify_utxo_outputs<T, K>(
|
fn identify_utxo_outputs<T, C, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
outputs: Vec<(pedersen::Commitment, pedersen::RangeProof, bool)>,
|
outputs: Vec<(pedersen::Commitment, pedersen::RangeProof, bool)>,
|
||||||
) -> Result<Vec<OutputResult>, Error>
|
) -> Result<Vec<OutputResult>, Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let mut wallet_outputs: Vec<OutputResult> = Vec::new();
|
let mut wallet_outputs: Vec<OutputResult> = Vec::new();
|
||||||
|
@ -56,7 +57,7 @@ where
|
||||||
"Scanning {} outputs in the current Grin utxo set",
|
"Scanning {} outputs in the current Grin utxo set",
|
||||||
outputs.len(),
|
outputs.len(),
|
||||||
);
|
);
|
||||||
let current_chain_height = wallet.get_chain_height()?;
|
let current_chain_height = wallet.client().get_chain_height()?;
|
||||||
|
|
||||||
for output in outputs.iter() {
|
for output in outputs.iter() {
|
||||||
let (commit, proof, is_coinbase) = output;
|
let (commit, proof, is_coinbase) = output;
|
||||||
|
@ -96,13 +97,14 @@ where
|
||||||
|
|
||||||
/// Attempts to populate a list of outputs with their
|
/// Attempts to populate a list of outputs with their
|
||||||
/// correct child indices based on the root key
|
/// correct child indices based on the root key
|
||||||
fn populate_child_indices<T, K>(
|
fn populate_child_indices<T, C, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
outputs: &mut Vec<OutputResult>,
|
outputs: &mut Vec<OutputResult>,
|
||||||
max_derivations: u32,
|
max_derivations: u32,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
info!(
|
info!(
|
||||||
|
@ -146,9 +148,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restore a wallet
|
/// Restore a wallet
|
||||||
pub fn restore<T, K>(wallet: &mut T) -> Result<(), Error>
|
pub fn restore<T, C, K>(wallet: &mut T) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let max_derivations = 1_000_000;
|
let max_derivations = 1_000_000;
|
||||||
|
@ -170,7 +173,7 @@ where
|
||||||
let mut result_vec: Vec<OutputResult> = vec![];
|
let mut result_vec: Vec<OutputResult> = vec![];
|
||||||
loop {
|
loop {
|
||||||
let (highest_index, last_retrieved_index, outputs) =
|
let (highest_index, last_retrieved_index, outputs) =
|
||||||
wallet.get_outputs_by_pmmr_index(start_index, batch_size)?;
|
wallet.client().get_outputs_by_pmmr_index(start_index, batch_size)?;
|
||||||
info!(
|
info!(
|
||||||
LOGGER,
|
LOGGER,
|
||||||
"Retrieved {} outputs, up to index {}. (Highest index: {})",
|
"Retrieved {} outputs, up to index {}. (Highest index: {})",
|
||||||
|
|
|
@ -25,7 +25,7 @@ use libwallet::types::*;
|
||||||
/// and saves the private wallet identifiers of our selected outputs
|
/// and saves the private wallet identifiers of our selected outputs
|
||||||
/// into our transaction context
|
/// into our transaction context
|
||||||
|
|
||||||
pub fn build_send_tx_slate<T: ?Sized, K>(
|
pub fn build_send_tx_slate<T: ?Sized, C, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
num_participants: usize,
|
num_participants: usize,
|
||||||
amount: u64,
|
amount: u64,
|
||||||
|
@ -43,7 +43,8 @@ pub fn build_send_tx_slate<T: ?Sized, K>(
|
||||||
Error,
|
Error,
|
||||||
>
|
>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let (elems, inputs, change, change_derivation, amount, fee) = select_send_tx(
|
let (elems, inputs, change, change_derivation, amount, fee) = select_send_tx(
|
||||||
|
@ -122,7 +123,7 @@ where
|
||||||
/// returning the key of the fresh output and a closure
|
/// returning the key of the fresh output and a closure
|
||||||
/// that actually performs the addition of the output to the
|
/// that actually performs the addition of the output to the
|
||||||
/// wallet
|
/// wallet
|
||||||
pub fn build_recipient_output_with_slate<T: ?Sized, K>(
|
pub fn build_recipient_output_with_slate<T: ?Sized, C, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
slate: &mut Slate,
|
slate: &mut Slate,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
|
@ -134,7 +135,8 @@ pub fn build_recipient_output_with_slate<T: ?Sized, K>(
|
||||||
Error,
|
Error,
|
||||||
>
|
>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
// Create a potential output for this transaction
|
// Create a potential output for this transaction
|
||||||
|
@ -182,7 +184,7 @@ where
|
||||||
/// Builds a transaction to send to someone from the HD seed associated with the
|
/// Builds a transaction to send to someone from the HD seed associated with the
|
||||||
/// wallet and the amount to send. Handles reading through the wallet data file,
|
/// wallet and the amount to send. Handles reading through the wallet data file,
|
||||||
/// selecting outputs to spend and building the change.
|
/// selecting outputs to spend and building the change.
|
||||||
pub fn select_send_tx<T: ?Sized, K>(
|
pub fn select_send_tx<T: ?Sized, C, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
amount: u64,
|
amount: u64,
|
||||||
current_height: u64,
|
current_height: u64,
|
||||||
|
@ -202,7 +204,8 @@ pub fn select_send_tx<T: ?Sized, K>(
|
||||||
Error,
|
Error,
|
||||||
>
|
>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let key_id = wallet.keychain().root_key_id();
|
let key_id = wallet.keychain().root_key_id();
|
||||||
|
@ -287,14 +290,15 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Selects inputs and change for a transaction
|
/// Selects inputs and change for a transaction
|
||||||
pub fn inputs_and_change<T: ?Sized, K>(
|
pub fn inputs_and_change<T: ?Sized, C, K>(
|
||||||
coins: &Vec<OutputData>,
|
coins: &Vec<OutputData>,
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
amount: u64,
|
amount: u64,
|
||||||
fee: u64,
|
fee: u64,
|
||||||
) -> Result<(Vec<Box<build::Append<K>>>, u64, Option<u32>), Error>
|
) -> Result<(Vec<Box<build::Append<K>>>, u64, Option<u32>), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let mut parts = vec![];
|
let mut parts = vec![];
|
||||||
|
|
|
@ -25,9 +25,10 @@ use util::LOGGER;
|
||||||
|
|
||||||
/// Receive a transaction, modifying the slate accordingly (which can then be
|
/// Receive a transaction, modifying the slate accordingly (which can then be
|
||||||
/// sent back to sender for posting)
|
/// sent back to sender for posting)
|
||||||
pub fn receive_tx<T: ?Sized, K>(wallet: &mut T, slate: &mut Slate) -> Result<(), Error>
|
pub fn receive_tx<T: ?Sized, C, K>(wallet: &mut T, slate: &mut Slate) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
// create an output using the amount in the slate
|
// create an output using the amount in the slate
|
||||||
|
@ -53,7 +54,7 @@ where
|
||||||
|
|
||||||
/// Issue a new transaction to the provided sender by spending some of our
|
/// Issue a new transaction to the provided sender by spending some of our
|
||||||
/// wallet
|
/// wallet
|
||||||
pub fn create_send_tx<T: ?Sized, K>(
|
pub fn create_send_tx<T: ?Sized, C, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
amount: u64,
|
amount: u64,
|
||||||
minimum_confirmations: u64,
|
minimum_confirmations: u64,
|
||||||
|
@ -68,11 +69,12 @@ pub fn create_send_tx<T: ?Sized, K>(
|
||||||
Error,
|
Error,
|
||||||
>
|
>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
// Get lock height
|
// Get lock height
|
||||||
let current_height = wallet.get_chain_height()?;
|
let current_height = wallet.client().get_chain_height()?;
|
||||||
// ensure outputs we're selecting are up to date
|
// ensure outputs we're selecting are up to date
|
||||||
updater::refresh_outputs(wallet)?;
|
updater::refresh_outputs(wallet)?;
|
||||||
|
|
||||||
|
@ -110,13 +112,14 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Complete a transaction as the sender
|
/// Complete a transaction as the sender
|
||||||
pub fn complete_tx<T: ?Sized, K>(
|
pub fn complete_tx<T: ?Sized, C, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
slate: &mut Slate,
|
slate: &mut Slate,
|
||||||
context: &sigcontext::Context,
|
context: &sigcontext::Context,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let _ = slate.fill_round_2(wallet.keychain(), &context.sec_key, &context.sec_nonce, 0)?;
|
let _ = slate.fill_round_2(wallet.keychain(), &context.sec_key, &context.sec_nonce, 0)?;
|
||||||
|
@ -129,14 +132,15 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Issue a burn tx
|
/// Issue a burn tx
|
||||||
pub fn issue_burn_tx<T: ?Sized, K>(
|
pub fn issue_burn_tx<T: ?Sized, C, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
amount: u64,
|
amount: u64,
|
||||||
minimum_confirmations: u64,
|
minimum_confirmations: u64,
|
||||||
max_outputs: usize,
|
max_outputs: usize,
|
||||||
) -> Result<Transaction, Error>
|
) -> Result<Transaction, Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -144,7 +148,7 @@ where
|
||||||
// &Identifier::zero());
|
// &Identifier::zero());
|
||||||
let keychain = wallet.keychain().clone();
|
let keychain = wallet.keychain().clone();
|
||||||
|
|
||||||
let current_height = wallet.get_chain_height()?;
|
let current_height = wallet.client().get_chain_height()?;
|
||||||
|
|
||||||
let _ = updater::refresh_outputs(wallet);
|
let _ = updater::refresh_outputs(wallet);
|
||||||
|
|
||||||
|
|
|
@ -33,12 +33,13 @@ use util::secp::pedersen;
|
||||||
use util::{self, LOGGER};
|
use util::{self, LOGGER};
|
||||||
|
|
||||||
/// Retrieve all of the 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, K>(
|
pub fn retrieve_outputs<T: ?Sized, C, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
show_spent: bool,
|
show_spent: bool,
|
||||||
) -> Result<Vec<OutputData>, Error>
|
) -> Result<Vec<OutputData>, Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let root_key_id = wallet.keychain().clone().root_key_id();
|
let root_key_id = wallet.keychain().clone().root_key_id();
|
||||||
|
@ -61,23 +62,25 @@ where
|
||||||
|
|
||||||
/// Refreshes the outputs in a wallet with the latest information
|
/// Refreshes the outputs in a wallet with the latest information
|
||||||
/// from a node
|
/// from a node
|
||||||
pub fn refresh_outputs<T: ?Sized, K>(wallet: &mut T) -> Result<(), Error>
|
pub fn refresh_outputs<T: ?Sized, C, K>(wallet: &mut T) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let height = wallet.get_chain_height()?;
|
let height = wallet.client().get_chain_height()?;
|
||||||
refresh_output_state(wallet, height)?;
|
refresh_output_state(wallet, height)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// build a local map of wallet outputs keyed by commit
|
/// build a local map of wallet outputs keyed by commit
|
||||||
/// and a list of outputs we want to query the node for
|
/// and a list of outputs we want to query the node for
|
||||||
pub fn map_wallet_outputs<T: ?Sized, K>(
|
pub fn map_wallet_outputs<T: ?Sized, C, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
) -> Result<HashMap<pedersen::Commitment, Identifier>, Error>
|
) -> Result<HashMap<pedersen::Commitment, Identifier>, Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let mut wallet_outputs: HashMap<pedersen::Commitment, Identifier> = HashMap::new();
|
let mut wallet_outputs: HashMap<pedersen::Commitment, Identifier> = HashMap::new();
|
||||||
|
@ -94,14 +97,15 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply refreshed API output data to the wallet
|
/// Apply refreshed API output data to the wallet
|
||||||
pub fn apply_api_outputs<T: ?Sized, K>(
|
pub fn apply_api_outputs<T: ?Sized, C, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
wallet_outputs: &HashMap<pedersen::Commitment, Identifier>,
|
wallet_outputs: &HashMap<pedersen::Commitment, Identifier>,
|
||||||
api_outputs: &HashMap<pedersen::Commitment, String>,
|
api_outputs: &HashMap<pedersen::Commitment, String>,
|
||||||
height: u64,
|
height: u64,
|
||||||
) -> Result<(), libwallet::Error>
|
) -> Result<(), libwallet::Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
// now for each commit, find the output in the wallet and the corresponding
|
// now for each commit, find the output in the wallet and the corresponding
|
||||||
|
@ -129,9 +133,10 @@ where
|
||||||
|
|
||||||
/// Builds a single api query to retrieve the latest output data from the node.
|
/// Builds a single api query to retrieve the latest output data from the node.
|
||||||
/// So we can refresh the local wallet outputs.
|
/// So we can refresh the local wallet outputs.
|
||||||
fn refresh_output_state<T: ?Sized, K>(wallet: &mut T, height: u64) -> Result<(), Error>
|
fn refresh_output_state<T: ?Sized, C, K>(wallet: &mut T, height: u64) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
debug!(LOGGER, "Refreshing wallet outputs");
|
debug!(LOGGER, "Refreshing wallet outputs");
|
||||||
|
@ -142,15 +147,16 @@ where
|
||||||
|
|
||||||
let wallet_output_keys = wallet_outputs.keys().map(|commit| commit.clone()).collect();
|
let wallet_output_keys = wallet_outputs.keys().map(|commit| commit.clone()).collect();
|
||||||
|
|
||||||
let api_outputs = wallet.get_outputs_from_node(wallet_output_keys)?;
|
let api_outputs = wallet.client().get_outputs_from_node(wallet_output_keys)?;
|
||||||
apply_api_outputs(wallet, &wallet_outputs, &api_outputs, height)?;
|
apply_api_outputs(wallet, &wallet_outputs, &api_outputs, height)?;
|
||||||
clean_old_unconfirmed(wallet, height)?;
|
clean_old_unconfirmed(wallet, height)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clean_old_unconfirmed<T: ?Sized, K>(wallet: &mut T, height: u64) -> Result<(), Error>
|
fn clean_old_unconfirmed<T: ?Sized, C, K>(wallet: &mut T, height: u64) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
if height < 500 {
|
if height < 500 {
|
||||||
|
@ -172,9 +178,10 @@ where
|
||||||
|
|
||||||
/// Retrieve summary info about the wallet
|
/// Retrieve summary info about the wallet
|
||||||
/// caller should refresh first if desired
|
/// caller should refresh first if desired
|
||||||
pub fn retrieve_info<T: ?Sized, K>(wallet: &mut T) -> Result<WalletInfo, Error>
|
pub fn retrieve_info<T: ?Sized, C, K>(wallet: &mut T) -> Result<WalletInfo, Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let current_height = wallet.details().last_confirmed_height;
|
let current_height = wallet.details().last_confirmed_height;
|
||||||
|
@ -213,9 +220,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a coinbase output and insert into wallet
|
/// Build a coinbase output and insert into wallet
|
||||||
pub fn build_coinbase<T: ?Sized, K>(wallet: &mut T, block_fees: &BlockFees) -> Result<CbData, Error>
|
pub fn build_coinbase<T: ?Sized, C, K>(wallet: &mut T, block_fees: &BlockFees) -> Result<CbData, Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let (out, kern, block_fees) = receive_coinbase(wallet, block_fees).context(ErrorKind::Node)?;
|
let (out, kern, block_fees) = receive_coinbase(wallet, block_fees).context(ErrorKind::Node)?;
|
||||||
|
@ -238,12 +246,13 @@ where
|
||||||
|
|
||||||
//TODO: Split up the output creation and the wallet insertion
|
//TODO: Split up the output creation and the wallet insertion
|
||||||
/// Build a coinbase output and the corresponding kernel
|
/// Build a coinbase output and the corresponding kernel
|
||||||
pub fn receive_coinbase<T: ?Sized, K>(
|
pub fn receive_coinbase<T: ?Sized, C, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
block_fees: &BlockFees,
|
block_fees: &BlockFees,
|
||||||
) -> Result<(Output, TxKernel, BlockFees), Error>
|
) -> Result<(Output, TxKernel, BlockFees), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let root_key_id = wallet.keychain().root_key_id();
|
let root_key_id = wallet.keychain().root_key_id();
|
||||||
|
|
|
@ -34,14 +34,16 @@ use libwallet::error::{Error, ErrorKind};
|
||||||
use util::secp::pedersen;
|
use util::secp::pedersen;
|
||||||
|
|
||||||
/// Combined trait to allow dynamic wallet dispatch
|
/// Combined trait to allow dynamic wallet dispatch
|
||||||
pub trait WalletInst<K>: WalletBackend<K> + WalletClient + Send + Sync + 'static
|
pub trait WalletInst<C, K>: WalletBackend<C, K> + Send + Sync + 'static
|
||||||
where
|
where
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
impl<T, K> WalletInst<K> for T
|
impl<T, C, K> WalletInst<C, K> for T
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient + Send + Sync + 'static,
|
T: WalletBackend<C, K> + Send + Sync + 'static,
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -50,8 +52,9 @@ where
|
||||||
/// Wallets should implement this backend for their storage. All functions
|
/// Wallets should implement this backend for their storage. All functions
|
||||||
/// here expect that the wallet instance has instantiated itself or stored
|
/// here expect that the wallet instance has instantiated itself or stored
|
||||||
/// whatever credentials it needs
|
/// whatever credentials it needs
|
||||||
pub trait WalletBackend<K>
|
pub trait WalletBackend<C, K>
|
||||||
where
|
where
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Initialize with whatever stored credentials we have
|
/// Initialize with whatever stored credentials we have
|
||||||
|
@ -63,6 +66,9 @@ where
|
||||||
/// Return the keychain being used
|
/// Return the keychain being used
|
||||||
fn keychain(&mut self) -> &mut K;
|
fn keychain(&mut self) -> &mut K;
|
||||||
|
|
||||||
|
/// Return the client being used
|
||||||
|
fn client(&mut self) -> &mut C;
|
||||||
|
|
||||||
/// Iterate over all output data stored by the backend
|
/// Iterate over all output data stored by the backend
|
||||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = OutputData> + 'a>;
|
fn iter<'a>(&'a self) -> Box<Iterator<Item = OutputData> + 'a>;
|
||||||
|
|
||||||
|
@ -121,12 +127,12 @@ pub trait WalletOutputBatch {
|
||||||
|
|
||||||
/// Encapsulate all communication functions. No functions within libwallet
|
/// Encapsulate all communication functions. No functions within libwallet
|
||||||
/// should care about communication details
|
/// should care about communication details
|
||||||
pub trait WalletClient {
|
pub trait WalletClient: Sync + Send + Clone {
|
||||||
/// Return the URL of the check node
|
/// Return the URL of the check node
|
||||||
fn node_url(&self) -> &str;
|
fn node_url(&self) -> &str;
|
||||||
|
|
||||||
/// Call the wallet API to create a coinbase transaction
|
/// Call the wallet API to create a coinbase transaction
|
||||||
fn create_coinbase(&self, block_fees: &BlockFees) -> Result<CbData, Error>;
|
fn create_coinbase(&self, dest: &str, block_fees: &BlockFees) -> Result<CbData, Error>;
|
||||||
|
|
||||||
/// Send a transaction slate to another listening wallet and return result
|
/// Send a transaction slate to another listening wallet and return result
|
||||||
/// TODO: Probably need a slate wrapper type
|
/// TODO: Probably need a slate wrapper type
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{fs, path};
|
use std::{fs, path};
|
||||||
|
|
||||||
|
@ -22,12 +21,9 @@ use failure::ResultExt;
|
||||||
use keychain::{Identifier, Keychain};
|
use keychain::{Identifier, Keychain};
|
||||||
use store::{self, option_to_not_found, to_key};
|
use store::{self, option_to_not_found, to_key};
|
||||||
|
|
||||||
use client;
|
|
||||||
use libtx::slate::Slate;
|
|
||||||
use libwallet::types::*;
|
use libwallet::types::*;
|
||||||
use libwallet::{internal, Error, ErrorKind};
|
use libwallet::{internal, Error, ErrorKind};
|
||||||
use types::{WalletConfig, WalletSeed};
|
use types::{WalletConfig, WalletSeed};
|
||||||
use util::secp::pedersen;
|
|
||||||
|
|
||||||
pub const DB_DIR: &'static str = "wallet_data";
|
pub const DB_DIR: &'static str = "wallet_data";
|
||||||
|
|
||||||
|
@ -47,18 +43,19 @@ pub fn wallet_db_exists(config: WalletConfig) -> bool {
|
||||||
db_path.exists()
|
db_path.exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LMDBBackend<K> {
|
pub struct LMDBBackend<C, K> {
|
||||||
db: store::Store,
|
db: store::Store,
|
||||||
config: WalletConfig,
|
config: WalletConfig,
|
||||||
/// passphrase: TODO better ways of dealing with this other than storing
|
/// passphrase: TODO better ways of dealing with this other than storing
|
||||||
passphrase: String,
|
passphrase: String,
|
||||||
|
|
||||||
/// Keychain
|
/// Keychain
|
||||||
keychain: Option<K>,
|
keychain: Option<K>,
|
||||||
|
/// client
|
||||||
|
client: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K> LMDBBackend<K> {
|
impl<C, K> LMDBBackend<C, K> {
|
||||||
pub fn new(config: WalletConfig, passphrase: &str) -> Result<Self, Error> {
|
pub fn new(config: WalletConfig, passphrase: &str, client: C) -> Result<Self, Error> {
|
||||||
let db_path = path::Path::new(&config.data_file_dir).join(DB_DIR);
|
let db_path = path::Path::new(&config.data_file_dir).join(DB_DIR);
|
||||||
fs::create_dir_all(&db_path).expect("Couldn't create wallet backend directory!");
|
fs::create_dir_all(&db_path).expect("Couldn't create wallet backend directory!");
|
||||||
|
|
||||||
|
@ -69,6 +66,7 @@ impl<K> LMDBBackend<K> {
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
passphrase: String::from(passphrase),
|
passphrase: String::from(passphrase),
|
||||||
keychain: None,
|
keychain: None,
|
||||||
|
client: client,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,8 +78,9 @@ impl<K> LMDBBackend<K> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K> WalletBackend<K> for LMDBBackend<K>
|
impl<C, K> WalletBackend<C, K> for LMDBBackend<C, K>
|
||||||
where
|
where
|
||||||
|
C: WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Initialise with whatever stored credentials we have
|
/// Initialise with whatever stored credentials we have
|
||||||
|
@ -106,6 +105,11 @@ where
|
||||||
self.keychain.as_mut().unwrap()
|
self.keychain.as_mut().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the client being used
|
||||||
|
fn client(&mut self) -> &mut C {
|
||||||
|
&mut self.client
|
||||||
|
}
|
||||||
|
|
||||||
fn get(&self, id: &Identifier) -> Result<OutputData, Error> {
|
fn get(&self, id: &Identifier) -> Result<OutputData, Error> {
|
||||||
let key = to_key(OUTPUT_PREFIX, &mut id.to_bytes().to_vec());
|
let key = to_key(OUTPUT_PREFIX, &mut id.to_bytes().to_vec());
|
||||||
option_to_not_found(self.db.get_ser(&key), &format!("Key Id: {}", id)).map_err(|e| e.into())
|
option_to_not_found(self.db.get_ser(&key), &format!("Key Id: {}", id)).map_err(|e| e.into())
|
||||||
|
@ -159,13 +163,21 @@ where
|
||||||
|
|
||||||
/// An atomic batch in which all changes can be committed all at once or
|
/// An atomic batch in which all changes can be committed all at once or
|
||||||
/// discarded on error.
|
/// discarded on error.
|
||||||
pub struct Batch<'a, K: 'a> {
|
pub struct Batch<'a, C: 'a, K: 'a>
|
||||||
store: &'a LMDBBackend<K>,
|
where
|
||||||
|
C: WalletClient,
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
|
store: &'a LMDBBackend<C, K>,
|
||||||
db: RefCell<Option<store::Batch<'a>>>,
|
db: RefCell<Option<store::Batch<'a>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
impl<'a, K> WalletOutputBatch for Batch<'a, K> {
|
impl<'a, C, K> WalletOutputBatch for Batch<'a, C, K>
|
||||||
|
where
|
||||||
|
C: WalletClient,
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
fn save(&mut self, out: OutputData) -> Result<(), Error> {
|
fn save(&mut self, out: OutputData) -> Result<(), Error> {
|
||||||
let key = to_key(OUTPUT_PREFIX, &mut out.key_id.to_bytes().to_vec());
|
let key = to_key(OUTPUT_PREFIX, &mut out.key_id.to_bytes().to_vec());
|
||||||
self.db.borrow().as_ref().unwrap().put_ser(&key, &out)?;
|
self.db.borrow().as_ref().unwrap().put_ser(&key, &out)?;
|
||||||
|
@ -205,65 +217,3 @@ impl<'a, K> WalletOutputBatch for Batch<'a, K> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K> WalletClient for LMDBBackend<K> {
|
|
||||||
/// Return URL for check node
|
|
||||||
fn node_url(&self) -> &str {
|
|
||||||
&self.config.check_node_api_http_addr
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Call the wallet API to create a coinbase transaction
|
|
||||||
fn create_coinbase(&self, block_fees: &BlockFees) -> Result<CbData, Error> {
|
|
||||||
let res = client::create_coinbase(self.node_url(), block_fees)
|
|
||||||
.context(ErrorKind::WalletComms(format!("Creating Coinbase")))?;
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send a transaction slate to another listening wallet and return result
|
|
||||||
fn send_tx_slate(&self, addr: &str, slate: &Slate) -> Result<Slate, Error> {
|
|
||||||
let res = client::send_tx_slate(addr, slate)
|
|
||||||
.context(ErrorKind::WalletComms(format!("Sending transaction")))?;
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Posts a tranaction to a grin node
|
|
||||||
fn post_tx(&self, tx: &TxWrapper, fluff: bool) -> Result<(), Error> {
|
|
||||||
let res = client::post_tx(self.node_url(), tx, fluff).context(ErrorKind::Node)?;
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// retrieves the current tip from the specified grin node
|
|
||||||
fn get_chain_height(&self) -> Result<u64, Error> {
|
|
||||||
let res = client::get_chain_height(self.node_url()).context(ErrorKind::Node)?;
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// retrieve a list of outputs from the specified grin node
|
|
||||||
/// need "by_height" and "by_id" variants
|
|
||||||
fn get_outputs_from_node(
|
|
||||||
&self,
|
|
||||||
wallet_outputs: Vec<pedersen::Commitment>,
|
|
||||||
) -> Result<HashMap<pedersen::Commitment, String>, Error> {
|
|
||||||
let res = client::get_outputs_from_node(self.node_url(), wallet_outputs)
|
|
||||||
.context(ErrorKind::Node)?;
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Outputs by PMMR index
|
|
||||||
fn get_outputs_by_pmmr_index(
|
|
||||||
&self,
|
|
||||||
start_height: u64,
|
|
||||||
max_outputs: u64,
|
|
||||||
) -> Result<
|
|
||||||
(
|
|
||||||
u64,
|
|
||||||
u64,
|
|
||||||
Vec<(pedersen::Commitment, pedersen::RangeProof, bool)>,
|
|
||||||
),
|
|
||||||
Error,
|
|
||||||
> {
|
|
||||||
let res = client::get_outputs_by_pmmr_index(self.node_url(), start_height, max_outputs)
|
|
||||||
.context(ErrorKind::Node)?;
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -28,11 +28,11 @@ use core::core::hash::Hashed;
|
||||||
use core::core::{Output, OutputFeatures, OutputIdentifier, Transaction, TxKernel};
|
use core::core::{Output, OutputFeatures, OutputIdentifier, Transaction, TxKernel};
|
||||||
use core::{consensus, global, pow};
|
use core::{consensus, global, pow};
|
||||||
use keychain::ExtKeychain;
|
use keychain::ExtKeychain;
|
||||||
use wallet::WalletConfig;
|
use wallet::{HTTPWalletClient, WalletConfig};
|
||||||
use wallet::file_wallet::FileWallet;
|
use wallet::file_wallet::FileWallet;
|
||||||
use wallet::libwallet::internal::updater;
|
use wallet::libwallet::internal::updater;
|
||||||
use wallet::libwallet::types::{BlockFees, BlockIdentifier, OutputStatus,
|
use wallet::libwallet::types::{BlockFees, BlockIdentifier, OutputStatus,
|
||||||
WalletBackend};
|
WalletBackend, WalletClient};
|
||||||
use wallet::libwallet::{Error, ErrorKind};
|
use wallet::libwallet::{Error, ErrorKind};
|
||||||
|
|
||||||
use util;
|
use util;
|
||||||
|
@ -40,9 +40,10 @@ use util::secp::pedersen;
|
||||||
|
|
||||||
/// Mostly for testing, refreshes output state against a local chain instance
|
/// Mostly for testing, refreshes output state against a local chain instance
|
||||||
/// instead of via an http API call
|
/// instead of via an http API call
|
||||||
pub fn refresh_output_state_local<T, K>(wallet: &mut T, chain: &chain::Chain) -> Result<(), Error>
|
pub fn refresh_output_state_local<T, C, K>(wallet: &mut T, chain: &chain::Chain) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: keychain::Keychain,
|
K: keychain::Keychain,
|
||||||
{
|
{
|
||||||
let wallet_outputs = updater::map_wallet_outputs(wallet)?;
|
let wallet_outputs = updater::map_wallet_outputs(wallet)?;
|
||||||
|
@ -71,12 +72,13 @@ where
|
||||||
/// (0:total, 1:amount_awaiting_confirmation, 2:confirmed but locked,
|
/// (0:total, 1:amount_awaiting_confirmation, 2:confirmed but locked,
|
||||||
/// 3:currently_spendable, 4:locked total) TODO: Should be a wallet lib
|
/// 3:currently_spendable, 4:locked total) TODO: Should be a wallet lib
|
||||||
/// function with nicer return values
|
/// function with nicer return values
|
||||||
pub fn get_wallet_balances<T, K>(
|
pub fn get_wallet_balances<T, C, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
height: u64,
|
height: u64,
|
||||||
) -> Result<(u64, u64, u64, u64, u64), Error>
|
) -> Result<(u64, u64, u64, u64, u64), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: keychain::Keychain,
|
K: keychain::Keychain,
|
||||||
{
|
{
|
||||||
let mut unspent_total = 0;
|
let mut unspent_total = 0;
|
||||||
|
@ -156,9 +158,10 @@ pub fn add_block_with_reward(chain: &Chain, txs: Vec<&Transaction>, reward: (Out
|
||||||
/// adds a reward output to a wallet, includes that reward in a block, mines
|
/// adds a reward output to a wallet, includes that reward in a block, mines
|
||||||
/// the block and adds it to the chain, with option transactions included.
|
/// the block and adds it to the chain, with option transactions included.
|
||||||
/// Helpful for building up precise wallet balances for testing.
|
/// Helpful for building up precise wallet balances for testing.
|
||||||
pub fn award_block_to_wallet<T, K>(chain: &Chain, txs: Vec<&Transaction>, wallet: &mut T)
|
pub fn award_block_to_wallet<T, C, K>(chain: &Chain, txs: Vec<&Transaction>, wallet: &mut T)
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: keychain::Keychain,
|
K: keychain::Keychain,
|
||||||
{
|
{
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
|
@ -183,9 +186,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// adds many block rewards to a wallet, no transactions
|
/// adds many block rewards to a wallet, no transactions
|
||||||
pub fn award_blocks_to_wallet<T, K>(chain: &Chain, wallet: &mut T, num_rewards: usize)
|
pub fn award_blocks_to_wallet<T, C, K>(chain: &Chain, wallet: &mut T, num_rewards: usize)
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<C, K>,
|
||||||
|
C: WalletClient,
|
||||||
K: keychain::Keychain,
|
K: keychain::Keychain,
|
||||||
{
|
{
|
||||||
for _ in 0..num_rewards {
|
for _ in 0..num_rewards {
|
||||||
|
@ -194,11 +198,11 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new wallet in a particular directory
|
/// Create a new wallet in a particular directory
|
||||||
pub fn create_wallet(dir: &str) -> FileWallet<ExtKeychain> {
|
pub fn create_wallet(dir: &str, client: HTTPWalletClient) -> FileWallet<HTTPWalletClient, ExtKeychain> {
|
||||||
let mut wallet_config = WalletConfig::default();
|
let mut wallet_config = WalletConfig::default();
|
||||||
wallet_config.data_file_dir = String::from(dir);
|
wallet_config.data_file_dir = String::from(dir);
|
||||||
wallet::WalletSeed::init_file(&wallet_config).expect("Failed to create wallet seed file.");
|
wallet::WalletSeed::init_file(&wallet_config).expect("Failed to create wallet seed file.");
|
||||||
let mut wallet = FileWallet::new(wallet_config.clone(), "")
|
let mut wallet = FileWallet::new(wallet_config.clone(), "", client)
|
||||||
.unwrap_or_else(|e| panic!("Error creating wallet: {:?} Config: {:?}", e, wallet_config));
|
.unwrap_or_else(|e| panic!("Error creating wallet: {:?} Config: {:?}", e, wallet_config));
|
||||||
wallet.open_with_credentials().unwrap_or_else(|e| {
|
wallet.open_with_credentials().unwrap_or_else(|e| {
|
||||||
panic!(
|
panic!(
|
||||||
|
|
|
@ -35,6 +35,7 @@ use chain::types::NoopAdapter;
|
||||||
use core::global::ChainTypes;
|
use core::global::ChainTypes;
|
||||||
use core::{global, pow};
|
use core::{global, pow};
|
||||||
use util::LOGGER;
|
use util::LOGGER;
|
||||||
|
use wallet::HTTPWalletClient;
|
||||||
use wallet::libwallet::internal::selection;
|
use wallet::libwallet::internal::selection;
|
||||||
|
|
||||||
fn clean_output_dir(test_dir: &str) {
|
fn clean_output_dir(test_dir: &str) {
|
||||||
|
@ -60,9 +61,10 @@ fn setup(test_dir: &str, chain_dir: &str) -> Chain {
|
||||||
/// Build and test new version of sending API
|
/// Build and test new version of sending API
|
||||||
#[test]
|
#[test]
|
||||||
fn build_transaction() {
|
fn build_transaction() {
|
||||||
|
let client = HTTPWalletClient::new("");
|
||||||
let chain = setup("test_output", "build_transaction_2/.grin");
|
let chain = setup("test_output", "build_transaction_2/.grin");
|
||||||
let mut wallet1 = common::create_wallet("test_output/build_transaction_2/wallet1");
|
let mut wallet1 = common::create_wallet("test_output/build_transaction_2/wallet1", client.clone());
|
||||||
let mut wallet2 = common::create_wallet("test_output/build_transaction_2/wallet2");
|
let mut wallet2 = common::create_wallet("test_output/build_transaction_2/wallet2", client);
|
||||||
common::award_blocks_to_wallet(&chain, &mut wallet1, 10);
|
common::award_blocks_to_wallet(&chain, &mut wallet1, 10);
|
||||||
// Wallet 1 has 600 Grins, wallet 2 has 0. Create a transaction that sends
|
// Wallet 1 has 600 Grins, wallet 2 has 0. Create a transaction that sends
|
||||||
// 300 Grins from wallet 1 to wallet 2, using libtx
|
// 300 Grins from wallet 1 to wallet 2, using libtx
|
||||||
|
|
Loading…
Reference in a new issue