Change how RPCs eth_call and eth_estimateGas handle "Pending" (#11127)

* Change how RPCs eth_call and eth_estimateGas handle "Pending"

Before this PR we would return a rather confusing error when calling `eth_call` and `eth_estimateGas` with `"Pending"`, e.g.:

```
{"jsonrpc":"2.0","error":{"code":-32000,"message":"This request is not supported because your node is running with state pruning. Run with --pruning=archive."},"id":"e237678f6648ed12ff05a74933d06d17"}
```

In reality what is going on is that users often use `"Pending"` when they really mean `"Latest"` (e.g. MyCrypto…) and when the block in question is not actually pending. This changes our behaviour for these two RPC calls to fall back to `"Latest"` when the query with `"Pending"` fails.
Note that we already behave this way for many other RPCs:

	- eth_call (after this PR)
	- eth_estimateGas (after this PR)
	- eth_getBalance
	- eth_getCode
	- eth_getStorageAt

Closes https://github.com/paritytech/parity-ethereum/issues/10096

* Fetch jsonrpc from git

* No real need to wait for new jsonrpc

* Add tests for calling eth_call/eth_estimateGas with "Pending"

* Fix a todo, add another

* Change client.latest_state to return the best header as well so we avoid potential data races and do less work

* Impl review suggestions

* Update rpc/src/v1/impls/eth.rs

Co-Authored-By: Niklas Adolfsson <niklasadolfsson1@gmail.com>

* Review grumbles

* update docs
This commit is contained in:
David
2019-10-11 15:54:36 +02:00
committed by GitHub
parent f3015ce0c6
commit aefa8d5f59
8 changed files with 153 additions and 50 deletions

View File

@@ -1033,15 +1033,16 @@ impl Client {
}
/// Get a copy of the best block's state.
pub fn latest_state(&self) -> State<StateDB> {
pub fn latest_state_and_header(&self) -> (State<StateDB>, Header) {
let header = self.best_block_header();
State::from_existing(
let state = State::from_existing(
self.state_db.read().boxed_clone_canon(&header.hash()),
*header.state_root(),
self.engine.account_start_nonce(header.number()),
self.factories.clone()
)
.expect("State root of best block header always valid.")
.expect("State root of best block header always valid.");
(state, header)
}
/// Attempt to get a copy of a specific block's final state.
@@ -1051,9 +1052,9 @@ impl Client {
/// is unknown.
pub fn state_at(&self, id: BlockId) -> Option<State<StateDB>> {
// fast path for latest state.
match id.clone() {
BlockId::Latest => return Some(self.latest_state()),
_ => {},
if let BlockId::Latest = id {
let (state, _) = self.latest_state_and_header();
return Some(state)
}
let block_number = match self.block_number(id) {
@@ -1087,8 +1088,9 @@ impl Client {
}
/// Get a copy of the best block's state.
pub fn state(&self) -> Box<dyn StateInfo> {
Box::new(self.latest_state()) as Box<_>
pub fn state(&self) -> impl StateInfo {
let (state, _) = self.latest_state_and_header();
state
}
/// Get info on the cache.
@@ -1476,8 +1478,8 @@ impl ImportBlock for Client {
impl StateClient for Client {
type State = State<::state_db::StateDB>;
fn latest_state(&self) -> Self::State {
Client::latest_state(self)
fn latest_state_and_header(&self) -> (Self::State, Header) {
Client::latest_state_and_header(self)
}
fn state_at(&self, id: BlockId) -> Option<Self::State> {

View File

@@ -45,13 +45,16 @@ use types::{
receipt::RichReceipt,
};
use block::SealedBlock;
use call_contract::CallContract;
use registrar::RegistrarClient;
use client::{BlockProducer, SealedBlockImporter};
use client_traits::{BlockChain, ChainInfo, AccountData, Nonce, ScheduleInfo};
use account_state::state::StateInfo;
use crate::{
block::SealedBlock,
client::{BlockProducer, SealedBlockImporter},
};
/// Provides methods to verify incoming external transactions
pub trait TransactionVerifierClient: Send + Sync
// Required for ServiceTransactionChecker

View File

@@ -644,8 +644,8 @@ impl StateInfo for TestState {
impl StateClient for TestBlockChainClient {
type State = TestState;
fn latest_state(&self) -> Self::State {
TestState
fn latest_state_and_header(&self) -> (Self::State, Header) {
(TestState, self.best_block_header())
}
fn state_at(&self, _id: BlockId) -> Option<Self::State> {

View File

@@ -17,6 +17,7 @@
use std::str::{FromStr, from_utf8};
use std::sync::Arc;
use account_state::state::StateInfo;
use ethereum_types::{U256, Address};
use ethkey::KeyPair;
use hash::keccak;