feat(cln): add expose_private_channels config option#1758
feat(cln): add expose_private_channels config option#1758thesimplekid merged 4 commits intocashubtc:mainfrom
Conversation
f792367 to
eb3cb38
Compare
…tion Add configuration to pass `exposeprivatechannels: true` to CLN's invoice RPC, allowing private channel route hints to be included in bolt11 invoices. Since cln-rpc types this field as `Option<Vec<ShortChannelId>>` which cannot represent a boolean, `call_raw` is used to bypass the typed API when the option is enabled. Includes integration test that opens a private channel between CLN-1 and CLN-2, then verifies that invoices include the private channel route hint when the option is enabled. Closes cashubtc#1757 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0b83b0d to
7554685
Compare
|
This PR uses call_raw to bypass a cln-rpc typing limitation where exposeprivatechannels is typed as Option<Vec> and cannot represent boolean true. |
|
The current test generates 10 invoices and asserts that at least one includes a private channel route hint. In local testing this passed at 6/10, but since CLN selects route hints from 3 candidates (LND-1, LND-2, CLN-2) non-deterministically, there's a ~1.7% chance ((2/3)^10) that all 10 miss the private channel. Would it be better to loop until the first private channel hint is found, with an upper bound of 100 attempts? The probability of 100 consecutive misses is (2/3)^100 ≈ 2.5 × 10⁻¹⁸, making it effectively impossible to flake. The test would still exit immediately on first success, so typical runtime stays at 1-3 iterations. |
thesimplekid
left a comment
There was a problem hiding this comment.
Would it be better to loop until the first private channel hint is found, with an upper bound of 100 attempts?
Yeah I think this makes sense if you saw it fail 4/10 times locally would like to reduce flakiness where we can if we know there is a potential source of it, since we already have some issues with our ci just because its so heavy.
| deschashonly: None, | ||
| exposeprivatechannels: None, | ||
| }; | ||
|
|
||
| // cln-rpc types exposeprivatechannels as Option<Vec<ShortChannelId>> | ||
| // which cannot represent boolean true. Use call_raw to bypass this | ||
| // limitation when expose_private_channels is enabled. | ||
| let invoice_response: InvoiceResponse = if self.expose_private_channels { | ||
| let mut params = serde_json::to_value(&request).map_err(Error::from)?; | ||
| params["exposeprivatechannels"] = serde_json::Value::Bool(true); | ||
| cln_client | ||
| .call_raw("invoice", ¶ms) | ||
| .await | ||
| .map_err(Error::from)? | ||
| } else { | ||
| cln_client.call_typed(&request).await.map_err(Error::from)? | ||
| }; |
There was a problem hiding this comment.
Would another option be on the start up of the mint list the cln channels and then pass in the channel ides on the exposeprivatechannels field of the request? I'm not necessarily requesting we do that instead this is probably simpler just trying to understand the api.
There was a problem hiding this comment.
That would be cleaner from a cdk<-> cln API perspective. however, fetching short cheannel ids only at start up wouldn't detect channels opened after launch.
The root cause is that cln-rpc doesn't expose the needed fields in its tyepd API yet. Once the upstream issue is resolved, we won't need the startup-based approach or the raw JSON workaround in this PR.
For now, I think it makes sense to go with json-raw approach and switch over when the typed API catches up.
Updated. The test now iterates up to 100 times, It breaks on the first match. |
Summary
expose_private_channelsconfig option to cdk-cln backend (default:false)exposeprivatechannels: trueto CLN'sinvoiceRPC so private channels become route hint candidates in bolt11 invoicescall_rawto bypass cln-rpc's typed API limitation (Option<Vec<ShortChannelId>>cannot represent booleantrue)Context
CLN's default behavior for route hint selection is non-deterministic — it depends on internal heuristics around inbound capacity, channel count, and other factors. In practice, this means mint nodes with private channel inbound liquidity may intermittently fail to receive payments, because CLN omits the private channel route hints that payers need for routing. This option lets mint operators explicitly include private channels as route hint candidates.
See also: ElementsProject/lightning#7601 for the upstream cln-rpc typing limitation.
Closes #1757
CHANGED
Cln::new()now acceptsexpose_private_channels: boolparameterADDED
expose_private_channelsfield in[cln]config sectionCDK_MINTD_CLN_EXPOSE_PRIVATE_CHANNELSenvironment variableClnClient::open_private_channel()for integration testscreate_cln_backend_with_options()helper for integration teststest_expose_private_channelsTest plan
cargo test -p cdk-clnpassescargo clippy -p cdk-cln -- -D warningspassescargo fmtpassestest_expose_private_channels): opens private channel between CLN-1 and CLN-2, generates 10 invoices withexpose_private_channels=true, verifies at least one invoice includes private channel route hint (6/10 in local test)false)🤖 Generated with Claude Code