Update taproot commit weight to match `lnd` (#3158)
What changed, and why it matters
This commit adjusts the estimated transaction size (weight) Eclair reserves when closing or updating Taproot Lightning channels. It makes Eclair's estimate match lnd's more pessimistic assumption about how many bytes are needed to count transaction inputs and outputs. If the estimate is too low, a channel partner could be forced to pay unexpectedly high on-chain fees or a cooperative close could fail; if too high, funds get locked up longer than necessary. The change is a small numeric tweak from 960 to 968, not a clear-cut vulnerability fix.
Treat as a routine interoperability and safety-margin improvement rather than an urgent security patch. Reviewers should verify that 968 weight units correctly covers the worst-case output-count encoding and that related fee/reserve calculations downstream use this value consistently. No immediate user action is required unless the project specifically flags this as a consensus or security fix.
Security signals we found
Fee/weight estimation mismatch between implementations
Taproot Lightning channel commitment transaction sizing
Interoperability alignment with lnd
Potential for under- or over-reserved on-chain fees
Evidence from the diff
The patch changes commitWeight for SimpleTaprootChannelCommitmentFormat from 960 to 968 in Transactions.scala. The comment explains that the extra 8 weight units account for encoding the transaction output count as a 3-byte varint instead of a 1-byte varint, matching lnd’s pessimistic weight estimate. This weight is used when computing commitment transaction fees and reserve amounts in Taproot Lightning channels. The change is a compatibility/consistency adjustment; it does not by itself fix an obvious memory-safety bug, crash, or cryptographic flaw, but an incorrect weight could affect fee accounting and mutual-close safety margins.
Changed components
eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scalaSimpleTaprootChannelCommitmentFormatcommitment transaction weight calculationInspect captured patch +5 / −3
diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala b/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala
index 6c62891..d60a70b 100644
--- a/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala
+++ b/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala
@@ -171,10 +171,12 @@ object Transactions {
sealed trait TaprootCommitmentFormat extends CommitmentFormat
sealed trait SimpleTaprootChannelCommitmentFormat extends TaprootCommitmentFormat {
- // weights for taproot transactions are deterministic since signatures are encoded as 64 bytes and
- // not in variable length DER format (around 72 bytes)
+ // Weights for taproot transactions are deterministic since signatures are encoded as 64 bytes and not in variable
+ // length DER format like ECDSA (which is used for segwit v0 commitment formats).
override val fundingInputWeight = 230
- override val commitWeight = 960
+ // Note that the commit weight assumes that the number of outputs is encoded using 3 bytes, to handle the case
+ // where we have a lot of HTLCs pending.
+ override val commitWeight = 968
override val anchorInputWeight = 230
override val htlcOutputWeight = 172
override val htlcTimeoutWeight = 645
Why this scored 33/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.