From 60f6a3fed3dd2e41657ab658eda8140bc78a9790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 14 Aug 2017 16:59:46 +0200 Subject: [PATCH 1/3] Increase default gas limit for eth_call. --- rpc/src/v1/helpers/fake_sign.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rpc/src/v1/helpers/fake_sign.rs b/rpc/src/v1/helpers/fake_sign.rs index 21cb0cfe1..e5d2c905d 100644 --- a/rpc/src/v1/helpers/fake_sign.rs +++ b/rpc/src/v1/helpers/fake_sign.rs @@ -18,6 +18,7 @@ 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; @@ -33,7 +34,7 @@ pub fn sign_call( 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: request.gas.unwrap_or(U256::max_value()), 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(), From a34bea1dad472728184e1a7a68749fd2d8b1ac54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 15 Aug 2017 10:07:00 +0200 Subject: [PATCH 2/3] Fix balance increase. --- ethcore/src/client/client.rs | 17 +++-------------- ethcore/src/executive.rs | 2 +- rpc/src/v1/helpers/fake_sign.rs | 1 + 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 7141c7bdb..fdd201e68 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1112,20 +1112,9 @@ impl Client { }.fake_sign(from) } - fn do_call(&self, env_info: &EnvInfo, state: &mut State, increase_balance: bool, t: &SignedTransaction, analytics: CallAnalytics) -> Result { + fn do_call(&self, env_info: &EnvInfo, state: &mut State, t: &SignedTransaction, analytics: CallAnalytics) -> Result { 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 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. 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, CallError> { @@ -1179,7 +1168,7 @@ impl BlockChainClient for Client { let mut results = Vec::with_capacity(transactions.len()); 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; results.push(ret); } diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index bd7cf28c1..8f2fb06f2 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -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 { let sender = t.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 { // give the sender a sufficient balance self.state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty)?; diff --git a/rpc/src/v1/helpers/fake_sign.rs b/rpc/src/v1/helpers/fake_sign.rs index e5d2c905d..b9be422c5 100644 --- a/rpc/src/v1/helpers/fake_sign.rs +++ b/rpc/src/v1/helpers/fake_sign.rs @@ -34,6 +34,7 @@ pub fn sign_call( 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(U256::one() << 100), gas: request.gas.unwrap_or(U256::max_value()), gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(&**client, &**miner)), value: request.value.unwrap_or(0.into()), From 5ff771b125f47709724fbbed4d18bb17491c98e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 15 Aug 2017 10:23:28 +0200 Subject: [PATCH 3/3] Cap gas limit for dapp-originating requests. --- rpc/src/v1/helpers/fake_sign.rs | 12 ++++++++++-- rpc/src/v1/impls/eth.rs | 8 ++++---- rpc/src/v1/impls/light/eth.rs | 4 ++-- rpc/src/v1/impls/light/parity.rs | 2 +- rpc/src/v1/impls/light/trace.rs | 12 ++++++++---- rpc/src/v1/impls/parity.rs | 4 ++-- rpc/src/v1/impls/traces.rs | 30 +++++++++++++++++++----------- rpc/src/v1/metadata.rs | 9 +++++++++ rpc/src/v1/tests/mocked/traces.rs | 6 +++--- rpc/src/v1/traits/eth.rs | 8 ++++---- rpc/src/v1/traits/parity.rs | 4 ++-- rpc/src/v1/traits/traces.rs | 11 +++++++---- 12 files changed, 71 insertions(+), 39 deletions(-) diff --git a/rpc/src/v1/helpers/fake_sign.rs b/rpc/src/v1/helpers/fake_sign.rs index b9be422c5..c5b95f6a4 100644 --- a/rpc/src/v1/helpers/fake_sign.rs +++ b/rpc/src/v1/helpers/fake_sign.rs @@ -28,14 +28,22 @@ pub fn sign_call( client: &Arc, miner: &Arc, request: CallRequest, + gas_cap: bool, ) -> Result { 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 { nonce: request.nonce.unwrap_or_else(|| client.latest_nonce(&from)), action: request.to.map_or(Action::Create, Action::Call), - // gas: request.gas.unwrap_or(U256::one() << 100), - gas: request.gas.unwrap_or(U256::max_value()), + 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(), diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 7c656c752..0cf70bf23 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -612,9 +612,9 @@ impl Eth for EthClient where self.send_raw_transaction(raw) } - fn call(&self, request: CallRequest, num: Trailing) -> BoxFuture { + fn call(&self, meta: Self::Metadata, request: CallRequest, num: Trailing) -> BoxFuture { 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(), }; @@ -628,9 +628,9 @@ impl Eth for EthClient where ).boxed() } - fn estimate_gas(&self, request: CallRequest, num: Trailing) -> BoxFuture { + fn estimate_gas(&self, meta: Self::Metadata, request: CallRequest, num: Trailing) -> BoxFuture { 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(), }; diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index fd03f1226..d33b5a06f 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -383,7 +383,7 @@ impl Eth for EthClient { self.send_raw_transaction(raw) } - fn call(&self, req: CallRequest, num: Trailing) -> BoxFuture { + fn call(&self, _meta: Self::Metadata, req: CallRequest, num: Trailing) -> BoxFuture { 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) -> BoxFuture { + fn estimate_gas(&self, _meta: Self::Metadata, req: CallRequest, num: Trailing) -> BoxFuture { // TODO: binary chop for more accurate estimates. self.fetcher().proved_execution(req, num).and_then(|res| { match res { diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 62a7721fc..676e39b11 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -390,7 +390,7 @@ impl Parity for ParityClient { ipfs::cid(content) } - fn call(&self, _requests: Vec, _block: Trailing) -> BoxFuture, Error> { + fn call(&self, _meta: Self::Metadata, _requests: Vec, _block: Trailing) -> BoxFuture, Error> { future::err(errors::light_unimplemented(None)).boxed() } } diff --git a/rpc/src/v1/impls/light/trace.rs b/rpc/src/v1/impls/light/trace.rs index 81ed592c5..22360183d 100644 --- a/rpc/src/v1/impls/light/trace.rs +++ b/rpc/src/v1/impls/light/trace.rs @@ -17,7 +17,9 @@ //! 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, TraceOptions, H256}; @@ -27,6 +29,8 @@ use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, By pub struct TracesClient; impl Traces for TracesClient { + type Metadata = Metadata; + fn filter(&self, _filter: TraceFilter) -> Result>, Error> { Err(errors::light_unimplemented(None)) } @@ -43,12 +47,12 @@ impl Traces for TracesClient { Err(errors::light_unimplemented(None)) } - fn call(&self, _request: CallRequest, _flags: TraceOptions, _block: Trailing) -> Result { - Err(errors::light_unimplemented(None)) + fn call(&self, _meta: Self::Metadata, _request: CallRequest, _flags: TraceOptions, _block: Trailing) -> BoxFuture { + future::err(errors::light_unimplemented(None)).boxed() } - fn call_many(&self, _request: Vec<(CallRequest, TraceOptions)>, _block: Trailing) -> Result, Error> { - Err(errors::light_unimplemented(None)) + fn call_many(&self, _meta: Self::Metadata, _request: Vec<(CallRequest, TraceOptions)>, _block: Trailing) -> BoxFuture, Error> { + future::err(errors::light_unimplemented(None)).boxed() } fn raw_transaction(&self, _raw_transaction: Bytes, _flags: TraceOptions, _block: Trailing) -> Result { diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index d855d7e17..fb82c5205 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -411,11 +411,11 @@ impl Parity for ParityClient where ipfs::cid(content) } - fn call(&self, requests: Vec, block: Trailing) -> BoxFuture, Error> { + fn call(&self, meta: Self::Metadata, requests: Vec, block: Trailing) -> BoxFuture, Error> { let requests: Result, Error> = requests .into_iter() .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() ))) .collect(); diff --git a/rpc/src/v1/impls/traces.rs b/rpc/src/v1/impls/traces.rs index 31a0e889e..9ed2c39a4 100644 --- a/rpc/src/v1/impls/traces.rs +++ b/rpc/src/v1/impls/traces.rs @@ -18,13 +18,15 @@ 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, TraceOptions, H256}; @@ -54,6 +56,8 @@ impl TracesClient { } impl Traces for TracesClient where C: MiningBlockChainClient + 'static, M: MinerService + 'static { + type Metadata = Metadata; + fn filter(&self, filter: TraceFilter) -> Result>, Error> { Ok(self.client.filter_traces(filter.into()) .map(|traces| traces.into_iter().map(LocalizedTrace::from).collect())) @@ -79,31 +83,35 @@ impl Traces for TracesClient where C: MiningBlockChainClient + 'stat .map(LocalizedTrace::from)) } - fn call(&self, request: CallRequest, flags: TraceOptions, block: Trailing) -> Result { + fn call(&self, meta: Self::Metadata, request: CallRequest, flags: TraceOptions, block: Trailing) -> BoxFuture { 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, to_call_analytics(flags), block.into()) + 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 call_many(&self, requests: Vec<(CallRequest, TraceOptions)>, block: Trailing) -> Result, Error> { + fn call_many(&self, meta: Self::Metadata, requests: Vec<(CallRequest, TraceOptions)>, block: Trailing) -> BoxFuture, Error> { let block = block.unwrap_or_default(); - let requests = requests.into_iter() + 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)?; + let signed = fake_sign::sign_call(&self.client, &self.miner, request, meta.is_dapp())?; Ok((signed, to_call_analytics(flags))) }) - .collect::, _>>()?; + .collect::, 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_err(errors::call) + .map_err(errors::call); + + futures::done(res).boxed() } fn raw_transaction(&self, raw_transaction: Bytes, flags: TraceOptions, block: Trailing) -> Result { diff --git a/rpc/src/v1/metadata.rs b/rpc/src/v1/metadata.rs index b65003ad8..f0644d455 100644 --- a/rpc/src/v1/metadata.rs +++ b/rpc/src/v1/metadata.rs @@ -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 {} diff --git a/rpc/src/v1/tests/mocked/traces.rs b/rpc/src/v1/tests/mocked/traces.rs index 50890648c..cd3ae3666 100644 --- a/rpc/src/v1/tests/mocked/traces.rs +++ b/rpc/src/v1/tests/mocked/traces.rs @@ -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, _miner: Arc, - io: IoHandler, + io: IoHandler, } 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 { diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index 941263335..9e7ed9715 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -110,12 +110,12 @@ build_rpc_trait! { fn submit_transaction(&self, Bytes) -> Result; /// Call contract, returning the output data. - #[rpc(async, name = "eth_call")] - fn call(&self, CallRequest, Trailing) -> BoxFuture; + #[rpc(meta, name = "eth_call")] + fn call(&self, Self::Metadata, CallRequest, Trailing) -> BoxFuture; /// Estimate gas needed for execution of given contract. - #[rpc(async, name = "eth_estimateGas")] - fn estimate_gas(&self, CallRequest, Trailing) -> BoxFuture; + #[rpc(meta, name = "eth_estimateGas")] + fn estimate_gas(&self, Self::Metadata, CallRequest, Trailing) -> BoxFuture; /// Get transaction by its hash. #[rpc(name = "eth_getTransactionByHash")] diff --git a/rpc/src/v1/traits/parity.rs b/rpc/src/v1/traits/parity.rs index a0b1a6e99..c9ca522c1 100644 --- a/rpc/src/v1/traits/parity.rs +++ b/rpc/src/v1/traits/parity.rs @@ -205,7 +205,7 @@ build_rpc_trait! { fn ipfs_cid(&self, Bytes) -> Result; /// Call contract, returning the output data. - #[rpc(async, name = "parity_call")] - fn call(&self, Vec, Trailing) -> BoxFuture, Error>; + #[rpc(meta, name = "parity_call")] + fn call(&self, Self::Metadata, Vec, Trailing) -> BoxFuture, Error>; } } diff --git a/rpc/src/v1/traits/traces.rs b/rpc/src/v1/traits/traces.rs index 568788af2..33bcb0afd 100644 --- a/rpc/src/v1/traits/traces.rs +++ b/rpc/src/v1/traits/traces.rs @@ -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, 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>, Error>; @@ -40,12 +43,12 @@ build_rpc_trait! { fn block_traces(&self, BlockNumber) -> Result>, Error>; /// Executes the given call and returns a number of possible traces for it. - #[rpc(name = "trace_call")] - fn call(&self, CallRequest, TraceOptions, Trailing) -> Result; + #[rpc(meta, name = "trace_call")] + fn call(&self, Self::Metadata, CallRequest, TraceOptions, Trailing) -> BoxFuture; /// Executes all given calls and returns a number of possible traces for each of it. - #[rpc(name = "trace_callMany")] - fn call_many(&self, Vec<(CallRequest, TraceOptions)>, Trailing) -> Result, Error>; + #[rpc(meta, name = "trace_callMany")] + fn call_many(&self, Self::Metadata, Vec<(CallRequest, TraceOptions)>, Trailing) -> BoxFuture, Error>; /// Executes the given raw transaction and returns a number of possible traces for it. #[rpc(name = "trace_rawTransaction")]