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