provider.rpcdb
Documentation for eth_defi.provider.rpcdb Python module.
JSON-RPC request accounting and DuckDB persistence.
A caller creates one RPCRequestStats for a phase, passes it to Web3
providers, and persists the aggregate with RPCUsageDatabase.
Module Attributes
Environment variable overriding |
|
Marker value used to preserve a completed zero-call scan iteration. |
Functions
|
Format current-cycle and daily JSON-RPC usage for one chain. |
|
Convert heterogeneous provider failures to stable aggregation values. |
Resolve the shared JSON-RPC tracking DuckDB path. |
Classes
Bind a fixed operation label to an existing physical-request accumulator. |
|
Thread-safe, pickle-safe physical JSON-RPC request counters. |
|
Append-only DuckDB storage for JSON-RPC scan accounting. |
- DEFAULT_RPC_TRACKING_DATABASE = PosixPath('/home/runner/.tradingstrategy/rpc-tracking.duckdb')
Default shared DuckDB path for JSON-RPC request accounting.
- RPC_TRACKING_DATABASE_PATH_ENV = 'RPC_TRACKING_DATABASE_PATH'
Environment variable overriding
DEFAULT_RPC_TRACKING_DATABASE.
- ZERO_CALL_MARKER = 'none'
Marker value used to preserve a completed zero-call scan iteration.
- resolve_rpc_tracking_database_path()
Resolve the shared JSON-RPC tracking DuckDB path.
The resolver follows the same convention as other repository DuckDB modules: a module-level default below
~/.tradingstrategyand an environment-variable override with user-home expansion.- Returns
Expanded path from
RPC_TRACKING_DATABASE_PATHor the default path.- Return type
- normalise_rpc_error(error)
Convert heterogeneous provider failures to stable aggregation values.
JSON-RPC response dictionaries use their numeric error code. HTTP failures use
http_<status>. Other Python failures use the concrete exception class name. The provider’s original error message is retained.- Parameters
error (Union[BaseException, dict[str, Any]]) – A JSON-RPC error dictionary or an exception raised by the provider.
- Returns
(error_code, error_message)suitable forRPCRequestStats.record_error().- Return type
- class RPCRequestStats
Bases:
objectThread-safe, pickle-safe physical JSON-RPC request counters.
callsis keyed by(rpc_provider_domain, api_call)anderrorsby(rpc_provider_domain, error_code, error_message).operation_callsuses(operation, rpc_provider_domain, api_call)to attribute those same physical attempts to scanner work without increasing the total. Tuple positions match the persistence writer’s unpacking order. The lock is excluded from pickle state and recreated in subprocesses.- calls: collections.Counter[tuple[str, str]]
Key:
(rpc_provider_domain, api_call); value: physical attempt count. The domain is the provider hostname with an optional non-default port; api_call is the JSON-RPC method name, e.g.eth_call.
- errors: collections.Counter[tuple[str, str, str]]
Key:
(rpc_provider_domain, error_code, error_message); value: failure count. Codes are normalised bynormalise_rpc_error(); messages retain the provider’s original text so distinct failures remain distinguishable.
- operation_calls: collections.Counter[tuple[str, str, str]]
Key:
(operation, rpc_provider_domain, api_call); value: physical attempt count. Operation is the scanner work label at request time. These rows describe the same requests ascallsand must never be added to its totals.
- record_call(rpc_provider_domain, api_call, count=1, *, operation=None)
Record physical JSON-RPC request attempts.
Provider instrumentation calls this for each attempt, including retry and failover. Operation labels describe those same attempts; counting Multicall subcalls here or adding operation totals would inflate cost.
- Parameters
rpc_provider_domain (str) – Provider hostname, optionally including a non-default port.
api_call (str) – JSON-RPC method name such as
eth_call.count (int) – Positive number of attempts to add.
operation (Optional[str]) – Explicit attribution label from a bound recorder, or
Noneto use this accumulator’s phase label. The shared default label is never changed, so concurrent providers can use different labels safely.
- Returns
None; both total and operation counters advance together.
- Return type
None
- record_error(rpc_provider_domain, error_code, error_message, count=1)
Record JSON-RPC request failures.
- merge(other)
Merge another worker or phase aggregate exactly once.
- Parameters
other (eth_defi.provider.rpcdb.RPCRequestStats) – Detached task statistics to add to this accumulator.
- Return type
None
- export()
Take a detached copy of both counter mappings.
- Returns
(calls, errors)safe to iterate without holding the accumulator lock. Call keys are(rpc_provider_domain, api_call); error keys are(rpc_provider_domain, error_code, error_message). Values are integer attempt and failure counts respectively. Operation counters are excluded from this legacy two-counter interface.- Return type
tuple[collections.Counter[tuple[str, str]], collections.Counter[tuple[str, str, str]]]
- __init__(calls=<factory>, errors=<factory>, operation_calls=<factory>, operation='unclassified')
- Parameters
calls (collections.Counter[tuple[str, str]]) –
errors (collections.Counter[tuple[str, str, str]]) –
operation_calls (collections.Counter[tuple[str, str, str]]) –
operation (str) –
- Return type
None
- class RPCOperationRecorder
Bases:
objectBind a fixed operation label to an existing physical-request accumulator.
Multicall attaches this lightweight recorder to its worker-owned provider for the isolated lane. Regular and isolated recorders share the same locked counters: provider retries and verification requests are counted exactly once, without thread-local context, copied counters or a later merge step. The provider binding is restored by the reader even when a request fails. Pickling retains the label and uses the accumulator’s existing serialisation, which excludes the lock and recreates it inside the receiving process.
- stats: eth_defi.provider.rpcdb.RPCRequestStats
Shared accumulator receiving both physical totals and operation breakdowns.
- record_call(rpc_provider_domain, api_call, count=1)
Count provider attempts using this recorder’s explicit operation label.
The fallback provider invokes the same interface on an accumulator or a recorder. Delegating once keeps operation rows a partition of physical totals, including unsuccessful attempts and provider-switch verification.
- record_error(rpc_provider_domain, error_code, error_message, count=1)
Keep provider errors in the shared accumulator’s existing breakdown.
Error keys do not include an operation label. Forwarding them unchanged preserves the persisted schema and avoids counting one failure in both the phase accumulator and a separate lane accumulator.
- Parameters
- Returns
None; the shared error counter advances under its existing lock.
- Return type
None
- __init__(stats, operation)
- Parameters
stats (eth_defi.provider.rpcdb.RPCRequestStats) –
operation (str) –
- Return type
None
- class RPCUsageDatabase
Bases:
objectAppend-only DuckDB storage for JSON-RPC scan accounting.
One connection belongs to one externally serialised writer. Callers sharing a database across processes must hold their pipeline lock for the complete connection lifetime.
Open the tracking database and initialise its fixed schema.
- Parameters
path – DuckDB file path. Parent directories are created automatically.
- __init__(path)
Open the tracking database and initialise its fixed schema.
- Parameters
path (pathlib.Path) – DuckDB file path. Parent directories are created automatically.
- Return type
None
- allocate_cycle()
Allocate the next persistent cycle number.
Allocation uses both tables and must be called while the external pipeline-writer lock is held. A crash before the first row is inserted may reuse the unpersisted number on the next invocation.
- Returns
Next positive cycle number.
- Return type
- record_scan(chain, phase, cycle_started, cycle_number, stats, items_scanned, metrics=None)
Append one finished phase attempt, including failed or degraded scans.
Call and error rows are committed in the same transaction. An empty call aggregate writes a zero-count marker so the scan iteration and its item count remain visible. Unknown item counts on early failures should be passed as zero.
The all-chain phase boundary calls this after its workers have merged their counters. Legacy positional schemas remain unchanged for scanner rollback; operation labels and outcomes live in a separate detail table. A successful function return does not prove full reader coverage, so pending candidates and unavailable/overdue readers produce a degraded outcome even when the phase did not raise an exception.
- Parameters
chain (int) – EVM chain id.
phase (str) – Caller-defined scan phase, for example
lead_discovery.cycle_started (datetime.date) – Naive UTC calendar date on which the logical cycle started.
cycle_number (int) – Persistent cycle identifier shared by scanner retries.
stats (eth_defi.provider.rpcdb.RPCRequestStats) – Physical request and error counters for this attempt only.
items_scanned (int) – Non-negative number of logical items submitted during the attempt.
metrics (Optional[dict]) – Optional phase diagnostics stored only in the separate detail table.
- Return type
None
- fetch_cycle_calls(chain, cycle_started, cycle_number)
Fetch current-cycle method rows for one chain.
- fetch_daily_totals(chain, cycle_started)
Fetch daily provider totals without multiplying retry item counts.
Each cycle contributes the sum of its method rows and the maximum item count reported by any retry. Provider rows display provider-specific calls with the cycle-level item denominator.
- fetch_cycle_errors(chain, cycle_started, cycle_number)
Fetch current-cycle error totals for one chain.
- close()
Checkpoint and close the DuckDB connection explicitly.
- Return type
None
- format_rpc_usage_report(database, chain, cycle_started, cycle_number)
Format current-cycle and daily JSON-RPC usage for one chain.
The formatter is output-system agnostic: scanners may print the returned text, log it, or embed it in another report. Daily rows keep lead discovery and price scanning separate through their
phasecolumn.- Parameters
database (eth_defi.provider.rpcdb.RPCUsageDatabase) – Open tracking database.
chain (int) – EVM chain id to report.
cycle_started (datetime.date) – UTC date of the current logical cycle.
cycle_number (int) – Current persistent cycle number.
- Returns
Multi-table plain-text report.
- Return type