livepeer / livepeer/go-livepeer

Support per-capability pricing oracle selection for BYOC capabilities

Open
#3,929 0 comments 0 reactions 0 assignees View on GitHub
status: triage
Dominant language
Go
Stars
586
Forks
226
Avg merge
1d 17h
Merged PRs (30d)
19

Description

## Problem

BYOC external capabilities can express custom-currency prices today, but the pricing oracle/feed is effectively node-global and BYOC prices are snapshotted into `jobPriceInfo` at registration time. This makes it hard for an orchestrator to use different pricing policies/oracles for different capabilities or models.

This is useful for AI BYOC because different model capabilities may need different pricing policies: provider cost, observed tokens/sec, queue/utilization, target margin, and market floor can differ by model.

## Current behavior / research

Researched against `feat/remote-signer-byoc` at `a78e876ff6c97d935344643c2547d0f84d4b26dd`.

Relevant paths:

- `cmd/livepeer/starter/flags.go`: `-priceFeedAddr` is a single node-level Chainlink feed address used for custom currency conversion on `-pricePerUnit` / `-maxPricePerUnit`.
- `cmd/livepeer/starter/starter.go`: initializes one global `core.PriceFeedWatcher` from `-priceFeedAddr`.
- `core/autoconvertedprice.go`: `NewAutoConvertedPrice()` reads from global `core.PriceFeedWatcher` and updates its internal wei value when feed updates arrive.
- `core/external_capabilities.go`: BYOC capability config accepts `price_per_unit`, `price_scaling`, and `currency`, then creates an `AutoConvertedPrice`.
- `core/ai_orchestrator.go`: `RegisterExternalCapability()` calls `SetPriceForExternalCapability("default", cap.Name, cap.GetPrice())`, which stores the current price value.
- `core/livepeernode.go`: built-in capability/model prices store `*AutoConvertedPrice`, but BYOC `jobPriceInfo` stores `*big.Rat`, so feed updates are not preserved in the advertised BYOC price unless the capability is re-registered or code updates the stored value.

## Proposal

Add per-capability pricing oracle selection for BYOC capabilities. The minimal version should preserve existing registration JSON and add an optional pricing/oracle section.

Possible shape:

```json
{
"name": "openai-chat-completions/Qwen3-Coder-30B-A3B-Instruct",
"url": "http://worker:8000",
"capacity": 1,
"price_per_unit": 1,
"price_scaling": 86400,
"currency": "USD",
"pricing_oracle": {
"source": "chainlink",
"price_feed_addr": "0x...",
"policy": "competitive-v1"
}
}
```

Implementation options:

1. Keep the current fields as the default/backward-compatible path.
2. Add an oracle resolver keyed by capability name/model. For Chainlink-style feeds, deduplicate watchers by feed address.
3. Store a dynamic price handle for BYOC, not only a `*big.Rat` snapshot. Either change `jobPriceInfo` to store `*AutoConvertedPrice`/a pricing source interface, or have the update callback call `SetPriceForExternalCapability(...)` when the oracle price changes.
4. Allow offchain signed oracle records as a future source type, where the oracle emits final `wei/sec` for `orchestrator + capability + model + policy + valid_until`, signed by a configured key.
5. Keep `GetOrchestrator` / `CapabilitiesPrices` and `PriceInfoForCaps` returning the final current wei price so gateway and remote signer behavior remains simple.

## Acceptance criteria

- Existing BYOC capability registration without `pricing_oracle` continues to work.
- A single orchestrator can register capability A using one oracle/feed and capability B using a different oracle/feed.
- Feed/oracle updates change the advertised BYOC `PriceInfo` without requiring capability re-registration.
- Built-in capability pricing behavior is not regressed.
- Tests cover at least:
- two BYOC capabilities using different feed currencies/addresses,
- dynamic update propagation into advertised BYOC price,
- fallback to current node-level `-priceFeedAddr`,
- invalid/missing oracle config errors.

Contributor guide

Open the contributing guide

Research direction

Start with cmd/livepeer/starter/flags.go and starter.go, then trace pricing through core/autoconvertedprice.go, core/external_capabilities.go, core/ai_orchestrator.go, and core/livepeernode.go. Use the stated acceptance criteria to define tests for distinct feeds, dynamic advertised-price updates, node-level fallback, and invalid oracle configuration. Done means existing registrations still work while per-capability oracle selection updates BYOC PriceInfo without re-registration.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
backend, backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.