Separate RPC serialization from implementation (#2072)
* add auto-args deserialization for RPC * make block param member public * change BlockParam to a more generic Trailing<T> mechanism * define work type * build_rpc_trait macro, implement eth protocol * fix up tests * move eth_filter API to new macro
This commit is contained in:
parent
84ba75f7cb
commit
ff0be9f361
171
rpc/src/v1/helpers/auto_args.rs
Normal file
171
rpc/src/v1/helpers/auto_args.rs
Normal file
@ -0,0 +1,171 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity 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 General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Automatically serialize and deserialize parameters around a strongly-typed function.
|
||||
|
||||
// because we reuse the type names as idents in the macros as a dirty hack to
|
||||
// work around `concat_idents!` being unstable.
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use super::errors;
|
||||
|
||||
use jsonrpc_core::{Error, Params, Value, from_params, to_value};
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
/// Auto-generates an RPC trait from trait definition.
|
||||
///
|
||||
/// This just copies out all the methods, docs, and adds another
|
||||
/// function `to_delegate` which will automatically wrap each strongly-typed
|
||||
/// function in a wrapper which handles parameter and output type serialization.
|
||||
///
|
||||
/// Every function must have a `#[name("rpc_nameHere")]` attribute after
|
||||
/// its documentation, and no other attributes. All function names are
|
||||
/// allowed except for `to_delegate`, which is auto-generated.
|
||||
macro_rules! build_rpc_trait {
|
||||
(
|
||||
$(#[$t_attr: meta])*
|
||||
pub trait $name: ident {
|
||||
$(
|
||||
$(#[doc=$m_doc: expr])* #[name($rpc_name: expr)]
|
||||
fn $method: ident (&self $(, $param: ty)*) -> $out: ty;
|
||||
)*
|
||||
}
|
||||
) => {
|
||||
$(#[$t_attr])*
|
||||
pub trait $name: Sized + Send + Sync + 'static {
|
||||
$(
|
||||
$(#[doc=$m_doc])*
|
||||
fn $method(&self $(, $param)*) -> $out;
|
||||
)*
|
||||
|
||||
/// Transform this into an `IoDelegate`, automatically wrapping
|
||||
/// the parameters.
|
||||
fn to_delegate(self) -> ::jsonrpc_core::IoDelegate<Self> {
|
||||
let mut del = ::jsonrpc_core::IoDelegate::new(self.into());
|
||||
$(
|
||||
del.add_method($rpc_name, move |base, params| {
|
||||
($name::$method as fn(&_ $(, $param)*) -> $out).wrap_rpc(base, params)
|
||||
});
|
||||
)*
|
||||
del
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper type without an implementation of `Deserialize`
|
||||
/// which allows a special implementation of `Wrap` for functions
|
||||
/// that take a trailing default parameter.
|
||||
pub struct Trailing<T: Default + Deserialize>(pub T);
|
||||
|
||||
/// Wrapper trait for synchronous RPC functions.
|
||||
pub trait Wrap<B: Send + Sync + 'static> {
|
||||
fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error>;
|
||||
}
|
||||
|
||||
// special impl for no parameters.
|
||||
impl<B, OUT> Wrap<B> for fn(&B) -> Result<OUT, Error>
|
||||
where B: Send + Sync + 'static, OUT: Serialize
|
||||
{
|
||||
fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error> {
|
||||
::v1::helpers::params::expect_no_params(params)
|
||||
.and_then(|()| (self)(base))
|
||||
.map(to_value)
|
||||
}
|
||||
}
|
||||
|
||||
// creates a wrapper implementation which deserializes the parameters,
|
||||
// calls the function with concrete type, and serializes the output.
|
||||
macro_rules! wrap {
|
||||
($($x: ident),+) => {
|
||||
impl <
|
||||
BASE: Send + Sync + 'static,
|
||||
OUT: Serialize,
|
||||
$($x: Deserialize,)+
|
||||
> Wrap<BASE> for fn(&BASE, $($x,)+) -> Result<OUT, Error> {
|
||||
fn wrap_rpc(&self, base: &BASE, params: Params) -> Result<Value, Error> {
|
||||
from_params::<($($x,)+)>(params).and_then(|($($x,)+)| {
|
||||
(self)(base, $($x,)+)
|
||||
}).map(to_value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// special impl for no parameters other than block parameter.
|
||||
impl<B, OUT, T> Wrap<B> for fn(&B, Trailing<T>) -> Result<OUT, Error>
|
||||
where B: Send + Sync + 'static, OUT: Serialize, T: Default + Deserialize
|
||||
{
|
||||
fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error> {
|
||||
let len = match params {
|
||||
Params::Array(ref v) => v.len(),
|
||||
Params::None => 0,
|
||||
_ => return Err(errors::invalid_params("not an array", "")),
|
||||
};
|
||||
|
||||
let (id,) = match len {
|
||||
0 => (T::default(),),
|
||||
1 => try!(from_params::<(T,)>(params)),
|
||||
_ => return Err(Error::invalid_params()),
|
||||
};
|
||||
|
||||
(self)(base, Trailing(id)).map(to_value)
|
||||
}
|
||||
}
|
||||
|
||||
// similar to `wrap!`, but handles a single default trailing parameter
|
||||
// accepts an additional argument indicating the number of non-trailing parameters.
|
||||
macro_rules! wrap_with_trailing {
|
||||
($num: expr, $($x: ident),+) => {
|
||||
impl <
|
||||
BASE: Send + Sync + 'static,
|
||||
OUT: Serialize,
|
||||
$($x: Deserialize,)+
|
||||
TRAILING: Default + Deserialize,
|
||||
> Wrap<BASE> for fn(&BASE, $($x,)+ Trailing<TRAILING>) -> Result<OUT, Error> {
|
||||
fn wrap_rpc(&self, base: &BASE, params: Params) -> Result<Value, Error> {
|
||||
let len = match params {
|
||||
Params::Array(ref v) => v.len(),
|
||||
Params::None => 0,
|
||||
_ => return Err(errors::invalid_params("not an array", "")),
|
||||
};
|
||||
|
||||
let params = match len - $num {
|
||||
0 => from_params::<($($x,)+)>(params)
|
||||
.map(|($($x,)+)| ($($x,)+ TRAILING::default())),
|
||||
1 => from_params::<($($x,)+ TRAILING)>(params)
|
||||
.map(|($($x,)+ id)| ($($x,)+ id)),
|
||||
_ => Err(Error::invalid_params()),
|
||||
};
|
||||
|
||||
let ($($x,)+ id) = try!(params);
|
||||
(self)(base, $($x,)+ Trailing(id)).map(to_value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wrap!(A, B, C, D, E);
|
||||
wrap!(A, B, C, D);
|
||||
wrap!(A, B, C);
|
||||
wrap!(A, B);
|
||||
wrap!(A);
|
||||
|
||||
wrap_with_trailing!(5, A, B, C, D, E);
|
||||
wrap_with_trailing!(4, A, B, C, D);
|
||||
wrap_with_trailing!(3, A, B, C);
|
||||
wrap_with_trailing!(2, A, B);
|
||||
wrap_with_trailing!(1, A);
|
@ -41,7 +41,7 @@ fn prepare_transaction<C, M>(client: &C, miner: &M, request: TransactionRequest)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result<Value, Error>
|
||||
pub fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result<RpcH256, Error>
|
||||
where C: MiningBlockChainClient, M: MinerService {
|
||||
let hash = RpcH256::from(signed_transaction.hash());
|
||||
|
||||
@ -49,7 +49,7 @@ pub fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: Sig
|
||||
|
||||
import
|
||||
.map_err(errors::from_transaction_error)
|
||||
.map(|_| to_value(&hash))
|
||||
.map(|_| hash)
|
||||
}
|
||||
|
||||
pub fn signature_with_password(accounts: &AccountProvider, address: Address, hash: H256, pass: String) -> Result<Value, Error> {
|
||||
@ -70,7 +70,7 @@ pub fn unlock_sign_and_dispatch<C, M>(client: &C, miner: &M, request: Transactio
|
||||
};
|
||||
|
||||
trace!(target: "miner", "send_transaction: dispatching tx: {}", ::rlp::encode(&signed_transaction).to_vec().pretty());
|
||||
dispatch_transaction(&*client, &*miner, signed_transaction)
|
||||
dispatch_transaction(&*client, &*miner, signed_transaction).map(to_value)
|
||||
}
|
||||
|
||||
pub fn sign_and_dispatch<C, M>(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, address: Address) -> Result<Value, Error>
|
||||
@ -84,7 +84,7 @@ pub fn sign_and_dispatch<C, M>(client: &C, miner: &M, request: TransactionReques
|
||||
};
|
||||
|
||||
trace!(target: "miner", "send_transaction: dispatching tx: {}", ::rlp::encode(&signed_transaction).to_vec().pretty());
|
||||
dispatch_transaction(&*client, &*miner, signed_transaction)
|
||||
dispatch_transaction(&*client, &*miner, signed_transaction).map(to_value)
|
||||
}
|
||||
|
||||
pub fn default_gas_price<C, M>(client: &C, miner: &M) -> U256 where C: MiningBlockChainClient, M: MinerService {
|
||||
|
@ -14,10 +14,15 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#[macro_use]
|
||||
pub mod auto_args;
|
||||
|
||||
#[macro_use]
|
||||
pub mod errors;
|
||||
|
||||
pub mod dispatch;
|
||||
pub mod params;
|
||||
|
||||
mod poll_manager;
|
||||
mod poll_filter;
|
||||
mod requests;
|
||||
|
@ -36,14 +36,6 @@ pub fn params_len(params: &Params) -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize request parameters with optional second parameter `BlockNumber` defaulting to `BlockNumber::Latest`.
|
||||
pub fn from_params_default_second<F>(params: Params) -> Result<(F, BlockNumber, ), Error> where F: serde::de::Deserialize {
|
||||
match params_len(¶ms) {
|
||||
1 => from_params::<(F, )>(params).map(|(f,)| (f, BlockNumber::Latest)),
|
||||
_ => from_params::<(F, BlockNumber)>(params),
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize request parameters with optional third parameter `BlockNumber` defaulting to `BlockNumber::Latest`.
|
||||
pub fn from_params_default_third<F1, F2>(params: Params) -> Result<(F1, F2, BlockNumber, ), Error> where F1: serde::de::Deserialize, F2: serde::de::Deserialize {
|
||||
match params_len(¶ms) {
|
||||
|
@ -42,10 +42,14 @@ use ethcore::log_entry::LogEntry;
|
||||
use ethcore::filter::Filter as EthcoreFilter;
|
||||
use self::ethash::SeedHashCompute;
|
||||
use v1::traits::Eth;
|
||||
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, CallRequest, Index, Filter, Log, Receipt, H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256};
|
||||
use v1::types::{
|
||||
Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo,
|
||||
Transaction, CallRequest, Index, Filter, Log, Receipt, Work,
|
||||
H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256,
|
||||
};
|
||||
use v1::helpers::{CallRequest as CRequest, errors, limit_logs};
|
||||
use v1::helpers::dispatch::{default_gas_price, dispatch_transaction};
|
||||
use v1::helpers::params::{expect_no_params, from_params_default_second, from_params_default_third};
|
||||
use v1::helpers::auto_args::Trailing;
|
||||
|
||||
/// Eth RPC options
|
||||
pub struct EthClientOptions {
|
||||
@ -100,7 +104,7 @@ impl<C, S: ?Sized, M, EM> EthClient<C, S, M, EM> where
|
||||
}
|
||||
}
|
||||
|
||||
fn block(&self, id: BlockID, include_txs: bool) -> Result<Value, Error> {
|
||||
fn block(&self, id: BlockID, include_txs: bool) -> Result<Option<Block>, Error> {
|
||||
let client = take_weak!(self.client);
|
||||
match (client.block(id.clone()), client.block_total_difficulty(id)) {
|
||||
(Some(bytes), Some(total_difficulty)) => {
|
||||
@ -131,28 +135,28 @@ impl<C, S: ?Sized, M, EM> EthClient<C, S, M, EM> where
|
||||
},
|
||||
extra_data: Bytes::new(view.extra_data())
|
||||
};
|
||||
Ok(to_value(&block))
|
||||
Ok(Some(block))
|
||||
},
|
||||
_ => Ok(Value::Null)
|
||||
_ => Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn transaction(&self, id: TransactionID) -> Result<Value, Error> {
|
||||
fn transaction(&self, id: TransactionID) -> Result<Option<Transaction>, Error> {
|
||||
match take_weak!(self.client).transaction(id) {
|
||||
Some(t) => Ok(to_value(&Transaction::from(t))),
|
||||
None => Ok(Value::Null)
|
||||
Some(t) => Ok(Some(Transaction::from(t))),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn uncle(&self, id: UncleID) -> Result<Value, Error> {
|
||||
fn uncle(&self, id: UncleID) -> Result<Option<Block>, Error> {
|
||||
let client = take_weak!(self.client);
|
||||
let uncle: BlockHeader = match client.uncle(id) {
|
||||
Some(rlp) => rlp::decode(&rlp),
|
||||
None => { return Ok(Value::Null); }
|
||||
None => { return Ok(None); }
|
||||
};
|
||||
let parent_difficulty = match client.block_total_difficulty(BlockID::Hash(uncle.parent_hash().clone())) {
|
||||
Some(difficulty) => difficulty,
|
||||
None => { return Ok(Value::Null); }
|
||||
None => { return Ok(None); }
|
||||
};
|
||||
|
||||
let block = Block {
|
||||
@ -177,7 +181,7 @@ impl<C, S: ?Sized, M, EM> EthClient<C, S, M, EM> where
|
||||
uncles: vec![],
|
||||
transactions: BlockTransactions::Hashes(vec![]),
|
||||
};
|
||||
Ok(to_value(&block))
|
||||
Ok(Some(block))
|
||||
}
|
||||
|
||||
fn sign_call(&self, request: CRequest) -> Result<SignedTransaction, Error> {
|
||||
@ -240,20 +244,19 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
M: MinerService + 'static,
|
||||
EM: ExternalMinerService + 'static {
|
||||
|
||||
fn protocol_version(&self, params: Params) -> Result<Value, Error> {
|
||||
fn protocol_version(&self) -> Result<String, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
|
||||
Ok(Value::String(format!("{}", take_weak!(self.sync).status().protocol_version).to_owned()))
|
||||
let version = take_weak!(self.sync).status().protocol_version.to_owned();
|
||||
Ok(format!("{}", version))
|
||||
}
|
||||
|
||||
fn syncing(&self, params: Params) -> Result<Value, Error> {
|
||||
fn syncing(&self) -> Result<SyncStatus, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
|
||||
let status = take_weak!(self.sync).status();
|
||||
let res = match status.state {
|
||||
SyncState::Idle => SyncStatus::None,
|
||||
match status.state {
|
||||
SyncState::Idle => Ok(SyncStatus::None),
|
||||
SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks | SyncState::ChainHead
|
||||
| SyncState::SnapshotManifest | SyncState::SnapshotData | SyncState::SnapshotWaiting => {
|
||||
let current_block = U256::from(take_weak!(self.client).chain_info().best_block_number);
|
||||
@ -265,240 +268,222 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
current_block: current_block.into(),
|
||||
highest_block: highest_block.into(),
|
||||
};
|
||||
SyncStatus::Info(info)
|
||||
Ok(SyncStatus::Info(info))
|
||||
} else {
|
||||
SyncStatus::None
|
||||
Ok(SyncStatus::None)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(to_value(&res))
|
||||
}
|
||||
|
||||
fn author(&self, params: Params) -> Result<Value, Error> {
|
||||
fn author(&self) -> Result<RpcH160, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
|
||||
Ok(to_value(&RpcH160::from(take_weak!(self.miner).author())))
|
||||
Ok(RpcH160::from(take_weak!(self.miner).author()))
|
||||
}
|
||||
|
||||
fn is_mining(&self, params: Params) -> Result<Value, Error> {
|
||||
fn is_mining(&self) -> Result<bool, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
|
||||
Ok(to_value(&(take_weak!(self.miner).is_sealing())))
|
||||
Ok(take_weak!(self.miner).is_sealing())
|
||||
}
|
||||
|
||||
fn hashrate(&self, params: Params) -> Result<Value, Error> {
|
||||
fn hashrate(&self) -> Result<RpcU256, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
|
||||
Ok(to_value(&RpcU256::from(self.external_miner.hashrate())))
|
||||
Ok(RpcU256::from(self.external_miner.hashrate()))
|
||||
}
|
||||
|
||||
fn gas_price(&self, params: Params) -> Result<Value, Error> {
|
||||
fn gas_price(&self) -> Result<RpcU256, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
|
||||
let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
|
||||
Ok(to_value(&RpcU256::from(default_gas_price(&*client, &*miner))))
|
||||
Ok(RpcU256::from(default_gas_price(&*client, &*miner)))
|
||||
}
|
||||
|
||||
fn accounts(&self, params: Params) -> Result<Value, Error> {
|
||||
fn accounts(&self) -> Result<Vec<RpcH160>, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
|
||||
let store = take_weak!(self.accounts);
|
||||
let accounts = try!(store.accounts().map_err(|e| errors::internal("Could not fetch accounts.", e)));
|
||||
Ok(to_value(&accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>()))
|
||||
Ok(accounts.into_iter().map(Into::into).collect())
|
||||
}
|
||||
|
||||
fn block_number(&self, params: Params) -> Result<Value, Error> {
|
||||
fn block_number(&self) -> Result<RpcU256, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
|
||||
Ok(to_value(&RpcU256::from(take_weak!(self.client).chain_info().best_block_number)))
|
||||
Ok(RpcU256::from(take_weak!(self.client).chain_info().best_block_number))
|
||||
}
|
||||
|
||||
fn balance(&self, params: Params) -> Result<Value, Error> {
|
||||
fn balance(&self, address: RpcH160, num: Trailing<BlockNumber>) -> Result<RpcU256, Error> {
|
||||
try!(self.active());
|
||||
from_params_default_second(params)
|
||||
.and_then(|(address, block_number,)| {
|
||||
let address: Address = RpcH160::into(address);
|
||||
match block_number {
|
||||
BlockNumber::Pending => Ok(to_value(&RpcU256::from(take_weak!(self.miner).balance(&*take_weak!(self.client), &address)))),
|
||||
|
||||
let address = address.into();
|
||||
match num.0 {
|
||||
BlockNumber::Pending => Ok(take_weak!(self.miner).balance(&*take_weak!(self.client), &address).into()),
|
||||
id => match take_weak!(self.client).balance(&address, id.into()) {
|
||||
Some(balance) => Ok(to_value(&RpcU256::from(balance))),
|
||||
Some(balance) => Ok(balance.into()),
|
||||
None => Err(errors::state_pruned()),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn storage_at(&self, params: Params) -> Result<Value, Error> {
|
||||
fn storage_at(&self, address: RpcH160, pos: RpcU256, num: Trailing<BlockNumber>) -> Result<RpcH256, Error> {
|
||||
try!(self.active());
|
||||
from_params_default_third::<RpcH160, RpcU256>(params)
|
||||
.and_then(|(address, position, block_number,)| {
|
||||
let address: Address = RpcH160::into(address);
|
||||
let position: U256 = RpcU256::into(position);
|
||||
match block_number {
|
||||
BlockNumber::Pending => Ok(to_value(&RpcU256::from(take_weak!(self.miner).storage_at(&*take_weak!(self.client), &address, &H256::from(position))))),
|
||||
let position: U256 = RpcU256::into(pos);
|
||||
match num.0 {
|
||||
BlockNumber::Pending => Ok(take_weak!(self.miner).storage_at(&*take_weak!(self.client), &address, &H256::from(position)).into()),
|
||||
id => match take_weak!(self.client).storage_at(&address, &H256::from(position), id.into()) {
|
||||
Some(s) => Ok(to_value(&RpcH256::from(s))),
|
||||
Some(s) => Ok(s.into()),
|
||||
None => Err(errors::state_pruned()),
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
fn transaction_count(&self, params: Params) -> Result<Value, Error> {
|
||||
fn transaction_count(&self, address: RpcH160, num: Trailing<BlockNumber>) -> Result<RpcU256, Error> {
|
||||
try!(self.active());
|
||||
from_params_default_second(params)
|
||||
.and_then(|(address, block_number,)| {
|
||||
|
||||
let address: Address = RpcH160::into(address);
|
||||
match block_number {
|
||||
BlockNumber::Pending => Ok(to_value(&RpcU256::from(take_weak!(self.miner).nonce(&*take_weak!(self.client), &address)))),
|
||||
match num.0 {
|
||||
BlockNumber::Pending => Ok(take_weak!(self.miner).nonce(&*take_weak!(self.client), &address).into()),
|
||||
id => match take_weak!(self.client).nonce(&address, id.into()) {
|
||||
Some(nonce) => Ok(to_value(&RpcU256::from(nonce))),
|
||||
Some(nonce) => Ok(nonce.into()),
|
||||
None => Err(errors::state_pruned()),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn block_transaction_count_by_hash(&self, params: Params) -> Result<Value, Error> {
|
||||
fn block_transaction_count_by_hash(&self, hash: RpcH256) -> Result<Option<RpcU256>, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(RpcH256,)>(params)
|
||||
.and_then(|(hash,)| // match
|
||||
Ok(
|
||||
take_weak!(self.client).block(BlockID::Hash(hash.into()))
|
||||
.map_or(Ok(Value::Null), |bytes| Ok(to_value(&RpcU256::from(BlockView::new(&bytes).transactions_count())))))
|
||||
.map(|bytes| BlockView::new(&bytes).transactions_count().into())
|
||||
)
|
||||
}
|
||||
|
||||
fn block_transaction_count_by_number(&self, params: Params) -> Result<Value, Error> {
|
||||
fn block_transaction_count_by_number(&self, num: BlockNumber) -> Result<Option<RpcU256>, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(BlockNumber,)>(params)
|
||||
.and_then(|(block_number,)| match block_number {
|
||||
BlockNumber::Pending => Ok(to_value(
|
||||
&RpcU256::from(take_weak!(self.miner).status().transactions_in_pending_block)
|
||||
|
||||
match num {
|
||||
BlockNumber::Pending => Ok(Some(
|
||||
take_weak!(self.miner).status().transactions_in_pending_block.into()
|
||||
)),
|
||||
_ => take_weak!(self.client).block(block_number.into())
|
||||
.map_or(Ok(Value::Null), |bytes| Ok(to_value(&RpcU256::from(BlockView::new(&bytes).transactions_count()))))
|
||||
})
|
||||
_ => Ok(
|
||||
take_weak!(self.client).block(num.into())
|
||||
.map(|bytes| BlockView::new(&bytes).transactions_count().into())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn block_uncles_count_by_hash(&self, params: Params) -> Result<Value, Error> {
|
||||
fn block_uncles_count_by_hash(&self, hash: RpcH256) -> Result<Option<RpcU256>, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(RpcH256,)>(params)
|
||||
.and_then(|(hash,)|
|
||||
|
||||
Ok(
|
||||
take_weak!(self.client).block(BlockID::Hash(hash.into()))
|
||||
.map_or(Ok(Value::Null), |bytes| Ok(to_value(&RpcU256::from(BlockView::new(&bytes).uncles_count())))))
|
||||
.map(|bytes| BlockView::new(&bytes).uncles_count().into())
|
||||
)
|
||||
}
|
||||
|
||||
fn block_uncles_count_by_number(&self, params: Params) -> Result<Value, Error> {
|
||||
fn block_uncles_count_by_number(&self, num: BlockNumber) -> Result<Option<RpcU256>, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(BlockNumber,)>(params)
|
||||
.and_then(|(block_number,)| match block_number {
|
||||
BlockNumber::Pending => Ok(to_value(&RpcU256::from(0))),
|
||||
_ => take_weak!(self.client).block(block_number.into())
|
||||
.map_or(Ok(Value::Null), |bytes| Ok(to_value(&RpcU256::from(BlockView::new(&bytes).uncles_count()))))
|
||||
})
|
||||
|
||||
match num {
|
||||
BlockNumber::Pending => Ok(Some(0.into())),
|
||||
_ => Ok(
|
||||
take_weak!(self.client).block(num.into())
|
||||
.map(|bytes| BlockView::new(&bytes).uncles_count().into())
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn code_at(&self, params: Params) -> Result<Value, Error> {
|
||||
fn code_at(&self, address: RpcH160, num: Trailing<BlockNumber>) -> Result<Bytes, Error> {
|
||||
try!(self.active());
|
||||
from_params_default_second(params)
|
||||
.and_then(|(address, block_number,)| {
|
||||
|
||||
let address: Address = RpcH160::into(address);
|
||||
match block_number {
|
||||
BlockNumber::Pending => Ok(to_value(&take_weak!(self.miner).code(&*take_weak!(self.client), &address).map_or_else(Bytes::default, Bytes::new))),
|
||||
_ => match take_weak!(self.client).code(&address, block_number.into()) {
|
||||
Some(code) => Ok(to_value(&code.map_or_else(Bytes::default, Bytes::new))),
|
||||
match num.0 {
|
||||
BlockNumber::Pending => Ok(take_weak!(self.miner).code(&*take_weak!(self.client), &address).map_or_else(Bytes::default, Bytes::new)),
|
||||
_ => match take_weak!(self.client).code(&address, num.0.into()) {
|
||||
Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)),
|
||||
None => Err(errors::state_pruned()),
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn block_by_hash(&self, params: Params) -> Result<Value, Error> {
|
||||
fn block_by_hash(&self, hash: RpcH256, include_txs: bool) -> Result<Option<Block>, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(RpcH256, bool)>(params)
|
||||
.and_then(|(hash, include_txs)| self.block(BlockID::Hash(hash.into()), include_txs))
|
||||
|
||||
self.block(BlockID::Hash(hash.into()), include_txs)
|
||||
}
|
||||
|
||||
fn block_by_number(&self, params: Params) -> Result<Value, Error> {
|
||||
fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> Result<Option<Block>, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(BlockNumber, bool)>(params)
|
||||
.and_then(|(number, include_txs)| self.block(number.into(), include_txs))
|
||||
|
||||
self.block(num.into(), include_txs)
|
||||
}
|
||||
|
||||
fn transaction_by_hash(&self, params: Params) -> Result<Value, Error> {
|
||||
fn transaction_by_hash(&self, hash: RpcH256) -> Result<Option<Transaction>, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(RpcH256,)>(params)
|
||||
.and_then(|(hash,)| {
|
||||
|
||||
let miner = take_weak!(self.miner);
|
||||
let hash: H256 = hash.into();
|
||||
match miner.transaction(&hash) {
|
||||
Some(pending_tx) => Ok(to_value(&Transaction::from(pending_tx))),
|
||||
Some(pending_tx) => Ok(Some(pending_tx.into())),
|
||||
None => self.transaction(TransactionID::Hash(hash))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn transaction_by_block_hash_and_index(&self, params: Params) -> Result<Value, Error> {
|
||||
fn transaction_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> Result<Option<Transaction>, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(RpcH256, Index)>(params)
|
||||
.and_then(|(hash, index)| self.transaction(TransactionID::Location(BlockID::Hash(hash.into()), index.value())))
|
||||
|
||||
self.transaction(TransactionID::Location(BlockID::Hash(hash.into()), index.value()))
|
||||
}
|
||||
|
||||
fn transaction_by_block_number_and_index(&self, params: Params) -> Result<Value, Error> {
|
||||
fn transaction_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> Result<Option<Transaction>, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(BlockNumber, Index)>(params)
|
||||
.and_then(|(number, index)| self.transaction(TransactionID::Location(number.into(), index.value())))
|
||||
|
||||
self.transaction(TransactionID::Location(num.into(), index.value()))
|
||||
}
|
||||
|
||||
fn transaction_receipt(&self, params: Params) -> Result<Value, Error> {
|
||||
fn transaction_receipt(&self, hash: RpcH256) -> Result<Option<Receipt>, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(RpcH256,)>(params)
|
||||
.and_then(|(hash,)| {
|
||||
|
||||
let miner = take_weak!(self.miner);
|
||||
let hash: H256 = hash.into();
|
||||
match (miner.pending_receipt(&hash), self.options.allow_pending_receipt_query) {
|
||||
(Some(receipt), true) => Ok(to_value(&Receipt::from(receipt))),
|
||||
(Some(receipt), true) => Ok(Some(receipt.into())),
|
||||
_ => {
|
||||
let client = take_weak!(self.client);
|
||||
let receipt = client.transaction_receipt(TransactionID::Hash(hash));
|
||||
Ok(to_value(&receipt.map(Receipt::from)))
|
||||
Ok(receipt.map(Into::into))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn uncle_by_block_hash_and_index(&self, params: Params) -> Result<Value, Error> {
|
||||
fn uncle_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> Result<Option<Block>, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(RpcH256, Index)>(params)
|
||||
.and_then(|(hash, index)| self.uncle(UncleID { block: BlockID::Hash(hash.into()), position: index.value() }))
|
||||
|
||||
self.uncle(UncleID { block: BlockID::Hash(hash.into()), position: index.value() })
|
||||
}
|
||||
|
||||
fn uncle_by_block_number_and_index(&self, params: Params) -> Result<Value, Error> {
|
||||
fn uncle_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> Result<Option<Block>, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(BlockNumber, Index)>(params)
|
||||
.and_then(|(number, index)| self.uncle(UncleID { block: number.into(), position: index.value() }))
|
||||
|
||||
self.uncle(UncleID { block: num.into(), position: index.value() })
|
||||
}
|
||||
|
||||
fn compilers(&self, params: Params) -> Result<Value, Error> {
|
||||
fn compilers(&self) -> Result<Vec<String>, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
|
||||
let mut compilers = vec![];
|
||||
if Command::new(SOLC).output().is_ok() {
|
||||
compilers.push("solidity".to_owned())
|
||||
}
|
||||
Ok(to_value(&compilers))
|
||||
|
||||
Ok(compilers)
|
||||
}
|
||||
|
||||
fn logs(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(Filter, )>(params).and_then(|(filter,)| {
|
||||
fn logs(&self, filter: Filter) -> Result<Vec<Log>, Error> {
|
||||
let include_pending = filter.to_block == Some(BlockNumber::Pending);
|
||||
let filter: EthcoreFilter = filter.into();
|
||||
let mut logs = take_weak!(self.client).logs(filter.clone())
|
||||
@ -512,13 +497,13 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
}
|
||||
|
||||
let logs = limit_logs(logs, filter.limit);
|
||||
Ok(to_value(&logs))
|
||||
})
|
||||
|
||||
Ok(logs)
|
||||
}
|
||||
|
||||
fn work(&self, params: Params) -> Result<Value, Error> {
|
||||
fn work(&self, no_new_work_timeout: Trailing<u64>) -> Result<Work, Error> {
|
||||
try!(self.active());
|
||||
let (no_new_work_timeout,) = from_params::<(u64,)>(params).unwrap_or((0,));
|
||||
let no_new_work_timeout = no_new_work_timeout.0;
|
||||
|
||||
let client = take_weak!(self.client);
|
||||
// check if we're still syncing and return empty strings in that case
|
||||
@ -550,91 +535,95 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
if no_new_work_timeout > 0 && b.block().header().timestamp() + no_new_work_timeout < get_time().sec as u64 {
|
||||
Err(errors::no_new_work())
|
||||
} else if self.options.send_block_number_in_get_work {
|
||||
let block_number = RpcU256::from(b.block().header().number());
|
||||
Ok(to_value(&(RpcH256::from(pow_hash), RpcH256::from(seed_hash), RpcH256::from(target), block_number)))
|
||||
let block_number = b.block().header().number();
|
||||
Ok(Work {
|
||||
pow_hash: pow_hash.into(),
|
||||
seed_hash: seed_hash.into(),
|
||||
target: target.into(),
|
||||
number: Some(block_number),
|
||||
})
|
||||
} else {
|
||||
Ok(to_value(&(RpcH256::from(pow_hash), RpcH256::from(seed_hash), RpcH256::from(target))))
|
||||
Ok(Work {
|
||||
pow_hash: pow_hash.into(),
|
||||
seed_hash: seed_hash.into(),
|
||||
target: target.into(),
|
||||
number: None
|
||||
})
|
||||
}
|
||||
}).unwrap_or(Err(Error::internal_error())) // no work found.
|
||||
}
|
||||
|
||||
fn submit_work(&self, params: Params) -> Result<Value, Error> {
|
||||
fn submit_work(&self, nonce: RpcH64, pow_hash: RpcH256, mix_hash: RpcH256) -> Result<bool, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(RpcH64, RpcH256, RpcH256)>(params).and_then(|(nonce, pow_hash, mix_hash)| {
|
||||
|
||||
let nonce: H64 = nonce.into();
|
||||
let pow_hash: H256 = pow_hash.into();
|
||||
let mix_hash: H256 = mix_hash.into();
|
||||
trace!(target: "miner", "submit_work: Decoded: nonce={}, pow_hash={}, mix_hash={}", nonce, pow_hash, mix_hash);
|
||||
|
||||
let miner = take_weak!(self.miner);
|
||||
let client = take_weak!(self.client);
|
||||
let seal = vec![rlp::encode(&mix_hash).to_vec(), rlp::encode(&nonce).to_vec()];
|
||||
let r = miner.submit_seal(&*client, pow_hash, seal);
|
||||
Ok(to_value(&r.is_ok()))
|
||||
})
|
||||
Ok(miner.submit_seal(&*client, pow_hash, seal).is_ok())
|
||||
}
|
||||
|
||||
fn submit_hashrate(&self, params: Params) -> Result<Value, Error> {
|
||||
fn submit_hashrate(&self, rate: RpcU256, id: RpcH256) -> Result<bool, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(RpcU256, RpcH256)>(params).and_then(|(rate, id)| {
|
||||
self.external_miner.submit_hashrate(rate.into(), id.into());
|
||||
Ok(to_value(&true))
|
||||
})
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn send_raw_transaction(&self, params: Params) -> Result<Value, Error> {
|
||||
fn send_raw_transaction(&self, raw: Bytes) -> Result<RpcH256, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(Bytes, )>(params)
|
||||
.and_then(|(raw_transaction, )| {
|
||||
let raw_transaction = raw_transaction.to_vec();
|
||||
|
||||
let raw_transaction = raw.to_vec();
|
||||
match UntrustedRlp::new(&raw_transaction).as_val() {
|
||||
Ok(signed_transaction) => dispatch_transaction(&*take_weak!(self.client), &*take_weak!(self.miner), signed_transaction),
|
||||
Err(_) => Ok(to_value(&RpcH256::from(H256::from(0)))),
|
||||
Err(_) => Ok(RpcH256::from(H256::from(0))),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn call(&self, params: Params) -> Result<Value, Error> {
|
||||
fn call(&self, request: CallRequest, num: Trailing<BlockNumber>) -> Result<Bytes, Error> {
|
||||
try!(self.active());
|
||||
from_params_default_second(params)
|
||||
.and_then(|(request, block_number,)| {
|
||||
|
||||
let request = CallRequest::into(request);
|
||||
let signed = try!(self.sign_call(request));
|
||||
let r = match block_number {
|
||||
|
||||
let r = match num.0 {
|
||||
BlockNumber::Pending => take_weak!(self.miner).call(&*take_weak!(self.client), &signed, Default::default()),
|
||||
block_number => take_weak!(self.client).call(&signed, block_number.into(), Default::default()),
|
||||
num => take_weak!(self.client).call(&signed, num.into(), Default::default()),
|
||||
};
|
||||
Ok(to_value(&r.map(|e| Bytes(e.output)).unwrap_or(Bytes::new(vec![]))))
|
||||
})
|
||||
|
||||
Ok(r.map(|e| Bytes(e.output)).unwrap_or(Bytes::new(vec![])))
|
||||
}
|
||||
|
||||
fn estimate_gas(&self, params: Params) -> Result<Value, Error> {
|
||||
fn estimate_gas(&self, request: CallRequest, num: Trailing<BlockNumber>) -> Result<RpcU256, Error> {
|
||||
try!(self.active());
|
||||
from_params_default_second(params)
|
||||
.and_then(|(request, block_number,)| {
|
||||
|
||||
let request = CallRequest::into(request);
|
||||
let signed = try!(self.sign_call(request));
|
||||
let r = match block_number {
|
||||
let r = match num.0 {
|
||||
BlockNumber::Pending => take_weak!(self.miner).call(&*take_weak!(self.client), &signed, Default::default()),
|
||||
block => take_weak!(self.client).call(&signed, block.into(), Default::default()),
|
||||
num => take_weak!(self.client).call(&signed, num.into(), Default::default()),
|
||||
};
|
||||
Ok(to_value(&RpcU256::from(r.map(|res| res.gas_used + res.refunded).unwrap_or(From::from(0)))))
|
||||
})
|
||||
|
||||
Ok(RpcU256::from(r.map(|res| res.gas_used + res.refunded).unwrap_or(From::from(0))))
|
||||
}
|
||||
|
||||
fn compile_lll(&self, _: Params) -> Result<Value, Error> {
|
||||
fn compile_lll(&self, _: String) -> Result<Bytes, Error> {
|
||||
try!(self.active());
|
||||
|
||||
rpc_unimplemented!()
|
||||
}
|
||||
|
||||
fn compile_serpent(&self, _: Params) -> Result<Value, Error> {
|
||||
fn compile_serpent(&self, _: String) -> Result<Bytes, Error> {
|
||||
try!(self.active());
|
||||
|
||||
rpc_unimplemented!()
|
||||
}
|
||||
|
||||
fn compile_solidity(&self, params: Params) -> Result<Value, Error> {
|
||||
fn compile_solidity(&self, code: String) -> Result<Bytes, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(String, )>(params)
|
||||
.and_then(|(code, )| {
|
||||
let maybe_child = Command::new(SOLC)
|
||||
.arg("--bin")
|
||||
.arg("--optimize")
|
||||
@ -654,11 +643,10 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
|
||||
let s = String::from_utf8_lossy(&output.stdout);
|
||||
if let Some(hex) = s.lines().skip_while(|ref l| !l.contains("Binary")).skip(1).next() {
|
||||
Ok(to_value(&Bytes::new(hex.from_hex().unwrap_or(vec![]))))
|
||||
Ok(Bytes::new(hex.from_hex().unwrap_or(vec![])))
|
||||
} else {
|
||||
Err(errors::compilation("Unexpected output."))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,8 @@ use ethcore::filter::Filter as EthcoreFilter;
|
||||
use ethcore::client::{BlockChainClient, BlockID};
|
||||
use util::Mutex;
|
||||
use v1::traits::EthFilter;
|
||||
use v1::types::{BlockNumber, Index, Filter, Log, H256 as RpcH256, U256 as RpcU256};
|
||||
use v1::types::{BlockNumber, Index, Filter, FilterChanges, Log, H256 as RpcH256, U256 as RpcU256};
|
||||
use v1::helpers::{PollFilter, PollManager, limit_logs};
|
||||
use v1::helpers::params::expect_no_params;
|
||||
use v1::impls::eth::pending_logs;
|
||||
|
||||
/// Eth filter rpc implementation.
|
||||
@ -59,49 +58,40 @@ impl<C, M> EthFilterClient<C, M> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, M> EthFilter for EthFilterClient<C, M> where
|
||||
C: BlockChainClient + 'static,
|
||||
M: MinerService + 'static {
|
||||
|
||||
fn new_filter(&self, params: Params) -> Result<Value, Error> {
|
||||
impl<C, M> EthFilter for EthFilterClient<C, M>
|
||||
where C: BlockChainClient + 'static, M: MinerService + 'static
|
||||
{
|
||||
fn new_filter(&self, filter: Filter) -> Result<RpcU256, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(Filter, )>(params)
|
||||
.and_then(|(filter, )| {
|
||||
let mut polls = self.polls.lock();
|
||||
let block_number = take_weak!(self.client).chain_info().best_block_number;
|
||||
let id = polls.create_poll(PollFilter::Logs(block_number, Default::default(), filter));
|
||||
Ok(to_value(&RpcU256::from(id)))
|
||||
})
|
||||
Ok(id.into())
|
||||
}
|
||||
|
||||
fn new_block_filter(&self, params: Params) -> Result<Value, Error> {
|
||||
fn new_block_filter(&self) -> Result<RpcU256, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
|
||||
let mut polls = self.polls.lock();
|
||||
let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number));
|
||||
Ok(to_value(&RpcU256::from(id)))
|
||||
Ok(id.into())
|
||||
}
|
||||
|
||||
fn new_pending_transaction_filter(&self, params: Params) -> Result<Value, Error> {
|
||||
fn new_pending_transaction_filter(&self) -> Result<RpcU256, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
|
||||
let mut polls = self.polls.lock();
|
||||
let pending_transactions = take_weak!(self.miner).pending_transactions_hashes();
|
||||
let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions));
|
||||
|
||||
Ok(to_value(&RpcU256::from(id)))
|
||||
Ok(id.into())
|
||||
}
|
||||
|
||||
fn filter_changes(&self, params: Params) -> Result<Value, Error> {
|
||||
fn filter_changes(&self, index: Index) -> Result<FilterChanges, Error> {
|
||||
try!(self.active());
|
||||
let client = take_weak!(self.client);
|
||||
from_params::<(Index,)>(params)
|
||||
.and_then(|(index,)| {
|
||||
let mut polls = self.polls.lock();
|
||||
match polls.poll_mut(&index.value()) {
|
||||
None => Ok(Value::Array(vec![] as Vec<Value>)),
|
||||
None => Ok(FilterChanges::Empty),
|
||||
Some(filter) => match *filter {
|
||||
PollFilter::Block(ref mut block_number) => {
|
||||
// + 1, cause we want to return hashes including current block hash.
|
||||
@ -114,7 +104,7 @@ impl<C, M> EthFilter for EthFilterClient<C, M> where
|
||||
|
||||
*block_number = current_number;
|
||||
|
||||
Ok(to_value(&hashes))
|
||||
Ok(FilterChanges::Hashes(hashes))
|
||||
},
|
||||
PollFilter::PendingTransaction(ref mut previous_hashes) => {
|
||||
// get hashes of pending transactions
|
||||
@ -137,7 +127,7 @@ impl<C, M> EthFilter for EthFilterClient<C, M> where
|
||||
*previous_hashes = current_hashes;
|
||||
|
||||
// return new hashes
|
||||
Ok(to_value(&new_hashes))
|
||||
Ok(FilterChanges::Hashes(new_hashes))
|
||||
},
|
||||
PollFilter::Logs(ref mut block_number, ref mut previous_logs, ref filter) => {
|
||||
// retrive the current block number
|
||||
@ -180,17 +170,15 @@ impl<C, M> EthFilter for EthFilterClient<C, M> where
|
||||
// we want to get logs
|
||||
*block_number = current_number + 1;
|
||||
|
||||
Ok(to_value(&logs))
|
||||
Ok(FilterChanges::Logs(logs))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn filter_logs(&self, params: Params) -> Result<Value, Error> {
|
||||
fn filter_logs(&self, index: Index) -> Result<Vec<Log>, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(Index,)>(params)
|
||||
.and_then(|(index,)| {
|
||||
|
||||
let mut polls = self.polls.lock();
|
||||
match polls.poll(&index.value()) {
|
||||
Some(&PollFilter::Logs(ref _block_number, ref _previous_log, ref filter)) => {
|
||||
@ -207,20 +195,17 @@ impl<C, M> EthFilter for EthFilterClient<C, M> where
|
||||
|
||||
let logs = limit_logs(logs, filter.limit);
|
||||
|
||||
Ok(to_value(&logs))
|
||||
Ok(logs)
|
||||
},
|
||||
// just empty array
|
||||
_ => Ok(Value::Array(vec![] as Vec<Value>)),
|
||||
_ => Ok(Vec::new()),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn uninstall_filter(&self, params: Params) -> Result<Value, Error> {
|
||||
fn uninstall_filter(&self, index: Index) -> Result<bool, Error> {
|
||||
try!(self.active());
|
||||
from_params::<(Index,)>(params)
|
||||
.map(|(index,)| {
|
||||
|
||||
self.polls.lock().remove_poll(&index.value());
|
||||
to_value(&true)
|
||||
})
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
@ -18,186 +18,185 @@
|
||||
use std::sync::Arc;
|
||||
use jsonrpc_core::*;
|
||||
|
||||
use v1::types::{Block, BlockNumber, Bytes, CallRequest, Filter, FilterChanges, Index};
|
||||
use v1::types::{Log, Receipt, SyncStatus, Transaction, Work};
|
||||
use v1::types::{H64, H160, H256, U256};
|
||||
|
||||
use v1::helpers::auto_args::{Trailing, Wrap};
|
||||
|
||||
build_rpc_trait! {
|
||||
/// Eth rpc interface.
|
||||
pub trait Eth: Sized + Send + Sync + 'static {
|
||||
/// Returns protocol version.
|
||||
fn protocol_version(&self, _: Params) -> Result<Value, Error>;
|
||||
pub trait Eth {
|
||||
/// Returns protocol version encoded as a string (quotes are necessary).
|
||||
#[name("eth_protocolVersion")]
|
||||
fn protocol_version(&self) -> Result<String, Error>;
|
||||
|
||||
/// Returns an object with data about the sync status or false. (wtf?)
|
||||
fn syncing(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_syncing")]
|
||||
fn syncing(&self) -> Result<SyncStatus, Error>;
|
||||
|
||||
/// Returns the number of hashes per second that the node is mining with.
|
||||
fn hashrate(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_hashrate")]
|
||||
fn hashrate(&self) -> Result<U256, Error>;
|
||||
|
||||
/// Returns block author.
|
||||
fn author(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_coinbase")]
|
||||
fn author(&self) -> Result<H160, Error>;
|
||||
|
||||
/// Returns true if client is actively mining new blocks.
|
||||
fn is_mining(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_mining")]
|
||||
fn is_mining(&self) -> Result<bool, Error>;
|
||||
|
||||
/// Returns current gas_price.
|
||||
fn gas_price(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_gasPrice")]
|
||||
fn gas_price(&self) -> Result<U256, Error>;
|
||||
|
||||
/// Returns accounts list.
|
||||
fn accounts(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_accounts")]
|
||||
fn accounts(&self) -> Result<Vec<H160>, Error>;
|
||||
|
||||
/// Returns highest block number.
|
||||
fn block_number(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_blockNumber")]
|
||||
fn block_number(&self) -> Result<U256, Error>;
|
||||
|
||||
/// Returns balance of the given account.
|
||||
fn balance(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getBalance")]
|
||||
fn balance(&self, H160, Trailing<BlockNumber>) -> Result<U256, Error>;
|
||||
|
||||
/// Returns content of the storage at given address.
|
||||
fn storage_at(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getStorageAt")]
|
||||
fn storage_at(&self, H160, U256, Trailing<BlockNumber>) -> Result<H256, Error>;
|
||||
|
||||
/// Returns block with given hash.
|
||||
fn block_by_hash(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getBlockByHash")]
|
||||
fn block_by_hash(&self, H256, bool) -> Result<Option<Block>, Error>;
|
||||
|
||||
/// Returns block with given number.
|
||||
fn block_by_number(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getBlockByNumber")]
|
||||
fn block_by_number(&self, BlockNumber, bool) -> Result<Option<Block>, Error>;
|
||||
|
||||
/// Returns the number of transactions sent from given address at given time (block number).
|
||||
fn transaction_count(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getTransactionCount")]
|
||||
fn transaction_count(&self, H160, Trailing<BlockNumber>) -> Result<U256, Error>;
|
||||
|
||||
/// Returns the number of transactions in a block with given hash.
|
||||
fn block_transaction_count_by_hash(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getBlockTransactionCountByHash")]
|
||||
fn block_transaction_count_by_hash(&self, H256) -> Result<Option<U256>, Error>;
|
||||
|
||||
/// Returns the number of transactions in a block with given block number.
|
||||
fn block_transaction_count_by_number(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getBlockTransactionCountByNumber")]
|
||||
fn block_transaction_count_by_number(&self, BlockNumber) -> Result<Option<U256>, Error>;
|
||||
|
||||
/// Returns the number of uncles in a block with given hash.
|
||||
fn block_uncles_count_by_hash(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getUncleCountByBlockHash")]
|
||||
fn block_uncles_count_by_hash(&self, H256) -> Result<Option<U256>, Error>;
|
||||
|
||||
/// Returns the number of uncles in a block with given block number.
|
||||
fn block_uncles_count_by_number(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getUncleCountByBlockNumber")]
|
||||
fn block_uncles_count_by_number(&self, BlockNumber) -> Result<Option<U256>, Error>;
|
||||
|
||||
/// Returns the code at given address at given time (block number).
|
||||
fn code_at(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getCode")]
|
||||
fn code_at(&self, H160, Trailing<BlockNumber>) -> Result<Bytes, Error>;
|
||||
|
||||
/// Sends signed transaction.
|
||||
fn send_raw_transaction(&self, _: Params) -> Result<Value, Error>;
|
||||
/// Sends signed transaction, returning its hash.
|
||||
#[name("eth_sendRawTransaction")]
|
||||
fn send_raw_transaction(&self, Bytes) -> Result<H256, Error>;
|
||||
|
||||
/// Call contract.
|
||||
fn call(&self, _: Params) -> Result<Value, Error>;
|
||||
/// Call contract, returning the output data.
|
||||
#[name("eth_call")]
|
||||
fn call(&self, CallRequest, Trailing<BlockNumber>) -> Result<Bytes, Error>;
|
||||
|
||||
/// Estimate gas needed for execution of given contract.
|
||||
fn estimate_gas(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_estimateGas")]
|
||||
fn estimate_gas(&self, CallRequest, Trailing<BlockNumber>) -> Result<U256, Error>;
|
||||
|
||||
/// Get transaction by its hash.
|
||||
fn transaction_by_hash(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getTransactionByHash")]
|
||||
fn transaction_by_hash(&self, H256) -> Result<Option<Transaction>, Error>;
|
||||
|
||||
/// Returns transaction at given block hash and index.
|
||||
fn transaction_by_block_hash_and_index(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getTransactionByBlockHashAndIndex")]
|
||||
fn transaction_by_block_hash_and_index(&self, H256, Index) -> Result<Option<Transaction>, Error>;
|
||||
|
||||
/// Returns transaction by given block number and index.
|
||||
fn transaction_by_block_number_and_index(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getTransactionByBlockNumberAndIndex")]
|
||||
fn transaction_by_block_number_and_index(&self, BlockNumber, Index) -> Result<Option<Transaction>, Error>;
|
||||
|
||||
/// Returns transaction receipt.
|
||||
fn transaction_receipt(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getTransactionReceipt")]
|
||||
fn transaction_receipt(&self, H256) -> Result<Option<Receipt>, Error>;
|
||||
|
||||
/// Returns an uncles at given block and index.
|
||||
fn uncle_by_block_hash_and_index(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getUncleByBlockHashAndIndex")]
|
||||
fn uncle_by_block_hash_and_index(&self, H256, Index) -> Result<Option<Block>, Error>;
|
||||
|
||||
/// Returns an uncles at given block and index.
|
||||
fn uncle_by_block_number_and_index(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getUncleByBlockNumberAndIndex")]
|
||||
fn uncle_by_block_number_and_index(&self, BlockNumber, Index) -> Result<Option<Block>, Error>;
|
||||
|
||||
/// Returns available compilers.
|
||||
fn compilers(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getCompilers")]
|
||||
fn compilers(&self) -> Result<Vec<String>, Error>;
|
||||
|
||||
/// Compiles lll code.
|
||||
fn compile_lll(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_compileLLL")]
|
||||
fn compile_lll(&self, String) -> Result<Bytes, Error>;
|
||||
|
||||
/// Compiles solidity.
|
||||
fn compile_solidity(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_compileSolidity")]
|
||||
fn compile_solidity(&self, String) -> Result<Bytes, Error>;
|
||||
|
||||
/// Compiles serpent.
|
||||
fn compile_serpent(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_compileSerpent")]
|
||||
fn compile_serpent(&self, String) -> Result<Bytes, Error>;
|
||||
|
||||
/// Returns logs matching given filter object.
|
||||
fn logs(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getLogs")]
|
||||
fn logs(&self, Filter) -> Result<Vec<Log>, Error>;
|
||||
|
||||
/// Returns the hash of the current block, the seedHash, and the boundary condition to be met.
|
||||
fn work(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getWork")]
|
||||
fn work(&self, Trailing<u64>) -> Result<Work, Error>;
|
||||
|
||||
/// Used for submitting a proof-of-work solution.
|
||||
fn submit_work(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_submitWork")]
|
||||
fn submit_work(&self, H64, H256, H256) -> Result<bool, Error>;
|
||||
|
||||
/// Used for submitting mining hashrate.
|
||||
fn submit_hashrate(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_submitHashrate")]
|
||||
fn submit_hashrate(&self, U256, H256) -> Result<bool, Error>;
|
||||
}
|
||||
}
|
||||
|
||||
/// Should be used to convert object to io delegate.
|
||||
fn to_delegate(self) -> IoDelegate<Self> {
|
||||
let mut delegate = IoDelegate::new(Arc::new(self));
|
||||
delegate.add_method("eth_protocolVersion", Eth::protocol_version);
|
||||
delegate.add_method("eth_syncing", Eth::syncing);
|
||||
delegate.add_method("eth_hashrate", Eth::hashrate);
|
||||
delegate.add_method("eth_coinbase", Eth::author);
|
||||
delegate.add_method("eth_mining", Eth::is_mining);
|
||||
delegate.add_method("eth_gasPrice", Eth::gas_price);
|
||||
delegate.add_method("eth_accounts", Eth::accounts);
|
||||
delegate.add_method("eth_blockNumber", Eth::block_number);
|
||||
delegate.add_method("eth_getBalance", Eth::balance);
|
||||
delegate.add_method("eth_getStorageAt", Eth::storage_at);
|
||||
delegate.add_method("eth_getTransactionCount", Eth::transaction_count);
|
||||
delegate.add_method("eth_getBlockTransactionCountByHash", Eth::block_transaction_count_by_hash);
|
||||
delegate.add_method("eth_getBlockTransactionCountByNumber", Eth::block_transaction_count_by_number);
|
||||
delegate.add_method("eth_getUncleCountByBlockHash", Eth::block_uncles_count_by_hash);
|
||||
delegate.add_method("eth_getUncleCountByBlockNumber", Eth::block_uncles_count_by_number);
|
||||
delegate.add_method("eth_getCode", Eth::code_at);
|
||||
delegate.add_method("eth_sendRawTransaction", Eth::send_raw_transaction);
|
||||
delegate.add_method("eth_call", Eth::call);
|
||||
delegate.add_method("eth_estimateGas", Eth::estimate_gas);
|
||||
delegate.add_method("eth_getBlockByHash", Eth::block_by_hash);
|
||||
delegate.add_method("eth_getBlockByNumber", Eth::block_by_number);
|
||||
delegate.add_method("eth_getTransactionByHash", Eth::transaction_by_hash);
|
||||
delegate.add_method("eth_getTransactionByBlockHashAndIndex", Eth::transaction_by_block_hash_and_index);
|
||||
delegate.add_method("eth_getTransactionByBlockNumberAndIndex", Eth::transaction_by_block_number_and_index);
|
||||
delegate.add_method("eth_getTransactionReceipt", Eth::transaction_receipt);
|
||||
delegate.add_method("eth_getUncleByBlockHashAndIndex", Eth::uncle_by_block_hash_and_index);
|
||||
delegate.add_method("eth_getUncleByBlockNumberAndIndex", Eth::uncle_by_block_number_and_index);
|
||||
delegate.add_method("eth_getCompilers", Eth::compilers);
|
||||
delegate.add_method("eth_compileLLL", Eth::compile_lll);
|
||||
delegate.add_method("eth_compileSolidity", Eth::compile_solidity);
|
||||
delegate.add_method("eth_compileSerpent", Eth::compile_serpent);
|
||||
delegate.add_method("eth_getLogs", Eth::logs);
|
||||
delegate.add_method("eth_getWork", Eth::work);
|
||||
delegate.add_method("eth_submitWork", Eth::submit_work);
|
||||
delegate.add_method("eth_submitHashrate", Eth::submit_hashrate);
|
||||
delegate
|
||||
}
|
||||
}
|
||||
build_rpc_trait! {
|
||||
|
||||
/// Eth filters rpc api (polling).
|
||||
// TODO: do filters api properly
|
||||
pub trait EthFilter: Sized + Send + Sync + 'static {
|
||||
pub trait EthFilter {
|
||||
/// Returns id of new filter.
|
||||
fn new_filter(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_newFilter")]
|
||||
fn new_filter(&self, Filter) -> Result<U256, Error>;
|
||||
|
||||
/// Returns id of new block filter.
|
||||
fn new_block_filter(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_newBlockFilter")]
|
||||
fn new_block_filter(&self) -> Result<U256, Error>;
|
||||
|
||||
/// Returns id of new block filter.
|
||||
fn new_pending_transaction_filter(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_newPendingTransactionFilter")]
|
||||
fn new_pending_transaction_filter(&self) -> Result<U256, Error>;
|
||||
|
||||
/// Returns filter changes since last poll.
|
||||
fn filter_changes(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getFilterChanges")]
|
||||
fn filter_changes(&self, Index) -> Result<FilterChanges, Error>;
|
||||
|
||||
/// Returns all logs matching given filter (in a range 'from' - 'to').
|
||||
fn filter_logs(&self, _: Params) -> Result<Value, Error>;
|
||||
#[name("eth_getFilterLogs")]
|
||||
fn filter_logs(&self, Index) -> Result<Vec<Log>, Error>;
|
||||
|
||||
/// Uninstalls filter.
|
||||
fn uninstall_filter(&self, _: Params) -> Result<Value, Error>;
|
||||
|
||||
/// Should be used to convert object to io delegate.
|
||||
fn to_delegate(self) -> IoDelegate<Self> {
|
||||
let mut delegate = IoDelegate::new(Arc::new(self));
|
||||
delegate.add_method("eth_newFilter", EthFilter::new_filter);
|
||||
delegate.add_method("eth_newBlockFilter", EthFilter::new_block_filter);
|
||||
delegate.add_method("eth_newPendingTransactionFilter", EthFilter::new_pending_transaction_filter);
|
||||
delegate.add_method("eth_getFilterChanges", EthFilter::filter_changes);
|
||||
delegate.add_method("eth_getFilterLogs", EthFilter::filter_logs);
|
||||
delegate.add_method("eth_uninstallFilter", EthFilter::uninstall_filter);
|
||||
delegate
|
||||
#[name("eth_uninstallFilter")]
|
||||
fn uninstall_filter(&self, Index) -> Result<bool, Error>;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,12 @@ pub enum BlockNumber {
|
||||
Pending,
|
||||
}
|
||||
|
||||
impl Default for BlockNumber {
|
||||
fn default() -> Self {
|
||||
BlockNumber::Latest
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserialize for BlockNumber {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<BlockNumber, D::Error>
|
||||
where D: Deserializer {
|
||||
|
@ -14,12 +14,12 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use serde::{Deserialize, Deserializer, Error};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer, Error};
|
||||
use serde_json::value;
|
||||
use jsonrpc_core::Value;
|
||||
use ethcore::filter::Filter as EthFilter;
|
||||
use ethcore::client::BlockID;
|
||||
use v1::types::{BlockNumber, H160, H256};
|
||||
use v1::types::{BlockNumber, H160, H256, Log};
|
||||
|
||||
/// Variadic value
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
@ -93,6 +93,27 @@ impl Into<EthFilter> for Filter {
|
||||
}
|
||||
}
|
||||
|
||||
/// Results of the filter_changes RPC.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum FilterChanges {
|
||||
/// New logs.
|
||||
Logs(Vec<Log>),
|
||||
/// New hashes (block or transactions)
|
||||
Hashes(Vec<H256>),
|
||||
/// Empty result,
|
||||
Empty,
|
||||
}
|
||||
|
||||
impl Serialize for FilterChanges {
|
||||
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error> where S: Serializer {
|
||||
match *self {
|
||||
FilterChanges::Logs(ref logs) => logs.serialize(s),
|
||||
FilterChanges::Hashes(ref hashes) => hashes.serialize(s),
|
||||
FilterChanges::Empty => (&[] as &[Value]).serialize(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json;
|
||||
|
@ -30,13 +30,14 @@ mod receipt;
|
||||
mod trace;
|
||||
mod trace_filter;
|
||||
mod uint;
|
||||
mod work;
|
||||
|
||||
pub use self::bytes::Bytes;
|
||||
pub use self::block::{Block, BlockTransactions};
|
||||
pub use self::block_number::BlockNumber;
|
||||
pub use self::call_request::CallRequest;
|
||||
pub use self::confirmations::{ConfirmationPayload, ConfirmationRequest, TransactionModification};
|
||||
pub use self::filter::Filter;
|
||||
pub use self::filter::{Filter, FilterChanges};
|
||||
pub use self::hash::{H64, H160, H256, H512, H520, H2048};
|
||||
pub use self::index::Index;
|
||||
pub use self::log::Log;
|
||||
@ -47,3 +48,4 @@ pub use self::receipt::Receipt;
|
||||
pub use self::trace::{LocalizedTrace, TraceResults};
|
||||
pub use self::trace_filter::TraceFilter;
|
||||
pub use self::uint::U256;
|
||||
pub use self::work::Work;
|
||||
|
43
rpc/src/v1/types/work.rs
Normal file
43
rpc/src/v1/types/work.rs
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity 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 General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use super::{H256, U256};
|
||||
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
/// The result of an `eth_getWork` call: it differs based on an option
|
||||
/// whether to send the block number.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Work {
|
||||
/// The proof-of-work hash.
|
||||
pub pow_hash: H256,
|
||||
/// The seed hash.
|
||||
pub seed_hash: H256,
|
||||
/// The target.
|
||||
pub target: H256,
|
||||
/// The block number: this isn't always stored.
|
||||
pub number: Option<u64>,
|
||||
}
|
||||
|
||||
impl Serialize for Work {
|
||||
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error> where S: Serializer {
|
||||
match self.number.as_ref() {
|
||||
Some(num) => (&self.pow_hash, &self.seed_hash, &self.target, U256::from(*num)).serialize(s),
|
||||
None => (&self.pow_hash, &self.seed_hash, &self.target).serialize(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user