Skip to content

feat: introduce balius-proto for runtime <-> WASM schema#98

Open
scarmuega wants to merge 4 commits intomainfrom
feat/balius-proto-schema
Open

feat: introduce balius-proto for runtime <-> WASM schema#98
scarmuega wants to merge 4 commits intomainfrom
feat/balius-proto-schema

Conversation

@scarmuega
Copy link
Copy Markdown
Member

@scarmuega scarmuega commented May 1, 2026

Summary

  • Introduces balius-proto, a Balius-owned protobuf schema (mirrors utxorpc-spec 0.17.0 wire format) that defines the WASM ABI independently of upstream u5c.
  • Runtime now ingests upstream u5c types and converts once into balius_proto::cardano::* at chainsync ingress and at ledger reads (u5c.rs); BigInt → u64/i64 is fallible and halts on overflow.
  • balius-sdk drops the utxorpc-spec dep in favor of balius-proto; Utxo<D>::coin() and PParams access become plain integer reads (no BigInt unwrap).

Why

The runtime was shipping raw utxorpc::spec::cardano::* prost bytes across the WIT boundary, which implicitly made the upstream u5c spec the WASM ABI. When u5c 0.17 → 0.18.1 flipped TxOutput.coin (and similar fields across Asset, Tx.fee, Collateral, certs, governance actions, PParams) from uint64 to BigInt, every existing pre-BigInt worker started decoding garbage. This PR breaks that coupling: workers built against the old SDK keep working because the new bytes are byte-identical to what they expect, and future upstream u5c churn is absorbed by a single hardcoded conversion layer inside the runtime.

Notes

  • Conversion error semantics: BigUInt/BigNInt and out-of-range Int produce ConvertError::Overflow. Surfaces as Error::Convert in the runtime and wit::LedgerError::Upstream for ledger paths — workers halt rather than receive lossy values.
  • balius-proto ships pre-generated cardano.rs + pbjson cardano.serde.rs (no protoc required at build).
  • convert feature on balius-proto is gated so the SDK doesn't pull utxorpc-spec transitively.

Test plan

  • cargo check --workspace clean
  • cargo test -p balius-proto --features convert — 7/7 pass (wire-compat round-trip via 0.17.0, convert path, overflow errors, load-bearing convert→0.17 decode)
  • cargo test --workspace — all pass except the pre-existing u5c-chainsync::wallet_balance (5-vs-7 WIT variant mismatch from a stale checked-in wallet.wasm; verified failing identically on main)
  • Smoke test against a staging u5c endpoint with an existing pre-BigInt worker to confirm utxo_handled / tx_handled metrics advance and no decode errors appear in logs

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Introduced balius-proto crate providing protobuf-based Cardano schema with wire compatibility support across schema versions
  • Refactor

    • Migrated from utxorpc-spec to balius-proto for core transaction and UTXO types; simplified protocol parameters to expose only coins_per_utxo_byte
  • Tests

    • Added wire compatibility tests across different schema versions

Decouple the WASM ABI from the upstream utxorpc spec. The runtime
previously shipped utxorpc::spec::cardano::* prost-encoded bytes across
the WIT boundary as cbor; that implicitly made the upstream u5c spec the
WASM ABI, so the 0.17 -> 0.18 BigInt break propagated to every existing
worker.

balius-proto owns a frozen schema (mirrors utxorpc-spec 0.17.0 wire
format). The runtime converts upstream u5c types into this schema once
at chainsync ingress and at ledger reads. BigInt -> u64/i64 is fallible
and halts the worker on overflow. Workers built against the pre-BigInt
SDK keep decoding cleanly because the new bytes are wire-identical to
what they expect.

balius-sdk drops the utxorpc-spec dep in favor of balius-proto;
Utxo<D>::coin() and PParams field access become plain integers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 1, 2026

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d9359dd3-4f36-47d5-9704-4299eaabb6d1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

A new balius-proto crate is introduced containing minimal Cardano protobuf definitions and conversion utilities. This library is integrated into balius-runtime and balius-sdk, replacing direct utxorpc-spec dependencies while simplifying protocol parameter handling to a single coins_per_utxo_byte field.

Changes

Cohort / File(s) Summary
Workspace & New Crate Setup
Cargo.toml, balius-proto/Cargo.toml, balius-proto/src/lib.rs
Root workspace updated to include balius-proto member. New crate manifest declares prost and bytes dependencies, with optional utxorpc-spec and convert feature for version compatibility testing.
Balius Proto Schema & Conversions
balius-proto/src/cardano.rs, balius-proto/src/convert.rs
Defines minimal Cardano protobuf message types (TxInput, TxOutput, Tx, Asset, Multiasset, etc.) and PlutusData variants. Adds conversion module with ConvertError, TryFrom impls for legacy-to-balius type mapping, and coins_per_utxo_byte() extraction utility with overflow detection.
Balius Proto Tests
balius-proto/tests/wire_compat.rs
Validates wire compatibility between legacy and utxorpc-spec 0.17.0 types; verifies conversion roundtrips, overflow handling, and field preservation across encoding/decoding.
Runtime Integration
balius-runtime/Cargo.toml, balius-runtime/src/lib.rs, balius-runtime/src/ledgers/u5c.rs
Adds balius-proto dependency with convert feature. Updates TxInput::Cardano, Utxo::Cardano, and Tx::Cardano to use balius_proto::cardano::* types. Changes Block::txs() to return Result<Vec<Tx>, Error> with fallible per-transaction conversion. Introduces chain_utxo_to_wit and utxo_page_to_wit helpers; simplifies read_params to extract only coins_per_utxo_byte via conversion utility.
SDK Dependency & Type Updates
balius-sdk/Cargo.toml, balius-sdk/src/qol.rs
Replaces utxorpc-spec with balius-proto. Updates Utxo<D> and Tx wrapper types to use balius_proto::cardano payloads. Simplifies Utxo::coin() by removing nested BigInt parsing.
SDK Parameter & DSL Updates
balius-sdk/src/txbuilder/mod.rs, balius-sdk/src/txbuilder/dsl.rs
Introduces local PParams struct containing only coins_per_utxo_byte: u64 with serde deserialization. Removes re-export of upstream PParams. Simplifies MinUtxoLovelace::eval to use coins_per_utxo_byte directly without nested field extraction.
Mock Parameters
balius-runtime/src/ledgers/mock_pparams.json
Drastically reduces schema to single coins_per_utxo_byte field (snake_case), removing all transaction/block limits, fees, deposits, cost models, and execution units.
Example Updates
examples/asteria-tracker/Cargo.toml, examples/asteria-tracker/src/lib.rs
Switches to balius-proto dependency and updates imports from utxorpc_spec::utxorpc::v1alpha::cardano to balius_proto::cardano for PlutusData, BigInt, and multiasset types.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Poem

🐇 Hops with glee through proto fields,
Wire-compatible, the structure yields,
No BigInt nested, just coins so clean,
Smallest PParams ever seen!
Conversion safe from overflow's sting—
A schema fit for everything! 🌿✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the primary objective of the PR—introducing balius-proto as the schema bridge between runtime and WASM, which is reflected throughout all major changes in the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/balius-proto-schema

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
balius-runtime/src/lib.rs (1)

315-319: 💤 Low value

Consider making from_bytes fallible for robustness.

The unwrap() on Block::decode will panic if the stored bytes are malformed. While blocks are converted at chain-sync ingress (so stored data should be valid), returning Result would provide graceful handling for edge cases like store corruption.

♻️ Optional: Return Result instead of panicking
-    pub fn from_bytes(data: &[u8]) -> Self {
+    pub fn from_bytes(data: &[u8]) -> Result<Self, prost::DecodeError> {
         use prost::Message;
 
-        Self::Cardano(balius_proto::cardano::Block::decode(data).unwrap())
+        Ok(Self::Cardano(balius_proto::cardano::Block::decode(data)?))
     }

This would require updating call sites to handle the Result.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@balius-runtime/src/lib.rs` around lines 315 - 319, Change from_bytes to be
fallible: replace the current panic-on-error behavior in from_bytes (which
constructs Self::Cardano from
balius_proto::cardano::Block::decode(data).unwrap()) with a Result-returning
signature (e.g., Result<Self, prost::DecodeError> or your crate error type) and
propagate the decode error using ? or map_err so malformed bytes are returned as
Err; update callers of from_bytes to handle the Result accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@balius-runtime/src/lib.rs`:
- Around line 315-319: Change from_bytes to be fallible: replace the current
panic-on-error behavior in from_bytes (which constructs Self::Cardano from
balius_proto::cardano::Block::decode(data).unwrap()) with a Result-returning
signature (e.g., Result<Self, prost::DecodeError> or your crate error type) and
propagate the decode error using ? or map_err so malformed bytes are returned as
Err; update callers of from_bytes to handle the Result accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 80355eac-cee7-4a23-82f6-a522fe0c6b2f

📥 Commits

Reviewing files that changed from the base of the PR and between e9c8cd5 and a2cdca5.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (17)
  • Cargo.toml
  • balius-proto/Cargo.toml
  • balius-proto/src/cardano.rs
  • balius-proto/src/cardano.serde.rs
  • balius-proto/src/convert.rs
  • balius-proto/src/lib.rs
  • balius-proto/tests/wire_compat.rs
  • balius-runtime/Cargo.toml
  • balius-runtime/src/drivers/chainsync.rs
  • balius-runtime/src/ledgers/u5c.rs
  • balius-runtime/src/lib.rs
  • balius-sdk/Cargo.toml
  • balius-sdk/src/qol.rs
  • balius-sdk/src/txbuilder/dsl.rs
  • balius-sdk/src/txbuilder/mod.rs
  • examples/asteria-tracker/Cargo.toml
  • examples/asteria-tracker/src/lib.rs

scarmuega and others added 2 commits May 1, 2026 10:28
Drop everything from cardano.rs except the wire surface workers
actually consume:

  TxOutput { address, coin, assets }
  Tx       { inputs, outputs, fee, hash }
  TxInput  { tx_hash, output_index, as_output }
  Multiasset, Asset (output_coin only)

Tags absent from these structs (datum, script, certificates,
withdrawals, mint, witnesses, validity, auxiliary, proposals, ...) are
deliberately dropped — workers needing them must extend the schema and
the converter explicitly. This shrinks balius-proto from ~5400 LOC of
generated cardano + 14k LOC of pbjson serde to 181 LOC total.

Block/BlockBody/BlockHeader move out of balius-proto since they never
cross WIT. The runtime's Block enum reverts to wrapping
utxorpc::spec::cardano::Block; per-Tx conversion happens at apply_block
/ undo_block via the fallible Block::txs() accessor.

PParams gone too: the SDK txbuilder now defines a minimal
PParams { coins_per_utxo_byte: u64 } locally, and the runtime's
read-params emits a matching minimal JSON shape.

asteria-tracker example trimmed to use only multiasset fields (datum-
derived position is dropped since the datum tag is gone).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The datum payload (PlutusData) and the witness set are common worker
inputs — bring them back into the trimmed schema. Both were
wire-stable across utxorpc-spec 0.17 -> 0.18, so the converter just
roundtrips them via prost.

New types in cardano.rs: Datum, PlutusData (+ Constr, PlutusDataPair,
PlutusDataMap, PlutusDataArray, BigInt), Script (+ NativeScript,
NativeScriptList, ScriptNOfK), WitnessSet, VKeyWitness.

Tags on PlutusData and Constr.any_constructor match upstream 0.17
verbatim (verified by failing-then-fixing wire_compat tests).

asteria-tracker example restores its datum-derived position tracking.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@SupernaviX SupernaviX left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully tx3 integration lets you throw out all this compat stuff

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants