Feature/slate serialization (#2534)

* - Add backwards compatability
- Add hex serialization

* rustfmt

* rustfmt

* Windows Compatibility Fixes #1 (#2535)

* initial changes for windows build and unit/integration tests

* rustfmt

* wallet+store tests

* rustfmt

* fix linux daemonize

* better encapsulate file rename

* rustfmt

* remove daemonize commands

* rustfmt

* remove server start/stop commands

* add ability to drop pmmr backend files explicitly for txhashset unzip

* rustfmt

* fix pmmr tests

* rustfmt

* Windows TUI Fix (#2555)

* switch pancurses backend to win32

* revert changes to restore test

* compatibility fix + debug messages

* rustfmt

* Add content disposition for OK responses  (#2545)

* Testing http send and fixing accordingly

* add repost method into wallet owner api (#2553)

* add repost method into wallet owner api

* rustfmt

* Add ability to compare selection strategies (#2516)

Before tx creation user can estimate fee and locked amount
with different selection strategies by providing `-e` flag for
`wallet send` command.
This commit is contained in:
Yoni Svechinsky
2019-02-13 15:29:44 +02:00
committed by Yeastplume
parent 0d36acf01b
commit ee4eed71ea
39 changed files with 2408 additions and 1221 deletions
+108 -9
View File
@@ -15,13 +15,14 @@
//! Controller for wallet.. instantiates and handles listeners (or single-run
//! invocations) as needed.
//! Still experimental
use crate::adapters::util::get_versioned_slate;
use crate::adapters::{FileWalletCommAdapter, HTTPWalletCommAdapter, KeybaseWalletCommAdapter};
use crate::api::{ApiServer, BasicAuthMiddleware, Handler, ResponseFuture, Router, TLSConfig};
use crate::core::core;
use crate::core::core::Transaction;
use crate::keychain::Keychain;
use crate::libwallet::api::{APIForeign, APIOwner};
use crate::libwallet::slate::Slate;
use crate::libwallet::slate::{Slate, VersionedSlate};
use crate::libwallet::types::{
CbData, NodeClient, OutputData, SendTXArgs, TxLogEntry, WalletBackend, WalletInfo,
};
@@ -40,6 +41,7 @@ use std::marker::PhantomData;
use std::net::SocketAddr;
use std::sync::Arc;
use url::form_urlencoded;
use uuid::Uuid;
/// Instantiate wallet Owner API for a single-use (command line) call
/// Return a function containing a loaded API context to call
@@ -467,6 +469,87 @@ where
))
}
pub fn repost(
&self,
req: Request<Body>,
api: APIOwner<T, C, K>,
) -> Box<dyn Future<Item = (), Error = Error> + Send> {
let params = parse_params(&req);
let mut id_int: Option<u32> = None;
let mut tx_uuid: Option<Uuid> = None;
if let Some(id_string) = params.get("id") {
match id_string[0].parse() {
Ok(id) => id_int = Some(id),
Err(e) => {
error!("repost: could not parse id: {}", e);
return Box::new(err(ErrorKind::GenericError(
"repost: cannot repost transaction. Could not parse id in request."
.to_owned(),
)
.into()));
}
}
} else if let Some(tx_id_string) = params.get("tx_id") {
match tx_id_string[0].parse() {
Ok(tx_id) => tx_uuid = Some(tx_id),
Err(e) => {
error!("repost: could not parse tx_id: {}", e);
return Box::new(err(ErrorKind::GenericError(
"repost: cannot repost transaction. Could not parse tx_id in request."
.to_owned(),
)
.into()));
}
}
} else {
return Box::new(err(ErrorKind::GenericError(
"repost: Cannot repost transaction. Missing id or tx_id param in request."
.to_owned(),
)
.into()));
}
let res = api.retrieve_txs(true, id_int, tx_uuid);
if let Err(e) = res {
return Box::new(err(ErrorKind::GenericError(format!(
"repost: cannot repost transaction. retrieve_txs failed, err: {:?}",
e
))
.into()));
}
let (_, txs) = res.unwrap();
let res = api.get_stored_tx(&txs[0]);
if let Err(e) = res {
return Box::new(err(ErrorKind::GenericError(format!(
"repost: cannot repost transaction. get_stored_tx failed, err: {:?}",
e
))
.into()));
}
let stored_tx = res.unwrap();
if stored_tx.is_none() {
error!(
"Transaction with id {:?}/{:?} does not have transaction data. Not reposting.",
id_int, tx_uuid,
);
return Box::new(err(ErrorKind::GenericError(
"repost: Cannot repost transaction. Missing id or tx_id param in request."
.to_owned(),
)
.into()));
}
let fluff = params.get("fluff").is_some();
Box::new(match api.post_tx(&stored_tx.unwrap(), fluff) {
Ok(_) => ok(()),
Err(e) => {
error!("repost: failed with error: {}", e);
err(e)
}
})
}
fn handle_post_request(&self, req: Request<Body>) -> WalletResponseFuture {
let api = APIOwner::new(self.wallet.clone());
match req
@@ -487,10 +570,14 @@ where
),
"cancel_tx" => Box::new(
self.cancel_tx(req, api)
.and_then(|_| ok(response(StatusCode::OK, ""))),
.and_then(|_| ok(response(StatusCode::OK, "{}"))),
),
"post_tx" => Box::new(
self.post_tx(req, api)
.and_then(|_| ok(response(StatusCode::OK, "{}"))),
),
"repost" => Box::new(
self.repost(req, api)
.and_then(|_| ok(response(StatusCode::OK, ""))),
),
_ => Box::new(err(ErrorKind::GenericError(
@@ -574,16 +661,17 @@ where
&self,
req: Request<Body>,
mut api: APIForeign<T, C, K>,
) -> Box<dyn Future<Item = Slate, Error = Error> + Send> {
) -> Box<dyn Future<Item = VersionedSlate, Error = Error> + Send> {
Box::new(parse_body(req).and_then(
//TODO: No way to insert a message from the params
move |mut slate| {
move |slate: VersionedSlate| {
let mut slate: Slate = slate.into();
if let Err(e) = api.verify_slate_messages(&slate) {
error!("Error validating participant messages: {}", e);
err(e)
} else {
match api.receive_tx(&mut slate, None, None) {
Ok(_) => ok(slate.clone()),
Ok(_) => ok(get_versioned_slate(&slate.clone())),
Err(e) => {
error!("receive_tx: failed with error: {}", e);
err(e)
@@ -677,20 +765,31 @@ fn create_ok_response(json: &str) -> Response<Body> {
"access-control-allow-headers",
"Content-Type, Authorization",
)
.header(hyper::header::CONTENT_TYPE, "application/json")
.body(json.to_string().into())
.unwrap()
}
/// Build a new hyper Response with the status code and body provided.
///
/// Whenever the status code is `StatusCode::OK` the text parameter should be
/// valid JSON as the content type header will be set to `application/json'
fn response<T: Into<Body>>(status: StatusCode, text: T) -> Response<Body> {
Response::builder()
let mut builder = &mut Response::builder();
builder = builder
.status(status)
.header("access-control-allow-origin", "*")
.header(
"access-control-allow-headers",
"Content-Type, Authorization",
)
.body(text.into())
.unwrap()
);
if status == StatusCode::OK {
builder = builder.header(hyper::header::CONTENT_TYPE, "application/json");
}
builder.body(text.into()).unwrap()
}
fn parse_params(req: &Request<Body>) -> HashMap<String, Vec<String>> {