Slate compatibility between versions (#35)

* wallet compatibilities

* rustfmt
This commit is contained in:
Yeastplume 2019-04-02 15:42:28 +01:00 committed by GitHub
parent 2d8a6b81e0
commit 0e9ccef3e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 115 additions and 24 deletions

View file

@ -763,14 +763,14 @@ where
Box::new(parse_body(req).and_then( Box::new(parse_body(req).and_then(
//TODO: No way to insert a message from the params //TODO: No way to insert a message from the params
move |slate_str: String| { move |slate_str: String| {
let mut slate: Slate = Slate::deserialize_upgrade(&slate_str).unwrap(); let slate: Slate = Slate::deserialize_upgrade(&slate_str).unwrap();
if let Err(e) = api.verify_slate_messages(&slate) { if let Err(e) = api.verify_slate_messages(&slate) {
error!("Error validating participant messages: {}", e); error!("Error validating participant messages: {}", e);
err(e) err(e)
} else { } else {
match api.receive_tx(&mut slate, None, None) { match api.receive_tx(&slate, None, None) {
Ok(_) => ok(slate Ok(s) => ok(s
.serialize_to_version(Some(slate.version_info.orig_version)) .serialize_to_version(Some(s.version_info.orig_version))
.unwrap()), .unwrap()),
Err(e) => { Err(e) => {
error!("receive_tx: failed with error: {}", e); error!("receive_tx: failed with error: {}", e);
@ -798,7 +798,7 @@ where
), ),
"receive_tx" => Box::new( "receive_tx" => Box::new(
self.receive_tx(req, api) self.receive_tx(req, api)
.and_then(|res| ok(json_response(&res))), .and_then(|res| ok(json_response_slate(&res))),
), ),
_ => Box::new(ok(response(StatusCode::BAD_REQUEST, "unknown action"))), _ => Box::new(ok(response(StatusCode::BAD_REQUEST, "unknown action"))),
} }
@ -909,6 +909,29 @@ where
} }
} }
// As above, dealing with stringified slate output
// from older versions.
// Older versions are expecting a slate objects, anything from
// 1.1.0 up is expecting a string
fn json_response_slate<T>(s: &T) -> Response<Body>
where
T: Serialize,
{
match serde_json::to_string(s) {
Ok(mut json) => {
if let None = json.find("version_info") {
let mut r = json.clone();
r.pop();
r.remove(0);
// again, for backwards slate compat
json = r.replace("\\\"", "\"")
}
response(StatusCode::OK, json)
}
Err(_) => response(StatusCode::INTERNAL_SERVER_ERROR, ""),
}
}
// pretty-printed version of above // pretty-printed version of above
fn json_response_pretty<T>(s: &T) -> Response<Body> fn json_response_pretty<T>(s: &T) -> Response<Body>
where where
@ -987,10 +1010,26 @@ where
req.into_body() req.into_body()
.concat2() .concat2()
.map_err(|_| ErrorKind::GenericError("Failed to read request".to_owned()).into()) .map_err(|_| ErrorKind::GenericError("Failed to read request".to_owned()).into())
.and_then(|body| match serde_json::from_reader(&body.to_vec()[..]) { .and_then(|body| {
match serde_json::from_reader(&body.to_vec()[..]) {
Ok(obj) => ok(obj), Ok(obj) => ok(obj),
Err(e) => { Err(_) => {
err(ErrorKind::GenericError(format!("Invalid request body: {}", e)).into()) // try to parse as string instead, for backwards compatibility
let replaced_str = String::from_utf8(body.to_vec().clone())
.unwrap()
.replace("\"", "\\\"");
let mut str_vec = replaced_str.as_bytes().to_vec();
str_vec.push(0x22);
str_vec.insert(0, 0x22);
match serde_json::from_reader(&str_vec[..]) {
Ok(obj) => ok(obj),
Err(e) => err(ErrorKind::GenericError(format!(
"Invalid request body: {}",
e
))
.into()),
}
}
} }
}), }),
) )

View file

@ -15,9 +15,11 @@
/// HTTP Wallet 'plugin' implementation /// HTTP Wallet 'plugin' implementation
use crate::api; use crate::api;
use crate::libwallet::slate::Slate; use crate::libwallet::slate::Slate;
use crate::libwallet::slate_versions::{v0, v1};
use crate::libwallet::{Error, ErrorKind}; use crate::libwallet::{Error, ErrorKind};
use crate::WalletCommAdapter; use crate::WalletCommAdapter;
use config::WalletConfig; use config::WalletConfig;
use failure::ResultExt;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Clone)] #[derive(Clone)]
@ -47,16 +49,65 @@ impl WalletCommAdapter for HTTPWalletCommAdapter {
let url = format!("{}/v1/wallet/foreign/receive_tx", dest); let url = format!("{}/v1/wallet/foreign/receive_tx", dest);
debug!("Posting transaction slate to {}", url); debug!("Posting transaction slate to {}", url);
let slate = slate.serialize_to_version(Some(slate.version_info.orig_version))?; let slate = slate.serialize_to_version(Some(slate.version_info.orig_version))?;
// For compatibility with older clients
let res: Slate = {
if let None = slate.find("version_info") {
let version = Slate::parse_slate_version(&slate)?;
match version {
1 => {
let ver1: v1::SlateV1 =
serde_json::from_str(&slate).context(ErrorKind::SlateDeser)?;
let r: Result<v1::SlateV1, _> =
api::client::post(url.as_str(), None, &ver1);
match r {
Err(e) => {
let report = format!(
"Posting transaction slate (is recipient listening?): {}",
e
);
error!("{}", report);
return Err(ErrorKind::ClientCallback(report).into());
}
Ok(s) => Slate::deserialize_upgrade(
&serde_json::to_string(&s).context(ErrorKind::SlateDeser)?,
)?,
}
}
_ => {
let ver0: v0::SlateV0 =
serde_json::from_str(&slate).context(ErrorKind::SlateDeser)?;
let r: Result<v0::SlateV0, _> =
api::client::post(url.as_str(), None, &ver0);
match r {
Err(e) => {
let report = format!(
"Posting transaction slate (is recipient listening?): {}",
e
);
error!("{}", report);
return Err(ErrorKind::ClientCallback(report).into());
}
Ok(s) => Slate::deserialize_upgrade(
&serde_json::to_string(&s).context(ErrorKind::SlateDeser)?,
)?,
}
}
}
} else {
let res: Result<String, _> = api::client::post(url.as_str(), None, &slate); let res: Result<String, _> = api::client::post(url.as_str(), None, &slate);
match res { match res {
Err(e) => { Err(e) => {
let report = format!("Posting transaction slate (is recipient listening?): {}", e); let report =
format!("Posting transaction slate (is recipient listening?): {}", e);
error!("{}", report); error!("{}", report);
Err(ErrorKind::ClientCallback(report).into()) return Err(ErrorKind::ClientCallback(report).into());
} }
Ok(r) => Ok(Slate::deserialize_upgrade(&r)?), Ok(r) => Slate::deserialize_upgrade(&r)?,
} }
} }
};
Ok(res)
}
fn send_tx_async(&self, _dest: &str, _slate: &Slate) -> Result<(), Error> { fn send_tx_async(&self, _dest: &str, _slate: &Slate) -> Result<(), Error> {
unimplemented!(); unimplemented!();

View file

@ -163,9 +163,9 @@ pub struct ParticipantMessages {
} }
impl Slate { impl Slate {
// TODO: Reduce the number of changes that need to occur below for each new /// TODO: Reduce the number of changes that need to occur below for each new
// slate version /// slate version
fn parse_slate_version(slate_json: &str) -> Result<u16, Error> { pub fn parse_slate_version(slate_json: &str) -> Result<u16, Error> {
// keep attempting to deser, working through known versions until we have // keep attempting to deser, working through known versions until we have
// enough to get the version out // enough to get the version out
let res: Result<SlateV2, serde_json::Error> = serde_json::from_str(slate_json); let res: Result<SlateV2, serde_json::Error> = serde_json::from_str(slate_json);
@ -218,7 +218,8 @@ impl Slate {
1 => { 1 => {
let v2: SlateV2 = serde_json::from_str(&ser_self).context(ErrorKind::SlateDeser)?; let v2: SlateV2 = serde_json::from_str(&ser_self).context(ErrorKind::SlateDeser)?;
let v1 = SlateV1::from(v2); let v1 = SlateV1::from(v2);
Ok(serde_json::to_string(&v1).context(ErrorKind::SlateDeser)?) let slate = serde_json::to_string(&v1).context(ErrorKind::SlateDeser)?;
Ok(slate)
} }
0 => { 0 => {
let v2: SlateV2 = serde_json::from_str(&ser_self).context(ErrorKind::SlateDeser)?; let v2: SlateV2 = serde_json::from_str(&ser_self).context(ErrorKind::SlateDeser)?;

View file

@ -397,10 +397,10 @@ pub fn parse_send_args(args: &ArgMatches) -> Result<command::SendArgs, ParseErro
// target slate version to create/send // target slate version to create/send
let target_slate_version = { let target_slate_version = {
match args.is_present("target_slate_version") { match args.is_present("slate_version") {
true => { true => {
let v = parse_required(args, "target_slate_version")?; let v = parse_required(args, "slate_version")?;
Some(parse_u64(v, "target_slate_version")? as u16) Some(parse_u64(v, "slate_version")? as u16)
} }
false => None, false => None,
} }