2022-11-03 19:24:17 +00:00
|
|
|
use std::path::PathBuf;
|
2022-08-27 00:05:12 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2022-11-03 19:24:17 +00:00
|
|
|
use config::networks::Network;
|
2022-08-21 13:13:56 +00:00
|
|
|
use ethers::prelude::{Address, U256};
|
2022-11-17 17:14:13 +00:00
|
|
|
use ethers::types::{Filter, Log, Transaction, TransactionReceipt, H256};
|
2022-09-16 19:32:15 +00:00
|
|
|
use eyre::{eyre, Result};
|
2022-08-21 13:13:56 +00:00
|
|
|
|
2022-09-29 23:35:43 +00:00
|
|
|
use common::types::BlockTag;
|
2022-08-29 20:54:58 +00:00
|
|
|
use config::Config;
|
2022-09-10 04:01:23 +00:00
|
|
|
use consensus::types::Header;
|
2022-09-01 19:58:45 +00:00
|
|
|
use execution::types::{CallOpts, ExecutionBlock};
|
2022-09-16 19:32:15 +00:00
|
|
|
use log::{info, warn};
|
2022-09-10 04:01:23 +00:00
|
|
|
use tokio::spawn;
|
2022-09-22 21:30:47 +00:00
|
|
|
use tokio::sync::RwLock;
|
2022-09-10 04:01:23 +00:00
|
|
|
use tokio::time::sleep;
|
|
|
|
|
2022-09-16 19:32:15 +00:00
|
|
|
use crate::database::{Database, FileDB};
|
2022-09-29 23:35:43 +00:00
|
|
|
use crate::node::Node;
|
2022-09-10 04:01:23 +00:00
|
|
|
use crate::rpc::Rpc;
|
2022-08-21 13:13:56 +00:00
|
|
|
|
2022-09-16 19:32:15 +00:00
|
|
|
pub struct Client<DB: Database> {
|
2022-09-22 21:30:47 +00:00
|
|
|
node: Arc<RwLock<Node>>,
|
2022-09-10 04:01:23 +00:00
|
|
|
rpc: Option<Rpc>,
|
2022-11-03 23:36:14 +00:00
|
|
|
db: Option<DB>,
|
2022-08-21 13:13:56 +00:00
|
|
|
}
|
|
|
|
|
2022-09-16 19:32:15 +00:00
|
|
|
impl Client<FileDB> {
|
2022-11-03 19:24:17 +00:00
|
|
|
fn new(config: Config) -> Result<Self> {
|
2022-09-10 04:01:23 +00:00
|
|
|
let config = Arc::new(config);
|
2022-11-03 19:24:17 +00:00
|
|
|
let node = Node::new(config.clone())?;
|
2022-09-22 21:30:47 +00:00
|
|
|
let node = Arc::new(RwLock::new(node));
|
2022-09-10 04:01:23 +00:00
|
|
|
|
2022-11-30 01:31:25 +00:00
|
|
|
let rpc = config.rpc_port.map(|port| Rpc::new(node.clone(), port));
|
2022-09-10 04:01:23 +00:00
|
|
|
|
2022-10-05 17:52:07 +00:00
|
|
|
let data_dir = config.data_dir.clone();
|
2022-11-30 01:31:25 +00:00
|
|
|
let db = data_dir.map(FileDB::new);
|
2022-09-16 19:32:15 +00:00
|
|
|
|
|
|
|
Ok(Client { node, rpc, db })
|
2022-09-10 04:01:23 +00:00
|
|
|
}
|
2022-09-16 19:32:15 +00:00
|
|
|
}
|
2022-09-10 04:01:23 +00:00
|
|
|
|
2022-11-30 01:31:25 +00:00
|
|
|
#[derive(Default)]
|
2022-11-03 19:24:17 +00:00
|
|
|
pub struct ClientBuilder {
|
|
|
|
network: Option<Network>,
|
|
|
|
consensus_rpc: Option<String>,
|
|
|
|
execution_rpc: Option<String>,
|
|
|
|
checkpoint: Option<Vec<u8>>,
|
|
|
|
rpc_port: Option<u16>,
|
|
|
|
data_dir: Option<PathBuf>,
|
|
|
|
config: Option<Config>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ClientBuilder {
|
|
|
|
pub fn new() -> Self {
|
2022-11-30 01:31:25 +00:00
|
|
|
Self::default()
|
2022-11-03 19:24:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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).expect("cannot parse checkpoint");
|
|
|
|
self.checkpoint = Some(checkpoint);
|
|
|
|
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 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()
|
|
|
|
};
|
|
|
|
|
2022-11-03 23:36:14 +00:00
|
|
|
let consensus_rpc = self.consensus_rpc.unwrap_or_else(|| {
|
2022-11-03 19:24:17 +00:00
|
|
|
self.config
|
|
|
|
.as_ref()
|
2022-11-03 23:36:14 +00:00
|
|
|
.expect("missing consensus rpc")
|
2022-11-03 19:24:17 +00:00
|
|
|
.consensus_rpc
|
2022-11-03 23:36:14 +00:00
|
|
|
.clone()
|
|
|
|
});
|
2022-11-03 19:24:17 +00:00
|
|
|
|
2022-11-03 23:36:14 +00:00
|
|
|
let execution_rpc = self.execution_rpc.unwrap_or_else(|| {
|
2022-11-03 19:24:17 +00:00
|
|
|
self.config
|
|
|
|
.as_ref()
|
2022-11-03 23:36:14 +00:00
|
|
|
.expect("missing execution rpc")
|
2022-11-03 19:24:17 +00:00
|
|
|
.execution_rpc
|
2022-11-03 23:36:14 +00:00
|
|
|
.clone()
|
|
|
|
});
|
2022-11-03 19:24:17 +00:00
|
|
|
|
2022-11-03 23:36:14 +00:00
|
|
|
let checkpoint = if let Some(checkpoint) = self.checkpoint {
|
|
|
|
checkpoint
|
|
|
|
} else if let Some(config) = &self.config {
|
|
|
|
config.checkpoint.clone()
|
|
|
|
} else {
|
|
|
|
base_config.checkpoint
|
|
|
|
};
|
2022-11-03 19:24:17 +00:00
|
|
|
|
|
|
|
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 config = Config {
|
|
|
|
consensus_rpc,
|
|
|
|
execution_rpc,
|
|
|
|
checkpoint,
|
|
|
|
rpc_port,
|
|
|
|
data_dir,
|
|
|
|
chain: base_config.chain,
|
|
|
|
forks: base_config.forks,
|
2022-11-14 20:23:51 +00:00
|
|
|
max_checkpoint_age: base_config.max_checkpoint_age,
|
2022-11-03 19:24:17 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Client::new(config)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-16 19:32:15 +00:00
|
|
|
impl<DB: Database> Client<DB> {
|
2022-09-10 04:01:23 +00:00
|
|
|
pub async fn start(&mut self) -> Result<()> {
|
2022-11-03 23:36:14 +00:00
|
|
|
if let Some(rpc) = &mut self.rpc {
|
|
|
|
rpc.start().await?;
|
|
|
|
}
|
|
|
|
|
|
|
|
let res = self.node.write().await.sync().await;
|
|
|
|
if let Err(err) = res {
|
|
|
|
warn!("consensus error: {}", err);
|
|
|
|
}
|
2022-09-10 04:01:23 +00:00
|
|
|
|
|
|
|
let node = self.node.clone();
|
|
|
|
spawn(async move {
|
|
|
|
loop {
|
2022-09-22 21:30:47 +00:00
|
|
|
let res = node.write().await.advance().await;
|
2022-09-10 04:01:23 +00:00
|
|
|
if let Err(err) = res {
|
2022-09-29 23:35:43 +00:00
|
|
|
warn!("consensus error: {}", err);
|
2022-09-10 04:01:23 +00:00
|
|
|
}
|
2022-09-02 04:13:22 +00:00
|
|
|
|
2022-09-28 20:48:24 +00:00
|
|
|
let next_update = node.read().await.duration_until_next_update();
|
|
|
|
sleep(next_update).await;
|
2022-09-10 04:01:23 +00:00
|
|
|
}
|
|
|
|
});
|
2022-08-31 21:40:44 +00:00
|
|
|
|
|
|
|
Ok(())
|
2022-08-31 00:31:58 +00:00
|
|
|
}
|
|
|
|
|
2022-09-16 19:32:15 +00:00
|
|
|
pub async fn shutdown(&self) {
|
2022-09-22 21:30:47 +00:00
|
|
|
let node = self.node.read().await;
|
2022-09-16 19:32:15 +00:00
|
|
|
let checkpoint = if let Some(checkpoint) = node.get_last_checkpoint() {
|
|
|
|
checkpoint
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
|
|
|
info!("saving last checkpoint hash");
|
2022-11-03 23:36:14 +00:00
|
|
|
let res = self.db.as_ref().map(|db| db.save_checkpoint(checkpoint));
|
|
|
|
if res.is_some() && res.unwrap().is_err() {
|
2022-09-16 19:32:15 +00:00
|
|
|
warn!("checkpoint save failed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-03 23:36:14 +00:00
|
|
|
pub async fn call(&self, opts: &CallOpts, block: BlockTag) -> Result<Vec<u8>> {
|
2022-11-12 00:41:37 +00:00
|
|
|
self.node
|
|
|
|
.read()
|
|
|
|
.await
|
|
|
|
.call(opts, block)
|
|
|
|
.await
|
|
|
|
.map_err(|err| err.into())
|
2022-08-24 01:33:48 +00:00
|
|
|
}
|
|
|
|
|
2022-09-10 04:01:23 +00:00
|
|
|
pub async fn estimate_gas(&self, opts: &CallOpts) -> Result<u64> {
|
2022-11-12 00:41:37 +00:00
|
|
|
self.node
|
|
|
|
.read()
|
|
|
|
.await
|
|
|
|
.estimate_gas(opts)
|
|
|
|
.await
|
|
|
|
.map_err(|err| err.into())
|
2022-08-27 20:43:27 +00:00
|
|
|
}
|
|
|
|
|
2022-11-03 23:36:14 +00:00
|
|
|
pub async fn get_balance(&self, address: &Address, block: BlockTag) -> Result<U256> {
|
2022-09-22 21:30:47 +00:00
|
|
|
self.node.read().await.get_balance(address, block).await
|
2022-08-21 13:13:56 +00:00
|
|
|
}
|
|
|
|
|
2022-11-03 23:36:14 +00:00
|
|
|
pub async fn get_nonce(&self, address: &Address, block: BlockTag) -> Result<u64> {
|
2022-09-22 21:30:47 +00:00
|
|
|
self.node.read().await.get_nonce(address, block).await
|
2022-08-21 13:13:56 +00:00
|
|
|
}
|
|
|
|
|
2022-11-03 23:36:14 +00:00
|
|
|
pub async fn get_code(&self, address: &Address, block: BlockTag) -> Result<Vec<u8>> {
|
2022-09-22 21:30:47 +00:00
|
|
|
self.node.read().await.get_code(address, block).await
|
2022-08-21 16:59:47 +00:00
|
|
|
}
|
|
|
|
|
2022-09-06 17:57:47 +00:00
|
|
|
pub async fn get_storage_at(&self, address: &Address, slot: H256) -> Result<U256> {
|
2022-09-22 21:30:47 +00:00
|
|
|
self.node.read().await.get_storage_at(address, slot).await
|
2022-08-21 21:51:11 +00:00
|
|
|
}
|
|
|
|
|
2022-11-30 01:31:25 +00:00
|
|
|
pub async fn send_raw_transaction(&self, bytes: &[u8]) -> Result<H256> {
|
2022-09-22 21:30:47 +00:00
|
|
|
self.node.read().await.send_raw_transaction(bytes).await
|
2022-09-01 21:07:30 +00:00
|
|
|
}
|
|
|
|
|
2022-09-02 00:28:12 +00:00
|
|
|
pub async fn get_transaction_receipt(
|
|
|
|
&self,
|
2022-09-06 17:57:47 +00:00
|
|
|
tx_hash: &H256,
|
2022-09-02 00:28:12 +00:00
|
|
|
) -> Result<Option<TransactionReceipt>> {
|
2022-09-10 04:01:23 +00:00
|
|
|
self.node
|
2022-09-22 21:30:47 +00:00
|
|
|
.read()
|
2022-09-10 04:01:23 +00:00
|
|
|
.await
|
|
|
|
.get_transaction_receipt(tx_hash)
|
2022-09-02 00:28:12 +00:00
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
2022-09-06 17:57:47 +00:00
|
|
|
pub async fn get_transaction_by_hash(&self, tx_hash: &H256) -> Result<Option<Transaction>> {
|
2022-09-10 04:01:23 +00:00
|
|
|
self.node
|
2022-09-22 21:30:47 +00:00
|
|
|
.read()
|
2022-09-10 04:01:23 +00:00
|
|
|
.await
|
|
|
|
.get_transaction_by_hash(tx_hash)
|
2022-09-02 03:28:37 +00:00
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
2022-11-17 17:14:13 +00:00
|
|
|
pub async fn get_logs(&self, filter: &Filter) -> Result<Vec<Log>> {
|
|
|
|
self.node.read().await.get_logs(filter).await
|
|
|
|
}
|
|
|
|
|
2022-09-10 04:01:23 +00:00
|
|
|
pub async fn get_gas_price(&self) -> Result<U256> {
|
2022-09-22 21:30:47 +00:00
|
|
|
self.node.read().await.get_gas_price()
|
2022-08-29 15:59:02 +00:00
|
|
|
}
|
|
|
|
|
2022-09-10 04:01:23 +00:00
|
|
|
pub async fn get_priority_fee(&self) -> Result<U256> {
|
2022-09-22 21:30:47 +00:00
|
|
|
self.node.read().await.get_priority_fee()
|
2022-08-29 16:06:50 +00:00
|
|
|
}
|
|
|
|
|
2022-09-10 04:01:23 +00:00
|
|
|
pub async fn get_block_number(&self) -> Result<u64> {
|
2022-09-22 21:30:47 +00:00
|
|
|
self.node.read().await.get_block_number()
|
2022-08-31 21:40:44 +00:00
|
|
|
}
|
|
|
|
|
2022-10-27 17:46:32 +00:00
|
|
|
pub async fn get_block_by_number(
|
|
|
|
&self,
|
2022-11-03 23:36:14 +00:00
|
|
|
block: BlockTag,
|
2022-10-27 17:46:32 +00:00
|
|
|
full_tx: bool,
|
|
|
|
) -> Result<Option<ExecutionBlock>> {
|
|
|
|
self.node
|
|
|
|
.read()
|
|
|
|
.await
|
|
|
|
.get_block_by_number(block, full_tx)
|
|
|
|
.await
|
2022-09-02 04:13:22 +00:00
|
|
|
}
|
|
|
|
|
2022-10-27 17:46:32 +00:00
|
|
|
pub async fn get_block_by_hash(
|
|
|
|
&self,
|
|
|
|
hash: &Vec<u8>,
|
|
|
|
full_tx: bool,
|
|
|
|
) -> Result<Option<ExecutionBlock>> {
|
|
|
|
self.node
|
|
|
|
.read()
|
|
|
|
.await
|
|
|
|
.get_block_by_hash(hash, full_tx)
|
|
|
|
.await
|
2022-08-27 00:05:12 +00:00
|
|
|
}
|
|
|
|
|
2022-09-10 04:01:23 +00:00
|
|
|
pub async fn chain_id(&self) -> u64 {
|
2022-09-22 21:30:47 +00:00
|
|
|
self.node.read().await.chain_id()
|
2022-08-21 13:13:56 +00:00
|
|
|
}
|
2022-08-31 21:40:44 +00:00
|
|
|
|
2022-09-28 21:50:39 +00:00
|
|
|
pub async fn get_header(&self) -> Result<Header> {
|
|
|
|
self.node.read().await.get_header()
|
2022-08-31 21:40:44 +00:00
|
|
|
}
|
2022-08-21 13:13:56 +00:00
|
|
|
}
|