feat: support custom stores via trait interface (#67)
Home /
TxPipe /
hollow
May 11, 11-12 PM (0)
May 11, 12-1 PM (0)
May 11, 1-2 PM (0)
May 11, 2-3 PM (0)
May 11, 3-4 PM (0)
May 11, 4-5 PM (0)
May 11, 5-6 PM (0)
May 11, 6-7 PM (0)
May 11, 7-8 PM (0)
May 11, 8-9 PM (0)
May 11, 9-10 PM (0)
May 11, 10-11 PM (0)
May 11, 11-12 AM (0)
May 12, 12-1 AM (0)
May 12, 1-2 AM (0)
May 12, 2-3 AM (0)
May 12, 3-4 AM (0)
May 12, 4-5 AM (0)
May 12, 5-6 AM (0)
May 12, 6-7 AM (0)
May 12, 7-8 AM (0)
May 12, 8-9 AM (0)
May 12, 9-10 AM (0)
May 12, 10-11 AM (0)
May 12, 11-12 PM (0)
May 12, 12-1 PM (0)
May 12, 1-2 PM (0)
May 12, 2-3 PM (0)
May 12, 3-4 PM (0)
May 12, 4-5 PM (0)
May 12, 5-6 PM (0)
May 12, 6-7 PM (0)
May 12, 7-8 PM (0)
May 12, 8-9 PM (0)
May 12, 9-10 PM (0)
May 12, 10-11 PM (0)
May 12, 11-12 AM (0)
May 13, 12-1 AM (0)
May 13, 1-2 AM (0)
May 13, 2-3 AM (0)
May 13, 3-4 AM (0)
May 13, 4-5 AM (0)
May 13, 5-6 AM (0)
May 13, 6-7 AM (0)
May 13, 7-8 AM (0)
May 13, 8-9 AM (0)
May 13, 9-10 AM (0)
May 13, 10-11 AM (0)
May 13, 11-12 PM (0)
May 13, 12-1 PM (0)
May 13, 1-2 PM (0)
May 13, 2-3 PM (0)
May 13, 3-4 PM (0)
May 13, 4-5 PM (0)
May 13, 5-6 PM (0)
May 13, 6-7 PM (0)
May 13, 7-8 PM (0)
May 13, 8-9 PM (0)
May 13, 9-10 PM (0)
May 13, 10-11 PM (0)
May 13, 11-12 AM (0)
May 14, 12-1 AM (0)
May 14, 1-2 AM (0)
May 14, 2-3 AM (0)
May 14, 3-4 AM (0)
May 14, 4-5 AM (0)
May 14, 5-6 AM (0)
May 14, 6-7 AM (0)
May 14, 7-8 AM (0)
May 14, 8-9 AM (0)
May 14, 9-10 AM (0)
May 14, 10-11 AM (0)
May 14, 11-12 PM (0)
May 14, 12-1 PM (0)
May 14, 1-2 PM (0)
May 14, 2-3 PM (0)
May 14, 3-4 PM (0)
May 14, 4-5 PM (0)
May 14, 5-6 PM (0)
May 14, 6-7 PM (0)
May 14, 7-8 PM (0)
May 14, 8-9 PM (0)
May 14, 9-10 PM (0)
May 14, 10-11 PM (0)
May 14, 11-12 AM (0)
May 15, 12-1 AM (0)
May 15, 1-2 AM (0)
May 15, 2-3 AM (0)
May 15, 3-4 AM (0)
May 15, 4-5 AM (0)
May 15, 5-6 AM (0)
May 15, 6-7 AM (0)
May 15, 7-8 AM (0)
May 15, 8-9 AM (0)
May 15, 9-10 AM (0)
May 15, 10-11 AM (0)
May 15, 11-12 PM (1)
May 15, 12-1 PM (1)
May 15, 1-2 PM (0)
May 15, 2-3 PM (1)
May 15, 3-4 PM (1)
May 15, 4-5 PM (0)
May 15, 5-6 PM (0)
May 15, 6-7 PM (0)
May 15, 7-8 PM (0)
May 15, 8-9 PM (0)
May 15, 9-10 PM (0)
May 15, 10-11 PM (0)
May 15, 11-12 AM (0)
May 16, 12-1 AM (0)
May 16, 1-2 AM (0)
May 16, 2-3 AM (0)
May 16, 3-4 AM (0)
May 16, 4-5 AM (0)
May 16, 5-6 AM (0)
May 16, 6-7 AM (0)
May 16, 7-8 AM (0)
May 16, 8-9 AM (0)
May 16, 9-10 AM (0)
May 16, 10-11 AM (0)
May 16, 11-12 PM (0)
May 16, 12-1 PM (1)
May 16, 1-2 PM (0)
May 16, 2-3 PM (3)
May 16, 3-4 PM (0)
May 16, 4-5 PM (0)
May 16, 5-6 PM (0)
May 16, 6-7 PM (0)
May 16, 7-8 PM (0)
May 16, 8-9 PM (0)
May 16, 9-10 PM (0)
May 16, 10-11 PM (0)
May 16, 11-12 AM (0)
May 17, 12-1 AM (0)
May 17, 1-2 AM (0)
May 17, 2-3 AM (0)
May 17, 3-4 AM (0)
May 17, 4-5 AM (0)
May 17, 5-6 AM (0)
May 17, 6-7 AM (0)
May 17, 7-8 AM (0)
May 17, 8-9 AM (0)
May 17, 9-10 AM (0)
May 17, 10-11 AM (0)
May 17, 11-12 PM (0)
May 17, 12-1 PM (0)
May 17, 1-2 PM (0)
May 17, 2-3 PM (0)
May 17, 3-4 PM (0)
May 17, 4-5 PM (0)
May 17, 5-6 PM (0)
May 17, 6-7 PM (0)
May 17, 7-8 PM (0)
May 17, 8-9 PM (0)
May 17, 9-10 PM (0)
May 17, 10-11 PM (0)
May 17, 11-12 AM (0)
May 18, 12-1 AM (0)
May 18, 1-2 AM (0)
May 18, 2-3 AM (0)
May 18, 3-4 AM (0)
May 18, 4-5 AM (0)
May 18, 5-6 AM (0)
May 18, 6-7 AM (0)
May 18, 7-8 AM (0)
May 18, 8-9 AM (0)
May 18, 9-10 AM (0)
May 18, 10-11 AM (0)
May 18, 11-12 PM (0)
8 commits this week
May 11, 2026
-
May 18, 2026
Merge branch 'main' of github.com:txpipe/balius into feat/allow-custom-stores
fix: decode BigUInt values that fit in u64; strengthen wire-compat tests
Three improvements from PR review: 1. **BigUInt → u64 when it fits** (`convert.rs::unwrap_u64`). Previously any `BigUInt` variant unconditionally produced `ConvertError::Overflow`, even for values well within u64 range. u5c is free to encode positive values as `BigUInt(bytes)` instead of `Int(i64)` regardless of size, so the strict behavior halted workers on legitimate data. The converter now decodes BigUInt's big-endian byte representation (trimming leading zeros) and returns `Overflow` only when the value truly exceeds u64::MAX. Negative values and `BigNInt` still halt. 2. **Datum payload assertion** in `balius-core/tests/u5c_v017_wire_compat.rs::wire_compat_tx_output_roundtrips_via_017`. The test constructed a `BoundedBytes` payload but never asserted it after decode — a regression where hash/CBOR survive but payload mapping drifts would have gone undetected. 3. **Datum & WitnessSet roundtrip coverage** in `balius-runtime::ledgers::u5c::convert::tests`. The `roundtrip_opt` helper assumes Datum and WitnessSet share an identical wire format between utxorpc-spec 0.17 and 0.18 — a load-bearing assumption that was exercised only with `None` inputs. Two new tests round-trip populated values (datum with a BoundedBytes payload, witness set with both a VKey witness and a plutus datum) through `convert_tx_output` / `convert_tx` and decode under 0.17 prost. If 0.18 ever diverges on these types the test will catch it at CI time instead of as a silent decode error in production. Tests: balius-runtime --lib goes 8 → 13 (3 BigUInt + 2 roundtrip); balius-core unchanged at 4; e2e::faucet_claim still passes. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
refactor: rename balius-proto -> balius-core, nest schema under proto::v0
The crate's job has been "the Balius-owned wire schema", but the name "balius-proto" advertised protobuf as the only thing it carries. `balius-core` is a roomier name for what is really the foundational types crate for the runtime <-> WASM interface — protobuf today, more things possibly later. The schema module also gets nested: `balius_proto::cardano` becomes `balius_core::proto::v0::cardano`. The `v0` segment makes the versioning explicit: this schema is wire-compatible with utxorpc-spec 0.17 by construction (the entire point of this PR), so it is frozen for pre-BigInt worker compat. A future breaking change to the schema goes under `proto::v1`, leaving `v0` consumers untouched. Mechanical changes: - Crate dir balius-proto/ -> balius-core/ - Package name -> balius-core; description updated - src/cardano.rs -> src/proto/v0/cardano.rs (plus new mod.rs files) - Workspace member + all 3 dependent Cargo.tomls updated (balius-runtime, balius-sdk, examples/asteria-tracker) - Import paths: balius_proto::cardano -> balius_core::proto::v0::cardano across balius-sdk, balius-runtime, examples/asteria-tracker - Doc/comment references updated No behavior change. cargo check --workspace --tests clean; 2/2 wire-compat tests in balius-core; 9/9 lib tests in balius-runtime (incl. all 8 u5c convert tests); e2e::faucet_claim still passes; only the pre-existing u5c-chainsync::wallet_balance stale-wasm failure remains. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
refactor(balius-runtime): split u5c adapter into mod.rs + convert.rs
The u5c ledger module grew large enough that the ledger-facing surface
(Config, Ledger, wit ↔ utxorpc From impls, chain_utxo_to_wit) was sharing
a file with the u5c → balius_proto conversion layer. Promote
`ledgers/u5c.rs` to a folder with two siblings:
ledgers/u5c/
mod.rs — ledger adapter: Config, Ledger, pattern conversions
convert.rs — ConvertError, convert_tx / convert_tx_output / ...,
pparams_to_legacy_json, all the BigInt-flattening
helpers, and the unit tests that assert ABI compat
against utxorpc-spec 0.17 (prost + pbjson)
The previously integration-style tests at
`balius-runtime/tests/u5c_convert.rs` move into a `#[cfg(test)] mod tests`
inside `convert.rs` — they're testing internals of that module, so unit
tests are the right home. Test count unchanged; they now run as part of
the runtime's lib tests.
Call sites in `lib.rs` updated to the new path
(`ledgers::u5c::convert::convert_tx`, `ledgers::u5c::convert::ConvertError`).
No re-exports — the structure is explicit.
Verified: cargo check --workspace clean; 9/9 lib tests pass (8 convert
tests + 1 router test); e2e::faucet_claim still passes; pre-existing
u5c-chainsync::wallet_balance stale-wasm failure unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
refactor: move u5c conversion out of balius-proto into the runtime adapter
balius-proto is the Balius-owned wire schema crate; coupling it to an arbitrary upstream service (utxorpc-spec) defeats the point of having a schema crate in the first place. The conversion is u5c-specific and only consumed by balius-runtime, so it moves into the u5c ledger adapter. balius-proto/src/convert.rs is deleted along with its `convert` feature and the `utxorpc-spec` / `serde_json` deps. The crate is now pure types plus wire-format invariant assertions. The TryFrom impls become plain `convert_tx` / `convert_tx_output` / etc. functions inside `balius-runtime/src/ledgers/u5c.rs` (the orphan rule forbids the impls here — neither side is local to balius-runtime). `ConvertError` and `pparams_to_legacy_json` move alongside them. Call sites in `lib.rs::Block::txs` and the ledger paths update from `.try_into()` to the named functions. No behavior change. Conversion tests move from `balius-proto/tests/wire_compat.rs` to a new `balius-runtime/tests/u5c_convert.rs`. balius-proto keeps only the two `wire_compat_*` tests — the wire-format invariant of the schema itself, no upstream involved. Verified: cargo check --workspace clean; 2/2 wire-compat tests in balius-proto; 8/8 u5c convert tests in balius-runtime; e2e::faucet_claim still passes (end-to-end ABI compat path through the mock ledger); u5c-chainsync::wallet_balance still fails on the same pre-existing stale-wasm 5-vs-7 WIT variant mismatch, unrelated. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
feat(balius-proto): emit full PParams as 0.17 pbjson for worker ABI compat
Pre-BigInt workers ship a utxorpc-spec 0.17 pbjson deserializer for the
JSON `read-params` returns. The prior approach in this PR — emitting
`{"coins_per_utxo_byte": N}` snake_case — broke that contract: the key
doesn't match, the value type doesn't match, and 30 other fields the
worker may read are gone entirely.
PParams crosses the WIT boundary as JSON, not protobuf, so prost
wire-compat (the trick that anchors Tx/UTxO bytes) buys nothing for it.
Instead, `pparams_to_legacy_json` walks the upstream `PParams`
imperatively and emits exactly the JSON shape utxorpc-spec 0.17's pbjson
serializer would produce: camelCase keys, u64/i64 as JSON strings,
u32/i32 as plain numbers, None / proto3-default fields omitted. BigInt
fields collapse via `unwrap_u64`; overflow halts the worker as before.
The SDK side keeps a minimal `PParams` (only `coins_per_utxo_byte` is
actually consumed today) but now declares it with
`serde_with::DisplayFromStr` and `rename = "coinsPerUtxoByte"` so it
reads the same pbjson shape as old workers' decoder.
`mock_pparams.json` is restored to the canonical 0.17 pbjson snapshot,
so the mock ledger and the real ledger now hand workers identical bytes.
Tests:
- `convert_pparams_decodes_under_017_pbjson` — load-bearing: converted
PParams round-trips through utxorpc-spec 0.17's actual pbjson decoder.
- `convert_pparams_overflow_propagates` — BigUInt halts.
- `convert_pparams_omits_default_fields` — pbjson omit-default preserved.
- `e2e::faucet_claim` exercises the full path end-to-end (mock JSON →
SDK PParams → MinUtxoLovelace → tx build) and passes.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>