Merge pull request #6299 from paritytech/callgas

Increase default gas limit for eth_call.
This commit is contained in:
Robert Habermeier 2017-08-16 05:55:16 +02:00 committed by GitHub
commit d5252ddf64
14 changed files with 76 additions and 53 deletions

View File

@ -1112,20 +1112,9 @@ impl Client {
}.fake_sign(from) }.fake_sign(from)
} }
fn do_call(&self, env_info: &EnvInfo, state: &mut State<StateDB>, increase_balance: bool, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, CallError> { fn do_call(&self, env_info: &EnvInfo, state: &mut State<StateDB>, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, CallError> {
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None }; let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
// give the sender a sufficient balance (if calling in pending block)
if increase_balance {
let sender = t.sender();
let balance = state.balance(&sender).map_err(ExecutionError::from)?;
let needed_balance = t.value + t.gas * t.gas_price;
if balance < needed_balance {
state.add_balance(&sender, &(needed_balance - balance), state::CleanupMode::NoEmpty)
.map_err(ExecutionError::from)?;
}
}
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false }; let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
let mut ret = Executive::new(state, env_info, &*self.engine).transact_virtual(t, options)?; let mut ret = Executive::new(state, env_info, &*self.engine).transact_virtual(t, options)?;
@ -1167,7 +1156,7 @@ impl BlockChainClient for Client {
// that's just a copy of the state. // that's just a copy of the state.
let mut state = self.state_at(block).ok_or(CallError::StatePruned)?; let mut state = self.state_at(block).ok_or(CallError::StatePruned)?;
self.do_call(&env_info, &mut state, block == BlockId::Pending, transaction, analytics) self.do_call(&env_info, &mut state, transaction, analytics)
} }
fn call_many(&self, transactions: &[(SignedTransaction, CallAnalytics)], block: BlockId) -> Result<Vec<Executed>, CallError> { fn call_many(&self, transactions: &[(SignedTransaction, CallAnalytics)], block: BlockId) -> Result<Vec<Executed>, CallError> {
@ -1179,7 +1168,7 @@ impl BlockChainClient for Client {
let mut results = Vec::with_capacity(transactions.len()); let mut results = Vec::with_capacity(transactions.len());
for &(ref t, analytics) in transactions { for &(ref t, analytics) in transactions {
let ret = self.do_call(&env_info, &mut state, block == BlockId::Pending, t, analytics)?; let ret = self.do_call(&env_info, &mut state, t, analytics)?;
env_info.gas_used = ret.cumulative_gas_used; env_info.gas_used = ret.cumulative_gas_used;
results.push(ret); results.push(ret);
} }

View File

@ -157,7 +157,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
pub fn transact_virtual(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result<Executed, ExecutionError> { pub fn transact_virtual(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result<Executed, ExecutionError> {
let sender = t.sender(); let sender = t.sender();
let balance = self.state.balance(&sender)?; let balance = self.state.balance(&sender)?;
let needed_balance = t.value + t.gas * t.gas_price; let needed_balance = t.value.saturating_add(t.gas.saturating_mul(t.gas_price));
if balance < needed_balance { if balance < needed_balance {
// give the sender a sufficient balance // give the sender a sufficient balance
self.state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty)?; self.state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty)?;

View File

@ -18,6 +18,7 @@ use std::sync::Arc;
use ethcore::client::MiningBlockChainClient; use ethcore::client::MiningBlockChainClient;
use ethcore::miner::MinerService; use ethcore::miner::MinerService;
use ethcore::transaction::{Transaction, SignedTransaction, Action}; use ethcore::transaction::{Transaction, SignedTransaction, Action};
use util::U256;
use jsonrpc_core::Error; use jsonrpc_core::Error;
use v1::helpers::CallRequest; use v1::helpers::CallRequest;
@ -27,13 +28,22 @@ pub fn sign_call<B: MiningBlockChainClient, M: MinerService>(
client: &Arc<B>, client: &Arc<B>,
miner: &Arc<M>, miner: &Arc<M>,
request: CallRequest, request: CallRequest,
gas_cap: bool,
) -> Result<SignedTransaction, Error> { ) -> Result<SignedTransaction, Error> {
let from = request.from.unwrap_or(0.into()); let from = request.from.unwrap_or(0.into());
let mut gas = request.gas.unwrap_or(U256::max_value());
if gas_cap {
let max_gas = 50_000_000.into();
if gas > max_gas {
warn!("Gas limit capped to {} (from {})", max_gas, gas);
gas = max_gas
}
}
Ok(Transaction { Ok(Transaction {
nonce: request.nonce.unwrap_or_else(|| client.latest_nonce(&from)), nonce: request.nonce.unwrap_or_else(|| client.latest_nonce(&from)),
action: request.to.map_or(Action::Create, Action::Call), 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)), gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(&**client, &**miner)),
value: request.value.unwrap_or(0.into()), value: request.value.unwrap_or(0.into()),
data: request.data.unwrap_or_default(), data: request.data.unwrap_or_default(),

View File

@ -612,9 +612,9 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
self.send_raw_transaction(raw) 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 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, Ok(signed) => signed,
Err(e) => return future::err(e).boxed(), Err(e) => return future::err(e).boxed(),
}; };
@ -628,9 +628,9 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
).boxed() ).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 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, Ok(signed) => signed,
Err(e) => return future::err(e).boxed(), Err(e) => return future::err(e).boxed(),
}; };

View File

@ -383,7 +383,7 @@ impl Eth for EthClient {
self.send_raw_transaction(raw) 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| { self.fetcher().proved_execution(req, num).and_then(|res| {
match res { match res {
Ok(exec) => Ok(exec.output.into()), Ok(exec) => Ok(exec.output.into()),
@ -392,7 +392,7 @@ impl Eth for EthClient {
}).boxed() }).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. // TODO: binary chop for more accurate estimates.
self.fetcher().proved_execution(req, num).and_then(|res| { self.fetcher().proved_execution(req, num).and_then(|res| {
match res { match res {

View File

@ -390,7 +390,7 @@ impl Parity for ParityClient {
ipfs::cid(content) ipfs::cid(content)
} }
fn call(&self, _requests: Vec<CallRequest>, _block: Trailing<BlockNumber>) -> BoxFuture<Vec<Bytes>, Error> { fn call(&self, _meta: Self::Metadata, _requests: Vec<CallRequest>, _block: Trailing<BlockNumber>) -> BoxFuture<Vec<Bytes>, Error> {
future::err(errors::light_unimplemented(None)).boxed() future::err(errors::light_unimplemented(None)).boxed()
} }
} }

View File

@ -17,7 +17,9 @@
//! Traces api implementation. //! Traces api implementation.
use jsonrpc_core::Error; use jsonrpc_core::Error;
use jsonrpc_core::futures::{future, Future, BoxFuture};
use jsonrpc_macros::Trailing; use jsonrpc_macros::Trailing;
use v1::Metadata;
use v1::traits::Traces; use v1::traits::Traces;
use v1::helpers::errors; use v1::helpers::errors;
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceOptions, H256}; use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceOptions, H256};
@ -27,6 +29,8 @@ use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, By
pub struct TracesClient; pub struct TracesClient;
impl Traces for TracesClient { impl Traces for TracesClient {
type Metadata = Metadata;
fn filter(&self, _filter: TraceFilter) -> Result<Option<Vec<LocalizedTrace>>, Error> { fn filter(&self, _filter: TraceFilter) -> Result<Option<Vec<LocalizedTrace>>, Error> {
Err(errors::light_unimplemented(None)) Err(errors::light_unimplemented(None))
} }
@ -43,12 +47,12 @@ impl Traces for TracesClient {
Err(errors::light_unimplemented(None)) Err(errors::light_unimplemented(None))
} }
fn call(&self, _request: CallRequest, _flags: TraceOptions, _block: Trailing<BlockNumber>) -> Result<TraceResults, Error> { fn call(&self, _meta: Self::Metadata, _request: CallRequest, _flags: TraceOptions, _block: Trailing<BlockNumber>) -> BoxFuture<TraceResults, Error> {
Err(errors::light_unimplemented(None)) future::err(errors::light_unimplemented(None)).boxed()
} }
fn call_many(&self, _request: Vec<(CallRequest, TraceOptions)>, _block: Trailing<BlockNumber>) -> Result<Vec<TraceResults>, Error> { fn call_many(&self, _meta: Self::Metadata, _request: Vec<(CallRequest, TraceOptions)>, _block: Trailing<BlockNumber>) -> BoxFuture<Vec<TraceResults>, Error> {
Err(errors::light_unimplemented(None)) future::err(errors::light_unimplemented(None)).boxed()
} }
fn raw_transaction(&self, _raw_transaction: Bytes, _flags: TraceOptions, _block: Trailing<BlockNumber>) -> Result<TraceResults, Error> { fn raw_transaction(&self, _raw_transaction: Bytes, _flags: TraceOptions, _block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {

View File

@ -411,11 +411,11 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
ipfs::cid(content) ipfs::cid(content)
} }
fn call(&self, requests: Vec<CallRequest>, block: Trailing<BlockNumber>) -> BoxFuture<Vec<Bytes>, Error> { fn call(&self, meta: Self::Metadata, requests: Vec<CallRequest>, block: Trailing<BlockNumber>) -> BoxFuture<Vec<Bytes>, Error> {
let requests: Result<Vec<(SignedTransaction, _)>, Error> = requests let requests: Result<Vec<(SignedTransaction, _)>, Error> = requests
.into_iter() .into_iter()
.map(|request| Ok(( .map(|request| Ok((
fake_sign::sign_call(&self.client, &self.miner, request.into())?, fake_sign::sign_call(&self.client, &self.miner, request.into(), meta.is_dapp())?,
Default::default() Default::default()
))) )))
.collect(); .collect();

View File

@ -18,13 +18,15 @@
use std::sync::Arc; use std::sync::Arc;
use rlp::UntrustedRlp;
use ethcore::client::{MiningBlockChainClient, CallAnalytics, TransactionId, TraceId}; use ethcore::client::{MiningBlockChainClient, CallAnalytics, TransactionId, TraceId};
use ethcore::miner::MinerService; use ethcore::miner::MinerService;
use ethcore::transaction::SignedTransaction; use ethcore::transaction::SignedTransaction;
use rlp::UntrustedRlp;
use jsonrpc_core::Error; use jsonrpc_core::Error;
use jsonrpc_core::futures::{self, Future, BoxFuture};
use jsonrpc_macros::Trailing; use jsonrpc_macros::Trailing;
use v1::Metadata;
use v1::traits::Traces; use v1::traits::Traces;
use v1::helpers::{errors, fake_sign}; use v1::helpers::{errors, fake_sign};
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceOptions, H256}; use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceOptions, H256};
@ -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 { 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> { fn filter(&self, filter: TraceFilter) -> Result<Option<Vec<LocalizedTrace>>, Error> {
Ok(self.client.filter_traces(filter.into()) Ok(self.client.filter_traces(filter.into())
.map(|traces| traces.into_iter().map(LocalizedTrace::from).collect())) .map(|traces| traces.into_iter().map(LocalizedTrace::from).collect()))
@ -79,31 +83,35 @@ impl<C, M> Traces for TracesClient<C, M> where C: MiningBlockChainClient + 'stat
.map(LocalizedTrace::from)) .map(LocalizedTrace::from))
} }
fn call(&self, request: CallRequest, flags: TraceOptions, 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 block = block.unwrap_or_default();
let request = CallRequest::into(request); 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, to_call_analytics(flags), block.into()) let res = self.client.call(&signed, to_call_analytics(flags), block.into())
.map(TraceResults::from) .map(TraceResults::from)
.map_err(errors::call) .map_err(errors::call);
futures::done(res).boxed()
} }
fn call_many(&self, requests: Vec<(CallRequest, TraceOptions)>, block: Trailing<BlockNumber>) -> Result<Vec<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 block = block.unwrap_or_default();
let requests = requests.into_iter() let requests = try_bf!(requests.into_iter()
.map(|(request, flags)| { .map(|(request, flags)| {
let request = CallRequest::into(request); let request = CallRequest::into(request);
let signed = fake_sign::sign_call(&self.client, &self.miner, request)?; let signed = fake_sign::sign_call(&self.client, &self.miner, request, meta.is_dapp())?;
Ok((signed, to_call_analytics(flags))) Ok((signed, to_call_analytics(flags)))
}) })
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, Error>>());
self.client.call_many(&requests, block.into()) let res = self.client.call_many(&requests, block.into())
.map(|results| results.into_iter().map(TraceResults::from).collect()) .map(|results| results.into_iter().map(TraceResults::from).collect())
.map_err(errors::call) .map_err(errors::call);
futures::done(res).boxed()
} }
fn raw_transaction(&self, raw_transaction: Bytes, flags: TraceOptions, block: Trailing<BlockNumber>) -> Result<TraceResults, Error> { fn raw_transaction(&self, raw_transaction: Bytes, flags: TraceOptions, block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {

View File

@ -42,6 +42,15 @@ impl Metadata {
_ => DappId::default(), _ => 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 {} impl jsonrpc_core::Metadata for Metadata {}

View File

@ -25,12 +25,12 @@ use vm::CallType;
use jsonrpc_core::IoHandler; use jsonrpc_core::IoHandler;
use v1::tests::helpers::{TestMinerService}; use v1::tests::helpers::{TestMinerService};
use v1::{Traces, TracesClient}; use v1::{Metadata, Traces, TracesClient};
struct Tester { struct Tester {
client: Arc<TestBlockChainClient>, client: Arc<TestBlockChainClient>,
_miner: Arc<TestMinerService>, _miner: Arc<TestMinerService>,
io: IoHandler, io: IoHandler<Metadata>,
} }
fn io() -> Tester { fn io() -> Tester {
@ -67,7 +67,7 @@ fn io() -> Tester {
})); }));
let miner = Arc::new(TestMinerService::default()); let miner = Arc::new(TestMinerService::default());
let traces = TracesClient::new(&client, &miner); let traces = TracesClient::new(&client, &miner);
let mut io = IoHandler::new(); let mut io = IoHandler::default();
io.extend_with(traces.to_delegate()); io.extend_with(traces.to_delegate());
Tester { Tester {

View File

@ -110,12 +110,12 @@ build_rpc_trait! {
fn submit_transaction(&self, Bytes) -> Result<H256, Error>; fn submit_transaction(&self, Bytes) -> Result<H256, Error>;
/// Call contract, returning the output data. /// Call contract, returning the output data.
#[rpc(async, name = "eth_call")] #[rpc(meta, name = "eth_call")]
fn call(&self, CallRequest, Trailing<BlockNumber>) -> BoxFuture<Bytes, Error>; fn call(&self, Self::Metadata, CallRequest, Trailing<BlockNumber>) -> BoxFuture<Bytes, Error>;
/// Estimate gas needed for execution of given contract. /// Estimate gas needed for execution of given contract.
#[rpc(async, name = "eth_estimateGas")] #[rpc(meta, name = "eth_estimateGas")]
fn estimate_gas(&self, CallRequest, Trailing<BlockNumber>) -> BoxFuture<U256, Error>; fn estimate_gas(&self, Self::Metadata, CallRequest, Trailing<BlockNumber>) -> BoxFuture<U256, Error>;
/// Get transaction by its hash. /// Get transaction by its hash.
#[rpc(name = "eth_getTransactionByHash")] #[rpc(name = "eth_getTransactionByHash")]

View File

@ -205,7 +205,7 @@ build_rpc_trait! {
fn ipfs_cid(&self, Bytes) -> Result<String, Error>; fn ipfs_cid(&self, Bytes) -> Result<String, Error>;
/// Call contract, returning the output data. /// Call contract, returning the output data.
#[rpc(async, name = "parity_call")] #[rpc(meta, name = "parity_call")]
fn call(&self, Vec<CallRequest>, Trailing<BlockNumber>) -> BoxFuture<Vec<Bytes>, Error>; fn call(&self, Self::Metadata, Vec<CallRequest>, Trailing<BlockNumber>) -> BoxFuture<Vec<Bytes>, Error>;
} }
} }

View File

@ -17,12 +17,15 @@
//! Traces specific rpc interface. //! Traces specific rpc interface.
use jsonrpc_core::Error; use jsonrpc_core::Error;
use jsonrpc_core::futures::BoxFuture;
use jsonrpc_macros::Trailing; use jsonrpc_macros::Trailing;
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256, TraceOptions}; use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256, TraceOptions};
build_rpc_trait! { build_rpc_trait! {
/// Traces specific rpc interface. /// Traces specific rpc interface.
pub trait Traces { pub trait Traces {
type Metadata;
/// Returns traces matching given filter. /// Returns traces matching given filter.
#[rpc(name = "trace_filter")] #[rpc(name = "trace_filter")]
fn filter(&self, TraceFilter) -> Result<Option<Vec<LocalizedTrace>>, Error>; fn filter(&self, TraceFilter) -> Result<Option<Vec<LocalizedTrace>>, Error>;
@ -40,12 +43,12 @@ build_rpc_trait! {
fn block_traces(&self, BlockNumber) -> Result<Option<Vec<LocalizedTrace>>, Error>; fn block_traces(&self, BlockNumber) -> Result<Option<Vec<LocalizedTrace>>, Error>;
/// Executes the given call and returns a number of possible traces for it. /// Executes the given call and returns a number of possible traces for it.
#[rpc(name = "trace_call")] #[rpc(meta, name = "trace_call")]
fn call(&self, CallRequest, TraceOptions, Trailing<BlockNumber>) -> Result<TraceResults, Error>; 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. /// Executes all given calls and returns a number of possible traces for each of it.
#[rpc(name = "trace_callMany")] #[rpc(meta, name = "trace_callMany")]
fn call_many(&self, Vec<(CallRequest, TraceOptions)>, Trailing<BlockNumber>) -> Result<Vec<TraceResults>, Error>; 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. /// Executes the given raw transaction and returns a number of possible traces for it.
#[rpc(name = "trace_rawTransaction")] #[rpc(name = "trace_rawTransaction")]