2018-03-05 22:33:44 +03:00
|
|
|
// Copyright 2018 The Grin Developers
|
2017-10-27 20:36:03 +03:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2018-02-28 20:56:09 +03:00
|
|
|
use std::time;
|
2017-10-27 20:36:03 +03:00
|
|
|
use std::ops::FnMut;
|
|
|
|
|
|
|
|
use futures::{Future, Stream};
|
2018-02-28 20:56:09 +03:00
|
|
|
use failure::ResultExt;
|
2017-10-27 20:36:03 +03:00
|
|
|
use hyper;
|
|
|
|
use hyper::{Method, Request};
|
|
|
|
use hyper::header::ContentType;
|
|
|
|
use tokio_core::reactor;
|
|
|
|
use tokio_retry::Retry;
|
|
|
|
use tokio_retry::strategy::FibonacciBackoff;
|
|
|
|
use serde_json;
|
|
|
|
|
|
|
|
use types::*;
|
|
|
|
use util::LOGGER;
|
2018-02-28 20:56:09 +03:00
|
|
|
use std::io;
|
2017-10-27 20:36:03 +03:00
|
|
|
|
|
|
|
/// Call the wallet API to create a coinbase output for the given block_fees.
|
|
|
|
/// Will retry based on default "retry forever with backoff" behavior.
|
|
|
|
pub fn create_coinbase(url: &str, block_fees: &BlockFees) -> Result<CbData, Error> {
|
2018-01-30 22:44:08 +03:00
|
|
|
let mut has_error = false;
|
|
|
|
|
2017-10-27 20:36:03 +03:00
|
|
|
retry_backoff_forever(|| {
|
|
|
|
let res = single_create_coinbase(&url, &block_fees);
|
|
|
|
if let Err(_) = res {
|
2018-01-30 22:44:08 +03:00
|
|
|
has_error = true;
|
2017-11-01 02:32:33 +03:00
|
|
|
error!(
|
|
|
|
LOGGER,
|
2018-03-04 03:19:54 +03:00
|
|
|
"Failed to get coinbase from {}. Run grin wallet listen", url
|
2017-11-01 02:32:33 +03:00
|
|
|
);
|
2017-10-27 20:36:03 +03:00
|
|
|
}
|
2018-01-30 22:44:08 +03:00
|
|
|
if has_error {
|
|
|
|
error!(LOGGER, "Successfully received coinbase from {}", url);
|
|
|
|
}
|
2017-10-27 20:36:03 +03:00
|
|
|
res
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Runs the specified function wrapped in some basic retry logic.
|
|
|
|
fn retry_backoff_forever<F, R>(f: F) -> Result<R, Error>
|
2017-11-01 02:32:33 +03:00
|
|
|
where
|
|
|
|
F: FnMut() -> Result<R, Error>,
|
2017-10-27 20:36:03 +03:00
|
|
|
{
|
2018-03-04 03:19:54 +03:00
|
|
|
let mut core =
|
|
|
|
reactor::Core::new().context(ErrorKind::GenericError("Could not create reactor"))?;
|
2017-11-01 02:32:33 +03:00
|
|
|
let retry_strategy =
|
|
|
|
FibonacciBackoff::from_millis(100).max_delay(time::Duration::from_secs(10));
|
2017-10-27 20:36:03 +03:00
|
|
|
let retry_future = Retry::spawn(core.handle(), retry_strategy, f);
|
|
|
|
let res = core.run(retry_future).unwrap();
|
|
|
|
Ok(res)
|
|
|
|
}
|
|
|
|
|
2018-03-20 06:18:54 +03:00
|
|
|
pub fn send_partial_tx(url: &str, partial_tx: &PartialTx, fluff: bool) -> Result<PartialTx, Error> {
|
|
|
|
single_send_partial_tx(url, partial_tx, fluff)
|
2017-11-01 21:32:34 +03:00
|
|
|
}
|
|
|
|
|
2018-03-20 06:18:54 +03:00
|
|
|
fn single_send_partial_tx(
|
|
|
|
url: &str,
|
|
|
|
partial_tx: &PartialTx,
|
|
|
|
fluff: bool,
|
|
|
|
) -> Result<PartialTx, Error> {
|
2018-03-04 03:19:54 +03:00
|
|
|
let mut core = reactor::Core::new().context(ErrorKind::Hyper)?;
|
2017-11-01 21:32:34 +03:00
|
|
|
let client = hyper::Client::new(&core.handle());
|
|
|
|
|
2018-03-20 06:18:54 +03:00
|
|
|
// In case we want to do an express send
|
|
|
|
let mut url_pool = url.to_owned();
|
|
|
|
if fluff {
|
|
|
|
url_pool = format!("{}{}", url, "?fluff");
|
|
|
|
}
|
|
|
|
|
2018-03-04 03:19:54 +03:00
|
|
|
let mut req = Request::new(
|
|
|
|
Method::Post,
|
2018-03-20 06:18:54 +03:00
|
|
|
url_pool.parse::<hyper::Uri>().context(ErrorKind::Hyper)?,
|
2018-03-04 03:19:54 +03:00
|
|
|
);
|
2017-11-01 21:32:34 +03:00
|
|
|
req.headers_mut().set(ContentType::json());
|
2018-02-28 20:56:09 +03:00
|
|
|
let json = serde_json::to_string(&partial_tx).context(ErrorKind::Hyper)?;
|
2017-11-01 21:32:34 +03:00
|
|
|
req.set_body(json);
|
|
|
|
|
2018-01-10 22:36:27 +03:00
|
|
|
let work = client.request(req).and_then(|res| {
|
|
|
|
res.body().concat2().and_then(move |body| {
|
2018-03-04 03:19:54 +03:00
|
|
|
let partial_tx: PartialTx =
|
|
|
|
serde_json::from_slice(&body).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
2018-01-10 22:36:27 +03:00
|
|
|
Ok(partial_tx)
|
|
|
|
})
|
|
|
|
});
|
2018-03-04 03:19:54 +03:00
|
|
|
let res = core.run(work).context(ErrorKind::Hyper)?;
|
|
|
|
Ok(res)
|
2017-11-01 21:32:34 +03:00
|
|
|
}
|
|
|
|
|
2017-10-27 20:36:03 +03:00
|
|
|
/// 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> {
|
2018-03-04 03:19:54 +03:00
|
|
|
let mut core =
|
|
|
|
reactor::Core::new().context(ErrorKind::GenericError("Could not create reactor"))?;
|
2017-10-27 20:36:03 +03:00
|
|
|
let client = hyper::Client::new(&core.handle());
|
|
|
|
|
2018-03-04 03:19:54 +03:00
|
|
|
let mut req = Request::new(
|
|
|
|
Method::Post,
|
|
|
|
url.parse::<hyper::Uri>().context(ErrorKind::Uri)?,
|
|
|
|
);
|
2017-10-27 20:36:03 +03:00
|
|
|
req.headers_mut().set(ContentType::json());
|
2018-02-28 20:56:09 +03:00
|
|
|
let json = serde_json::to_string(&block_fees).context(ErrorKind::Format)?;
|
2017-10-27 20:36:03 +03:00
|
|
|
req.set_body(json);
|
|
|
|
|
|
|
|
let work = client.request(req).and_then(|res| {
|
|
|
|
res.body().concat2().and_then(move |body| {
|
2017-11-01 02:32:33 +03:00
|
|
|
let coinbase: CbData =
|
|
|
|
serde_json::from_slice(&body).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
2017-10-27 20:36:03 +03:00
|
|
|
Ok(coinbase)
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
2018-03-04 03:19:54 +03:00
|
|
|
let res = core.run(work)
|
|
|
|
.context(ErrorKind::GenericError("Could not run core"))?;
|
2017-10-27 20:36:03 +03:00
|
|
|
Ok(res)
|
|
|
|
}
|