Skip to content

feat: add per-agent per-window rate limiting to record_usage#77

Merged
mikewheeleer merged 1 commit into
Agentpay-Org:mainfrom
greatest0fallt1me:feature/contracts-10-rate-limiting
Jun 24, 2026
Merged

feat: add per-agent per-window rate limiting to record_usage#77
mikewheeleer merged 1 commit into
Agentpay-Org:mainfrom
greatest0fallt1me:feature/contracts-10-rate-limiting

Conversation

@greatest0fallt1me

Copy link
Copy Markdown
Contributor

Closes #10.

Problem

record_usage enforced per-call min/max bounds but had no time-windowed rate limit — a single agent could call it unboundedly within a ledger window, inflating counters and ledger write load.

Change

A configurable per-agent fixed-window rate limit anchored to env.ledger().timestamp():

  • set_max_requests_per_window(max) / get_max_requests_per_window — per-window request cap.
  • set_rate_window_seconds(seconds) / get_rate_window_seconds — window length.
  • Per-agent DataKey::RateWindow(Address) stores (window_start, count_in_window).
  • In record_usage: roll the window forward when expired, then reject calls that would exceed the cap with RateLimitExceeded (Add settle_all to drain every service for an agent in one call #15, append-only).

Disabled by default — the limiter activates only when both the cap and window length are non-zero, so existing behaviour is preserved.

Windowing semantics

Fixed window (not sliding): the window opens at an agent's first in-window call and rolls forward as a whole once now >= window_start + window_seconds, resetting the count.

Tests

  • test_rate_limit_disabled_by_default, test_rate_limit_config_round_trips
  • test_rate_limit_rejects_over_cap_in_window (exactly-at-cap allowed, +1 → #15)
  • test_rate_limit_window_rollover_resets_count
  • test_rate_limit_is_per_agent

cargo fmt --all -- --check, cargo build, cargo test all green — 56 passed; 0 failed.

Security notes

Window arithmetic is saturating (overflow-safe). The agent cannot reset its own window early — window_start only ever advances.

Closes Agentpay-Org#10. record_usage enforced per-call min/max bounds but had no
time-windowed rate limit, so a single agent could call it unboundedly
within a ledger window. Add admin-configurable MaxRequestsPerWindow and
WindowSeconds plus per-agent RateWindow(Address) state tracking
(window_start, count). record_usage rolls the fixed window forward when
expired and rejects calls that would exceed the cap with RateLimitExceeded
(Agentpay-Org#15). Disabled by default (both settings 0), preserving current behaviour.
Window math is saturating and the agent cannot reset its own window early.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mikewheeleer mikewheeleer merged commit 590217b into Agentpay-Org:main Jun 24, 2026
1 check passed
mikewheeleer added a commit that referenced this pull request Jun 24, 2026
…e, registry, tests, docs

Reconcile enum codes (BatchTooLarge=16, AgentBlocked=17 vs RateLimitExceeded=15),
re-add dropped DataKey/EscrowError variants, rebuild test.rs from base + each PR's
tests, and update base tests for the new settle(caller,...) signature. 160 tests pass.
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.

Add per-agent, per-window rate limiting to record_usage

2 participants