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:
Ignotus Peverell
2017-05-28 20:21:29 -07:00
parent da41120293
commit f79fb8ef95
22 changed files with 181 additions and 101 deletions
+3 -2
View File
@@ -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
View File
@@ -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);
});
+3
View File
@@ -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
View File
@@ -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);
}
}