feat: refactor client (#17)
* seperate client and node * encapsule rpc inside client * pass proper port into rpc * track chain head in seperate thread * client new takes config instead of arc * refactor main * add start method to client
This commit is contained in:
parent
b8d21abe44
commit
cf6c211516
|
@ -1,19 +1,24 @@
|
||||||
use std::{sync::Arc, time::Duration};
|
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use common::utils::hex_str_to_bytes;
|
use common::utils::hex_str_to_bytes;
|
||||||
use dirs::home_dir;
|
use dirs::home_dir;
|
||||||
use env_logger::Env;
|
use env_logger::Env;
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
use tokio::{sync::Mutex, time::sleep};
|
|
||||||
|
|
||||||
use client::{rpc::Rpc, Client};
|
use client::Client;
|
||||||
use config::{networks, Config};
|
use config::{networks, Config};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
|
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
|
||||||
|
|
||||||
|
let config = get_config()?;
|
||||||
|
let mut client = Client::new(config).await?;
|
||||||
|
client.start().await?;
|
||||||
|
|
||||||
|
std::future::pending().await
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_config() -> Result<Config> {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
let mut config = match cli.network.as_str() {
|
let mut config = match cli.network.as_str() {
|
||||||
"goerli" => networks::goerli(),
|
"goerli" => networks::goerli(),
|
||||||
|
@ -28,26 +33,19 @@ async fn main() -> Result<()> {
|
||||||
config.general.checkpoint = hex_str_to_bytes(&checkpoint)?;
|
config.general.checkpoint = hex_str_to_bytes(&checkpoint)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut client = Client::new(Arc::new(config)).await?;
|
if let Some(port) = cli.port {
|
||||||
client.sync().await?;
|
config.general.rpc_port = Some(port);
|
||||||
|
|
||||||
let client = Arc::new(Mutex::new(client));
|
|
||||||
|
|
||||||
let mut rpc = Rpc::new(client.clone(), cli.port);
|
|
||||||
rpc.start().await?;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
sleep(Duration::from_secs(10)).await;
|
|
||||||
client.lock().await.advance().await?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[clap(short, long, default_value = "goerli")]
|
#[clap(short, long, default_value = "goerli")]
|
||||||
network: String,
|
network: String,
|
||||||
#[clap(short, long, default_value = "8545")]
|
#[clap(short, long)]
|
||||||
port: u16,
|
port: Option<u16>,
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
checkpoint: Option<String>,
|
checkpoint: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,198 +1,132 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use ethers::prelude::{Address, U256};
|
use ethers::prelude::{Address, U256};
|
||||||
use ethers::types::{Transaction, TransactionReceipt, H256};
|
use ethers::types::{Transaction, TransactionReceipt, H256};
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
|
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use consensus::rpc::nimbus_rpc::NimbusRpc;
|
use consensus::types::Header;
|
||||||
use consensus::types::{ExecutionPayload, Header};
|
|
||||||
use consensus::ConsensusClient;
|
|
||||||
use execution::evm::Evm;
|
|
||||||
use execution::rpc::http_rpc::HttpRpc;
|
|
||||||
use execution::types::{CallOpts, ExecutionBlock};
|
use execution::types::{CallOpts, ExecutionBlock};
|
||||||
use execution::ExecutionClient;
|
use log::warn;
|
||||||
|
use tokio::spawn;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
use tokio::time::sleep;
|
||||||
|
|
||||||
|
use crate::node::Node;
|
||||||
|
use crate::rpc::Rpc;
|
||||||
|
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
consensus: ConsensusClient<NimbusRpc>,
|
node: Arc<Mutex<Node>>,
|
||||||
execution: ExecutionClient<HttpRpc>,
|
rpc: Option<Rpc>,
|
||||||
config: Arc<Config>,
|
|
||||||
payloads: HashMap<u64, ExecutionPayload>,
|
|
||||||
block_hashes: HashMap<Vec<u8>, u64>,
|
|
||||||
block_head: u64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub async fn new(config: Arc<Config>) -> Result<Self> {
|
pub async fn new(config: Config) -> Result<Self> {
|
||||||
let consensus_rpc = &config.general.consensus_rpc;
|
let config = Arc::new(config);
|
||||||
let checkpoint_hash = &config.general.checkpoint;
|
let node = Node::new(config.clone()).await?;
|
||||||
let execution_rpc = &config.general.execution_rpc;
|
let node = Arc::new(Mutex::new(node));
|
||||||
|
|
||||||
let consensus =
|
let rpc = if let Some(port) = config.general.rpc_port {
|
||||||
ConsensusClient::new(consensus_rpc, checkpoint_hash, config.clone()).await?;
|
Some(Rpc::new(node.clone(), port))
|
||||||
let execution = ExecutionClient::new(execution_rpc)?;
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let payloads = HashMap::new();
|
Ok(Client { node, rpc })
|
||||||
let block_hashes = HashMap::new();
|
|
||||||
|
|
||||||
Ok(Client {
|
|
||||||
consensus,
|
|
||||||
execution,
|
|
||||||
config,
|
|
||||||
payloads,
|
|
||||||
block_hashes,
|
|
||||||
block_head: 0,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn sync(&mut self) -> Result<()> {
|
pub async fn start(&mut self) -> Result<()> {
|
||||||
self.consensus.sync().await?;
|
self.rpc.as_mut().unwrap().start().await?;
|
||||||
|
self.node.lock().await.sync().await?;
|
||||||
|
|
||||||
let head = self.consensus.get_header();
|
let node = self.node.clone();
|
||||||
let payload = self
|
spawn(async move {
|
||||||
.consensus
|
loop {
|
||||||
.get_execution_payload(&Some(head.slot))
|
let res = node.lock().await.advance().await;
|
||||||
.await?;
|
if let Err(err) = res {
|
||||||
|
warn!("{}", err);
|
||||||
|
}
|
||||||
|
|
||||||
self.block_head = payload.block_number;
|
sleep(Duration::from_secs(10)).await;
|
||||||
self.block_hashes
|
}
|
||||||
.insert(payload.block_hash.to_vec(), payload.block_number);
|
});
|
||||||
self.payloads.insert(payload.block_number, payload);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn advance(&mut self) -> Result<()> {
|
pub async fn call(&self, opts: &CallOpts, block: &Option<u64>) -> Result<Vec<u8>> {
|
||||||
self.consensus.advance().await?;
|
self.node.lock().await.call(opts, block)
|
||||||
|
|
||||||
let head = self.consensus.get_header();
|
|
||||||
let payload = self
|
|
||||||
.consensus
|
|
||||||
.get_execution_payload(&Some(head.slot))
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
self.block_head = payload.block_number;
|
|
||||||
self.block_hashes
|
|
||||||
.insert(payload.block_hash.to_vec(), payload.block_number);
|
|
||||||
self.payloads.insert(payload.block_number, payload);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(&self, opts: &CallOpts, block: &Option<u64>) -> Result<Vec<u8>> {
|
pub async fn estimate_gas(&self, opts: &CallOpts) -> Result<u64> {
|
||||||
let payload = self.get_payload(block)?;
|
self.node.lock().await.estimate_gas(opts)
|
||||||
let mut evm = Evm::new(self.execution.clone(), payload, self.chain_id());
|
|
||||||
evm.call(opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn estimate_gas(&self, opts: &CallOpts) -> Result<u64> {
|
|
||||||
let payload = self.get_payload(&None)?;
|
|
||||||
let mut evm = Evm::new(self.execution.clone(), payload, self.chain_id());
|
|
||||||
evm.estimate_gas(opts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_balance(&self, address: &Address, block: &Option<u64>) -> Result<U256> {
|
pub async fn get_balance(&self, address: &Address, block: &Option<u64>) -> Result<U256> {
|
||||||
let payload = self.get_payload(block)?;
|
self.node.lock().await.get_balance(address, block).await
|
||||||
let account = self.execution.get_account(&address, None, &payload).await?;
|
|
||||||
Ok(account.balance)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_nonce(&self, address: &Address, block: &Option<u64>) -> Result<u64> {
|
pub async fn get_nonce(&self, address: &Address, block: &Option<u64>) -> Result<u64> {
|
||||||
let payload = self.get_payload(block)?;
|
self.node.lock().await.get_nonce(address, block).await
|
||||||
let account = self.execution.get_account(&address, None, &payload).await?;
|
|
||||||
Ok(account.nonce)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_code(&self, address: &Address, block: &Option<u64>) -> Result<Vec<u8>> {
|
pub async fn get_code(&self, address: &Address, block: &Option<u64>) -> Result<Vec<u8>> {
|
||||||
let payload = self.get_payload(block)?;
|
self.node.lock().await.get_code(address, block).await
|
||||||
self.execution.get_code(&address, &payload).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_storage_at(&self, address: &Address, slot: H256) -> Result<U256> {
|
pub async fn get_storage_at(&self, address: &Address, slot: H256) -> Result<U256> {
|
||||||
let payload = self.get_payload(&None)?;
|
self.node.lock().await.get_storage_at(address, slot).await
|
||||||
let account = self
|
|
||||||
.execution
|
|
||||||
.get_account(address, Some(&[slot]), &payload)
|
|
||||||
.await?;
|
|
||||||
let value = account.slots.get(&slot);
|
|
||||||
match value {
|
|
||||||
Some(value) => Ok(*value),
|
|
||||||
None => Err(eyre::eyre!("Slot Not Found")),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_raw_transaction(&self, bytes: &Vec<u8>) -> Result<H256> {
|
pub async fn send_raw_transaction(&self, bytes: &Vec<u8>) -> Result<H256> {
|
||||||
self.execution.send_raw_transaction(bytes).await
|
self.node.lock().await.send_raw_transaction(bytes).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_transaction_receipt(
|
pub async fn get_transaction_receipt(
|
||||||
&self,
|
&self,
|
||||||
tx_hash: &H256,
|
tx_hash: &H256,
|
||||||
) -> Result<Option<TransactionReceipt>> {
|
) -> Result<Option<TransactionReceipt>> {
|
||||||
self.execution
|
self.node
|
||||||
.get_transaction_receipt(tx_hash, &self.payloads)
|
.lock()
|
||||||
|
.await
|
||||||
|
.get_transaction_receipt(tx_hash)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_transaction_by_hash(&self, tx_hash: &H256) -> Result<Option<Transaction>> {
|
pub async fn get_transaction_by_hash(&self, tx_hash: &H256) -> Result<Option<Transaction>> {
|
||||||
self.execution
|
self.node
|
||||||
.get_transaction(tx_hash, &self.payloads)
|
.lock()
|
||||||
|
.await
|
||||||
|
.get_transaction_by_hash(tx_hash)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_gas_price(&self) -> Result<U256> {
|
pub async fn get_gas_price(&self) -> Result<U256> {
|
||||||
let payload = self.get_payload(&None)?;
|
self.node.lock().await.get_gas_price()
|
||||||
let base_fee = U256::from_little_endian(&payload.base_fee_per_gas.to_bytes_le());
|
|
||||||
let tip = U256::from(10_u64.pow(9));
|
|
||||||
Ok(base_fee + tip)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_priority_fee(&self) -> Result<U256> {
|
pub async fn get_priority_fee(&self) -> Result<U256> {
|
||||||
let tip = U256::from(10_u64.pow(9));
|
self.node.lock().await.get_priority_fee()
|
||||||
Ok(tip)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_block_number(&self) -> Result<u64> {
|
pub async fn get_block_number(&self) -> Result<u64> {
|
||||||
let payload = self.get_payload(&None)?;
|
self.node.lock().await.get_block_number()
|
||||||
Ok(payload.block_number)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_block_by_number(&self, block: &Option<u64>) -> Result<ExecutionBlock> {
|
pub async fn get_block_by_number(&self, block: &Option<u64>) -> Result<ExecutionBlock> {
|
||||||
let payload = self.get_payload(block)?;
|
self.node.lock().await.get_block_by_number(block)
|
||||||
self.execution.get_block(&payload)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_block_by_hash(&self, hash: &Vec<u8>) -> Result<ExecutionBlock> {
|
pub async fn get_block_by_hash(&self, hash: &Vec<u8>) -> Result<ExecutionBlock> {
|
||||||
let block = self.block_hashes.get(hash);
|
self.node.lock().await.get_block_by_hash(hash)
|
||||||
let payload = self.get_payload(&block.cloned())?;
|
|
||||||
self.execution.get_block(&payload)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chain_id(&self) -> u64 {
|
pub async fn chain_id(&self) -> u64 {
|
||||||
self.config.general.chain_id
|
self.node.lock().await.chain_id()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_header(&self) -> &Header {
|
pub async fn get_header(&self) -> Header {
|
||||||
self.consensus.get_header()
|
self.node.lock().await.get_header().clone()
|
||||||
}
|
|
||||||
|
|
||||||
fn get_payload(&self, block: &Option<u64>) -> Result<ExecutionPayload> {
|
|
||||||
match block {
|
|
||||||
Some(block) => {
|
|
||||||
let payload = self.payloads.get(block);
|
|
||||||
match payload {
|
|
||||||
Some(payload) => Ok(payload.clone()),
|
|
||||||
None => Err(eyre::eyre!("Block Not Found")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let payload = self.payloads.get(&self.block_head);
|
|
||||||
match payload {
|
|
||||||
Some(payload) => Ok(payload.clone()),
|
|
||||||
None => Err(eyre::eyre!("Block Not Found")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,3 +2,5 @@ mod client;
|
||||||
pub use crate::client::*;
|
pub use crate::client::*;
|
||||||
|
|
||||||
pub mod rpc;
|
pub mod rpc;
|
||||||
|
|
||||||
|
mod node;
|
||||||
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ethers::prelude::{Address, U256};
|
||||||
|
use ethers::types::{Transaction, TransactionReceipt, H256};
|
||||||
|
use eyre::Result;
|
||||||
|
|
||||||
|
use config::Config;
|
||||||
|
use consensus::rpc::nimbus_rpc::NimbusRpc;
|
||||||
|
use consensus::types::{ExecutionPayload, Header};
|
||||||
|
use consensus::ConsensusClient;
|
||||||
|
use execution::evm::Evm;
|
||||||
|
use execution::rpc::http_rpc::HttpRpc;
|
||||||
|
use execution::types::{CallOpts, ExecutionBlock};
|
||||||
|
use execution::ExecutionClient;
|
||||||
|
|
||||||
|
pub struct Node {
|
||||||
|
consensus: ConsensusClient<NimbusRpc>,
|
||||||
|
execution: ExecutionClient<HttpRpc>,
|
||||||
|
config: Arc<Config>,
|
||||||
|
payloads: HashMap<u64, ExecutionPayload>,
|
||||||
|
block_hashes: HashMap<Vec<u8>, u64>,
|
||||||
|
block_head: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node {
|
||||||
|
pub async fn new(config: Arc<Config>) -> Result<Self> {
|
||||||
|
let consensus_rpc = &config.general.consensus_rpc;
|
||||||
|
let checkpoint_hash = &config.general.checkpoint;
|
||||||
|
let execution_rpc = &config.general.execution_rpc;
|
||||||
|
|
||||||
|
let consensus =
|
||||||
|
ConsensusClient::new(consensus_rpc, checkpoint_hash, config.clone()).await?;
|
||||||
|
let execution = ExecutionClient::new(execution_rpc)?;
|
||||||
|
|
||||||
|
let payloads = HashMap::new();
|
||||||
|
let block_hashes = HashMap::new();
|
||||||
|
|
||||||
|
Ok(Node {
|
||||||
|
consensus,
|
||||||
|
execution,
|
||||||
|
config,
|
||||||
|
payloads,
|
||||||
|
block_hashes,
|
||||||
|
block_head: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn sync(&mut self) -> Result<()> {
|
||||||
|
self.consensus.sync().await?;
|
||||||
|
|
||||||
|
let head = self.consensus.get_header();
|
||||||
|
let payload = self
|
||||||
|
.consensus
|
||||||
|
.get_execution_payload(&Some(head.slot))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
self.block_head = payload.block_number;
|
||||||
|
self.block_hashes
|
||||||
|
.insert(payload.block_hash.to_vec(), payload.block_number);
|
||||||
|
self.payloads.insert(payload.block_number, payload);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn advance(&mut self) -> Result<()> {
|
||||||
|
self.consensus.advance().await?;
|
||||||
|
|
||||||
|
let head = self.consensus.get_header();
|
||||||
|
let payload = self
|
||||||
|
.consensus
|
||||||
|
.get_execution_payload(&Some(head.slot))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
self.block_head = payload.block_number;
|
||||||
|
self.block_hashes
|
||||||
|
.insert(payload.block_hash.to_vec(), payload.block_number);
|
||||||
|
self.payloads.insert(payload.block_number, payload);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call(&self, opts: &CallOpts, block: &Option<u64>) -> Result<Vec<u8>> {
|
||||||
|
let payload = self.get_payload(block)?;
|
||||||
|
let mut evm = Evm::new(self.execution.clone(), payload, self.chain_id());
|
||||||
|
evm.call(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn estimate_gas(&self, opts: &CallOpts) -> Result<u64> {
|
||||||
|
let payload = self.get_payload(&None)?;
|
||||||
|
let mut evm = Evm::new(self.execution.clone(), payload, self.chain_id());
|
||||||
|
evm.estimate_gas(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_balance(&self, address: &Address, block: &Option<u64>) -> Result<U256> {
|
||||||
|
let payload = self.get_payload(block)?;
|
||||||
|
let account = self.execution.get_account(&address, None, &payload).await?;
|
||||||
|
Ok(account.balance)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_nonce(&self, address: &Address, block: &Option<u64>) -> Result<u64> {
|
||||||
|
let payload = self.get_payload(block)?;
|
||||||
|
let account = self.execution.get_account(&address, None, &payload).await?;
|
||||||
|
Ok(account.nonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_code(&self, address: &Address, block: &Option<u64>) -> Result<Vec<u8>> {
|
||||||
|
let payload = self.get_payload(block)?;
|
||||||
|
self.execution.get_code(&address, &payload).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_storage_at(&self, address: &Address, slot: H256) -> Result<U256> {
|
||||||
|
let payload = self.get_payload(&None)?;
|
||||||
|
let account = self
|
||||||
|
.execution
|
||||||
|
.get_account(address, Some(&[slot]), &payload)
|
||||||
|
.await?;
|
||||||
|
let value = account.slots.get(&slot);
|
||||||
|
match value {
|
||||||
|
Some(value) => Ok(*value),
|
||||||
|
None => Err(eyre::eyre!("Slot Not Found")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_raw_transaction(&self, bytes: &Vec<u8>) -> Result<H256> {
|
||||||
|
self.execution.send_raw_transaction(bytes).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_transaction_receipt(
|
||||||
|
&self,
|
||||||
|
tx_hash: &H256,
|
||||||
|
) -> Result<Option<TransactionReceipt>> {
|
||||||
|
self.execution
|
||||||
|
.get_transaction_receipt(tx_hash, &self.payloads)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_transaction_by_hash(&self, tx_hash: &H256) -> Result<Option<Transaction>> {
|
||||||
|
self.execution
|
||||||
|
.get_transaction(tx_hash, &self.payloads)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_gas_price(&self) -> Result<U256> {
|
||||||
|
let payload = self.get_payload(&None)?;
|
||||||
|
let base_fee = U256::from_little_endian(&payload.base_fee_per_gas.to_bytes_le());
|
||||||
|
let tip = U256::from(10_u64.pow(9));
|
||||||
|
Ok(base_fee + tip)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_priority_fee(&self) -> Result<U256> {
|
||||||
|
let tip = U256::from(10_u64.pow(9));
|
||||||
|
Ok(tip)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_block_number(&self) -> Result<u64> {
|
||||||
|
let payload = self.get_payload(&None)?;
|
||||||
|
Ok(payload.block_number)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_block_by_number(&self, block: &Option<u64>) -> Result<ExecutionBlock> {
|
||||||
|
let payload = self.get_payload(block)?;
|
||||||
|
self.execution.get_block(&payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_block_by_hash(&self, hash: &Vec<u8>) -> Result<ExecutionBlock> {
|
||||||
|
let block = self.block_hashes.get(hash);
|
||||||
|
let payload = self.get_payload(&block.cloned())?;
|
||||||
|
self.execution.get_block(&payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn chain_id(&self) -> u64 {
|
||||||
|
self.config.general.chain_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_header(&self) -> &Header {
|
||||||
|
self.consensus.get_header()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_payload(&self, block: &Option<u64>) -> Result<ExecutionPayload> {
|
||||||
|
match block {
|
||||||
|
Some(block) => {
|
||||||
|
let payload = self.payloads.get(block);
|
||||||
|
match payload {
|
||||||
|
Some(payload) => Ok(payload.clone()),
|
||||||
|
None => Err(eyre::eyre!("Block Not Found")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let payload = self.payloads.get(&self.block_head);
|
||||||
|
match payload {
|
||||||
|
Some(payload) => Ok(payload.clone()),
|
||||||
|
None => Err(eyre::eyre!("Block Not Found")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ use ethers::{
|
||||||
types::{Address, Transaction, TransactionReceipt, H256},
|
types::{Address, Transaction, TransactionReceipt, H256},
|
||||||
};
|
};
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
use log::{error, info};
|
use log::{info, warn};
|
||||||
use std::{fmt::Display, net::SocketAddr, str::FromStr, sync::Arc};
|
use std::{fmt::Display, net::SocketAddr, str::FromStr, sync::Arc};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
@ -13,20 +13,21 @@ use jsonrpsee::{
|
||||||
proc_macros::rpc,
|
proc_macros::rpc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Client;
|
use crate::node::Node;
|
||||||
|
|
||||||
use common::utils::{hex_str_to_bytes, u64_to_hex_string};
|
use common::utils::{hex_str_to_bytes, u64_to_hex_string};
|
||||||
use execution::types::{CallOpts, ExecutionBlock};
|
use execution::types::{CallOpts, ExecutionBlock};
|
||||||
|
|
||||||
pub struct Rpc {
|
pub struct Rpc {
|
||||||
client: Arc<Mutex<Client>>,
|
node: Arc<Mutex<Node>>,
|
||||||
handle: Option<HttpServerHandle>,
|
handle: Option<HttpServerHandle>,
|
||||||
port: u16,
|
port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rpc {
|
impl Rpc {
|
||||||
pub fn new(client: Arc<Mutex<Client>>, port: u16) -> Self {
|
pub fn new(node: Arc<Mutex<Node>>, port: u16) -> Self {
|
||||||
Rpc {
|
Rpc {
|
||||||
client,
|
node,
|
||||||
handle: None,
|
handle: None,
|
||||||
port,
|
port,
|
||||||
}
|
}
|
||||||
|
@ -34,7 +35,7 @@ impl Rpc {
|
||||||
|
|
||||||
pub async fn start(&mut self) -> Result<SocketAddr> {
|
pub async fn start(&mut self) -> Result<SocketAddr> {
|
||||||
let rpc_inner = RpcInner {
|
let rpc_inner = RpcInner {
|
||||||
client: self.client.clone(),
|
node: self.node.clone(),
|
||||||
port: self.port,
|
port: self.port,
|
||||||
};
|
};
|
||||||
let (handle, addr) = start(rpc_inner).await?;
|
let (handle, addr) = start(rpc_inner).await?;
|
||||||
|
@ -86,7 +87,7 @@ trait NetRpc {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct RpcInner {
|
struct RpcInner {
|
||||||
client: Arc<Mutex<Client>>,
|
node: Arc<Mutex<Node>>,
|
||||||
port: u16,
|
port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,8 +96,8 @@ impl EthRpcServer for RpcInner {
|
||||||
async fn get_balance(&self, address: &str, block: &str) -> Result<String, Error> {
|
async fn get_balance(&self, address: &str, block: &str) -> Result<String, Error> {
|
||||||
let block = convert_err(decode_block(block))?;
|
let block = convert_err(decode_block(block))?;
|
||||||
let address = convert_err(Address::from_str(address))?;
|
let address = convert_err(Address::from_str(address))?;
|
||||||
let client = self.client.lock().await;
|
let node = self.node.lock().await;
|
||||||
let balance = convert_err(client.get_balance(&address, &block).await)?;
|
let balance = convert_err(node.get_balance(&address, &block).await)?;
|
||||||
|
|
||||||
Ok(balance.encode_hex())
|
Ok(balance.encode_hex())
|
||||||
}
|
}
|
||||||
|
@ -104,8 +105,8 @@ impl EthRpcServer for RpcInner {
|
||||||
async fn get_transaction_count(&self, address: &str, block: &str) -> Result<String, Error> {
|
async fn get_transaction_count(&self, address: &str, block: &str) -> Result<String, Error> {
|
||||||
let block = convert_err(decode_block(block))?;
|
let block = convert_err(decode_block(block))?;
|
||||||
let address = convert_err(Address::from_str(address))?;
|
let address = convert_err(Address::from_str(address))?;
|
||||||
let client = self.client.lock().await;
|
let node = self.node.lock().await;
|
||||||
let nonce = convert_err(client.get_nonce(&address, &block).await)?;
|
let nonce = convert_err(node.get_nonce(&address, &block).await)?;
|
||||||
|
|
||||||
Ok(nonce.encode_hex())
|
Ok(nonce.encode_hex())
|
||||||
}
|
}
|
||||||
|
@ -113,48 +114,48 @@ impl EthRpcServer for RpcInner {
|
||||||
async fn get_code(&self, address: &str, block: &str) -> Result<String, Error> {
|
async fn get_code(&self, address: &str, block: &str) -> Result<String, Error> {
|
||||||
let block = convert_err(decode_block(block))?;
|
let block = convert_err(decode_block(block))?;
|
||||||
let address = convert_err(Address::from_str(address))?;
|
let address = convert_err(Address::from_str(address))?;
|
||||||
let client = self.client.lock().await;
|
let node = self.node.lock().await;
|
||||||
let code = convert_err(client.get_code(&address, &block).await)?;
|
let code = convert_err(node.get_code(&address, &block).await)?;
|
||||||
|
|
||||||
Ok(hex::encode(code))
|
Ok(hex::encode(code))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn call(&self, opts: CallOpts, block: &str) -> Result<String, Error> {
|
async fn call(&self, opts: CallOpts, block: &str) -> Result<String, Error> {
|
||||||
let block = convert_err(decode_block(block))?;
|
let block = convert_err(decode_block(block))?;
|
||||||
let client = self.client.lock().await;
|
let node = self.node.lock().await;
|
||||||
let res = convert_err(client.call(&opts, &block))?;
|
let res = convert_err(node.call(&opts, &block))?;
|
||||||
|
|
||||||
Ok(format!("0x{}", hex::encode(res)))
|
Ok(format!("0x{}", hex::encode(res)))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn estimate_gas(&self, opts: CallOpts) -> Result<String, Error> {
|
async fn estimate_gas(&self, opts: CallOpts) -> Result<String, Error> {
|
||||||
let client = self.client.lock().await;
|
let node = self.node.lock().await;
|
||||||
let gas = convert_err(client.estimate_gas(&opts))?;
|
let gas = convert_err(node.estimate_gas(&opts))?;
|
||||||
|
|
||||||
Ok(u64_to_hex_string(gas))
|
Ok(u64_to_hex_string(gas))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn chain_id(&self) -> Result<String, Error> {
|
async fn chain_id(&self) -> Result<String, Error> {
|
||||||
let client = self.client.lock().await;
|
let node = self.node.lock().await;
|
||||||
let id = client.chain_id();
|
let id = node.chain_id();
|
||||||
Ok(u64_to_hex_string(id))
|
Ok(u64_to_hex_string(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn gas_price(&self) -> Result<String, Error> {
|
async fn gas_price(&self) -> Result<String, Error> {
|
||||||
let client = self.client.lock().await;
|
let node = self.node.lock().await;
|
||||||
let gas_price = convert_err(client.get_gas_price())?;
|
let gas_price = convert_err(node.get_gas_price())?;
|
||||||
Ok(gas_price.encode_hex())
|
Ok(gas_price.encode_hex())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn max_priority_fee_per_gas(&self) -> Result<String, Error> {
|
async fn max_priority_fee_per_gas(&self) -> Result<String, Error> {
|
||||||
let client = self.client.lock().await;
|
let node = self.node.lock().await;
|
||||||
let tip = convert_err(client.get_priority_fee())?;
|
let tip = convert_err(node.get_priority_fee())?;
|
||||||
Ok(tip.encode_hex())
|
Ok(tip.encode_hex())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn block_number(&self) -> Result<String, Error> {
|
async fn block_number(&self) -> Result<String, Error> {
|
||||||
let client = self.client.lock().await;
|
let node = self.node.lock().await;
|
||||||
let num = convert_err(client.get_block_number())?;
|
let num = convert_err(node.get_block_number())?;
|
||||||
Ok(u64_to_hex_string(num))
|
Ok(u64_to_hex_string(num))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,31 +165,31 @@ impl EthRpcServer for RpcInner {
|
||||||
_full_tx: bool,
|
_full_tx: bool,
|
||||||
) -> Result<ExecutionBlock, Error> {
|
) -> Result<ExecutionBlock, Error> {
|
||||||
let block = convert_err(decode_block(block))?;
|
let block = convert_err(decode_block(block))?;
|
||||||
let client = self.client.lock().await;
|
let node = self.node.lock().await;
|
||||||
let block = convert_err(client.get_block_by_number(&block))?;
|
let block = convert_err(node.get_block_by_number(&block))?;
|
||||||
|
|
||||||
Ok(block)
|
Ok(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_block_by_hash(&self, hash: &str, _full_tx: bool) -> Result<ExecutionBlock, Error> {
|
async fn get_block_by_hash(&self, hash: &str, _full_tx: bool) -> Result<ExecutionBlock, Error> {
|
||||||
let hash = convert_err(hex_str_to_bytes(hash))?;
|
let hash = convert_err(hex_str_to_bytes(hash))?;
|
||||||
let client = self.client.lock().await;
|
let node = self.node.lock().await;
|
||||||
let block = convert_err(client.get_block_by_hash(&hash))?;
|
let block = convert_err(node.get_block_by_hash(&hash))?;
|
||||||
|
|
||||||
Ok(block)
|
Ok(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_raw_transaction(&self, bytes: &str) -> Result<String, Error> {
|
async fn send_raw_transaction(&self, bytes: &str) -> Result<String, Error> {
|
||||||
let client = self.client.lock().await;
|
let node = self.node.lock().await;
|
||||||
let bytes = convert_err(hex_str_to_bytes(bytes))?;
|
let bytes = convert_err(hex_str_to_bytes(bytes))?;
|
||||||
let tx_hash = convert_err(client.send_raw_transaction(&bytes).await)?;
|
let tx_hash = convert_err(node.send_raw_transaction(&bytes).await)?;
|
||||||
Ok(hex::encode(tx_hash))
|
Ok(hex::encode(tx_hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_transaction_receipt(&self, hash: &str) -> Result<TransactionReceipt, Error> {
|
async fn get_transaction_receipt(&self, hash: &str) -> Result<TransactionReceipt, Error> {
|
||||||
let client = self.client.lock().await;
|
let node = self.node.lock().await;
|
||||||
let hash = H256::from_slice(&convert_err(hex_str_to_bytes(hash))?);
|
let hash = H256::from_slice(&convert_err(hex_str_to_bytes(hash))?);
|
||||||
let receipt = convert_err(client.get_transaction_receipt(&hash).await)?;
|
let receipt = convert_err(node.get_transaction_receipt(&hash).await)?;
|
||||||
|
|
||||||
match receipt {
|
match receipt {
|
||||||
Some(receipt) => Ok(receipt),
|
Some(receipt) => Ok(receipt),
|
||||||
|
@ -197,9 +198,9 @@ impl EthRpcServer for RpcInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_transaction_by_hash(&self, hash: &str) -> Result<Transaction, Error> {
|
async fn get_transaction_by_hash(&self, hash: &str) -> Result<Transaction, Error> {
|
||||||
let client = self.client.lock().await;
|
let node = self.node.lock().await;
|
||||||
let hash = H256::from_slice(&convert_err(hex_str_to_bytes(hash))?);
|
let hash = H256::from_slice(&convert_err(hex_str_to_bytes(hash))?);
|
||||||
let tx = convert_err(client.get_transaction_by_hash(&hash).await)?;
|
let tx = convert_err(node.get_transaction_by_hash(&hash).await)?;
|
||||||
|
|
||||||
match tx {
|
match tx {
|
||||||
Some(tx) => Ok(tx),
|
Some(tx) => Ok(tx),
|
||||||
|
@ -211,8 +212,8 @@ impl EthRpcServer for RpcInner {
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl NetRpcServer for RpcInner {
|
impl NetRpcServer for RpcInner {
|
||||||
async fn version(&self) -> Result<String, Error> {
|
async fn version(&self) -> Result<String, Error> {
|
||||||
let client = self.client.lock().await;
|
let node = self.node.lock().await;
|
||||||
Ok(client.chain_id().to_string())
|
Ok(node.chain_id().to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +237,7 @@ async fn start(rpc: RpcInner) -> Result<(HttpServerHandle, SocketAddr)> {
|
||||||
|
|
||||||
fn convert_err<T, E: Display>(res: Result<T, E>) -> Result<T, Error> {
|
fn convert_err<T, E: Display>(res: Result<T, E>) -> Result<T, Error> {
|
||||||
res.map_err(|err| {
|
res.map_err(|err| {
|
||||||
error!("{}", err);
|
warn!("{}", err);
|
||||||
Error::Custom(err.to_string())
|
Error::Custom(err.to_string())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ genesis_root = "0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43e
|
||||||
checkpoint = "0x172128eadf1da46467f4d6a822206698e2d3f957af117dd650954780d680dc99"
|
checkpoint = "0x172128eadf1da46467f4d6a822206698e2d3f957af117dd650954780d680dc99"
|
||||||
consensus_rpc = "http://testing.prater.beacon-api.nimbus.team"
|
consensus_rpc = "http://testing.prater.beacon-api.nimbus.team"
|
||||||
execution_rpc = "https://eth-goerli.g.alchemy.com:443/v2/o_8Qa9kgwDPf9G8sroyQ-uQtyhyWa3ao"
|
execution_rpc = "https://eth-goerli.g.alchemy.com:443/v2/o_8Qa9kgwDPf9G8sroyQ-uQtyhyWa3ao"
|
||||||
|
rpc_port = 8545
|
||||||
|
|
||||||
[forks]
|
[forks]
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ pub struct General {
|
||||||
pub checkpoint: Vec<u8>,
|
pub checkpoint: Vec<u8>,
|
||||||
pub consensus_rpc: String,
|
pub consensus_rpc: String,
|
||||||
pub execution_rpc: String,
|
pub execution_rpc: String,
|
||||||
|
pub rpc_port: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
|
|
|
@ -19,6 +19,7 @@ pub fn goerli() -> Config {
|
||||||
execution_rpc:
|
execution_rpc:
|
||||||
"https://eth-goerli.g.alchemy.com:443/v2/o_8Qa9kgwDPf9G8sroyQ-uQtyhyWa3ao"
|
"https://eth-goerli.g.alchemy.com:443/v2/o_8Qa9kgwDPf9G8sroyQ-uQtyhyWa3ao"
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|
rpc_port: Some(8545),
|
||||||
},
|
},
|
||||||
forks: Forks {
|
forks: Forks {
|
||||||
genesis: Fork {
|
genesis: Fork {
|
||||||
|
|
Loading…
Reference in New Issue