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,
|
||||
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());
|
||||
|
@ -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};
|
||||
@ -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;
|
||||
@ -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,
|
||||
};
|
||||
@ -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 {
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
@ -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()))
|
||||
}
|
||||
|
@ -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;
|
||||
@ -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())));
|
||||
@ -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");
|
||||
|
@ -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};
|
||||
|
||||
@ -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>;
|
||||
|
@ -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)]
|
||||
@ -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 {
|
||||
|
@ -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};
|
||||
|
Loading…
Reference in New Issue
Block a user