Skip to content

UTEXO-Protocol/rgb-lightning-node

 
 

Repository files navigation

RLN - RGB Lightning Node

RGB-enabled LN node daemon ported from rgb-lightning-sample, which is based on ldk-sample.

The node enables the possibility to create payment channels containing assets issued using the RGB protocol, as well as routing RGB asset denominated payments across multiple channels, given that they all possess the necessary liquidity. In this way, RGB assets can be transferred with the same user experience and security assumptions of regular Bitcoin Lightning Network payments. This is achieved by adding to each lightning commitment transaction a dedicated extra output containing the anchor to the RGB state transition.

More context on how RGB works on the Lightning Network can be found here.

The RGB functionality for now can be tested only in regtest or testnet environments, but an advanced user may be able to apply changes in order to use it also on other networks. Please be careful, this software is early alpha, we do not take any responsibility for loss of funds or any other issue you may encounter.

Also note that rust-lightning has been changed in order to support RGB channels, here a comparison with v0.2, the version we applied the changes to.

Install

Clone the project, including (shallow) submodules:

git clone https://github.com/RGB-Tools/rgb-lightning-node --recurse-submodules --shallow-submodules

Then, from the project root, install the rgb-lightning-node binary by running:

cargo install --locked --path .

The docker image can be built with:

docker build -t rgb-lightning-node .

UniFFI Bindings

See UniFFI SDK documentation for setup, runtime model, binding generation, test commands, and artifact packaging details.

Run

In order to operate, the node will need:

  • a bitcoind node
  • an indexer instance (electrum or esplora)
  • an RGB proxy server instance

Once services are running, daemons can be started. Each daemon needs to be started in a separate shell with rgb-lightning-node, specifying:

  • bitcoind user, password, host and port
  • node data directory
  • node listening port
  • LN peer listening port
  • network

Regtest

To easily start the required services on a regtest network, run:

./regtest.sh start

This command will create the directories needed by the services, start the docker containers and mine some blocks. The test environment will always start in a clean state, taking down previous running services (if any) and re-creating data directories.

Here's an example of how to start three regtest nodes, each one using the shared regtest services provided by docker compose:

# 1st shell
rgb-lightning-node dataldk0/ --daemon-listening-port 3001 \
    --ldk-peer-listening-port 9735 --network regtest \
    --disable-authentication

# 2nd shell
rgb-lightning-node dataldk1/ --daemon-listening-port 3002 \
    --ldk-peer-listening-port 9736 --network regtest \
    --disable-authentication

# 3rd shell
rgb-lightning-node dataldk2/ --daemon-listening-port 3003 \
    --ldk-peer-listening-port 9737 --network regtest \
    --disable-authentication

To instead run node in docker use the following template:

docker run \
    --rm -it \
    -p 3001:3001 \
    -v RLNdata1:/RLNdata \
    --network rgb-lightning-node_default \
    rgb-lightning-node \
        --daemon-listening-port 3001 \
        --ldk-peer-listening-port 9735 \
        --network regtest \
        --disable-authentication \
        RLNdata

Note: this persists data across runs in the RLNdata1 volume; to start from scratch delete it with docker volume rm RLNdata1

To send some bitcoins to a node, first get a bitcoin address with the POST /address API, then run:

./regtest.sh sendtoaddress <address> <amount>

To mine, run:

./regtest.sh mine <blocks>

To stop running services and to cleanup data directories, run:

./regtest.sh stop

For more info about regtest utility commands, run:

./regtest.sh -h

When unlocking regtest nodes use the following local services:

  • bitcoind_rpc_username: user
  • bitcoind_rpc_password: password
  • bitcoind_rpc_host: localhost
  • bitcoind_rpc_port: 18433
  • indexer_url: 127.0.0.1:50001
  • proxy_endpoint: rpc://127.0.0.1:3000/json-rpc

To unlock a regtest nodes running in docker use the following local services:

  • bitcoind_rpc_username: user
  • bitcoind_rpc_password: password
  • bitcoind_rpc_host: bitcoind
  • bitcoind_rpc_port: 18433
  • indexer_url: electrs:50001
  • proxy_endpoint: rpc://proxy:3000/json-rpc

Testnet

Testnet3

When running the node on the testnet3 network the docker services are not needed because the node will use some public services.

Here's an example of how to start three testnet3 nodes, each one using the external testnet3 services:

# 1st shell
rgb-lightning-node dataldk0/ --daemon-listening-port 3001 \
    --ldk-peer-listening-port 9735 --network testnet \
    --disable-authentication

# 2nd shell
rgb-lightning-node dataldk1/ --daemon-listening-port 3002 \
    --ldk-peer-listening-port 9736 --network testnet \
    --disable-authentication

# 3rd shell
rgb-lightning-node dataldk2/ --daemon-listening-port 3003 \
    --ldk-peer-listening-port 9737 --network testnet \
    --disable-authentication

When unlocking testnet3 nodes you can use the following services:

  • bitcoind_rpc_username: user
  • bitcoind_rpc_password: password
  • bitcoind_rpc_host: electrum.iriswallet.com
  • bitcoind_rpc_port: 18332
  • indexer_url: ssl://electrum.iriswallet.com:50013
  • proxy_endpoint: rpcs://proxy.iriswallet.com/0.2/json-rpc

Testnet4

To run testnet4 use the same options as testnet3 except for:

  • CLI arg: --network testnet4
  • bitcoind_rpc_port: 18443
  • indexer_url: ssl://electrum.iriswallet.com:50053

Use

Once daemons are running, they can be operated via REST JSON APIs.

For example, using curl:

curl -X POST -H "Content-type: application/json" \
    -d '{"ticker": "USDT", "name": "Tether", "amounts": [666], "precision": 0}' \
    http://localhost:3001/issueasset

The node currently exposes the following APIs:

  • /address (POST)
  • /apay/new (POST)
  • /apay/outboundinvoice (POST)
  • /assetbalance (POST)
  • /assetmetadata (POST)
  • /backup (POST)
  • /btcbalance (POST)
  • /cancelhodlinvoice (POST)
  • /changepassword (POST)
  • /checkindexerurl (POST)
  • /checkproxyendpoint (POST)
  • /claimhodlinvoice (POST)
  • /closechannel (POST)
  • /connectpeer (POST)
  • /createutxos (POST)
  • /decodelninvoice (POST)
  • /decodergbinvoice (POST)
  • /disconnectpeer (POST)
  • /estimatefee (POST)
  • /failtransfers (POST)
  • /getassetmedia (POST)
  • /getchannelid (POST)
  • /getpayment (POST)
  • /getswap (POST)
  • /inflate (POST)
  • /init (POST)
  • /invoicestatus (POST)
  • /issueassetcfa (POST)
  • /issueassetifa (POST)
  • /issueassetnia (POST)
  • /issueassetuda (POST)
  • /keysend (POST)
  • /listassets (POST)
  • /listchannels (GET)
  • /listpayments (GET)
  • /listpeers (GET)
  • /listswaps (GET)
  • /listtransactions (POST)
  • /listtransfers (POST)
  • /listunspents (POST)
  • /lninvoice (POST)
  • /lock (POST)
  • /makerexecute (POST)
  • /makerinit (POST)
  • /networkinfo (GET)
  • /nodeinfo (GET)
  • /openchannel (POST)
  • /postassetmedia (POST)
  • /refreshtransfers (POST)
  • /restore (POST)
  • /revoketoken (POST)
  • /rgbinvoice (POST)
  • /sendbtc (POST)
  • /sendonionmessage (POST)
  • /sendpayment (POST)
  • /sendrgb (POST)
  • /shutdown (POST)
  • /signmessage (POST)
  • /sync (POST)
  • /taker (POST)
  • /unlock (POST)
  • /vssbackup (POST) — requires the vss feature
  • /vssbackupinfo (GET) — requires the vss feature

To get more details about the available APIs see the OpenAPI specification. A Swagger UI for the master branch is generated from the specification and available at https://rgb-tools.github.io/rgb-lightning-node. Otherwise a local copy can be exposed. To do so, from the project root, run:

docker run -it \
  -p 8246:8080 \
  -e SWAGGER_JSON=/var/specs/openapi.yaml \
  -v $PWD/openapi.yaml:/var/specs/openapi.yaml \
  swaggerapi/swagger-ui

It can then be accessed by pointing a browser at http://localhost:8246.

If a daemon is running on your machine on one of the example ports given above, you can even call the APIs directly from the Swagger UI.

To stop the daemon, exit with the /shutdown API (or press Ctrl+C).

Authentication

RLN provides API authentication via Biscuit tokens.

One-time setup

First, generate a root keypair. This keypair is your issuer key: the private half signs new tokens, and the public half is shared with your node so it can verify them.

# install the biscuit CLI (or download a prebuilt binary from the Biscuit releases page)
cargo install biscuit-cli

# generate a root keypair (prints both keys)
biscuit keypair

# alternatively, you can export just the private key
biscuit keypair --only-private-key > private-key-file
# and later derive the public key from it
biscuit keypair --from-file private-key-file --only-public-key

Save the private key in a secure way (e.g. in a secret manager).

When starting the node, pass the public key with:

--root-public-key <public_key>

To disable authentication provide the explicit --disable-authentication arg and do not provide any key.

Minting tokens

You can now create Biscuit tokens that will allow calling the authenticated APIs.

Tokens must carry a role, these are the available roles:

  • admin token (full access):

    echo 'role("admin");' \
      | biscuit generate --private-key-file private-key-file -
  • read-only token (allows access only to endpoints that do not make any write operations):

    echo 'role("read-only");' \
      | biscuit generate --private-key-file private-key-file -
  • custom token (allows access only to the specified API paths), for example:

    echo 'role("custom");
          right("api", "/nodeinfo");
          right("api", "/networkinfo");' \
      | biscuit generate --private-key-file private-key-file -

Tokens can also carry an expiry date. Add a check clause to enforce expiration, for example:

echo 'role("admin");
      check if time($t), $t <= 2025-08-30T00:00:00Z;' \
  | biscuit generate --private-key-file private-key-file -

Using tokens

All authenticated requests must include the Biscuit token in the Authorization header:

curl -H "Authorization: Bearer <token>" [...] http://<node-address>/networkinfo

In the Swagger UI you can add the token by clicking the Authorize button (lock icon) at the top right, pasting the token and clicking Authorize.

Revoking tokens

A token can be revoked before its expiration. When you revoke a token, the node will reject any future request carrying that token. The node exposes a /revoketoken endpoint for this purpose. Internally, the node extracts the token’s revocation identifiers and adds them to its revocation list. Every request checks this list before authenticating.

Test

Tests for a few scenarios using the regtest network are included. The same services and data directories as the regtest.sh script are used, so the two cannot run at the same time.

Tests can be executed with:

cargo test

Projects using RLN

Here is a list of projects using RLN, in alphabetical order:

VSS Cloud Backup (optional)

The node supports optional cloud backup via VSS (Versioned Storage Service). When enabled, the node replicates its state to a remote VSS server so it can be recovered on a new device. The feature is fully opt-in: it must be compiled in with --features vss and turned on at runtime with --vss-url. Without both, the node behaves exactly as before.

Two independent data streams are backed up:

  • Node KV state — channel manager, channel monitors, payment info, swap data and RGB channel info. Every update is written to both the local SQLite database and the remote VSS server.
  • RGB wallet data — the wallet files managed by rgb-lib, backed up automatically after every state-changing wallet operation.

Setup

Start the VSS server alongside regtest services:

VSS=1 ./regtest.sh start

Or manually:

docker compose --profile vss up -d

Usage

Pass --vss-url when starting the node:

cargo run --features vss -- /tmp/rlndata --vss-url https://example.com/vss

Options:

  • --vss-url <URL> — VSS server URL; enables VSS backup. For non-loopback hosts an https:// URL is required (see --vss-allow-http).
  • --vss-allow-http — allow an http:// --vss-url for non-loopback hosts. By default only https:// URLs and loopback HTTP URLs (e.g. http://localhost:8081/vss) are accepted. Use only on a network you trust out-of-band.
  • --vss-allow-empty-restore — on a fresh device, if a VSS restore fails (server unreachable, wrong key, etc.), start with empty local state instead of aborting unlock. Use with care: starting fresh with no channel monitors can lose funds if the node had active channels. The default (abort on restore failure) is the safe choice.

Encryption

The KV stream is always encrypted at rest on VSS using XChaCha20-Poly1305 with a key derived from the VSS signing key. There is no option to disable it. The VSS signing key is derived from the wallet mnemonic, so backups can only be read and restored by a node initialized with the same mnemonic.

Recovery

On a fresh start, if the local database has no channel-manager state but the VSS server has data, the node automatically restores from VSS before initializing. Each VSS store is owned by a single running node instance; a second node pointed at the same store refuses to start to avoid corrupting state.

VSS replication is best-effort: a write that fails to reach the server is queued and retried on later successful writes. The number of pending writes is reported by GET /vssbackupinfo so monitoring can alert on persistent staleness.

API endpoints (when VSS is enabled)

  • POST /vssbackup — trigger a manual RGB wallet backup
  • GET /vssbackupinfo — check backup status (includes pending write count)

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • Rust 81.9%
  • Kotlin 9.9%
  • Python 6.7%
  • Shell 1.1%
  • Other 0.4%