EIP-1186: add eth_getProof
RPC-Method (#9001)
* 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
This commit is contained in:
parent
03600dce97
commit
8865b95818
@ -291,6 +291,7 @@ impl FullDependencies {
|
|||||||
allow_pending_receipt_query: !self.geth_compatibility,
|
allow_pending_receipt_query: !self.geth_compatibility,
|
||||||
send_block_number_in_get_work: !self.geth_compatibility,
|
send_block_number_in_get_work: !self.geth_compatibility,
|
||||||
gas_price_percentile: self.gas_price_percentile,
|
gas_price_percentile: self.gas_price_percentile,
|
||||||
|
allow_experimental_rpcs: self.experimental_rpcs,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
handler.extend_with(client.to_delegate());
|
handler.extend_with(client.to_delegate());
|
||||||
|
@ -21,12 +21,12 @@ use std::time::{Instant, Duration, SystemTime, UNIX_EPOCH};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use rlp::Rlp;
|
use rlp::Rlp;
|
||||||
use ethereum_types::{U256, H256, Address};
|
use ethereum_types::{U256, H256, H160, Address};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
use ethash::{self, SeedHashCompute};
|
use ethash::{self, SeedHashCompute};
|
||||||
use ethcore::account_provider::AccountProvider;
|
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::filter::Filter as EthcoreFilter;
|
||||||
use ethcore::header::{BlockNumber as EthBlockNumber};
|
use ethcore::header::{BlockNumber as EthBlockNumber};
|
||||||
use ethcore::miner::{self, MinerService};
|
use ethcore::miner::{self, MinerService};
|
||||||
@ -35,6 +35,7 @@ use ethcore::encoded;
|
|||||||
use sync::SyncProvider;
|
use sync::SyncProvider;
|
||||||
use miner::external::ExternalMinerService;
|
use miner::external::ExternalMinerService;
|
||||||
use transaction::{SignedTransaction, LocalizedTransaction};
|
use transaction::{SignedTransaction, LocalizedTransaction};
|
||||||
|
use hash::keccak;
|
||||||
|
|
||||||
use jsonrpc_core::{BoxFuture, Result};
|
use jsonrpc_core::{BoxFuture, Result};
|
||||||
use jsonrpc_core::futures::future;
|
use jsonrpc_core::futures::future;
|
||||||
@ -46,7 +47,7 @@ use v1::helpers::block_import::is_major_importing;
|
|||||||
use v1::traits::Eth;
|
use v1::traits::Eth;
|
||||||
use v1::types::{
|
use v1::types::{
|
||||||
RichBlock, Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo,
|
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,
|
H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256, block_number_to_id,
|
||||||
U64 as RpcU64,
|
U64 as RpcU64,
|
||||||
};
|
};
|
||||||
@ -64,6 +65,8 @@ pub struct EthClientOptions {
|
|||||||
pub send_block_number_in_get_work: bool,
|
pub send_block_number_in_get_work: bool,
|
||||||
/// Gas Price Percentile used as default gas price.
|
/// Gas Price Percentile used as default gas price.
|
||||||
pub gas_price_percentile: usize,
|
pub gas_price_percentile: usize,
|
||||||
|
/// Enable Experimental RPC-Calls
|
||||||
|
pub allow_experimental_rpcs: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EthClientOptions {
|
impl EthClientOptions {
|
||||||
@ -83,6 +86,7 @@ impl Default for EthClientOptions {
|
|||||||
allow_pending_receipt_query: true,
|
allow_pending_receipt_query: true,
|
||||||
send_block_number_in_get_work: true,
|
send_block_number_in_get_work: true,
|
||||||
gas_price_percentile: 50,
|
gas_price_percentile: 50,
|
||||||
|
allow_experimental_rpcs: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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.
|
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
|
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,
|
SN: SnapshotService + 'static,
|
||||||
S: SyncProvider + 'static,
|
S: SyncProvider + 'static,
|
||||||
M: MinerService<State=T> + 'static,
|
M: MinerService<State=T> + 'static,
|
||||||
@ -547,6 +551,50 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
|||||||
Box::new(future::done(res))
|
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> {
|
fn storage_at(&self, address: RpcH160, pos: RpcU256, num: Trailing<BlockNumber>) -> BoxFuture<RpcH256> {
|
||||||
let address: Address = RpcH160::into(address);
|
let address: Address = RpcH160::into(address);
|
||||||
let position: U256 = RpcU256::into(pos);
|
let position: U256 = RpcU256::into(pos);
|
||||||
|
@ -47,7 +47,7 @@ use v1::helpers::light_fetch::{self, LightFetch};
|
|||||||
use v1::traits::Eth;
|
use v1::traits::Eth;
|
||||||
use v1::types::{
|
use v1::types::{
|
||||||
RichBlock, Block, BlockTransactions, BlockNumber, LightBlockNumber, Bytes, SyncStatus, SyncInfo,
|
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,
|
H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256,
|
||||||
U64 as RpcU64,
|
U64 as RpcU64,
|
||||||
};
|
};
|
||||||
@ -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>> {
|
fn compilers(&self) -> Result<Vec<String>> {
|
||||||
Err(errors::deprecated("Compilation functionality is deprecated.".to_string()))
|
Err(errors::deprecated("Compilation functionality is deprecated.".to_string()))
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ use parity_runtime::Runtime;
|
|||||||
use jsonrpc_core::IoHandler;
|
use jsonrpc_core::IoHandler;
|
||||||
use v1::helpers::dispatch::FullDispatcher;
|
use v1::helpers::dispatch::FullDispatcher;
|
||||||
use v1::helpers::nonce;
|
use v1::helpers::nonce;
|
||||||
use v1::impls::{EthClient, SigningUnsafeClient};
|
use v1::impls::{EthClient, EthClientOptions, SigningUnsafeClient};
|
||||||
use v1::metadata::Metadata;
|
use v1::metadata::Metadata;
|
||||||
use v1::tests::helpers::{TestSnapshotService, TestSyncProvider, Config};
|
use v1::tests::helpers::{TestSnapshotService, TestSyncProvider, Config};
|
||||||
use v1::traits::eth::Eth;
|
use v1::traits::eth::Eth;
|
||||||
@ -140,7 +140,13 @@ impl EthTester {
|
|||||||
&opt_account_provider,
|
&opt_account_provider,
|
||||||
&miner_service,
|
&miner_service,
|
||||||
&external_miner,
|
&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())));
|
let reservations = Arc::new(Mutex::new(nonce::Reservations::new(runtime.executor())));
|
||||||
@ -198,6 +204,33 @@ fn eth_get_balance() {
|
|||||||
assert_eq!(tester.handler.handle_request_sync(req_new_acc).unwrap(), res_new_acc);
|
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]
|
#[test]
|
||||||
fn eth_block_number() {
|
fn eth_block_number() {
|
||||||
let chain = extract_chain!("BlockchainTests/bcGasPricerTest/RPC_API_Test");
|
let chain = extract_chain!("BlockchainTests/bcGasPricerTest/RPC_API_Test");
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
use jsonrpc_core::{Result, BoxFuture};
|
use jsonrpc_core::{Result, BoxFuture};
|
||||||
use jsonrpc_macros::Trailing;
|
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::{Log, Receipt, SyncStatus, Transaction, Work};
|
||||||
use v1::types::{H64, H160, H256, U256, U64};
|
use v1::types::{H64, H160, H256, U256, U64};
|
||||||
|
|
||||||
@ -69,6 +69,10 @@ build_rpc_trait! {
|
|||||||
#[rpc(name = "eth_getBalance")]
|
#[rpc(name = "eth_getBalance")]
|
||||||
fn balance(&self, H160, Trailing<BlockNumber>) -> BoxFuture<U256>;
|
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.
|
/// Returns content of the storage at given address.
|
||||||
#[rpc(name = "eth_getStorageAt")]
|
#[rpc(name = "eth_getStorageAt")]
|
||||||
fn storage_at(&self, H160, U256, Trailing<BlockNumber>) -> BoxFuture<H256>;
|
fn storage_at(&self, H160, U256, Trailing<BlockNumber>) -> BoxFuture<H256>;
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
use v1::types::{H160, H256, U256, Bytes};
|
||||||
|
|
||||||
/// Account information.
|
/// Account information.
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
|
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
|
||||||
@ -21,6 +22,28 @@ pub struct AccountInfo {
|
|||||||
pub name: String,
|
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`).
|
/// Extended account information (used by `parity_allAccountInfo`).
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
|
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
|
||||||
pub struct ExtAccountInfo {
|
pub struct ExtAccountInfo {
|
||||||
|
@ -46,8 +46,9 @@ mod private_receipt;
|
|||||||
mod eip191;
|
mod eip191;
|
||||||
|
|
||||||
pub mod pubsub;
|
pub mod pubsub;
|
||||||
|
|
||||||
pub use self::eip191::{EIP191Version, PresignedTransaction};
|
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::bytes::Bytes;
|
||||||
pub use self::block::{RichBlock, Block, BlockTransactions, Header, RichHeader, Rich};
|
pub use self::block::{RichBlock, Block, BlockTransactions, Header, RichHeader, Rich};
|
||||||
pub use self::block_number::{BlockNumber, LightBlockNumber, block_number_to_id};
|
pub use self::block_number::{BlockNumber, LightBlockNumber, block_number_to_id};
|
||||||
|
Loading…
Reference in New Issue
Block a user