diff --git a/Cargo.lock b/Cargo.lock index 670c17025..2e63bd906 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -809,6 +809,7 @@ dependencies = [ "derive_more 2.0.1", "futures", "futures-utils-wasm", + "governor", "parking_lot 0.12.4", "serde", "serde_json", @@ -2618,6 +2619,7 @@ name = "boundless-cli" version = "0.15.0" dependencies = [ "alloy", + "alloy-provider", "anyhow", "assert_cmd", "assert_fs", @@ -4683,6 +4685,12 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + [[package]] name = "futures-util" version = "0.3.31" @@ -4868,6 +4876,27 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "governor" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be93b4ec2e4710b04d9264c0c7350cdd62a8c20e5e4ac732552ebb8f0debe8eb" +dependencies = [ + "cfg-if", + "futures-sink", + "futures-timer", + "futures-util", + "getrandom 0.3.3", + "no-std-compat", + "nonzero_ext", + "parking_lot 0.12.4", + "portable-atomic", + "quanta", + "smallvec", + "spinning_top", + "web-time", +] + [[package]] name = "group" version = "0.12.1" @@ -6582,6 +6611,12 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "no-std-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" + [[package]] name = "no_std_strings" version = "0.1.3" @@ -6598,6 +6633,12 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nonzero_ext" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" + [[package]] name = "normalize-line-endings" version = "0.3.0" @@ -7604,6 +7645,21 @@ dependencies = [ "parking_lot 0.12.4", ] +[[package]] +name = "quanta" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi 0.11.1+wasi-snapshot-preview1", + "web-sys", + "winapi", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -7757,6 +7813,15 @@ dependencies = [ "rand_core 0.9.3", ] +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.9.4", +] + [[package]] name = "rawpointer" version = "0.2.1" @@ -9670,6 +9735,15 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spinning_top" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" +dependencies = [ + "lock_api", +] + [[package]] name = "spki" version = "0.6.0" diff --git a/Cargo.toml b/Cargo.toml index b33cf95e7..c6bdff196 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ order-stream = { path = "crates/order-stream" } async-stream = "0.3" alloy = { version = "1.0", default-features = false } alloy-primitives = { version = "1.0" } +alloy-provider = { version = "1.0" } alloy-sol-types = { version = "1.0", features = ["json"] } alloy-chains = "0.2.0" anyhow = { version = "1.0" } diff --git a/crates/boundless-cli/Cargo.toml b/crates/boundless-cli/Cargo.toml index 2c28a1134..34500f13e 100644 --- a/crates/boundless-cli/Cargo.toml +++ b/crates/boundless-cli/Cargo.toml @@ -14,6 +14,7 @@ shadow-rs = "1.1" [dependencies] alloy = { workspace = true, features = ["full"] } +alloy-provider = { workspace = true, features = ["throttle"] } anyhow = { workspace = true } atomicwrites = "0.4.4" bincode = { workspace = true } diff --git a/crates/boundless-cli/src/bin/boundless.rs b/crates/boundless-cli/src/bin/boundless.rs index 887cbc2a2..e7169d30a 100644 --- a/crates/boundless-cli/src/bin/boundless.rs +++ b/crates/boundless-cli/src/bin/boundless.rs @@ -1489,6 +1489,7 @@ mod tests { let config = GlobalConfig { rpc_url: Some(anvil.endpoint_url()), + rps: u32::MAX, private_key: Some(private_key), deployment: Some(ctx.deployment.clone()), tx_timeout: None, @@ -1957,6 +1958,7 @@ mod tests { let prover_config = GlobalConfig { rpc_url: Some(anvil.endpoint_url()), + rps: u32::MAX, private_key: Some(ctx.prover_signer.clone()), deployment: Some(ctx.deployment), tx_timeout: None, @@ -2292,6 +2294,7 @@ mod tests { let prover_config = GlobalConfig { rpc_url: Some(anvil.endpoint_url()), + rps: u32::MAX, private_key: Some(ctx.prover_signer.clone()), deployment: Some(ctx.deployment), tx_timeout: None, diff --git a/crates/boundless-cli/src/commands/povw/claim.rs b/crates/boundless-cli/src/commands/povw/claim.rs index 2ed484210..dabd2edfe 100644 --- a/crates/boundless-cli/src/commands/povw/claim.rs +++ b/crates/boundless-cli/src/commands/povw/claim.rs @@ -21,8 +21,12 @@ use alloy::{ contract::Event, primitives::{Address, U256}, providers::{Provider, ProviderBuilder}, - rpc::types::{Filter, Log}, + rpc::{ + client::RpcClient, + types::{Filter, Log}, + }, sol_types::SolEvent, + transports::layers::ThrottleLayer, }; use anyhow::{bail, ensure, Context}; use boundless_povw::{ @@ -99,12 +103,14 @@ impl PovwClaim { let tx_signer = global_config.require_private_key()?; let rpc_url = global_config.require_rpc_url()?; - // Connect to the chain. - let provider = ProviderBuilder::new() - .wallet(tx_signer.clone()) + let client = RpcClient::builder() + .layer(ThrottleLayer::new(global_config.rps)) .connect(rpc_url.as_str()) .await - .with_context(|| format!("failed to connect provider to {rpc_url}"))?; + .with_context(|| format!("failed to connect to {rpc_url}"))?; + + // Connect to the chain. + let provider = ProviderBuilder::new().wallet(tx_signer).connect_client(client); let chain_id = provider.get_chain_id().await.context("Failed to query the chain ID")?; let chain_spec = CHAIN_SPECS.get(&chain_id).with_context(|| { diff --git a/crates/boundless-cli/src/config.rs b/crates/boundless-cli/src/config.rs index f0d109a04..42b31db87 100644 --- a/crates/boundless-cli/src/config.rs +++ b/crates/boundless-cli/src/config.rs @@ -34,6 +34,10 @@ pub struct GlobalConfig { #[clap(long, env = "RPC_URL", global = true)] pub rpc_url: Option, + /// Limit the requests per second to the RPC endpoint + #[clap(long, env = "RPS", global = true, default_value_t = 25)] + pub rps: u32, + /// Private key of the wallet (without 0x prefix) #[clap(long, env = "PRIVATE_KEY", global = true, hide_env_values = true)] pub private_key: Option,