eclair icon indicating copy to clipboard operation
eclair copied to clipboard

Liquidity Ads

Open t-bast opened this issue 3 years ago • 4 comments

The initiator of open_channel2, tx_init_rbf and splice_init can request funding from the remote node. The non-initiator node will:

  • let the open-channel-interceptor plugin decide whether to lease liquidity for new channels or not, and how much
  • always honor liquidity requests on existing channels (RBF and splice)

We currently don't modify commitment transactions to enforce the lease. This is different from https://github.com/lightning/bolts/pull/878 and instead matches https://github.com/lightning/bolts/pull/1145.

We currently use the temporary tlv tag 1337 while we're waiting for feedback on our spec proposal.

Liquidity ads are included in the node_announcement message, which lets buyers compare sellers and connect to sellers that provide rates they are comfortable with.

We store every liquidity purchase (whether we're buyer or seller) in the audit DB. This is important information when choosing which peers are worth keeping channels with.

t-bast avatar Jan 04 '23 09:01 t-bast

Codecov Report

Attention: Patch coverage is 93.85475% with 22 lines in your changes are missing coverage. Please review.

Project coverage is 86.07%. Comparing base (c8184b3) to head (74f2c0d).

:exclamation: Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2550      +/-   ##
==========================================
+ Coverage   85.96%   86.07%   +0.11%     
==========================================
  Files         219      220       +1     
  Lines       18441    18709     +268     
  Branches      762      809      +47     
==========================================
+ Hits        15853    16104     +251     
- Misses       2588     2605      +17     
Files Coverage Δ
...r-core/src/main/scala/fr/acinq/eclair/Eclair.scala 56.61% <100.00%> (+0.18%) :arrow_up:
.../src/main/scala/fr/acinq/eclair/PluginParams.scala 66.66% <ø> (ø)
...in/scala/fr/acinq/eclair/channel/ChannelData.scala 100.00% <ø> (ø)
.../scala/fr/acinq/eclair/channel/ChannelEvents.scala 100.00% <100.00%> (ø)
...c/main/scala/fr/acinq/eclair/channel/Helpers.scala 94.56% <100.00%> (+0.02%) :arrow_up:
...in/scala/fr/acinq/eclair/channel/fsm/Channel.scala 85.47% <100.00%> (+0.27%) :arrow_up:
...inq/eclair/channel/fund/InteractiveTxBuilder.scala 91.80% <100.00%> (+0.42%) :arrow_up:
...cinq/eclair/channel/fund/InteractiveTxFunder.scala 92.80% <100.00%> (+0.32%) :arrow_up:
...c/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala 99.73% <100.00%> (+0.04%) :arrow_up:
...cala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala 99.72% <100.00%> (+0.04%) :arrow_up:
... and 16 more

... and 1 file with indirect coverage changes

codecov-commenter avatar Jan 04 '23 09:01 codecov-commenter

FYI, here is a patch on channel/Monitoring.scala to track liquidity splices:

diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Monitoring.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Monitoring.scala
index fa15594cc0..4900a46467 100644
--- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Monitoring.scala
+++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Monitoring.scala
@@ -57,10 +57,18 @@ object Monitoring {
      */
     def recordSplice(fundingParams: InteractiveTxParams, sharedTx: SharedTransaction): Unit = {
       if (fundingParams.localContribution > 0.sat) {
-        Metrics.Splices.withTag(Tags.Origin, Tags.Origins.Local).withTag(Tags.SpliceType, Tags.SpliceTypes.SpliceIn).record(fundingParams.localContribution.toLong)
+        if (fundingParams.isInitiator) {
+          Metrics.Splices.withTag(Tags.Origin, Tags.Origins.Local).withTag(Tags.SpliceType, Tags.SpliceTypes.SpliceIn).record(fundingParams.localContribution.toLong)
+        } else {
+          Metrics.Splices.withTag(Tags.Origin, Tags.Origins.Local).withTag(Tags.SpliceType, Tags.SpliceTypes.SpliceLiquidity).record(fundingParams.localContribution.toLong)
+        }
       }
       if (fundingParams.remoteContribution > 0.sat) {
-        Metrics.Splices.withTag(Tags.Origin, Tags.Origins.Remote).withTag(Tags.SpliceType, Tags.SpliceTypes.SpliceIn).record(fundingParams.remoteContribution.toLong)
+        if (fundingParams.isInitiator) {
+          Metrics.Splices.withTag(Tags.Origin, Tags.Origins.Remote).withTag(Tags.SpliceType, Tags.SpliceTypes.SpliceLiquidity).record(fundingParams.remoteContribution.toLong)
+        } else {
+          Metrics.Splices.withTag(Tags.Origin, Tags.Origins.Remote).withTag(Tags.SpliceType, Tags.SpliceTypes.SpliceIn).record(fundingParams.remoteContribution.toLong)
+        }
       }
       if (sharedTx.localOnlyNonChangeOutputs.nonEmpty) {
         Metrics.Splices.withTag(Tags.Origin, Tags.Origins.Local).withTag(Tags.SpliceType, Tags.SpliceTypes.SpliceOut).record(sharedTx.localOnlyNonChangeOutputs.map(_.amount).sum.toLong)
@@ -68,10 +76,10 @@ object Monitoring {
       if (sharedTx.remoteOutputs.nonEmpty) {
         Metrics.Splices.withTag(Tags.Origin, Tags.Origins.Remote).withTag(Tags.SpliceType, Tags.SpliceTypes.SpliceOut).record(sharedTx.remoteOutputs.map(_.amount).sum.toLong)
       }
-      if (fundingParams.localContribution < 0.sat && sharedTx.localOutputs.isEmpty) {
+      if (fundingParams.localContribution < 0.sat && sharedTx.localOutputs.isEmpty && fundingParams.remoteContribution == 0.sat) {
         Metrics.Splices.withTag(Tags.Origin, Tags.Origins.Local).withTag(Tags.SpliceType, Tags.SpliceTypes.SpliceCpfp).record(Math.abs(fundingParams.localContribution.toLong))
       }
-      if (fundingParams.remoteContribution < 0.sat && sharedTx.remoteOutputs.isEmpty) {
+      if (fundingParams.remoteContribution < 0.sat && sharedTx.remoteOutputs.isEmpty && fundingParams.localContribution == 0.sat) {
         Metrics.Splices.withTag(Tags.Origin, Tags.Origins.Remote).withTag(Tags.SpliceType, Tags.SpliceTypes.SpliceCpfp).record(Math.abs(fundingParams.remoteContribution.toLong))
       }
     }
@@ -114,6 +122,7 @@ object Monitoring {
       val SpliceIn = "splice-in"
       val SpliceOut = "splice-out"
       val SpliceCpfp = "splice-cpfp"
+      val SpliceLiquidity = "splice-liquidity"
     }
   }

A "purer" way would have been to add a isInitiator tag, instead of a SpliceLiquidity type, but it's also less user friendly. Here we are arbitrarily categorizing splices anyway. Will see how it goes on feature branches.

pm47 avatar Dec 12 '23 15:12 pm47

Please rebase 🙏

pm47 avatar Mar 28 '24 16:03 pm47

Rebased and squashed! I'll work on porting the annoying-to-rebase parts to master to simplify future rebases.

t-bast avatar Mar 29 '24 10:03 t-bast

Superseded by #2848

t-bast avatar Jul 19 '24 09:07 t-bast