Skip to content

Make RGB acceptance transactional and crash-safe - #80

Draft
Jainakin wants to merge 1 commit into
UTEXO-Protocol:devfrom
Jainakin:hardik/transactional-rgb-acceptance
Draft

Make RGB acceptance transactional and crash-safe#80
Jainakin wants to merge 1 commit into
UTEXO-Protocol:devfrom
Jainakin:hardik/transactional-rgb-acceptance

Conversation

@Jainakin

@Jainakin Jainakin commented Aug 10, 2026

Copy link
Copy Markdown

Summary

Make protocol-owned RGB acceptance transactional and recoverable across process crashes, while keeping witness-throughput work out of this PR.

  • stage RGB stock mutations in an isolated runtime before touching live state
  • serialize process access to wallet RGB state with an OS-backed lock
  • persist a versioned acceptance journal and durably promote staged state
  • expose idempotent finalize and rollback operations tied to one operation ID
  • reject unrelated RGB mutation while an unresolved operation owns the stock
  • expose exact-owner operations needed by channel funding: coloring/consumption, witness insertion, and preconsumed send completion
  • repair interrupted journal and promotion states on restart
  • cover persistence boundaries with deterministic subprocess crash injection

Current head: 22c76737894db67caa2b0743e4c258ba8c2422f0. The PR is one commit on current dev (62a8c3a), changing 17 files.

Safety model

A protocol operation prepares and validates an isolated stock snapshot, syncs staged files, records the journal, and only then promotes the snapshot. Until the embedding protocol records a deterministic commit decision, ordinary RGB mutation is rejected with the owning operation ID.

Recovery is explicit and idempotent:

  • finalize keeps promoted state and removes recovery evidence only after durable completion
  • rollback restores the exact pre-operation snapshot and removes the journal only after the restored state is durable
  • ambiguous broadcast outcomes are never guessed by rgb-lib; the protocol caller must reconcile external evidence before choosing an action
  • operation-owned mutations require an exact, non-empty owner ID and cannot bypass another operation's journal

Production persistence uses write_all. The 4 KiB write granularity exists only under cfg(test) for deterministic kill injection.

Review scope

The reviewer-requested throughput split is complete. OperationResolver, witness prefetch, high-history fixtures, Signet proxy tooling, performance workflows, and related Docker harness changes are not in this PR.

color_psbt_and_consume_for_operation is intentionally retained because the final rust-lightning #32 receiver boundary calls it while the promoted acceptance journal owns the stock. Removing it would either break #32 or force an unsafe ordinary-wallet access path. The exact-owner witness API is covered by the real send-operation integration test, including ordinary-access rejection and wrong-owner rejection.

Witness-resolution throughput remains separate work in rgb-ops #18 and rgb-ops #20.

Validation

  • exact formatting gate passed
  • no-default and all-feature checks passed
  • all-feature/all-target clippy passed
  • focused Docker-backed operation-owner send test passed
  • current GitHub matrix is green across Linux, macOS, Windows, stable, nightly, MSRV, no-default, Electrum, Esplora, formatting, lint, docs, coverage, and feature tests; optional AI review jobs are skipped

Dependency and merge order

  1. This PR
  2. rust-lightning #32, repinned to the official merge commit
  3. rgb-lightning-node #139, repinned to the official rust-lightning commit
  4. rgb-lightning-node #140, rebased onto merged #139

Release gates

  • reviewer approval of the transactional boundary and recovery invariants
  • downstream RLN crash/restart validation against final immutable revisions
  • production-LSP interoperability before release

This PR remains draft until those gates are complete.

@dcorral dcorral left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Transactional acceptance core is right and well-tested. Two separable pieces should come out so this PR is only the crash-safety fix, plus one minor. Details inline.

Comment thread src/wallet/rust_only.rs
/// <div class="warning">This method is meant for protocol integrations that provide their own
/// durable commit decision.</div>
#[cfg(any(feature = "electrum", feature = "esplora"))]
pub fn color_psbt_and_consume_for_operation(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Dead. Nothing calls it, not even the tests here. Sender colors through color_psbt_and_consume and stages through prepare_consume_fascia. Drop it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Retained after revalidating the final dependency stack. color_psbt_and_consume_for_operation is called by rust-lightning #32 at lightning/src/rgb_utils/mod.rs:667 while the promoted acceptance journal owns the stock. Removing it would either break #32 or require an unsafe ordinary-wallet access path, so the final #80 description records this required downstream caller.

Comment thread src/utils.rs Outdated
}

#[cfg(any(feature = "electrum", feature = "esplora"))]
pub(crate) fn prefetch_consignment_witnesses<const TRANSFER: bool>(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Split this out: prefetch_consignment_witnesses + OperationResolver and its whole apparatus (high_history_perf.rs, perf-fixture/*, signet-profile-proxy.mjs, the Dockerfiles, compose.yaml, regtest.sh, the workflow, chain.rs). ~1.1k lines of validation throughput, not acceptance. The staged path is correct with the plain OffchainResolver, so nothing here needs it. Own PR, own perf review.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed at head 22c7673. OperationResolver, witness prefetching, performance fixtures, proxy tooling, Docker harnesses, and performance workflows were removed. #80 now contains only transactional acceptance and the exact operation-owner APIs required by the downstream funding boundary.

Comment thread src/wallet/rust_only.rs
}

#[cfg(any(feature = "electrum", feature = "esplora"))]
fn write_all_checkpointed(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Minor, non-blocking: this chunks every write into 4096-byte file.write() calls in release too, only for test crash granularity. Gate the chunking behind the test cfg and write_all in prod.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed at head 22c7673. Production persistence uses write_all; 4 KiB chunking is compiled only under cfg(test) for deterministic crash injection.

@Jainakin
Jainakin force-pushed the hardik/transactional-rgb-acceptance branch 4 times, most recently from 0d310c4 to 2aeb3d4 Compare August 27, 2026 15:47
@Jainakin
Jainakin force-pushed the hardik/transactional-rgb-acceptance branch from 2aeb3d4 to 22c7673 Compare August 27, 2026 16:23
@Jainakin

Copy link
Copy Markdown
Author

Final current-head update:

  • Head: 22c76737894db67caa2b0743e4c258ba8c2422f0
  • Witness-throughput tooling has been removed; this PR is limited to transactional acceptance and exact operation-owner APIs.
  • color_psbt_and_consume_for_operation is retained because rust-lightning Add optional lock_time to singlesig send methods for final-locktime funding txs #32 calls it while the promoted acceptance journal owns the stock.
  • Production persistence uses write_all; deterministic 4 KiB chunking is test-only.
  • Current CI: 23 successful checks and 2 optional jobs skipped, with no failures.

The required order remains #80, #32 repinned to the official #80 merge commit, #139 repinned to the official #32 merge commit, then #140 rebased onto merged #139.

Could you re-review the current head?

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