mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-08 12:21:09 +03:00
fix the wallet receiver api (#222)
This commit is contained in:
parent
7a803a8dc1
commit
9e36b820f6
8 changed files with 77 additions and 62 deletions
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
},
|
},
|
||||||
|
|
|
@ -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()?;
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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.")),
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
})?;
|
})?;
|
||||||
|
|
Loading…
Reference in a new issue