Commit c6c91081 authored by Daniel Edgecumbe's avatar Daniel Edgecumbe

Add createpsbt to backend

parent 7626c077
Pipeline #308 passed with stages
in 1 minute and 1 second
......@@ -29,6 +29,7 @@ pub enum BitcoinRPCParameter {
Bool(bool),
Int(i64),
Str(String),
Any(serde_json::Value),
}
#[derive(Serialize, Deserialize, Debug)]
......
......@@ -30,6 +30,7 @@ extern crate r2d2_postgres;
use r2d2_postgres::{TlsMode, PostgresConnectionManager};
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
mod log;
......
//
// Copyright (C) 2016-2018 Daniel Edgecumbe (esotericnonsense)
// Electron Relocation Limited
//
// This file is part of bitcoin-top. bitcoin-top is free software: you can
// redistribute it and/or modify it under the terms of the GNU Affero General
// Public License as published by the Free Software Foundation, either version 3
// of the License, or (at your option) any later version.
//
// bitcoin-top is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with bitcoin-top. If not, see <http://www.gnu.org/licenses/>.
//
extern crate hyper;
use hyper::{Body, Response};
use hyper::rt::{Future};
extern crate serde_json;
//use PgPool;
//use log::log;
use bitcoin_rpc;
use bitcoin_rpc::BitcoinRPCParameter::{self, Any};
#[derive(Serialize, Deserialize, Debug)]
struct RPCCRTResp {
result: String,
}
type BoxFut = Box<Future<Item=Response<Body>, Error=hyper::Error> + Send>;
// TODO: use dummy change addresses?
pub fn create_psbt(rpc_auth: &str, rpc_addr: &str, address: &str, amount: f64, feerate: f64) -> BoxFut {
let a = Any(json!([]));
let b = Any(json!({address: amount}));
//serde_json::from_str(
// &format!("[{{\"{}\":{}}}]", address, amount)
//).unwrap();
let c = Any(json!(0));
let d = Any(json!({"feeRate": feerate}));
let proxied = bitcoin_rpc::get_resp_future_rpc(
"walletcreatefundedpsbt".to_string(),
Some(vec![a, b, c, d]),
rpc_auth,
rpc_addr,
);
return Box::new(proxied);
}
pub fn decode_psbt(rpc_auth: &str, rpc_addr: &str, psbt: &str) -> BoxFut {
let proxied = bitcoin_rpc::get_resp_future_rpc(
"decodepsbt".to_string(),
Some(vec![BitcoinRPCParameter::Str(psbt.to_string())]),
rpc_auth,
rpc_addr,
);
return Box::new(proxied);
}
......@@ -24,6 +24,7 @@ extern crate hyper;
use hyper::{Body, Response};
use hyper::rt::{Future, Stream};
use hyper::header::{HeaderName, HeaderValue};
extern crate serde_json;
extern crate tokio_threadpool;
use self::tokio_threadpool::blocking;
......@@ -38,12 +39,25 @@ pub mod mempoolbins;
pub mod nettotals;
mod peerinfo;
mod whitelist;
mod createpsbt;
use server_get::whitelist::WHITELIST;
use bitcoin_rpc;
use bitcoin_rpc::BitcoinRPCParameter;
#[derive(Serialize, Deserialize, Debug)]
struct RPCCreatePSBTResp {
result: RPCCreatePSBT,
}
#[derive(Serialize, Deserialize, Debug)]
struct RPCCreatePSBT {
psbt: String,
fee: f64,
changepos: u32,
}
fn add_headers(response: &mut Response<Body>, cache_secs: usize) {
let hn = HeaderName::from_lowercase(b"cache-control").unwrap();
let hv = HeaderValue::from_str(
......@@ -377,6 +391,106 @@ pub fn server_get(x: &str, pool: &PgPool, rpc_auth: &str, rpc_addr: &str) -> Box
return Box::new(test);
}
if method == "createpsbt" {
if raw_args.len() != 5 {
eprintln!("{:#?}", raw_args);
*response.body_mut() = Body::from(
"{\"result\": null, \"error\": \"createpsbt/address/amount/feerate\", \"id\": \"na\"}\n"
);
return Box::new(futures::future::ok(response));
}
let address: &str = raw_args[2];
let amount = match raw_args[3].parse::<f64>() {
Ok(x) => x,
Err(_) => {
*response.body_mut() = Body::from(
"{\"result\": null, \"error\": \"amount is not a number\", \"id\": \"na\"}\n"
);
return Box::new(futures::future::ok(response));
},
};
let feerate = match raw_args[4].parse::<f64>() {
Ok(x) => x,
Err(_) => {
*response.body_mut() = Body::from(
"{\"result\": null, \"error\": \"feerate is not a number\", \"id\": \"na\"}\n"
);
return Box::new(futures::future::ok(response));
},
};
let rpc_auth = rpc_auth.to_string();
let rpc_addr = rpc_addr.to_string();
add_headers(&mut response, 1);
let proxied = createpsbt::create_psbt(
&rpc_auth, &rpc_addr, address, amount, feerate
)
.and_then(move |res| {
res
.into_body()
.concat2()
.and_then(move |c| {
let rr: RPCCreatePSBTResp =
match serde_json::from_slice(&c) {
Ok(x) => x,
Err(y) => {
// TODO: distinctly suboptimal
panic!("oh for fuck's sake {}", y);
},
};
let rrr = rr.result;
createpsbt::decode_psbt(
&rpc_auth, &rpc_addr, &rrr.psbt
)
.and_then(move |res| {
res
.into_body()
.concat2()
.map(move |c| {
let j: serde_json::Value =
match serde_json::from_slice(&c) {
Ok(x) => x,
Err(y) => {
// TODO: distinctly suboptimal
panic!("oh for fuck's sake {}", y);
},
};
// seriously
let jr = j.as_object().unwrap()
.get("result").unwrap().as_object().unwrap();
let mut jr = jr.clone();
jr.insert(
"psbt".to_string(),
json!(rrr.psbt)
);
jr.insert(
"fee".to_string(),
json!(rrr.fee)
);
jr.insert(
"changepos".to_string(),
json!(rrr.changepos)
);
let ser = serde_json::to_string(&jr).unwrap();
*response.body_mut() = Body::from(ser);
response
})
})
})
});
return Box::new(proxied);
}
// done with weird custom methods now
let (cache_secs, argument_cap, _) = match WHITELIST.get(method) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment