Sending end of the wallet
Most of the logic to build a transaction that sends coin to another party. Still requires more debugging and clean up. Main changes and additions are: * Update to serde 1.0 * API endpoint to retrieve an Output * Output is now Serialize and Deserialize * Wallet configuration * Command line for the send operation * Wallet data checker to update created outputs into confirmed * Wallet-specific configuration
This commit is contained in:
+3
-2
@@ -26,8 +26,9 @@ use rest::Error;
|
||||
/// returns a JSON object. Handles request building, JSON deserialization and
|
||||
/// response code checking.
|
||||
pub fn get<'a, T>(url: &'a str) -> Result<T, Error>
|
||||
where T: Deserialize
|
||||
where for<'de> T: Deserialize<'de>
|
||||
{
|
||||
println!("get {}", url);
|
||||
let client = hyper::Client::new();
|
||||
let res = check_error(client.get(url).send())?;
|
||||
serde_json::from_reader(res)
|
||||
@@ -40,7 +41,7 @@ pub fn get<'a, T>(url: &'a str) -> Result<T, Error>
|
||||
/// checking.
|
||||
pub fn post<'a, IN, OUT>(url: &'a str, input: &IN) -> Result<OUT, Error>
|
||||
where IN: Serialize,
|
||||
OUT: Deserialize
|
||||
for<'de> OUT: Deserialize<'de>
|
||||
{
|
||||
let in_json = serde_json::to_string(input)
|
||||
.map_err(|e| Error::Internal(format!("Could not serialize data to JSON: {}", e)))?;
|
||||
|
||||
+30
-1
@@ -24,8 +24,12 @@
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
use core::core::Output;
|
||||
use core::core::hash::Hash;
|
||||
use chain::{self, Tip};
|
||||
use rest::*;
|
||||
use secp::pedersen::Commitment;
|
||||
use util;
|
||||
|
||||
/// ApiEndpoint implementation for the blockchain. Exposes the current chain
|
||||
/// state as a simple JSON object.
|
||||
@@ -50,13 +54,38 @@ impl ApiEndpoint for ChainApi {
|
||||
}
|
||||
}
|
||||
|
||||
/// ApiEndpoint implementation for outputs that have been included in the chain.
|
||||
#[derive(Clone)]
|
||||
pub struct OutputApi {
|
||||
/// data store access
|
||||
chain_store: Arc<chain::ChainStore>,
|
||||
}
|
||||
|
||||
impl ApiEndpoint for OutputApi {
|
||||
type ID = String;
|
||||
type T = Output;
|
||||
type OP_IN = ();
|
||||
type OP_OUT = ();
|
||||
|
||||
fn operations(&self) -> Vec<Operation> {
|
||||
vec![Operation::Get]
|
||||
}
|
||||
|
||||
fn get(&self, id: String) -> ApiResult<Output> {
|
||||
debug!("GET output {}", id);
|
||||
let c = util::from_hex(id.clone()).map_err(|e| Error::Argument(format!("Not a valid commitment: {}", id)))?;
|
||||
self.chain_store.get_output_by_commit(&Commitment::from_vec(c)).map_err(|e| Error::Internal(e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Start all server REST APIs. Just register all of them on a ApiServer
|
||||
/// instance and runs the corresponding HTTP server.
|
||||
pub fn start_rest_apis(addr: String, chain_store: Arc<chain::ChainStore>) {
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut apis = ApiServer::new("/v1".to_string());
|
||||
apis.register_endpoint("/chain".to_string(), ChainApi { chain_store: chain_store });
|
||||
apis.register_endpoint("/chain".to_string(), ChainApi { chain_store: chain_store.clone() });
|
||||
apis.register_endpoint("/chain/output".to_string(), OutputApi { chain_store: chain_store.clone() });
|
||||
apis.start(&addr[..]).unwrap_or_else(|e| {
|
||||
error!("Failed to start API HTTP server: {}.", e);
|
||||
});
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
extern crate grin_core as core;
|
||||
extern crate grin_chain as chain;
|
||||
extern crate grin_util as util;
|
||||
extern crate secp256k1zkp as secp;
|
||||
|
||||
extern crate hyper;
|
||||
#[macro_use]
|
||||
|
||||
+6
-5
@@ -31,6 +31,7 @@ use iron::modifiers::Header;
|
||||
use iron::middleware::Handler;
|
||||
use router::Router;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde_json;
|
||||
|
||||
/// Errors that can be returned by an ApiEndpoint implementation.
|
||||
@@ -109,9 +110,9 @@ pub type ApiResult<T> = ::std::result::Result<T, Error>;
|
||||
/// create and accepted by all other methods must have a string representation.
|
||||
pub trait ApiEndpoint: Clone + Send + Sync + 'static {
|
||||
type ID: ToString + FromStr;
|
||||
type T: Serialize + Deserialize;
|
||||
type OP_IN: Serialize + Deserialize;
|
||||
type OP_OUT: Serialize + Deserialize;
|
||||
type T: Serialize + DeserializeOwned;
|
||||
type OP_IN: Serialize + DeserializeOwned;
|
||||
type OP_OUT: Serialize + DeserializeOwned;
|
||||
|
||||
fn operations(&self) -> Vec<Operation>;
|
||||
|
||||
@@ -251,7 +252,7 @@ impl ApiServer {
|
||||
};
|
||||
let full_path = format!("{}", root.clone());
|
||||
self.router.route(op.to_method(), full_path.clone(), wrapper, route_name);
|
||||
info!("POST {}", full_path);
|
||||
info!("route: POST {}", full_path);
|
||||
} else {
|
||||
|
||||
// regular REST operations
|
||||
@@ -264,7 +265,7 @@ impl ApiServer {
|
||||
};
|
||||
let wrapper = ApiWrapper(endpoint.clone());
|
||||
self.router.route(op.to_method(), full_path.clone(), wrapper, route_name);
|
||||
info!("{} {}", op.to_method(), full_path);
|
||||
info!("route: {} {}", op.to_method(), full_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user