chanbackup: add SimpleTaprootFinalVersion for production taproot backups
What changed, and why it matters
This commit adds a new backup version number (7) for a specific type of taproot Lightning channel. It is a compatibility and labeling change in how channel backups are created and recognized, not a fix for an active security flaw. There is no evidence in the commit of a vulnerability being exploited or of malicious behavior.
No immediate security action required. Treat as a normal compatibility/format update. Review related release notes or follow-up commits if you operate taproot channels to ensure backup/restore workflows recognize the new version.
Security signals we found
New backup version constant added for production taproot channel type
Serialization/deserialization paths updated to accept the new version
No cryptographic, authorization, or input-validation changes present
No mention of vulnerability, CVE, bug, exploit, or security fix in commit message or diff
Evidence from the diff
The change introduces SimpleTaprootFinalVersion = 7 in chanbackup/single.go to mark production taproot channels that use final scripts with OP_CHECKSIGVERIFY, distinguishing them from earlier staging taproot channels. It updates version decoding, taproot detection, backup creation, serialization, and deserialization to recognize the new version. This is a forward-compatibility/data-format change; it does not alter cryptographic logic, fix a bug, or patch an exploit vector.
Changed components
lnd/chanbackup/single.goStatic Channel Backup (SCB) version handlingTaproot channel backup formatInspect captured patch +12 / −1
diff --git a/chanbackup/single.go b/chanbackup/single.go
index 01d14f6..0a38d6b 100644
--- a/chanbackup/single.go
+++ b/chanbackup/single.go
@@ -59,6 +59,11 @@ const (
// channel with a top level tapscript commitment.
TapscriptRootVersion = 6
+ // SimpleTaprootFinalVersion is a version that denotes this channel is
+ // using the production musig2 based taproot commitment format with
+ // final scripts (OP_CHECKSIGVERIFY instead of OP_CHECKSIG + OP_DROP).
+ SimpleTaprootFinalVersion = 7
+
// closeTxVersionMask is the byte mask used that is ORed to version byte
// on wire indicating that the backup has CloseTxInputs.
closeTxVersionMask = 1 << 7
@@ -94,7 +99,8 @@ func DecodeVersion(encoded byte) (SingleBackupVersion, bool) {
// IsTaproot returns if this is a backup of a taproot channel. This will also be
// true for simple taproot overlay channels when a version is added.
func (v SingleBackupVersion) IsTaproot() bool {
- return v == SimpleTaprootVersion || v == TapscriptRootVersion
+ return v == SimpleTaprootVersion || v == TapscriptRootVersion ||
+ v == SimpleTaprootFinalVersion
}
// HasTapscriptRoot returns true if the channel is using a top level tapscript
@@ -302,6 +308,9 @@ func NewSingle(channel *channeldb.OpenChannel,
}
switch {
+ case channel.ChanType.IsTaprootFinal():
+ single.Version = SimpleTaprootFinalVersion
+
case channel.ChanType.IsTaproot():
if channel.ChanType.HasTapscriptRoot() {
single.Version = TapscriptRootVersion
@@ -351,6 +360,7 @@ func (s *Single) Serialize(w io.Writer) error {
case ScriptEnforcedLeaseVersion:
case SimpleTaprootVersion:
case TapscriptRootVersion:
+ case SimpleTaprootFinalVersion:
default:
return fmt.Errorf("unable to serialize w/ unknown "+
"version: %v", s.Version)
@@ -585,6 +595,7 @@ func (s *Single) Deserialize(r io.Reader) error {
case ScriptEnforcedLeaseVersion:
case SimpleTaprootVersion:
case TapscriptRootVersion:
+ case SimpleTaprootFinalVersion:
default:
return fmt.Errorf("unable to de-serialize w/ unknown "+
"version: %v", s.Version)
Why this scored 19/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.