TL;DR
Prototype a standalone Go service that owns captive Core on its own hardware and streams ledgers to RPC over WebSocket or gRPC. Measure whether a network stream can feed ingest as fast as the local subprocess pipe does today. If it can, Core's RAM, CPU, and disk load leave the RPC box entirely, and one Core service can feed multiple RPC instances.
Why
Captive Core runs as a subprocess on the RPC box. It consumes RAM and writes to disk on the same hardware that has to ingest each ledger inside the Phase 3 budget (80 ms). Current benchmarks are replaying synthetic ledgers, this PoC is done in anticipation of the risk of core contending for hardware with RPC.
How RPC consumes Core today
The full-history path consumes Core through ledgerbackend.LedgerStream — one method, RawLedgers(ctx, Range, ...), yielding raw XDR bytes per ledger. The production implementation opens a local captive Core subprocess (cmd/stellar-rpc/internal/fullhistory/daemon.go:470, ledgerbackend.NewCaptiveCoreStream); the stream owns Core's lifecycle. This interface is the seam: a remote implementation of LedgerStream slots in without touching ingest.
The service
A Go server that owns captive Core:
- Starts and supervises captive Core on its own hardware with its own NVMe.
- Maintains a retention buffer of ~10,000 ledgers, written to disk.
- Streams new ledgers to every subscriber over WebSocket or gRPC. A subscriber asks for the tip, or for a specific ledger if it fell behind. Too far behind returns an error — with the retention window sized right this does not happen, since RPC v2 runs near the tip.
The assumption the PoC exists to test: the network roundtrip may not cost what it looks like. With a streaming transport the server writes bytes as Core produces the ledger, so the consumer does not wait for the whole ledger to materialize before it starts ingesting. If per-ledger delivery latency stays within the local pipe's envelope, the architecture works.
What it buys beyond latency
- Removes Core from RPC's RAM and CPU budget entirely — the OOM class of failure leaves the box.
- One Core service feeds multiple RPC instances; fewer Core instances lower the fleet cost.
Residual risk
The query path stays on the RPC box. Moving Core removes Core's resource pressure, but query load still competes with ingest — that side is the companion status-query PoC.
Done when
A prototype service streams ledgers to an RPC instance implementing LedgerStream over the network, a Phase 3-style run and the results support a go/no-go recommendation on the architecture.
Related
TL;DR
Prototype a standalone Go service that owns captive Core on its own hardware and streams ledgers to RPC over WebSocket or gRPC. Measure whether a network stream can feed ingest as fast as the local subprocess pipe does today. If it can, Core's RAM, CPU, and disk load leave the RPC box entirely, and one Core service can feed multiple RPC instances.
Why
Captive Core runs as a subprocess on the RPC box. It consumes RAM and writes to disk on the same hardware that has to ingest each ledger inside the Phase 3 budget (80 ms). Current benchmarks are replaying synthetic ledgers, this PoC is done in anticipation of the risk of core contending for hardware with RPC.
How RPC consumes Core today
The full-history path consumes Core through
ledgerbackend.LedgerStream— one method,RawLedgers(ctx, Range, ...), yielding raw XDR bytes per ledger. The production implementation opens a local captive Core subprocess (cmd/stellar-rpc/internal/fullhistory/daemon.go:470,ledgerbackend.NewCaptiveCoreStream); the stream owns Core's lifecycle. This interface is the seam: a remote implementation ofLedgerStreamslots in without touching ingest.The service
A Go server that owns captive Core:
The assumption the PoC exists to test: the network roundtrip may not cost what it looks like. With a streaming transport the server writes bytes as Core produces the ledger, so the consumer does not wait for the whole ledger to materialize before it starts ingesting. If per-ledger delivery latency stays within the local pipe's envelope, the architecture works.
What it buys beyond latency
Residual risk
The query path stays on the RPC box. Moving Core removes Core's resource pressure, but query load still competes with ingest — that side is the companion status-query PoC.
Done when
A prototype service streams ledgers to an RPC instance implementing
LedgerStreamover the network, a Phase 3-style run and the results support a go/no-go recommendation on the architecture.Related