Wallet API Test Client (#1242)
* beginnings to testclient implementation for more complete wallet API testing * rework TestWalletClient to be message-based proxy * test fix * wallet tests now exercising the API directly as much as possible, capable of instantiating multiple wallets * test in place to run both file and db wallets * ensure all wallet api functions lock wallet as needed. Split up transaction creation from posting to chain
This commit is contained in:
+42
-25
@@ -28,8 +28,8 @@ use tokio_core::reactor;
|
||||
|
||||
use api;
|
||||
use error::{Error, ErrorKind};
|
||||
use libwallet;
|
||||
use libtx::slate::Slate;
|
||||
use libwallet;
|
||||
use util::secp::pedersen;
|
||||
use util::{self, LOGGER};
|
||||
|
||||
@@ -40,7 +40,7 @@ pub struct HTTPWalletClient {
|
||||
|
||||
impl HTTPWalletClient {
|
||||
/// Create a new client that will communicate with the given grin node
|
||||
pub fn new(node_url:&str) -> HTTPWalletClient {
|
||||
pub fn new(node_url: &str) -> HTTPWalletClient {
|
||||
HTTPWalletClient {
|
||||
node_url: node_url.to_owned(),
|
||||
}
|
||||
@@ -52,9 +52,14 @@ impl WalletClient for HTTPWalletClient {
|
||||
&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> {
|
||||
/// 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) => {
|
||||
@@ -64,7 +69,9 @@ impl WalletClient for HTTPWalletClient {
|
||||
);
|
||||
error!(LOGGER, "Underlying Error: {}", e.cause().unwrap());
|
||||
error!(LOGGER, "Backtrace: {}", e.backtrace().unwrap());
|
||||
Err(libwallet::ErrorKind::ClientCallback("Failed to get coinbase"))?
|
||||
Err(libwallet::ErrorKind::ClientCallback(
|
||||
"Failed to get coinbase",
|
||||
))?
|
||||
}
|
||||
Ok(res) => Ok(res),
|
||||
}
|
||||
@@ -83,35 +90,41 @@ impl WalletClient for HTTPWalletClient {
|
||||
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 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"))?
|
||||
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"))?;
|
||||
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))?;
|
||||
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"))?;
|
||||
.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;
|
||||
@@ -121,8 +134,9 @@ impl WalletClient for HTTPWalletClient {
|
||||
} else {
|
||||
url = format!("{}/v1/pool/push", dest);
|
||||
}
|
||||
api::client::post(url.as_str(), tx)
|
||||
.context(libwallet::ErrorKind::ClientCallback("Posting transaction to node"))?;
|
||||
api::client::post(url.as_str(), tx).context(libwallet::ErrorKind::ClientCallback(
|
||||
"Posting transaction to node",
|
||||
))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -130,8 +144,9 @@ impl WalletClient for HTTPWalletClient {
|
||||
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"))?;
|
||||
let res = api::client::get::<api::Tip>(url.as_str()).context(
|
||||
libwallet::ErrorKind::ClientCallback("Getting chain height from node"),
|
||||
)?;
|
||||
Ok(res.height)
|
||||
}
|
||||
|
||||
@@ -205,7 +220,9 @@ impl WalletClient for HTTPWalletClient {
|
||||
LOGGER,
|
||||
"get_outputs_by_pmmr_index: unable to contact API {}. Error: {}", addr, e
|
||||
);
|
||||
Err(libwallet::ErrorKind::ClientCallback("unable to contact api"))?
|
||||
Err(libwallet::ErrorKind::ClientCallback(
|
||||
"unable to contact api",
|
||||
))?
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,8 +247,9 @@ pub fn create_coinbase(dest: &str, block_fees: &BlockFees) -> Result<CbData, Err
|
||||
|
||||
/// 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> {
|
||||
let mut core =
|
||||
reactor::Core::new().context(ErrorKind::GenericError("Could not create reactor"))?;
|
||||
let mut core = reactor::Core::new().context(ErrorKind::GenericError(
|
||||
"Could not create reactor".to_owned(),
|
||||
))?;
|
||||
let client = hyper::Client::new(&core.handle());
|
||||
|
||||
let mut req = Request::new(
|
||||
@@ -253,7 +271,6 @@ fn single_create_coinbase(url: &str, block_fees: &BlockFees) -> Result<CbData, E
|
||||
});
|
||||
|
||||
let res = core.run(work)
|
||||
.context(ErrorKind::GenericError("Could not run core"))?;
|
||||
.context(ErrorKind::GenericError("Could not run core".to_owned()))?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ pub enum ErrorKind {
|
||||
|
||||
/// Other
|
||||
#[fail(display = "Generic error: {}", _0)]
|
||||
GenericError(&'static str),
|
||||
GenericError(String),
|
||||
}
|
||||
|
||||
impl Fail for Error {
|
||||
|
||||
@@ -177,13 +177,12 @@ where
|
||||
self.keychain = Some(keychain.context(libwallet::ErrorKind::CallbackImpl(
|
||||
"Error deriving keychain",
|
||||
))?);
|
||||
// Just blow up password for now after it's been used
|
||||
self.passphrase = String::from("");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Close wallet and remove any stored credentials (TBD)
|
||||
fn close(&mut self) -> Result<(), libwallet::Error> {
|
||||
debug!(LOGGER, "Closing wallet keychain");
|
||||
self.keychain = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+101
-51
@@ -18,6 +18,7 @@
|
||||
//! Still experimental, not sure this is the best way to do this
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use core::ser;
|
||||
use keychain::Keychain;
|
||||
@@ -31,27 +32,27 @@ use util::{self, LOGGER};
|
||||
|
||||
/// Wrapper around internal API functions, containing a reference to
|
||||
/// the wallet/keychain that they're acting upon
|
||||
pub struct APIOwner<'a, W: ?Sized, C, K>
|
||||
pub struct APIOwner<W: ?Sized, C, K>
|
||||
where
|
||||
W: 'a + WalletBackend<C, K>,
|
||||
W: WalletBackend<C, K>,
|
||||
C: WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
/// Wallet, contains its keychain (TODO: Split these up into 2 traits
|
||||
/// perhaps)
|
||||
pub wallet: &'a mut Box<W>,
|
||||
pub wallet: Arc<Mutex<Box<W>>>,
|
||||
phantom: PhantomData<K>,
|
||||
phantom_c: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<'a, W: ?Sized, C, K> APIOwner<'a, W, C, K>
|
||||
impl<W: ?Sized, C, K> APIOwner<W, C, K>
|
||||
where
|
||||
W: 'a + WalletBackend<C, K>,
|
||||
W: WalletBackend<C, K>,
|
||||
C: WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
/// Create new API instance
|
||||
pub fn new(wallet_in: &'a mut Box<W>) -> APIOwner<'a, W, C, K> {
|
||||
pub fn new(wallet_in: Arc<Mutex<Box<W>>>) -> Self {
|
||||
APIOwner {
|
||||
wallet: wallet_in,
|
||||
phantom: PhantomData,
|
||||
@@ -62,18 +63,26 @@ where
|
||||
/// Attempt to update and retrieve outputs
|
||||
/// Return (whether the outputs were validated against a node, OutputData)
|
||||
pub fn retrieve_outputs(
|
||||
&mut self,
|
||||
&self,
|
||||
include_spent: bool,
|
||||
refresh_from_node: bool,
|
||||
) -> Result<(bool, Vec<OutputData>), Error> {
|
||||
|
||||
let mut w = self.wallet.lock().unwrap();
|
||||
w.open_with_credentials()?;
|
||||
|
||||
let mut validated = false;
|
||||
if refresh_from_node {
|
||||
validated = self.update_outputs();
|
||||
validated = self.update_outputs(&mut w);
|
||||
}
|
||||
Ok((
|
||||
|
||||
let res = Ok((
|
||||
validated,
|
||||
updater::retrieve_outputs(&mut **self.wallet, include_spent)?,
|
||||
))
|
||||
updater::retrieve_outputs(&mut **w, include_spent)?,
|
||||
));
|
||||
|
||||
w.close()?;
|
||||
res
|
||||
}
|
||||
|
||||
/// Retrieve summary info for wallet
|
||||
@@ -81,12 +90,19 @@ where
|
||||
&mut self,
|
||||
refresh_from_node: bool,
|
||||
) -> Result<(bool, WalletInfo), Error> {
|
||||
let mut w = self.wallet.lock().unwrap();
|
||||
w.open_with_credentials()?;
|
||||
|
||||
let mut validated = false;
|
||||
if refresh_from_node {
|
||||
validated = self.update_outputs();
|
||||
validated = self.update_outputs(&mut w);
|
||||
}
|
||||
let wallet_info = updater::retrieve_info(&mut **self.wallet)?;
|
||||
Ok((validated, wallet_info))
|
||||
|
||||
let wallet_info = updater::retrieve_info(&mut **w)?;
|
||||
let res = Ok((validated, wallet_info));
|
||||
|
||||
w.close()?;
|
||||
res
|
||||
}
|
||||
|
||||
/// Issues a send transaction and sends to recipient
|
||||
@@ -97,37 +113,42 @@ where
|
||||
dest: &str,
|
||||
max_outputs: usize,
|
||||
selection_strategy_is_use_all: bool,
|
||||
fluff: bool,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<Slate, Error> {
|
||||
let mut w = self.wallet.lock().unwrap();
|
||||
w.open_with_credentials()?;
|
||||
|
||||
let client;
|
||||
let mut slate_out: Slate;
|
||||
let lock_fn_out;
|
||||
|
||||
client = w.client().clone();
|
||||
let (slate, context, lock_fn) = tx::create_send_tx(
|
||||
&mut **self.wallet,
|
||||
&mut **w,
|
||||
amount,
|
||||
minimum_confirmations,
|
||||
max_outputs,
|
||||
selection_strategy_is_use_all,
|
||||
)?;
|
||||
|
||||
let mut slate = match self.wallet.client().send_tx_slate(dest, &slate) {
|
||||
lock_fn_out = lock_fn;
|
||||
slate_out = match w.client().send_tx_slate(dest, &slate) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
error!(
|
||||
LOGGER,
|
||||
"Communication with receiver failed on SenderInitiation send. Aborting transaction {:?}",
|
||||
e,
|
||||
);
|
||||
LOGGER,
|
||||
"Communication with receiver failed on SenderInitiation send. Aborting transaction {:?}",
|
||||
e,
|
||||
);
|
||||
return Err(e)?;
|
||||
}
|
||||
};
|
||||
|
||||
tx::complete_tx(&mut **self.wallet, &mut slate, &context)?;
|
||||
tx::complete_tx(&mut **w, &mut slate_out, &context)?;
|
||||
|
||||
// All good here, so let's post it
|
||||
let tx_hex = util::to_hex(ser::ser_vec(&slate.tx).unwrap());
|
||||
self.wallet.client().post_tx(&TxWrapper { tx_hex: tx_hex }, fluff)?;
|
||||
|
||||
// All good here, lock our inputs
|
||||
lock_fn(self.wallet)?;
|
||||
Ok(())
|
||||
// lock our inputs
|
||||
lock_fn_out(&mut **w)?;
|
||||
w.close()?;
|
||||
Ok(slate_out)
|
||||
}
|
||||
|
||||
/// Issue a burn TX
|
||||
@@ -137,40 +158,60 @@ where
|
||||
minimum_confirmations: u64,
|
||||
max_outputs: usize,
|
||||
) -> Result<(), Error> {
|
||||
let tx_burn = tx::issue_burn_tx(
|
||||
&mut **self.wallet,
|
||||
amount,
|
||||
minimum_confirmations,
|
||||
max_outputs,
|
||||
)?;
|
||||
let mut w = self.wallet.lock().unwrap();
|
||||
w.open_with_credentials()?;
|
||||
let tx_burn = tx::issue_burn_tx(&mut **w, amount, minimum_confirmations, max_outputs)?;
|
||||
let tx_hex = util::to_hex(ser::ser_vec(&tx_burn).unwrap());
|
||||
self.wallet.client().post_tx(&TxWrapper { tx_hex: tx_hex }, false)?;
|
||||
w.client().post_tx(&TxWrapper { tx_hex: tx_hex }, false)?;
|
||||
w.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Posts a transaction to the chain
|
||||
pub fn post_tx(&self, slate: &Slate, fluff: bool) -> Result<(), Error> {
|
||||
let tx_hex = util::to_hex(ser::ser_vec(&slate.tx).unwrap());
|
||||
let client = {
|
||||
let mut w = self.wallet.lock().unwrap();
|
||||
w.client().clone()
|
||||
};
|
||||
client.post_tx(&TxWrapper { tx_hex: tx_hex }, fluff)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Attempt to restore contents of wallet
|
||||
pub fn restore(&mut self) -> Result<(), Error> {
|
||||
self.wallet.restore()
|
||||
let mut w = self.wallet.lock().unwrap();
|
||||
w.open_with_credentials()?;
|
||||
let res = w.restore();
|
||||
w.close()?;
|
||||
res
|
||||
}
|
||||
|
||||
/// Retrieve current height from node
|
||||
pub fn node_height(&mut self) -> Result<(u64, bool), Error> {
|
||||
match self.wallet.client().get_chain_height() {
|
||||
Ok(height) => Ok((height, true)),
|
||||
let mut w = self.wallet.lock().unwrap();
|
||||
w.open_with_credentials()?;
|
||||
let res = w.client().get_chain_height();
|
||||
match res {
|
||||
Ok(height) => {
|
||||
w.close()?;
|
||||
Ok((height, true))
|
||||
},
|
||||
Err(_) => {
|
||||
let outputs = self.retrieve_outputs(true, false)?;
|
||||
let height = match outputs.1.iter().map(|out| out.height).max() {
|
||||
Some(height) => height,
|
||||
None => 0,
|
||||
};
|
||||
w.close()?;
|
||||
Ok((height, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to update outputs in wallet, return whether it was successful
|
||||
fn update_outputs(&mut self) -> bool {
|
||||
match updater::refresh_outputs(&mut **self.wallet) {
|
||||
fn update_outputs(&self, w: &mut W ) -> bool {
|
||||
match updater::refresh_outputs(&mut *w) {
|
||||
Ok(_) => true,
|
||||
Err(_) => false,
|
||||
}
|
||||
@@ -179,41 +220,50 @@ where
|
||||
|
||||
/// Wrapper around external API functions, intended to communicate
|
||||
/// with other parties
|
||||
pub struct APIForeign<'a, W: ?Sized, C, K>
|
||||
pub struct APIForeign<W: ?Sized, C, K>
|
||||
where
|
||||
W: 'a + WalletBackend<C, K>,
|
||||
W: WalletBackend<C, K>,
|
||||
C: WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
/// Wallet, contains its keychain (TODO: Split these up into 2 traits
|
||||
/// perhaps)
|
||||
pub wallet: &'a mut Box<W>,
|
||||
pub wallet: Arc<Mutex<Box<W>>>,
|
||||
phantom: PhantomData<K>,
|
||||
phantom_c: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<'a, W: ?Sized, C, K> APIForeign<'a, W, C, K>
|
||||
impl<'a, W: ?Sized, C, K> APIForeign<W, C, K>
|
||||
where
|
||||
W: WalletBackend<C, K>,
|
||||
C: WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
/// Create new API instance
|
||||
pub fn new(wallet_in: &'a mut Box<W>) -> APIForeign<W, C, K> {
|
||||
APIForeign {
|
||||
pub fn new(wallet_in: Arc<Mutex<Box<W>>>) -> Box<Self> {
|
||||
Box::new(APIForeign {
|
||||
wallet: wallet_in,
|
||||
phantom: PhantomData,
|
||||
phantom_c: PhantomData,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Build a new (potential) coinbase transaction in the wallet
|
||||
pub fn build_coinbase(&mut self, block_fees: &BlockFees) -> Result<CbData, Error> {
|
||||
updater::build_coinbase(&mut **self.wallet, block_fees)
|
||||
let mut w = self.wallet.lock().unwrap();
|
||||
w.open_with_credentials()?;
|
||||
let res = updater::build_coinbase(&mut **w, block_fees);
|
||||
w.close()?;
|
||||
res
|
||||
|
||||
}
|
||||
|
||||
/// Receive a transaction from a sender
|
||||
pub fn receive_tx(&mut self, slate: &mut Slate) -> Result<(), Error> {
|
||||
tx::receive_tx(&mut **self.wallet, slate)
|
||||
let mut w = self.wallet.lock().unwrap();
|
||||
w.open_with_credentials()?;
|
||||
let res = tx::receive_tx(&mut **w, slate);
|
||||
w.close()?;
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ use keychain::Keychain;
|
||||
use libtx::slate::Slate;
|
||||
use libwallet::api::{APIForeign, APIOwner};
|
||||
use libwallet::types::{
|
||||
BlockFees, CbData, OutputData, SendTXArgs, WalletBackend, WalletClient, WalletInfo
|
||||
BlockFees, CbData, OutputData, SendTXArgs, WalletBackend, WalletClient, WalletInfo,
|
||||
};
|
||||
use libwallet::{Error, ErrorKind};
|
||||
|
||||
@@ -40,32 +40,33 @@ use util::LOGGER;
|
||||
|
||||
/// Instantiate wallet Owner API for a single-use (command line) call
|
||||
/// Return a function containing a loaded API context to call
|
||||
pub fn owner_single_use<F, T: ?Sized, C, K>(wallet: Box<T>, f: F) -> Result<(), Error>
|
||||
pub fn owner_single_use<F, T: ?Sized, C, K>(
|
||||
wallet: Arc<Mutex<Box<T>>>,
|
||||
f: F,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: WalletBackend<C, K>,
|
||||
F: FnOnce(&mut APIOwner<T, C, K>) -> Result<(), Error>,
|
||||
C: WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
let mut w = wallet;
|
||||
w.open_with_credentials()?;
|
||||
f(&mut APIOwner::new(&mut w))?;
|
||||
w.close()?;
|
||||
f(&mut APIOwner::new(wallet.clone()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Instantiate wallet Foreign API for a single-use (command line) call
|
||||
/// Return a function containing a loaded API context to call
|
||||
pub fn foreign_single_use<F, T: ?Sized, C, K>(wallet: &mut Box<T>, f: F) -> Result<(), Error>
|
||||
pub fn foreign_single_use<F, T: ?Sized, C, K>(
|
||||
wallet: Arc<Mutex<Box<T>>>,
|
||||
f: F,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: WalletBackend<C, K>,
|
||||
F: FnOnce(&mut APIForeign<T, C, K>) -> Result<(), Error>,
|
||||
C: WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
wallet.open_with_credentials()?;
|
||||
f(&mut APIForeign::new(wallet))?;
|
||||
wallet.close()?;
|
||||
f(&mut APIForeign::new(wallet.clone()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -193,7 +194,11 @@ where
|
||||
api.node_height()
|
||||
}
|
||||
|
||||
fn handle_request(&self, req: &mut Request, api: &mut APIOwner<T, C, K>) -> IronResult<Response> {
|
||||
fn handle_request(
|
||||
&self,
|
||||
req: &mut Request,
|
||||
api: &mut APIOwner<T, C, K>,
|
||||
) -> IronResult<Response> {
|
||||
let url = req.url.clone();
|
||||
let path_elems = url.path();
|
||||
match *path_elems.last().unwrap() {
|
||||
@@ -218,16 +223,7 @@ where
|
||||
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 w = wallet;
|
||||
let mut api = APIOwner::new(&mut w);
|
||||
let mut api = APIOwner::new(self.wallet.clone());
|
||||
let mut resp_json = self.handle_request(req, &mut api);
|
||||
if !resp_json.is_err() {
|
||||
resp_json
|
||||
@@ -236,9 +232,6 @@ where
|
||||
.headers
|
||||
.set_raw("access-control-allow-origin", vec![b"*".to_vec()]);
|
||||
}
|
||||
api.wallet
|
||||
.close()
|
||||
.map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?;
|
||||
resp_json
|
||||
}
|
||||
}
|
||||
@@ -271,7 +264,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn issue_send_tx(&self, req: &mut Request, api: &mut APIOwner<T, C, K>) -> Result<(), Error> {
|
||||
fn issue_send_tx(&self, req: &mut Request, api: &mut APIOwner<T, C, K>) -> Result<Slate, Error> {
|
||||
let struct_body = req.get::<bodyparser::Struct<SendTXArgs>>();
|
||||
match struct_body {
|
||||
Ok(Some(args)) => api.issue_send_tx(
|
||||
@@ -280,18 +273,17 @@ where
|
||||
&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",
|
||||
"Invalid request body: issue_send_tx".to_owned(),
|
||||
))?
|
||||
}
|
||||
Err(e) => {
|
||||
error!(LOGGER, "Invalid request body: issue_send_tx {:?}", e);
|
||||
Err(ErrorKind::GenericError(
|
||||
"Invalid request body: issue_send_tx",
|
||||
"Invalid request body: issue_send_tx".to_owned(),
|
||||
))?
|
||||
}
|
||||
}
|
||||
@@ -302,14 +294,18 @@ where
|
||||
api.issue_burn_tx(60, 10, 1000)
|
||||
}
|
||||
|
||||
fn handle_request(&self, req: &mut Request, api: &mut APIOwner<T, C, 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 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",
|
||||
"Unknown error handling post request".to_owned(),
|
||||
))?,
|
||||
}
|
||||
}
|
||||
@@ -343,18 +339,7 @@ where
|
||||
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 wallet = self.wallet.lock().unwrap();
|
||||
let mut api = APIOwner::new(&mut wallet);
|
||||
let mut api = APIOwner::new(self.wallet.clone());
|
||||
let resp = match self.handle_request(req, &mut api) {
|
||||
Ok(r) => self.create_ok_response(&r),
|
||||
Err(e) => {
|
||||
@@ -362,9 +347,6 @@ where
|
||||
self.create_error_response(e)
|
||||
}
|
||||
};
|
||||
api.wallet
|
||||
.close()
|
||||
.map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?;
|
||||
resp
|
||||
}
|
||||
}
|
||||
@@ -425,13 +407,13 @@ where
|
||||
Ok(None) => {
|
||||
error!(LOGGER, "Missing request body: build_coinbase");
|
||||
Err(ErrorKind::GenericError(
|
||||
"Invalid request body: build_coinbase",
|
||||
"Invalid request body: build_coinbase".to_owned(),
|
||||
))?
|
||||
}
|
||||
Err(e) => {
|
||||
error!(LOGGER, "Invalid request body: build_coinbase: {:?}", e);
|
||||
Err(ErrorKind::GenericError(
|
||||
"Invalid request body: build_coinbase",
|
||||
"Invalid request body: build_coinbase".to_owned(),
|
||||
))?
|
||||
}
|
||||
}
|
||||
@@ -443,7 +425,9 @@ where
|
||||
api.receive_tx(&mut slate)?;
|
||||
Ok(slate.clone())
|
||||
} else {
|
||||
Err(ErrorKind::GenericError("Invalid request body: receive_tx"))?
|
||||
Err(ErrorKind::GenericError(
|
||||
"Invalid request body: receive_tx".to_owned(),
|
||||
))?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,22 +457,8 @@ where
|
||||
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 wallet = self.wallet.lock().unwrap();
|
||||
let mut api = APIForeign::new(&mut wallet);
|
||||
let resp_json = self.handle_request(req, &mut api);
|
||||
api.wallet
|
||||
.close()
|
||||
.map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?;
|
||||
let mut api = APIForeign::new(self.wallet.clone());
|
||||
let resp_json = self.handle_request(req, &mut *api);
|
||||
resp_json
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ pub enum ErrorKind {
|
||||
|
||||
/// Other
|
||||
#[fail(display = "Generic error: {}", _0)]
|
||||
GenericError(&'static str),
|
||||
GenericError(String),
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
|
||||
@@ -306,7 +306,7 @@ impl BlockIdentifier {
|
||||
|
||||
/// convert to hex string
|
||||
pub fn from_hex(hex: &str) -> Result<BlockIdentifier, Error> {
|
||||
let hash = Hash::from_hex(hex).context(ErrorKind::GenericError("Invalid hex"))?;
|
||||
let hash = Hash::from_hex(hex).context(ErrorKind::GenericError("Invalid hex".to_owned()))?;
|
||||
Ok(BlockIdentifier(hash))
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -78,8 +78,8 @@ impl WalletSeed {
|
||||
}
|
||||
|
||||
fn from_hex(hex: &str) -> Result<WalletSeed, Error> {
|
||||
let bytes =
|
||||
util::from_hex(hex.to_string()).context(ErrorKind::GenericError("Invalid hex"))?;
|
||||
let bytes = util::from_hex(hex.to_string())
|
||||
.context(ErrorKind::GenericError("Invalid hex".to_owned()))?;
|
||||
Ok(WalletSeed::from_bytes(&bytes))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user