mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 17:01:09 +03:00
[WIP] Updates to support web-wallet (#1160)
* updates to support web wallet workflow * rustfmt * functions to support wallet, error handling * rustfmt * rebase rustfmt * test fix
This commit is contained in:
parent
922b04608f
commit
88616fd341
22 changed files with 260 additions and 89 deletions
|
@ -201,7 +201,7 @@ impl OutputHandler {
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut return_vec = vec![];
|
let mut return_vec = vec![];
|
||||||
for i in start_height..end_height + 1 {
|
for i in (start_height..=end_height).rev() {
|
||||||
let res = self.outputs_at_height(i, commitments.clone(), include_rp);
|
let res = self.outputs_at_height(i, commitments.clone(), include_rp);
|
||||||
if res.outputs.len() > 0 {
|
if res.outputs.len() > 0 {
|
||||||
return_vec.push(res);
|
return_vec.push(res);
|
||||||
|
|
|
@ -20,10 +20,10 @@ use std::fs::File;
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use core::core::Committed;
|
||||||
use core::core::hash::{Hash, Hashed};
|
use core::core::hash::{Hash, Hashed};
|
||||||
use core::core::pmmr::MerkleProof;
|
use core::core::pmmr::MerkleProof;
|
||||||
use core::core::target::Difficulty;
|
use core::core::target::Difficulty;
|
||||||
use core::core::Committed;
|
|
||||||
use core::core::{Block, BlockHeader, Output, OutputIdentifier, Transaction, TxKernel};
|
use core::core::{Block, BlockHeader, Output, OutputIdentifier, Transaction, TxKernel};
|
||||||
use core::global;
|
use core::global;
|
||||||
use grin_store::Error::NotFoundErr;
|
use grin_store::Error::NotFoundErr;
|
||||||
|
@ -31,8 +31,8 @@ use pipe;
|
||||||
use store;
|
use store;
|
||||||
use txhashset;
|
use txhashset;
|
||||||
use types::*;
|
use types::*;
|
||||||
use util::secp::pedersen::{Commitment, RangeProof};
|
|
||||||
use util::LOGGER;
|
use util::LOGGER;
|
||||||
|
use util::secp::pedersen::{Commitment, RangeProof};
|
||||||
|
|
||||||
/// Orphan pool size is limited by MAX_ORPHAN_SIZE
|
/// Orphan pool size is limited by MAX_ORPHAN_SIZE
|
||||||
pub const MAX_ORPHAN_SIZE: usize = 200;
|
pub const MAX_ORPHAN_SIZE: usize = 200;
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
|
|
||||||
//! Transactions
|
//! Transactions
|
||||||
|
|
||||||
use std::cmp::max;
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
use std::cmp::max;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::{error, fmt};
|
use std::{error, fmt};
|
||||||
|
@ -26,12 +26,12 @@ use util::{kernel_sig_msg, static_secp_instance};
|
||||||
|
|
||||||
use consensus;
|
use consensus;
|
||||||
use consensus::VerifySortOrder;
|
use consensus::VerifySortOrder;
|
||||||
|
use core::BlockHeader;
|
||||||
|
use core::Committed;
|
||||||
use core::committed;
|
use core::committed;
|
||||||
use core::global;
|
use core::global;
|
||||||
use core::hash::{Hash, Hashed, ZERO_HASH};
|
use core::hash::{Hash, Hashed, ZERO_HASH};
|
||||||
use core::pmmr::MerkleProof;
|
use core::pmmr::MerkleProof;
|
||||||
use core::BlockHeader;
|
|
||||||
use core::Committed;
|
|
||||||
use keychain;
|
use keychain;
|
||||||
use keychain::BlindingFactor;
|
use keychain::BlindingFactor;
|
||||||
use ser::{self, read_and_verify_sorted, ser_vec, PMMRable, Readable, Reader, Writeable,
|
use ser::{self, read_and_verify_sorted, ser_vec, PMMRable, Readable, Reader, Writeable,
|
||||||
|
|
|
@ -675,7 +675,7 @@ impl NetAdapter for Peers {
|
||||||
|
|
||||||
fn peer_difficulty(&self, addr: SocketAddr, diff: Difficulty, height: u64) {
|
fn peer_difficulty(&self, addr: SocketAddr, diff: Difficulty, height: u64) {
|
||||||
if diff != self.total_difficulty() || height != self.total_height() {
|
if diff != self.total_difficulty() || height != self.total_height() {
|
||||||
debug!(
|
trace!(
|
||||||
LOGGER,
|
LOGGER,
|
||||||
"ping/pong: {}: {} @ {} vs us: {} @ {}",
|
"ping/pong: {}: {} @ {} vs us: {} @ {}",
|
||||||
addr,
|
addr,
|
||||||
|
|
|
@ -29,9 +29,9 @@ use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use core::core::{Block, BlockHeader};
|
use core::core::{Block, BlockHeader};
|
||||||
|
|
||||||
|
use chain::ChainStore;
|
||||||
use chain::txhashset;
|
use chain::txhashset;
|
||||||
use chain::types::Tip;
|
use chain::types::Tip;
|
||||||
use chain::ChainStore;
|
|
||||||
use core::core::target::Difficulty;
|
use core::core::target::Difficulty;
|
||||||
|
|
||||||
use keychain::{ExtKeychain, Keychain};
|
use keychain::{ExtKeychain, Keychain};
|
||||||
|
|
|
@ -35,8 +35,8 @@ use core::core::transaction::Transaction;
|
||||||
use p2p;
|
use p2p;
|
||||||
use pool;
|
use pool;
|
||||||
use store;
|
use store;
|
||||||
use util::OneTime;
|
|
||||||
use util::LOGGER;
|
use util::LOGGER;
|
||||||
|
use util::OneTime;
|
||||||
|
|
||||||
// All adapters use `Weak` references instead of `Arc` to avoid cycles that
|
// All adapters use `Weak` references instead of `Arc` to avoid cycles that
|
||||||
// can never be destroyed. These 2 functions are simple helpers to reduce the
|
// can never be destroyed. These 2 functions are simple helpers to reduce the
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{cmp, thread};
|
use std::{cmp, thread};
|
||||||
use time;
|
use time;
|
||||||
|
@ -457,7 +457,7 @@ mod test {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
get_locator_heights(10000),
|
get_locator_heights(10000),
|
||||||
vec![
|
vec![
|
||||||
10000, 9998, 9994, 9986, 9970, 9938, 9874, 9746, 9490, 8978, 7954, 5906, 1810, 0,
|
10000, 9998, 9994, 9986, 9970, 9938, 9874, 9746, 9490, 8978, 7954, 5906, 1810, 0
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,7 +305,7 @@ impl LocalServerContainer {
|
||||||
let mut wallet = FileWallet::new(config.clone(), "")
|
let mut wallet = FileWallet::new(config.clone(), "")
|
||||||
.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);
|
||||||
wallet::libwallet::internal::updater::retrieve_info(&mut wallet).unwrap()
|
wallet::libwallet::internal::updater::retrieve_info(&mut wallet, true).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_amount_to(
|
pub fn send_amount_to(
|
||||||
|
|
|
@ -681,7 +681,7 @@ fn wallet_command(wallet_args: &ArgMatches, global_config: GlobalConfig) {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
("info", Some(_)) => {
|
("info", Some(_)) => {
|
||||||
let _res = wallet::display::info(&api.retrieve_summary_info()?.1)
|
let _res = wallet::display::info(&api.retrieve_summary_info(true)?)
|
||||||
.unwrap_or_else(|e| {
|
.unwrap_or_else(|e| {
|
||||||
panic!(
|
panic!(
|
||||||
"Error getting wallet info: {:?} Config: {:?}",
|
"Error getting wallet info: {:?} Config: {:?}",
|
||||||
|
@ -692,7 +692,7 @@ fn wallet_command(wallet_args: &ArgMatches, global_config: GlobalConfig) {
|
||||||
}
|
}
|
||||||
("outputs", Some(_)) => {
|
("outputs", Some(_)) => {
|
||||||
let (height, validated) = api.node_height()?;
|
let (height, validated) = api.node_height()?;
|
||||||
let (_, outputs) = api.retrieve_outputs(show_spent)?;
|
let (_, outputs) = api.retrieve_outputs(show_spent, true)?;
|
||||||
let _res =
|
let _res =
|
||||||
wallet::display::outputs(height, validated, outputs).unwrap_or_else(|e| {
|
wallet::display::outputs(height, validated, outputs).unwrap_or_else(|e| {
|
||||||
panic!(
|
panic!(
|
||||||
|
|
|
@ -41,10 +41,8 @@
|
||||||
//! Adapted from https://github.com/behnam/rust-cursive-table-view
|
//! Adapted from https://github.com/behnam/rust-cursive-table-view
|
||||||
//! A basic table view implementation for [cursive](https://crates.io/crates/cursive).
|
//! A basic table view implementation for [cursive](https://crates.io/crates/cursive).
|
||||||
|
|
||||||
#![deny(
|
#![deny(missing_docs, missing_copy_implementations, trivial_casts, trivial_numeric_casts,
|
||||||
missing_docs, missing_copy_implementations, trivial_casts, trivial_numeric_casts, unsafe_code,
|
unsafe_code, unused_import_braces, unused_qualifications)]
|
||||||
unused_import_braces, unused_qualifications
|
|
||||||
)]
|
|
||||||
|
|
||||||
// Crate Dependencies ---------------------------------------------------------
|
// Crate Dependencies ---------------------------------------------------------
|
||||||
extern crate cursive;
|
extern crate cursive;
|
||||||
|
@ -56,6 +54,7 @@ use std::hash::Hash;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
// External Dependencies ------------------------------------------------------
|
// External Dependencies ------------------------------------------------------
|
||||||
|
use cursive::With;
|
||||||
use cursive::align::HAlign;
|
use cursive::align::HAlign;
|
||||||
use cursive::direction::Direction;
|
use cursive::direction::Direction;
|
||||||
use cursive::event::{Callback, Event, EventResult, Key};
|
use cursive::event::{Callback, Event, EventResult, Key};
|
||||||
|
@ -63,7 +62,6 @@ use cursive::theme::ColorStyle;
|
||||||
use cursive::theme::PaletteColor::*;
|
use cursive::theme::PaletteColor::*;
|
||||||
use cursive::vec::Vec2;
|
use cursive::vec::Vec2;
|
||||||
use cursive::view::{ScrollBase, View};
|
use cursive::view::{ScrollBase, View};
|
||||||
use cursive::With;
|
|
||||||
use cursive::{Cursive, Printer};
|
use cursive::{Cursive, Printer};
|
||||||
|
|
||||||
/// A trait for displaying and sorting items inside a
|
/// A trait for displaying and sorting items inside a
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
|
|
||||||
//! Types specific to the UI module
|
//! Types specific to the UI module
|
||||||
|
|
||||||
use cursive::view::View;
|
|
||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
|
use cursive::view::View;
|
||||||
use servers::ServerStats;
|
use servers::ServerStats;
|
||||||
|
|
||||||
/// Main message struct to communicate between the UI and
|
/// Main message struct to communicate between the UI and
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
|
|
||||||
use core::core;
|
use core::core;
|
||||||
use core::core::amount_to_hr_string;
|
use core::core::amount_to_hr_string;
|
||||||
use libwallet::types::{OutputData, WalletInfo};
|
|
||||||
use libwallet::Error;
|
use libwallet::Error;
|
||||||
|
use libwallet::types::{OutputData, WalletInfo};
|
||||||
use prettytable;
|
use prettytable;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use term;
|
use term;
|
||||||
|
|
|
@ -414,15 +414,26 @@ impl<K> WalletClient for FileWallet<K> {
|
||||||
dest: &str,
|
dest: &str,
|
||||||
block_fees: &BlockFees,
|
block_fees: &BlockFees,
|
||||||
) -> Result<CbData, libwallet::Error> {
|
) -> Result<CbData, libwallet::Error> {
|
||||||
let res =
|
let res = client::create_coinbase(dest, block_fees);
|
||||||
client::create_coinbase(dest, block_fees).context(libwallet::ErrorKind::WalletComms)?;
|
match res {
|
||||||
Ok(res)
|
Ok(r) => Ok(r),
|
||||||
|
Err(e) => {
|
||||||
|
let message = format!("{}", e.cause().unwrap());
|
||||||
|
Err(libwallet::ErrorKind::WalletComms(message))?
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a transaction slate to another listening wallet and return result
|
/// Send a transaction slate to another listening wallet and return result
|
||||||
fn send_tx_slate(&self, dest: &str, slate: &Slate) -> Result<Slate, libwallet::Error> {
|
fn send_tx_slate(&self, dest: &str, slate: &Slate) -> Result<Slate, libwallet::Error> {
|
||||||
let res = client::send_tx_slate(dest, slate).context(libwallet::ErrorKind::WalletComms)?;
|
let res = client::send_tx_slate(dest, slate);
|
||||||
Ok(res)
|
match res {
|
||||||
|
Ok(r) => Ok(r),
|
||||||
|
Err(e) => {
|
||||||
|
let message = format!("{}", e.cause().unwrap());
|
||||||
|
Err(libwallet::ErrorKind::WalletComms(message))?
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Posts a tranaction to a grin node
|
/// Posts a tranaction to a grin node
|
||||||
|
|
|
@ -23,8 +23,8 @@ use keychain::{BlindSum, BlindingFactor, Keychain};
|
||||||
use libtx::error::{Error, ErrorKind};
|
use libtx::error::{Error, ErrorKind};
|
||||||
use libtx::{aggsig, build, tx_fee};
|
use libtx::{aggsig, build, tx_fee};
|
||||||
|
|
||||||
use util::secp::key::{PublicKey, SecretKey};
|
|
||||||
use util::secp::Signature;
|
use util::secp::Signature;
|
||||||
|
use util::secp::key::{PublicKey, SecretKey};
|
||||||
use util::{secp, LOGGER};
|
use util::{secp, LOGGER};
|
||||||
|
|
||||||
/// Public data for each participant in the slate
|
/// Public data for each participant in the slate
|
||||||
|
|
|
@ -60,8 +60,12 @@ where
|
||||||
pub fn retrieve_outputs(
|
pub fn retrieve_outputs(
|
||||||
&mut self,
|
&mut self,
|
||||||
include_spent: bool,
|
include_spent: bool,
|
||||||
|
refresh_from_node: bool,
|
||||||
) -> Result<(bool, Vec<OutputData>), Error> {
|
) -> Result<(bool, Vec<OutputData>), Error> {
|
||||||
let validated = self.update_outputs();
|
let mut validated = false;
|
||||||
|
if refresh_from_node {
|
||||||
|
validated = self.update_outputs();
|
||||||
|
}
|
||||||
Ok((
|
Ok((
|
||||||
validated,
|
validated,
|
||||||
updater::retrieve_outputs(self.wallet, include_spent)?,
|
updater::retrieve_outputs(self.wallet, include_spent)?,
|
||||||
|
@ -69,9 +73,12 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve summary info for wallet
|
/// Retrieve summary info for wallet
|
||||||
pub fn retrieve_summary_info(&mut self) -> Result<(bool, WalletInfo), Error> {
|
pub fn retrieve_summary_info(&mut self, refresh_from_node: bool) -> Result<WalletInfo, Error> {
|
||||||
let validated = self.update_outputs();
|
let mut validated = false;
|
||||||
Ok((validated, updater::retrieve_info(self.wallet)?))
|
if refresh_from_node {
|
||||||
|
validated = self.update_outputs();
|
||||||
|
}
|
||||||
|
updater::retrieve_info(self.wallet, validated)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Issues a send transaction and sends to recipient
|
/// Issues a send transaction and sends to recipient
|
||||||
|
@ -139,7 +146,7 @@ where
|
||||||
match self.wallet.get_chain_height(self.wallet.node_url()) {
|
match self.wallet.get_chain_height(self.wallet.node_url()) {
|
||||||
Ok(height) => Ok((height, true)),
|
Ok(height) => Ok((height, true)),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let outputs = self.retrieve_outputs(true)?;
|
let outputs = self.retrieve_outputs(true, false)?;
|
||||||
let height = match outputs.1.iter().map(|out| out.height).max() {
|
let height = match outputs.1.iter().map(|out| out.height).max() {
|
||||||
Some(height) => height,
|
Some(height) => height,
|
||||||
None => 0,
|
None => 0,
|
||||||
|
|
|
@ -21,17 +21,20 @@ use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use bodyparser;
|
use bodyparser;
|
||||||
use iron::Handler;
|
use iron::Handler;
|
||||||
|
use iron::Headers;
|
||||||
use iron::prelude::*;
|
use iron::prelude::*;
|
||||||
use iron::status;
|
use iron::status;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
use urlencoded::UrlEncodedQuery;
|
||||||
|
|
||||||
use failure::Fail;
|
use failure::Fail;
|
||||||
|
|
||||||
use keychain::Keychain;
|
use keychain::Keychain;
|
||||||
use libtx::slate::Slate;
|
use libtx::slate::Slate;
|
||||||
use libwallet::api::{APIForeign, APIOwner};
|
use libwallet::api::{APIForeign, APIOwner};
|
||||||
use libwallet::types::{BlockFees, CbData, OutputData, WalletBackend, WalletClient, WalletInfo};
|
use libwallet::types::{BlockFees, CbData, OutputData, SendTXArgs, WalletBackend, WalletClient,
|
||||||
|
WalletInfo};
|
||||||
use libwallet::{Error, ErrorKind};
|
use libwallet::{Error, ErrorKind};
|
||||||
|
|
||||||
use util::LOGGER;
|
use util::LOGGER;
|
||||||
|
@ -69,13 +72,19 @@ where
|
||||||
pub fn owner_listener<T, K>(wallet: T, addr: &str) -> Result<(), Error>
|
pub fn owner_listener<T, K>(wallet: T, addr: &str) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<K> + WalletClient,
|
||||||
OwnerAPIHandler<T, K>: Handler,
|
OwnerAPIGetHandler<T, K>: Handler,
|
||||||
|
OwnerAPIPostHandler<T, K>: Handler,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let api_handler = OwnerAPIHandler::new(Arc::new(Mutex::new(wallet)));
|
let wallet_arc = Arc::new(Mutex::new(wallet));
|
||||||
|
let api_get_handler = OwnerAPIGetHandler::new(wallet_arc.clone());
|
||||||
|
let api_post_handler = OwnerAPIPostHandler::new(wallet_arc);
|
||||||
|
let api_options_handler = OwnerAPIOptionsHandler {};
|
||||||
|
|
||||||
let router = router!(
|
let router = router!(
|
||||||
receive_tx: get "/wallet/owner/*" => api_handler,
|
owner_options: options "/wallet/owner/*" => api_options_handler,
|
||||||
|
owner_get: get "/wallet/owner/*" => api_get_handler,
|
||||||
|
owner_post: post "/wallet/owner/*" => api_post_handler,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut apis = ApiServer::new("/v1".to_string());
|
let mut apis = ApiServer::new("/v1".to_string());
|
||||||
|
@ -117,7 +126,7 @@ where
|
||||||
}
|
}
|
||||||
/// API Handler/Wrapper for owner functions
|
/// API Handler/Wrapper for owner functions
|
||||||
|
|
||||||
pub struct OwnerAPIHandler<T, K>
|
pub struct OwnerAPIGetHandler<T, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K>,
|
T: WalletBackend<K>,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
@ -127,13 +136,13 @@ where
|
||||||
phantom: PhantomData<K>,
|
phantom: PhantomData<K>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, K> OwnerAPIHandler<T, K>
|
impl<T, K> OwnerAPIGetHandler<T, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<K> + WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
pub fn new(wallet: Arc<Mutex<T>>) -> OwnerAPIHandler<T, K> {
|
pub fn new(wallet: Arc<Mutex<T>>) -> OwnerAPIGetHandler<T, K> {
|
||||||
OwnerAPIHandler {
|
OwnerAPIGetHandler {
|
||||||
wallet,
|
wallet,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
|
@ -143,9 +152,14 @@ where
|
||||||
&self,
|
&self,
|
||||||
req: &mut Request,
|
req: &mut Request,
|
||||||
api: &mut APIOwner<T, K>,
|
api: &mut APIOwner<T, K>,
|
||||||
) -> Result<Vec<OutputData>, Error> {
|
) -> Result<(bool, Vec<OutputData>), Error> {
|
||||||
let res = api.retrieve_outputs(false)?;
|
let mut update_from_node = false;
|
||||||
Ok(res.1)
|
if let Ok(params) = req.get_ref::<UrlEncodedQuery>() {
|
||||||
|
if let Some(_) = params.get("refresh") {
|
||||||
|
update_from_node = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
api.retrieve_outputs(false, update_from_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retrieve_summary_info(
|
fn retrieve_summary_info(
|
||||||
|
@ -153,31 +167,32 @@ where
|
||||||
req: &mut Request,
|
req: &mut Request,
|
||||||
api: &mut APIOwner<T, K>,
|
api: &mut APIOwner<T, K>,
|
||||||
) -> Result<WalletInfo, Error> {
|
) -> Result<WalletInfo, Error> {
|
||||||
let res = api.retrieve_summary_info()?;
|
let mut update_from_node = false;
|
||||||
Ok(res.1)
|
if let Ok(params) = req.get_ref::<UrlEncodedQuery>() {
|
||||||
|
if let Some(_) = params.get("refresh") {
|
||||||
|
update_from_node = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
api.retrieve_summary_info(update_from_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn issue_send_tx(&self, req: &mut Request, api: &mut APIOwner<T, K>) -> Result<(), Error> {
|
fn node_height(
|
||||||
// TODO: Args
|
&self,
|
||||||
api.issue_send_tx(60, 10, "", 1000, true, true)
|
req: &mut Request,
|
||||||
}
|
api: &mut APIOwner<T, K>,
|
||||||
|
) -> Result<(u64, bool), Error> {
|
||||||
fn issue_burn_tx(&self, req: &mut Request, api: &mut APIOwner<T, K>) -> Result<(), Error> {
|
api.node_height()
|
||||||
// TODO: Args
|
|
||||||
api.issue_burn_tx(60, 10, 1000)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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, 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() {
|
||||||
"retrieve_outputs" => json_response_pretty(&self.retrieve_outputs(req, api)
|
"retrieve_outputs" => json_response(&self.retrieve_outputs(req, api)
|
||||||
.map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?),
|
.map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?),
|
||||||
"retrieve_summary_info" => json_response_pretty(&self.retrieve_summary_info(req, api)
|
"retrieve_summary_info" => json_response(&self.retrieve_summary_info(req, api)
|
||||||
.map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?),
|
.map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?),
|
||||||
"issue_send_tx" => json_response_pretty(&self.issue_send_tx(req, api)
|
"node_height" => json_response(&self.node_height(req, api)
|
||||||
.map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?),
|
|
||||||
"issue_burn_tx" => json_response_pretty(&self.issue_burn_tx(req, api)
|
|
||||||
.map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?),
|
.map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?),
|
||||||
_ => Err(IronError::new(
|
_ => Err(IronError::new(
|
||||||
Fail::compat(ErrorKind::Hyper),
|
Fail::compat(ErrorKind::Hyper),
|
||||||
|
@ -187,7 +202,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, K> Handler for OwnerAPIHandler<T, K>
|
impl<T, K> Handler for OwnerAPIGetHandler<T, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient + Send + Sync + 'static,
|
T: WalletBackend<K> + WalletClient + Send + Sync + 'static,
|
||||||
K: Keychain + 'static,
|
K: Keychain + 'static,
|
||||||
|
@ -203,11 +218,13 @@ where
|
||||||
})?;
|
})?;
|
||||||
let mut api = APIOwner::new(&mut *wallet);
|
let mut api = APIOwner::new(&mut *wallet);
|
||||||
let mut resp_json = self.handle_request(req, &mut api);
|
let mut resp_json = self.handle_request(req, &mut api);
|
||||||
resp_json
|
if !resp_json.is_err() {
|
||||||
.as_mut()
|
resp_json
|
||||||
.unwrap()
|
.as_mut()
|
||||||
.headers
|
.unwrap()
|
||||||
.set_raw("access-control-allow-origin", vec![b"*".to_vec()]);
|
.headers
|
||||||
|
.set_raw("access-control-allow-origin", vec![b"*".to_vec()]);
|
||||||
|
}
|
||||||
api.wallet
|
api.wallet
|
||||||
.close()
|
.close()
|
||||||
.map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?;
|
.map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?;
|
||||||
|
@ -215,6 +232,138 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct OwnerAPIPostHandler<T, K>
|
||||||
|
where
|
||||||
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
|
/// Wallet instance
|
||||||
|
pub wallet: Arc<Mutex<T>>,
|
||||||
|
phantom: PhantomData<K>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, K> OwnerAPIPostHandler<T, K>
|
||||||
|
where
|
||||||
|
T: WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
|
pub fn new(wallet: Arc<Mutex<T>>) -> OwnerAPIPostHandler<T, K> {
|
||||||
|
OwnerAPIPostHandler {
|
||||||
|
wallet,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn issue_send_tx(&self, req: &mut Request, api: &mut APIOwner<T, K>) -> Result<(), Error> {
|
||||||
|
let struct_body = req.get::<bodyparser::Struct<SendTXArgs>>();
|
||||||
|
match struct_body {
|
||||||
|
Ok(Some(args)) => api.issue_send_tx(
|
||||||
|
args.amount,
|
||||||
|
args.minimum_confirmations,
|
||||||
|
&args.dest,
|
||||||
|
args.max_outputs,
|
||||||
|
args.selection_strategy_is_use_all,
|
||||||
|
args.fluff,
|
||||||
|
),
|
||||||
|
Ok(None) => {
|
||||||
|
error!(LOGGER, "Missing request body: issue_send_tx");
|
||||||
|
Err(ErrorKind::GenericError(
|
||||||
|
"Invalid request body: issue_send_tx",
|
||||||
|
))?
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!(LOGGER, "Invalid request body: issue_send_tx {:?}", e);
|
||||||
|
Err(ErrorKind::GenericError(
|
||||||
|
"Invalid request body: issue_send_tx",
|
||||||
|
))?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn issue_burn_tx(&self, req: &mut Request, api: &mut APIOwner<T, K>) -> Result<(), Error> {
|
||||||
|
// TODO: Args
|
||||||
|
api.issue_burn_tx(60, 10, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_request(&self, req: &mut Request, api: &mut APIOwner<T, K>) -> Result<String, Error> {
|
||||||
|
let url = req.url.clone();
|
||||||
|
let path_elems = url.path();
|
||||||
|
match *path_elems.last().unwrap() {
|
||||||
|
"issue_send_tx" => json_response_pretty(&self.issue_send_tx(req, api)?),
|
||||||
|
"issue_burn_tx" => json_response_pretty(&self.issue_burn_tx(req, api)?),
|
||||||
|
_ => Err(ErrorKind::GenericError(
|
||||||
|
"Unknown error handling post request",
|
||||||
|
))?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_error_response(&self, e: Error) -> IronResult<Response> {
|
||||||
|
let mut headers = Headers::new();
|
||||||
|
headers.set_raw("access-control-allow-origin", vec![b"*".to_vec()]);
|
||||||
|
headers.set_raw(
|
||||||
|
"access-control-allow-headers",
|
||||||
|
vec![b"Content-Type".to_vec()],
|
||||||
|
);
|
||||||
|
let message = format!("{}", e.kind());
|
||||||
|
let mut r = Response::with((status::InternalServerError, message));
|
||||||
|
r.headers = headers;
|
||||||
|
Ok(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_ok_response(&self, json: &str) -> IronResult<Response> {
|
||||||
|
let mut headers = Headers::new();
|
||||||
|
headers.set_raw("access-control-allow-origin", vec![b"*".to_vec()]);
|
||||||
|
let mut r = Response::with((status::Ok, json));
|
||||||
|
r.headers = headers;
|
||||||
|
Ok(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, K> Handler for OwnerAPIPostHandler<T, K>
|
||||||
|
where
|
||||||
|
T: WalletBackend<K> + WalletClient + Send + Sync + 'static,
|
||||||
|
K: Keychain + 'static,
|
||||||
|
{
|
||||||
|
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
||||||
|
// every request should open with stored credentials,
|
||||||
|
// do its thing and then de-init whatever secrets have been
|
||||||
|
// stored
|
||||||
|
let mut wallet = self.wallet.lock().unwrap();
|
||||||
|
wallet.open_with_credentials().map_err(|e| {
|
||||||
|
error!(LOGGER, "Error opening wallet: {:?}", e);
|
||||||
|
IronError::new(Fail::compat(e), status::BadRequest)
|
||||||
|
})?;
|
||||||
|
let mut api = APIOwner::new(&mut *wallet);
|
||||||
|
let resp = match self.handle_request(req, &mut api) {
|
||||||
|
Ok(r) => self.create_ok_response(&r),
|
||||||
|
Err(e) => {
|
||||||
|
error!(LOGGER, "Request Error: {:?}", e);
|
||||||
|
self.create_error_response(e)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
api.wallet
|
||||||
|
.close()
|
||||||
|
.map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?;
|
||||||
|
resp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Options handler
|
||||||
|
pub struct OwnerAPIOptionsHandler {}
|
||||||
|
|
||||||
|
impl Handler for OwnerAPIOptionsHandler where {
|
||||||
|
fn handle(&self, _req: &mut Request) -> IronResult<Response> {
|
||||||
|
let mut resp_json = Ok(Response::with((status::Ok, "{}")));
|
||||||
|
let mut headers = Headers::new();
|
||||||
|
headers.set_raw("access-control-allow-origin", vec![b"*".to_vec()]);
|
||||||
|
headers.set_raw(
|
||||||
|
"access-control-allow-headers",
|
||||||
|
vec![b"Content-Type".to_vec()],
|
||||||
|
);
|
||||||
|
resp_json.as_mut().unwrap().headers = headers;
|
||||||
|
resp_json
|
||||||
|
}
|
||||||
|
}
|
||||||
/// API Handler/Wrapper for foreign functions
|
/// API Handler/Wrapper for foreign functions
|
||||||
|
|
||||||
pub struct ForeignAPIHandler<T, K>
|
pub struct ForeignAPIHandler<T, K>
|
||||||
|
@ -291,7 +440,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, K> Handler for ForeignAPIHandler<T, K>
|
impl<T, K> Handler for ForeignAPIHandler<T, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient + Send + Sync + 'static,
|
T: WalletBackend<K> + WalletClient + Send + Sync + 'static,
|
||||||
|
@ -328,12 +476,12 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// pretty-printed version of above
|
// pretty-printed version of above
|
||||||
fn json_response_pretty<T>(s: &T) -> IronResult<Response>
|
fn json_response_pretty<T>(s: &T) -> Result<String, Error>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
{
|
{
|
||||||
match serde_json::to_string_pretty(s) {
|
match serde_json::to_string_pretty(s) {
|
||||||
Ok(json) => Ok(Response::with((status::Ok, json))),
|
Ok(json) => Ok(json),
|
||||||
Err(_) => Ok(Response::with((status::InternalServerError, ""))),
|
Err(_) => Err(ErrorKind::Format)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,8 +94,8 @@ pub enum ErrorKind {
|
||||||
Node,
|
Node,
|
||||||
|
|
||||||
/// Error contacting wallet API
|
/// Error contacting wallet API
|
||||||
#[fail(display = "Wallet communication error")]
|
#[fail(display = "Wallet Communication Error: {}", _0)]
|
||||||
WalletComms,
|
WalletComms(String),
|
||||||
|
|
||||||
/// Error originating from hyper.
|
/// Error originating from hyper.
|
||||||
#[fail(display = "Hyper error")]
|
#[fail(display = "Hyper error")]
|
||||||
|
|
|
@ -24,8 +24,8 @@ use keychain::{Identifier, Keychain};
|
||||||
use libtx::proof;
|
use libtx::proof;
|
||||||
use libwallet::types::*;
|
use libwallet::types::*;
|
||||||
use util;
|
use util;
|
||||||
use util::secp::pedersen;
|
|
||||||
use util::LOGGER;
|
use util::LOGGER;
|
||||||
|
use util::secp::pedersen;
|
||||||
|
|
||||||
fn get_merkle_proof_for_commit(node_addr: &str, commit: &str) -> Result<MerkleProofWrapper, Error> {
|
fn get_merkle_proof_for_commit(node_addr: &str, commit: &str) -> Result<MerkleProofWrapper, Error> {
|
||||||
let url = format!("{}/v1/txhashset/merkleproof?id={}", node_addr, commit);
|
let url = format!("{}/v1/txhashset/merkleproof?id={}", node_addr, commit);
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
//! Selection of inputs for building transactions
|
//! Selection of inputs for building transactions
|
||||||
|
|
||||||
use keychain::{Identifier, Keychain};
|
use keychain::{Identifier, Keychain};
|
||||||
use libtx::{build, slate::Slate, tx_fee};
|
use libtx::{build, tx_fee, slate::Slate};
|
||||||
use libwallet::error::{Error, ErrorKind};
|
use libwallet::error::{Error, ErrorKind};
|
||||||
use libwallet::internal::{keys, sigcontext};
|
use libwallet::internal::{keys, sigcontext};
|
||||||
use libwallet::types::*;
|
use libwallet::types::*;
|
||||||
|
@ -93,12 +93,7 @@ where
|
||||||
let coin = wallet_data.get_output(&id).unwrap().clone();
|
let coin = wallet_data.get_output(&id).unwrap().clone();
|
||||||
wallet_data.lock_output(&coin);
|
wallet_data.lock_output(&coin);
|
||||||
}
|
}
|
||||||
// probably just want to leave as unconfirmed for now
|
})
|
||||||
// or create a new status
|
|
||||||
/*for id in lock_outputs {
|
|
||||||
let coin = wallet_data.get_output(&id).unwrap().clone();
|
|
||||||
wallet_data.lock_output(&coin);
|
|
||||||
}*/ })
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((slate, context, update_sender_wallet_fn))
|
Ok((slate, context, update_sender_wallet_fn))
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
//! the wallet storage and update them.
|
//! the wallet storage and update them.
|
||||||
|
|
||||||
use failure::ResultExt;
|
use failure::ResultExt;
|
||||||
use std::collections::hash_map::Entry;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::collections::hash_map::Entry;
|
||||||
|
|
||||||
use core::consensus::reward;
|
use core::consensus::reward;
|
||||||
use core::core::{Output, TxKernel};
|
use core::core::{Output, TxKernel};
|
||||||
|
@ -29,8 +29,8 @@ use libwallet::error::{Error, ErrorKind};
|
||||||
use libwallet::internal::keys;
|
use libwallet::internal::keys;
|
||||||
use libwallet::types::*;
|
use libwallet::types::*;
|
||||||
use util;
|
use util;
|
||||||
use util::secp::pedersen;
|
|
||||||
use util::LOGGER;
|
use util::LOGGER;
|
||||||
|
use util::secp::pedersen;
|
||||||
|
|
||||||
/// 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, K>(wallet: &mut T, show_spent: bool) -> Result<Vec<OutputData>, Error>
|
pub fn retrieve_outputs<T, K>(wallet: &mut T, show_spent: bool) -> Result<Vec<OutputData>, Error>
|
||||||
|
@ -241,13 +241,12 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve summary info about the wallet
|
/// Retrieve summary info about the wallet
|
||||||
pub fn retrieve_info<T, K>(wallet: &mut T) -> Result<WalletInfo, Error>
|
/// caller should refresh first if desired
|
||||||
|
pub fn retrieve_info<T, K>(wallet: &mut T, refreshed: bool) -> Result<WalletInfo, Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<K> + WalletClient,
|
T: WalletBackend<K> + WalletClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let result = refresh_outputs(wallet);
|
|
||||||
|
|
||||||
let height_res = wallet.get_chain_height(&wallet.node_url());
|
let height_res = wallet.get_chain_height(&wallet.node_url());
|
||||||
|
|
||||||
let ret_val = wallet.read_wallet(|wallet_data| {
|
let ret_val = wallet.read_wallet(|wallet_data| {
|
||||||
|
@ -282,10 +281,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut data_confirmed = true;
|
|
||||||
if let Err(_) = result {
|
|
||||||
data_confirmed = false;
|
|
||||||
}
|
|
||||||
Ok(WalletInfo {
|
Ok(WalletInfo {
|
||||||
current_height: current_height,
|
current_height: current_height,
|
||||||
total: unspent_total + unconfirmed_total,
|
total: unspent_total + unconfirmed_total,
|
||||||
|
@ -293,7 +288,7 @@ where
|
||||||
amount_confirmed_but_locked: unspent_but_locked_total,
|
amount_confirmed_but_locked: unspent_but_locked_total,
|
||||||
amount_currently_spendable: unspent_total - unspent_but_locked_total,
|
amount_currently_spendable: unspent_total - unspent_but_locked_total,
|
||||||
amount_locked: locked_total,
|
amount_locked: locked_total,
|
||||||
data_confirmed: data_confirmed,
|
data_confirmed: refreshed,
|
||||||
data_confirmed_from: String::from(from),
|
data_confirmed_from: String::from(from),
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -423,3 +423,20 @@ pub struct TxWrapper {
|
||||||
/// hex representation of transaction
|
/// hex representation of transaction
|
||||||
pub tx_hex: String,
|
pub tx_hex: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send TX API Args
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct SendTXArgs {
|
||||||
|
/// amount to send
|
||||||
|
pub amount: u64,
|
||||||
|
/// minimum confirmations
|
||||||
|
pub minimum_confirmations: u64,
|
||||||
|
/// destination url
|
||||||
|
pub dest: String,
|
||||||
|
/// Max number of outputs
|
||||||
|
pub max_outputs: usize,
|
||||||
|
/// whether to use all outputs (combine)
|
||||||
|
pub selection_strategy_is_use_all: bool,
|
||||||
|
/// dandelion control
|
||||||
|
pub fluff: bool,
|
||||||
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@ mod common;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use chain::types::*;
|
|
||||||
use chain::Chain;
|
use chain::Chain;
|
||||||
|
use chain::types::*;
|
||||||
use core::global::ChainTypes;
|
use core::global::ChainTypes;
|
||||||
use core::{global, pow};
|
use core::{global, pow};
|
||||||
use util::LOGGER;
|
use util::LOGGER;
|
||||||
|
|
Loading…
Reference in a new issue