1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
use alloy::rpc::types::Log;
use thiserror::Error;
use crate::storage::codec::decoder::DecodedEventWithHeader;
pub mod backfill;
pub mod config;
pub(crate) mod cursor;
pub mod error_tracking;
pub mod events;
pub mod heads;
pub mod provider;
pub mod stream;
#[derive(Debug, Clone, Error)]
pub enum RpcError {
#[error("Connection Error: {0}")]
ConnectionError(String),
#[error("Subscription Error: {0}")]
SubscriptionError(String),
#[error("Log Fetch Error: {0}")]
LogFetchError(String),
#[error("Transport Error: {0}")]
TransportError(String),
#[error("All Providers Suspended: {0}")]
AllProvidersSuspended(String),
/// Internal-only signal — produced by `next_cursor_after_batch`, intercepted at
/// the three call sites, never yielded to consumers. See `ProviderStalled` for the
/// terminal variant that consumers receive when a provider tip is genuinely stalled.
#[error(
"Cursor past tip: refusing to advance to block {to_block}; provider reports tip {reported_tip}"
)]
CursorPastTip { to_block: u64, reported_tip: u64 },
#[error(
"provider stalled: tip {reported_tip} did not reach block {to_block} after {stalled_cycles} cycles"
)]
ProviderStalled {
to_block: u64,
reported_tip: u64,
stalled_cycles: u32,
},
/// A tip reorg detected by the live `parent_hash` linkage. `common_ancestor`
/// is the highest block the new chain still shares with what we recorded — the
/// single value a consumer's rollback acts on. `depth` (detection point minus
/// ancestor) and the competing hashes drive no decision, so they are not carried.
#[error("reorg: common ancestor at block {common_ancestor}")]
Reorg { common_ancestor: u64 },
/// The divergence is older than the detector ring (`> finality`): no common
/// ancestor exists within the finality window. A totality branch — unreachable
/// under a finality-deep ring plus economic finality; it fires only on a genuine
/// `> finality` catastrophe or a misconfigured too-shallow ring. Field-less: a
/// consumer routes it straight to terminate / operator, never to a rollback, and
/// a number measuring how far the walk got would drive no decision.
#[error(
"reorg beyond finality: no common ancestor within the detector ring (consensus invariant violated)"
)]
ReorgBeyondFinality,
#[error("Other Error: {0}")]
Other(String),
}
pub type LogRange = (u64, u64, Vec<Log>);
pub type DecodedEventRange = (u64, u64, Vec<DecodedEventWithHeader>);