Merge branch 'master' into Fix-4858
This commit is contained in:
@@ -24,6 +24,7 @@ serde_json = "1.0"
|
||||
time = "0.1"
|
||||
tokio-timer = "0.1"
|
||||
transient-hashmap = "0.4"
|
||||
itertools = "0.5"
|
||||
|
||||
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||
jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||
@@ -46,12 +47,13 @@ ethjson = { path = "../json" }
|
||||
ethcore-devtools = { path = "../devtools" }
|
||||
ethcore-light = { path = "../ethcore/light" }
|
||||
ethcore-logger = { path = "../logger" }
|
||||
vm = { path = "../ethcore/vm" }
|
||||
parity-updater = { path = "../updater" }
|
||||
parity-reactor = { path = "../util/reactor" }
|
||||
rlp = { path = "../util/rlp" }
|
||||
fetch = { path = "../util/fetch" }
|
||||
node-health = { path = "../dapps/node-health" }
|
||||
parity-reactor = { path = "../util/reactor" }
|
||||
parity-updater = { path = "../updater" }
|
||||
rlp = { path = "../util/rlp" }
|
||||
stats = { path = "../util/stats" }
|
||||
vm = { path = "../ethcore/vm" }
|
||||
|
||||
clippy = { version = "0.0.103", optional = true}
|
||||
pretty_assertions = "0.1"
|
||||
|
||||
@@ -18,9 +18,10 @@ use std::io::{self, Read, Write};
|
||||
use std::path::Path;
|
||||
use std::{fs, time, mem};
|
||||
|
||||
use itertools::Itertools;
|
||||
use rand::Rng;
|
||||
use rand::os::OsRng;
|
||||
use util::{H256, Hashable, Itertools};
|
||||
use util::{H256, Hashable};
|
||||
|
||||
/// Providing current time in seconds
|
||||
pub trait TimeProvider {
|
||||
|
||||
@@ -24,6 +24,7 @@ extern crate cid;
|
||||
extern crate crypto as rust_crypto;
|
||||
extern crate futures;
|
||||
extern crate futures_cpupool;
|
||||
extern crate itertools;
|
||||
extern crate multihash;
|
||||
extern crate order_stat;
|
||||
extern crate rand;
|
||||
@@ -54,6 +55,7 @@ extern crate ethsync;
|
||||
extern crate ethcore_logger;
|
||||
extern crate vm;
|
||||
extern crate fetch;
|
||||
extern crate node_health;
|
||||
extern crate parity_reactor;
|
||||
extern crate parity_updater as updater;
|
||||
extern crate rlp;
|
||||
|
||||
@@ -22,12 +22,6 @@ use v1::types::LocalDapp;
|
||||
pub trait DappsService: Send + Sync + 'static {
|
||||
/// List available local dapps.
|
||||
fn list_dapps(&self) -> Vec<LocalDapp>;
|
||||
}
|
||||
|
||||
impl<F> DappsService for F where
|
||||
F: Fn() -> Vec<LocalDapp> + Send + Sync + 'static
|
||||
{
|
||||
fn list_dapps(&self) -> Vec<LocalDapp> {
|
||||
(*self)()
|
||||
}
|
||||
/// Refresh local dapps list
|
||||
fn refresh_local_dapps(&self) -> bool;
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ impl<C: MiningBlockChainClient, M: MinerService> Dispatcher for FullDispatcher<C
|
||||
-> BoxFuture<WithToken<SignedTransaction>, Error>
|
||||
{
|
||||
let (client, miner) = (self.client.clone(), self.miner.clone());
|
||||
let network_id = client.signing_network_id();
|
||||
let chain_id = client.signing_chain_id();
|
||||
let address = filled.from;
|
||||
future::done({
|
||||
let t = Transaction {
|
||||
@@ -146,12 +146,12 @@ impl<C: MiningBlockChainClient, M: MinerService> Dispatcher for FullDispatcher<C
|
||||
};
|
||||
|
||||
if accounts.is_hardware_address(address) {
|
||||
hardware_signature(&*accounts, address, t, network_id).map(WithToken::No)
|
||||
hardware_signature(&*accounts, address, t, chain_id).map(WithToken::No)
|
||||
} else {
|
||||
let hash = t.hash(network_id);
|
||||
let hash = t.hash(chain_id);
|
||||
let signature = try_bf!(signature(&*accounts, address, hash, password));
|
||||
Ok(signature.map(|sig| {
|
||||
SignedTransaction::new(t.with_signature(sig, network_id))
|
||||
SignedTransaction::new(t.with_signature(sig, chain_id))
|
||||
.expect("Transaction was signed by AccountsProvider; it never produces invalid signatures; qed")
|
||||
}))
|
||||
}
|
||||
@@ -358,7 +358,7 @@ impl Dispatcher for LightDispatcher {
|
||||
fn sign(&self, accounts: Arc<AccountProvider>, filled: FilledTransactionRequest, password: SignWith)
|
||||
-> BoxFuture<WithToken<SignedTransaction>, Error>
|
||||
{
|
||||
let network_id = self.client.signing_network_id();
|
||||
let chain_id = self.client.signing_chain_id();
|
||||
let address = filled.from;
|
||||
|
||||
let with_nonce = move |filled: FilledTransactionRequest, nonce| {
|
||||
@@ -372,14 +372,14 @@ impl Dispatcher for LightDispatcher {
|
||||
};
|
||||
|
||||
if accounts.is_hardware_address(address) {
|
||||
return hardware_signature(&*accounts, address, t, network_id).map(WithToken::No)
|
||||
return hardware_signature(&*accounts, address, t, chain_id).map(WithToken::No)
|
||||
}
|
||||
|
||||
let hash = t.hash(network_id);
|
||||
let hash = t.hash(chain_id);
|
||||
let signature = signature(&*accounts, address, hash, password)?;
|
||||
|
||||
Ok(signature.map(|sig| {
|
||||
SignedTransaction::new(t.with_signature(sig, network_id))
|
||||
SignedTransaction::new(t.with_signature(sig, chain_id))
|
||||
.expect("Transaction was signed by AccountsProvider; it never produces invalid signatures; qed")
|
||||
}))
|
||||
};
|
||||
@@ -512,6 +512,10 @@ pub fn execute<D: Dispatcher + 'static>(
|
||||
).boxed()
|
||||
},
|
||||
ConfirmationPayload::EthSignMessage(address, data) => {
|
||||
if accounts.is_hardware_address(address) {
|
||||
return future::err(errors::unsupported("Signing via hardware wallets is not supported.", None)).boxed();
|
||||
}
|
||||
|
||||
let hash = eth_data_hash(data);
|
||||
let res = signature(&accounts, address, hash, pass)
|
||||
.map(|result| result
|
||||
@@ -522,6 +526,10 @@ pub fn execute<D: Dispatcher + 'static>(
|
||||
future::done(res).boxed()
|
||||
},
|
||||
ConfirmationPayload::Decrypt(address, data) => {
|
||||
if accounts.is_hardware_address(address) {
|
||||
return future::err(errors::unsupported("Decrypting via hardware wallets is not supported.", None)).boxed();
|
||||
}
|
||||
|
||||
let res = decrypt(&accounts, address, data, pass)
|
||||
.map(|result| result
|
||||
.map(RpcBytes)
|
||||
@@ -544,20 +552,20 @@ fn signature(accounts: &AccountProvider, address: Address, hash: H256, password:
|
||||
}
|
||||
|
||||
// obtain a hardware signature from the given account.
|
||||
fn hardware_signature(accounts: &AccountProvider, address: Address, t: Transaction, network_id: Option<u64>)
|
||||
fn hardware_signature(accounts: &AccountProvider, address: Address, t: Transaction, chain_id: Option<u64>)
|
||||
-> Result<SignedTransaction, Error>
|
||||
{
|
||||
debug_assert!(accounts.is_hardware_address(address));
|
||||
|
||||
let mut stream = rlp::RlpStream::new();
|
||||
t.rlp_append_unsigned_transaction(&mut stream, network_id);
|
||||
t.rlp_append_unsigned_transaction(&mut stream, chain_id);
|
||||
let signature = accounts.sign_with_hardware(address, &stream.as_raw())
|
||||
.map_err(|e| {
|
||||
debug!(target: "miner", "Error signing transaction with hardware wallet: {}", e);
|
||||
errors::account("Error signing transaction with hardware wallet", e)
|
||||
})?;
|
||||
|
||||
SignedTransaction::new(t.with_signature(signature, network_id))
|
||||
SignedTransaction::new(t.with_signature(signature, chain_id))
|
||||
.map_err(|e| {
|
||||
debug!(target: "miner", "Hardware wallet has produced invalid signature: {}", e);
|
||||
errors::account("Invalid signature generated", e)
|
||||
@@ -576,8 +584,9 @@ fn decrypt(accounts: &AccountProvider, address: Address, msg: Bytes, password: S
|
||||
}
|
||||
|
||||
/// Extract the default gas price from a client and miner.
|
||||
pub fn default_gas_price<C, M>(client: &C, miner: &M) -> U256
|
||||
where C: MiningBlockChainClient, M: MinerService
|
||||
pub fn default_gas_price<C, M>(client: &C, miner: &M) -> U256 where
|
||||
C: MiningBlockChainClient,
|
||||
M: MinerService,
|
||||
{
|
||||
client.gas_price_corpus(100).median().cloned().unwrap_or_else(|| miner.sensible_gas_price())
|
||||
}
|
||||
|
||||
@@ -71,6 +71,14 @@ pub fn public_unsupported(details: Option<String>) -> Error {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unsupported<T: Into<String>>(msg: T, details: Option<T>) -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
|
||||
message: msg.into(),
|
||||
data: details.map(Into::into).map(Value::String),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_not_found() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::REQUEST_NOT_FOUND),
|
||||
@@ -302,7 +310,7 @@ pub fn transaction_message(error: TransactionError) -> String {
|
||||
GasLimitExceeded { limit, got } => {
|
||||
format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got)
|
||||
},
|
||||
InvalidNetworkId => "Invalid network id.".into(),
|
||||
InvalidChainId => "Invalid chain id.".into(),
|
||||
InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(),
|
||||
SenderBanned => "Sender is banned in local queue.".into(),
|
||||
RecipientBanned => "Recipient is banned in local queue.".into(),
|
||||
|
||||
@@ -18,22 +18,34 @@ use std::sync::Arc;
|
||||
use ethcore::client::MiningBlockChainClient;
|
||||
use ethcore::miner::MinerService;
|
||||
use ethcore::transaction::{Transaction, SignedTransaction, Action};
|
||||
use util::U256;
|
||||
|
||||
use jsonrpc_core::Error;
|
||||
use v1::helpers::CallRequest;
|
||||
use v1::helpers::dispatch::default_gas_price;
|
||||
|
||||
pub fn sign_call<B: MiningBlockChainClient, M: MinerService>(
|
||||
client: &Arc<B>,
|
||||
pub fn sign_call<C: MiningBlockChainClient, M: MinerService> (
|
||||
client: &Arc<C>,
|
||||
miner: &Arc<M>,
|
||||
request: CallRequest,
|
||||
gas_cap: bool,
|
||||
) -> Result<SignedTransaction, Error> {
|
||||
let max_gas = 50_000_000.into();
|
||||
let gas = match request.gas {
|
||||
Some(gas) if gas_cap && gas > max_gas => {
|
||||
warn!("Gas limit capped to {} (from {})", max_gas, gas);
|
||||
max_gas
|
||||
}
|
||||
Some(gas) => gas,
|
||||
None if gas_cap => max_gas,
|
||||
None => U256::from(2) << 50,
|
||||
};
|
||||
let from = request.from.unwrap_or(0.into());
|
||||
|
||||
Ok(Transaction {
|
||||
nonce: request.nonce.unwrap_or_else(|| client.latest_nonce(&from)),
|
||||
action: request.to.map_or(Action::Create, Action::Call),
|
||||
gas: request.gas.unwrap_or(50_000_000.into()),
|
||||
gas,
|
||||
gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(&**client, &**miner)),
|
||||
value: request.value.unwrap_or(0.into()),
|
||||
data: request.data.unwrap_or_default(),
|
||||
|
||||
@@ -264,6 +264,7 @@ fn check_known<C>(client: &C, number: BlockNumber) -> Result<(), Error> where C:
|
||||
|
||||
match client.block_status(number.into()) {
|
||||
BlockStatus::InChain => Ok(()),
|
||||
BlockStatus::Pending => Ok(()),
|
||||
_ => Err(errors::unknown_block()),
|
||||
}
|
||||
}
|
||||
@@ -361,20 +362,12 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
||||
fn balance(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256, Error> {
|
||||
let address = address.into();
|
||||
|
||||
let res = match num.unwrap_or_default() {
|
||||
BlockNumber::Pending => {
|
||||
match self.miner.balance(&*self.client, &address) {
|
||||
Some(balance) => Ok(balance.into()),
|
||||
None => Err(errors::database("latest balance missing"))
|
||||
}
|
||||
}
|
||||
id => {
|
||||
try_bf!(check_known(&*self.client, id.clone()));
|
||||
match self.client.balance(&address, id.into()) {
|
||||
Some(balance) => Ok(balance.into()),
|
||||
None => Err(errors::state_pruned()),
|
||||
}
|
||||
}
|
||||
let id = num.unwrap_or_default();
|
||||
|
||||
try_bf!(check_known(&*self.client, id.clone()));
|
||||
let res = match self.client.balance(&address, id.into()) {
|
||||
Some(balance) => Ok(balance.into()),
|
||||
None => Err(errors::state_pruned()),
|
||||
};
|
||||
|
||||
future::done(res).boxed()
|
||||
@@ -384,20 +377,12 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
||||
let address: Address = RpcH160::into(address);
|
||||
let position: U256 = RpcU256::into(pos);
|
||||
|
||||
let res = match num.unwrap_or_default() {
|
||||
BlockNumber::Pending => {
|
||||
match self.miner.storage_at(&*self.client, &address, &H256::from(position)) {
|
||||
Some(s) => Ok(s.into()),
|
||||
None => Err(errors::database("latest storage missing"))
|
||||
}
|
||||
}
|
||||
id => {
|
||||
try_bf!(check_known(&*self.client, id.clone()));
|
||||
match self.client.storage_at(&address, &H256::from(position), id.into()) {
|
||||
Some(s) => Ok(s.into()),
|
||||
None => Err(errors::state_pruned()),
|
||||
}
|
||||
}
|
||||
let id = num.unwrap_or_default();
|
||||
|
||||
try_bf!(check_known(&*self.client, id.clone()));
|
||||
let res = match self.client.storage_at(&address, &H256::from(position), id.into()) {
|
||||
Some(s) => Ok(s.into()),
|
||||
None => Err(errors::state_pruned()),
|
||||
};
|
||||
|
||||
future::done(res).boxed()
|
||||
@@ -410,18 +395,12 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
||||
BlockNumber::Pending if self.options.pending_nonce_from_queue => {
|
||||
let nonce = self.miner.last_nonce(&address)
|
||||
.map(|n| n + 1.into())
|
||||
.or_else(|| self.miner.nonce(&*self.client, &address));
|
||||
.or_else(|| self.client.nonce(&address, BlockNumber::Pending.into()));
|
||||
match nonce {
|
||||
Some(nonce) => Ok(nonce.into()),
|
||||
None => Err(errors::database("latest nonce missing"))
|
||||
}
|
||||
}
|
||||
BlockNumber::Pending => {
|
||||
match self.miner.nonce(&*self.client, &address) {
|
||||
Some(nonce) => Ok(nonce.into()),
|
||||
None => Err(errors::database("latest nonce missing"))
|
||||
}
|
||||
}
|
||||
id => {
|
||||
try_bf!(check_known(&*self.client, id.clone()));
|
||||
match self.client.nonce(&address, id.into()) {
|
||||
@@ -468,20 +447,12 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
||||
fn code_at(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<Bytes, Error> {
|
||||
let address: Address = RpcH160::into(address);
|
||||
|
||||
let res = match num.unwrap_or_default() {
|
||||
BlockNumber::Pending => {
|
||||
match self.miner.code(&*self.client, &address) {
|
||||
Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)),
|
||||
None => Err(errors::database("latest code missing"))
|
||||
}
|
||||
}
|
||||
id => {
|
||||
try_bf!(check_known(&*self.client, id.clone()));
|
||||
match self.client.code(&address, id.into()) {
|
||||
Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)),
|
||||
None => Err(errors::state_pruned()),
|
||||
}
|
||||
}
|
||||
let id = num.unwrap_or_default();
|
||||
try_bf!(check_known(&*self.client, id.clone()));
|
||||
|
||||
let res = match self.client.code(&address, id.into()) {
|
||||
Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)),
|
||||
None => Err(errors::state_pruned()),
|
||||
};
|
||||
|
||||
future::done(res).boxed()
|
||||
@@ -641,17 +612,15 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
||||
self.send_raw_transaction(raw)
|
||||
}
|
||||
|
||||
fn call(&self, request: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<Bytes, Error> {
|
||||
fn call(&self, meta: Self::Metadata, request: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<Bytes, Error> {
|
||||
let request = CallRequest::into(request);
|
||||
let signed = match fake_sign::sign_call(&self.client, &self.miner, request) {
|
||||
let signed = match fake_sign::sign_call(&self.client, &self.miner, request, meta.is_dapp()) {
|
||||
Ok(signed) => signed,
|
||||
Err(e) => return future::err(e).boxed(),
|
||||
};
|
||||
|
||||
let result = match num.unwrap_or_default() {
|
||||
BlockNumber::Pending => self.miner.call(&*self.client, &signed, Default::default()),
|
||||
num => self.client.call(&signed, num.into(), Default::default()),
|
||||
};
|
||||
let num = num.unwrap_or_default();
|
||||
let result = self.client.call(&signed, Default::default(), num.into());
|
||||
|
||||
future::done(result
|
||||
.map(|b| b.output.into())
|
||||
@@ -659,9 +628,9 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
||||
).boxed()
|
||||
}
|
||||
|
||||
fn estimate_gas(&self, request: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256, Error> {
|
||||
fn estimate_gas(&self, meta: Self::Metadata, request: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256, Error> {
|
||||
let request = CallRequest::into(request);
|
||||
let signed = match fake_sign::sign_call(&self.client, &self.miner, request) {
|
||||
let signed = match fake_sign::sign_call(&self.client, &self.miner, request, meta.is_dapp()) {
|
||||
Ok(signed) => signed,
|
||||
Err(e) => return future::err(e).boxed(),
|
||||
};
|
||||
|
||||
@@ -245,17 +245,27 @@ impl<C: Send + Sync + 'static> EthPubSub for EthPubSubClient<C> {
|
||||
kind: pubsub::Kind,
|
||||
params: Trailing<pubsub::Params>,
|
||||
) {
|
||||
match (kind, params.into()) {
|
||||
let error = match (kind, params.into()) {
|
||||
(pubsub::Kind::NewHeads, None) => {
|
||||
self.heads_subscribers.write().push(subscriber)
|
||||
self.heads_subscribers.write().push(subscriber);
|
||||
return;
|
||||
},
|
||||
(pubsub::Kind::Logs, Some(pubsub::Params::Logs(filter))) => {
|
||||
self.logs_subscribers.write().push(subscriber, filter.into());
|
||||
return;
|
||||
},
|
||||
(pubsub::Kind::NewHeads, _) => {
|
||||
errors::invalid_params("newHeads", "Expected no parameters.")
|
||||
},
|
||||
(pubsub::Kind::Logs, _) => {
|
||||
errors::invalid_params("logs", "Expected a filter object.")
|
||||
},
|
||||
_ => {
|
||||
let _ = subscriber.reject(errors::unimplemented(None));
|
||||
errors::unimplemented(None)
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
let _ = subscriber.reject(error);
|
||||
}
|
||||
|
||||
fn unsubscribe(&self, id: SubscriptionId) -> BoxFuture<bool, Error> {
|
||||
|
||||
@@ -383,7 +383,7 @@ impl Eth for EthClient {
|
||||
self.send_raw_transaction(raw)
|
||||
}
|
||||
|
||||
fn call(&self, req: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<Bytes, Error> {
|
||||
fn call(&self, _meta: Self::Metadata, req: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<Bytes, Error> {
|
||||
self.fetcher().proved_execution(req, num).and_then(|res| {
|
||||
match res {
|
||||
Ok(exec) => Ok(exec.output.into()),
|
||||
@@ -392,7 +392,7 @@ impl Eth for EthClient {
|
||||
}).boxed()
|
||||
}
|
||||
|
||||
fn estimate_gas(&self, req: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256, Error> {
|
||||
fn estimate_gas(&self, _meta: Self::Metadata, req: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256, Error> {
|
||||
// TODO: binary chop for more accurate estimates.
|
||||
self.fetcher().proved_execution(req, num).and_then(|res| {
|
||||
match res {
|
||||
|
||||
@@ -19,15 +19,15 @@ use std::sync::Arc;
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use futures::{future, Future, BoxFuture};
|
||||
|
||||
use ethcore_logger::RotatingLogger;
|
||||
use util::misc::version_data;
|
||||
|
||||
use crypto::ecies;
|
||||
use crypto::{ecies, DEFAULT_MAC};
|
||||
use ethkey::{Brain, Generator};
|
||||
use ethstore::random_phrase;
|
||||
use ethsync::LightSyncProvider;
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use crypto::DEFAULT_MAC;
|
||||
use ethcore_logger::RotatingLogger;
|
||||
use node_health::{NodeHealth, Health};
|
||||
|
||||
use light::client::LightChainClient;
|
||||
|
||||
@@ -39,7 +39,7 @@ use v1::helpers::light_fetch::LightFetch;
|
||||
use v1::metadata::Metadata;
|
||||
use v1::traits::Parity;
|
||||
use v1::types::{
|
||||
Bytes, U256, H160, H256, H512,
|
||||
Bytes, U256, H160, H256, H512, CallRequest,
|
||||
Peers, Transaction, RpcSettings, Histogram,
|
||||
TransactionStats, LocalTransactionStatus,
|
||||
BlockNumber, ConsensusCapability, VersionInfo,
|
||||
@@ -53,6 +53,7 @@ pub struct ParityClient {
|
||||
accounts: Arc<AccountProvider>,
|
||||
logger: Arc<RotatingLogger>,
|
||||
settings: Arc<NetworkSettings>,
|
||||
health: NodeHealth,
|
||||
signer: Option<Arc<SignerService>>,
|
||||
dapps_address: Option<(String, u16)>,
|
||||
ws_address: Option<(String, u16)>,
|
||||
@@ -67,18 +68,20 @@ impl ParityClient {
|
||||
accounts: Arc<AccountProvider>,
|
||||
logger: Arc<RotatingLogger>,
|
||||
settings: Arc<NetworkSettings>,
|
||||
health: NodeHealth,
|
||||
signer: Option<Arc<SignerService>>,
|
||||
dapps_address: Option<(String, u16)>,
|
||||
ws_address: Option<(String, u16)>,
|
||||
) -> Self {
|
||||
ParityClient {
|
||||
light_dispatch: light_dispatch,
|
||||
accounts: accounts,
|
||||
logger: logger,
|
||||
settings: settings,
|
||||
signer: signer,
|
||||
dapps_address: dapps_address,
|
||||
ws_address: ws_address,
|
||||
light_dispatch,
|
||||
accounts,
|
||||
logger,
|
||||
settings,
|
||||
health,
|
||||
signer,
|
||||
dapps_address,
|
||||
ws_address,
|
||||
eip86_transition: client.eip86_transition(),
|
||||
}
|
||||
}
|
||||
@@ -389,4 +392,14 @@ impl Parity for ParityClient {
|
||||
fn ipfs_cid(&self, content: Bytes) -> Result<String, Error> {
|
||||
ipfs::cid(content)
|
||||
}
|
||||
|
||||
fn call(&self, _meta: Self::Metadata, _requests: Vec<CallRequest>, _block: Trailing<BlockNumber>) -> BoxFuture<Vec<Bytes>, Error> {
|
||||
future::err(errors::light_unimplemented(None)).boxed()
|
||||
}
|
||||
|
||||
fn node_health(&self) -> BoxFuture<Health, Error> {
|
||||
self.health.health()
|
||||
.map_err(|err| errors::internal("Health API failure.", err))
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +135,10 @@ impl<F: Fetch> ParitySet for ParitySetClient<F> {
|
||||
}))
|
||||
}
|
||||
|
||||
fn dapps_refresh(&self) -> Result<bool, Error> {
|
||||
self.dapps.as_ref().map(|dapps| dapps.refresh_local_dapps()).ok_or_else(errors::dapps_disabled)
|
||||
}
|
||||
|
||||
fn dapps_list(&self) -> Result<Vec<LocalDapp>, Error> {
|
||||
self.dapps.as_ref().map(|dapps| dapps.list_dapps()).ok_or_else(errors::dapps_disabled)
|
||||
}
|
||||
|
||||
@@ -17,16 +17,20 @@
|
||||
//! Traces api implementation.
|
||||
|
||||
use jsonrpc_core::Error;
|
||||
use jsonrpc_core::futures::{future, Future, BoxFuture};
|
||||
use jsonrpc_macros::Trailing;
|
||||
use v1::Metadata;
|
||||
use v1::traits::Traces;
|
||||
use v1::helpers::errors;
|
||||
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256};
|
||||
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceOptions, H256};
|
||||
|
||||
/// Traces api implementation.
|
||||
// TODO: all calling APIs should be possible w. proved remote TX execution.
|
||||
pub struct TracesClient;
|
||||
|
||||
impl Traces for TracesClient {
|
||||
type Metadata = Metadata;
|
||||
|
||||
fn filter(&self, _filter: TraceFilter) -> Result<Option<Vec<LocalizedTrace>>, Error> {
|
||||
Err(errors::light_unimplemented(None))
|
||||
}
|
||||
@@ -43,15 +47,19 @@ impl Traces for TracesClient {
|
||||
Err(errors::light_unimplemented(None))
|
||||
}
|
||||
|
||||
fn call(&self, _request: CallRequest, _flags: Vec<String>, _block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
|
||||
fn call(&self, _meta: Self::Metadata, _request: CallRequest, _flags: TraceOptions, _block: Trailing<BlockNumber>) -> BoxFuture<TraceResults, Error> {
|
||||
future::err(errors::light_unimplemented(None)).boxed()
|
||||
}
|
||||
|
||||
fn call_many(&self, _meta: Self::Metadata, _request: Vec<(CallRequest, TraceOptions)>, _block: Trailing<BlockNumber>) -> BoxFuture<Vec<TraceResults>, Error> {
|
||||
future::err(errors::light_unimplemented(None)).boxed()
|
||||
}
|
||||
|
||||
fn raw_transaction(&self, _raw_transaction: Bytes, _flags: TraceOptions, _block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
|
||||
Err(errors::light_unimplemented(None))
|
||||
}
|
||||
|
||||
fn raw_transaction(&self, _raw_transaction: Bytes, _flags: Vec<String>, _block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
|
||||
Err(errors::light_unimplemented(None))
|
||||
}
|
||||
|
||||
fn replay_transaction(&self, _transaction_hash: H256, _flags: Vec<String>) -> Result<TraceResults, Error> {
|
||||
fn replay_transaction(&self, _transaction_hash: H256, _flags: TraceOptions) -> Result<TraceResults, Error> {
|
||||
Err(errors::light_unimplemented(None))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,30 +20,31 @@ use std::str::FromStr;
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use futures::{future, Future, BoxFuture};
|
||||
|
||||
use ethcore_logger::RotatingLogger;
|
||||
use util::Address;
|
||||
use util::misc::version_data;
|
||||
|
||||
use crypto::ecies;
|
||||
use crypto::{DEFAULT_MAC, ecies};
|
||||
use ethkey::{Brain, Generator};
|
||||
use ethstore::random_phrase;
|
||||
use ethsync::{SyncProvider, ManageNetwork};
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use ethcore::client::{MiningBlockChainClient};
|
||||
use ethcore::ids::BlockId;
|
||||
use ethcore::miner::MinerService;
|
||||
use ethcore::client::{MiningBlockChainClient};
|
||||
use ethcore::mode::Mode;
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use ethcore::transaction::SignedTransaction;
|
||||
use ethcore_logger::RotatingLogger;
|
||||
use node_health::{NodeHealth, Health};
|
||||
use updater::{Service as UpdateService};
|
||||
use crypto::DEFAULT_MAC;
|
||||
|
||||
use jsonrpc_core::Error;
|
||||
use jsonrpc_macros::Trailing;
|
||||
use v1::helpers::{self, errors, ipfs, SigningQueue, SignerService, NetworkSettings};
|
||||
use v1::helpers::{self, errors, fake_sign, ipfs, SigningQueue, SignerService, NetworkSettings};
|
||||
use v1::helpers::accounts::unwrap_provider;
|
||||
use v1::metadata::Metadata;
|
||||
use v1::traits::Parity;
|
||||
use v1::types::{
|
||||
Bytes, U256, H160, H256, H512,
|
||||
Bytes, U256, H160, H256, H512, CallRequest,
|
||||
Peers, Transaction, RpcSettings, Histogram,
|
||||
TransactionStats, LocalTransactionStatus,
|
||||
BlockNumber, ConsensusCapability, VersionInfo,
|
||||
@@ -52,17 +53,13 @@ use v1::types::{
|
||||
};
|
||||
|
||||
/// Parity implementation.
|
||||
pub struct ParityClient<C, M, S: ?Sized, U> where
|
||||
C: MiningBlockChainClient,
|
||||
M: MinerService,
|
||||
S: SyncProvider,
|
||||
U: UpdateService,
|
||||
{
|
||||
pub struct ParityClient<C, M, U> {
|
||||
client: Arc<C>,
|
||||
miner: Arc<M>,
|
||||
sync: Arc<S>,
|
||||
updater: Arc<U>,
|
||||
sync: Arc<SyncProvider>,
|
||||
net: Arc<ManageNetwork>,
|
||||
health: NodeHealth,
|
||||
accounts: Option<Arc<AccountProvider>>,
|
||||
logger: Arc<RotatingLogger>,
|
||||
settings: Arc<NetworkSettings>,
|
||||
@@ -72,39 +69,39 @@ pub struct ParityClient<C, M, S: ?Sized, U> where
|
||||
eip86_transition: u64,
|
||||
}
|
||||
|
||||
impl<C, M, S: ?Sized, U> ParityClient<C, M, S, U> where
|
||||
impl<C, M, U> ParityClient<C, M, U> where
|
||||
C: MiningBlockChainClient,
|
||||
M: MinerService,
|
||||
S: SyncProvider,
|
||||
U: UpdateService,
|
||||
{
|
||||
/// Creates new `ParityClient`.
|
||||
pub fn new(
|
||||
client: &Arc<C>,
|
||||
miner: &Arc<M>,
|
||||
sync: &Arc<S>,
|
||||
updater: &Arc<U>,
|
||||
net: &Arc<ManageNetwork>,
|
||||
store: &Option<Arc<AccountProvider>>,
|
||||
client: Arc<C>,
|
||||
miner: Arc<M>,
|
||||
sync: Arc<SyncProvider>,
|
||||
updater: Arc<U>,
|
||||
net: Arc<ManageNetwork>,
|
||||
health: NodeHealth,
|
||||
accounts: Option<Arc<AccountProvider>>,
|
||||
logger: Arc<RotatingLogger>,
|
||||
settings: Arc<NetworkSettings>,
|
||||
signer: Option<Arc<SignerService>>,
|
||||
dapps_address: Option<(String, u16)>,
|
||||
ws_address: Option<(String, u16)>,
|
||||
) -> Self {
|
||||
let eip86_transition = client.eip86_transition();
|
||||
ParityClient {
|
||||
client: client.clone(),
|
||||
miner: miner.clone(),
|
||||
sync: sync.clone(),
|
||||
updater: updater.clone(),
|
||||
net: net.clone(),
|
||||
accounts: store.clone(),
|
||||
logger: logger,
|
||||
settings: settings,
|
||||
signer: signer,
|
||||
dapps_address: dapps_address,
|
||||
ws_address: ws_address,
|
||||
eip86_transition: client.eip86_transition(),
|
||||
client,
|
||||
miner,
|
||||
sync,
|
||||
updater,
|
||||
net,
|
||||
health,
|
||||
accounts,
|
||||
logger,
|
||||
settings,
|
||||
signer,
|
||||
dapps_address,
|
||||
ws_address,
|
||||
eip86_transition,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,10 +112,9 @@ impl<C, M, S: ?Sized, U> ParityClient<C, M, S, U> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
|
||||
M: MinerService + 'static,
|
||||
impl<C, M, U> Parity for ParityClient<C, M, U> where
|
||||
C: MiningBlockChainClient + 'static,
|
||||
S: SyncProvider + 'static,
|
||||
M: MinerService + 'static,
|
||||
U: UpdateService + 'static,
|
||||
{
|
||||
type Metadata = Metadata;
|
||||
@@ -409,4 +405,29 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
|
||||
fn ipfs_cid(&self, content: Bytes) -> Result<String, Error> {
|
||||
ipfs::cid(content)
|
||||
}
|
||||
|
||||
fn call(&self, meta: Self::Metadata, requests: Vec<CallRequest>, block: Trailing<BlockNumber>) -> BoxFuture<Vec<Bytes>, Error> {
|
||||
let requests: Result<Vec<(SignedTransaction, _)>, Error> = requests
|
||||
.into_iter()
|
||||
.map(|request| Ok((
|
||||
fake_sign::sign_call(&self.client, &self.miner, request.into(), meta.is_dapp())?,
|
||||
Default::default()
|
||||
)))
|
||||
.collect();
|
||||
|
||||
let block = block.unwrap_or_default();
|
||||
let requests = try_bf!(requests);
|
||||
|
||||
let result = self.client.call_many(&requests, block.into())
|
||||
.map(|res| res.into_iter().map(|res| res.output.into()).collect())
|
||||
.map_err(errors::call);
|
||||
|
||||
future::done(result).boxed()
|
||||
}
|
||||
|
||||
fn node_health(&self) -> BoxFuture<Health, Error> {
|
||||
self.health.health()
|
||||
.map_err(|err| errors::internal("Health API failure.", err))
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,6 +176,10 @@ impl<C, M, U, F> ParitySet for ParitySetClient<C, M, U, F> where
|
||||
}))
|
||||
}
|
||||
|
||||
fn dapps_refresh(&self) -> Result<bool, Error> {
|
||||
self.dapps.as_ref().map(|dapps| dapps.refresh_local_dapps()).ok_or_else(errors::dapps_disabled)
|
||||
}
|
||||
|
||||
fn dapps_list(&self) -> Result<Vec<LocalDapp>, Error> {
|
||||
self.dapps.as_ref().map(|dapps| dapps.list_dapps()).ok_or_else(errors::dapps_disabled)
|
||||
}
|
||||
|
||||
@@ -124,9 +124,9 @@ impl<D: Dispatcher + 'static> Personal for PersonalClient<D> {
|
||||
.map(move |tx| (tx, dispatcher))
|
||||
})
|
||||
.and_then(|(pending_tx, dispatcher)| {
|
||||
let network_id = pending_tx.network_id();
|
||||
trace!(target: "miner", "send_transaction: dispatching tx: {} for network ID {:?}",
|
||||
::rlp::encode(&*pending_tx).into_vec().pretty(), network_id);
|
||||
let chain_id = pending_tx.chain_id();
|
||||
trace!(target: "miner", "send_transaction: dispatching tx: {} for chain ID {:?}",
|
||||
::rlp::encode(&*pending_tx).into_vec().pretty(), chain_id);
|
||||
|
||||
dispatcher.dispatch_transaction(pending_tx).map(Into::into)
|
||||
})
|
||||
|
||||
@@ -18,18 +18,20 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use rlp::UntrustedRlp;
|
||||
use ethcore::client::{MiningBlockChainClient, CallAnalytics, TransactionId, TraceId};
|
||||
use ethcore::miner::MinerService;
|
||||
use ethcore::transaction::SignedTransaction;
|
||||
use rlp::UntrustedRlp;
|
||||
|
||||
use jsonrpc_core::Error;
|
||||
use jsonrpc_core::futures::{self, Future, BoxFuture};
|
||||
use jsonrpc_macros::Trailing;
|
||||
use v1::Metadata;
|
||||
use v1::traits::Traces;
|
||||
use v1::helpers::{errors, fake_sign};
|
||||
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256};
|
||||
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceOptions, H256};
|
||||
|
||||
fn to_call_analytics(flags: Vec<String>) -> CallAnalytics {
|
||||
fn to_call_analytics(flags: TraceOptions) -> CallAnalytics {
|
||||
CallAnalytics {
|
||||
transaction_tracing: flags.contains(&("trace".to_owned())),
|
||||
vm_tracing: flags.contains(&("vmTrace".to_owned())),
|
||||
@@ -54,6 +56,8 @@ impl<C, M> TracesClient<C, M> {
|
||||
}
|
||||
|
||||
impl<C, M> Traces for TracesClient<C, M> where C: MiningBlockChainClient + 'static, M: MinerService + 'static {
|
||||
type Metadata = Metadata;
|
||||
|
||||
fn filter(&self, filter: TraceFilter) -> Result<Option<Vec<LocalizedTrace>>, Error> {
|
||||
Ok(self.client.filter_traces(filter.into())
|
||||
.map(|traces| traces.into_iter().map(LocalizedTrace::from).collect()))
|
||||
@@ -79,29 +83,49 @@ impl<C, M> Traces for TracesClient<C, M> where C: MiningBlockChainClient + 'stat
|
||||
.map(LocalizedTrace::from))
|
||||
}
|
||||
|
||||
fn call(&self, request: CallRequest, flags: Vec<String>, block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
|
||||
fn call(&self, meta: Self::Metadata, request: CallRequest, flags: TraceOptions, block: Trailing<BlockNumber>) -> BoxFuture<TraceResults, Error> {
|
||||
let block = block.unwrap_or_default();
|
||||
|
||||
let request = CallRequest::into(request);
|
||||
let signed = fake_sign::sign_call(&self.client, &self.miner, request)?;
|
||||
let signed = try_bf!(fake_sign::sign_call(&self.client, &self.miner, request, meta.is_dapp()));
|
||||
|
||||
self.client.call(&signed, block.into(), to_call_analytics(flags))
|
||||
let res = self.client.call(&signed, to_call_analytics(flags), block.into())
|
||||
.map(TraceResults::from)
|
||||
.map_err(errors::call)
|
||||
.map_err(errors::call);
|
||||
|
||||
futures::done(res).boxed()
|
||||
}
|
||||
|
||||
fn raw_transaction(&self, raw_transaction: Bytes, flags: Vec<String>, block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
|
||||
fn call_many(&self, meta: Self::Metadata, requests: Vec<(CallRequest, TraceOptions)>, block: Trailing<BlockNumber>) -> BoxFuture<Vec<TraceResults>, Error> {
|
||||
let block = block.unwrap_or_default();
|
||||
|
||||
let requests = try_bf!(requests.into_iter()
|
||||
.map(|(request, flags)| {
|
||||
let request = CallRequest::into(request);
|
||||
let signed = fake_sign::sign_call(&self.client, &self.miner, request, meta.is_dapp())?;
|
||||
Ok((signed, to_call_analytics(flags)))
|
||||
})
|
||||
.collect::<Result<Vec<_>, Error>>());
|
||||
|
||||
let res = self.client.call_many(&requests, block.into())
|
||||
.map(|results| results.into_iter().map(TraceResults::from).collect())
|
||||
.map_err(errors::call);
|
||||
|
||||
futures::done(res).boxed()
|
||||
}
|
||||
|
||||
fn raw_transaction(&self, raw_transaction: Bytes, flags: TraceOptions, block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
|
||||
let block = block.unwrap_or_default();
|
||||
|
||||
let tx = UntrustedRlp::new(&raw_transaction.into_vec()).as_val().map_err(|e| errors::invalid_params("Transaction is not valid RLP", e))?;
|
||||
let signed = SignedTransaction::new(tx).map_err(errors::transaction)?;
|
||||
|
||||
self.client.call(&signed, block.into(), to_call_analytics(flags))
|
||||
self.client.call(&signed, to_call_analytics(flags), block.into())
|
||||
.map(TraceResults::from)
|
||||
.map_err(errors::call)
|
||||
}
|
||||
|
||||
fn replay_transaction(&self, transaction_hash: H256, flags: Vec<String>) -> Result<TraceResults, Error> {
|
||||
fn replay_transaction(&self, transaction_hash: H256, flags: TraceOptions) -> Result<TraceResults, Error> {
|
||||
self.client.replay(TransactionId::Hash(transaction_hash.into()), to_call_analytics(flags))
|
||||
.map(TraceResults::from)
|
||||
.map_err(errors::call)
|
||||
|
||||
@@ -42,6 +42,15 @@ impl Metadata {
|
||||
_ => DappId::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the request originates from a Dapp.
|
||||
pub fn is_dapp(&self) -> bool {
|
||||
if let Origin::Dapps(_) = self.origin {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl jsonrpc_core::Metadata for Metadata {}
|
||||
|
||||
@@ -34,4 +34,8 @@ impl DappsService for TestDappsService {
|
||||
icon_url: "title.png".into(),
|
||||
}]
|
||||
}
|
||||
|
||||
fn refresh_local_dapps(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::collections::hash_map::Entry;
|
||||
use util::{Address, H256, Bytes, U256, RwLock, Mutex};
|
||||
use ethcore::error::{Error, CallError};
|
||||
use ethcore::client::{MiningBlockChainClient, Executed, CallAnalytics};
|
||||
use ethcore::block::{ClosedBlock, IsBlock};
|
||||
use ethcore::error::Error;
|
||||
use ethcore::client::MiningBlockChainClient;
|
||||
use ethcore::block::ClosedBlock;
|
||||
use ethcore::header::BlockNumber;
|
||||
use ethcore::transaction::{UnverifiedTransaction, SignedTransaction, PendingTransaction};
|
||||
use ethcore::receipt::{Receipt, RichReceipt};
|
||||
@@ -280,41 +280,6 @@ impl MinerService for TestMinerService {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn balance(&self, _chain: &MiningBlockChainClient, address: &Address) -> Option<U256> {
|
||||
self.latest_closed_block.lock()
|
||||
.as_ref()
|
||||
.map(|b| b.block().fields().state.balance(address))
|
||||
.map(|b| b.ok())
|
||||
.unwrap_or(Some(U256::default()))
|
||||
}
|
||||
|
||||
fn call(&self, _chain: &MiningBlockChainClient, _t: &SignedTransaction, _analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn storage_at(&self, _chain: &MiningBlockChainClient, address: &Address, position: &H256) -> Option<H256> {
|
||||
self.latest_closed_block.lock()
|
||||
.as_ref()
|
||||
.map(|b| b.block().fields().state.storage_at(address, position))
|
||||
.map(|s| s.ok())
|
||||
.unwrap_or(Some(H256::default()))
|
||||
}
|
||||
|
||||
fn nonce(&self, _chain: &MiningBlockChainClient, address: &Address) -> Option<U256> {
|
||||
// we assume all transactions are in a pending block, ignoring the
|
||||
// reality of gas limits.
|
||||
Some(self.last_nonce(address).unwrap_or(U256::zero()))
|
||||
}
|
||||
|
||||
fn code(&self, _chain: &MiningBlockChainClient, address: &Address) -> Option<Option<Bytes>> {
|
||||
self.latest_closed_block.lock()
|
||||
.as_ref()
|
||||
.map(|b| b.block().fields().state.code(address))
|
||||
.map(|c| c.ok())
|
||||
.unwrap_or(None)
|
||||
.map(|c| c.map(|c| (&*c).clone()))
|
||||
}
|
||||
|
||||
fn sensible_gas_price(&self) -> U256 {
|
||||
20000000000u64.into()
|
||||
}
|
||||
|
||||
@@ -432,10 +432,7 @@ fn rpc_eth_balance_pending() {
|
||||
"id": 1
|
||||
}"#;
|
||||
|
||||
// the TestMinerService doesn't communicate with the the TestBlockChainClient in any way.
|
||||
// if this returns zero, we know that the "pending" call is being properly forwarded to the
|
||||
// miner.
|
||||
let response = r#"{"jsonrpc":"2.0","result":"0x0","id":1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":"0x5","id":1}"#;
|
||||
|
||||
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
|
||||
}
|
||||
@@ -547,7 +544,7 @@ fn rpc_eth_pending_transaction_by_hash() {
|
||||
tester.miner.pending_transactions.lock().insert(H256::zero(), tx);
|
||||
}
|
||||
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"condition":null,"creates":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x1","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","networkId":null,"nonce":"0x0","publicKey":"0x7ae46da747962c2ee46825839c1ef9298e3bd2e70ca2938495c3693a485ec3eaa8f196327881090ff64cf4fbb0a48485d4f83098e189ed3b7a87d5941b59f789","r":"0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353","raw":"0xf85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","s":"0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","standardV":"0x0","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"v":"0x1b","value":"0xa"},"id":1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"chainId":null,"condition":null,"creates":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x1","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","nonce":"0x0","publicKey":"0x7ae46da747962c2ee46825839c1ef9298e3bd2e70ca2938495c3693a485ec3eaa8f196327881090ff64cf4fbb0a48485d4f83098e189ed3b7a87d5941b59f789","r":"0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353","raw":"0xf85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","s":"0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","standardV":"0x0","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"v":"0x1b","value":"0xa"},"id":1}"#;
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_getTransactionByHash",
|
||||
@@ -863,12 +860,13 @@ fn rpc_eth_sign_transaction() {
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned() +
|
||||
r#""raw":"0x"# + &rlp.to_hex() + r#"","# +
|
||||
r#""tx":{"# +
|
||||
r#""blockHash":null,"blockNumber":null,"condition":null,"creates":null,"# +
|
||||
r#""blockHash":null,"blockNumber":null,"# +
|
||||
&format!("\"chainId\":{},", t.chain_id().map_or("null".to_owned(), |n| format!("{}", n))) +
|
||||
r#""condition":null,"creates":null,"# +
|
||||
&format!("\"from\":\"0x{:?}\",", &address) +
|
||||
r#""gas":"0x76c0","gasPrice":"0x9184e72a000","# +
|
||||
&format!("\"hash\":\"0x{:?}\",", t.hash()) +
|
||||
r#""input":"0x","# +
|
||||
&format!("\"networkId\":{},", t.network_id().map_or("null".to_owned(), |n| format!("{}", n))) +
|
||||
r#""nonce":"0x1","# +
|
||||
&format!("\"publicKey\":\"0x{:?}\",", t.recover_public().unwrap()) +
|
||||
&format!("\"r\":\"0x{}\",", U256::from(signature.r()).to_hex()) +
|
||||
|
||||
@@ -15,13 +15,15 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::sync::Arc;
|
||||
use ethcore_logger::RotatingLogger;
|
||||
use util::Address;
|
||||
use ethsync::ManageNetwork;
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use ethcore::client::{TestBlockChainClient};
|
||||
use ethcore::client::{TestBlockChainClient, Executed};
|
||||
use ethcore::miner::LocalTransactionStatus;
|
||||
use ethcore_logger::RotatingLogger;
|
||||
use ethstore::ethkey::{Generator, Random};
|
||||
use ethsync::ManageNetwork;
|
||||
use node_health::{self, NodeHealth};
|
||||
use parity_reactor;
|
||||
use util::Address;
|
||||
|
||||
use jsonrpc_core::IoHandler;
|
||||
use v1::{Parity, ParityClient};
|
||||
@@ -30,13 +32,14 @@ use v1::helpers::{SignerService, NetworkSettings};
|
||||
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService, TestUpdater};
|
||||
use super::manage_network::TestManageNetwork;
|
||||
|
||||
pub type TestParityClient = ParityClient<TestBlockChainClient, TestMinerService, TestSyncProvider, TestUpdater>;
|
||||
pub type TestParityClient = ParityClient<TestBlockChainClient, TestMinerService, TestUpdater>;
|
||||
|
||||
pub struct Dependencies {
|
||||
pub miner: Arc<TestMinerService>,
|
||||
pub client: Arc<TestBlockChainClient>,
|
||||
pub sync: Arc<TestSyncProvider>,
|
||||
pub updater: Arc<TestUpdater>,
|
||||
pub health: NodeHealth,
|
||||
pub logger: Arc<RotatingLogger>,
|
||||
pub settings: Arc<NetworkSettings>,
|
||||
pub network: Arc<ManageNetwork>,
|
||||
@@ -54,6 +57,11 @@ impl Dependencies {
|
||||
network_id: 3,
|
||||
num_peers: 120,
|
||||
})),
|
||||
health: NodeHealth::new(
|
||||
Arc::new(FakeSync),
|
||||
node_health::TimeChecker::new::<String>(&[], node_health::CpuPool::new(1)),
|
||||
parity_reactor::Remote::new_sync(),
|
||||
),
|
||||
updater: Arc::new(TestUpdater::default()),
|
||||
logger: Arc::new(RotatingLogger::new("rpc=trace".to_owned())),
|
||||
settings: Arc::new(NetworkSettings {
|
||||
@@ -75,12 +83,13 @@ impl Dependencies {
|
||||
let opt_accounts = Some(self.accounts.clone());
|
||||
|
||||
ParityClient::new(
|
||||
&self.client,
|
||||
&self.miner,
|
||||
&self.sync,
|
||||
&self.updater,
|
||||
&self.network,
|
||||
&opt_accounts,
|
||||
self.client.clone(),
|
||||
self.miner.clone(),
|
||||
self.sync.clone(),
|
||||
self.updater.clone(),
|
||||
self.network.clone(),
|
||||
self.health.clone(),
|
||||
opt_accounts.clone(),
|
||||
self.logger.clone(),
|
||||
self.settings.clone(),
|
||||
signer,
|
||||
@@ -102,6 +111,13 @@ impl Dependencies {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FakeSync;
|
||||
impl node_health::SyncStatus for FakeSync {
|
||||
fn is_major_importing(&self) -> bool { false }
|
||||
fn peers(&self) -> (usize, usize) { (4, 25) }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_parity_accounts_info() {
|
||||
let deps = Dependencies::new();
|
||||
@@ -504,3 +520,53 @@ fn rpc_parity_cid() {
|
||||
|
||||
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_parity_call() {
|
||||
use util::U256;
|
||||
|
||||
let deps = Dependencies::new();
|
||||
deps.client.set_execution_result(Ok(Executed {
|
||||
exception: None,
|
||||
gas: U256::zero(),
|
||||
gas_used: U256::from(0xff30),
|
||||
refunded: U256::from(0x5),
|
||||
cumulative_gas_used: U256::zero(),
|
||||
logs: vec![],
|
||||
contracts_created: vec![],
|
||||
output: vec![0x12, 0x34, 0xff],
|
||||
trace: vec![],
|
||||
vm_trace: None,
|
||||
state_diff: None,
|
||||
}));
|
||||
let io = deps.default_client();
|
||||
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "parity_call",
|
||||
"params": [[{
|
||||
"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
|
||||
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
|
||||
"gas": "0x76c0",
|
||||
"gasPrice": "0x9184e72a000",
|
||||
"value": "0x9184e72a",
|
||||
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
|
||||
}],
|
||||
"latest"],
|
||||
"id": 1
|
||||
}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":["0x1234ff"],"id":1}"#;
|
||||
|
||||
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_parity_node_health() {
|
||||
let deps = Dependencies::new();
|
||||
let io = deps.default_client();
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "parity_nodeHealth", "params":[], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"peers":{"details":[4,25],"message":"","status":"ok"},"sync":{"details":false,"message":"","status":"ok"},"time":{"details":0,"message":"","status":"ok"}},"id":1}"#;
|
||||
|
||||
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ fn rpc_parity_remove_transaction() {
|
||||
let hash = signed.hash();
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "parity_removeTransaction", "params":[""#.to_owned() + &format!("0x{:?}", hash) + r#""], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"condition":null,"creates":null,"from":"0x0000000000000000000000000000000000000002","gas":"0x76c0","gasPrice":"0x9184e72a000","hash":"0xa2e0da8a8064e0b9f93e95a53c2db6d01280efb8ac72a708d25487e67dd0f8fc","input":"0x","networkId":null,"nonce":"0x1","publicKey":null,"r":"0x1","raw":"0xe9018609184e72a0008276c0940000000000000000000000000000000000000005849184e72a80800101","s":"0x1","standardV":"0x4","to":"0x0000000000000000000000000000000000000005","transactionIndex":null,"v":"0x0","value":"0x9184e72a"},"id":1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"chainId":null,"condition":null,"creates":null,"from":"0x0000000000000000000000000000000000000002","gas":"0x76c0","gasPrice":"0x9184e72a000","hash":"0xa2e0da8a8064e0b9f93e95a53c2db6d01280efb8ac72a708d25487e67dd0f8fc","input":"0x","nonce":"0x1","publicKey":null,"r":"0x1","raw":"0xe9018609184e72a0008276c0940000000000000000000000000000000000000005849184e72a80800101","s":"0x1","standardV":"0x4","to":"0x0000000000000000000000000000000000000005","transactionIndex":null,"v":"0x0","value":"0x9184e72a"},"id":1}"#;
|
||||
|
||||
miner.pending_transactions.lock().insert(hash, signed);
|
||||
assert_eq!(io.handle_request_sync(&request), Some(response.to_owned()));
|
||||
|
||||
@@ -454,12 +454,13 @@ fn should_confirm_sign_transaction_with_rlp() {
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned() +
|
||||
r#""raw":"0x"# + &rlp.to_hex() + r#"","# +
|
||||
r#""tx":{"# +
|
||||
r#""blockHash":null,"blockNumber":null,"condition":null,"creates":null,"# +
|
||||
r#""blockHash":null,"blockNumber":null,"# +
|
||||
&format!("\"chainId\":{},", t.chain_id().map_or("null".to_owned(), |n| format!("{}", n))) +
|
||||
r#""condition":null,"creates":null,"# +
|
||||
&format!("\"from\":\"0x{:?}\",", &address) +
|
||||
r#""gas":"0x989680","gasPrice":"0x1000","# +
|
||||
&format!("\"hash\":\"0x{:?}\",", t.hash()) +
|
||||
r#""input":"0x","# +
|
||||
&format!("\"networkId\":{},", t.network_id().map_or("null".to_owned(), |n| format!("{}", n))) +
|
||||
r#""nonce":"0x0","# +
|
||||
&format!("\"publicKey\":\"0x{:?}\",", t.public_key().unwrap()) +
|
||||
&format!("\"r\":\"0x{}\",", U256::from(signature.r()).to_hex()) +
|
||||
|
||||
@@ -297,12 +297,13 @@ fn should_add_sign_transaction_to_the_queue() {
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned() +
|
||||
r#""raw":"0x"# + &rlp.to_hex() + r#"","# +
|
||||
r#""tx":{"# +
|
||||
r#""blockHash":null,"blockNumber":null,"condition":null,"creates":null,"# +
|
||||
r#""blockHash":null,"blockNumber":null,"# +
|
||||
&format!("\"chainId\":{},", t.chain_id().map_or("null".to_owned(), |n| format!("{}", n))) +
|
||||
r#""condition":null,"creates":null,"# +
|
||||
&format!("\"from\":\"0x{:?}\",", &address) +
|
||||
r#""gas":"0x76c0","gasPrice":"0x9184e72a000","# +
|
||||
&format!("\"hash\":\"0x{:?}\",", t.hash()) +
|
||||
r#""input":"0x","# +
|
||||
&format!("\"networkId\":{},", t.network_id().map_or("null".to_owned(), |n| format!("{}", n))) +
|
||||
r#""nonce":"0x1","# +
|
||||
&format!("\"publicKey\":\"0x{:?}\",", t.public_key().unwrap()) +
|
||||
&format!("\"r\":\"0x{}\",", U256::from(signature.r()).to_hex()) +
|
||||
|
||||
@@ -25,12 +25,12 @@ use vm::CallType;
|
||||
|
||||
use jsonrpc_core::IoHandler;
|
||||
use v1::tests::helpers::{TestMinerService};
|
||||
use v1::{Traces, TracesClient};
|
||||
use v1::{Metadata, Traces, TracesClient};
|
||||
|
||||
struct Tester {
|
||||
client: Arc<TestBlockChainClient>,
|
||||
_miner: Arc<TestMinerService>,
|
||||
io: IoHandler,
|
||||
io: IoHandler<Metadata>,
|
||||
}
|
||||
|
||||
fn io() -> Tester {
|
||||
@@ -67,7 +67,7 @@ fn io() -> Tester {
|
||||
}));
|
||||
let miner = Arc::new(TestMinerService::default());
|
||||
let traces = TracesClient::new(&client, &miner);
|
||||
let mut io = IoHandler::new();
|
||||
let mut io = IoHandler::default();
|
||||
io.extend_with(traces.to_delegate());
|
||||
|
||||
Tester {
|
||||
@@ -170,6 +170,16 @@ fn rpc_trace_call() {
|
||||
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_trace_multi_call() {
|
||||
let tester = io();
|
||||
|
||||
let request = r#"{"jsonrpc":"2.0","method":"trace_callMany","params":[[[{}, ["stateDiff", "vmTrace", "trace"]]]],"id":1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":[{"output":"0x010203","stateDiff":null,"trace":[],"vmTrace":null}],"id":1}"#;
|
||||
|
||||
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_trace_call_state_pruned() {
|
||||
let tester = io();
|
||||
|
||||
@@ -110,12 +110,12 @@ build_rpc_trait! {
|
||||
fn submit_transaction(&self, Bytes) -> Result<H256, Error>;
|
||||
|
||||
/// Call contract, returning the output data.
|
||||
#[rpc(async, name = "eth_call")]
|
||||
fn call(&self, CallRequest, Trailing<BlockNumber>) -> BoxFuture<Bytes, Error>;
|
||||
#[rpc(meta, name = "eth_call")]
|
||||
fn call(&self, Self::Metadata, CallRequest, Trailing<BlockNumber>) -> BoxFuture<Bytes, Error>;
|
||||
|
||||
/// Estimate gas needed for execution of given contract.
|
||||
#[rpc(async, name = "eth_estimateGas")]
|
||||
fn estimate_gas(&self, CallRequest, Trailing<BlockNumber>) -> BoxFuture<U256, Error>;
|
||||
#[rpc(meta, name = "eth_estimateGas")]
|
||||
fn estimate_gas(&self, Self::Metadata, CallRequest, Trailing<BlockNumber>) -> BoxFuture<U256, Error>;
|
||||
|
||||
/// Get transaction by its hash.
|
||||
#[rpc(name = "eth_getTransactionByHash")]
|
||||
|
||||
@@ -22,8 +22,9 @@ use jsonrpc_core::Error;
|
||||
use jsonrpc_macros::Trailing;
|
||||
use futures::BoxFuture;
|
||||
|
||||
use node_health::Health;
|
||||
use v1::types::{
|
||||
H160, H256, H512, U256, Bytes,
|
||||
H160, H256, H512, U256, Bytes, CallRequest,
|
||||
Peers, Transaction, RpcSettings, Histogram,
|
||||
TransactionStats, LocalTransactionStatus,
|
||||
BlockNumber, ConsensusCapability, VersionInfo,
|
||||
@@ -203,5 +204,13 @@ build_rpc_trait! {
|
||||
/// Get IPFS CIDv0 given protobuf encoded bytes.
|
||||
#[rpc(name = "parity_cidV0")]
|
||||
fn ipfs_cid(&self, Bytes) -> Result<String, Error>;
|
||||
|
||||
/// Call contract, returning the output data.
|
||||
#[rpc(meta, name = "parity_call")]
|
||||
fn call(&self, Self::Metadata, Vec<CallRequest>, Trailing<BlockNumber>) -> BoxFuture<Vec<Bytes>, Error>;
|
||||
|
||||
/// Returns node's health report.
|
||||
#[rpc(async, name = "parity_nodeHealth")]
|
||||
fn node_health(&self) -> BoxFuture<Health, Error>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +96,10 @@ build_rpc_trait! {
|
||||
#[rpc(async, name = "parity_hashContent")]
|
||||
fn hash_content(&self, String) -> BoxFuture<H256, Error>;
|
||||
|
||||
/// Returns true if refresh successful, error if unsuccessful or server is disabled.
|
||||
#[rpc(name = "parity_dappsRefresh")]
|
||||
fn dapps_refresh(&self) -> Result<bool, Error>;
|
||||
|
||||
/// Returns a list of local dapps
|
||||
#[rpc(name = "parity_dappsList")]
|
||||
fn dapps_list(&self) -> Result<Vec<LocalDapp>, Error>;
|
||||
|
||||
@@ -17,12 +17,15 @@
|
||||
//! Traces specific rpc interface.
|
||||
|
||||
use jsonrpc_core::Error;
|
||||
use jsonrpc_core::futures::BoxFuture;
|
||||
use jsonrpc_macros::Trailing;
|
||||
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256};
|
||||
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256, TraceOptions};
|
||||
|
||||
build_rpc_trait! {
|
||||
/// Traces specific rpc interface.
|
||||
pub trait Traces {
|
||||
type Metadata;
|
||||
|
||||
/// Returns traces matching given filter.
|
||||
#[rpc(name = "trace_filter")]
|
||||
fn filter(&self, TraceFilter) -> Result<Option<Vec<LocalizedTrace>>, Error>;
|
||||
@@ -40,15 +43,19 @@ build_rpc_trait! {
|
||||
fn block_traces(&self, BlockNumber) -> Result<Option<Vec<LocalizedTrace>>, Error>;
|
||||
|
||||
/// Executes the given call and returns a number of possible traces for it.
|
||||
#[rpc(name = "trace_call")]
|
||||
fn call(&self, CallRequest, Vec<String>, Trailing<BlockNumber>) -> Result<TraceResults, Error>;
|
||||
#[rpc(meta, name = "trace_call")]
|
||||
fn call(&self, Self::Metadata, CallRequest, TraceOptions, Trailing<BlockNumber>) -> BoxFuture<TraceResults, Error>;
|
||||
|
||||
/// Executes all given calls and returns a number of possible traces for each of it.
|
||||
#[rpc(meta, name = "trace_callMany")]
|
||||
fn call_many(&self, Self::Metadata, Vec<(CallRequest, TraceOptions)>, Trailing<BlockNumber>) -> BoxFuture<Vec<TraceResults>, Error>;
|
||||
|
||||
/// Executes the given raw transaction and returns a number of possible traces for it.
|
||||
#[rpc(name = "trace_rawTransaction")]
|
||||
fn raw_transaction(&self, Bytes, Vec<String>, Trailing<BlockNumber>) -> Result<TraceResults, Error>;
|
||||
fn raw_transaction(&self, Bytes, TraceOptions, Trailing<BlockNumber>) -> Result<TraceResults, Error>;
|
||||
|
||||
/// Executes the transaction with the given hash and returns a number of possible traces for it.
|
||||
#[rpc(name = "trace_replayTransaction")]
|
||||
fn replay_transaction(&self, H256, Vec<String>) -> Result<TraceResults, Error>;
|
||||
fn replay_transaction(&self, H256, TraceOptions) -> Result<TraceResults, Error>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ impl<T: Serialize> Serialize for Rich<T> {
|
||||
// and serialize
|
||||
value.serialize(serializer)
|
||||
} else {
|
||||
Err(S::Error::custom("Unserializable structures."))
|
||||
Err(S::Error::custom("Unserializable structures: expected objects"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,7 +230,7 @@ mod tests {
|
||||
fn test_serialize_block_transactions() {
|
||||
let t = BlockTransactions::Full(vec![Transaction::default()]);
|
||||
let serialized = serde_json::to_string(&t).unwrap();
|
||||
assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"networkId":null,"standardV":"0x0","v":"0x0","r":"0x0","s":"0x0","condition":null}]"#);
|
||||
assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"chainId":null,"standardV":"0x0","v":"0x0","r":"0x0","s":"0x0","condition":null}]"#);
|
||||
|
||||
let t = BlockTransactions::Hashes(vec![H256::default().into()]);
|
||||
let serialized = serde_json::to_string(&t).unwrap();
|
||||
|
||||
@@ -79,8 +79,12 @@ impl<'a> Visitor<'a> for BlockNumberVisitor {
|
||||
"latest" => Ok(BlockNumber::Latest),
|
||||
"earliest" => Ok(BlockNumber::Earliest),
|
||||
"pending" => Ok(BlockNumber::Pending),
|
||||
_ if value.starts_with("0x") => u64::from_str_radix(&value[2..], 16).map(BlockNumber::Num).map_err(|_| Error::custom("invalid block number")),
|
||||
_ => value.parse::<u64>().map(BlockNumber::Num).map_err(|_| Error::custom("invalid block number"))
|
||||
_ if value.starts_with("0x") => u64::from_str_radix(&value[2..], 16).map(BlockNumber::Num).map_err(|e| {
|
||||
Error::custom(format!("Invalid block number: {}", e))
|
||||
}),
|
||||
_ => value.parse::<u64>().map(BlockNumber::Num).map_err(|e| {
|
||||
Error::custom(format!("Invalid block number: {}", e))
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,9 +81,9 @@ impl<'a> Visitor<'a> for BytesVisitor {
|
||||
);
|
||||
Ok(Bytes::new(Vec::new()))
|
||||
} else if value.len() >= 2 && &value[0..2] == "0x" && value.len() & 1 == 0 {
|
||||
Ok(Bytes::new(FromHex::from_hex(&value[2..]).map_err(|_| Error::custom("invalid hex"))?))
|
||||
Ok(Bytes::new(FromHex::from_hex(&value[2..]).map_err(|e| Error::custom(format!("Invalid hex: {}", e)))?))
|
||||
} else {
|
||||
Err(Error::custom("invalid format"))
|
||||
Err(Error::custom("Invalid bytes format. Expected a 0x-prefixed hex string with even length"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ impl<'a> Visitor<'a> for DerivationTypeVisitor {
|
||||
match value {
|
||||
"soft" => Ok(DerivationType::Soft),
|
||||
"hard" => Ok(DerivationType::Hard),
|
||||
_ => Err(Error::custom("invalid derivation type")),
|
||||
v => Err(Error::custom(format!("invalid derivation type: {:?}", v))),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ impl<'a, T> Deserialize<'a> for VariadicValue<T> where T: DeserializeOwned {
|
||||
|
||||
from_value(v.clone()).map(VariadicValue::Single)
|
||||
.or_else(|_| from_value(v).map(VariadicValue::Multiple))
|
||||
.map_err(|_| D::Error::custom("Invalid type."))
|
||||
.map_err(|err| D::Error::custom(format!("Invalid variadic value type: {}", err)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,8 +47,12 @@ impl<'a> Visitor<'a> for IndexVisitor {
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: Error {
|
||||
match value {
|
||||
_ if value.starts_with("0x") => usize::from_str_radix(&value[2..], 16).map(Index).map_err(|_| Error::custom("invalid index")),
|
||||
_ => value.parse::<usize>().map(Index).map_err(|_| Error::custom("invalid index")),
|
||||
_ if value.starts_with("0x") => usize::from_str_radix(&value[2..], 16).map(Index).map_err(|e| {
|
||||
Error::custom(format!("Invalid index: {}", e))
|
||||
}),
|
||||
_ => value.parse::<usize>().map(Index).map_err(|e| {
|
||||
Error::custom(format!("Invalid index: {}", e))
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,3 +78,7 @@ pub use self::transaction_request::TransactionRequest;
|
||||
pub use self::transaction_condition::TransactionCondition;
|
||||
pub use self::uint::{U128, U256};
|
||||
pub use self::work::Work;
|
||||
|
||||
// TODO [ToDr] Refactor to a proper type Vec of enums?
|
||||
/// Expected tracing type.
|
||||
pub type TraceOptions = Vec<String>;
|
||||
|
||||
@@ -84,7 +84,7 @@ impl<'a> Deserialize<'a> for Params {
|
||||
}
|
||||
|
||||
from_value(v.clone()).map(Params::Logs)
|
||||
.map_err(|_| D::Error::custom("Invalid type."))
|
||||
.map_err(|e| D::Error::custom(format!("Invalid Pub-Sub parameters: {}", e)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,8 +59,8 @@ pub struct Transaction {
|
||||
#[serde(rename="publicKey")]
|
||||
pub public_key: Option<H512>,
|
||||
/// The network id of the transaction, if any.
|
||||
#[serde(rename="networkId")]
|
||||
pub network_id: Option<u64>,
|
||||
#[serde(rename="chainId")]
|
||||
pub chain_id: Option<u64>,
|
||||
/// The standardised V field of the signature (0 or 1).
|
||||
#[serde(rename="standardV")]
|
||||
pub standard_v: U256,
|
||||
@@ -196,7 +196,7 @@ impl Transaction {
|
||||
},
|
||||
raw: ::rlp::encode(&t.signed).into_vec().into(),
|
||||
public_key: t.recover_public().ok().map(Into::into),
|
||||
network_id: t.network_id(),
|
||||
chain_id: t.chain_id(),
|
||||
standard_v: t.standard_v().into(),
|
||||
v: t.original_v().into(),
|
||||
r: signature.r().into(),
|
||||
@@ -230,7 +230,7 @@ impl Transaction {
|
||||
},
|
||||
raw: ::rlp::encode(&t).into_vec().into(),
|
||||
public_key: t.public_key().map(Into::into),
|
||||
network_id: t.network_id(),
|
||||
chain_id: t.chain_id(),
|
||||
standard_v: t.standard_v().into(),
|
||||
v: t.original_v().into(),
|
||||
r: signature.r().into(),
|
||||
@@ -273,7 +273,7 @@ mod tests {
|
||||
fn test_transaction_serialize() {
|
||||
let t = Transaction::default();
|
||||
let serialized = serde_json::to_string(&t).unwrap();
|
||||
assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"networkId":null,"standardV":"0x0","v":"0x0","r":"0x0","s":"0x0","condition":null}"#);
|
||||
assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"chainId":null,"standardV":"0x0","v":"0x0","r":"0x0","s":"0x0","condition":null}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user