diff --git a/rpc/core/src/eth.rs b/rpc/core/src/eth.rs index fac336922c..c394c2c3ad 100644 --- a/rpc/core/src/eth.rs +++ b/rpc/core/src/eth.rs @@ -57,7 +57,7 @@ pub trait EthApi { /// Returns current gas_price. #[rpc(name = "eth_gasPrice")] - fn gas_price(&self) -> BoxFuture; + fn gas_price(&self) -> Result; /// Returns accounts list. #[rpc(name = "eth_accounts")] @@ -69,7 +69,7 @@ pub trait EthApi { /// Returns balance of the given account. #[rpc(name = "eth_getBalance")] - fn balance(&self, _: H160, _: Option) -> BoxFuture; + fn balance(&self, _: H160, _: Option) -> Result; /// Returns the account- and storage-values of the specified account including the Merkle-proof #[rpc(name = "eth_getProof")] @@ -109,7 +109,7 @@ pub trait EthApi { /// Returns the code at given address at given time (block number). #[rpc(name = "eth_getCode")] - fn code_at(&self, _: H160, _: Option) -> BoxFuture; + fn code_at(&self, _: H160, _: Option) -> Result; /// Sends signed transaction, returning its hash. #[rpc(name = "eth_sendRawTransaction")] diff --git a/rpc/primitives/src/lib.rs b/rpc/primitives/src/lib.rs index 446a67b2f5..5cc0721c22 100644 --- a/rpc/primitives/src/lib.rs +++ b/rpc/primitives/src/lib.rs @@ -16,7 +16,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_core::{H160, H256}; +use sp_core::{H160, H256, U256}; use ethereum::Log; use ethereum_types::Bloom; use codec::{Encode, Decode}; @@ -39,6 +39,8 @@ sp_api::decl_runtime_apis! { fn chain_id() -> u64; fn account_basic(address: H160) -> pallet_evm::Account; fn transaction_status(hash: H256) -> Option; + fn gas_price() -> U256; + fn account_code_at(address: H160) -> Vec; fn author() -> H160; } } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 7bac0bbd89..431dc4dc7d 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -18,7 +18,7 @@ use std::{marker::PhantomData, sync::Arc}; 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 _}; +use sp_runtime::traits::{Block as BlockT, Header as _, UniqueSaturatedInto}; use sp_runtime::transaction_validity::TransactionSource; use sp_api::{ProvideRuntimeApi, BlockId}; use sp_consensus::SelectChain; @@ -107,8 +107,18 @@ impl EthApiT for EthApi where .map_err(|_| internal_err("fetch runtime chain id failed"))?.into())) } - fn gas_price(&self) -> BoxFuture { - unimplemented!("gas_price"); + fn gas_price(&self) -> Result { + let header = self + .select_chain + .best_chain() + .map_err(|_| internal_err("fetch header failed"))?; + Ok( + self.client + .runtime_api() + .gas_price(&BlockId::Hash(header.hash())) + .map_err(|_| internal_err("fetch runtime chain id failed"))? + .into(), + ) } fn accounts(&self) -> Result> { @@ -116,11 +126,30 @@ impl EthApiT for EthApi where } fn block_number(&self) -> Result { - unimplemented!("block_number"); + let header = self + .select_chain + .best_chain() + .map_err(|_| internal_err("fetch header failed"))?; + Ok(U256::from(header.number().clone().unique_saturated_into())) } - fn balance(&self, _: H160, _: Option) -> BoxFuture { - unimplemented!("balance"); + fn balance(&self, address: H160, number: Option) -> Result { + if let Some(number) = number { + if number != BlockNumber::Latest { + unimplemented!("fetch nonce for past blocks is not yet supported"); + } + } + let header = self + .select_chain + .best_chain() + .map_err(|_| internal_err("fetch header failed"))?; + Ok( + self.client + .runtime_api() + .account_basic(&BlockId::Hash(header.hash()), address) + .map_err(|_| internal_err("fetch runtime chain id failed"))? + .balance.into(), + ) } fn proof(&self, _: H160, _: Vec, _: Option) -> BoxFuture { @@ -168,8 +197,23 @@ impl EthApiT for EthApi where Ok(U256::zero()) } - fn code_at(&self, _: H160, _: Option) -> BoxFuture { - unimplemented!("code_at"); + fn code_at(&self, address: H160, number: Option) -> Result { + if let Some(number) = number { + if number != BlockNumber::Latest { + unimplemented!("fetch nonce for past blocks is not yet supported"); + } + } + let header = self + .select_chain + .best_chain() + .map_err(|_| internal_err("fetch header failed"))?; + Ok( + self.client + .runtime_api() + .account_code_at(&BlockId::Hash(header.hash()), address) + .map_err(|_| internal_err("fetch runtime chain id failed"))? + .into(), + ) } fn send_raw_transaction(&self, bytes: Bytes) -> BoxFuture { diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index 2cf8b2960a..629ab2152a 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -33,6 +33,7 @@ use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata, U256, H160, H256}; use sp_runtime::traits::{ BlakeTwo256, Block as BlockT, IdentifyAccount, IdentityLookup, NumberFor, Saturating, Verify, + UniqueSaturatedInto }; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, @@ -451,6 +452,14 @@ impl_runtime_apis! { ethereum::Module::::transaction_status(hash) } + fn gas_price() -> U256 { + FixedGasPrice::min_gas_price() + } + + fn account_code_at(address: H160) -> Vec { + evm::Module::::account_codes(address) + } + fn author() -> H160 { let digest = >::digest(); let pre_runtime_digests = digest.logs.iter().filter_map(|d| d.as_pre_runtime());