live runner: metered session dies after ~600 tickets because ticket params are never rotated
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 76/100
調査の方向性
src/livepeer_gateway/remote_signer.py で send_payment()、_payment_request()、run_payments() を読み始め、それらの動作を、ここで説明されているレスポンスの詳細およびリフレッシュフローと比較してください。セッションの失敗を再現するには live-runner-test/realtime_transcription_soak.py を使用してください。成功した支払いによってチケットパラメーターが最新に保たれるか、無効な送信者 nonce から回復し、長時間のセッションが nonce 上限で終了しなくなれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Summary
A metered live-runner session dies after ~600 signed tickets because the SDK reuses the ticket params from the original 402 challenge for the session's whole life. The orchestrator's recipient caps distinct sender nonces per recipientRand at 600 (pm/recipient.go:26, maxSenderNonces), so once that many tickets have been signed against one params set, every further payment is rejected:
HTTP 400 ... body='invalid ticket senderNonce: too many values sender=0x491F...E0DB nonce=611'
The SDK retries the same doomed nonce sequence, the orchestrator releases the session a few seconds later, and the stream ends.
How fast this happens is set by the orchestrator's ticketEV, not by anything the client controls: tickets per payment is fee / ticketEV. Measured against two orchestrators serving livepeer-example/realtime-transcription at the same price (73562861230 wei/s):
| orch | faceValue | winProb | ticketEV | tickets/payment | 600 reached after |
|---|---|---|---|---|---|
0xdc28F2… |
1.196e15 | 8.361e-04 | 1e12 wei | 1.0 | ~600 payments (~30 min) |
0x9727b4… |
1.196e15 | 8.361e-06 | 1e10 wei | 30.4 | ~20 payments (~60 s) |
Both configurations are legal. Payment cadence is irrelevant: total tickets is spend / ticketEV however you batch them.
Root cause
src/livepeer_gateway/remote_signer.py (same on main and rs/live-runner-session-payments):
send_payment()POSTs to the session payment URL and discards the response (_post_empty, line 273). go-livepeer returnsPaymentResult{Info: oInfo}on every successful payment (server/ai_http.go:569), and thatOrchestratorInfocarries freshTicketParamswith a new seed — i.e. a newrecipientRandthat would reset the nonce map._payment_request()always sends"orchestrator": self._challenge.payment_params, the params from the initial 402, for the entire session.run_payments()treats any 4xx except 408/429 as fatal, so the nonce error stops funding instead of refreshing.
Refresh is wired up, but only for one trigger: the signer returns HTTP 480 when it knows params expired, raising SignerRefreshRequired → POST /refresh-payment. The 600-nonce cap is a recipient-side limit the signer cannot see, so it never fires. That is why the 1e12 ticketEV orchestrator survives: its params expire (40 blocks) and get refreshed before 600 tickets accumulate. It is timing, not correctness — a long enough session there fails identically.
Fix
- Preferred: consume
PaymentResult.Info.TicketParamsfrom each successful payment and use it for the next cycle. Matches what the orchestrator already sends and is safe at anyticketEV. - Minimum: treat
invalid ticket senderNonceliketicketparams expired— call/refresh-paymentand retry. go-livepeer's own gateway does exactly this (server/ai_process.go:1556,isInvalidTicketSenderNonce).
Reproduction
24h WebSocket soak of livepeer-example/realtime-transcription, one held session streaming 16 kHz PCM, signer at a $0.50/hour cap:
- against the
1e10ticketEV orchestrator: 200 sessions in 5.2h, lifetimes median 87s / min 86s / max 88s, first payment failure at a constant +67s, 1,182 payment failures, 197 forced reconnects. Deterministic, not flaky. - against the
1e12ticketEV orchestrator: 1 session, unbroken 5.17h, 4TicketParams expiredfailures, all self-recovered.
The socket itself never faulted in either lane: 0 stalls, 0 transcript gaps, 0 socket errors across 9.9h of streaming. The only failure mode is payments.
Harness: live-runner-test/realtime_transcription_soak.py.
- 主要言語
- Python
- スター
- 1
- フォーク
- 8
- PR マージ指標
- 30日以内にマージされた PR はありません
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
livepeer/livepeer-python-gateway のほかの issue
-
call_runner rejects a top-level JSON array, so a runner cannot pass one through対応中かも @rickstaa が 58 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
livepeer/livepeer-python-gateway#64 · コメント 1 件 ·
-
Align pricing terminology: pixels_per_unit -> pricing_unit_size (track go-livepeer #3942)再び着手できるかも このイシューのプルリクエストはマージされずにクローズされました。 オープンImprovement
難易度 1/5 1時間未満 初心者へのやさしさ 68/100
livepeer/livepeer-python-gateway#27 · コメント 1 件 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
-
trickle_publisher: `_resolve_next_seq` fallback drops first video segment + logs noisy warning再び着手できるかも このイシューのプルリクエストはマージされずにクローズされました。 オープン
難易度 1/5 1時間未満 初心者へのやさしさ 70/100
livepeer/livepeer-python-gateway#12 · コメント 1 件 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 22/100
livepeer/livepeer-python-gateway#74 · コメント 3 件 ·
livepeer/livepeer-python-gateway の issue をすべて見る
似ている issue
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
jbacalso24/mimry#291 ·
メンテナーはふだん 1 日以内に返信
-
good first issue
難易度 2/5 1時間未満 初心者へのやさしさ 82/100
eli-alvarado/us-watchlist-alerts#14 ·
メンテナーはふだん 1 日以内に返信
-
from-review-extraction python severity:nit
難易度 2/5 1〜3時間 初心者へのやさしさ 80/100
LearningCircuit/local-deep-research#7462 ·
メンテナーはふだん 2 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
cathrynlavery/diagram-design#441 ·
メンテナーはふだん 2 日以内に返信
-
[Cleanup] Include the public header in work_split.cpp対応中かも @blozano-tt が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
tenstorrent/tt-metal#60850 ·
メンテナーはふだん 1 日以内に返信