Add bindings/c-ffi: C / C++ bindings alongside uniffi#25
Open
Jainakin wants to merge 1 commit intoUTEXO-Protocol:devfrom
Open
Add bindings/c-ffi: C / C++ bindings alongside uniffi#25Jainakin wants to merge 1 commit intoUTEXO-Protocol:devfrom
Jainakin wants to merge 1 commit intoUTEXO-Protocol:devfrom
Conversation
Thin extern-"C" shim on top of the existing UniFFI-exposed SdkNode API
(reuses block_on_sdk; no changes under src/). Mirrors the rgb-lib c-ffi
pattern: opaque COpaqueStruct handle, CResult / CResultString tagged
unions, and JSON strings for all complex inputs/outputs. Serde-friendly
mirror types in json_types.rs convert to/from the UniFFI typed wrappers
so no Serialize/Deserialize derives are needed upstream in
src/uniffi_api/types.rs.
Exposes 61 extern "C" functions covering the full SdkNode surface plus
lifecycle, namespace-level helpers, and free primitives. Build emits
librlncffi.{a,dylib} and a committed cbindgen-generated rln.h / rln.hpp
so consumers (Bare native addons, N-API wrappers, ctypes, etc.) can
embed without running build.rs. Includes a smoke-test example.c.
The sub-crate is its own Cargo workspace and mirrors the parent's
[patch.crates-io] table to keep registry lightning crates unified onto
the in-tree rust-lightning submodule. Cargo.lock is committed and pins
rgb-lib to the same revision as the parent's Cargo.lock so a fresh
checkout builds with --locked.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a new
bindings/c-ffi/sub-crate that exposes theSdkNodeAPI over aC ABI. It is a thin extern-"C" shim on top of the existing UniFFI-exposed API
in
src/uniffi_api/— same async-bridge (block_on_sdkinsrc/uniffi_api/state.rs), sameSdkNodestruct, no changes tosrc/.This unblocks consumers that don't have a UniFFI runtime: Node.js / Bun via
N-API, Bare native addons,
Python via
ctypes, etc. The intended first consumer is abare-runtimenative addon mirroring the
rgb-lib-barepattern.
What's exposed
61 extern "C" functions covering the full
SdkNodesurface plus lifecycle,namespace-level helpers, and dropping primitives:
rln_sdk_node_new,rln_sdk_node_init,rln_sdk_node_unlock,rln_sdk_node_shutdown,free_sdk_noderln_open_channel,rln_close_channel,rln_list_channels,rln_get_channel_id,rln_connect_peer,rln_disconnect_peer,rln_list_peersrln_send_payment,rln_keysend,rln_ln_invoice,rln_invoice_status,rln_cancel_hodl_invoice,rln_claim_hodl_invoice,rln_decode_ln_invoice,rln_decode_rgb_invoice,rln_get_payment,rln_list_paymentsrln_rgb_invoice,rln_send_rgb,rln_refresh_transfers,rln_fail_transfers,rln_inflate,rln_list_transfers,rln_list_unspents,rln_post_asset_media,rln_get_asset_media,rln_check_proxy_endpointrln_issue_asset_{nia,cfa,ifa,uda},rln_list_assets,rln_asset_balance,rln_asset_metadatarln_node_info,rln_network_info,rln_address,rln_btc_balance,rln_sign_message,rln_estimate_fee,rln_check_indexer_url,rln_send_btc,rln_create_utxos,rln_list_transactions,rln_syncrln_maker_init,rln_maker_execute,rln_taker,rln_send_onion_message,rln_get_swap,rln_list_swapsrln_uniffi_healthcheck,rln_uniffi_is_initialized,rln_sdk_initialize,rln_sdk_shutdownrln_free_stringABI / wire format
Mirrors the
rgb-libc-ffi pattern:COpaqueStructopaque handle forSdkNode.CResult/CResultStringtagged-union returns; onErr,innercarriesthe formatted error message — caller frees via
rln_free_string.Typed wrappers (
PublicKey,Txid,ContractId,ChannelId,PaymentHash,Bolt11Invoice) are passed as their canonical string forms(hex / bech32 / BIP-21) inside the JSON or as bare string args.
cbindgengeneratesrln.handrln.hppat build time. Both arecommitted to keep first-time consumers (and the included
example.c)buildable without running
build.rsfirst.JSON-friendly mirror request/response types live in
src/json_types.rs(~1900 LoC, all mechanical) with
TryFrom/Fromconversions to and fromthe UniFFI typed wrappers. This avoids requiring
serde::{Serialize, Deserialize}derives on the existing types insrc/uniffi_api/types.rs.File layout
```
bindings/c-ffi/
Cargo.toml # rln-c-ffi crate, [workspace] block, [patch.crates-io]
Cargo.lock # committed — pins rgb-lib to the same rev as parent
build.rs # cbindgen → rln.h / rln.hpp
cbindgen.toml
Makefile # rust-build + example wiring (mirrors rgb-lib c-ffi)
README.md
rln.h # generated, committed
rln.hpp # generated, committed
example.c # smoke test (healthcheck + is_initialized)
src/
lib.rs # 61 extern "C" wrappers
api.rs # handler functions (parse JSON → call SdkNode → JSON)
json_types.rs # mirror request/response structs + converters
utils.rs # COpaqueStruct, CResult helpers, ptr helpers
```
No changes to existing files outside
bindings/c-ffi/.Build & verify
```sh
cd bindings/c-ffi
cargo build # libs + headers
make build-example # gcc -lrlncffi
DYLD_LIBRARY_PATH=target/debug ./example
rgb-lightning-node c-ffi smoke test
[healthcheck] OK: rgb_lightning_node_uniffi_ready
[is_initialized] OK: false
```
Outputs:
target/debug/librlncffi.{a,dylib}(≈170 MB dylib, ≈1.6 GB staticunstripped on darwin; release builds are far smaller).
Notes on workspace / dep resolution
The c-ffi sub-crate is its own Cargo workspace (
[workspace]block). Itmirrors the parent crate's
[patch.crates-io]table to keeplightning/lightning-background-processorunified onto the in-treerust-lightningsubmodule — without that, registry pulls of
lightning-net-tokioetc.trigger trait-bound mismatches with the path-deped
lightning. Thecommitted
Cargo.lockpinsrgb-libto the same revision the parentCargo.lockuses, so a fresh clone +cargo build --lockedreproduceswithout
cargo update --precisegymnastics.A direct
lightning/lightning-invoicedep is added so the sub-cratecan construct
PaymentHash/ChannelIdby their real crate paths(
rgb_lightning_node::PaymentHashis a type alias; Rust 2021 doesn't allowtuple-struct construction through aliases).
Out of scope
.so/.dylibdistribution (will live in theconsuming
rgb-lightning-node-barepackage).SdkNode; can be added later if/when the SDK does.invoice notifications etc. are not exposed by UniFFI either.