What changed, and why it matters
This commit is a routine internal cleanup in LND's channel graph database code. It removes unused cached signature and public-key fields and their accessor methods, and switches some functions from returning structs by value to returning pointers. There is no change to security-sensitive behavior, no bug fix, and no externally reported issue.
No security action required. Treat as normal refactoring; standard code review and regression testing are sufficient.
Security signals we found
No security-relevant behavioral change
No validation or cryptographic logic modified
No externally reported vulnerability addressed
Pure code simplification / dead-code removal
Evidence from the diff
The patch refactors graph/db/models.ChannelAuthProof and ChannelEdgeInfo by deleting lazily-cached ecdsa.Signature and btcec.PublicKey fields plus their getter methods (Node1Sig, Node2Sig, BitcoinSig1, BitcoinSig2, BitcoinKey1, BitcoinKey2, AddNodeKeys). It updates callers to copy raw key bytes directly and changes fetchChanEdgeInfo/deserializeChanEdgeInfo to return *models.ChannelEdgeInfo instead of models.ChannelEdgeInfo. The serialization/deserialization logic and wire format are unchanged. No validation, cryptographic, or access-control logic is modified.
Changed components
graph/db/kv_store.gograph/db/models/channel_auth_proof.gograph/db/models/channel_edge_info.goautopilot/prefattach_test.goInspect captured patch +35 / −190
diff --git a/autopilot/prefattach_test.go b/autopilot/prefattach_test.go
index 3ab0c4f..78b738d 100644
--- a/autopilot/prefattach_test.go
+++ b/autopilot/prefattach_test.go
@@ -495,7 +495,11 @@ func (d *testDBGraph) addRandChannel(node1, node2 *btcec.PublicKey,
Capacity: capacity,
Features: lnwire.EmptyFeatureVector(),
}
- edge.AddNodeKeys(lnNode1, lnNode2, lnNode1, lnNode2)
+ copy(edge.NodeKey1Bytes[:], lnNode1.SerializeCompressed())
+ copy(edge.NodeKey2Bytes[:], lnNode2.SerializeCompressed())
+ copy(edge.BitcoinKey1Bytes[:], lnNode1.SerializeCompressed())
+ copy(edge.BitcoinKey2Bytes[:], lnNode2.SerializeCompressed())
+
if err := d.db.AddChannelEdge(ctx, edge); err != nil {
return nil, nil, err
}
diff --git a/graph/db/kv_store.go b/graph/db/kv_store.go
index ae4136e..c8e6151 100644
--- a/graph/db/kv_store.go
+++ b/graph/db/kv_store.go
@@ -469,7 +469,7 @@ func forEachChannel(db kvdb.Backend, cb func(*models.ChannelEdgeInfo,
chanID: chanID,
}]
- return cb(&info, policy1, policy2)
+ return cb(info, policy1, policy2)
},
)
}, reset)
@@ -557,7 +557,7 @@ func (c *KVStore) ForEachChannelCacheable(cb func(*models.CachedEdgeInfo,
}
return cb(
- models.NewCachedEdge(&info),
+ models.NewCachedEdge(info),
cachedPolicy1, cachedPolicy2,
)
},
@@ -1393,7 +1393,7 @@ func (c *KVStore) AddEdgeProof(chanID lnwire.ShortChannelID,
edge.AuthProof = proof
- return putChanEdgeInfo(edgeIndex, &edge, chanKey)
+ return putChanEdgeInfo(edgeIndex, edge, chanKey)
}, func() {})
}
@@ -2238,7 +2238,7 @@ func (c *KVStore) fetchNextChanUpdateBatch(
// Now we have all the information we need to build the
// channel edge.
channel := ChannelEdge{
- Info: &edgeInfo,
+ Info: edgeInfo,
Policy1: edge1,
Policy2: edge2,
Node1: node1,
@@ -2784,7 +2784,7 @@ func (c *KVStore) FilterChannelRange(startHeight,
continue
}
- node1Key, node2Key := computeEdgePolicyKeys(&edgeInfo)
+ node1Key, node2Key := computeEdgePolicyKeys(edgeInfo)
rawPolicy := edges.Get(node1Key)
if len(rawPolicy) != 0 {
@@ -2936,7 +2936,7 @@ func (c *KVStore) fetchChanInfos(tx kvdb.RTx, chanIDs []uint64) (
}
chanEdges = append(chanEdges, ChannelEdge{
- Info: &edgeInfo,
+ Info: edgeInfo,
Policy1: edge1,
Policy2: edge2,
Node1: node1,
@@ -3087,7 +3087,7 @@ func (c *KVStore) delChannelEdgeUnsafe(edges, edgeIndex, chanIndex,
// being removed due to the channel becoming a zombie. We do this to
// ensure we don't store unnecessary data for spent channels.
if !isZombie {
- return &edgeInfo, nil
+ return edgeInfo, nil
}
nodeKey1, nodeKey2 := edgeInfo.NodeKey1Bytes, edgeInfo.NodeKey2Bytes
@@ -3106,7 +3106,7 @@ func (c *KVStore) delChannelEdgeUnsafe(edges, edgeIndex, chanIndex,
)
}
- return &edgeInfo, markEdgeZombie(
+ return edgeInfo, markEdgeZombie(
zombieIndex, byteOrder.Uint64(chanID), nodeKey1, nodeKey2,
)
}
@@ -3551,7 +3551,7 @@ func nodeTraversal(tx kvdb.RTx, nodePub []byte, db kvdb.Backend,
}
// Finally, we execute the callback.
- err = cb(tx, &edgeInfo, outgoingPolicy, incomingPolicy)
+ err = cb(tx, edgeInfo, outgoingPolicy, incomingPolicy)
if err != nil {
return err
}
@@ -3781,7 +3781,7 @@ func (c *KVStore) FetchChannelEdgesByOutpoint(op *wire.OutPoint) (
if err != nil {
return fmt.Errorf("%w: chanID=%x", err, chanID)
}
- edgeInfo = &edge
+ edgeInfo = edge
// Once we have the information about the channels' parameters,
// we'll fetch the routing policies for each for the directed
@@ -3887,7 +3887,7 @@ func (c *KVStore) FetchChannelEdgesByID(chanID uint64) (
return err
}
- edgeInfo = &edge
+ edgeInfo = edge
// Then we'll attempt to fetch the accompanying policies of this
// edge.
@@ -4702,11 +4702,11 @@ func putChanEdgeInfo(edgeIndex kvdb.RwBucket,
}
func fetchChanEdgeInfo(edgeIndex kvdb.RBucket,
- chanID []byte) (models.ChannelEdgeInfo, error) {
+ chanID []byte) (*models.ChannelEdgeInfo, error) {
edgeInfoBytes := edgeIndex.Get(chanID)
if edgeInfoBytes == nil {
- return models.ChannelEdgeInfo{}, ErrEdgeNotFound
+ return nil, ErrEdgeNotFound
}
edgeInfoReader := bytes.NewReader(edgeInfoBytes)
@@ -4714,34 +4714,34 @@ func fetchChanEdgeInfo(edgeIndex kvdb.RBucket,
return deserializeChanEdgeInfo(edgeInfoReader)
}
-func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo, error) {
+func deserializeChanEdgeInfo(r io.Reader) (*models.ChannelEdgeInfo, error) {
var (
err error
edgeInfo models.ChannelEdgeInfo
)
if _, err := io.ReadFull(r, edgeInfo.NodeKey1Bytes[:]); err != nil {
- return models.ChannelEdgeInfo{}, err
+ return nil, err
}
if _, err := io.ReadFull(r, edgeInfo.NodeKey2Bytes[:]); err != nil {
- return models.ChannelEdgeInfo{}, err
+ return nil, err
}
if _, err := io.ReadFull(r, edgeInfo.BitcoinKey1Bytes[:]); err != nil {
- return models.ChannelEdgeInfo{}, err
+ return nil, err
}
if _, err := io.ReadFull(r, edgeInfo.BitcoinKey2Bytes[:]); err != nil {
- return models.ChannelEdgeInfo{}, err
+ return nil, err
}
featureBytes, err := wire.ReadVarBytes(r, 0, 900, "features")
if err != nil {
- return models.ChannelEdgeInfo{}, err
+ return nil, err
}
features := lnwire.NewRawFeatureVector()
err = features.Decode(bytes.NewReader(featureBytes))
if err != nil {
- return models.ChannelEdgeInfo{}, fmt.Errorf("unable to decode "+
+ return nil, fmt.Errorf("unable to decode "+
"features: %w", err)
}
edgeInfo.Features = lnwire.NewFeatureVector(features, lnwire.Features)
@@ -4750,19 +4750,19 @@ func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo, error) {
proof.NodeSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs")
if err != nil {
- return models.ChannelEdgeInfo{}, err
+ return nil, err
}
proof.NodeSig2Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs")
if err != nil {
- return models.ChannelEdgeInfo{}, err
+ return nil, err
}
proof.BitcoinSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs")
if err != nil {
- return models.ChannelEdgeInfo{}, err
+ return nil, err
}
proof.BitcoinSig2Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs")
if err != nil {
- return models.ChannelEdgeInfo{}, err
+ return nil, err
}
if !proof.IsEmpty() {
@@ -4771,17 +4771,17 @@ func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo, error) {
edgeInfo.ChannelPoint = wire.OutPoint{}
if err := ReadOutpoint(r, &edgeInfo.ChannelPoint); err != nil {
- return models.ChannelEdgeInfo{}, err
+ return nil, err
}
if err := binary.Read(r, byteOrder, &edgeInfo.Capacity); err != nil {
- return models.ChannelEdgeInfo{}, err
+ return nil, err
}
if err := binary.Read(r, byteOrder, &edgeInfo.ChannelID); err != nil {
- return models.ChannelEdgeInfo{}, err
+ return nil, err
}
if _, err := io.ReadFull(r, edgeInfo.ChainHash[:]); err != nil {
- return models.ChannelEdgeInfo{}, err
+ return nil, err
}
// We'll try and see if there are any opaque bytes left, if not, then
@@ -4793,10 +4793,10 @@ func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo, error) {
case errors.Is(err, io.ErrUnexpectedEOF):
case errors.Is(err, io.EOF):
case err != nil:
- return models.ChannelEdgeInfo{}, err
+ return nil, err
}
- return edgeInfo, nil
+ return &edgeInfo, nil
}
func putChanEdgePolicy(edges kvdb.RwBucket, edge *models.ChannelEdgePolicy,
diff --git a/graph/db/models/channel_auth_proof.go b/graph/db/models/channel_auth_proof.go
index 1341394..daf120b 100644
--- a/graph/db/models/channel_auth_proof.go
+++ b/graph/db/models/channel_auth_proof.go
@@ -1,7 +1,5 @@
package models
-import "github.com/btcsuite/btcd/btcec/v2/ecdsa"
-
// ChannelAuthProof is the authentication proof (the signature portion) for a
// channel. Using the four signatures contained in the struct, and some
// auxiliary knowledge (the funding script, node identities, and outpoint) nodes
@@ -10,117 +8,23 @@ import "github.com/btcsuite/btcd/btcec/v2/ecdsa"
// nodeID1 || nodeID2 || bitcoinKey1|| bitcoinKey2 || 2-byte-feature-len ||
// features.
type ChannelAuthProof struct {
- // nodeSig1 is a cached instance of the first node signature.
- nodeSig1 *ecdsa.Signature
-
// NodeSig1Bytes are the raw bytes of the first node signature encoded
// in DER format.
NodeSig1Bytes []byte
- // nodeSig2 is a cached instance of the second node signature.
- nodeSig2 *ecdsa.Signature
-
// NodeSig2Bytes are the raw bytes of the second node signature
// encoded in DER format.
NodeSig2Bytes []byte
- // bitcoinSig1 is a cached instance of the first bitcoin signature.
- bitcoinSig1 *ecdsa.Signature
-
// BitcoinSig1Bytes are the raw bytes of the first bitcoin signature
// encoded in DER format.
BitcoinSig1Bytes []byte
- // bitcoinSig2 is a cached instance of the second bitcoin signature.
- bitcoinSig2 *ecdsa.Signature
-
// BitcoinSig2Bytes are the raw bytes of the second bitcoin signature
// encoded in DER format.
BitcoinSig2Bytes []byte
}
-// Node1Sig is the signature using the identity key of the node that is first
-// in a lexicographical ordering of the serialized public keys of the two nodes
-// that created the channel.
-//
-// NOTE: By having this method to access an attribute, we ensure we only need
-// to fully deserialize the signature if absolutely necessary.
-func (c *ChannelAuthProof) Node1Sig() (*ecdsa.Signature, error) {
- if c.nodeSig1 != nil {
- return c.nodeSig1, nil
- }
-
- sig, err := ecdsa.ParseSignature(c.NodeSig1Bytes)
- if err != nil {
- return nil, err
- }
-
- c.nodeSig1 = sig
-
- return sig, nil
-}
-
-// Node2Sig is the signature using the identity key of the node that is second
-// in a lexicographical ordering of the serialized public keys of the two nodes
-// that created the channel.
-//
-// NOTE: By having this method to access an attribute, we ensure we only need
-// to fully deserialize the signature if absolutely necessary.
-func (c *ChannelAuthProof) Node2Sig() (*ecdsa.Signature, error) {
- if c.nodeSig2 != nil {
- return c.nodeSig2, nil
- }
-
- sig, err := ecdsa.ParseSignature(c.NodeSig2Bytes)
- if err != nil {
- return nil, err
- }
-
- c.nodeSig2 = sig
-
- return sig, nil
-}
-
-// BitcoinSig1 is the signature using the public key of the first node that was
-// used in the channel's multi-sig output.
-//
-// NOTE: By having this method to access an attribute, we ensure we only need
-// to fully deserialize the signature if absolutely necessary.
-func (c *ChannelAuthProof) BitcoinSig1() (*ecdsa.Signature, error) {
- if c.bitcoinSig1 != nil {
- return c.bitcoinSig1, nil
- }
-
- sig, err := ecdsa.ParseSignature(c.BitcoinSig1Bytes)
- if err != nil {
- return nil, err
- }
-
- c.bitcoinSig1 = sig
-
- return sig, nil
-}
-
-// BitcoinSig2 is the signature using the public key of the second node that
-// was used in the channel's multi-sig output.
-//
-// NOTE: By having this method to access an attribute, we ensure we only need
-// to fully deserialize the signature if absolutely necessary.
-func (c *ChannelAuthProof) BitcoinSig2() (*ecdsa.Signature, error) {
- if c.bitcoinSig2 != nil {
- return c.bitcoinSig2, nil
- }
-
- sig, err := ecdsa.ParseSignature(c.BitcoinSig2Bytes)
- if err != nil {
- return nil, err
- }
-
- c.bitcoinSig2 = sig
-
- return sig, nil
-}
-
// IsEmpty check is the authentication proof is empty Proof is empty if at
// least one of the signatures are equal to nil.
func (c *ChannelAuthProof) IsEmpty() bool {
diff --git a/graph/db/models/channel_edge_info.go b/graph/db/models/channel_edge_info.go
index d192875..b86c140 100644
--- a/graph/db/models/channel_edge_info.go
+++ b/graph/db/models/channel_edge_info.go
@@ -26,9 +26,6 @@ type ChannelEdgeInfo struct {
// ChainHash is the hash that uniquely identifies the chain that this
// channel was opened within.
- //
- // TODO(roasbeef): need to modify db keying for multi-chain
- // * must add chain hash to prefix as well
ChainHash chainhash.Hash
// NodeKey1Bytes is the raw public key of the first node.
@@ -41,11 +38,9 @@ type ChannelEdgeInfo struct {
// BitcoinKey1Bytes is the raw public key of the first node.
BitcoinKey1Bytes [33]byte
- bitcoinKey1 *btcec.PublicKey
// BitcoinKey2Bytes is the raw public key of the first node.
BitcoinKey2Bytes [33]byte
- bitcoinKey2 *btcec.PublicKey
// Features is the list of protocol features supported by this channel
// edge.
@@ -79,24 +74,6 @@ type ChannelEdgeInfo struct {
ExtraOpaqueData []byte
}
-// AddNodeKeys is a setter-like method that can be used to replace the set of
-// keys for the target ChannelEdgeInfo.
-func (c *ChannelEdgeInfo) AddNodeKeys(nodeKey1, nodeKey2, bitcoinKey1,
- bitcoinKey2 *btcec.PublicKey) {
-
- c.nodeKey1 = nodeKey1
- copy(c.NodeKey1Bytes[:], c.nodeKey1.SerializeCompressed())
-
- c.nodeKey2 = nodeKey2
- copy(c.NodeKey2Bytes[:], nodeKey2.SerializeCompressed())
-
- c.bitcoinKey1 = bitcoinKey1
- copy(c.BitcoinKey1Bytes[:], c.bitcoinKey1.SerializeCompressed())
-
- c.bitcoinKey2 = bitcoinKey2
- copy(c.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
-}
-
// NodeKey1 is the identity public key of the "first" node that was involved in
// the creation of this channel. A node is considered "first" if the
// lexicographical ordering the its serialized public key is "smaller" than
@@ -139,46 +116,6 @@ func (c *ChannelEdgeInfo) NodeKey2() (*btcec.PublicKey, error) {
return key, nil
}
-// BitcoinKey1 is the Bitcoin multi-sig key belonging to the first node, that
-// was involved in the funding transaction that originally created the channel
-// that this struct represents.
-//
-// NOTE: By having this method to access an attribute, we ensure we only need
-// to fully deserialize the pubkey if absolutely necessary.
-func (c *ChannelEdgeInfo) BitcoinKey1() (*btcec.PublicKey, error) {
- if c.bitcoinKey1 != nil {
- return c.bitcoinKey1, nil
- }
-
- key, err := btcec.ParsePubKey(c.BitcoinKey1Bytes[:])
- if err != nil {
- return nil, err
- }
- c.bitcoinKey1 = key
-
- return key, nil
-}
-
-// BitcoinKey2 is the Bitcoin multi-sig key belonging to the second node, that
-// was involved in the funding transaction that originally created the channel
-// that this struct represents.
-//
-// NOTE: By having this method to access an attribute, we ensure we only need
-// to fully deserialize the pubkey if absolutely necessary.
-func (c *ChannelEdgeInfo) BitcoinKey2() (*btcec.PublicKey, error) {
- if c.bitcoinKey2 != nil {
- return c.bitcoinKey2, nil
- }
-
- key, err := btcec.ParsePubKey(c.BitcoinKey2Bytes[:])
- if err != nil {
- return nil, err
- }
- c.bitcoinKey2 = key
-
- return key, nil
-}
-
// OtherNodeKeyBytes returns the node key bytes of the other end of the channel.
func (c *ChannelEdgeInfo) OtherNodeKeyBytes(thisNodeKey []byte) (
[33]byte, error) {
Why this scored 15/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.