Skip to content

oracle: Network-coordinated fetch scheduling#7

Open
martonp wants to merge 4 commits intomasterfrom
oracleQuotas
Open

oracle: Network-coordinated fetch scheduling#7
martonp wants to merge 4 commits intomasterfrom
oracleQuotas

Conversation

@martonp
Copy link
Contributor

@martonp martonp commented Feb 10, 2026

This PR adds network-coordinated fetch scheduling for oracle sources, so nodes in the mesh share rate-limited API quotas intelligently instead of each node fetching independently.

Source interface and quota tracking

Oracle source implementations refactored into a subpackage structure (oracle/sources/, oracle/sources/providers/, oracle/sources/utils/).

A Source interface is created that must be implemented by each source, and it includes a QuotaStatus() function, which returns the source's remaining API quota (fetches remaining, fetch limit, and reset time).

Sources fall into two categories:

  • Unlimited sources (coinpaprika, dcrdata, firo, mempool, bitcore): no API key required, QuotaStatus() returns math.MaxInt64 for remaining fetches.
  • Tracked sources (coinmarketcap, blockcypher, tatum): use a QuotaTracker that periodically reconciles against the provider's quota API. Multiple sources can share a single tracker when they share an API key, and each declares its CreditsPerRequest so the tracker can convert raw API credits into fetch counts.

Network-coordinated fetch scheduling

When multiple nodes run the same oracle sources, they should coordinate so they don't all fetch from the same rate-limited API simultaneously. The quota manager computes a networkSchedule for each source using quota data from all active peers in the mesh.

The algorithm has three steps:

  1. Sustainable rate: Each peer's quota yields a rate (fetches/sec) computed as remainingFetches / timeUntilReset, with a 10% safety margin. The network rate is the sum of all peer rates, and the sustainable period is its reciprocal, clamped between the source's MinPeriod and 1 hour.

  2. Deterministic ordering: Peers are ranked by SHA256(timeWindow, nodeID) / node_rate. The time window rotates every MinPeriod seconds so the ordering reshuffles periodically, while dividing by the node's sustainable rate biases toward nodes with higher quotas. This ordering is deterministic. Every node computes the same result from the same inputs without any leader election.

  3. Per-node timing: The first node in the ordering fetches at networkNextFetchTime. Each subsequent node waits an additional 3-second propagation delay, giving the previous node time to fetch and gossip the result before the next node attempts the same fetch.

Quota sharing protocol

Nodes share their quota information through three mechanisms:

  • Handshake on connection: When two tatanka nodes connect, they exchange quota status for all their sources via the /tatanka/quota-handshake/1.0.0 stream protocol.
  • Periodic heartbeats: Every 5 minutes, each node publishes its current quotas to a gossipsub topic. Peer quotas older than 6 minutes are expired and excluded from scheduling.
  • Oracle updates now include the quota status.

Tatankactl UI

The tatankactl CLI is replaced with an interactive bubbletea UI. In addition to the connection information that was already available, all details of the oracle's functioning can be monitored through the tool.

Move source definitions into oracle/sources/ with provider
implementations in oracle/sources/providers/ and shared utilities
in oracle/sources/utils/. This separates the source abstraction
from the oracle core logic. Also adds quota tracking for each of
the sources.
Updates the algorithm to determine when to perform the next fetch
for each source to be based on the quotas of the entire mesh. The
sustainable fetch rate of the entire network is calculated, and
the entire network can deterministically determine which node
should perform the next fetch.

Additionally, an Oracle Snapshot function is added which will allow
the admin tools to view the state of the oracle.
Add quota handshake and heartbeat protocols for sharing quota
information between tatanka nodes.
Replace the CLI-based tatankactl with an interactive bubbletea TUI.
Add oracle source status view with per-source detail screens showing
schedule, fetch order, quotas, and price/fee rate contributions.
Add aggregated data view with drill-down into individual tickers.
@dnldd
Copy link
Contributor

dnldd commented Feb 12, 2026

refactor and quota additions look good, running local tests soon. I think cmd/tatanka/.!28982!tatanka executable slipped through however. Or did you intend to commit it?

Update: local tests look good too. We might have to look at the mempool source again, it's failing all fetch attempts.

Comment on lines +54 to +64
func (cfg *QuotaTrackerConfig) verify() {
if cfg == nil {
panic("quota tracker config is nil")
}
if cfg.FetchQuota == nil {
panic("fetch quota function is required")
}
if cfg.Log == nil {
panic("logger is required")
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not consolidate config errors (errors.Join) and return it instead of panicking?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants