poa-bridge/bridge/src/api.rs

194 lines
5.0 KiB
Rust
Raw Normal View History

2017-08-11 04:13:27 -07:00
use std::time::Duration;
2017-08-31 08:32:34 -07:00
use serde::de::DeserializeOwned;
use serde_json::Value;
2017-08-13 07:13:03 -07:00
use futures::{Future, Stream, Poll};
2017-08-31 08:32:34 -07:00
use tokio_timer::{Timer, Interval, Timeout};
use web3::{self, api, Transport};
2017-08-13 04:09:50 -07:00
use web3::api::Namespace;
2017-08-31 08:32:34 -07:00
use web3::types::{Log, Filter, H256, H520, U256, FilterBuilder, TransactionRequest, Bytes, Address, CallRequest};
2017-08-11 04:13:27 -07:00
use web3::helpers::CallResult;
2017-08-12 01:55:18 -07:00
use error::{Error, ErrorKind};
2017-08-11 04:13:27 -07:00
2017-08-13 04:09:28 -07:00
/// Imperative alias for web3 function.
2017-08-01 02:36:48 -07:00
pub use web3::confirm::send_transaction_with_confirmation;
2017-08-11 04:13:27 -07:00
2017-08-31 08:32:34 -07:00
/// Wrapper type for `CallResult`
pub struct ApiCall<T, F> {
future: CallResult<T, F>,
message: &'static str,
}
impl<T, F> ApiCall<T, F> {
pub fn message(&self) -> &'static str {
self.message
}
}
impl<T: DeserializeOwned, F: Future<Item = Value, Error = web3::Error>>Future for ApiCall<T, F> {
type Item = T;
type Error = Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
trace!(target: "bridge", "{}", self.message);
self.future.poll().map_err(ErrorKind::Web3).map_err(Into::into)
}
2017-08-11 04:13:27 -07:00
}
2017-08-13 04:09:28 -07:00
/// Imperative wrapper for web3 function.
2017-08-31 08:32:34 -07:00
pub fn logs<T: Transport>(transport: T, filter: &Filter) -> ApiCall<Vec<Log>, T::Out> {
ApiCall {
future: api::Eth::new(transport).logs(filter),
message: "eth_getLogs",
}
2017-08-11 04:13:27 -07:00
}
2017-08-13 04:09:28 -07:00
/// Imperative wrapper for web3 function.
2017-08-31 08:32:34 -07:00
pub fn block_number<T: Transport>(transport: T) -> ApiCall<U256, T::Out> {
ApiCall {
future: api::Eth::new(transport).block_number(),
message: "eth_blockNumber",
}
2017-08-11 04:13:27 -07:00
}
2017-08-13 04:09:28 -07:00
/// Imperative wrapper for web3 function.
2017-08-31 08:32:34 -07:00
pub fn send_transaction<T: Transport>(transport: T, tx: TransactionRequest) -> ApiCall<H256, T::Out> {
ApiCall {
future: api::Eth::new(transport).send_transaction(tx),
message: "eth_sendTransaction",
}
2017-08-12 07:57:07 -07:00
}
2017-08-23 10:09:51 -07:00
/// Imperative wrapper for web3 function.
2017-08-31 08:32:34 -07:00
pub fn call<T: Transport>(transport: T, address: Address, payload: Bytes) -> ApiCall<Bytes, T::Out> {
let future = api::Eth::new(transport).call(CallRequest {
2017-08-24 05:50:48 -07:00
from: None,
to: address,
gas: None,
gas_price: None,
value: None,
data: Some(payload),
2017-08-31 08:32:34 -07:00
}, None);
ApiCall {
future,
message: "eth_call",
}
2017-08-23 10:09:51 -07:00
}
2017-08-31 08:32:34 -07:00
pub fn sign<T: Transport>(transport: T, address: Address, data: Bytes) -> ApiCall<H520, T::Out> {
ApiCall {
future: api::Eth::new(transport).sign(address, data),
message: "eth_sign",
}
2017-08-13 07:13:03 -07:00
}
2017-08-13 04:09:28 -07:00
/// Used for `LogStream` initialization.
2017-08-12 01:55:18 -07:00
pub struct LogStreamInit {
pub after: u64,
pub filter: FilterBuilder,
2017-08-31 08:32:34 -07:00
pub request_timeout: Duration,
2017-08-12 01:55:18 -07:00
pub poll_interval: Duration,
2017-08-13 04:09:28 -07:00
pub confirmations: u64,
2017-08-11 04:13:27 -07:00
}
2017-08-13 04:09:28 -07:00
/// Contains all logs matching `LogStream` filter in inclusive range `[from, to]`.
#[derive(Debug, PartialEq)]
2017-08-12 01:55:18 -07:00
pub struct LogStreamItem {
pub from: u64,
pub to: u64,
pub logs: Vec<Log>,
2017-08-11 04:13:27 -07:00
}
2017-08-13 04:09:28 -07:00
/// Log Stream state.
enum LogStreamState<T: Transport> {
/// Log Stream is waiting for timer to poll.
2017-08-12 01:55:18 -07:00
Wait,
2017-08-25 07:27:55 -07:00
/// Fetching best block number.
2017-08-31 08:32:34 -07:00
FetchBlockNumber(Timeout<ApiCall<U256, T::Out>>),
2017-08-13 04:09:28 -07:00
/// Fetching logs for new best block.
2017-08-12 01:55:18 -07:00
FetchLogs {
from: u64,
to: u64,
2017-08-31 08:32:34 -07:00
future: Timeout<ApiCall<Vec<Log>, T::Out>>,
2017-08-12 01:55:18 -07:00
},
2017-08-13 04:09:28 -07:00
/// All logs has been fetched.
2017-08-12 01:55:18 -07:00
NextItem(Option<LogStreamItem>),
2017-08-11 04:13:27 -07:00
}
2017-08-13 04:09:28 -07:00
/// Creates new `LogStream`.
2017-08-31 08:32:34 -07:00
pub fn log_stream<T: Transport>(transport: T, timer: Timer, init: LogStreamInit) -> LogStream<T> {
2017-08-13 04:09:28 -07:00
LogStream {
transport,
2017-08-31 08:32:34 -07:00
interval: timer.interval(init.poll_interval),
timer,
2017-08-13 04:09:28 -07:00
state: LogStreamState::Wait,
after: init.after,
filter: init.filter,
confirmations: init.confirmations,
2017-08-31 08:32:34 -07:00
request_timeout: init.request_timeout,
2017-08-13 04:09:28 -07:00
}
}
/// Stream of confirmed logs.
2017-08-12 01:55:18 -07:00
pub struct LogStream<T: Transport> {
2017-08-11 04:13:27 -07:00
transport: T,
2017-08-31 08:32:34 -07:00
timer: Timer,
2017-08-12 01:55:18 -07:00
interval: Interval,
state: LogStreamState<T>,
after: u64,
filter: FilterBuilder,
2017-08-13 04:09:28 -07:00
confirmations: u64,
2017-08-31 08:32:34 -07:00
request_timeout: Duration,
2017-08-11 04:13:27 -07:00
}
2017-08-12 01:55:18 -07:00
impl<T: Transport> Stream for LogStream<T> {
type Item = LogStreamItem;
type Error = Error;
2017-08-11 04:13:27 -07:00
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
loop {
let next_state = match self.state {
2017-08-12 11:03:48 -07:00
LogStreamState::Wait => {
let _ = try_stream!(self.interval.poll());
2017-08-31 08:32:34 -07:00
LogStreamState::FetchBlockNumber(self.timer.timeout(block_number(&self.transport), self.request_timeout))
2017-08-11 04:13:27 -07:00
},
2017-08-12 01:55:18 -07:00
LogStreamState::FetchBlockNumber(ref mut future) => {
2017-08-31 08:32:34 -07:00
let last_block = try_ready!(future.poll()).low_u64();
2017-08-13 04:09:28 -07:00
let last_confirmed_block = last_block.saturating_sub(self.confirmations);
2017-08-12 01:55:18 -07:00
if last_confirmed_block > self.after {
let from = self.after + 1;
let filter = self.filter.clone()
.from_block(from.into())
.to_block(last_confirmed_block.into())
.build();
LogStreamState::FetchLogs {
from: from,
to: last_confirmed_block,
2017-08-31 08:32:34 -07:00
future: self.timer.timeout(logs(&self.transport, &filter), self.request_timeout),
2017-08-12 01:55:18 -07:00
}
} else {
LogStreamState::Wait
}
2017-08-11 04:13:27 -07:00
},
2017-08-12 01:55:18 -07:00
LogStreamState::FetchLogs { ref mut future, from, to } => {
2017-08-31 08:32:34 -07:00
let logs = try_ready!(future.poll());
2017-08-12 01:55:18 -07:00
let item = LogStreamItem {
from,
to,
logs,
};
self.after = to;
LogStreamState::NextItem(Some(item))
},
LogStreamState::NextItem(ref mut item) => match item.take() {
None => LogStreamState::Wait,
2017-08-13 04:09:50 -07:00
some => return Ok(some.into()),
2017-08-11 04:13:27 -07:00
},
};
2017-08-12 01:55:18 -07:00
2017-08-11 04:13:27 -07:00
self.state = next_state;
}
}
}