Repository navigation
Conversation
call_runner takes on_payment_session, called with each session the signer signs, before the paid request goes out. A caller can link a charge to the call that caused it, including a call that fails after the signer has signed. LivePaymentSession.manifest_id is the manifest from the 402 challenge, so the session is identified without reading the signer's state.
There was a problem hiding this comment.
🟡 Changes recommended
Cancellation and signer-response validation failures can leave charged sessions unreported.
2 open findings
What changed in this PR
Adds payment-session reporting to call_runner so callers can associate signer charges with calls, including failed calls.
Changes:
- Adds an optional sync or async callback before paid requests.
- Exposes the challenge’s manifest ID without decoding signer state.
- Tests reporting, callback failures, cancellation, and manifest stability.
| File | Description |
|---|---|
| tests/test_live_runner.py | Tests payment-session callback behavior. |
| tests/test_live_payment_session.py | Tests manifest ID stability across refreshes. |
| src/livepeer_gateway/remote_signer.py | Exposes manifest_id. |
| src/livepeer_gateway/live_runner.py | Adds callback support and reporting. |
| src/livepeer_gateway/__init__.py | Exports the callback type. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Replace gathering of payment_task with a drain loop to handle cancellation more gracefully. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
NE-Build-Track/livepeer-builder-core That commit is not on |
|
@rickstaa Copilot is not really pulling its weight here either, see below. Here's a tighter version of this PR: #81 From Codex: The Copilot follow-ups add substantial complexity for cases that do not warrant special handling here. Malformed signer responses already raise exceptions and prevent the paid request; both supplied signers serialize typed responses. The callback’s value is payment attribution, particularly when the runner subsequently fails—not reporting signer errors. The cancellation fix introduces a bug: if an async callback stalls, Please keep The guarantee should be reporting successfully obtained payment sessions before dispatch. A signer can charge before its response reaches the client, so cancellation or response failure can leave a charge unreported. Shielding cannot guarantee complete accounting. Simplify the tests accordingly:
|
|
Closing in favor of #81 |

Summary
This PR lets a gateway find out what each
call_runnercall cost.call_runnertakes a new, optionalon_payment_sessioncallback. Each time the remote signer signs a payment session, the SDK calls it with that session. The session's newmanifest_idproperty names the orchestrator session the payment funds, so the gateway can match it to Clearinghouse usage records and charge the right job.Callers that don't pass the callback see no change in results, errors or streams.
Why
The signer charges when it signs a payment, not when the job succeeds. So a call can be charged and still fail: the runner errors, the payment turns out to be unusable, or the caller cancels. A gateway that bills its own users has to know which charges belong to which call, including the failed ones. Today
call_runnerdoesn't tell it.We need this for the Network Engineering SPE build track (project board). Its second milestone defines how the builder engine reports network cost per job (ISS-04). The engine records the manifest of every payment the signer signs, then matches each one to a Clearinghouse usage record, so every job shows what it cost, whether it succeeded or not. livepeer-builder-core pins this branch until it merges.
An earlier version read
AuthIDfrom the signer's state. On #74, Josh pointed out that the state is opaque and shouldn't become a public contract, and suggested ManifestID instead. This version uses ManifestID and doesn't decode the signer's state.What callers see
asyncio.wait_for, for example, still accounts for every session it signed.Known limits
RunnerSelectionCursorstill fails over after a signed payment, so one job can pay twice. Runner selection: pool size, failure classification and payment_sent on rejections #70 tracks that.This replaces #71, which was closed so the change could target a fork branch.
Test plan
pytest -W error::ResourceWarningate6d243b: 227 passed, 2 failed. Both failures are intests/test_stats_pull.pyand fail the same way onmain. The new tests cover sync and async callbacks, repeated 402s, a runner failure after payment, a refused session, an unusable payment, a raising callback, a cancelled call, andmanifest_idstaying the same across a payment refresh.