lsps-plugin: add cln-lsps-policy plugin for LSPS2 fee policy management - #9349
lsps-plugin: add cln-lsps-policy plugin for LSPS2 fee policy management#9349Andezion wants to merge 3 commits into
Conversation
9833ed2 to
7553558
Compare
7553558 to
2a4087f
Compare
2a4087f to
8c133c1
Compare
|
hey, think theres a name clash here cln-lsps-policy gets added to RUST_PLUGIN_NAMES and DEFAULT_TARGETS so it loads as a builtin by default. it registers lsps2-policy-getpolicy and lsps2-policy-getchannelcapacity, but tests/plugins/lsps2_policy.py already registers those exact same two names. so anyone supplying their own policy plugin (or just that fixture) would hit a duplicate rpc registration afaict is the default policy meant to be opt-in? or should it back off when another policy plugin is already loaded |
8c133c1 to
a49c382
Compare
niklasgruener
left a comment
There was a problem hiding this comment.
i found these while running the PR through Context Goblin, a code review tool we’re currently developing. the main concerns are around configuration validation and how malformed or unauthenticated requests interact with the default policy behavior. hope the comments are useful.
| proportional | ||
| ); | ||
| } | ||
| if valid_until_hours <= 0 { |
There was a problem hiding this comment.
this checks that the value is positive, but not that it can actually be converted below. a very large positive i64 would be accepted at startup, then Duration::try_hours would fail on every getpolicy call.
could we validate the upper bound here as well so an invalid config fails during startup?
| v: serde_json::Value, | ||
| ) -> Result<serde_json::Value, anyhow::Error> { | ||
| let _req: Lsps2PolicyGetInfoRequest = | ||
| serde_json::from_value(v).unwrap_or(Lsps2PolicyGetInfoRequest { token: None }); |
There was a problem hiding this comment.
could this propagate the deserialization error with serde_json::from_value(v)?, like on_getchannelcapacity does below?
right now malformed parameters are silently converted into { token: None }, so an invalid request becomes indistinguishable from a valid anonymous request. that could also become a fail-open path if token validation is added later.
| let _req: Lsps2PolicyGetChannelCapacityRequest = serde_json::from_value(v)?; | ||
|
|
||
| let res = Lsps2PolicyGetChannelCapacityResponse { | ||
| channel_capacity_msat: Some(p.state().channel_capacity_msat), |
There was a problem hiding this comment.
the request includes init_payment_size, but the response always uses the configured capacity.
with the defaults, this returns a 10,000,000,000 msat (0.1 BTC) channel regardless of the payment size, while the opening policy charges a flat 1,000 msat fee and client_rejected is always false.
could the capacity be derived or capped based on init_payment_size, or should the fixed-capacity and no-client-gating behavior be documented more explicitly?
a49c382 to
9bbd070
Compare
9bbd070 to
d203303
Compare
Summary
cln-lsps-servicecalls out to two internal RPC methods to make LSPS2 policydecisions -
lsps2-policy-getpolicyandlsps2-policy-getchannelcapacity-but no plugin in the repo registers them, so the service can't run standalone
This adds a new
cln-lsps-policybinary that implements both:lsps2-policy-getpolicy- returns the LSP's fee parameter menu(
Lsps2PolicyGetInfoResponse), built from configurable CLN options.lsps2-policy-getchannelcapacity- returns the channel capacity to openfor a given JIT-channel buy request (
Lsps2PolicyGetChannelCapacityResponse)All policy knods are exposed as plugin options with sensible defaults, so an
LSP operator can tune fees/limits without touching code:
lsps2-policy-min-fee-msatlsps2-policy-proportional-ppmlsps2-policy-valid-until-hourslsps2-policy-min-lifetimelsps2-policy-max-client-to-self-delaylsps2-policy-min-payment-size-msatlsps2-policy-max-payment-size-msatlsps2-policy-channel-capacity-msatValues are validated at startup (non-negative,
max > min, ppm in[0, 1_000_000]) so misconfiguration fails fast instead of silentlyproducing bad fee params
Test plan
cargo build- all three binaries (cln-lsps-client,cln-lsps-service,cln-lsps-policy) compile cleanlycargo test- 84 passed, 0 failed (no regressions in existinglsps-plugin test suite)
cln-lsps-service+cln-lsps-policytogether against a client and confirm
lsps2.get_info/lsps2.buysucceedImportant
26.06 FREEZE April 30th: Non-bugfix PRs not ready by this date will wait for 26.09.
RC1 is scheduled on May 14th
The final release is scheduled for June 1st.
Checklist
Before submitting the PR, ensure the following tasks are completed. If an item is not applicable to your PR, please mark it as checked:
tools/lightning-downgradeChangelog-None