stratus/eth/external_rpc/
mod.rs1pub use postgres::PostgresExternalRpc;
2pub use postgres::PostgresExternalRpcConfig;
3
4mod postgres;
5
6use std::str::FromStr;
7use std::sync::Arc;
8use std::time::Duration;
9
10use anyhow::anyhow;
11use clap::Parser;
12use display_json::DebugAsJson;
13
14use crate::alias::JsonValue;
15use crate::eth::primitives::Account;
16use crate::eth::primitives::Address;
17use crate::eth::primitives::BlockNumber;
18use crate::eth::primitives::ExternalBlock;
19use crate::eth::primitives::ExternalReceipt;
20use crate::eth::primitives::Hash;
21use crate::eth::primitives::Wei;
22use crate::ext::parse_duration;
23
24pub type ExternalBlockWithReceipts = (ExternalBlock, Vec<ExternalReceipt>);
25
26#[allow(async_fn_in_trait)]
27pub trait ExternalRpc: Send + Sync {
28 async fn read_max_block_number_in_range(&self, start: BlockNumber, end: BlockNumber) -> anyhow::Result<Option<BlockNumber>>;
30
31 async fn read_block_and_receipts_in_range(&self, start: BlockNumber, end: BlockNumber) -> anyhow::Result<Vec<ExternalBlockWithReceipts>>;
33
34 async fn read_initial_accounts(&self) -> anyhow::Result<Vec<Account>>;
36
37 async fn save_initial_account(&self, address: Address, balance: Wei) -> anyhow::Result<()>;
39
40 async fn save_block_and_receipts(&self, number: BlockNumber, block: JsonValue, receipts: Vec<(Hash, ExternalReceipt)>) -> anyhow::Result<()>;
42}
43
44#[derive(DebugAsJson, Clone, Parser, serde::Serialize)]
50pub struct ExternalRpcConfig {
51 #[arg(long = "external-rpc-storage", env = "EXTERNAL_RPC_STORAGE")]
53 pub external_rpc_storage_kind: ExternalRpcKind,
54
55 #[arg(long = "external-rpc-storage-connections", env = "EXTERNAL_RPC_STORAGE_CONNECTIONS")]
57 pub external_rpc_storage_connections: u32,
58
59 #[arg(long = "external-rpc-storage-timeout", value_parser=parse_duration, env = "EXTERNAL_RPC_STORAGE_TIMEOUT")]
61 pub external_rpc_storage_timeout: Duration,
62
63 #[arg(long = "external-rpc-slow-query-warn-threshold", value_parser=parse_duration, env = "EXTERNAL_RPC_SLOW_QUERY_WARN_THRESHOLD", default_value = "1s")]
65 pub external_rpc_slow_query_warn_threshold: Duration,
66}
67
68#[derive(DebugAsJson, Clone, serde::Serialize)]
69pub enum ExternalRpcKind {
70 Postgres { url: String },
71}
72
73impl ExternalRpcConfig {
74 pub async fn init(&self) -> anyhow::Result<Arc<PostgresExternalRpc>> {
76 tracing::info!(config = ?self, "creating external rpc storage");
77
78 let ExternalRpcKind::Postgres { url } = &self.external_rpc_storage_kind;
79
80 let config = PostgresExternalRpcConfig {
81 url: url.to_owned(),
82 connections: self.external_rpc_storage_connections,
83 acquire_timeout: self.external_rpc_storage_timeout,
84 slow_query_warn_threshold: self.external_rpc_slow_query_warn_threshold,
85 };
86
87 Ok(Arc::new(PostgresExternalRpc::new(config).await?))
88 }
89}
90
91impl FromStr for ExternalRpcKind {
92 type Err = anyhow::Error;
93
94 fn from_str(s: &str) -> anyhow::Result<Self, Self::Err> {
95 match s {
96 s if s.starts_with("postgres://") => Ok(Self::Postgres { url: s.to_string() }),
97 s => Err(anyhow!("unknown external rpc storage: {}", s)),
98 }
99 }
100}