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
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]>