Skip to content

Commit 409c7c1

Browse files
authored
Don't store anchor transaction in channel data (#3187)
We don't need to store the anchor transaction in our channel data when closing a channel: this isn't used anywhere and unnecessarily uses space in our DB. Also, once the commit tx is confirmed, we don't need to watch the anchor output again on restarts.
1 parent 51a144c commit 409c7c1

File tree

3 files changed

+9
-11
lines changed

3 files changed

+9
-11
lines changed

eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,8 +1645,8 @@ object Helpers {
16451645
val relevantOutpoints = tx.txIn.map(_.outPoint).filter(outPoint => {
16461646
// is this the commit tx itself? (we could do this outside of the loop...)
16471647
val isCommitTx = localCommitPublished.commitTx.txid == tx.txid
1648-
// does the tx spend an output of the local commitment tx?
1649-
val spendsTheCommitTx = localCommitPublished.commitTx.txid == outPoint.txid
1648+
// does the tx spend an output of the local commitment tx (other than the anchor output)?
1649+
val spendsTheCommitTx = localCommitPublished.commitTx.txid == outPoint.txid && !localCommitPublished.anchorOutput_opt.contains(outPoint)
16501650
// is the tx one of our 3rd stage delayed txs? (a 3rd stage tx is a tx spending the output of an htlc tx, which
16511651
// is itself spending the output of the commitment tx)
16521652
val is3rdStageDelayedTx = localCommitPublished.htlcDelayedOutputs.contains(outPoint)
@@ -1672,8 +1672,8 @@ object Helpers {
16721672
val relevantOutpoints = tx.txIn.map(_.outPoint).filter(outPoint => {
16731673
// is this the commit tx itself? (we could do this outside of the loop...)
16741674
val isCommitTx = remoteCommitPublished.commitTx.txid == tx.txid
1675-
// does the tx spend an output of the remote commitment tx?
1676-
val spendsTheCommitTx = remoteCommitPublished.commitTx.txid == outPoint.txid
1675+
// does the tx spend an output of the remote commitment tx (other than the anchor output)?
1676+
val spendsTheCommitTx = remoteCommitPublished.commitTx.txid == outPoint.txid && !remoteCommitPublished.anchorOutput_opt.contains(outPoint)
16771677
isCommitTx || spendsTheCommitTx
16781678
})
16791679
// then we add the relevant outpoints to the map keeping track of which txid spends which outpoint
@@ -1696,8 +1696,8 @@ object Helpers {
16961696
val relevantOutpoints = tx.txIn.map(_.outPoint).filter(outPoint => {
16971697
// is this the commit tx itself? (we could do this outside of the loop...)
16981698
val isCommitTx = revokedCommitPublished.commitTx.txid == tx.txid
1699-
// does the tx spend an output of the remote commitment tx?
1700-
val spendsTheCommitTx = revokedCommitPublished.commitTx.txid == outPoint.txid
1699+
// does the tx spend an output of the remote commitment tx (other than the anchor output)?
1700+
val spendsTheCommitTx = revokedCommitPublished.commitTx.txid == outPoint.txid && !revokedCommitPublished.anchorOutput_opt.contains(outPoint)
17011701
// is the tx one of our 3rd stage delayed txs? (a 3rd stage tx is a tx spending the output of an htlc tx, which
17021702
// is itself spending the output of the commitment tx)
17031703
val is3rdStageDelayedTx = revokedCommitPublished.htlcDelayedOutputs.contains(outPoint)

eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ErrorHandlers.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ trait ErrorHandlers extends CommonHandlers {
256256
// we will watch for its confirmation. This ensures that we detect double-spends that could come from:
257257
// - our own RBF attempts
258258
// - remote transactions for outputs that both parties may spend (e.g. HTLCs)
259-
val watchSpentQueue = lcp.localOutput_opt ++ lcp.anchorOutput_opt ++ lcp.htlcOutputs.toSeq
259+
val watchSpentQueue = lcp.localOutput_opt ++ (if (!lcp.isConfirmed) lcp.anchorOutput_opt else None) ++ lcp.htlcOutputs.toSeq
260260
watchSpentIfNeeded(lcp.commitTx, watchSpentQueue, lcp.irrevocablySpent)
261261
}
262262

@@ -337,7 +337,7 @@ trait ErrorHandlers extends CommonHandlers {
337337
// we will watch for its confirmation. This ensures that we detect double-spends that could come from:
338338
// - our own RBF attempts
339339
// - remote transactions for outputs that both parties may spend (e.g. HTLCs)
340-
val watchSpentQueue = rcp.localOutput_opt ++ rcp.anchorOutput_opt ++ rcp.htlcOutputs.toSeq
340+
val watchSpentQueue = rcp.localOutput_opt ++ (if (!rcp.isConfirmed) rcp.anchorOutput_opt else None) ++ rcp.htlcOutputs.toSeq
341341
watchSpentIfNeeded(rcp.commitTx, watchSpentQueue, rcp.irrevocablySpent)
342342
}
343343

eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -993,7 +993,6 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with
993993
awaitCond(alice.stateName == CLOSING)
994994
// Alice republishes the HTLC-success transaction, which then confirms.
995995
assert(alice2blockchain.expectReplaceableTxPublished[HtlcSuccessTx].input == htlcSuccess.input)
996-
closingTxs.anchorTx_opt.foreach(anchorTx => alice2blockchain.expectWatchOutputSpent(anchorTx.txIn.head.outPoint))
997996
alice2blockchain.expectWatchOutputSpent(htlcSuccess.input.outPoint)
998997
alice ! WatchOutputSpentTriggered(htlcSuccess.amountIn, htlcSuccess.tx)
999998
alice2blockchain.expectWatchTxConfirmed(htlcSuccess.tx.txid)
@@ -1010,7 +1009,6 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with
10101009
alice ! INPUT_RESTORED(beforeRestart2)
10111010
alice2blockchain.expectMsgType[SetChannelId]
10121011
awaitCond(alice.stateName == CLOSING)
1013-
closingTxs.anchorTx_opt.foreach(anchorTx => alice2blockchain.expectWatchOutputSpent(anchorTx.txIn.head.outPoint))
10141012
// Alice republishes the 3rd-stage HTLC transaction, which then confirms.
10151013
alice2blockchain.expectFinalTxPublished(htlcDelayedTx.tx.txid)
10161014
alice2blockchain.expectWatchOutputSpent(htlcDelayedTx.input)
@@ -1252,7 +1250,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with
12521250

12531251
// Bob re-publishes closing transactions: he has 1 HTLC-success and 1 HTLC-timeout transactions left.
12541252
val republishedHtlcTxsBob = (1 to 2).map(_ => bob2blockchain.expectMsgType[PublishReplaceableTx])
1255-
bob2blockchain.expectWatchOutputsSpent(remainingHtlcOutputs ++ closingTxsBob.anchorTx_opt.map(_.txIn.head.outPoint).toSeq)
1253+
bob2blockchain.expectWatchOutputsSpent(remainingHtlcOutputs)
12561254
assert(republishedHtlcTxsBob.map(_.input).toSet == Set(htlcTimeoutTxBob2.txIn.head.outPoint, closingTxsBob.htlcSuccessTxs.head.txIn.head.outPoint))
12571255
bob2blockchain.expectNoMessage(100 millis)
12581256

0 commit comments

Comments
 (0)