Skip to content

Commit

Permalink
Merge pull request #12 from worldcoin/osiris/better-providers
Browse files Browse the repository at this point in the history
Osiris/better providers
  • Loading branch information
0xOsiris authored Oct 24, 2024
2 parents 871fad1 + 3f5adca commit be62c91
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 82 deletions.
9 changes: 6 additions & 3 deletions config.stage.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ address = "0xb2ead588f14e69266d1b87936b75325181377076"
state_bridge_addr = "0x2F418Aa7D500B525EE8B80BB5F643A877ef82e09"
world_id_addr = "0xE177F37AF0A862A02edFEa4F59C02668E9d0aAA4"
provider = { rpc_endpoint = "https://eth.llamarpc.com" }
wallet = { type = "mnemonic", mnemonic = "your mnemonic here" }
# Optionally Define a custom L1 Signer for this network
# wallet = { type = "mnemonic", mnemonic = "your mnemonic here" }

[[bridged_networks]]
type = "evm"
Expand All @@ -21,7 +22,8 @@ address = "0xb2ead588f14e69266d1b87936b75325181377076"
state_bridge_addr = "0x158379286D7083dDA05930CD3C6374954Fb511aA"
world_id_addr = "0xf07d3efadD82A1F0b4C5Cc3476806d9a170147Ba"
provider = { rpc_endpoint = "https://eth.llamarpc.com" }
wallet = { type = "mnemonic", mnemonic = "your mnemonic here" }
# Optionally Define a custom L1 Signer for this network
# wallet = { type = "mnemonic", mnemonic = "your mnemonic here" }

[[bridged_networks]]
type = "evm"
Expand All @@ -30,5 +32,6 @@ address = "0xb2ead588f14e69266d1b87936b75325181377076"
state_bridge_addr = "0x5fFe37995158528d97A819bA390C1F81d74eB2b9"
world_id_addr = "0x163b09b4fE21177c455D850BD815B6D583732432"
provider = { rpc_endpoint = "https://eth.llamarpc.com" }
wallet = { type = "mnemonic", mnemonic = "your mnemonic here" }
# Optionally Define a custom L1 Signer for this network
# wallet = { type = "mnemonic", mnemonic = "your mnemonic here" }

47 changes: 42 additions & 5 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
use core::fmt;
use std::path::Path;

use alloy::network::EthereumWallet;
use alloy::primitives::Address;
use alloy::providers::{ProviderBuilder, RootProvider};
use alloy::providers::fillers::{
BlobGasFiller, CachedNonceManager, ChainIdFiller, GasFiller, JoinFill,
NonceFiller,
};
use alloy::providers::{Provider, ProviderBuilder};
use alloy::rpc::client::ClientBuilder;
use alloy::transports::http::Http;
use alloy::transports::layers::{RetryBackoffLayer, RetryBackoffService};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use url::Url;

use crate::relay::signer::{AlloySignerProvider, TxFillers};

pub type ThrottledTransport = RetryBackoffService<Http<Client>>;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
/// The global wallet configuration
pub wallet: Option<WalletConfig>,
/// The network from which roots will be propagated
pub canonical_network: CanonicalNetworkConfig,
/// The networks to which roots will be propagated
Expand Down Expand Up @@ -74,6 +81,8 @@ impl fmt::Debug for BridgedNetworkConfig {
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CanonicalNetworkConfig {
pub world_id_addr: Address,
/// The global wallet configuration
pub wallet: Option<WalletConfig>,
/// The number of blocks in the past to start scanning for new root events
#[serde(default = "default::start_scan")]
pub start_scan: u64,
Expand Down Expand Up @@ -116,7 +125,7 @@ pub struct ProviderConfig {
}

impl ProviderConfig {
pub fn provider(&self) -> RootProvider<RetryBackoffService<Http<Client>>> {
pub fn provider(&self) -> impl Provider<ThrottledTransport> {
let client = ClientBuilder::default()
.layer(RetryBackoffLayer::new(
self.max_rate_limit_retries,
Expand All @@ -126,6 +135,34 @@ impl ProviderConfig {
.http(self.rpc_endpoint.clone());
ProviderBuilder::new().on_client(client)
}

pub fn signer(&self, wallet: EthereumWallet) -> AlloySignerProvider {
let client = ClientBuilder::default()
.layer(RetryBackoffLayer::new(
self.max_rate_limit_retries,
self.initial_backoff,
self.compute_units_per_second,
))
.http(self.rpc_endpoint.clone());

ProviderBuilder::new()
.filler(Self::tx_fillers())
.wallet(wallet)
.on_client(client)
}

fn tx_fillers() -> TxFillers {
JoinFill::new(
GasFiller,
JoinFill::new(
BlobGasFiller,
JoinFill::new(
NonceFiller::new(CachedNonceManager::default()),
ChainIdFiller::default(),
),
),
)
}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -154,7 +191,7 @@ mod default {
}

pub const fn max_rate_limit_retries() -> u32 {
1
10
}

pub const fn initial_backoff() -> u64 {
Expand Down
99 changes: 65 additions & 34 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,24 @@ pub mod utils;
use std::path::PathBuf;
use std::sync::Arc;

use abi::IStateBridge::IStateBridgeInstance;
use alloy::network::EthereumWallet;
use alloy::primitives::U256;
use alloy::providers::{Provider, ProviderBuilder};
use alloy::providers::Provider;
use alloy::rpc::types::Filter;
use alloy::signers::local::MnemonicBuilder;
use alloy::sol_types::SolEvent;
use alloy_signer_local::coins_bip39::English;
use clap::Parser;
use config::{NetworkType, WalletConfig};
use eyre::eyre::{eyre, OptionExt, Result};
use eyre::eyre::{eyre, Result};
use futures::StreamExt;
use relay::signer::{AlloySigner, Signer, TxSitterSigner};
use relay::{EVMRelay, Relay, Relayer};
use telemetry_batteries::metrics::statsd::StatsdBattery;
use telemetry_batteries::tracing::datadog::DatadogBattery;
use telemetry_batteries::tracing::TracingShutdownHandle;
use tokio::task::JoinSet;
use tracing::info;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;

Expand All @@ -52,6 +52,10 @@ pub async fn main() -> Result<()> {
eyre::install()?;
dotenv::dotenv().ok();

// Set default log level if not set
if std::env::var("RUST_LOG").is_err() {
std::env::set_var("RUST_LOG", "info");
}
let opts = Opts::parse();

let config = Config::load(opts.config.as_deref())?;
Expand Down Expand Up @@ -100,7 +104,7 @@ pub async fn run(config: Config) -> Result<()> {

let latest_block_number = provider.get_block_number().await?;

// Start in the past by approximately 2 hours
// // Start in the past by approximately 2 hours
let start_block_number = latest_block_number
.checked_sub(config.canonical_network.start_scan)
.unwrap_or_default();
Expand All @@ -127,7 +131,7 @@ pub async fn run(config: Config) -> Result<()> {
joinset.spawn(async move {
relay.subscribe_roots(tx.subscribe()).await.map_err(|error| {
match relay {
Relayer::Evm(EVMRelay {
Relayer::EVMRelay(EVMRelay {
signer: _,
world_id_address,
provider,
Expand All @@ -139,7 +143,7 @@ pub async fn run(config: Config) -> Result<()> {
"Error subscribing to roots"
);
}
Relayer::Svm(_) => {
Relayer::SvmRelay(_) => {
tracing::error!(%error, "Error subscribing to roots");
}
}
Expand Down Expand Up @@ -175,61 +179,88 @@ pub async fn run(config: Config) -> Result<()> {
Ok(())
}

/// Initializes the relayers for the bridged networks.
///
/// Additionally initializes the signers from the global wallet configuration if present,
/// otherwise from the bridged network configuration.
fn init_relays(cfg: Config) -> Result<Vec<Relayer>> {
// Optinally use a global wallet configuration for all networks without a specific wallet configuration.
let global_signer = if let Some(wallet) = cfg.canonical_network.wallet {
match wallet {
WalletConfig::Mnemonic { mnemonic } => {
let signer = MnemonicBuilder::<English>::default()
.phrase(mnemonic)
.index(0)?
.build()?;
let wallet = EthereumWallet::new(signer);

let provider =
cfg.canonical_network.provider.signer(wallet.clone());

Some(Arc::new(provider))
}
_ => None,
}
} else {
None
};
cfg.bridged_networks
.iter()
.map(|bridged| {
let wallet_config = bridged
.wallet
.as_ref()
.or(cfg.wallet.as_ref())
.ok_or_eyre("No wallet configuration found")?;

let wallet_config = bridged.wallet.as_ref();
match bridged.ty {
NetworkType::Evm => match wallet_config {
WalletConfig::Mnemonic { mnemonic } => {
Some(WalletConfig::Mnemonic { mnemonic }) => {
let signer = MnemonicBuilder::<English>::default()
.phrase(mnemonic)
.index(0)
.unwrap()
.build()
.expect("Failed to build wallet");
.index(0)?
.build()?;
let wallet = EthereumWallet::new(signer);
let l1_provider = ProviderBuilder::default()
.with_recommended_fillers()
.wallet(wallet)
.on_http(
cfg.canonical_network
.provider
.rpc_endpoint
.clone(),
);
let state_bridge = IStateBridgeInstance::new(
let provider = cfg
.canonical_network
.provider
.signer(wallet.clone());
let alloy_signer = AlloySigner::new(
bridged.state_bridge_addr,
l1_provider,
Arc::new(provider),
);

let signer = AlloySigner::new(state_bridge);

Ok(Relayer::Evm(EVMRelay::new(
Signer::AlloySigner(signer),
Ok(Relayer::EVMRelay(EVMRelay::new(
Signer::AlloySigner(alloy_signer),
bridged.world_id_addr,
bridged.provider.rpc_endpoint.clone(),
)))
}
WalletConfig::TxSitter { url, gas_limit } => {
Some(WalletConfig::TxSitter { url, gas_limit }) => {
let signer = TxSitterSigner::new(
url.as_str(),
bridged.state_bridge_addr,
*gas_limit,
);

Ok(Relayer::Evm(EVMRelay::new(
Ok(Relayer::EVMRelay(EVMRelay::new(
Signer::TxSitterSigner(signer),
bridged.world_id_addr,
bridged.provider.rpc_endpoint.clone(),
)))
}
None => {
if let Some(global_signer) = &global_signer {
info!(network = %bridged.name, "Using global wallet configuration for bridged network");
let alloy_signer = AlloySigner::new(
bridged.state_bridge_addr,
global_signer.clone(),
);

Ok(Relayer::EVMRelay(EVMRelay::new(
Signer::AlloySigner(alloy_signer),
bridged.world_id_addr,
bridged.provider.rpc_endpoint.clone(),
)))
} else {
Err(eyre!("No wallet configuration found"))
}
}
},
NetworkType::Svm => unimplemented!(),
NetworkType::Scroll => unimplemented!(),
Expand Down
39 changes: 27 additions & 12 deletions src/relay/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,17 @@ pub(crate) trait Relay {
async fn subscribe_roots(&self, rx: Receiver<Field>) -> Result<()>;
}

pub enum Relayer {
Evm(EVMRelay),
Svm(SvmRelay),
}

impl Relay for Relayer {
async fn subscribe_roots(&self, rx: Receiver<Field>) -> Result<()> {
match self {
Relayer::Evm(relay) => relay.subscribe_roots(rx).await,
Relayer::Svm(_relay) => unimplemented!(),
macro_rules! relay {
($($relay_type:ident),+ $(,)?) => {
pub enum Relayer {
$($relay_type($relay_type),)+
}
impl Relay for Relayer {
async fn subscribe_roots(&self, rx: Receiver<Field>) -> Result<()> {
match self {
$(Relayer::$relay_type(relay) => Ok(relay.subscribe_roots(rx).await?),)+
}
}
}
}
}
Expand Down Expand Up @@ -68,8 +69,14 @@ impl Relay for EVMRelay {
let latest = world_id.latestRoot().call().await?._0;

if latest != field {
tracing::trace!(new_root = ?field, latest_root =?latest, "Propagating root");
self.signer.propagate_root().await?;
match self.signer.propagate_root().await {
Ok(_) => {
tracing::info!(root = %field, previous_root=%latest, provider = %self.provider, "Root propagated successfully");
}
Err(e) => {
tracing::error!(error = %e, root = %field, previous_root=%latest, provider = %self.provider, "Failed to propagate root");
}
}
// We sleep for 2 blocks, so we don't resend the same root prior to derivation of the message on L2.
std::thread::sleep(std::time::Duration::from_secs(
ROOT_PROPAGATION_BACKOFF,
Expand All @@ -80,3 +87,11 @@ impl Relay for EVMRelay {
}

pub struct SvmRelay;

impl Relay for SvmRelay {
async fn subscribe_roots(&self, _rx: Receiver<Field>) -> Result<()> {
unimplemented!()
}
}

relay!(EVMRelay, SvmRelay);
Loading

0 comments on commit be62c91

Please sign in to comment.