From 6dff233e43332675f0cea1a0834104f003b14298 Mon Sep 17 00:00:00 2001 From: tgmichel Date: Wed, 17 Jun 2020 16:44:19 +0200 Subject: [PATCH 1/3] StorageData wip --- rpc/Cargo.toml | 4 ++++ rpc/src/lib.rs | 63 ++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 170b94cae1..4b2cfabd69 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -15,14 +15,18 @@ frontier-rpc-core = { path = "core" } frontier-rpc-primitives = { path = "primitives" } sp-runtime = { path = "../vendor/substrate/primitives/runtime" } sp-api = { path = "../vendor/substrate/primitives/api" } +sp-io = { path = "../vendor/substrate/primitives/io" } sp-consensus = { path = "../vendor/substrate/primitives/consensus/common" } sp-transaction-pool = { path = "../vendor/substrate/primitives/transaction-pool" } sp-storage = { path = "../vendor/substrate/primitives/storage" } sc-service = { path = "../vendor/substrate/client/service" } sc-client-api = { path = "../vendor/substrate/client/api" } +sp-blockchain = { path = "../vendor/substrate/primitives/blockchain" } +frame-support = { path = "../vendor/substrate/frame/support" } ethereum = { version = "0.2", features = ["codec"] } codec = { package = "parity-scale-codec", version = "1.0.0" } rlp = "0.4" pallet-ethereum = "0.1" futures = { version = "0.3.1", features = ["compat"] } sha3 = "0.8" +hex = { version = "0.4" } \ No newline at end of file diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 6c011253dc..ece76eed6c 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -20,9 +20,12 @@ use ethereum::{Block as EthereumBlock, Transaction as EthereumTransaction}; use ethereum_types::{H160, H256, H64, U256, U64}; use jsonrpc_core::{BoxFuture, Result, ErrorCode, Error, futures::future::{self, Future}}; use futures::future::TryFutureExt; -use sp_runtime::traits::{Block as BlockT, Header as _, UniqueSaturatedInto}; +use sp_runtime::traits::{Block as BlockT, Header as _, UniqueSaturatedInto, NumberFor}; use sp_runtime::transaction_validity::TransactionSource; use sp_api::{ProvideRuntimeApi, BlockId}; +use sp_io::hashing::{twox_64, twox_128, blake2_128, blake2_256}; +use sp_blockchain::{Error as BlockChainError, HeaderMetadata, HeaderBackend}; +use sp_storage::StorageKey; use sp_consensus::SelectChain; use sp_transaction_pool::TransactionPool; use sc_client_api::backend::{StorageProvider, Backend, StateBackend}; @@ -36,7 +39,8 @@ use frontier_rpc_core::types::{ use frontier_rpc_primitives::{EthereumRuntimeApi, ConvertTransaction, TransactionStatus}; pub use frontier_rpc_core::EthApiServer; - +use frame_support::debug::native; +use codec::{Encode,Decode}; fn internal_err(message: &str) -> Error { Error { code: ErrorCode::InternalError, @@ -131,8 +135,13 @@ fn transaction_build( } } +fn storage_prefix_build(module: &[u8], storage: &[u8]) -> Vec { + [twox_128(module), twox_128(storage)].concat().to_vec() +} + impl EthApiT for EthApi where - C: ProvideRuntimeApi + StorageProvider, + C: ProvideRuntimeApi + StorageProvider + + HeaderBackend + HeaderMetadata, C::Api: EthereumRuntimeApi, BE: Backend + 'static, BE::State: StateBackend, @@ -206,15 +215,51 @@ impl EthApiT for EthApi where } fn balance(&self, address: H160, number: Option) -> Result { + let header = self.select_chain.best_chain() + .map_err(|_| internal_err("fetch header failed"))?; + + let number_param: u32; + if let Some(number) = number { - if number != BlockNumber::Latest { - unimplemented!("fetch nonce for past blocks is not yet supported"); + + if let Some(block_number) = number.to_min_block_num() { + number_param = block_number.unique_saturated_into(); + } else if number == BlockNumber::Latest { + number_param = header.number().clone().unique_saturated_into() as u32; + } else { + unimplemented!("only latest or block number are supported"); } + } else { + number_param = header.number().clone().unique_saturated_into() as u32; } - let header = self - .select_chain - .best_chain() - .map_err(|_| internal_err("fetch header failed"))?; + + let mut block_hash = None; + if let Ok(result) = self.client.header(BlockId::Number(number_param.into())) { + if let Some(header) = result { + block_hash = Some(header.hash()); + } + } + + let mut data: U256 = U256::zero(); + if let Some(block_hash) = block_hash { + // StorageProvider prefix + let mut prefix = storage_prefix_build(b"EVM", b"Accounts"); + // StorageMap blake2_128_concat key + let mut storage_key = blake2_128(address.as_bytes()).to_vec(); + storage_key.extend_from_slice(address.as_bytes()); + // Module and Storage prefix + StorageMap concat + prefix.extend(storage_key.clone()); + + let key = StorageKey(prefix); + + // TODO this is wip, we need to decode the StorageData back to evm::backend::Account + data = match self.client.storage(&BlockId::Hash(block_hash), &key) { + //Ok(Some(data)) => (&data.0).balance.into(), + Ok(data) => U256::zero(), + Err(_) => U256::zero() + }; + } + Ok( self.client .runtime_api() From f32bae1d72c4ac0f881681290638d646905daafd Mon Sep 17 00:00:00 2001 From: tgmichel Date: Thu, 18 Jun 2020 15:35:57 +0200 Subject: [PATCH 2/3] Access StorageData for eth_getBalance --- rpc/Cargo.toml | 4 +--- rpc/primitives/src/lib.rs | 1 + rpc/src/lib.rs | 28 ++++++++++++++-------------- template/runtime/src/lib.rs | 5 +++++ 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 4b2cfabd69..1c3926f418 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -22,11 +22,9 @@ sp-storage = { path = "../vendor/substrate/primitives/storage" } sc-service = { path = "../vendor/substrate/client/service" } sc-client-api = { path = "../vendor/substrate/client/api" } sp-blockchain = { path = "../vendor/substrate/primitives/blockchain" } -frame-support = { path = "../vendor/substrate/frame/support" } ethereum = { version = "0.2", features = ["codec"] } codec = { package = "parity-scale-codec", version = "1.0.0" } rlp = "0.4" pallet-ethereum = "0.1" futures = { version = "0.3.1", features = ["compat"] } -sha3 = "0.8" -hex = { version = "0.4" } \ No newline at end of file +sha3 = "0.8" \ No newline at end of file diff --git a/rpc/primitives/src/lib.rs b/rpc/primitives/src/lib.rs index 4ea881fd57..5ace473bcb 100644 --- a/rpc/primitives/src/lib.rs +++ b/rpc/primitives/src/lib.rs @@ -38,6 +38,7 @@ sp_api::decl_runtime_apis! { pub trait EthereumRuntimeApi { fn chain_id() -> u64; fn account_basic(address: H160) -> pallet_evm::Account; + fn account_decode(bytes: Vec) -> pallet_evm::Account; fn transaction_status(hash: H256) -> Option; fn gas_price() -> U256; fn account_code_at(address: H160) -> Vec; diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index ece76eed6c..8fbbea6ca5 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -20,10 +20,10 @@ use ethereum::{Block as EthereumBlock, Transaction as EthereumTransaction}; use ethereum_types::{H160, H256, H64, U256, U64}; use jsonrpc_core::{BoxFuture, Result, ErrorCode, Error, futures::future::{self, Future}}; use futures::future::TryFutureExt; -use sp_runtime::traits::{Block as BlockT, Header as _, UniqueSaturatedInto, NumberFor}; +use sp_runtime::traits::{Block as BlockT, Header as _, UniqueSaturatedInto}; use sp_runtime::transaction_validity::TransactionSource; use sp_api::{ProvideRuntimeApi, BlockId}; -use sp_io::hashing::{twox_64, twox_128, blake2_128, blake2_256}; +use sp_io::hashing::{twox_128, blake2_128}; use sp_blockchain::{Error as BlockChainError, HeaderMetadata, HeaderBackend}; use sp_storage::StorageKey; use sp_consensus::SelectChain; @@ -37,10 +37,8 @@ use frontier_rpc_core::types::{ SyncStatus, Transaction, Work, Rich, Block, BlockTransactions }; use frontier_rpc_primitives::{EthereumRuntimeApi, ConvertTransaction, TransactionStatus}; - pub use frontier_rpc_core::EthApiServer; -use frame_support::debug::native; -use codec::{Encode,Decode}; + fn internal_err(message: &str) -> Error { Error { code: ErrorCode::InternalError, @@ -221,7 +219,6 @@ impl EthApiT for EthApi where let number_param: u32; if let Some(number) = number { - if let Some(block_number) = number.to_min_block_num() { number_param = block_number.unique_saturated_into(); } else if number == BlockNumber::Latest { @@ -240,7 +237,6 @@ impl EthApiT for EthApi where } } - let mut data: U256 = U256::zero(); if let Some(block_hash) = block_hash { // StorageProvider prefix let mut prefix = storage_prefix_build(b"EVM", b"Accounts"); @@ -252,14 +248,18 @@ impl EthApiT for EthApi where let key = StorageKey(prefix); - // TODO this is wip, we need to decode the StorageData back to evm::backend::Account - data = match self.client.storage(&BlockId::Hash(block_hash), &key) { - //Ok(Some(data)) => (&data.0).balance.into(), - Ok(data) => U256::zero(), - Err(_) => U256::zero() - }; + if let Ok(Some(data)) = self.client.storage( + &BlockId::Hash(block_hash), + &key) { + return Ok( + self.client + .runtime_api() + .account_decode(&BlockId::Hash(header.hash()), data.0) + .map_err(|_| internal_err("fetch runtime chain id failed"))? + .balance.into() + ); + } } - Ok( self.client .runtime_api() diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index 7feb3bbaa2..b760a16648 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -452,6 +452,11 @@ impl_runtime_apis! { evm::Module::::accounts(address) } + fn account_decode(bytes: Vec) -> EVMAccount { + let account: EVMAccount = Decode::decode(&mut &bytes[..]).unwrap(); + account + } + fn transaction_status(hash: H256) -> Option { ethereum::Module::::transaction_status(hash) } From 0271733ae1ce3862f106983d8bcc72aed483219a Mon Sep 17 00:00:00 2001 From: tgmichel Date: Thu, 18 Jun 2020 17:38:22 +0200 Subject: [PATCH 3/3] Remove account_decode Runtime impl --- rpc/Cargo.toml | 2 +- rpc/primitives/src/lib.rs | 4 ++-- rpc/src/lib.rs | 22 +++++++--------------- template/runtime/src/lib.rs | 5 ----- 4 files changed, 10 insertions(+), 23 deletions(-) diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 1c3926f418..7c071d3cec 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -27,4 +27,4 @@ codec = { package = "parity-scale-codec", version = "1.0.0" } rlp = "0.4" pallet-ethereum = "0.1" futures = { version = "0.3.1", features = ["compat"] } -sha3 = "0.8" \ No newline at end of file +sha3 = "0.8" diff --git a/rpc/primitives/src/lib.rs b/rpc/primitives/src/lib.rs index 5ace473bcb..f9f974c911 100644 --- a/rpc/primitives/src/lib.rs +++ b/rpc/primitives/src/lib.rs @@ -21,6 +21,7 @@ use ethereum::{Log, Block as EthereumBlock, Transaction as EthereumTransaction}; use ethereum_types::Bloom; use codec::{Encode, Decode}; use sp_std::vec::Vec; +pub use pallet_evm::{Account as EVMAccount}; #[derive(Eq, PartialEq, Clone, Encode, Decode, sp_runtime::RuntimeDebug)] pub struct TransactionStatus { @@ -37,8 +38,7 @@ sp_api::decl_runtime_apis! { /// API necessary for Ethereum-compatibility layer. pub trait EthereumRuntimeApi { fn chain_id() -> u64; - fn account_basic(address: H160) -> pallet_evm::Account; - fn account_decode(bytes: Vec) -> pallet_evm::Account; + fn account_basic(address: H160) -> EVMAccount; fn transaction_status(hash: H256) -> Option; fn gas_price() -> U256; fn account_code_at(address: H160) -> Vec; diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 8fbbea6ca5..e131ea7a37 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -36,7 +36,10 @@ use frontier_rpc_core::types::{ BlockNumber, Bytes, CallRequest, EthAccount, Filter, Index, Log, Receipt, RichBlock, SyncStatus, Transaction, Work, Rich, Block, BlockTransactions }; -use frontier_rpc_primitives::{EthereumRuntimeApi, ConvertTransaction, TransactionStatus}; +use frontier_rpc_primitives::{ + EthereumRuntimeApi, ConvertTransaction, TransactionStatus, EVMAccount +}; +use codec::Decode; pub use frontier_rpc_core::EthApiServer; fn internal_err(message: &str) -> Error { @@ -251,22 +254,11 @@ impl EthApiT for EthApi where if let Ok(Some(data)) = self.client.storage( &BlockId::Hash(block_hash), &key) { - return Ok( - self.client - .runtime_api() - .account_decode(&BlockId::Hash(header.hash()), data.0) - .map_err(|_| internal_err("fetch runtime chain id failed"))? - .balance.into() - ); + let account: EVMAccount = Decode::decode(&mut &data.0[..]).unwrap(); + return Ok(account.balance.into()); } } - Ok( - self.client - .runtime_api() - .account_basic(&BlockId::Hash(header.hash()), address) - .map_err(|_| internal_err("fetch runtime chain id failed"))? - .balance.into(), - ) + Ok(U256::zero()) } fn proof(&self, _: H160, _: Vec, _: Option) -> BoxFuture { diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index b760a16648..7feb3bbaa2 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -452,11 +452,6 @@ impl_runtime_apis! { evm::Module::::accounts(address) } - fn account_decode(bytes: Vec) -> EVMAccount { - let account: EVMAccount = Decode::decode(&mut &bytes[..]).unwrap(); - account - } - fn transaction_status(hash: H256) -> Option { ethereum::Module::::transaction_status(hash) }