Skip to content

Expose typed RGB funding recovery operations - #140

Draft
Jainakin wants to merge 6 commits into
UTEXO-Protocol:devfrom
Jainakin:hardik/rln-funding-recovery-api
Draft

Jainakin wants to merge 6 commits into
UTEXO-Protocol:devfrom
Jainakin:hardik/rln-funding-recovery-api

Conversation

@Jainakin

@Jainakin Jainakin commented Aug 10, 2026

Copy link
Copy Markdown

Summary

Expose the restart-safe RGB funding recovery implemented by #139 through RLN's HTTP, SDK, UniFFI, C-FFI, and OpenAPI surfaces.

This PR contains presentation and command plumbing only. Recovery ownership, admission, persistence, and reconciliation remain in #139.

Current head: 8e75121605b868124c12271f40b3531edd9e4672. The exact unique diff from #139 head 7f6708c is 14 files, 1,106 additions, and 18 deletions across two commits.

Public surface

HTTP

  • GET /rgbfundingrecoveries
  • POST /resolvergbfundingrecovery

Resolution accepts a canonical funding transaction ID and exactly one typed action:

  • recheck
  • resume_broadcast

Malformed IDs, unknown fields, unsupported actions, and unsafe force-rollback requests are rejected.

SDK and native bindings

  • SDK, UniFFI, and C-FFI list/resolve operations use equivalent durable-state semantics
  • sender/receiver role is typed
  • required operator action and accepted command are typed
  • lifecycle stage is an opaque snake-case diagnostic string
  • channel IDs retain exact 32-byte validation
  • C/C++ declarations and OpenAPI paths/schemas match the runtime surface

API stability and safety

The internal sender/receiver state machine remains typed and exhaustively maps to stable diagnostic strings. Public clients must branch on required_action, not stage, so internal lifecycle refinements do not become breaking changes across every binding.

  • list and resolve execute under Make RGB channel funding restart-safe #139's recovery admission policy
  • the quarantine guard is rebuilt from durable state after each operation
  • ambiguous post-handoff state cannot be force-rolled back through any public surface
  • recovery-required conditions remain typed conflicts rather than generic internal failures

The two unique commits are:

  1. 7301a87 exposes recovery operations through HTTP, SDK, UniFFI, and C FFI.
  2. 8e75121 preserves exact sender/receiver provenance, makes stage opaque, aligns OpenAPI, and adds exhaustive mapping coverage.

Review the exact #139-to-#140 diff

Validation

  • root, C-FFI, and UniFFI-bindgen formatting gates passed
  • all-feature compilation passed
  • exact CI clippy gate passed
  • complete library suite: 303 passed, 0 failed, 1 ignored
  • C-FFI suite: 4/4 passed
  • recovery HTTP/model and UniFFI mapping tests passed within the complete suite
  • OpenAPI YAML parses and every recovery-specific reference resolves

This restacked head has the exact same Git tree as fully validated head e665c70; only its ancestry changed to follow the corrected #139 commit structure. The fresh current-head GitHub matrix completed with 46 successful checks and one optional review job skipped. The only red check is the expected check-gitmodules ancestry gate.

Dependency and merge order

  1. rgb-lib #80
  2. rust-lightning #32, repinned to the official Upgrade APAY Access Policy #80 merge commit
  3. rgb-lightning-node #139, repinned to the official Reopen the database pool inside the restore endpoint to avoid stale post-restore queries #32 merge commit
  4. This PR, rebased onto merged Make RGB channel funding restart-safe #139

check-gitmodules is expected to remain red until the pinned rust-lightning commit is reachable from official dev; the ancestry gate must not be waived.

Release gates

  • complete the ordered merges and official immutable repins
  • rerun the full build, bindings, E2E, sanitizer, VSS, and platform matrix after those repins
  • complete production-LSP interoperability validation

This PR remains draft until those gates 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.

One trim on the recovery API surface, inline. Rest is good once #139 lands and the rust-lightning/rgb-lib pins move to merged SHAs.

Comment thread src/uniffi_api/types.rs Outdated
Receiver,
}

pub enum RgbFundingRecoveryStage {

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.

This leaks all 17 internal stages across the three binding layers (mirrored in ldk.rs and the c-ffi json_types). An operator needs the role and the required action (RetryReconciliation/ResumeBroadcast/RetryChainObservation/ManualChannelStateRecovery), not the full internal lifecycle as stable API. As is, every state-machine tweak breaks the bindings. Keep action and role typed, make stage an opaque string.

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 8e75121. Public stage is now an opaque string across HTTP, OpenAPI, UniFFI, and C-FFI. Role, required action, and accepted command remain typed, while the internal sender/receiver stage model remains exhaustive. The fresh current-head matrix completed with 46 successful checks; only the expected submodule ancestry gate is red.

* pin rgb-lib to exact version

* CI: switch from nightly to beta build

* add coverage support

* complete /listunspents fields

* fix README

* fix alphabetical order

* consignment/media for LN ops via p2p

* support out-of-band consignment/ack

* improve /refresh result

* add test reproducing sweeper breakage on force close with pending RGB HTLC

* fix for close_force_pending_htlc test

* use a generic drop guard for test-only node override statics

* restart the payer with the HTLC pending in close_force_pending_htlc

* update rust-lightning submodule

* add test for push_asset_amount above channel asset amount

* update rust-lightning (fixes push_asset_amount_above_chan_amt)

* wait for electrs to be usable after restarting it

* defer claiming payments in tests to fix pending status races

* replace magic-crypt with scrypt and XChaCha20Poly1305

The mnemonic file now records the scrypt work factors next to the salt, nonce
and ciphertext, so they can be raised later without leaving existing files
undecryptable. Key derivation and cipher setup are shared with the backup code,
whose derived key is unchanged.

Mnemonic files written by previous versions can no longer be read, including
those contained in older backups, so affected wallets have to be re-initialized.

* fix network conversion in WalletSource::list_confirmed_utxos

* shut down on panic or unexpected background processor exit

* improve shutdown on panic

* drop default indexer

* add electrum/esplora features

* Make bitcoind optional: add transaction-sync as an alternative chain backend

Adds `lightning-transaction-sync` (electrum/esplora) as an alternative to the
existing `lightning-block-sync` (bitcoind) chain backend, rather than replacing
it.

The chain backend is selected explicitly at unlock time via the `ldk_chain_sync`
field of the `/unlock` request, an adjacently-tagged `{ "mode", "config" }`
object:

  - `BlockSync`: consume full blocks from a trusted/local bitcoind over JSON-RPC.
    The `bitcoind_rpc_*` parameters live in this mode's `config`, so they are
    required exactly when this mode is selected.
  - `TransactionSync`: sync through an electrum/esplora indexer, so no bitcoind
    is required. By default it reuses the wallet's `indexer_url`; a dedicated LN
    indexer can be set in this mode's `config`.

Each backend is gated behind a Cargo feature (`block-sync`, `transaction-sync`),
both enabled by default and composing with the existing `electrum`/`esplora`
features, so a user can build with only the sync dependency they need. The mode
variants and their wiring are feature-gated accordingly, a build with neither
feature fails with a `compile_error!`, and the single-feature builds are covered
in the build and lint workflows.

The backends live in a new `ldk_chain_backend` module (`block_sync`,
`transaction_sync` and a shared `mod.rs` holding the chain-backend types and the
common fee-estimate logic). LDK is wired against trait objects for the fee
estimator, broadcaster and gossip UTXO lookup so one set of type aliases serves
both backends. Because `lightning-block-sync`'s `GossipVerifier` requires the
`P2PGossipSync` to be typed with `Arc<Self>`, a `BlockSyncGossipVerifier`
provides the block-sync gossip UTXO lookup against the shared trait-object
gossip sync, mirroring upstream's block cache. The transaction-sync gossip
lookup enforces the same six-confirmation depth as the block-sync path.

For the electrum backend, transactions registered via `Filter::register_tx` are
confirmed with a supplementary pass against the electrum server (without holding
its lock across network calls), as `ElectrumSyncClient::sync` alone does not
notify the confirmables about them in this setup.

Adds an integration test for the transaction-sync backend against both electrum
and esplora indexers (an esplora service is added to the regtest compose file):
three nodes are unlocked in transaction-sync mode, two announced RGB asset
channels are opened and node1 makes a multihop RGB payment to node3 (exercising
the indexer gossip lookup), the nodes are restarted (re-establishing the
channels after syncing via the indexer) and a channel is cooperatively closed.

Closes UTEXO-Protocol#125

* add electrum_opret_confirm test

* update rust-lightning (fix for electrum_opret_confirm test)

* improve the transaction-sync backend

 * drop workaround for note indexed transactions in electrum transaction
   sync
 * verify the funding output is unspent in the indexer gossip lookup as
   the block-sync path already did
 * require indexer_url in the transaction-sync config, following the
   default indexer removal
 * lint all 9 feature combinations in CI
 * test suite no longer needs block-sync; wait for esplora when mining
 * minor improvements/changes

* return errors instead of panicking on recoverable wallet failures

* point rgb-lib to master and bump MSRV to 1.94.0

* add asset filter and optional txid to listtransfers

* add BOLT11 description and description_hash to invoice creation, decode and payment APIs

* Send asset media over p2p on virtual channel opens and make funding transfer failures terminal

* Restore consignment generation for external-signer sends and wire p2p transfer limits through config

* decode sweep transfer info without panicking under the txes lock

* keep consignment cleanup non-fatal and tolerate a poisoned txes lock

* drop the cached sweep tx when persisting it fails

* reuse sweep receives across retries instead of issuing one per attempt

* shrink the cached sweep receive reuse margin when reusing addresses

* point rgb-lib at the upstream sync branch

* assert the sweep receive reuse margin is non-zero

* lower the scrypt work factors for the library test targets too, editing only the two log_n expressions

* pin the backup v1 derived key with a test vector

* validate a backup before installing it, so a failed restore leaves the node initializable

* say that the poisoned lock is ignored, not propagated

* update rust-lightning (electrum unindexed-output fix) and enable lightning indexer features

* migrate uniffi binding consumers to LdkChainSync and test the indexer_url config fallback

* bump the stale MSRV pins, format c-ffi, and keep backup v1 work factors out of feature gating

* point the rust-lightning submodule at the pushed sync branch

* stop the peer reconnect loop when the node stops instead of polling its database forever

* delete the staged funding consignment file once it is promoted to the KVStore

* pin the p2p funding transport and mandatory rgb-lib expirations in the sdk payment test

* make the asset-less transfer filter and receive reuse margin assertions non-vacuous

* use as_chunks for the fixed-size hex pair split

* route panics through a bounded shutdown that releases the vss fence only on a complete teardown

* gate scrypt CURRENT work factors on cfg(test) only

* run vss teardown headline tests in CI

* error instead of vanilla-sweeping a colored output missing from a non-empty transfer map

* stop the monitor kv store on abandoned vss teardown paths

* extract main exit decision so watchdog tests exercise the real one

* validate asset id and txid inputs to getconsignment against path traversal

* treat empty invoice description as none so description_hash invoices mint

* expose bolt11 description and description_hash on sdk and binding decode paths

* cover the pre-sync colored-channel deserialization tripwire

* bump rgb-lib pin and rust-lightning gitlink for the consignment and channel fixes

* flip rgb-lib pin to released UTEXO tag v0.3.0-beta.34 and bump submodule

* point rust-lightning submodule at the merged UTEXO dev branch

* do not fail CI when the codecov upload has no token

---------

Co-authored-by: Zoe Faltibà <zoefaltiba@gmail.com>
Co-authored-by: Nicola Busanello <nicola.busanello@gmail.com>
Co-authored-by: 0xaudron <r.arpeet82@gmail.com>
Co-authored-by: Zoe Faltibà <7492268+zoedberg@users.noreply.github.com>
Co-authored-by: bitwalt <walterm21@proton.me>
@Jainakin
Jainakin force-pushed the hardik/rln-funding-recovery-api branch from e665c70 to 8e75121 Compare August 27, 2026 18:09
@Jainakin

Copy link
Copy Markdown
Author

Final current-head update:

  • Head: 8e75121605b868124c12271f40b3531edd9e4672
  • Restacked onto the corrected Make RGB channel funding restart-safe #139 history with an unchanged Git tree.
  • Public recovery stage is opaque across HTTP, OpenAPI, UniFFI, and C-FFI.
  • Role, required action, and accepted command remain typed.
  • Fresh CI: 46 successful checks and 1 optional review skipped. The only red check is the expected submodule ancestry gate.

Please review the exact #139-to-#140 API diff after #139 is approved and merged.

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