fix(remote_signer): bind live payment manifest id to auth token session id - #4006
Conversation
…on id The orchestrator's live-runner enforces SegData.ManifestID == AuthToken.SessionId for fixed live payments and rejects a mismatch with "mismatched manifest and auth token". GenerateLivePayment derived the manifest id from the request (or a fresh RandomManifestID when empty), so v0.9.0 live generation failed with 403 even though auth, pricing, the 402 challenge, and reservation all succeeded. Bind the live manifest id to the challenge's oInfo.AuthToken.SessionId for non-BYOC payments so genSegCreds emits a matching (manifestID, sessionId) pair. BYOC keeps its capability-name manifest id for shared balance tracking across streams. Adds TestGenerateLivePayment_LV2V_ManifestBoundToSessionId proving the emitted SegData.ManifestID equals the challenge session id whether the request supplies a mismatched manifest id or omits it entirely, and updates the state-validation case so the "missing manifestID" guard is exercised only when no session id is available to bind to.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The native (non-BYOC) live payment path types fixed-price single-shot live-runner generations as "lv2v" and, when no explicit unit count is supplied, always recomputes pixels as a continuous 720p30 stream estimate (720*1280*30*60 = 1,658,880,000 pixels). Multiplying the orchestrator's per-request fixed price (advertised with PixelsPerUnit == 1) by that volume inflates the fee ~1.66e9x, so newBalanceUpdate/StageUpdate needs billions of tickets and GenerateLivePayment fails the max-100 guard (observed e2e: HTTP 400 "numTickets 2721947758 exceeds maximum of 100"). The v0.9.0 live-runner orchestrator debits exactly one unit for a fixed generation (server/ai_http.go reservePaidLiveRunnerSession -> AccountPayment units:1, requiring ExpectedPrice.PixelsPerUnit == 1). Honor an explicit req.InPixels on the lv2v path instead of unconditionally overriding it with the 720p estimate, so the gateway can charge exactly one unit (inPixels:1) and the fee equals the fixed per-request price (numTickets ~1). The continuous live-video path sends no InPixels and is unchanged. Sibling of the manifest-id fix on the same GenerateLivePayment path. Note: this is inert until the gateway sends inPixels:1 for fixed-unit (price_info.unit == "fixed") live runners.
|
Stacked a second fix on the same Second bug:
|
|
Closing as superseded — this PR is built on the wrong lineage. Its base is
Both effects this PR re-implements as Do not reopen or rebase (rebasing onto |
Summary
The remote signer's
POST /generate-live-paymenthandler(
server/remote_signer.go→GenerateLivePayment) set the segmentManifestIDfrom the request (req.ManifestID), falling back to a freshcore.RandomManifestID()when empty. The orchestrator's live-runner (v0.9.0)enforces
SegData.ManifestID == AuthToken.SessionIdfor fixed livepayments and rejects any mismatch with
403 mismatched manifest and auth token.Result: native live generation failed at the final hop even though auth,
per-cap pricing, payment mint, the 402 challenge, and reservation all
succeeded.
Fix
For non-BYOC (live) payments, bind the manifest id to the challenge's
oInfo.AuthToken.SessionId(the session id echoed back from the 402 challengeOrchestratorInfo).genSegCredsthen emits a matching(manifestID, sessionId)pair, so the orchestrator's check passes.(
AuthToken.GetSessionId() != ""); otherwise behavior is unchanged(nil-safe getter).
for shared balance tracking across streams.
(continuing) requests stay tied to the same id — the reason the previous
"missing manifestID with state" guard existed. That guard now only fires when
there is no session id to bind to.
Bug location (exact)
server/remote_signer.go,GenerateLivePayment:manifestID := req.ManifestID(~L401) then
manifestID = string(core.RandomManifestID())(~L419) — themanifest id was never tied to
oInfo.AuthToken.SessionId, whichgenSegCredsalso emits intoSegData.AuthToken(server/segment_rpc.goL693/L700).
Scope
Single, self-contained change in
GenerateLivePayment. The manifest id is notthreaded through additional call sites;
streamParams.ManifestIDalready flowsinto
genSegCreds, so setting the variable is sufficient.Test plan
TestGenerateLivePayment_LV2V_ManifestBoundToSessionId: decodes thereturned
segCredsand assertsSegData.ManifestID == AuthToken.SessionIdboth when the request supplies a different manifest id and when it omits
one entirely.
TestGenerateLivePayment_StateValidationErrors"missing manifestid with state" case to use an empty
AuthTokenso the guard is stillexercised (it now only applies when no session id is available).
go test ./server/ -run TestGenerateLivePayment— runs in CI. (Could notrun locally: this environment lacks go-livepeer's patched ffmpeg toolchain
(
~/compiled), so thelpmscgo build fails independently of this change.gofmt -econfirms both files parse and are formatted.)Deploy (for John / pymthouse)
Not deployed here. The pymthouse signer image
(
docker/signer-dmz/Dockerfile.signer) is builtFROM livepeer/go-livepeer:sha-….After this merges, rebuild the signer image from the updated
feat/remote-signer-byoc-v2(or cherry-pick this commit) and repointpymthouse-signer-testto the new tag. No orchestrator/infra change required.Made with Cursor