Repository navigation
ledger: serve RPC WIT on /rpc - #262
Merged
Merged
Conversation
rvolosatovs
commented
Oct 19, 2026
rvolosatovs
commented
Oct 19, 2026
rvolosatovs
commented
Oct 19, 2026
rvolosatovs
force-pushed
the
roman/ledger/utxo-wit
branch
13 times, most recently
from
October 20, 2026 11:43
0b523f4 to
6a7e51b
Compare
rvolosatovs
marked this pull request as ready for review
October 20, 2026 11:47
This was referenced Oct 20, 2026
Closed
rvolosatovs
force-pushed
the
roman/ledger/utxo-wit
branch
from
October 20, 2026 15:01
6a7e51b to
245af13
Compare
`Contract::utxos` treated every exported instance exporting anything named `utxo` as a UTXO instance, while `get_utxo_typed` then rejects it unless that export is a resource, and the typed UTXO imports are already matched only on a `utxo` resource. Require the export to be a resource, so an instance exporting a `utxo` type of another kind, or a `utxo` function, is not listed as a UTXO instance. Assisted-by: anthropic:claude-opus-5-5 Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
`headers-accept` is pinned to the head of maxcountryman/headers-accept#24, on top of the unreleased upstream main, whose media range matching ignores `q` when comparing parameters, so `Accept: text/plain;q=0.9` matches the `text/plain; charset=UTF-8` the ledger responds with. The PR additionally compares charset values case-insensitively, so `charset=utf-8` matches it too. The revision is fetched from the upstream repository, which holds the PR head, rather than from the fork it was pushed to. Assisted-by: anthropic:claude-opus-5-5 Assisted-by: anthropic:claude-fable-5-1 Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
`GET /rpc` returns the `starstream:ledger` package describing the ledger queries `POST /rpc` accepts. `GET /rpc?index=INDEX`, optionally with `&transaction=DIGEST`, instead returns a `starstream:ledger` package holding only a `utxo` interface for that unspent output: its UTXO's methods as the freestanding functions `/rpc` invokes. Each takes the output reference (`transaction`, `index`) followed by the method parameters, which are prefixed with `arg-` so the names never clash. `index` is a `u32` and `transaction` a digest, defaulting to the genesis block. Repeating either is rejected with 400, and an empty query (`GET /rpc?`, `GET /rpc?&`) is treated as no query. Both are served as WIT text by default, or encoded as Wasm on `Accept: application/wasm`, so clients can generate wRPC bindings without decoding the contract themselves. `HEAD /rpc` returns the headers of the same response. The `GET` and `HEAD` handlers of `/contracts`, `/transactions` and `/rpc` are merged into one handler each, generic over `HEAD`, which omits the body but keeps `Content-Length`. The UTXO WIT of every exported instance that exports a `utxo` resource is built once, at publish, and served from memory, keyed by export name as `POST /rpc` resolves it. It is converted from the component types the publish validation already computes into a fresh `Resolve` holding only the ledger package. The contract's WIT is never decoded with wit-parser, whose decoder overflows the stack, aborting the node, on valid components whose imported packages depend on each other. Only the shapes the compiler produces are handled: synchronous methods whose parameters and results are booleans, integers, and options, results and tuples of them. The `utxo` interface therefore defines no named types and depends on no other package. Publishing now rejects with 400 Wasm that is not a component and contracts with UTXO methods taking or returning anything else, such as a UTXO handle, naming the offending parameter or result. The ledger package is encoded to Wasm by a build script, only with the `server` feature, which is also the only one pulling in the script's `anyhow` build dependency. The ledger client gains `build_utxo_wit_request` and `Client::get_utxo_wit`, which takes an optional `Accept` media type and returns the raw body. GET request builders share a helper. `TransactionInput` gains `genesis` and `new` constructors. The CLI gains `ledger utxo wit [--transaction DIGEST] <INDEX>`, printing a UTXO's WIT in the shape `ledger utxo call` invokes it. `ledger utxo call` now resolves the method type from the Wasm-encoded UTXO WIT instead of downloading and decoding the whole contract. The CLI e2e test now starts the ledger with the outputs of the simulated `example` call as genesis, prints the UTXO's WIT and calls one of its methods. The ledger tests cover `GET /rpc`, the UTXO WIT of a compiled contract using options, results and tuples with parameters named `index` and `transaction`, rejecting a UTXO method taking a UTXO, and publishing a component whose imported packages form a cycle. Their `serve` helper no longer publishes the contract itself. Assisted-by: anthropic:claude-opus-5-5 Assisted-by: anthropic:claude-fable-5-1 Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs
force-pushed
the
roman/ledger/utxo-wit
branch
from
October 21, 2026 15:07
245af13 to
57a9fd4
Compare
Contributor
Author
|
same as #268 (comment) |
rvolosatovs
added a commit
that referenced
this pull request
Oct 21, 2026
Add `docs/ledger.md`, a usage-focused page for the development ledger:
- a quick start that compiles the `require_hash_preimage` example, runs
a
node with a genesis output created by `create-hash 42`, and spends it
with
`consume-hash`, first with a wrong preimage (traps, nothing submitted)
and
then with the right one;
- `starstream node` flags and the genesis TOML format;
- the `starstream ledger` client commands, including the `account`,
`admin`,
`block get` and `network` queries from #271;
- the ledger model: digests, accounts, nonces, UTXOs and blocks;
- the HTTP API: `POST /rpc` (COSE envelopes and wRPC queries against
`ledger.wit`, plus UTXO method calls), `GET /rpc` (ledger and per-UTXO
WIT,
from #262), `GET /contracts/<digest>`, `GET /transactions/<digest>`, the
envelope format and the error status codes.
A warning near the top says this is not a secure ledger: only genesis
outputs
need authorization, proofs are not checked, and state lives in memory.
`docs/cli.md` now has a short `starstream node` / `starstream ledger`
section
that links to the new page.
Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Serve invocation WIT on
GET /rpcClients can now fetch WIT describing what
POST /rpcaccepts and generate wRPC bindings from it, without having to decode contracts themselves.GET /rpcreturns thestarstream:ledgerpackage that describes the ledger queries.GET /rpc?index=INDEX[&transaction=DIGEST]returns astarstream:ledgerpackage with only autxointerface for that unspent output. Its functions are the UTXO's methods. Eachtakes the output reference (
transaction,index) followed by the method parameters, which get anarg-prefix so names can't clash. Iftransactionis omitted, it refers tothe genesis block. Repeating a parameter returns 400, and an empty query (
?,?&) counts as no query.Accept: application/wasm.HEAD /rpcis supported. TheGET/HEADhandlers for/contracts,/transactionsand/rpcaremerged into one handler each, generic over
HEAD.utxoresource is built once and served from memory. It is converted from the component types thatpublish validation already computes, so the contract's WIT is never decoded with wit-parser. That decoder overflows the stack on valid components whose imported packages depend on
each other, which would abort the node.
build_utxo_wit_requestandClient::get_utxo_wit.TransactionInputgainsgenesisandnewconstructors.ledger utxo wit [--transaction DIGEST] <INDEX>.ledger utxo callnow gets the method type from this endpoint instead of downloading and decoding the wholecontract.
Behaviour changes
options, results and tuples of those (e.g. a UTXO handle). The error names the offending parameter or result. These are the only shapes the compiler currently produces: structs and
enums in UTXO method signatures don't componentize yet.
Contract::utxosnow treats an instance as a UTXO instance only if itsutxoexport is a resource. This matches whatget_utxo_typedalready required.Dependency pins (temporary)
headers-acceptis pinned to Match charset parameter values case-insensitively maxcountryman/headers-accept#24, soAcceptmatching ignoresqand compares charsets case-insensitively. Switch back once it's merged andreleased.
Tests
examplecall as genesis, prints the UTXO's WIT and calls one of its methods.GET /rpcand the UTXO WIT of a compiled contract using options, results and tuples, with parameters namedindexandtransaction. They also check thata UTXO method taking a UTXO is rejected, and that a component whose imported packages form a cycle publishes.