multi: update models.ChannelAuthProof with v2 field

Also update it to more closely match the persisted version which has the
v1 and v2 only fields as optional.

Refactor ChannelAuthProof to support both v1 and v2 channel
announcements:

- Add Version field to distinguish v1 from v2 proofs
- Wrap v1-specific fields (NodeSig1/2, BitcoinSig1/2) in fn.Option
  since v2 doesn't use them
- Add optional Signature field for v2's single schnorr signature
- Add constructor functions NewV1ChannelAuthProof and
  NewV2ChannelAuthProof to enforce correct initialization
- Add getter methods (NodeSig1(), BitcoinSig1(), etc.) that safely
  unwrap options, returning empty slices when not present

The IsEmpty() check is updated to handle both versions correctly.
Both stores validate v1-only for now.
This commit is contained in:
Elle Mouton committed 2026-02-13 07:21:22 +02:00
1 parent 4480352d59
commit 7a260ee103
11 files changed
+300 -175

No files matched your search

+95 -11
View File
@@ -1,35 +1,119 @@
package models
import (
"github.com/lightningnetwork/lnd/fn/v2"
"github.com/lightningnetwork/lnd/lnwire"
)
// ChannelAuthProof is the authentication proof (the signature portion) for a
// channel. Using the four signatures contained in the struct, and some
// channel.
//
// For v1 channels:
// Using the four node and bitcoin signatures contained in the struct, and some
// auxiliary knowledge (the funding script, node identities, and outpoint) nodes
// on the network are able to validate the authenticity and existence of a
// channel. Each of these signatures signs the following digest: chanID ||
// nodeID1 || nodeID2 || bitcoinKey1|| bitcoinKey2 || 2-byte-feature-len ||
// features.
//
// For v2 channels:
// The single schnorr signature signs the tlv fields of the v2 channel
// announcement message which are in the signed range.
type ChannelAuthProof struct {
// Version is the version of the channel announcement.
Version lnwire.GossipVersion
// NodeSig1Bytes are the raw bytes of the first node signature encoded
// in DER format.
NodeSig1Bytes []byte
//
// NOTE: v1 channel announcements only.
NodeSig1Bytes fn.Option[[]byte]
// NodeSig2Bytes are the raw bytes of the second node signature
// encoded in DER format.
NodeSig2Bytes []byte
//
// NOTE: v1 channel announcements only.
NodeSig2Bytes fn.Option[[]byte]
// BitcoinSig1Bytes are the raw bytes of the first bitcoin signature
// encoded in DER format.
BitcoinSig1Bytes []byte
//
// NOTE: v1 channel announcements only.
BitcoinSig1Bytes fn.Option[[]byte]
// BitcoinSig2Bytes are the raw bytes of the second bitcoin signature
// encoded in DER format.
BitcoinSig2Bytes []byte
//
// NOTE: v1 channel announcements only.
BitcoinSig2Bytes fn.Option[[]byte]
// Signature is the raw bytes of the single schnorr signature for v2
// channel announcements.
//
// NOTE: v2 channel announcements only.
Signature fn.Option[[]byte]
}
// IsEmpty check is the authentication proof is empty Proof is empty if at
// least one of the signatures are equal to nil.
// IsEmpty check is the authentication proof is empty Proof is empty.
func (c *ChannelAuthProof) IsEmpty() bool {
return len(c.NodeSig1Bytes) == 0 ||
len(c.NodeSig2Bytes) == 0 ||
len(c.BitcoinSig1Bytes) == 0 ||
len(c.BitcoinSig2Bytes) == 0
// For v1 channel announcements, we either have all four signatures or
// none.
if c.Version == lnwire.GossipVersion1 {
return c.NodeSig1Bytes.IsNone()
}
// For v2 channel announcements, we only have a single signature.
return c.Signature.IsNone()
}
// NewV1ChannelAuthProof creates a new ChannelAuthProof for a v1 channel
// announcement.
func NewV1ChannelAuthProof(nodeSig1, nodeSig2, bitcoinSig1,
bitcoinSig2 []byte) *ChannelAuthProof {
return &ChannelAuthProof{
Version: lnwire.GossipVersion1,
NodeSig1Bytes: fn.Some(nodeSig1),
NodeSig2Bytes: fn.Some(nodeSig2),
BitcoinSig1Bytes: fn.Some(bitcoinSig1),
BitcoinSig2Bytes: fn.Some(bitcoinSig2),
}
}
// NewV2ChannelAuthProof creates a new ChannelAuthProof for a v2 channel
// announcement.
func NewV2ChannelAuthProof(signature []byte) *ChannelAuthProof {
return &ChannelAuthProof{
Version: lnwire.GossipVersion2,
Signature: fn.Some(signature),
}
}
// NodeSig1 returns the first node signature bytes, or an empty slice if not
// present.
func (c *ChannelAuthProof) NodeSig1() []byte {
return c.NodeSig1Bytes.UnwrapOr([]byte{})
}
// NodeSig2 returns the second node signature bytes, or an empty slice if not
// present.
func (c *ChannelAuthProof) NodeSig2() []byte {
return c.NodeSig2Bytes.UnwrapOr([]byte{})
}
// BitcoinSig1 returns the first bitcoin signature bytes, or an empty slice if
// not present.
func (c *ChannelAuthProof) BitcoinSig1() []byte {
return c.BitcoinSig1Bytes.UnwrapOr([]byte{})
}
// BitcoinSig2 returns the second bitcoin signature bytes, or an empty slice if
// not present.
func (c *ChannelAuthProof) BitcoinSig2() []byte {
return c.BitcoinSig2Bytes.UnwrapOr([]byte{})
}
// Sig returns the v2 signature bytes, or an empty slice if not present.
func (c *ChannelAuthProof) Sig() []byte {
return c.Signature.UnwrapOr([]byte{})
}