Skip to content

Implement a adaptive query cost governor that tracks per-wallet database query cost and throttles wallets exceeding the rolling budget #755

Description

@Chucks1093

Summary

The API has no per-wallet database cost controls. A single wallet making expensive paginated queries, deep search requests, or large analytics calls can saturate the connection pool and degrade the experience for all users. This issue implements a query cost governor that assigns a cost unit to each query based on its estimated database impact, tracks per-wallet rolling spend in Redis, and throttles wallets that exceed the budget with a 429 response and a backoff window.

Scope

1. Query cost model

  • Define a cost map in configuration: each route pattern maps to a cost unit (e.g. GET /creators = 1, GET /creators/:id/holders = 3, GET /search = 5, GET /creators/:id/history = 2)
  • Parameterised costs: limit query param multiplies the base cost (e.g. limit=100 on a cost-3 route = cost 30)
  • Cost map configurable via environment without code changes

2. Rolling budget tracking

  • On each authenticated request, before query execution, read the wallet's rolling spend from Redis key qcost:{walletAddress} (a sorted set of { cost, timestamp } entries)
  • Evict entries older than the rolling window (default 60 seconds) from the sorted set
  • If the sum of remaining entries plus the current request cost exceeds the budget (default 200 units/60s), return 429 query_budget_exceeded with Retry-After set to when the oldest entry will expire
  • Otherwise, append the current cost entry and proceed

3. Cost response headers

  • Add X-Query-Cost: {cost} and X-Query-Budget-Remaining: {remaining} headers to every authenticated response
  • On throttled responses include X-Query-Budget-Reset: {unix_timestamp} indicating when the budget resets

4. Admin override

  • Admin wallets (configurable list) bypass the governor entirely
  • A POST /internal/qcost/reset/:walletAddress endpoint (internal network only) allows operators to clear a wallet's budget immediately

5. Integration tests

  • Send requests summing to exactly the budget — assert all succeed
  • Send one request that pushes the total over the budget — assert 429 with correct Retry-After
  • Verify X-Query-Cost and X-Query-Budget-Remaining headers on each response
  • Wait for the rolling window to expire — assert requests succeed again
  • Admin wallet sends requests exceeding the budget — assert no throttling

Acceptance Criteria

  • Cost map applied correctly per route with limit param multiplier
  • Rolling budget tracked in Redis with window eviction
  • Budget exceeded returns 429 with Retry-After and X-Query-Budget-Reset
  • Cost and remaining budget headers on every authenticated response
  • Admin wallets bypass the governor
  • Budget resets correctly after the rolling window

ETA: 24 hours


Coordinate on Telegram

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardThird CampaignCampaign: Third Campaign

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions