use crate::Error;
use eth_types::{
Address, Block, Bytes, EIP1186ProofResponse, GethExecTrace, Hash, ResultGethExecTraces,
Transaction, Word, U64,
};
pub use ethers_core::types::BlockNumber;
use ethers_providers::JsonRpcClient;
use serde::Serialize;
pub fn serialize<T: serde::Serialize>(t: &T) -> serde_json::Value {
serde_json::to_value(t).expect("Types never fail to serialize.")
}
#[derive(Serialize)]
#[doc(hidden)]
pub(crate) struct GethLoggerConfig {
#[serde(rename = "EnableMemory")]
enable_memory: bool,
#[serde(rename = "DisableStack")]
disable_stack: bool,
#[serde(rename = "DisableStorage")]
disable_storage: bool,
#[serde(rename = "EnableReturnData")]
enable_return_data: bool,
}
impl Default for GethLoggerConfig {
fn default() -> Self {
Self {
enable_memory: false,
disable_stack: false,
disable_storage: false,
enable_return_data: true,
}
}
}
pub struct GethClient<P: JsonRpcClient>(pub P);
impl<P: JsonRpcClient> GethClient<P> {
pub fn new(provider: P) -> Self {
Self(provider)
}
pub async fn get_coinbase(&self) -> Result<Address, Error> {
self.0
.request("eth_coinbase", ())
.await
.map_err(|e| Error::JSONRpcError(e.into()))
}
pub async fn get_chain_id(&self) -> Result<u64, Error> {
let net_id: U64 = self
.0
.request("eth_chainId", ())
.await
.map_err(|e| Error::JSONRpcError(e.into()))?;
Ok(net_id.as_u64())
}
pub async fn get_block_by_hash(&self, hash: Hash) -> Result<Block<Transaction>, Error> {
let hash = serialize(&hash);
let flag = serialize(&true);
self.0
.request("eth_getBlockByHash", [hash, flag])
.await
.map_err(|e| Error::JSONRpcError(e.into()))
}
pub async fn get_block_by_number(
&self,
block_num: BlockNumber,
) -> Result<Block<Transaction>, Error> {
let num = serialize(&block_num);
let flag = serialize(&true);
self.0
.request("eth_getBlockByNumber", [num, flag])
.await
.map_err(|e| Error::JSONRpcError(e.into()))
}
pub async fn trace_block_by_hash(&self, hash: Hash) -> Result<Vec<GethExecTrace>, Error> {
let hash = serialize(&hash);
let cfg = serialize(&GethLoggerConfig::default());
let resp: ResultGethExecTraces = self
.0
.request("debug_traceBlockByHash", [hash, cfg])
.await
.map_err(|e| Error::JSONRpcError(e.into()))?;
Ok(resp.0.into_iter().map(|step| step.result).collect())
}
pub async fn trace_block_by_number(
&self,
block_num: BlockNumber,
) -> Result<Vec<GethExecTrace>, Error> {
let num = serialize(&block_num);
let cfg = serialize(&GethLoggerConfig::default());
let resp: ResultGethExecTraces = self
.0
.request("debug_traceBlockByNumber", [num, cfg])
.await
.map_err(|e| Error::JSONRpcError(e.into()))?;
Ok(resp.0.into_iter().map(|step| step.result).collect())
}
pub async fn get_code(
&self,
contract_address: Address,
block_num: BlockNumber,
) -> Result<Vec<u8>, Error> {
let address = serialize(&contract_address);
let num = serialize(&block_num);
let resp: Bytes = self
.0
.request("eth_getCode", [address, num])
.await
.map_err(|e| Error::JSONRpcError(e.into()))?;
Ok(resp.to_vec())
}
pub async fn get_proof(
&self,
account: Address,
keys: Vec<Word>,
block_num: BlockNumber,
) -> Result<EIP1186ProofResponse, Error> {
let account = serialize(&account);
let keys = serialize(&keys);
let num = serialize(&block_num);
self.0
.request("eth_getProof", [account, keys, num])
.await
.map_err(|e| Error::JSONRpcError(e.into()))
}
pub async fn miner_stop(&self) -> Result<(), Error> {
self.0
.request("miner_stop", ())
.await
.map_err(|e| Error::JSONRpcError(e.into()))
}
pub async fn miner_start(&self) -> Result<(), Error> {
self.0
.request("miner_start", [serialize(&1)])
.await
.map_err(|e| Error::JSONRpcError(e.into()))
}
}