Skip to content

Commit 767d2da

Browse files
committed
feat: cherry-pick #714
1 parent 250dbaa commit 767d2da

8 files changed

Lines changed: 67 additions & 10 deletions

File tree

book/fault_proofs/proposer.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ Depending on the one you choose, you must provide the corresponding environment
7878

7979
| Variable | Description | Default Value |
8080
|----------|-------------|---------------|
81+
| `RPC_CONCURRENCY` | Maximum number of concurrent RPC requests. Lower this value (e.g., `3`-`5`) if hitting 429 rate limit errors. | `10` |
82+
| `L1_CONFIG_DIR` | The directory containing the L1 chain configuration files. | `<project-root>/configs/L1` |
83+
| `L2_CONFIG_DIR` | Directory containing L2 chain configuration files | `<project-root>/configs/L2` |
8184
| `MOCK_MODE` | Whether to use mock mode | `false` |
8285
| `FAST_FINALITY_MODE` | Whether to use fast finality mode | `false` |
8386
| `RANGE_PROOF_STRATEGY` | Proof fulfillment strategy for range proofs. Set to `hosted` to use the hosted proof strategy. | `reserved` |

book/troubleshooting.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,38 @@ let l1_head_number = l1_head_number + 100;
4646
The error occurs in the derivation pipeline when attempting to validate L2 blocks. The L1 head must be sufficiently ahead of the batch posting block to ensure all required data is available and the safe head state is consistent. The buffer of 20 blocks is added empirically to handle most cases where RPCs may have an incorrect view of the safe head state and have minimum overhead for the derivation process.
4747

4848
Reference: [Fetcher Implementation](https://github.com/succinctlabs/op-succinct/blob/5dfc43928c75cef0ebf881d10bd8b3dcbe273419/utils/host/src/fetcher.rs#L773)
49+
50+
### RPC Rate Limit Errors (429)
51+
52+
**Error Message:**
53+
54+
```text
55+
error code 429: Too Many Requests
56+
```
57+
58+
or
59+
60+
```text
61+
rate limit exceeded
62+
```
63+
64+
**Cause:**
65+
This error occurs when your RPC provider is rate-limiting requests due to too many concurrent calls. OP Succinct makes concurrent RPC requests to fetch block data efficiently, which can exceed the limits of free or low-tier RPC plans.
66+
67+
**Solution:**
68+
Set the `RPC_CONCURRENCY` environment variable to a lower value:
69+
70+
```bash
71+
# For low-tier RPC plans, try 3-5 concurrent requests
72+
export RPC_CONCURRENCY=5
73+
74+
# For very restrictive plans
75+
export RPC_CONCURRENCY=3
76+
```
77+
78+
The default is `10` concurrent requests. Reducing this value will make operations slower but more reliable for rate-limited RPC endpoints.
79+
80+
**Recommendations:**
81+
- Free RPC tiers: Set `RPC_CONCURRENCY=3`
82+
- Basic paid tiers: Set `RPC_CONCURRENCY=5`
83+
- Professional tiers: Default `10` should work, or increase for faster performance

book/validity/proposer.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ Before starting the proposer, ensure you have deployed the relevant contracts an
3939
| Parameter | Description |
4040
|-----------|-------------|
4141
| `L1_BEACON_RPC` | L1 Consensus (Beacon) Node. Could be required for integrations that access consensus-layer data. |
42+
| `RPC_CONCURRENCY` | Default: `10`. Maximum number of concurrent RPC requests. Lower this value (e.g., `3`-`5`) if you're hitting 429 rate limit errors from your RPC provider. |
4243
| `NETWORK_RPC_URL` | Default: `https://rpc.production.succinct.xyz`. RPC URL for the Succinct Prover Network. |
4344
| `DATABASE_URL` | Default: `postgres://op-succinct@postgres:5432/op-succinct`. The address of a Postgres database for storing the intermediate proposer state. |
4445
| `DGF_ADDRESS` | Address of the `DisputeGameFactory` contract. Note: If set, the proposer will create a dispute game with the DisputeGameFactory, rather than the `OPSuccinctL2OutputOracle`. Compatible with `OptimismPortal2`. |

scripts/utils/bin/cost_estimator.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use op_succinct_host_utils::{
77
get_rolling_block_range, get_validated_block_range, split_range_based_on_safe_heads,
88
split_range_basic, SpanBatchRange,
99
},
10-
fetcher::OPSuccinctDataFetcher,
10+
fetcher::{get_rpc_concurrency_from_env, OPSuccinctDataFetcher},
1111
host::OPSuccinctHost,
1212
stats::ExecutionStats,
1313
witness_generation::WitnessGenerator,
@@ -47,7 +47,7 @@ async fn execute_blocks_and_write_stats_csv<H: OPSuccinctHost>(
4747
.expect("Failed to fetch block data range.");
4848
(range, block_data)
4949
})
50-
.buffered(15)
50+
.buffered(get_rpc_concurrency_from_env())
5151
.collect::<Vec<_>>()
5252
.await;
5353

@@ -252,7 +252,7 @@ async fn main() -> Result<()> {
252252
.await
253253
.expect("Failed to get host CLI args")
254254
})
255-
.buffered(15)
255+
.buffered(get_rpc_concurrency_from_env())
256256
.collect::<Vec<_>>()
257257
.await;
258258

scripts/utils/bin/gen_sp1_test_artifacts.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use futures::StreamExt;
44
use log::info;
55
use op_succinct_host_utils::{
66
block_range::{get_validated_block_range, split_range_basic},
7-
fetcher::OPSuccinctDataFetcher,
7+
fetcher::{get_rpc_concurrency_from_env, OPSuccinctDataFetcher},
88
host::OPSuccinctHost,
99
witness_generation::WitnessGenerator,
1010
};
@@ -49,7 +49,7 @@ async fn main() -> Result<()> {
4949
.await
5050
.expect("Failed to get host CLI args")
5151
})
52-
.buffered(15)
52+
.buffered(get_rpc_concurrency_from_env())
5353
.collect::<Vec<_>>()
5454
.await;
5555

utils/host/src/block_range.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use kona_rpc::{OutputResponse, SafeHeadResponse};
1010
use serde::{Deserialize, Serialize};
1111

1212
use crate::{
13-
fetcher::{OPSuccinctDataFetcher, RPCMode},
13+
fetcher::{get_rpc_concurrency_from_env, OPSuccinctDataFetcher, RPCMode},
1414
host::OPSuccinctHost,
1515
};
1616

@@ -154,7 +154,7 @@ pub async fn split_range_based_on_safe_heads(
154154
.expect("Failed to fetch safe head");
155155
result.safe_head.number
156156
})
157-
.buffered(15)
157+
.buffered(get_rpc_concurrency_from_env())
158158
.collect::<HashSet<_>>()
159159
.await;
160160

utils/host/src/fetcher.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ pub struct RPCConfig {
5656
pub l2_rpc: Url,
5757
// TODO(fakedev9999): Make optional if possible.
5858
pub l2_node_rpc: Url,
59+
/// Maximum number of concurrent RPC requests. Default: 5.
60+
/// Configure via RPC_CONCURRENCY environment variable.
61+
pub concurrency: usize,
5962
}
6063

6164
/// The mode corresponding to the chain we are fetching data for.
@@ -67,12 +70,26 @@ pub enum RPCMode {
6770
L2Node,
6871
}
6972

73+
/// Default RPC concurrency limit.
74+
/// Set RPC_CONCURRENCY env var to a lower value (e.g., 3-5) if hitting 429 rate limits.
75+
pub const DEFAULT_RPC_CONCURRENCY: usize = 10;
76+
77+
/// Gets the RPC concurrency from the RPC_CONCURRENCY environment variable.
78+
/// Returns DEFAULT_RPC_CONCURRENCY (10) if not set or invalid.
79+
pub fn get_rpc_concurrency_from_env() -> usize {
80+
env::var("RPC_CONCURRENCY")
81+
.ok()
82+
.and_then(|s| s.parse::<usize>().ok())
83+
.unwrap_or(DEFAULT_RPC_CONCURRENCY)
84+
}
85+
7086
/// Gets the RPC URLs from environment variables.
7187
///
7288
/// L1_RPC: The L1 RPC URL.
7389
/// L1_BEACON_RPC: The L1 beacon RPC URL.
7490
/// L2_RPC: The L2 RPC URL.
7591
/// L2_NODE_RPC: The L2 node RPC URL.
92+
/// RPC_CONCURRENCY: Maximum concurrent RPC requests (default: 5).
7693
pub fn get_rpcs_from_env() -> RPCConfig {
7794
let l1_rpc = env::var("L1_RPC").expect("L1_RPC must be set");
7895
let maybe_l1_beacon_rpc = env::var("L1_BEACON_RPC").ok();
@@ -92,6 +109,7 @@ pub fn get_rpcs_from_env() -> RPCConfig {
92109
l1_beacon_rpc,
93110
l2_rpc: Url::parse(&l2_rpc).expect("L2_RPC must be a valid URL"),
94111
l2_node_rpc: Url::parse(&l2_node_rpc).expect("L2_NODE_RPC must be a valid URL"),
112+
concurrency: get_rpc_concurrency_from_env(),
95113
}
96114
}
97115

@@ -214,7 +232,7 @@ impl OPSuccinctDataFetcher {
214232
total_tx_fees,
215233
})
216234
})
217-
.buffered(10)
235+
.buffered(self.rpc_config.concurrency)
218236
.collect::<Vec<Result<BlockInfo>>>()
219237
.await;
220238

@@ -470,7 +488,7 @@ impl OPSuccinctDataFetcher {
470488
// Process blocks in batches of 10, but maintain original order
471489
let results = stream::iter(block_numbers)
472490
.map(|block_number| self.get_l1_header(block_number.into()))
473-
.buffered(10)
491+
.buffered(self.rpc_config.concurrency)
474492
.collect::<Vec<_>>()
475493
.await;
476494

validity/src/proposer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ where
286286
self.driver_config.fetcher.clone(),
287287
)
288288
})
289-
.buffered(10) // Do 10 at a time, otherwise it's too slow when fetching the block range data.
289+
.buffered(self.driver_config.fetcher.rpc_config.concurrency)
290290
.try_collect::<Vec<OPSuccinctRequest>>()
291291
.await?;
292292

0 commit comments

Comments
 (0)