Skip to content

Commit c74ca1d

Browse files
seanhancaclaude
andauthored
fix(live-runner): per-signer payment type on the LR path (dual-path sibling to #46) (#47)
Sibling to #46. #46 gives the **BYOC** payment path a per-signer dual-path; this gives the **Live Runner** payment path the same, so selecting an LR runner doesn't break payment on the default (Daydream) signer. ## The bug `_get_runner_payment` (live_runner.py) hardcoded `type="live"` for every non-scope runner. `signer.daydream.live` only accepts `lv2v` → **`400 invalid job type`** → LR payment fails. The `lr-gateway` `lv2v` patch only fixed the isolated sidecar; the gateway itself was still broken for LR + Daydream. Without this, the transparent-routing plan's **Scenario 1 (Daydream + LR) breaks**. ## The fix - Canonical `_payment_type_for_signer` moved to **`remote_signer.py`** (the module that owns `LivePaymentSession`) so **both** payment paths share it and LR does **not** import the soon-deprecated `byoc.py`. Legacy Daydream → `lv2v`; modern signers → `byoc`. - `_get_runner_payment`: Scope/LV2V stays `lv2v`; every other runner uses the per-signer switch. Two files, +28/−2. Both compile. ## Verified Generalizes the exact fix proven on-chain via the lr-gateway `lv2v` patch: LR single-shot + Daydream signer → `Payment tickets processed, totalTickets=1` on Arbitrum. ## Follow-up Once #46 merges, `byoc.py`'s local `_payment_type_for_signer` copy should import this canonical one (trivial dedup) — the two PRs touch disjoint files so they merge without conflict. ## Test - [ ] `py_compile` (passes locally) - [ ] LR + Daydream signer → `type:lv2v` → ticket redeems (the Scenario-1 gate) - [ ] LR + modern signer → `type:byoc` (gated on the pymthouse upstream fix + orch byoc-single-shot verification) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 4e46379 commit c74ca1d

2 files changed

Lines changed: 28 additions & 2 deletions

File tree

src/livepeer_gateway/live_runner.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
GetPaymentResponse,
2222
LivePaymentSession,
2323
_freeze_headers,
24+
_payment_type_for_signer,
2425
get_signer_info,
2526
)
2627

@@ -737,10 +738,19 @@ async def _get_runner_payment(
737738
signer_url: str,
738739
signer_headers: Optional[dict[str, str]],
739740
) -> tuple[LivePaymentSession, GetPaymentResponse]:
741+
# Scope/LV2V is a live-video job → always "lv2v". Every other runner (single-shot
742+
# fal/tool caps) pays via the per-signer dual-path: legacy Daydream → "lv2v",
743+
# modern signers → "byoc". The old hardcoded "live" was rejected by the Daydream
744+
# signer ("invalid job type"), breaking LR payment on the default signer.
745+
payment_type = (
746+
"lv2v"
747+
if runner is not None and runner.app == "live-video-to-video/scope"
748+
else _payment_type_for_signer(signer_url)
749+
)
740750
session = LivePaymentSession(
741751
signer_url=signer_url,
742752
signer_headers=signer_headers,
743-
type="lv2v" if runner is not None and runner.app == "live-video-to-video/scope" else "live",
753+
type=payment_type,
744754
payment_params=challenge.payment_params,
745755
manifest_id=challenge.manifest_id,
746756
orchestrator_url=challenge.orchestrator_url,

src/livepeer_gateway/remote_signer.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
import ssl
99
from dataclasses import dataclass
1010
from functools import lru_cache
11-
from typing import Any, Optional
11+
from typing import Any, Literal, Optional
1212
from urllib.error import HTTPError, URLError
13+
from urllib.parse import urlparse
1314
from urllib.request import Request, urlopen
1415

1516
import aiohttp
@@ -19,6 +20,21 @@
1920
from .errors import LivepeerGatewayError, PaymentError, SignerRefreshRequired
2021
_LOG = logging.getLogger(__name__)
2122

23+
_LEGACY_DAYDREAM_SIGNER_HOST = "signer.daydream.live"
24+
25+
26+
def _payment_type_for_signer(signer_url: str) -> Literal["byoc", "lv2v"]:
27+
"""Select the payment payload shape for the target signer.
28+
29+
Legacy Daydream signer (signer.daydream.live) accepts only type:"lv2v";
30+
modern signers (pymthouse DMZ, …) accept type:"byoc". Shared by the BYOC and
31+
Live Runner payment paths so both speak the dialect their signer understands.
32+
"""
33+
hostname = (urlparse(signer_url).hostname or "").lower()
34+
if hostname == _LEGACY_DAYDREAM_SIGNER_HOST:
35+
return "lv2v"
36+
return "byoc"
37+
2238
@dataclass(frozen=True)
2339
class GetPaymentResponse:
2440
payment: str

0 commit comments

Comments
 (0)