lightninglabs / lightninglabs/aperture
meterd: reserve prompt tokens and bound the per-request estimate
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 268
- Forks
- 78
- Avg merge
- 22h 25m
- Merged PRs (30d)
- 1
Description
Found by an adversarial review pass over #247 and deferred out of it, since #247 was already large. This is the one deferred item where a buyer can deliberately cost the seller money on a live path, so it is the first thing to pick up after that PR lands.
The reservation only covers completions
AuthorizeRequest reserves an estimate against the bundle before the request goes upstream, and the estimate is derived from max_tokens (or the configured EstimatedTokens fallback). That covers completion tokens only. Prompt tokens are debited after the fact but never reserved.
So a buyer sending max_tokens: 1 with a 100k-token prompt reserves one token and consumes a hundred thousand. Fire N of those concurrently against a nearly-empty bundle and the debit clamps at zero, which means everything past the balance is served for free. The loss is bounded by concurrency times prompt size, and it is entirely buyer-controlled.
The fix is to floor the estimate by the body we already have in hand. readBodyPrefix gives the serialized request, so something on the order of len(body)/4 is a defensible lower bound on prompt tokens, and the estimate becomes max(completionEstimate, promptFloor).
max_tokens is unbounded in the other direction
Nothing caps what a client can put in max_tokens, so a large value inflates Reserved and can make a bundle read as exhausted while it still has balance. That is self-inflicted rather than an attack on the seller, but it amplifies any reservation that later leaks, so the estimate should be capped at the bundle size.
While we are in the debit math
weightedDebitMsat computes 2 * (prompt*inRate + completion*outRate) as an intermediate. With absurd counts from a hostile or broken backend that overflows int64 and goes negative, and a negative debit is no debit at all. The response tail is otherwise well defended (escaped quotes cannot forge a usage object, and keyInObjectPosition blocks string-embedded keys), so this needs a broken upstream rather than a malicious client, but clamping the counts to something sane before the multiply is cheap belt-and-braces.
Acceptance
- The estimate reserved at authorization accounts for prompt tokens.
- The estimate is capped at the bundle size.
- Debit arithmetic cannot go negative on any input.
- Tests cover a small-
max_tokens/large-prompt request against a nearly-empty bundle, and the overflow clamp.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Locate AuthorizeRequest, readBodyPrefix, and weightedDebitMsat, then inspect the existing authorization and debit tests around those entry points. Verify that prompt tokens are included, reservations are capped by bundle size, and debit arithmetic remains non-negative for extreme inputs; add coverage for the acceptance cases described.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- backend, payments, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 56/100