helios/execution/src/rpc/http_rpc.rs

239 lines
6.4 KiB
Rust

use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use async_trait::async_trait;
use ethers::prelude::Address;
use ethers::providers::{JsonRpcClient, Middleware, Provider, ProviderError};
use ethers::types::transaction::eip2718::TypedTransaction;
use ethers::types::transaction::eip2930::AccessList;
use ethers::types::{
BlockId, BlockNumber, Bytes, EIP1186ProofResponse, Eip1559TransactionRequest, FeeHistory,
Filter, Log, Transaction, TransactionReceipt, H256, U256,
};
use eyre::Result;
use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_json::to_value;
use wasm_bindgen::JsValue;
use crate::types::CallOpts;
use common::errors::RpcError;
use super::ExecutionRpc;
use js_sys::Promise;
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen_futures::JsFuture;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = window)]
fn consensus_rpc_handler(data: JsValue) -> Promise;
}
pub struct HttpRpc {
provider: Provider<LumeProvider>,
}
impl Clone for HttpRpc {
fn clone(&self) -> Self {
Self::new().unwrap()
}
}
pub struct LumeError {
message: String,
}
impl Display for LumeError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Error: {}", self.message)
}
}
impl Debug for LumeError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Debug: {}", self.message)
}
}
impl Error for LumeError {}
impl From<LumeError> for ProviderError {
fn from(err: LumeError) -> Self {
ProviderError::CustomError(err.to_string())
}
}
impl From<JsValue> for LumeError {
fn from(error: JsValue) -> Self {
LumeError {
message: error
.as_string()
.unwrap_or_else(|| "Unknown error".to_string()),
}
}
}
impl From<RpcError<String>> for LumeError {
fn from(error: RpcError<String>) -> Self {
LumeError {
message: error.to_string(),
}
}
}
#[derive(Clone, Debug)]
pub struct LumeProvider {}
impl LumeProvider {
pub fn new() -> Self {
LumeProvider {}
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl JsonRpcClient for LumeProvider {
type Error = LumeError;
async fn request<T, R>(&self, method: &str, params: T) -> Result<R, Self::Error>
where
T: Debug + Serialize + Send + Sync,
R: DeserializeOwned,
{
let js_params = to_value(&params).unwrap();
let json_str = serde_json::to_string(&js_params).unwrap();
let js_value = JsValue::from_str(&json_str);
let js_future = JsFuture::from(consensus_rpc_handler(js_value));
let result = js_future.await?;
let json = result.as_string().unwrap();
let response: R =
serde_json::from_str(&json).map_err(|e| RpcError::new(method, e.to_string()))?;
Ok(response)
}
}
#[async_trait(?Send)]
impl ExecutionRpc for HttpRpc {
fn new() -> Result<Self> {
let client = LumeProvider::new();
let provider = Provider::new(client);
Ok(HttpRpc { provider })
}
async fn get_proof(
&self,
address: &Address,
slots: &[H256],
block: u64,
) -> Result<EIP1186ProofResponse> {
let block = Some(BlockId::from(block));
let proof_response = self
.provider
.get_proof(*address, slots.to_vec(), block)
.await
.map_err(|e| RpcError::new("get_proof", e))?;
Ok(proof_response)
}
async fn create_access_list(&self, opts: &CallOpts, block: u64) -> Result<AccessList> {
let block = Some(BlockId::from(block));
let mut raw_tx = Eip1559TransactionRequest::new();
raw_tx.to = Some(opts.to.unwrap_or_default().into());
raw_tx.from = opts.from;
raw_tx.value = opts.value;
raw_tx.gas = Some(opts.gas.unwrap_or(U256::from(100_000_000)));
raw_tx.max_fee_per_gas = Some(U256::zero());
raw_tx.max_priority_fee_per_gas = Some(U256::zero());
raw_tx.data = opts
.data
.as_ref()
.map(|data| Bytes::from(data.as_slice().to_owned()));
let tx = TypedTransaction::Eip1559(raw_tx);
let list = self
.provider
.create_access_list(&tx, block)
.await
.map_err(|e| RpcError::new("create_access_list", e))?;
Ok(list.access_list)
}
async fn get_code(&self, address: &Address, block: u64) -> Result<Vec<u8>> {
let block = Some(BlockId::from(block));
let code = self
.provider
.get_code(*address, block)
.await
.map_err(|e| RpcError::new("get_code", e))?;
Ok(code.to_vec())
}
async fn send_raw_transaction(&self, bytes: &[u8]) -> Result<H256> {
let bytes = Bytes::from(bytes.to_owned());
let tx = self
.provider
.send_raw_transaction(bytes)
.await
.map_err(|e| RpcError::new("send_raw_transaction", e))?;
Ok(tx.tx_hash())
}
async fn get_transaction_receipt(&self, tx_hash: &H256) -> Result<Option<TransactionReceipt>> {
let receipt = self
.provider
.get_transaction_receipt(*tx_hash)
.await
.map_err(|e| RpcError::new("get_transaction_receipt", e))?;
Ok(receipt)
}
async fn get_transaction(&self, tx_hash: &H256) -> Result<Option<Transaction>> {
Ok(self
.provider
.get_transaction(*tx_hash)
.await
.map_err(|e| RpcError::new("get_transaction", e))?)
}
async fn get_logs(&self, filter: &Filter) -> Result<Vec<Log>> {
Ok(self
.provider
.get_logs(filter)
.await
.map_err(|e| RpcError::new("get_logs", e))?)
}
async fn chain_id(&self) -> Result<u64> {
Ok(self
.provider
.get_chainid()
.await
.map_err(|e| RpcError::new("chain_id", e))?
.as_u64())
}
async fn get_fee_history(
&self,
block_count: u64,
last_block: u64,
reward_percentiles: &[f64],
) -> Result<FeeHistory> {
let block = BlockNumber::from(last_block);
Ok(self
.provider
.fee_history(block_count, block, reward_percentiles)
.await
.map_err(|e| RpcError::new("fee_history", e))?)
}
}