multi: update models.ChannelAuthProof with v2 field
What changed, and why it matters
This commit refactors how Lightning Network channel authentication proofs are represented in the lnd codebase. It adds support for a future v2 channel announcement format (using a single Schnorr signature) while keeping v1 (four ECDSA signatures) as the only currently supported version. The change is structural and preparatory; it does not appear to fix an active security bug, nor does it introduce obvious new vulnerabilities. Both database stores explicitly reject v2 proofs for now.
Treat as a routine refactor/feature-prep commit. Reviewers should verify that the new getter methods and option wrappers do not introduce nil-slice or empty-slice edge cases in signature validation paths, and that the explicit v1-only guards in both stores are consistently applied. No immediate security response is indicated.
Security signals we found
Refactoring of security-critical data structure (channel authentication proof)
Explicit rejection of unsupported v2 proofs in both database stores
Use of option types to prevent accidental use of absent v1/v2 fields
No validation logic changes for v1 signatures observed
No mention of CVE, security bug, or vulnerability in commit message
Evidence from the diff
The commit updates models.ChannelAuthProof to be version-aware: it adds a Version field, wraps v1-only signature fields in fn.Option[[]byte], and adds an optional Signature field for v2’s single Schnorr signature. Constructors NewV1ChannelAuthProof and NewV2ChannelAuthProof enforce correct initialization, and getter methods safely unwrap options. Call sites in the gossiper, RPC server, graph stores, and tests are updated to use the new API. Both KVStore and SQLStore explicitly reject non-v1 proofs with an error, and deserialization defaults to v1. The IsEmpty() logic is updated to check the appropriate signature for each version.
Changed components
graph/db/models/channel_auth_proof.gograph/db/kv_store.gograph/db/sql_store.godiscovery/gossiper.gonetann/channel_announcement.gorpcserver.goInspect captured patch +300 / −175
diff --git a/discovery/gossiper.go b/discovery/gossiper.go
index 9d0338c..2cbd4e8 100644
--- a/discovery/gossiper.go
+++ b/discovery/gossiper.go
@@ -2504,25 +2504,25 @@ func (d *AuthenticatedGossiper) updateChannel(ctx context.Context,
ExtraOpaqueData: info.ExtraOpaqueData,
}
chanAnn.NodeSig1, err = lnwire.NewSigFromECDSARawSignature(
- info.AuthProof.NodeSig1Bytes,
+ info.AuthProof.NodeSig1(),
)
if err != nil {
return nil, nil, err
}
chanAnn.NodeSig2, err = lnwire.NewSigFromECDSARawSignature(
- info.AuthProof.NodeSig2Bytes,
+ info.AuthProof.NodeSig2(),
)
if err != nil {
return nil, nil, err
}
chanAnn.BitcoinSig1, err = lnwire.NewSigFromECDSARawSignature(
- info.AuthProof.BitcoinSig1Bytes,
+ info.AuthProof.BitcoinSig1(),
)
if err != nil {
return nil, nil, err
}
chanAnn.BitcoinSig2, err = lnwire.NewSigFromECDSARawSignature(
- info.AuthProof.BitcoinSig2Bytes,
+ info.AuthProof.BitcoinSig2(),
)
if err != nil {
return nil, nil, err
@@ -2808,12 +2808,12 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(ctx context.Context,
// If the proof checks out, then we'll save the proof itself to
// the database so we can fetch it later when gossiping with
// other nodes.
- proof = &models.ChannelAuthProof{
- NodeSig1Bytes: ann.NodeSig1.ToSignatureBytes(),
- NodeSig2Bytes: ann.NodeSig2.ToSignatureBytes(),
- BitcoinSig1Bytes: ann.BitcoinSig1.ToSignatureBytes(),
- BitcoinSig2Bytes: ann.BitcoinSig2.ToSignatureBytes(),
- }
+ proof = models.NewV1ChannelAuthProof(
+ ann.NodeSig1.ToSignatureBytes(),
+ ann.NodeSig2.ToSignatureBytes(),
+ ann.BitcoinSig1.ToSignatureBytes(),
+ ann.BitcoinSig2.ToSignatureBytes(),
+ )
}
// With the proof validated (if necessary), we can now store it within
@@ -3758,21 +3758,25 @@ func (d *AuthenticatedGossiper) handleAnnSig(ctx context.Context,
// We now have both halves of the channel announcement proof, then
// we'll reconstruct the initial announcement so we can validate it
// shortly below.
- var dbProof models.ChannelAuthProof
+ var dbProof *models.ChannelAuthProof
if isFirstNode {
- dbProof.NodeSig1Bytes = ann.NodeSignature.ToSignatureBytes()
- dbProof.NodeSig2Bytes = oppProof.NodeSignature.ToSignatureBytes()
- dbProof.BitcoinSig1Bytes = ann.BitcoinSignature.ToSignatureBytes()
- dbProof.BitcoinSig2Bytes = oppProof.BitcoinSignature.ToSignatureBytes()
+ dbProof = models.NewV1ChannelAuthProof(
+ ann.NodeSignature.ToSignatureBytes(),
+ oppProof.NodeSignature.ToSignatureBytes(),
+ ann.BitcoinSignature.ToSignatureBytes(),
+ oppProof.BitcoinSignature.ToSignatureBytes(),
+ )
} else {
- dbProof.NodeSig1Bytes = oppProof.NodeSignature.ToSignatureBytes()
- dbProof.NodeSig2Bytes = ann.NodeSignature.ToSignatureBytes()
- dbProof.BitcoinSig1Bytes = oppProof.BitcoinSignature.ToSignatureBytes()
- dbProof.BitcoinSig2Bytes = ann.BitcoinSignature.ToSignatureBytes()
+ dbProof = models.NewV1ChannelAuthProof(
+ oppProof.NodeSignature.ToSignatureBytes(),
+ ann.NodeSignature.ToSignatureBytes(),
+ oppProof.BitcoinSignature.ToSignatureBytes(),
+ ann.BitcoinSignature.ToSignatureBytes(),
+ )
}
chanAnn, e1Ann, e2Ann, err := netann.CreateChanAnnouncement(
- &dbProof, chanInfo, e1, e2,
+ dbProof, chanInfo, e1, e2,
)
if err != nil {
log.Error(err)
@@ -3798,7 +3802,7 @@ func (d *AuthenticatedGossiper) handleAnnSig(ctx context.Context,
// attest to the bitcoin keys by validating the signatures of
// announcement. If proof is valid then we'll populate the channel edge
// with it, so we can announce it on peer connect.
- err = d.cfg.Graph.AddProof(ann.ShortChannelID, &dbProof)
+ err = d.cfg.Graph.AddProof(ann.ShortChannelID, dbProof)
if err != nil {
err := fmt.Errorf("unable add proof to the channel chanID=%v:"+
" %v", ann.ChannelID, err)
diff --git a/graph/builder_test.go b/graph/builder_test.go
index b6fe886..f2648a0 100644
--- a/graph/builder_test.go
+++ b/graph/builder_test.go
@@ -279,12 +279,12 @@ func TestWakeUpOnStaleBranch(t *testing.T) {
ChannelID: chanID1,
NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2Bytes: node2.PubKeyBytes,
- AuthProof: &models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- },
+ AuthProof: models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ ),
Features: lnwire.EmptyFeatureVector(),
FundingScript: fn.Some(fundingScript1),
}
@@ -300,12 +300,12 @@ func TestWakeUpOnStaleBranch(t *testing.T) {
ChannelID: chanID2,
NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2Bytes: node2.PubKeyBytes,
- AuthProof: &models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- },
+ AuthProof: models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ ),
Features: lnwire.EmptyFeatureVector(),
FundingScript: fn.Some(fundingScript2),
}
@@ -493,12 +493,12 @@ func TestDisconnectedBlocks(t *testing.T) {
NodeKey2Bytes: node2.PubKeyBytes,
BitcoinKey1Bytes: node1.PubKeyBytes,
BitcoinKey2Bytes: node2.PubKeyBytes,
- AuthProof: &models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- },
+ AuthProof: models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ ),
Features: lnwire.EmptyFeatureVector(),
FundingScript: fn.Some([]byte{}),
}
@@ -516,12 +516,12 @@ func TestDisconnectedBlocks(t *testing.T) {
NodeKey2Bytes: node2.PubKeyBytes,
BitcoinKey1Bytes: node1.PubKeyBytes,
BitcoinKey2Bytes: node2.PubKeyBytes,
- AuthProof: &models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- },
+ AuthProof: models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ ),
Features: lnwire.EmptyFeatureVector(),
FundingScript: fn.Some([]byte{}),
}
@@ -649,12 +649,12 @@ func TestChansClosedOfflinePruneGraph(t *testing.T) {
ChannelID: chanID1.ToUint64(),
NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2Bytes: node2.PubKeyBytes,
- AuthProof: &models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- },
+ AuthProof: models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ ),
ChannelPoint: *chanUTXO,
Capacity: chanValue,
Features: lnwire.EmptyFeatureVector(),
diff --git a/graph/db/graph_test.go b/graph/db/graph_test.go
index 7c4255b..fcae25e 100644
--- a/graph/db/graph_test.go
+++ b/graph/db/graph_test.go
@@ -566,12 +566,12 @@ func TestEdgeInsertionDeletion(t *testing.T) {
Version: lnwire.GossipVersion1,
ChannelID: chanID,
ChainHash: *chaincfg.MainNetParams.GenesisHash,
- AuthProof: &models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- },
+ AuthProof: models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ ),
Features: lnwire.EmptyFeatureVector(),
ChannelPoint: outpoint,
Capacity: 9000,
@@ -642,12 +642,12 @@ func createEdge(height, txIndex uint32, txPosition uint16, outPointIndex uint32,
Version: lnwire.GossipVersion1,
ChannelID: shortChanID.ToUint64(),
ChainHash: *chaincfg.MainNetParams.GenesisHash,
- AuthProof: &models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- },
+ AuthProof: models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ ),
ChannelPoint: outpoint,
Capacity: 9000,
ExtraOpaqueData: make([]byte, 0),
@@ -821,17 +821,20 @@ func assertEdgeInfoEqual(t *testing.T, e1 *models.ChannelEdgeInfo,
}
require.True(t, bytes.Equal(
- e1.AuthProof.NodeSig1Bytes, e2.AuthProof.NodeSig1Bytes,
+ e1.AuthProof.NodeSig1(),
+ e2.AuthProof.NodeSig1(),
))
require.True(t, bytes.Equal(
- e1.AuthProof.NodeSig2Bytes, e2.AuthProof.NodeSig2Bytes,
+ e1.AuthProof.NodeSig2(),
+ e2.AuthProof.NodeSig2(),
))
require.True(t, bytes.Equal(
- e1.AuthProof.BitcoinSig1Bytes,
- e2.AuthProof.BitcoinSig1Bytes,
+ e1.AuthProof.BitcoinSig1(),
+ e2.AuthProof.BitcoinSig1(),
))
require.True(t, bytes.Equal(
- e1.AuthProof.BitcoinSig2Bytes, e2.AuthProof.BitcoinSig2Bytes,
+ e1.AuthProof.BitcoinSig2(),
+ e2.AuthProof.BitcoinSig2(),
))
if e1.ChannelPoint != e2.ChannelPoint {
@@ -917,12 +920,12 @@ func createChannelEdge(node1, node2 *models.Node,
return edgeInfo, nil, nil
}
- edgeInfo.AuthProof = &models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- }
+ edgeInfo.AuthProof = models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ )
edge1 := &models.ChannelEdgePolicy{
SigBytes: testSig.Serialize(),
@@ -1373,12 +1376,12 @@ func TestAddEdgeProof(t *testing.T) {
require.Equal(t, edge1, dbEdge)
// Now, add the edge proof.
- proof := &models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- }
+ proof := models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ )
// First, add the proof to the rest of the channel edge info and try
// to call AddChannelEdge again - this should fail due to the channel
@@ -1781,12 +1784,12 @@ func fillTestGraph(t testing.TB, graph *ChannelGraph, numNodes,
Version: lnwire.GossipVersion1,
ChannelID: chanID,
ChainHash: *chaincfg.MainNetParams.GenesisHash,
- AuthProof: &models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- },
+ AuthProof: models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ ),
Features: lnwire.EmptyFeatureVector(),
ChannelPoint: op,
Capacity: 1000,
@@ -1964,12 +1967,12 @@ func TestGraphPruning(t *testing.T) {
Version: lnwire.GossipVersion1,
ChannelID: chanID,
ChainHash: *chaincfg.MainNetParams.GenesisHash,
- AuthProof: &models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- },
+ AuthProof: models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ ),
Features: lnwire.EmptyFeatureVector(),
ChannelPoint: op,
Capacity: 1000,
diff --git a/graph/db/kv_store.go b/graph/db/kv_store.go
index 7407278..b137c62 100644
--- a/graph/db/kv_store.go
+++ b/graph/db/kv_store.go
@@ -1398,6 +1398,12 @@ func (c *KVStore) HasChannelEdge(
func (c *KVStore) AddEdgeProof(chanID lnwire.ShortChannelID,
proof *models.ChannelAuthProof) error {
+ // We only support v1 channel proofs in the KVStore.
+ if proof.Version != lnwire.GossipVersion1 {
+ return fmt.Errorf("only v1 channel proofs supported, got v%d",
+ proof.Version)
+ }
+
// Construct the channel's primary key which is the 8-byte channel ID.
var chanKey [8]byte
binary.BigEndian.PutUint64(chanKey[:], chanID.ToUint64())
@@ -4738,10 +4744,10 @@ func putChanEdgeInfo(edgeIndex kvdb.RwBucket,
authProof := edgeInfo.AuthProof
var nodeSig1, nodeSig2, bitcoinSig1, bitcoinSig2 []byte
if authProof != nil {
- nodeSig1 = authProof.NodeSig1Bytes
- nodeSig2 = authProof.NodeSig2Bytes
- bitcoinSig1 = authProof.BitcoinSig1Bytes
- bitcoinSig2 = authProof.BitcoinSig2Bytes
+ nodeSig1 = authProof.NodeSig1()
+ nodeSig2 = authProof.NodeSig2()
+ bitcoinSig1 = authProof.BitcoinSig1()
+ bitcoinSig2 = authProof.BitcoinSig2()
}
if err := wire.WriteVarBytes(&b, 0, nodeSig1); err != nil {
@@ -4899,24 +4905,42 @@ func deserializeChanEdgeInfo(r io.Reader) (*models.ChannelEdgeInfo, error) {
return nil, err
}
- proof := &models.ChannelAuthProof{}
+ proof := &models.ChannelAuthProof{
+ // KV store always uses v1.
+ Version: lnwire.GossipVersion1,
+ }
- proof.NodeSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs")
+ nodeSig1, err := wire.ReadVarBytes(r, 0, 80, "sigs")
if err != nil {
return nil, err
}
- proof.NodeSig2Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs")
+ if len(nodeSig1) > 0 {
+ proof.NodeSig1Bytes = fn.Some(nodeSig1)
+ }
+
+ nodeSig2, err := wire.ReadVarBytes(r, 0, 80, "sigs")
if err != nil {
return nil, err
}
- proof.BitcoinSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs")
+ if len(nodeSig2) > 0 {
+ proof.NodeSig2Bytes = fn.Some(nodeSig2)
+ }
+
+ bitcoinSig1, err := wire.ReadVarBytes(r, 0, 80, "sigs")
if err != nil {
return nil, err
}
- proof.BitcoinSig2Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs")
+ if len(bitcoinSig1) > 0 {
+ proof.BitcoinSig1Bytes = fn.Some(bitcoinSig1)
+ }
+
+ bitcoinSig2, err := wire.ReadVarBytes(r, 0, 80, "sigs")
if err != nil {
return nil, err
}
+ if len(bitcoinSig2) > 0 {
+ proof.BitcoinSig2Bytes = fn.Some(bitcoinSig2)
+ }
if !proof.IsEmpty() {
edgeInfo.AuthProof = proof
diff --git a/graph/db/models/channel_auth_proof.go b/graph/db/models/channel_auth_proof.go
index daf120b..1e1fb03 100644
--- a/graph/db/models/channel_auth_proof.go
+++ b/graph/db/models/channel_auth_proof.go
@@ -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{})
}
diff --git a/graph/db/sql_store.go b/graph/db/sql_store.go
index aeeeb37..2535826 100644
--- a/graph/db/sql_store.go
+++ b/graph/db/sql_store.go
@@ -2966,6 +2966,12 @@ func (s *SQLStore) DisconnectBlockAtHeight(height uint32) (
func (s *SQLStore) AddEdgeProof(scid lnwire.ShortChannelID,
proof *models.ChannelAuthProof) error {
+ // For now, we only support v1 channel proofs.
+ if proof.Version != lnwire.GossipVersion1 {
+ return fmt.Errorf("only v1 channel proofs supported, got v%d",
+ proof.Version)
+ }
+
var (
ctx = context.TODO()
scidBytes = channelIDToBytes(scid.ToUint64())
@@ -2975,10 +2981,10 @@ func (s *SQLStore) AddEdgeProof(scid lnwire.ShortChannelID,
res, err := db.AddV1ChannelProof(
ctx, sqlc.AddV1ChannelProofParams{
Scid: scidBytes,
- Node1Signature: proof.NodeSig1Bytes,
- Node2Signature: proof.NodeSig2Bytes,
- Bitcoin1Signature: proof.BitcoinSig1Bytes,
- Bitcoin2Signature: proof.BitcoinSig2Bytes,
+ Node1Signature: proof.NodeSig1(),
+ Node2Signature: proof.NodeSig2(),
+ Bitcoin1Signature: proof.BitcoinSig1(),
+ Bitcoin2Signature: proof.BitcoinSig2(),
},
)
if err != nil {
@@ -4284,10 +4290,10 @@ func insertChannel(ctx context.Context, db SQLQueries,
if edge.AuthProof != nil {
proof := edge.AuthProof
- createParams.Node1Signature = proof.NodeSig1Bytes
- createParams.Node2Signature = proof.NodeSig2Bytes
- createParams.Bitcoin1Signature = proof.BitcoinSig1Bytes
- createParams.Bitcoin2Signature = proof.BitcoinSig2Bytes
+ createParams.Node1Signature = proof.NodeSig1()
+ createParams.Node2Signature = proof.NodeSig2()
+ createParams.Bitcoin1Signature = proof.BitcoinSig1()
+ createParams.Bitcoin2Signature = proof.BitcoinSig2()
}
// Insert the new channel record.
@@ -4483,12 +4489,16 @@ func buildEdgeInfoWithBatchData(chain chainhash.Hash,
// safely check if one signature is present to determine if we have the
// rest of the signatures for the auth proof.
if len(dbChan.Bitcoin1Signature) > 0 {
- channel.AuthProof = &models.ChannelAuthProof{
- NodeSig1Bytes: dbChan.Node1Signature,
- NodeSig2Bytes: dbChan.Node2Signature,
- BitcoinSig1Bytes: dbChan.Bitcoin1Signature,
- BitcoinSig2Bytes: dbChan.Bitcoin2Signature,
+ // For v1 channels, we have four signatures.
+ if dbChan.Version == int16(lnwire.GossipVersion1) {
+ channel.AuthProof = models.NewV1ChannelAuthProof(
+ dbChan.Node1Signature,
+ dbChan.Node2Signature,
+ dbChan.Bitcoin1Signature,
+ dbChan.Bitcoin2Signature,
+ )
}
+ // TODO(elle): Add v2 support when needed.
}
return channel, nil
diff --git a/graph/notifications_test.go b/graph/notifications_test.go
index e220a0b..fab5b4c 100644
--- a/graph/notifications_test.go
+++ b/graph/notifications_test.go
@@ -68,12 +68,12 @@ var (
_ = testSScalar.SetByteSlice(testSBytes)
testSig = ecdsa.NewSignature(testRScalar, testSScalar)
- testAuthProof = models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- }
+ testAuthProof = *models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ )
)
func createTestNode(t *testing.T) *models.Node {
@@ -452,12 +452,12 @@ func TestEdgeUpdateNotification(t *testing.T) {
ChannelID: chanID.ToUint64(),
NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2Bytes: node2.PubKeyBytes,
- AuthProof: &models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- },
+ AuthProof: models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ ),
Features: lnwire.EmptyFeatureVector(),
ChannelPoint: *chanPoint,
Capacity: chanValue,
@@ -648,12 +648,12 @@ func TestNodeUpdateNotification(t *testing.T) {
NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2Bytes: node2.PubKeyBytes,
Features: lnwire.EmptyFeatureVector(),
- AuthProof: &models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- },
+ AuthProof: models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ ),
FundingScript: fn.Some(script),
}
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
@@ -834,12 +834,12 @@ func TestNotificationCancellation(t *testing.T) {
ChannelID: chanID.ToUint64(),
NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2Bytes: node2.PubKeyBytes,
- AuthProof: &models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- },
+ AuthProof: models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ ),
Features: lnwire.EmptyFeatureVector(),
ChannelPoint: *chanPoint,
Capacity: chanValue,
@@ -911,12 +911,12 @@ func TestChannelCloseNotification(t *testing.T) {
ChannelID: chanID.ToUint64(),
NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2Bytes: node2.PubKeyBytes,
- AuthProof: &models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- },
+ AuthProof: models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ ),
Features: lnwire.EmptyFeatureVector(),
ChannelPoint: *chanUtxo,
Capacity: chanValue,
diff --git a/netann/channel_announcement.go b/netann/channel_announcement.go
index 9bb21c4..fee3c5a 100644
--- a/netann/channel_announcement.go
+++ b/netann/channel_announcement.go
@@ -56,25 +56,25 @@ func CreateChanAnnouncement(chanProof *models.ChannelAuthProof,
var err error
chanAnn.BitcoinSig1, err = lnwire.NewSigFromECDSARawSignature(
- chanProof.BitcoinSig1Bytes,
+ chanProof.BitcoinSig1(),
)
if err != nil {
return nil, nil, nil, err
}
chanAnn.BitcoinSig2, err = lnwire.NewSigFromECDSARawSignature(
- chanProof.BitcoinSig2Bytes,
+ chanProof.BitcoinSig2(),
)
if err != nil {
return nil, nil, nil, err
}
chanAnn.NodeSig1, err = lnwire.NewSigFromECDSARawSignature(
- chanProof.NodeSig1Bytes,
+ chanProof.NodeSig1(),
)
if err != nil {
return nil, nil, nil, err
}
chanAnn.NodeSig2, err = lnwire.NewSigFromECDSARawSignature(
- chanProof.NodeSig2Bytes,
+ chanProof.NodeSig2(),
)
if err != nil {
return nil, nil, nil, err
diff --git a/netann/channel_announcement_test.go b/netann/channel_announcement_test.go
index 49f61a5..02d1d56 100644
--- a/netann/channel_announcement_test.go
+++ b/netann/channel_announcement_test.go
@@ -40,12 +40,12 @@ func TestCreateChanAnnouncement(t *testing.T) {
ExtraOpaqueData: []byte{0x1},
}
- chanProof := &models.ChannelAuthProof{
- NodeSig1Bytes: expChanAnn.NodeSig1.ToSignatureBytes(),
- NodeSig2Bytes: expChanAnn.NodeSig2.ToSignatureBytes(),
- BitcoinSig1Bytes: expChanAnn.BitcoinSig1.ToSignatureBytes(),
- BitcoinSig2Bytes: expChanAnn.BitcoinSig2.ToSignatureBytes(),
- }
+ chanProof := models.NewV1ChannelAuthProof(
+ expChanAnn.NodeSig1.ToSignatureBytes(),
+ expChanAnn.NodeSig2.ToSignatureBytes(),
+ expChanAnn.BitcoinSig1.ToSignatureBytes(),
+ expChanAnn.BitcoinSig2.ToSignatureBytes(),
+ )
chanInfo := &models.ChannelEdgeInfo{
Version: lnwire.GossipVersion1,
ChainHash: expChanAnn.ChainHash,
diff --git a/routing/pathfind_test.go b/routing/pathfind_test.go
index b7256e3..bbb31fd 100644
--- a/routing/pathfind_test.go
+++ b/routing/pathfind_test.go
@@ -99,12 +99,12 @@ var (
_ = testSScalar.SetByteSlice(testSBytes)
testSig = ecdsa.NewSignature(testRScalar, testSScalar)
- testAuthProof = models.ChannelAuthProof{
- NodeSig1Bytes: testSig.Serialize(),
- NodeSig2Bytes: testSig.Serialize(),
- BitcoinSig1Bytes: testSig.Serialize(),
- BitcoinSig2Bytes: testSig.Serialize(),
- }
+ testAuthProof = *models.NewV1ChannelAuthProof(
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ testSig.Serialize(),
+ )
)
// noProbabilitySource is used in testing to return the same probability 1 for
diff --git a/rpcserver.go b/rpcserver.go
index 06e0155..0c49639 100644
--- a/rpcserver.go
+++ b/rpcserver.go
@@ -6980,10 +6980,10 @@ func marshalDBEdge(edgeInfo *models.ChannelEdgeInfo,
// channel announcement.
if includeAuthProof && edgeInfo.AuthProof != nil {
edge.AuthProof = &lnrpc.ChannelAuthProof{
- NodeSig1: edgeInfo.AuthProof.NodeSig1Bytes,
- BitcoinSig1: edgeInfo.AuthProof.BitcoinSig1Bytes,
- NodeSig2: edgeInfo.AuthProof.NodeSig2Bytes,
- BitcoinSig2: edgeInfo.AuthProof.BitcoinSig2Bytes,
+ NodeSig1: edgeInfo.AuthProof.NodeSig1(),
+ BitcoinSig1: edgeInfo.AuthProof.BitcoinSig1(),
+ NodeSig2: edgeInfo.AuthProof.NodeSig2(),
+ BitcoinSig2: edgeInfo.AuthProof.BitcoinSig2(),
}
}
Why this scored 32/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.