graph/db: treat empty channel signatures as missing
This commit improves handling of missing channel signatures in the database: - Return nil from auth proof accessors instead of empty slices so that missing signatures are stored as NULL in SQL. - Update public channel checks to require signature length > 0, which properly handles existing empty bytea values in the database. - Add regression test covering empty v1 and v2 channel signatures to prevent future issues.
This commit is contained in:
5 files changed
+85
-27
No files matched your search
@@ -154,6 +154,10 @@ var versionedTests = []versionedTest{
|
||||
name: "node is public",
|
||||
test: testNodeIsPublic,
|
||||
},
|
||||
{
|
||||
name: "node is public empty channel signature",
|
||||
test: testIsPublicNodeEmptyChannelSignature,
|
||||
},
|
||||
}
|
||||
|
||||
// TestVersionedDBs runs various tests against both v1 and v2 versioned
|
||||
@@ -4265,6 +4269,59 @@ func testNodeIsPublic(t *testing.T, v lnwire.GossipVersion) {
|
||||
)
|
||||
}
|
||||
|
||||
// testIsPublicNodeEmptyChannelSignature ensures empty channel signatures don't
|
||||
// mark nodes as public.
|
||||
func testIsPublicNodeEmptyChannelSignature(t *testing.T,
|
||||
v lnwire.GossipVersion) {
|
||||
|
||||
t.Parallel()
|
||||
ctx := t.Context()
|
||||
|
||||
testGraph := MakeTestGraph(t)
|
||||
graph := NewVersionedGraph(testGraph, v)
|
||||
|
||||
// Set a source node as it's required for IsPublicNode.
|
||||
sourceNode := createTestVertex(t, v)
|
||||
err := graph.SetSourceNode(ctx, sourceNode)
|
||||
require.NoError(t, err)
|
||||
|
||||
node1 := createTestVertex(t, v)
|
||||
|
||||
node1.LastUpdate = nextUpdateTime()
|
||||
|
||||
err = graph.AddNode(ctx, node1)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create an edge between source node and node1, with
|
||||
// empty signatures. This tests that empty signatures
|
||||
// don't mark nodes as public.
|
||||
edgeInfo, _ := createEdge(
|
||||
v, 10, 0, 0, 0, sourceNode, node1,
|
||||
true,
|
||||
)
|
||||
|
||||
switch v {
|
||||
case lnwire.GossipVersion1:
|
||||
edgeInfo.AuthProof =
|
||||
models.NewV1ChannelAuthProof(
|
||||
[]byte{}, []byte{},
|
||||
[]byte{}, []byte{},
|
||||
)
|
||||
case lnwire.GossipVersion2:
|
||||
edgeInfo.AuthProof =
|
||||
models.NewV2ChannelAuthProof([]byte{})
|
||||
}
|
||||
|
||||
err = graph.AddChannelEdge(ctx, edgeInfo)
|
||||
require.NoError(t, err)
|
||||
|
||||
// node1 should NOT be considered public because the
|
||||
// channel announcement has empty signatures.
|
||||
isPublic, err := graph.IsPublicNode(node1.PubKeyBytes)
|
||||
require.NoError(t, err)
|
||||
require.False(t, isPublic)
|
||||
}
|
||||
|
||||
// BenchmarkIsPublicNode measures the performance of IsPublicNode when checking
|
||||
// a large number of nodes.
|
||||
func BenchmarkIsPublicNode(b *testing.B) {
|
||||
|
||||
@@ -3377,8 +3377,11 @@ func (c *KVStore) isPublic(tx kvdb.RTx, nodePub route.Vertex,
|
||||
}
|
||||
|
||||
// Since the edge _does_ extend to the source node, we'll also
|
||||
// need to ensure that this is a public edge.
|
||||
if info.AuthProof != nil {
|
||||
// need to ensure that this is a public edge with valid
|
||||
// signatures (not empty).
|
||||
if info.AuthProof != nil && !info.AuthProof.IsEmpty() &&
|
||||
len(info.AuthProof.BitcoinSig1()) > 0 {
|
||||
|
||||
nodeIsPublic = true
|
||||
return errDone
|
||||
}
|
||||
|
||||
@@ -89,31 +89,29 @@ func NewV2ChannelAuthProof(signature []byte) *ChannelAuthProof {
|
||||
}
|
||||
}
|
||||
|
||||
// NodeSig1 returns the first node signature bytes, or an empty slice if not
|
||||
// present.
|
||||
// NodeSig1 returns the first node signature bytes, or nil if not present.
|
||||
func (c *ChannelAuthProof) NodeSig1() []byte {
|
||||
return c.NodeSig1Bytes.UnwrapOr([]byte{})
|
||||
return c.NodeSig1Bytes.UnwrapOr(nil)
|
||||
}
|
||||
|
||||
// NodeSig2 returns the second node signature bytes, or an empty slice if not
|
||||
// present.
|
||||
// NodeSig2 returns the second node signature bytes, or nil if not present.
|
||||
func (c *ChannelAuthProof) NodeSig2() []byte {
|
||||
return c.NodeSig2Bytes.UnwrapOr([]byte{})
|
||||
return c.NodeSig2Bytes.UnwrapOr(nil)
|
||||
}
|
||||
|
||||
// BitcoinSig1 returns the first bitcoin signature bytes, or an empty slice if
|
||||
// not present.
|
||||
// BitcoinSig1 returns the first bitcoin signature bytes, or nil if not
|
||||
// present.
|
||||
func (c *ChannelAuthProof) BitcoinSig1() []byte {
|
||||
return c.BitcoinSig1Bytes.UnwrapOr([]byte{})
|
||||
return c.BitcoinSig1Bytes.UnwrapOr(nil)
|
||||
}
|
||||
|
||||
// BitcoinSig2 returns the second bitcoin signature bytes, or an empty slice if
|
||||
// not present.
|
||||
// BitcoinSig2 returns the second bitcoin signature bytes, or nil if not
|
||||
// present.
|
||||
func (c *ChannelAuthProof) BitcoinSig2() []byte {
|
||||
return c.BitcoinSig2Bytes.UnwrapOr([]byte{})
|
||||
return c.BitcoinSig2Bytes.UnwrapOr(nil)
|
||||
}
|
||||
|
||||
// Sig returns the v2 signature bytes, or an empty slice if not present.
|
||||
// Sig returns the v2 signature bytes, or nil if not present.
|
||||
func (c *ChannelAuthProof) Sig() []byte {
|
||||
return c.Signature.UnwrapOr([]byte{})
|
||||
return c.Signature.UnwrapOr(nil)
|
||||
}
|
||||
Reference in new issue
Block a user