bitcoin-dev-project/sim-ln

Feature: Multi-Implementation Support

carlaKC opened this issue · 14 comments

Add alternative implementations of LightningNode trait for:

  • Core Lightning
  • Eclair
  • LDK Node

I'd suggest starting with CLN or LDK-node first, so those are likely the easiest.

New tasks. Blocked by incompleteness in CLN rpc types

  • CLN track payment needs to report failure reason
  • CLN track payment needs to report htlc count
    • fix: we use listpays number_of_parts where available, or default to 1

We use lightning-listpays rpc, from which we don't get either of the above response fields

sr-gi commented

New tasks. Blocked by incompleteness in CLN rpc types

  • CLN track payment needs to report failure reason

  • CLN track payment needs to report htlc count

    • fix: we use listpays number_of_parts where available, or default to 1

We use lightning-listpays rpc, from which we don't get either of the above response fields

Let me take a look at that payment error data and how to parse it

Taking a look at LND's failure codes - some are spec-defined and some are "user friendly"/LND specific:

Custom LND Errors

These are not related to spec failure_code, and are just additional information that LND API surfaces.

LND could not find a route (due to timeout / no route / no local liquidity):

  • FAILURE_REASON_TIMEOUT PaymentFailureReason = 1
  • FAILURE_REASON_NO_ROUTE PaymentFailureReason = 2
  • FAILURE_REASON_INSUFFICIENT_BALANCE PaymentFailureReason = 5

Spec errors:

Spec failure codes related to the details for the final hop are represented by a single LND API value.

FAILURE_REASON_INCORRECT_PAYMENT_DETAILS PaymentFailureReason = 4 represents spec failure_codes:

  • 18 / final_incorrect_cltv_expiry
  • 19/ final_incorrect_htlc_amount

Any other failure code is expressed with a generic error value: FAILURE_REASON_ERROR PaymentFailureReason = 3

I think we're probably going to have to go with our own mapping - something like this:

PAYMENT_NOT_SENT represents:

  • LND/FAILURE_REASON_TIMEOUT
  • LND/FAILURE_REASON_NO_ROUTE
  • LND/FAILURE_REASON_INSUFFICIENT_BALANCE

INCORRECT_DETAILS represents:

  • LND/FAILURE_REASON_INCORRECT_PAYMENT_DETAILS
  • failure_code / 18
  • failure_code / 19

PAYMENT_FAILED represents:

  • LND/FAILURE_REASON_ERROR
  • failure_code/ any other value

Dropping this down to medium now that we have LND and CLN.

So I spent some time looking into LDK-Node integration and wanted to share some of my findings here in case there were any suggestions before I move forward.

  1. LDK-Node is in a library form and not a daemon with a CLI like LND or CLN. So the node needs to be configured, built and started within the code, rather than connected to as is done here with LND and CLN. I think that should be fine as it can be configured to point to an existing storage directory. So it can start up an existing node so long as it is not already running.
  2. Setting up LDK-Node in a local regtest environment is a little tricky as there’s not very good documentation for that, it's not a daemon like LND, and it does not yet work with bitcoind (needs to connect to an esplora server for chain sync). I was eventually able to set it up and send/receive keysend payments between an LDK-Node and an LND node in regtest.
  3. LDK-Node does not provide access to or customization of NodeFeatures. By default, the rust-lightning library sets the keysend_optional feature bit (55): https://github.com/lightningdevkit/rust-lightning/blob/3c9d88af2636422000402adb5aa4eab7c0845e81/lightning/src/ln/channelmanager.rs#L9490. One solution is to manually pass in the default NodeFeatures for Sim-LN.
  4. Separately, however, it does not allow keysend payments for mpp. https://github.com/lightningdevkit/rust-lightning/blob/3c9d88af2636422000402adb5aa4eab7c0845e81/lightning/src/util/config.rs#L825.
  5. For tracking payments, I would probably implement this the same as CLN, leveraging the list_payments method on the Node api, and waiting 500ms. However, the payment details don't return an HTLC count from my understanding. This is the extent of the details: https://docs.rs/ldk-node/latest/ldk_node/struct.PaymentDetails.html.

I'm working on a PR and that will provide more clarity on where other shortcomings / blockers might be, but thought I would just point this all out here in case you had any suggestions / concerns before I continue on.

Re 1 + 2:

While I'm not against our spinning up LDK nodes within Sim-LN some day, I don't really see it as a high priority if not yet pulled together into a usable daemon. Reasoning being that a) people probably aren't really using it right now if it's difficult to run and b) our value proposition is to add payment simulation to existing networks.

If you'd be interested, I think that working on eclair support would be a massive value add as it's one of the major players in the routing network and would be a great addition to be able to simulate more realistic networks.

That said, if the work of pulling together LDK node is minimal it could be something we could look - but I'd need some convincing tbh. Answers to the rest anyway:
3. Passing defaults in seems fine to me 👍
4. That's okay, I don't think that LND has MPP keysend either (we've already accepted that we have to add invoice based payments if we want MPP in sim-ln)
5. SGTM

Got it thanks @carlaKC! That makes sense to me and I agree it's prob not ready at this stage to be considered. I was eager to play with it and see what it is about, so this was a good learning experience regardless. 👍

For the reasons mentioned in this comment with whom I agree (especially the lack of current daemon-like runtime wrapping the LDK node library) I don't know if LDK node is the best way to go to support LDK. Even assuming a runtime is built around LDK node, I'm not sure if its Node API will expose htlc management related mechanism (node / channel features, payment details, modes of payments like mpp) to have sufficient support for Sim-LN experimentaiton.

On the other hand, ldk-sample already have a runtime built with a REPL shell to manage the node and its connects to
bitcoind. The REPL shell ain't great to integrate with the Sim-LN like done for CLN and LND, and it sounds a RPC interface
would have be to be landed and then maintained to support LDK.

I agree, it sounds the massive value add would be to add eclair support. From #181 and reading its documentation (README.md), here what could be tried to support eclair. There is an API where one can install plugin written in Scala, Java or any JVM-compatible language. I think from then a plugin could be designed to expose a GRPC interface and this interface driven by a sim-lib module to act sim actions (get_info, send_payment, track_payment, get_node_info, list_channels).

The Plugin API (https://github.com/ACINQ/eclair/blob/master/eclairnode/src/main/scala/fr/acinq/eclair/Plugin.scala) is minimally documented there is a collection of plugins available here (https://github.com/ACINQ/eclair-plugins). I don't know if one can be easy forked out to implement a sim-ln-rpc-interface, and I'm not sure if would work well with current sim-ln abstractions.

My take on this:

  1. Shelf LDK support for now, reconsider in future if there's user-demand or a cleaner way forward
  2. Add eclair support if there's a RPC plugin available out of the box, otherwise hold off there as well

Add eclair support if there's a RPC plugin available out of the box, otherwise hold off there as well

On eclair support, there is no RPC plugin available "just out of the box", however the current Eclair plugins and node architecture is reasonably easy to hack on, after just looking at it a couple of hours. Started a sim-ln module here: https://github.com/PurpleTimez/eclair-plugins/blob/eclair-sim-ln-plugin/sim-ln-module/src/main/scala/acinq/eclair/plugins/simln/SimLnPlugin.scala

From then, you can have eclair-cli instructing commands to the plugin to act on the state node. This can be called by a sim-ln runtime (e.g a forking process it might be more straightforward to call directly an eclair-cli). It might just be a bit more few hours to get that end-to-end working for a demo command, so I'm curious to try. Happy to get feedback if this sounds good to support eclair.