fix the wallet receiver api (#222)

This commit is contained in:
AntiochP 2017-11-01 14:32:34 -04:00 committed by GitHub
parent 7a803a8dc1
commit 9e36b820f6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 77 additions and 62 deletions

View file

@ -40,19 +40,16 @@ where
/// object as body on a given URL that returns a JSON object. Handles request /// object as body on a given URL that returns a JSON object. Handles request
/// building, JSON serialization and deserialization, and response code /// building, JSON serialization and deserialization, and response code
/// checking. /// checking.
pub fn post<'a, IN, OUT>(url: &'a str, input: &IN) -> Result<OUT, Error> pub fn post<'a, IN>(url: &'a str, input: &IN) -> Result<(), Error>
where where
IN: Serialize, IN: Serialize,
for<'de> OUT: Deserialize<'de>,
{ {
let in_json = serde_json::to_string(input).map_err(|e| { let in_json = serde_json::to_string(input).map_err(|e| {
Error::Internal(format!("Could not serialize data to JSON: {}", e)) Error::Internal(format!("Could not serialize data to JSON: {}", e))
})?; })?;
let client = hyper::Client::new(); let client = hyper::Client::new();
let res = check_error(client.post(url).body(&mut in_json.as_bytes()).send())?; let _res = check_error(client.post(url).body(&mut in_json.as_bytes()).send())?;
serde_json::from_reader(res).map_err(|e| { Ok(())
Error::Internal(format!("Server returned invalid JSON: {}", e))
})
} }
// convert hyper error and check for non success response codes // convert hyper error and check for non success response codes

View file

@ -372,7 +372,7 @@ fn wallet_command(wallet_args: &ArgMatches) {
let mut contents = String::new(); let mut contents = String::new();
file.read_to_string(&mut contents) file.read_to_string(&mut contents)
.expect("Unable to read transaction file."); .expect("Unable to read transaction file.");
wallet::receive_json_tx(&wallet_config, &keychain, contents.as_str()).unwrap(); wallet::receive_json_tx_str(&wallet_config, &keychain, contents.as_str()).unwrap();
} else { } else {
wallet::server::start_rest_apis(wallet_config, keychain); wallet::server::start_rest_apis(wallet_config, keychain);
}, },

View file

@ -55,6 +55,24 @@ where
Ok(res) Ok(res)
} }
pub fn send_partial_tx(url: &str, partial_tx: &JSONPartialTx) -> Result<(), Error> {
single_send_partial_tx(url, partial_tx)
}
fn single_send_partial_tx(url: &str, partial_tx: &JSONPartialTx) -> Result<(), Error> {
let mut core = reactor::Core::new()?;
let client = hyper::Client::new(&core.handle());
let mut req = Request::new(Method::Post, url.parse()?);
req.headers_mut().set(ContentType::json());
let json = serde_json::to_string(&partial_tx)?;
req.set_body(json);
let work = client.request(req);
let _ = core.run(work)?;
Ok(())
}
/// 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 = reactor::Core::new()?; let mut core = reactor::Core::new()?;

View file

@ -48,6 +48,6 @@ pub mod client;
pub mod server; pub mod server;
pub use info::show_info; pub use info::show_info;
pub use receiver::{receive_json_tx, WalletReceiver}; pub use receiver::{receive_json_tx, receive_json_tx_str, WalletReceiver};
pub use sender::{issue_burn_tx, issue_send_tx}; pub use sender::{issue_burn_tx, issue_send_tx};
pub use types::{BlockFees, CbData, Error, WalletConfig, WalletReceiveRequest, WalletSeed}; pub use types::{BlockFees, CbData, Error, WalletConfig, WalletReceiveRequest, WalletSeed};

View file

@ -16,17 +16,17 @@
//! receiving money in MimbleWimble requires an interactive exchange, a //! receiving money in MimbleWimble requires an interactive exchange, a
//! wallet server that's running at all time is required in many cases. //! wallet server that's running at all time is required in many cases.
use std::io::Read; use bodyparser;
use core::consensus::reward;
use core::core::{build, Block, Output, Transaction, TxKernel};
use core::ser;
use api;
use iron::prelude::*; use iron::prelude::*;
use iron::Handler; use iron::Handler;
use iron::status; use iron::status;
use keychain::{BlindingFactor, Identifier, Keychain};
use serde_json; use serde_json;
use api;
use core::consensus::reward;
use core::core::{build, Block, Output, Transaction, TxKernel};
use core::ser;
use keychain::{BlindingFactor, Identifier, Keychain};
use types::*; use types::*;
use util; use util;
use util::LOGGER; use util::LOGGER;
@ -37,21 +37,30 @@ pub struct TxWrapper {
pub tx_hex: String, pub tx_hex: String,
} }
pub fn receive_json_tx_str(
config: &WalletConfig,
keychain: &Keychain,
json_tx: &str,
) -> Result<(), Error> {
let partial_tx = serde_json::from_str(json_tx).unwrap();
receive_json_tx(config, keychain, &partial_tx)
}
/// Receive an already well formed JSON transaction issuance and finalize the /// Receive an already well formed JSON transaction issuance and finalize the
/// transaction, adding our receiving output, to broadcast to the rest of the /// transaction, adding our receiving output, to broadcast to the rest of the
/// network. /// network.
pub fn receive_json_tx( pub fn receive_json_tx(
config: &WalletConfig, config: &WalletConfig,
keychain: &Keychain, keychain: &Keychain,
partial_tx_str: &str, partial_tx: &JSONPartialTx,
) -> Result<(), Error> { ) -> Result<(), Error> {
let (amount, blinding, partial_tx) = partial_tx_from_json(keychain, partial_tx_str)?; let (amount, blinding, tx) = read_partial_tx(keychain, partial_tx)?;
let final_tx = receive_transaction(config, keychain, amount, blinding, partial_tx)?; let final_tx = receive_transaction(config, keychain, amount, blinding, tx)?;
let tx_hex = util::to_hex(ser::ser_vec(&final_tx).unwrap()); let tx_hex = util::to_hex(ser::ser_vec(&final_tx).unwrap());
let url = format!("{}/v1/pool/push", config.check_node_api_http_addr.as_str()); let url = format!("{}/v1/pool/push", config.check_node_api_http_addr.as_str());
let _: () = api::client::post(url.as_str(), &TxWrapper { tx_hex: tx_hex })
api::client::post(url.as_str(), &TxWrapper { tx_hex: tx_hex }).map_err(|e| Error::Node(e))?; .map_err(|e| Error::Node(e))?;
Ok(()) Ok(())
} }
@ -65,25 +74,18 @@ pub struct WalletReceiver {
impl Handler for WalletReceiver { impl Handler for WalletReceiver {
fn handle(&self, req: &mut Request) -> IronResult<Response> { fn handle(&self, req: &mut Request) -> IronResult<Response> {
let receive: WalletReceiveRequest = serde_json::from_reader(req.body.by_ref()) let struct_body = req.get::<bodyparser::Struct<JSONPartialTx>>();
.map_err(|e| IronError::new(e, status::BadRequest))?;
match receive { if let Ok(Some(partial_tx)) = struct_body {
WalletReceiveRequest::PartialTransaction(partial_tx_str) => { receive_json_tx(&self.config, &self.keychain, &partial_tx)
debug!(LOGGER, "Receive with transaction {}", &partial_tx_str,);
receive_json_tx(&self.config, &self.keychain, &partial_tx_str)
.map_err(|e| { .map_err(|e| {
api::Error::Internal( api::Error::Internal(
format!("Error processing partial transaction: {:?}", e), format!("Error processing partial transaction: {:?}", e),
) )})
})
.unwrap(); .unwrap();
Ok(Response::with(status::Ok)) Ok(Response::with(status::Ok))
} } else {
_ => Ok(Response::with( Ok(Response::with((status::BadRequest, "")))
(status::BadRequest, format!("Incorrect request data.")),
)),
} }
} }
} }

View file

@ -12,7 +12,10 @@
// 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 serde_json;
use api; use api;
use client;
use checker; use checker;
use core::core::{build, Transaction}; use core::core::{build, Transaction};
use core::ser; use core::ser;
@ -50,18 +53,16 @@ pub fn issue_send_tx(
minimum_confirmations, minimum_confirmations,
lock_height, lock_height,
)?; )?;
let json_tx = partial_tx_to_json(amount, blind_sum, tx);
let partial_tx = build_partial_tx(amount, blind_sum, tx);
if dest == "stdout" { if dest == "stdout" {
let json_tx = serde_json::to_string_pretty(&partial_tx).unwrap();
println!("{}", json_tx); println!("{}", json_tx);
} else if &dest[..4] == "http" { } else if &dest[..4] == "http" {
let url = format!("{}/v1/receive/transaction", &dest); let url = format!("{}/v1/receive/transaction", &dest);
debug!(LOGGER, "Posting partial transaction to {}", url); debug!(LOGGER, "Posting partial transaction to {}", url);
let request = WalletReceiveRequest::PartialTransaction(json_tx); client::send_partial_tx(&url, &partial_tx)?;
let _: CbData = api::client::post(url.as_str(), &request).expect(&format!(
"Wallet receiver at {} unreachable, could not send transaction. Is it running?",
url
));
} else { } else {
panic!("dest not in expected format: {}", dest); panic!("dest not in expected format: {}", dest);
} }

View file

@ -37,7 +37,7 @@ pub fn start_rest_apis(wallet_config: WalletConfig, keychain: Keychain) {
}; };
let router = router!( let router = router!(
receive_tx: get "/receive/transaction" => receive_tx_handler, receive_tx: post "/receive/transaction" => receive_tx_handler,
receive_coinbase: post "/receive/coinbase" => coinbase_handler, receive_coinbase: post "/receive/coinbase" => coinbase_handler,
); );

View file

@ -521,7 +521,7 @@ impl WalletData {
/// Helper in serializing the information a receiver requires to build a /// Helper in serializing the information a receiver requires to build a
/// transaction. /// transaction.
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
struct JSONPartialTx { pub struct JSONPartialTx {
amount: u64, amount: u64,
blind_sum: String, blind_sum: String,
tx: String, tx: String,
@ -529,34 +529,31 @@ struct JSONPartialTx {
/// Encodes the information for a partial transaction (not yet completed by the /// Encodes the information for a partial transaction (not yet completed by the
/// receiver) into JSON. /// receiver) into JSON.
pub fn partial_tx_to_json( pub fn build_partial_tx(
receive_amount: u64, receive_amount: u64,
blind_sum: keychain::BlindingFactor, blind_sum: keychain::BlindingFactor,
tx: Transaction, tx: Transaction,
) -> String { ) -> JSONPartialTx {
let partial_tx = JSONPartialTx { JSONPartialTx {
amount: receive_amount, amount: receive_amount,
blind_sum: util::to_hex(blind_sum.secret_key().as_ref().to_vec()), blind_sum: util::to_hex(blind_sum.secret_key().as_ref().to_vec()),
tx: util::to_hex(ser::ser_vec(&tx).unwrap()), tx: util::to_hex(ser::ser_vec(&tx).unwrap()),
}; }
serde_json::to_string_pretty(&partial_tx).unwrap()
} }
/// Reads a partial transaction encoded as JSON into the amount, sum of blinding /// Reads a partial transaction into the amount, sum of blinding
/// factors and the transaction itself. /// factors and the transaction itself.
pub fn partial_tx_from_json( pub fn read_partial_tx(
keychain: &keychain::Keychain, keychain: &keychain::Keychain,
json_str: &str, partial_tx: &JSONPartialTx,
) -> Result<(u64, keychain::BlindingFactor, Transaction), Error> { ) -> Result<(u64, keychain::BlindingFactor, Transaction), Error> {
let partial_tx: JSONPartialTx = serde_json::from_str(json_str)?; // let partial_tx: JSONPartialTx = serde_json::from_str(json_str)?;
let blind_bin = util::from_hex(partial_tx.blind_sum)?; let blind_bin = util::from_hex(partial_tx.blind_sum.clone())?;
// TODO - turn some data into a blinding factor here somehow
// let blinding = SecretKey::from_slice(&secp, &blind_bin[..])?;
let blinding = keychain::BlindingFactor::from_slice(keychain.secp(), &blind_bin[..])?; let blinding = keychain::BlindingFactor::from_slice(keychain.secp(), &blind_bin[..])?;
let tx_bin = util::from_hex(partial_tx.tx)?; let tx_bin = util::from_hex(partial_tx.tx.clone())?;
let tx = ser::deserialize(&mut &tx_bin[..]).map_err(|_| { let tx = ser::deserialize(&mut &tx_bin[..]).map_err(|_| {
Error::Format("Could not deserialize transaction, invalid format.".to_string()) Error::Format("Could not deserialize transaction, invalid format.".to_string())
})?; })?;