Skip to content

fix(fees): align Studio with Consensus v0.6 economics - #1748

Open
MuncleUscles wants to merge 17 commits into
v0.123-devfrom
fix/v0.123-fee-consensus-parity
Open

fix(fees): align Studio with Consensus v0.6 economics#1748
MuncleUscles wants to merge 17 commits into
v0.123-devfrom
fix/v0.123-fee-consensus-parity

Conversation

@MuncleUscles

@MuncleUscles MuncleUscles commented Aug 27, 2026

Copy link
Copy Markdown
Member

Delivery context

Targets Studio v0.123-dev and the Consensus v0.6 release train.

Depends-On: genlayerlabs/genlayer-consensus#1381
Depends-On: genlayerlabs/genlayer-js#212
Depends-On: genlayerlabs/genlayer-py#109
Cross-stack qualification: genlayerlabs/genlayer-e2e#756
Independent fee oracle: genlayerlabs/genlayer-fee-distribution-simulator#29 and #30

Consensus is authoritative for runtime behavior. The simulator is an independent economics oracle; TLA+ supplies input-domain and appeal-selection invariants.

Outcome

Studio now follows the v0.6 implementation across fee quoting, execution accounting, settlement, and decision-bound lifecycle behavior:

  • submission/activation pricing, validator ladders, rotations, mandatory attempts, terminal clamping, developer/DAO gross-up, exact 5/2 appeal rewards and 3/2 profit reserve;
  • storage, receipt gas, external/internal messages, useBalance, allocated-message limits, cancellation, top-ups, overpayment refunds, penalties, vindication, and dust conservation;
  • raw normal-round indexing, terminal committees, leader/validator timeouts, exact appeal deadlines, decision IDs, finalization, and rejection of legacy unbound appeals;
  • leader-timeout replay removes the timed-out leader from the actual committee while its bond retains the configured source-round committee cost and uses the configured induced-round rotation allowance independently of prior usage;
  • canonical fee/config/metering and lifecycle RPCs so SDKs and E2E consume the implementation rather than duplicating formulas;
  • UI appeal/finalize controls use exact server lifecycle fields, update as the deadline passes, and do not expose terminal decisions as appealable.

Selection-authority corrections

The second review wave found a deeper source-of-authority mismatch around jury identity, not just jury count:

  • activation now freezes the normalized validator selection pool used by that transaction;
  • execution and every later appeal select only from those frozen identities that are still live;
  • validators registered after activation cannot enter an already-active transaction;
  • every previously consumed leader and validator identity is excluded across the full appeal history, preventing historical jurors from becoming selectable again;
  • quote capacity and actual selection share the same frozen/live/excluded identity set;
  • the direct validator-appeal worker now applies that same frozen-pool gate, closing a path where a post-activation validator could still join.

This preserves Consensus-style transaction authority while still allowing validator removal to reduce live capacity.

Concurrency, atomicity, and failure-recovery corrections

The cross-check also found production-significant races and asynchronous failure modes that formula-only tests could not detect:

  • concurrent fee top-ups could both debit the sender while one accounting contribution was lost;
  • worker receipt/message accounting could overwrite a concurrent top-up;
  • concurrent cancellation/final settlement could refund the same fee state twice;
  • an appeal could pass a pre-lock deadline check and be admitted after expiry;
  • legacy transactions without fee accounting could enter a value-bearing appeal path;
  • a GenVM or generic worker failure during a paid appeal could erase the original agreed decision while leaving the admitted bond/funding in custody;
  • exhausting generic retries could cancel that agreed transaction and settle an unresolved appeal as if it had an outcome;
  • a process death after incrementally committed appeal states could trigger ordinary stuck-transaction recovery, wiping the exact pre-appeal decision/history;
  • contract disappearance during appeal processing could finalize the original decision while forfeiting a no-outcome appeal charge;
  • helper-chain acceptance/finalization retries could create a second set of internal children after a worker crash;
  • multiple same-recipient children in one block could collide on one helper-chain transaction ID and collapse into one Studio child;
  • finalized-history reads used the accepted-queue index instead of Consensus's recipient issuance order;
  • the local helper silently registered an arbitrary nonzero internal-message recipient as a GenVM ghost, while Consensus requires that recipient to have already been registered;
  • Studio could commit contract-value reservations, swallow a helper-chain failure, create local-only children, and debit the same message value again on retry;
  • an agreed decision could become appealable or finalizable while its acceptance-phase message effects were still unacknowledged, a state Consensus cannot expose because those effects are atomic.

Fee-accounting mutations now lock and re-read the latest transaction state, debit/refund and accounting changes share one transaction, cancellation/settlement are single-spend, and appeal admission revalidates lifecycle and time under the row lock.

Studio forms and executes an admitted appeal asynchronously, unlike Consensus's atomic call. It now captures the exact decision-bound admission state and restores it after worker/process failure instead of resetting or canceling the transaction. That snapshot remains through a successful validator appeal's terminal recomputation and is cleared only after a real outcome, abort, cancellation, or settlement. A committee-formation or contract-not-found failure that produces no appeal outcome unwinds the admission and returns the exact bond plus typed funding. Recovery and refunds are row-locked and concurrency-tested. The Studio helper bridge now makes each parent/phase/payload emission one-shot, recovers the original child IDs on retry, and derives collision-free child IDs from the recipient issuance index; distinct appealed decisions remain independently emit-able. Finalized history now reads that same issuance ledger, and nonzero internal-message recipients must already be registered ghosts just as they must be in Consensus. Message value reservations now share the parent accounting row lock and persist their exact backed/unbacked outcome by Consensus-compatible occurrence ID, so worker retries neither charge twice nor change the emitted payload. Missing or incomplete helper receipts are fatal to the phase, never converted into locally generated child IDs; retries recover the helper's durable IDs and idempotently finish partial local insertion. Acceptance delivery is independently claimable before the appeal deadline, cannot be overtaken by finalization, cannot exhaust into cancellation, and blocks quote, appeal, finalization, and UI actions until acknowledged. A successful repair republishes the accepted status so clients refresh. Address identity comparisons are checksum-case-insensitive, matching Solidity address semantics.

Validation

  • backend unit suite: 1,406 passing;
  • PostgreSQL database/migration/accounting/concurrency/recovery campaign: 215 passing, 1 expected xfail;
  • focused fee/lifecycle campaign: 390 passing;
  • regenerated simulator admission oracle: 61/61 appeal-bond checkpoints matched;
  • frontend unit suite: 214 passing across 33 files;
  • Vue typecheck: passing;
  • Ruff/format, commit hooks, and diff checks: clean;
  • bundled Hardhat deployment/message-replay profile: 15 passing.

Hosted two-stack execution is intentionally not claimed here; #756 contains the shared Studio/Consensus feature and must run against the exact dependency cut below.

Exact review cut

  • Studio: 0bd2b9dad98e614c039fa256ddc64e402ff63004
  • Consensus: b51c8fd67b890a72c35db78a360147c7b8edb770
  • simulator oracle: 58115643f733eedfa331f1b78243f4b373482704
  • simulator admission checkpoints: 09fa7790f44a7d809eb9b429d8ca900e1b876c38
  • JS SDK: 95d513a8e64157a51e90c977bd9a63bda40badb6
  • Python SDK: f39770cd93634e5ba0ad118f16c36e3c633e8a82
  • E2E: 3f61b9d64f2f20fab0a99d7a7b3eef389d7d6469
  • TLA+: 3e263455d8262ccb55d621920b1a96c96554123a

Release gate

Studio must consume a published JS SDK containing #212. Released genlayer-js@1.1.8 still uses the legacy unbound appeal selector/zero fallback, so publishing Studio before the corrected SDK would reintroduce the mismatch even though this branch is correct.

Mirror cap-priced round quotes, configured ladder semantics, appeal profit reserves, exact 2.5x rewards, typed appeal funding, immutable top-up schedules, live appeal overlay pricing, latest appeal ABIs, decision guards, and surplus refunds. Expose the canonical quote over RPC so cross-stack tests no longer maintain a second Studio formula.
@MuncleUscles MuncleUscles self-assigned this Aug 27, 2026
@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 52cd9f69-4ed1-45ba-85f0-8b4897c01903

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

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants