Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
EIP-1186: add eth_getProof RPC-Method (#9001)
Browse files Browse the repository at this point in the history
* added eth_getAccount

* changed to getProof

* implemented storage_proof

* better formatting of storage proof

* fixed imports;2C

* removed spaces

* fixed whitespace

* fixed docker

* added doc

* fixed Compile-error

* expose more ports

* added eth_getAccount

* changed to getProof

* implemented storage_proof

* better formatting of storage proof

* fixed docker

* removed slockit-changes

* fixed Dockerfile

* intend

* spaces

* removed spaces

* fixed whitespace

* fixed docker

* tabs

* fixed Compile-error

* added eth_getAccount

* changed to getProof

* implemented storage_proof

* fixed docker

* removed slockit-changes

* fixed Dockerfile

* intend

* spaces

* removed spaces

* fixed whitespace

* fixed docker

* tabs

* merged changes

* fixed warnings

* added eth_getAccount

* changed to getProof

* implemented storage_proof

* better formatting of storage proof

* Update Dockerfile

* fixed docker

* removed slockit-changes

* fixed Dockerfile

* intend

* spaces

* removed spaces

* fixed whitespace

* fixed docker

* tabs

* added eth_getAccount

* changed to getProof

* implemented storage_proof

* removed spaces

* fixed whitespace

* fixed docker

* added eth_getAccount

* changed to getProof

* implemented storage_proof

* better formatting of storage proof

* fixed docker

* removed slockit-changes

* fixed Dockerfile

* intend

* spaces

* removed spaces

* fixed whitespace

* fixed docker

* tabs

* merged changes

* fixed merge error

* fixed formatting

* fixed rename_all = "camelCase"

* fixed tabs

* fixed spaces

* removed port exposer

* formatting

* fixed comment

* use filter_map

* formatting

* use better variable names

* changed casting

* fixed tabs

* remote into() from address

* remove space

Co-Authored-By: simon-jentzsch <simon@slock.it>

* fixed storage_index

Co-Authored-By: simon-jentzsch <simon@slock.it>

* fixed clone

* fixed format

Co-Authored-By: simon-jentzsch <simon@slock.it>

* fixed empty lines

* removed Option from EthAccount

* fixed storage_index

* implemented test and fixed the struct-spaces

* fixed tests

* added experimental RPCs flag for getProof

* optmized code
  • Loading branch information
simon-jentzsch authored and 5chdn committed Nov 21, 2018
1 parent 03600dc commit 8865b95
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 9 deletions.
1 change: 1 addition & 0 deletions parity/rpc_apis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ impl FullDependencies {
allow_pending_receipt_query: !self.geth_compatibility,
send_block_number_in_get_work: !self.geth_compatibility,
gas_price_percentile: self.gas_price_percentile,
allow_experimental_rpcs: self.experimental_rpcs,
}
);
handler.extend_with(client.to_delegate());
Expand Down
56 changes: 52 additions & 4 deletions rpc/src/v1/impls/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ use std::time::{Instant, Duration, SystemTime, UNIX_EPOCH};
use std::sync::Arc;

use rlp::Rlp;
use ethereum_types::{U256, H256, Address};
use ethereum_types::{U256, H256, H160, Address};
use parking_lot::Mutex;

use ethash::{self, SeedHashCompute};
use ethcore::account_provider::AccountProvider;
use ethcore::client::{BlockChainClient, BlockId, TransactionId, UncleId, StateOrBlock, StateClient, StateInfo, Call, EngineInfo};
use ethcore::client::{BlockChainClient, BlockId, TransactionId, UncleId, StateOrBlock, StateClient, StateInfo, Call, EngineInfo, ProvingBlockChainClient};
use ethcore::filter::Filter as EthcoreFilter;
use ethcore::header::{BlockNumber as EthBlockNumber};
use ethcore::miner::{self, MinerService};
Expand All @@ -35,6 +35,7 @@ use ethcore::encoded;
use sync::SyncProvider;
use miner::external::ExternalMinerService;
use transaction::{SignedTransaction, LocalizedTransaction};
use hash::keccak;

use jsonrpc_core::{BoxFuture, Result};
use jsonrpc_core::futures::future;
Expand All @@ -46,7 +47,7 @@ use v1::helpers::block_import::is_major_importing;
use v1::traits::Eth;
use v1::types::{
RichBlock, Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo,
Transaction, CallRequest, Index, Filter, Log, Receipt, Work,
Transaction, CallRequest, Index, Filter, Log, Receipt, Work, EthAccount, StorageProof,
H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256, block_number_to_id,
U64 as RpcU64,
};
Expand All @@ -64,6 +65,8 @@ pub struct EthClientOptions {
pub send_block_number_in_get_work: bool,
/// Gas Price Percentile used as default gas price.
pub gas_price_percentile: usize,
/// Enable Experimental RPC-Calls
pub allow_experimental_rpcs: bool,
}

impl EthClientOptions {
Expand All @@ -83,6 +86,7 @@ impl Default for EthClientOptions {
allow_pending_receipt_query: true,
send_block_number_in_get_work: true,
gas_price_percentile: 50,
allow_experimental_rpcs: false,
}
}
}
Expand Down Expand Up @@ -450,7 +454,7 @@ fn check_known<C>(client: &C, number: BlockNumber) -> Result<()> where C: BlockC
const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6.

impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<C, SN, S, M, EM> where
C: miner::BlockChainClient + BlockChainClient + StateClient<State=T> + Call<State=T> + EngineInfo + 'static,
C: miner::BlockChainClient + StateClient<State=T> + ProvingBlockChainClient + Call<State=T> + EngineInfo + 'static,
SN: SnapshotService + 'static,
S: SyncProvider + 'static,
M: MinerService<State=T> + 'static,
Expand Down Expand Up @@ -547,6 +551,50 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
Box::new(future::done(res))
}

fn proof(&self, address: RpcH160, values: Vec<RpcH256>, num: Trailing<BlockNumber>) -> BoxFuture<EthAccount> {
try_bf!(errors::require_experimental(self.options.allow_experimental_rpcs, "1186"));

let a: H160 = address.clone().into();
let key1 = keccak(a);

let num = num.unwrap_or_default();
let id = match num {
BlockNumber::Num(n) => BlockId::Number(n),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Pending => {
warn!("`Pending` is deprecated and may be removed in future versions. Falling back to `Latest`");
BlockId::Latest
}
};

try_bf!(check_known(&*self.client, num.clone()));
let res = match self.client.prove_account(key1, id) {
Some((proof,account)) => Ok(EthAccount {
address: address,
balance: account.balance.into(),
nonce: account.nonce.into(),
code_hash: account.code_hash.into(),
storage_hash: account.storage_root.into(),
account_proof: proof.into_iter().map(Bytes::new).collect(),
storage_proof: values.into_iter().filter_map(|storage_index| {
let key2: H256 = storage_index.into();
self.client.prove_storage(key1, keccak(key2), id)
.map(|(storage_proof,storage_value)| StorageProof {
key: key2.into(),
value: storage_value.into(),
proof: storage_proof.into_iter().map(Bytes::new).collect()
})
})
.collect::<Vec<StorageProof>>()
}),
None => Err(errors::state_pruned()),
};

Box::new(future::done(res))
}


fn storage_at(&self, address: RpcH160, pos: RpcU256, num: Trailing<BlockNumber>) -> BoxFuture<RpcH256> {
let address: Address = RpcH160::into(address);
let position: U256 = RpcU256::into(pos);
Expand Down
6 changes: 5 additions & 1 deletion rpc/src/v1/impls/light/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use v1::helpers::light_fetch::{self, LightFetch};
use v1::traits::Eth;
use v1::types::{
RichBlock, Block, BlockTransactions, BlockNumber, LightBlockNumber, Bytes, SyncStatus, SyncInfo,
Transaction, CallRequest, Index, Filter, Log, Receipt, Work,
Transaction, CallRequest, Index, Filter, Log, Receipt, Work, EthAccount,
H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256,
U64 as RpcU64,
};
Expand Down Expand Up @@ -475,6 +475,10 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
}))
}

fn proof(&self, _address: RpcH160, _values:Vec<RpcH256>, _num: Trailing<BlockNumber>) -> BoxFuture<EthAccount> {
Box::new(future::err(errors::unimplemented(None)))
}

fn compilers(&self) -> Result<Vec<String>> {
Err(errors::deprecated("Compilation functionality is deprecated.".to_string()))
}
Expand Down
37 changes: 35 additions & 2 deletions rpc/src/v1/tests/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use parity_runtime::Runtime;
use jsonrpc_core::IoHandler;
use v1::helpers::dispatch::FullDispatcher;
use v1::helpers::nonce;
use v1::impls::{EthClient, SigningUnsafeClient};
use v1::impls::{EthClient, EthClientOptions, SigningUnsafeClient};
use v1::metadata::Metadata;
use v1::tests::helpers::{TestSnapshotService, TestSyncProvider, Config};
use v1::traits::eth::Eth;
Expand Down Expand Up @@ -140,7 +140,13 @@ impl EthTester {
&opt_account_provider,
&miner_service,
&external_miner,
Default::default(),
EthClientOptions {
pending_nonce_from_queue: false,
allow_pending_receipt_query: true,
send_block_number_in_get_work: true,
gas_price_percentile: 50,
allow_experimental_rpcs: true,
},
);

let reservations = Arc::new(Mutex::new(nonce::Reservations::new(runtime.executor())));
Expand Down Expand Up @@ -198,6 +204,33 @@ fn eth_get_balance() {
assert_eq!(tester.handler.handle_request_sync(req_new_acc).unwrap(), res_new_acc);
}

#[test]
fn eth_get_proof() {
let chain = extract_chain!("BlockchainTests/bcWalletTest/wallet2outOf3txs");
let tester = EthTester::from_chain(&chain);
// final account state
let req_latest = r#"{
"jsonrpc": "2.0",
"method": "eth_getProof",
"params": ["0xaaaf5374fce5edbc8e2a8697c15331677e6ebaaa", [], "latest"],
"id": 1
}"#;

let res_latest = r#","address":"0xaaaf5374fce5edbc8e2a8697c15331677e6ebaaa","balance":"0x9","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","nonce":"0x0","storageHash":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","storageProof":[]},"id":1}"#.to_owned();
assert!(tester.handler.handle_request_sync(req_latest).unwrap().to_string().ends_with(res_latest.as_str()));

// non-existant account
let req_new_acc = r#"{
"jsonrpc": "2.0",
"method": "eth_getProof",
"params": ["0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",[],"latest"],
"id": 3
}"#;

let res_new_acc = r#","address":"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","balance":"0x0","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","nonce":"0x0","storageHash":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","storageProof":[]},"id":3}"#.to_owned();
assert!(tester.handler.handle_request_sync(req_new_acc).unwrap().to_string().ends_with(res_new_acc.as_str()));
}

#[test]
fn eth_block_number() {
let chain = extract_chain!("BlockchainTests/bcGasPricerTest/RPC_API_Test");
Expand Down
6 changes: 5 additions & 1 deletion rpc/src/v1/traits/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
use jsonrpc_core::{Result, BoxFuture};
use jsonrpc_macros::Trailing;

use v1::types::{RichBlock, BlockNumber, Bytes, CallRequest, Filter, FilterChanges, Index};
use v1::types::{RichBlock, BlockNumber, Bytes, CallRequest, Filter, FilterChanges, Index, EthAccount};
use v1::types::{Log, Receipt, SyncStatus, Transaction, Work};
use v1::types::{H64, H160, H256, U256, U64};

Expand Down Expand Up @@ -69,6 +69,10 @@ build_rpc_trait! {
#[rpc(name = "eth_getBalance")]
fn balance(&self, H160, Trailing<BlockNumber>) -> BoxFuture<U256>;

/// Returns the account- and storage-values of the specified account including the Merkle-proof
#[rpc(name = "eth_getProof")]
fn proof(&self, H160, Vec<H256>, Trailing<BlockNumber>) -> BoxFuture<EthAccount>;

/// Returns content of the storage at given address.
#[rpc(name = "eth_getStorageAt")]
fn storage_at(&self, H160, U256, Trailing<BlockNumber>) -> BoxFuture<H256>;
Expand Down
23 changes: 23 additions & 0 deletions rpc/src/v1/types/account_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use v1::types::{H160, H256, U256, Bytes};

/// Account information.
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
Expand All @@ -21,6 +22,28 @@ pub struct AccountInfo {
pub name: String,
}

/// Datastructure with proof for one single storage-entry
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct StorageProof {
pub key: U256,
pub value: U256,
pub proof: Vec<Bytes>
}

/// Account information.
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct EthAccount {
pub address: H160,
pub balance: U256,
pub nonce: U256,
pub code_hash: H256,
pub storage_hash: H256,
pub account_proof: Vec<Bytes>,
pub storage_proof: Vec<StorageProof>,
}

/// Extended account information (used by `parity_allAccountInfo`).
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
pub struct ExtAccountInfo {
Expand Down
3 changes: 2 additions & 1 deletion rpc/src/v1/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ mod private_receipt;
mod eip191;

pub mod pubsub;

pub use self::eip191::{EIP191Version, PresignedTransaction};
pub use self::account_info::{AccountInfo, ExtAccountInfo, HwAccountInfo};
pub use self::account_info::{AccountInfo, ExtAccountInfo, HwAccountInfo, EthAccount, StorageProof};
pub use self::bytes::Bytes;
pub use self::block::{RichBlock, Block, BlockTransactions, Header, RichHeader, Rich};
pub use self::block_number::{BlockNumber, LightBlockNumber, block_number_to_id};
Expand Down

0 comments on commit 8865b95

Please sign in to comment.