Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/actions/private-sources/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Authenticate the pinned private RGB source
description: Configure Cargo's Git CLI fetches for rgb-lib-bfa.
inputs:
token:
description: Credential with read access to the pinned UTEXO-Protocol dependencies.
required: true
runs:
using: composite
steps:
- name: Configure scoped source authentication
shell: bash
env:
UTEXO_SOURCE_READ_TOKEN: ${{ inputs.token }}
run: |
set -euo pipefail
if [[ -z "$UTEXO_SOURCE_READ_TOKEN" ]]; then
echo "::error::Configure ORG_READ_TOKEN or RGB_LIB_RUST_LIGHTNING_PAT with read access to rgb-lib-bfa."
exit 1
fi
git config --global \
url."https://x-access-token:${UTEXO_SOURCE_READ_TOKEN}@github.com/UTEXO-Protocol/rgb-lib-bfa.git".insteadOf \
"https://github.com/UTEXO-Protocol/rgb-lib-bfa.git"
echo "CARGO_NET_GIT_FETCH_WITH_CLI=true" >> "$GITHUB_ENV"
34 changes: 34 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ on:
- master
workflow_dispatch: {}

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
Expand All @@ -29,6 +33,9 @@ jobs:
steps:
- name: Checkout source code
uses: actions/checkout@v4
- uses: ./.github/actions/private-sources
with:
token: ${{ secrets.ORG_READ_TOKEN || secrets.RGB_LIB_RUST_LIGHTNING_PAT }}
- name: Install Rust ${{ matrix.toolchain }} toolchain
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain ${{ matrix.toolchain }}
Expand All @@ -39,14 +46,40 @@ jobs:
- name: Build the workspace
shell: bash # Default on Winblows is powershell
run: cargo check --workspace --features lightning/electrum --verbose --color always
- name: Test the public RGB configuration contract with Electrum
shell: bash
run: cargo test -p lightning --features electrum --test rgb_config --verbose --color always

esplora:
name: Esplora workspace (Rust 1.94.0)
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout source code
uses: actions/checkout@v4
- uses: ./.github/actions/private-sources
with:
token: ${{ secrets.ORG_READ_TOKEN || secrets.RGB_LIB_RUST_LIGHTNING_PAT }}
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.94.0
rustflags: ""
- name: Check the supported Esplora source graph
run: cargo check --workspace --features lightning/esplora --verbose --color always
- name: Test the public RGB configuration contract with Esplora
run: cargo test -p lightning --features esplora --test rgb_config --verbose --color always

linting:
timeout-minutes: 30
runs-on: ubuntu-latest
env:
TOOLCHAIN: stable
steps:
- name: Checkout source code
uses: actions/checkout@v4
- uses: ./.github/actions/private-sources
with:
token: ${{ secrets.ORG_READ_TOKEN || secrets.RGB_LIB_RUST_LIGHTNING_PAT }}
- name: Install Rust ${{ env.TOOLCHAIN }} toolchain
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain ${{ env.TOOLCHAIN }}
Expand All @@ -58,6 +91,7 @@ jobs:
./ci/check-lint.sh

rustfmt:
timeout-minutes: 10
runs-on: ubuntu-latest
env:
TOOLCHAIN: 1.63.0
Expand Down
2 changes: 1 addition & 1 deletion lightning-invoice/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ serde = { version = "1.0", optional = true, default-features = false, features =
bitcoin = { version = "0.32.2", default-features = false, features = ["secp-recovery"] }

# RGB and related
rgb-lib = { git = "https://github.com/UTEXO-Protocol/rgb-lib.git", tag = "v0.3.0-beta.50-bfa", default-features = false }
rgb-lib = { git = "https://github.com/UTEXO-Protocol/rgb-lib-bfa.git", rev = "abd41d3afff6d8fb11461e26e843301650e22df3", default-features = false }

[dev-dependencies]
serde_json = { version = "1"}
Expand Down
3 changes: 2 additions & 1 deletion lightning/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,11 @@ amplify = "4.8"
bincode = "1.3"
rgb-strict-encoding = "1.0.1"
futures = "0.3"
rgb-lib = { git = "https://github.com/UTEXO-Protocol/rgb-lib.git", tag = "v0.3.0-beta.50-bfa", default-features = false }
rgb-lib = { git = "https://github.com/UTEXO-Protocol/rgb-lib-bfa.git", rev = "abd41d3afff6d8fb11461e26e843301650e22df3", default-features = false }
serde = { version = "^1.0", features = [
"derive",
] }
serde_json = "1.0"
tokio = { version = "1.14.1", features = [
"macros",
"rt-multi-thread",
Expand Down
49 changes: 37 additions & 12 deletions lightning/src/rgb_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ use rgb_lib::{
keys::WitnessVersion,
wallet::{
rust_only::{AssetColoringInfo, ColoringInfo},
DatabaseType, OnlineOptions, RgbWalletOpsOffline, SinglesigKeys, Wallet, WalletData,
DatabaseType, IndexerConfig, OnlineOptions, RgbWalletOpsOffline, SinglesigKeys, Wallet,
WalletData,
},
AssetSchema, Assignment, BitcoinNetwork, ConsignmentExt, ContractId, Error as RgbLibError,
Fascia, FileContent, RgbTransfer, WitnessOrd,
Expand All @@ -55,6 +56,8 @@ pub const INDEXER_URL_FNAME: &str = "indexer_url";
/// KVStore configuration key for the Ethereum RPC used to validate BFA funding consignments.
/// Missing or empty values disable BFA support.
pub const ETH_RPC_URL_FNAME: &str = "eth_rpc_url";
/// EVM RPC endpoints by chain ID, serialized as JSON for the current unlock.
pub const EVM_RPC_URLS_FNAME: &str = "evm_rpc_urls";
/// Name of the file containing the account-level xPub of the vanilla-side of the wallet
pub const WALLET_ACCOUNT_XPUB_VANILLA_FNAME: &str = "wallet_account_xpub_vanilla";
/// Name of the file containing the account-level xPub of the colored-side of the wallet
Expand Down Expand Up @@ -195,6 +198,34 @@ fn _get_eth_rpc_url(kv_store: &dyn KVStoreSync) -> Option<String> {
}
}

fn _get_evm_rpc_urls(kv_store: &dyn KVStoreSync) -> HashMap<u64, String> {
match kv_store.read_config(EVM_RPC_URLS_FNAME) {
Ok(value) => serde_json::from_str(&value).expect("invalid EVM RPC map in KVStore"),
Err(e) if e.kind() == io::ErrorKind::NotFound => HashMap::new(),
Err(e) => panic!("cannot read EVM RPC configuration: {e}"),
}
}

/// Construct explicit indexer and EVM options for the protocol-1.0 BFA library.
pub fn rgb_online_options(
indexer_url: String, evm_rpc_urls: HashMap<u64, String>, skip_consistency_check: bool,
) -> OnlineOptions {
let indexer_config =
if indexer_url.starts_with("https://") || indexer_url.starts_with("http://") {
IndexerConfig::Esplora { url: indexer_url }
} else {
IndexerConfig::Electrum { url: indexer_url }
};
OnlineOptions {
indexer_config,
skip_consistency_check,
vanilla_sync_lookback: VANILLA_SYNC_LOOKBACK,
failed_witness_receive_grace_secs: 86400,
proxy_auth_keys: HashMap::new(),
evm_rpc_urls,
}
}

#[cfg(test)]
mod bfa_config_tests {
use super::*;
Expand Down Expand Up @@ -238,7 +269,7 @@ pub fn supported_asset_schemas(bitcoin_network: BitcoinNetwork, bfa: bool) -> Ve

fn _new_rgb_wallet(
data_dir: String, bitcoin_network: BitcoinNetwork, account_xpub_vanilla: String,
account_xpub_colored: String, master_fingerprint: String, reuse_addresses: bool, bfa: bool,
account_xpub_colored: String, master_fingerprint: String, _reuse_addresses: bool, bfa: bool,
) -> Wallet {
let keys = SinglesigKeys {
account_xpub_vanilla,
Expand All @@ -255,7 +286,6 @@ fn _new_rgb_wallet(
database_type: DatabaseType::Sqlite,
max_allocations_per_utxo: 1,
supported_schemas: supported_asset_schemas(bitcoin_network, bfa),
reuse_addresses,
},
keys,
)
Expand All @@ -282,7 +312,7 @@ fn _get_wallet_data(
}

async fn _get_rgb_wallet(ldk_data_dir: &Path, kv_store: &dyn KVStoreSync) -> Wallet {
let bfa = _get_eth_rpc_url(kv_store).is_some();
let bfa = !_get_evm_rpc_urls(kv_store).is_empty();
let (
data_dir,
bitcoin_network,
Expand Down Expand Up @@ -328,7 +358,7 @@ async fn _accept_transfer(
reuse_addresses,
) = _get_wallet_data(ldk_data_dir, kv_store);
let indexer_url = _get_indexer_url(kv_store);
let eth_rpc_url = _get_eth_rpc_url(kv_store);
let evm_rpc_urls = _get_evm_rpc_urls(kv_store);
// the consignment is received from the channel counterparty over the p2p link and written to disk
let consignment_path = ldk_data_dir.join(format!("consignment_{funding_txid}"));
tokio::task::spawn_blocking(move || {
Expand All @@ -339,14 +369,9 @@ async fn _accept_transfer(
account_xpub_colored,
master_fingerprint,
reuse_addresses,
eth_rpc_url.is_some(),
!evm_rpc_urls.is_empty(),
);
let online = wallet.go_online(OnlineOptions {
indexer_url,
skip_consistency_check: true,
vanilla_sync_lookback: VANILLA_SYNC_LOOKBACK,
eth_rpc_url,
})?;
let online = wallet.go_online(rgb_online_options(indexer_url, evm_rpc_urls, true))?;
let (consignment, assignments, media_digests) = wallet.accept_transfer_consignment(
online,
consignment_path,
Expand Down
75 changes: 75 additions & 0 deletions lightning/tests/rgb_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//! Public RGB configuration contracts, independent of the legacy Lightning unit-test harness.

use lightning::rgb_utils::{rgb_online_options, supported_asset_schemas};
use rgb_lib::wallet::IndexerConfig;
use rgb_lib::{AssetSchema, BitcoinNetwork};
use std::collections::HashMap;

#[test]
fn bfa_schema_requires_explicit_opt_in_on_every_network() {
for network in [
BitcoinNetwork::Mainnet,
BitcoinNetwork::Testnet,
BitcoinNetwork::Testnet4,
BitcoinNetwork::Signet,
BitcoinNetwork::SignetCustom,
BitcoinNetwork::Regtest,
] {
let baseline = supported_asset_schemas(network, false);
assert!(!baseline.contains(&AssetSchema::Bfa));
assert!(baseline.contains(&AssetSchema::Nia));
assert!(baseline.contains(&AssetSchema::Cfa));
assert!(baseline.contains(&AssetSchema::Uda));
assert_eq!(baseline.contains(&AssetSchema::Ifa), network != BitcoinNetwork::Mainnet);
let enabled = supported_asset_schemas(network, true);
assert_eq!(enabled.iter().filter(|schema| **schema == AssetSchema::Bfa).count(), 1);
let retained: Vec<_> =
enabled.into_iter().filter(|schema| *schema != AssetSchema::Bfa).collect();
assert_eq!(retained, baseline, "BFA opt-in must preserve the other schema policy");
}
}

#[test]
fn indexer_selection_preserves_the_configured_url() {
for url in ["ssl://indexer.invalid:50002", "tcp://127.0.0.1:50001"] {
let options = rgb_online_options(url.into(), HashMap::new(), false);
assert!(
matches!(options.indexer_config, IndexerConfig::Electrum { url: actual } if actual == url)
);
}
for url in ["https://indexer.invalid/api", "http://127.0.0.1:3002"] {
let options = rgb_online_options(url.into(), HashMap::new(), false);
assert!(
matches!(options.indexer_config, IndexerConfig::Esplora { url: actual } if actual == url)
);
}
}

#[test]
fn online_configuration_retains_explicit_evm_endpoints_and_safety_policy() {
let endpoints = HashMap::from([
(1, "https://ethereum.invalid".into()),
(42161, "https://arbitrum.invalid/rpc".into()),
(31337, "http://127.0.0.1:8545".into()),
]);
for skip_consistency_check in [false, true] {
let options = rgb_online_options(
"ssl://indexer.invalid:50002".into(),
endpoints.clone(),
skip_consistency_check,
);
assert_eq!(options.evm_rpc_urls, endpoints);
assert_eq!(options.skip_consistency_check, skip_consistency_check);
assert_eq!(options.vanilla_sync_lookback, 20);
assert_eq!(options.failed_witness_receive_grace_secs, 86400);
assert!(options.proxy_auth_keys.is_empty(), "proxy authentication is explicit");
}
}

#[test]
fn missing_evm_configuration_does_not_invent_an_endpoint_or_proxy_secret() {
let options = rgb_online_options("http://127.0.0.1:3002".into(), HashMap::new(), false);
assert!(options.evm_rpc_urls.is_empty());
assert!(options.proxy_auth_keys.is_empty());
assert!(!options.skip_consistency_check);
}