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:
@@ -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> {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user