stash websocket progress
This commit is contained in:
parent
f28483dfd7
commit
81e5a08828
|
@ -0,0 +1,197 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use config::{Network, Config};
|
||||||
|
use execution::rpc::ExecutionRpc;
|
||||||
|
|
||||||
|
use crate::{database::FileDB, Client};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ClientBuilder {
|
||||||
|
pub network: Option<Network>,
|
||||||
|
pub consensus_rpc: Option<String>,
|
||||||
|
pub execution_rpc: Option<String>,
|
||||||
|
pub checkpoint: Option<Vec<u8>>,
|
||||||
|
pub rpc_port: Option<u16>,
|
||||||
|
pub data_dir: Option<PathBuf>,
|
||||||
|
pub config: Option<Config>,
|
||||||
|
pub fallback: Option<String>,
|
||||||
|
pub load_external_fallback: bool,
|
||||||
|
pub with_ws: bool,
|
||||||
|
pub with_http: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientBuilder {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default().with_http(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn network(mut self, network: Network) -> Self {
|
||||||
|
self.network = Some(network);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn consensus_rpc(mut self, consensus_rpc: &str) -> Self {
|
||||||
|
self.consensus_rpc = Some(consensus_rpc.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execution_rpc(mut self, execution_rpc: &str) -> Self {
|
||||||
|
self.execution_rpc = Some(execution_rpc.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn checkpoint(mut self, checkpoint: &str) -> Self {
|
||||||
|
let checkpoint = hex::decode(checkpoint.strip_prefix("0x").unwrap_or(checkpoint))
|
||||||
|
.expect("cannot parse checkpoint");
|
||||||
|
self.checkpoint = Some(checkpoint);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables the client to serve a websocket connection.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```rust
|
||||||
|
/// let mut client_builder = client::ClientBuilder::new().with_ws(true);
|
||||||
|
/// assert_eq!(client_builder.with_ws, true);
|
||||||
|
/// client_builder = client_builder.with_ws(false);
|
||||||
|
/// assert_eq!(client_builder.with_ws, false);
|
||||||
|
/// ```
|
||||||
|
pub fn with_ws(mut self, option: bool) -> Self {
|
||||||
|
self.with_ws = option;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables the client to serve an http connection (enabled by default).
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```rust
|
||||||
|
/// let mut client_builder = client::ClientBuilder::new();
|
||||||
|
/// assert_eq!(client_builder.with_http, true);
|
||||||
|
/// client_builder = client_builder.with_http(false);
|
||||||
|
/// assert_eq!(client_builder.with_http, false);
|
||||||
|
/// ```
|
||||||
|
pub fn with_http(mut self, option: bool) -> Self {
|
||||||
|
self.with_http = option;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rpc_port(mut self, port: u16) -> Self {
|
||||||
|
self.rpc_port = Some(port);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data_dir(mut self, data_dir: PathBuf) -> Self {
|
||||||
|
self.data_dir = Some(data_dir);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn config(mut self, config: Config) -> Self {
|
||||||
|
self.config = Some(config);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fallback(mut self, fallback: &str) -> Self {
|
||||||
|
self.fallback = Some(fallback.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_external_fallback(mut self) -> Self {
|
||||||
|
self.load_external_fallback = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> eyre::Result<Client<FileDB, _>> {
|
||||||
|
let base_config = if let Some(network) = self.network {
|
||||||
|
network.to_base_config()
|
||||||
|
} else {
|
||||||
|
let config = self
|
||||||
|
.config
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(eyre::eyre!("missing network config"))?;
|
||||||
|
config.to_base_config()
|
||||||
|
};
|
||||||
|
|
||||||
|
let consensus_rpc = self.consensus_rpc.unwrap_or_else(|| {
|
||||||
|
self.config
|
||||||
|
.as_ref()
|
||||||
|
.expect("missing consensus rpc")
|
||||||
|
.consensus_rpc
|
||||||
|
.clone()
|
||||||
|
});
|
||||||
|
|
||||||
|
let execution_rpc = self.execution_rpc.unwrap_or_else(|| {
|
||||||
|
self.config
|
||||||
|
.as_ref()
|
||||||
|
.expect("missing execution rpc")
|
||||||
|
.execution_rpc
|
||||||
|
.clone()
|
||||||
|
});
|
||||||
|
|
||||||
|
let checkpoint = if let Some(checkpoint) = self.checkpoint {
|
||||||
|
checkpoint
|
||||||
|
} else if let Some(config) = &self.config {
|
||||||
|
config.checkpoint.clone()
|
||||||
|
} else {
|
||||||
|
base_config.checkpoint
|
||||||
|
};
|
||||||
|
|
||||||
|
let rpc_port = if self.rpc_port.is_some() {
|
||||||
|
self.rpc_port
|
||||||
|
} else if let Some(config) = &self.config {
|
||||||
|
config.rpc_port
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let data_dir = if self.data_dir.is_some() {
|
||||||
|
self.data_dir
|
||||||
|
} else if let Some(config) = &self.config {
|
||||||
|
config.data_dir.clone()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let fallback = if self.fallback.is_some() {
|
||||||
|
self.fallback
|
||||||
|
} else if let Some(config) = &self.config {
|
||||||
|
config.fallback.clone()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let load_external_fallback = if let Some(config) = &self.config {
|
||||||
|
self.load_external_fallback || config.load_external_fallback
|
||||||
|
} else {
|
||||||
|
self.load_external_fallback
|
||||||
|
};
|
||||||
|
|
||||||
|
let with_ws = if let Some(config) = &self.config {
|
||||||
|
self.with_ws || config.with_ws
|
||||||
|
} else {
|
||||||
|
self.with_ws
|
||||||
|
};
|
||||||
|
|
||||||
|
let with_http = if let Some(config) = &self.config {
|
||||||
|
self.with_http || config.with_http
|
||||||
|
} else {
|
||||||
|
self.with_http
|
||||||
|
};
|
||||||
|
|
||||||
|
let config = Config {
|
||||||
|
consensus_rpc,
|
||||||
|
execution_rpc,
|
||||||
|
checkpoint,
|
||||||
|
rpc_port,
|
||||||
|
data_dir,
|
||||||
|
chain: base_config.chain,
|
||||||
|
forks: base_config.forks,
|
||||||
|
max_checkpoint_age: base_config.max_checkpoint_age,
|
||||||
|
fallback,
|
||||||
|
load_external_fallback,
|
||||||
|
with_ws,
|
||||||
|
with_http,
|
||||||
|
};
|
||||||
|
|
||||||
|
Client::new(config)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +1,13 @@
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use config::networks::Network;
|
use config::networks::Network;
|
||||||
use ethers::prelude::{Address, U256};
|
use ethers::prelude::{Address, U256};
|
||||||
use ethers::types::{Filter, Log, Transaction, TransactionReceipt, H256};
|
use ethers::types::{Filter, Log, Transaction, TransactionReceipt, H256};
|
||||||
use eyre::{eyre, Result};
|
|
||||||
|
|
||||||
use common::types::BlockTag;
|
use common::types::BlockTag;
|
||||||
use config::{CheckpointFallback, Config};
|
use config::{CheckpointFallback, Config};
|
||||||
use consensus::{types::Header, ConsensusClient};
|
use consensus::{types::Header, ConsensusClient};
|
||||||
|
use execution::rpc::ExecutionRpc;
|
||||||
use execution::types::{CallOpts, ExecutionBlock};
|
use execution::types::{CallOpts, ExecutionBlock};
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use tokio::spawn;
|
use tokio::spawn;
|
||||||
|
@ -19,207 +18,16 @@ use crate::database::{Database, FileDB};
|
||||||
use crate::node::Node;
|
use crate::node::Node;
|
||||||
use crate::rpc::Rpc;
|
use crate::rpc::Rpc;
|
||||||
|
|
||||||
#[derive(Default)]
|
pub struct Client<DB: Database, R: ExecutionRpc> {
|
||||||
pub struct ClientBuilder {
|
node: Arc<RwLock<Node<R>>>,
|
||||||
pub network: Option<Network>,
|
rpc: Option<Rpc<R>>,
|
||||||
pub consensus_rpc: Option<String>,
|
|
||||||
pub execution_rpc: Option<String>,
|
|
||||||
pub checkpoint: Option<Vec<u8>>,
|
|
||||||
pub rpc_port: Option<u16>,
|
|
||||||
pub data_dir: Option<PathBuf>,
|
|
||||||
pub config: Option<Config>,
|
|
||||||
pub fallback: Option<String>,
|
|
||||||
pub load_external_fallback: bool,
|
|
||||||
pub with_ws: bool,
|
|
||||||
pub with_http: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ClientBuilder {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default().with_http(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn network(mut self, network: Network) -> Self {
|
|
||||||
self.network = Some(network);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn consensus_rpc(mut self, consensus_rpc: &str) -> Self {
|
|
||||||
self.consensus_rpc = Some(consensus_rpc.to_string());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execution_rpc(mut self, execution_rpc: &str) -> Self {
|
|
||||||
self.execution_rpc = Some(execution_rpc.to_string());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn checkpoint(mut self, checkpoint: &str) -> Self {
|
|
||||||
let checkpoint = hex::decode(checkpoint.strip_prefix("0x").unwrap_or(checkpoint))
|
|
||||||
.expect("cannot parse checkpoint");
|
|
||||||
self.checkpoint = Some(checkpoint);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enables the client to serve a websocket connection.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```rust
|
|
||||||
/// let mut client_builder = client::ClientBuilder::new().with_ws(true);
|
|
||||||
/// assert_eq!(client_builder.with_ws, true);
|
|
||||||
/// client_builder = client_builder.with_ws(false);
|
|
||||||
/// assert_eq!(client_builder.with_ws, false);
|
|
||||||
/// ```
|
|
||||||
pub fn with_ws(mut self, option: bool) -> Self {
|
|
||||||
self.with_ws = option;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enables the client to serve an http connection (enabled by default).
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```rust
|
|
||||||
/// let mut client_builder = client::ClientBuilder::new();
|
|
||||||
/// assert_eq!(client_builder.with_http, true);
|
|
||||||
/// client_builder = client_builder.with_http(false);
|
|
||||||
/// assert_eq!(client_builder.with_http, false);
|
|
||||||
/// ```
|
|
||||||
pub fn with_http(mut self, option: bool) -> Self {
|
|
||||||
self.with_http = option;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rpc_port(mut self, port: u16) -> Self {
|
|
||||||
self.rpc_port = Some(port);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn data_dir(mut self, data_dir: PathBuf) -> Self {
|
|
||||||
self.data_dir = Some(data_dir);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn config(mut self, config: Config) -> Self {
|
|
||||||
self.config = Some(config);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fallback(mut self, fallback: &str) -> Self {
|
|
||||||
self.fallback = Some(fallback.to_string());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_external_fallback(mut self) -> Self {
|
|
||||||
self.load_external_fallback = true;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(self) -> Result<Client<FileDB>> {
|
|
||||||
let base_config = if let Some(network) = self.network {
|
|
||||||
network.to_base_config()
|
|
||||||
} else {
|
|
||||||
let config = self
|
|
||||||
.config
|
|
||||||
.as_ref()
|
|
||||||
.ok_or(eyre!("missing network config"))?;
|
|
||||||
config.to_base_config()
|
|
||||||
};
|
|
||||||
|
|
||||||
let consensus_rpc = self.consensus_rpc.unwrap_or_else(|| {
|
|
||||||
self.config
|
|
||||||
.as_ref()
|
|
||||||
.expect("missing consensus rpc")
|
|
||||||
.consensus_rpc
|
|
||||||
.clone()
|
|
||||||
});
|
|
||||||
|
|
||||||
let execution_rpc = self.execution_rpc.unwrap_or_else(|| {
|
|
||||||
self.config
|
|
||||||
.as_ref()
|
|
||||||
.expect("missing execution rpc")
|
|
||||||
.execution_rpc
|
|
||||||
.clone()
|
|
||||||
});
|
|
||||||
|
|
||||||
let checkpoint = if let Some(checkpoint) = self.checkpoint {
|
|
||||||
checkpoint
|
|
||||||
} else if let Some(config) = &self.config {
|
|
||||||
config.checkpoint.clone()
|
|
||||||
} else {
|
|
||||||
base_config.checkpoint
|
|
||||||
};
|
|
||||||
|
|
||||||
let rpc_port = if self.rpc_port.is_some() {
|
|
||||||
self.rpc_port
|
|
||||||
} else if let Some(config) = &self.config {
|
|
||||||
config.rpc_port
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let data_dir = if self.data_dir.is_some() {
|
|
||||||
self.data_dir
|
|
||||||
} else if let Some(config) = &self.config {
|
|
||||||
config.data_dir.clone()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let fallback = if self.fallback.is_some() {
|
|
||||||
self.fallback
|
|
||||||
} else if let Some(config) = &self.config {
|
|
||||||
config.fallback.clone()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let load_external_fallback = if let Some(config) = &self.config {
|
|
||||||
self.load_external_fallback || config.load_external_fallback
|
|
||||||
} else {
|
|
||||||
self.load_external_fallback
|
|
||||||
};
|
|
||||||
|
|
||||||
let with_ws = if let Some(config) = &self.config {
|
|
||||||
self.with_ws || config.with_ws
|
|
||||||
} else {
|
|
||||||
self.with_ws
|
|
||||||
};
|
|
||||||
|
|
||||||
let with_http = if let Some(config) = &self.config {
|
|
||||||
self.with_http || config.with_http
|
|
||||||
} else {
|
|
||||||
self.with_http
|
|
||||||
};
|
|
||||||
|
|
||||||
let config = Config {
|
|
||||||
consensus_rpc,
|
|
||||||
execution_rpc,
|
|
||||||
checkpoint,
|
|
||||||
rpc_port,
|
|
||||||
data_dir,
|
|
||||||
chain: base_config.chain,
|
|
||||||
forks: base_config.forks,
|
|
||||||
max_checkpoint_age: base_config.max_checkpoint_age,
|
|
||||||
fallback,
|
|
||||||
load_external_fallback,
|
|
||||||
with_ws,
|
|
||||||
with_http,
|
|
||||||
};
|
|
||||||
|
|
||||||
Client::new(config)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Client<DB: Database> {
|
|
||||||
node: Arc<RwLock<Node>>,
|
|
||||||
rpc: Option<Rpc>,
|
|
||||||
db: Option<DB>,
|
db: Option<DB>,
|
||||||
fallback: Option<String>,
|
fallback: Option<String>,
|
||||||
load_external_fallback: bool,
|
load_external_fallback: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client<FileDB> {
|
impl<R> Client<FileDB, R> where R: ExecutionRpc {
|
||||||
fn new(config: Config) -> Result<Self> {
|
pub fn new(config: Config) -> eyre::Result<Self> {
|
||||||
let config = Arc::new(config);
|
let config = Arc::new(config);
|
||||||
let node = Node::new(config.clone())?;
|
let node = Node::new(config.clone())?;
|
||||||
let node = Arc::new(RwLock::new(node));
|
let node = Arc::new(RwLock::new(node));
|
||||||
|
@ -241,8 +49,8 @@ impl Client<FileDB> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DB: Database> Client<DB> {
|
impl<DB: Database, R: ExecutionRpc> Client<DB, R> {
|
||||||
pub async fn start(&mut self) -> Result<()> {
|
pub async fn start(&mut self) -> eyre::Result<()> {
|
||||||
if let Some(rpc) = &mut self.rpc {
|
if let Some(rpc) = &mut self.rpc {
|
||||||
// We can start both ws and http servers since they only run if enabled in the config.
|
// We can start both ws and http servers since they only run if enabled in the config.
|
||||||
rpc.start_ws().await?;
|
rpc.start_ws().await?;
|
||||||
|
@ -362,7 +170,7 @@ impl<DB: Database> Client<DB> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn call(&self, opts: &CallOpts, block: BlockTag) -> Result<Vec<u8>> {
|
pub async fn call(&self, opts: &CallOpts, block: BlockTag) -> eyre::Result<Vec<u8>> {
|
||||||
self.node
|
self.node
|
||||||
.read()
|
.read()
|
||||||
.await
|
.await
|
||||||
|
@ -371,7 +179,7 @@ impl<DB: Database> Client<DB> {
|
||||||
.map_err(|err| err.into())
|
.map_err(|err| err.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn estimate_gas(&self, opts: &CallOpts) -> Result<u64> {
|
pub async fn estimate_gas(&self, opts: &CallOpts) -> eyre::Result<u64> {
|
||||||
self.node
|
self.node
|
||||||
.read()
|
.read()
|
||||||
.await
|
.await
|
||||||
|
@ -380,30 +188,30 @@ impl<DB: Database> Client<DB> {
|
||||||
.map_err(|err| err.into())
|
.map_err(|err| err.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_balance(&self, address: &Address, block: BlockTag) -> Result<U256> {
|
pub async fn get_balance(&self, address: &Address, block: BlockTag) -> eyre::Result<U256> {
|
||||||
self.node.read().await.get_balance(address, block).await
|
self.node.read().await.get_balance(address, block).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_nonce(&self, address: &Address, block: BlockTag) -> Result<u64> {
|
pub async fn get_nonce(&self, address: &Address, block: BlockTag) -> eyre::Result<u64> {
|
||||||
self.node.read().await.get_nonce(address, block).await
|
self.node.read().await.get_nonce(address, block).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_code(&self, address: &Address, block: BlockTag) -> Result<Vec<u8>> {
|
pub async fn get_code(&self, address: &Address, block: BlockTag) -> eyre::Result<Vec<u8>> {
|
||||||
self.node.read().await.get_code(address, block).await
|
self.node.read().await.get_code(address, block).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) -> eyre::Result<U256> {
|
||||||
self.node.read().await.get_storage_at(address, slot).await
|
self.node.read().await.get_storage_at(address, slot).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_raw_transaction(&self, bytes: &[u8]) -> Result<H256> {
|
pub async fn send_raw_transaction(&self, bytes: &[u8]) -> eyre::Result<H256> {
|
||||||
self.node.read().await.send_raw_transaction(bytes).await
|
self.node.read().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>> {
|
) -> eyre::Result<Option<TransactionReceipt>> {
|
||||||
self.node
|
self.node
|
||||||
.read()
|
.read()
|
||||||
.await
|
.await
|
||||||
|
@ -411,7 +219,7 @@ impl<DB: Database> Client<DB> {
|
||||||
.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) -> eyre::Result<Option<Transaction>> {
|
||||||
self.node
|
self.node
|
||||||
.read()
|
.read()
|
||||||
.await
|
.await
|
||||||
|
@ -419,19 +227,19 @@ impl<DB: Database> Client<DB> {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_logs(&self, filter: &Filter) -> Result<Vec<Log>> {
|
pub async fn get_logs(&self, filter: &Filter) -> eyre::Result<Vec<Log>> {
|
||||||
self.node.read().await.get_logs(filter).await
|
self.node.read().await.get_logs(filter).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_gas_price(&self) -> Result<U256> {
|
pub async fn get_gas_price(&self) -> eyre::Result<U256> {
|
||||||
self.node.read().await.get_gas_price()
|
self.node.read().await.get_gas_price()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_priority_fee(&self) -> Result<U256> {
|
pub async fn get_priority_fee(&self) -> eyre::Result<U256> {
|
||||||
self.node.read().await.get_priority_fee()
|
self.node.read().await.get_priority_fee()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_block_number(&self) -> Result<u64> {
|
pub async fn get_block_number(&self) -> eyre::Result<u64> {
|
||||||
self.node.read().await.get_block_number()
|
self.node.read().await.get_block_number()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,7 +247,7 @@ impl<DB: Database> Client<DB> {
|
||||||
&self,
|
&self,
|
||||||
block: BlockTag,
|
block: BlockTag,
|
||||||
full_tx: bool,
|
full_tx: bool,
|
||||||
) -> Result<Option<ExecutionBlock>> {
|
) -> eyre::Result<Option<ExecutionBlock>> {
|
||||||
self.node
|
self.node
|
||||||
.read()
|
.read()
|
||||||
.await
|
.await
|
||||||
|
@ -451,7 +259,7 @@ impl<DB: Database> Client<DB> {
|
||||||
&self,
|
&self,
|
||||||
hash: &Vec<u8>,
|
hash: &Vec<u8>,
|
||||||
full_tx: bool,
|
full_tx: bool,
|
||||||
) -> Result<Option<ExecutionBlock>> {
|
) -> eyre::Result<Option<ExecutionBlock>> {
|
||||||
self.node
|
self.node
|
||||||
.read()
|
.read()
|
||||||
.await
|
.await
|
||||||
|
@ -463,7 +271,7 @@ impl<DB: Database> Client<DB> {
|
||||||
self.node.read().await.chain_id()
|
self.node.read().await.chain_id()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_header(&self) -> Result<Header> {
|
pub async fn get_header(&self) -> eyre::Result<Header> {
|
||||||
self.node.read().await.get_header()
|
self.node.read().await.get_header()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,20 @@
|
||||||
|
|
||||||
|
/// Re-export builder logic
|
||||||
|
mod builder;
|
||||||
|
pub use crate::builder::*;
|
||||||
|
|
||||||
|
/// Re-export client logic
|
||||||
mod client;
|
mod client;
|
||||||
pub use crate::client::*;
|
pub use crate::client::*;
|
||||||
|
|
||||||
|
/// Expose database module
|
||||||
pub mod database;
|
pub mod database;
|
||||||
|
|
||||||
|
/// Expose errors module
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
|
||||||
|
/// Expose rpc module
|
||||||
pub mod rpc;
|
pub mod rpc;
|
||||||
|
|
||||||
|
/// Node module is internal to the client crate
|
||||||
mod node;
|
mod node;
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::time::Duration;
|
||||||
|
|
||||||
use ethers::prelude::{Address, U256};
|
use ethers::prelude::{Address, U256};
|
||||||
use ethers::types::{Filter, Log, Transaction, TransactionReceipt, H256};
|
use ethers::types::{Filter, Log, Transaction, TransactionReceipt, H256};
|
||||||
|
use execution::rpc::ExecutionRpc;
|
||||||
use eyre::{eyre, Result};
|
use eyre::{eyre, Result};
|
||||||
|
|
||||||
use common::errors::BlockNotFoundError;
|
use common::errors::BlockNotFoundError;
|
||||||
|
@ -13,22 +14,22 @@ use consensus::rpc::nimbus_rpc::NimbusRpc;
|
||||||
use consensus::types::{ExecutionPayload, Header};
|
use consensus::types::{ExecutionPayload, Header};
|
||||||
use consensus::ConsensusClient;
|
use consensus::ConsensusClient;
|
||||||
use execution::evm::Evm;
|
use execution::evm::Evm;
|
||||||
use execution::rpc::http_rpc::HttpRpc;
|
// use execution::rpc::http_rpc::HttpRpc;
|
||||||
use execution::types::{CallOpts, ExecutionBlock};
|
use execution::types::{CallOpts, ExecutionBlock};
|
||||||
use execution::ExecutionClient;
|
use execution::ExecutionClient;
|
||||||
|
|
||||||
use crate::errors::NodeError;
|
use crate::errors::NodeError;
|
||||||
|
|
||||||
pub struct Node {
|
pub struct Node<R> where R: ExecutionRpc, {
|
||||||
pub consensus: ConsensusClient<NimbusRpc>,
|
pub consensus: ConsensusClient<NimbusRpc>,
|
||||||
pub execution: Arc<ExecutionClient<HttpRpc>>,
|
pub execution: Arc<ExecutionClient<R>>,
|
||||||
pub config: Arc<Config>,
|
pub config: Arc<Config>,
|
||||||
payloads: BTreeMap<u64, ExecutionPayload>,
|
payloads: BTreeMap<u64, ExecutionPayload>,
|
||||||
finalized_payloads: BTreeMap<u64, ExecutionPayload>,
|
finalized_payloads: BTreeMap<u64, ExecutionPayload>,
|
||||||
pub history_size: usize,
|
pub history_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node {
|
impl<R> Node<R> where R: ExecutionRpc {
|
||||||
pub fn new(config: Arc<Config>) -> Result<Self, NodeError> {
|
pub fn new(config: Arc<Config>) -> Result<Self, NodeError> {
|
||||||
let consensus_rpc = &config.consensus_rpc;
|
let consensus_rpc = &config.consensus_rpc;
|
||||||
let checkpoint_hash = &config.checkpoint;
|
let checkpoint_hash = &config.checkpoint;
|
||||||
|
|
|
@ -16,10 +16,10 @@ use common::{
|
||||||
types::BlockTag,
|
types::BlockTag,
|
||||||
utils::{hex_str_to_bytes, u64_to_hex_string},
|
utils::{hex_str_to_bytes, u64_to_hex_string},
|
||||||
};
|
};
|
||||||
use execution::types::{CallOpts, ExecutionBlock};
|
use execution::{types::{CallOpts, ExecutionBlock}, rpc::ExecutionRpc};
|
||||||
|
|
||||||
pub struct Rpc {
|
pub struct Rpc<R> where R: ExecutionRpc {
|
||||||
node: Arc<RwLock<Node>>,
|
node: Arc<RwLock<Node<R>>>,
|
||||||
http_handle: Option<HttpServerHandle>,
|
http_handle: Option<HttpServerHandle>,
|
||||||
ws_handle: Option<WsServerHandle>,
|
ws_handle: Option<WsServerHandle>,
|
||||||
pub with_http: bool,
|
pub with_http: bool,
|
||||||
|
@ -27,8 +27,8 @@ pub struct Rpc {
|
||||||
port: u16,
|
port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rpc {
|
impl<R> Rpc<R> where R: ExecutionRpc {
|
||||||
pub fn new(node: Arc<RwLock<Node>>, with_http: bool, with_ws: bool, port: u16) -> Self {
|
pub fn new(node: Arc<RwLock<Node<R>>>, with_http: bool, with_ws: bool, port: u16) -> Self {
|
||||||
Rpc {
|
Rpc {
|
||||||
node,
|
node,
|
||||||
http_handle: None,
|
http_handle: None,
|
||||||
|
@ -112,13 +112,13 @@ trait NetRpc {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct RpcInner {
|
struct RpcInner<R> where R: ExecutionRpc {
|
||||||
node: Arc<RwLock<Node>>,
|
node: Arc<RwLock<Node<R>>>,
|
||||||
port: u16,
|
port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Rpc> for RpcInner {
|
impl<R> From<&Rpc<R>> for RpcInner<R> where R: ExecutionRpc {
|
||||||
fn from(rpc: &Rpc) -> Self {
|
fn from(rpc: &Rpc<R>) -> Self {
|
||||||
RpcInner {
|
RpcInner {
|
||||||
node: Arc::clone(&rpc.node),
|
node: Arc::clone(&rpc.node),
|
||||||
port: rpc.port,
|
port: rpc.port,
|
||||||
|
@ -126,7 +126,7 @@ impl From<&Rpc> for RpcInner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RpcInner {
|
impl<R> RpcInner<R> where R: ExecutionRpc {
|
||||||
pub async fn start_http(&self) -> Result<(HttpServerHandle, SocketAddr)> {
|
pub async fn start_http(&self) -> Result<(HttpServerHandle, SocketAddr)> {
|
||||||
let addr = format!("127.0.0.1:{}", self.port);
|
let addr = format!("127.0.0.1:{}", self.port);
|
||||||
let server = HttpServerBuilder::default().build(addr).await?;
|
let server = HttpServerBuilder::default().build(addr).await?;
|
||||||
|
@ -165,7 +165,7 @@ impl RpcInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl EthRpcServer for RpcInner {
|
impl<R> EthRpcServer for RpcInner<R> where R: ExecutionRpc {
|
||||||
async fn get_balance(&self, address: &str, block: BlockTag) -> Result<String, Error> {
|
async fn get_balance(&self, address: &str, block: BlockTag) -> Result<String, Error> {
|
||||||
let address = convert_err(Address::from_str(address))?;
|
let address = convert_err(Address::from_str(address))?;
|
||||||
let node = self.node.read().await;
|
let node = self.node.read().await;
|
||||||
|
@ -286,7 +286,7 @@ impl EthRpcServer for RpcInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl NetRpcServer for RpcInner {
|
impl<R> NetRpcServer for RpcInner<R> where R: ExecutionRpc {
|
||||||
async fn version(&self) -> Result<String, Error> {
|
async fn version(&self) -> Result<String, Error> {
|
||||||
let node = self.node.read().await;
|
let node = self.node.read().await;
|
||||||
Ok(node.chain_id().to_string())
|
Ok(node.chain_id().to_string())
|
||||||
|
|
|
@ -40,6 +40,10 @@ impl ExecutionRpc for HttpRpc {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn connect(&mut self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_proof(
|
async fn get_proof(
|
||||||
&self,
|
&self,
|
||||||
address: &Address,
|
address: &Address,
|
||||||
|
|
|
@ -24,6 +24,10 @@ impl ExecutionRpc for MockRpc {
|
||||||
Ok(MockRpc { path })
|
Ok(MockRpc { path })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn connect(&mut self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_proof(
|
async fn get_proof(
|
||||||
&self,
|
&self,
|
||||||
_address: &Address,
|
_address: &Address,
|
||||||
|
|
|
@ -16,6 +16,9 @@ pub trait ExecutionRpc: Send + Clone + Sync + 'static {
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
|
/// Connect allows the rpc to connect if asynchronous connection is required (eg websockets).
|
||||||
|
async fn connect(&mut self) -> Result<()>;
|
||||||
|
|
||||||
async fn get_proof(
|
async fn get_proof(
|
||||||
&self,
|
&self,
|
||||||
address: &Address,
|
address: &Address,
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use common::errors::RpcError;
|
||||||
|
use ethers::prelude::{Address, Ws};
|
||||||
|
use ethers::providers::{HttpRateLimitRetryPolicy, Middleware, Provider, RetryClient};
|
||||||
|
use ethers::types::transaction::eip2718::TypedTransaction;
|
||||||
|
use ethers::types::transaction::eip2930::AccessList;
|
||||||
|
use ethers::types::{
|
||||||
|
BlockId, Bytes, EIP1186ProofResponse, Eip1559TransactionRequest, Filter, Log, Transaction,
|
||||||
|
TransactionReceipt, H256, U256,
|
||||||
|
};
|
||||||
|
use eyre::Result;
|
||||||
|
|
||||||
|
use crate::types::CallOpts;
|
||||||
|
|
||||||
|
use super::ExecutionRpc;
|
||||||
|
|
||||||
|
pub struct WsRpc {
|
||||||
|
pub url: String,
|
||||||
|
pub provider: Option<Provider<Ws>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for WsRpc {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self::new(&self.url).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl ExecutionRpc for WsRpc {
|
||||||
|
fn new(rpc: &str) -> Result<Self> {
|
||||||
|
Ok(WsRpc {
|
||||||
|
url: rpc.to_string(),
|
||||||
|
provider: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn connect(&mut self) -> Result<()> {
|
||||||
|
let provider = Provider::<Ws>::connect(&self.url).await?;
|
||||||
|
self.provider = Some(provider);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
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.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))?)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue