Skip to content

Commit 8e3e206

Browse files
authored
Increase channel spent delay to 72 blocks (#3110)
We previously waited for 12 blocks before removing spent channels from our graph: the spec updates this delay to 72 blocks to allow more time for splice announcement in lightning/bolts#1270. We also make this configurable, which can simplify testing and allows nodes to wait even longer if they wish.
1 parent 8abb525 commit 8e3e206

File tree

6 files changed

+10
-4
lines changed

6 files changed

+10
-4
lines changed

eclair-core/src/main/resources/reference.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,9 @@ eclair {
415415

416416
router {
417417
watch-spent-window = 60 minutes // at startup watches on public channels will be put back within that window to reduce herd effect; must be > 0s
418+
// when we detect that a remote channel has been spent on-chain, we wait for 72 blocks before removing it from the graph
419+
// if this was a splice instead of a close, we will be able to simply update the channel in our graph and keep its reputation
420+
channel-spent-splice-delay = 72
418421

419422
channel-exclude-duration = 60 seconds // when a temporary channel failure is returned, we exclude the channel from our payment routes for this duration
420423
broadcast-interval = 60 seconds // see BOLT #7

eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ object NodeParams extends Logging {
664664
),
665665
routerConf = RouterConf(
666666
watchSpentWindow = watchSpentWindow,
667+
channelSpentSpliceDelay = config.getInt("router.channel-spent-splice-delay"),
667668
channelExcludeDuration = FiniteDuration(config.getDuration("router.channel-exclude-duration").getSeconds, TimeUnit.SECONDS),
668669
routerBroadcastInterval = FiniteDuration(config.getDuration("router.broadcast-interval").getSeconds, TimeUnit.SECONDS),
669670
syncConf = Router.SyncConf(

eclair-core/src/main/scala/fr/acinq/eclair/remote/EclairInternalsSerializer.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ object EclairInternalsSerializer {
109109

110110
val routerConfCodec: Codec[RouterConf] = (
111111
("watchSpentWindow" | finiteDurationCodec) ::
112+
("channelSpentSpliceDelay" | int32) ::
112113
("channelExcludeDuration" | finiteDurationCodec) ::
113114
("routerBroadcastInterval" | finiteDurationCodec) ::
114115
("syncConf" | syncConfCodec) ::

eclair-core/src/main/scala/fr/acinq/eclair/router/Router.scala

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ class Router(val nodeParams: NodeParams, watcher: typed.ActorRef[ZmqWatcher.Comm
266266
case Event(WatchExternalChannelSpentTriggered(shortChannelId, spendingTx), d) if d.channels.contains(shortChannelId) || d.prunedChannels.contains(shortChannelId) =>
267267
val fundingTxId = d.channels.get(shortChannelId).orElse(d.prunedChannels.get(shortChannelId)).get.fundingTxId
268268
log.info("funding tx txId={} of channelId={} has been spent by txId={}: waiting for the spending tx to have enough confirmations before removing the channel from the graph", fundingTxId, shortChannelId, spendingTx.txid)
269-
watcher ! WatchTxConfirmed(self, spendingTx.txid, ANNOUNCEMENTS_MINCONF * 2)
269+
watcher ! WatchTxConfirmed(self, spendingTx.txid, nodeParams.routerConf.channelSpentSpliceDelay)
270270
stay() using d.copy(spentChannels = d.spentChannels.updated(spendingTx.txid, d.spentChannels.getOrElse(spendingTx.txid, Set.empty) + shortChannelId))
271271

272272
case Event(WatchTxConfirmedTriggered(_, _, spendingTx), d) =>
@@ -345,9 +345,6 @@ class Router(val nodeParams: NodeParams, watcher: typed.ActorRef[ZmqWatcher.Comm
345345

346346
object Router {
347347

348-
// see https://github.com/lightningnetwork/lightning-rfc/blob/master/07-routing-gossip.md#requirements
349-
val ANNOUNCEMENTS_MINCONF = 6
350-
351348
def props(nodeParams: NodeParams, watcher: typed.ActorRef[ZmqWatcher.Command], initialized: Option[Promise[Done]] = None) = Props(new Router(nodeParams, watcher, initialized))
352349

353350
case class SearchBoundaries(maxFeeFlat: MilliSatoshi,
@@ -382,6 +379,7 @@ object Router {
382379
}
383380

384381
case class RouterConf(watchSpentWindow: FiniteDuration,
382+
channelSpentSpliceDelay: Int,
385383
channelExcludeDuration: FiniteDuration,
386384
routerBroadcastInterval: FiniteDuration,
387385
syncConf: SyncConf,

eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ object TestConstants {
200200
),
201201
routerConf = RouterConf(
202202
watchSpentWindow = 1 second,
203+
channelSpentSpliceDelay = 12,
203204
channelExcludeDuration = 60 seconds,
204205
routerBroadcastInterval = 1 day, // "disables" rebroadcast
205206
syncConf = Router.SyncConf(
@@ -389,6 +390,7 @@ object TestConstants {
389390
),
390391
routerConf = RouterConf(
391392
watchSpentWindow = 1 second,
393+
channelSpentSpliceDelay = 12,
392394
channelExcludeDuration = 60 seconds,
393395
routerBroadcastInterval = 1 day, // "disables" rebroadcast
394396
syncConf = Router.SyncConf(

eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ abstract class IntegrationSpec extends TestKitBaseClass with BitcoindService wit
8585
"eclair.channel.max-htlc-value-in-flight-percent" -> 100,
8686
"eclair.channel.max-block-processing-delay" -> "2 seconds",
8787
"eclair.channel.to-remote-delay-blocks" -> 24,
88+
"eclair.router.channel-spent-splice-delay" -> 12,
8889
"eclair.router.broadcast-interval" -> "2 seconds",
8990
"eclair.auto-reconnect" -> false,
9091
"eclair.multi-part-payment-expiry" -> "20 seconds",

0 commit comments

Comments
 (0)