graph/db: allow v2 nodes

Update the SQLStore node writer and readers to handle V2 ndoes.
Currently no logic will actually add such nodes. The following commits
will update what is needed so that CRUD for v2 nodes can be tested.
This commit is contained in:
Elle Mouton committed 2026-02-13 07:21:20 +02:00
1 parent 628b89cc40
commit 1738e0cabc
1 file changed
+76 -37
+76 -37
View File
@@ -538,7 +538,7 @@ func (s *SQLStore) SetSourceNode(ctx context.Context,
// Make sure that if a source node for this version is already // Make sure that if a source node for this version is already
// set, then the ID is the same as the one we are about to set. // set, then the ID is the same as the one we are about to set.
dbSourceNodeID, _, err := s.getSourceNode( dbSourceNodeID, _, err := s.getSourceNode(
ctx, db, lnwire.GossipVersion1, ctx, db, node.Version,
) )
if err != nil && !errors.Is(err, ErrSourceNodeNotSet) { if err != nil && !errors.Is(err, ErrSourceNodeNotSet) {
return fmt.Errorf("unable to fetch source node: %w", return fmt.Errorf("unable to fetch source node: %w",
@@ -3489,6 +3489,19 @@ func buildNode(ctx context.Context, cfg *sqldb.QueryConfig, db SQLQueries,
return buildNodeWithBatchData(dbNode, data) return buildNodeWithBatchData(dbNode, data)
} }
// isKnownGossipVersion checks whether the provided gossip version is known
// and supported.
func isKnownGossipVersion(v lnwire.GossipVersion) bool {
switch v {
case lnwire.GossipVersion1:
return true
case lnwire.GossipVersion2:
return true
default:
return false
}
}
// buildNodeWithBatchData builds a models.Node instance // buildNodeWithBatchData builds a models.Node instance
// from the provided sqlc.GraphNode and batchNodeData. If the node does have // from the provided sqlc.GraphNode and batchNodeData. If the node does have
// features/addresses/extra fields, then the corresponding fields are expected // features/addresses/extra fields, then the corresponding fields are expected
@@ -3496,15 +3509,18 @@ func buildNode(ctx context.Context, cfg *sqldb.QueryConfig, db SQLQueries,
func buildNodeWithBatchData(dbNode sqlc.GraphNode, func buildNodeWithBatchData(dbNode sqlc.GraphNode,
batchData *batchNodeData) (*models.Node, error) { batchData *batchNodeData) (*models.Node, error) {
if dbNode.Version != int16(lnwire.GossipVersion1) { v := lnwire.GossipVersion(dbNode.Version)
return nil, fmt.Errorf("unsupported node version: %d",
dbNode.Version) if !isKnownGossipVersion(v) {
return nil, fmt.Errorf("unknown node version: %d", v)
} }
var pub [33]byte pub, err := route.NewVertexFromBytes(dbNode.PubKey)
copy(pub[:], dbNode.PubKey) if err != nil {
return nil, fmt.Errorf("unable to parse pubkey: %w", err)
}
node := models.NewV1ShellNode(pub) node := models.NewShellNode(v, pub)
if len(dbNode.Signature) == 0 { if len(dbNode.Signature) == 0 {
return node, nil return node, nil
@@ -3518,8 +3534,10 @@ func buildNodeWithBatchData(dbNode sqlc.GraphNode,
if dbNode.LastUpdate.Valid { if dbNode.LastUpdate.Valid {
node.LastUpdate = time.Unix(dbNode.LastUpdate.Int64, 0) node.LastUpdate = time.Unix(dbNode.LastUpdate.Int64, 0)
} }
if dbNode.BlockHeight.Valid {
node.LastBlockHeight = uint32(dbNode.BlockHeight.Int64)
}
var err error
if dbNode.Color.Valid { if dbNode.Color.Valid {
nodeColor, err := DecodeHexColor(dbNode.Color.String) nodeColor, err := DecodeHexColor(dbNode.Color.String)
if err != nil { if err != nil {
@@ -3551,13 +3569,19 @@ func buildNodeWithBatchData(dbNode sqlc.GraphNode,
// Use preloaded extra fields. // Use preloaded extra fields.
if extraFields, exists := batchData.extraFields[dbNode.ID]; exists { if extraFields, exists := batchData.extraFields[dbNode.ID]; exists {
recs, err := lnwire.CustomRecords(extraFields).Serialize() if v == lnwire.GossipVersion1 {
if err != nil { records := lnwire.CustomRecords(extraFields)
return nil, fmt.Errorf("unable to serialize extra "+ recs, err := records.Serialize()
"signed fields: %w", err) if err != nil {
} return nil, fmt.Errorf("unable to serialize "+
if len(recs) != 0 { "extra signed fields: %w", err)
node.ExtraOpaqueData = recs }
if len(recs) != 0 {
node.ExtraOpaqueData = recs
}
} else if len(extraFields) > 0 {
node.ExtraSignedFields = extraFields
} }
} }
@@ -3637,10 +3661,13 @@ func upsertNodeAncillaryData(ctx context.Context, db SQLQueries,
// Convert the flat extra opaque data into a map of TLV types to // Convert the flat extra opaque data into a map of TLV types to
// values. // values.
extra, err := marshalExtraOpaqueData(node.ExtraOpaqueData) extra := node.ExtraSignedFields
if err != nil { if node.Version == lnwire.GossipVersion1 {
return fmt.Errorf("unable to marshal extra opaque data: %w", extra, err = marshalExtraOpaqueData(node.ExtraOpaqueData)
err) if err != nil {
return fmt.Errorf("unable to marshal extra opaque "+
"data: %w", err)
}
} }
// Update the node's extra signed fields. // Update the node's extra signed fields.
@@ -3655,34 +3682,39 @@ func upsertNodeAncillaryData(ctx context.Context, db SQLQueries,
// populateNodeParams populates the common node parameters from a models.Node. // populateNodeParams populates the common node parameters from a models.Node.
// This is a helper for building UpsertNodeParams and UpsertSourceNodeParams. // This is a helper for building UpsertNodeParams and UpsertSourceNodeParams.
func populateNodeParams(node *models.Node, func populateNodeParams(node *models.Node,
setParams func(lastUpdate sql.NullInt64, alias, setParams func(lastUpdate, lastBlockHeight sql.NullInt64, alias,
colorStr sql.NullString, signature []byte)) error { colorStr sql.NullString, signature []byte)) error {
if !node.HaveAnnouncement() { if !node.HaveAnnouncement() {
return nil return nil
} }
var (
alias, colorStr sql.NullString
lastUpdate, lastBlockHeight sql.NullInt64
)
node.Color.WhenSome(func(rgba color.RGBA) {
colorStr = sqldb.SQLStrValid(EncodeHexColor(rgba))
})
node.Alias.WhenSome(func(s string) {
alias = sqldb.SQLStrValid(s)
})
switch node.Version { switch node.Version {
case lnwire.GossipVersion1: case lnwire.GossipVersion1:
lastUpdate := sqldb.SQLInt64(node.LastUpdate.Unix()) lastUpdate = sqldb.SQLInt64(node.LastUpdate.Unix())
var alias, colorStr sql.NullString
node.Color.WhenSome(func(rgba color.RGBA) {
colorStr = sqldb.SQLStrValid(EncodeHexColor(rgba))
})
node.Alias.WhenSome(func(s string) {
alias = sqldb.SQLStrValid(s)
})
setParams(lastUpdate, alias, colorStr, node.AuthSigBytes)
case lnwire.GossipVersion2: case lnwire.GossipVersion2:
// No-op for now. lastBlockHeight = sqldb.SQLInt64(int64(node.LastBlockHeight))
default: default:
return fmt.Errorf("unknown gossip version: %d", node.Version) return fmt.Errorf("unknown gossip version: %d", node.Version)
} }
setParams(
lastUpdate, lastBlockHeight, alias, colorStr, node.AuthSigBytes,
)
return nil return nil
} }
@@ -3690,20 +3722,22 @@ func populateNodeParams(node *models.Node,
// strict UpsertNode query (requires timestamp to be increasing). // strict UpsertNode query (requires timestamp to be increasing).
func buildNodeUpsertParams(node *models.Node) (sqlc.UpsertNodeParams, error) { func buildNodeUpsertParams(node *models.Node) (sqlc.UpsertNodeParams, error) {
params := sqlc.UpsertNodeParams{ params := sqlc.UpsertNodeParams{
Version: int16(lnwire.GossipVersion1), Version: int16(node.Version),
PubKey: node.PubKeyBytes[:], PubKey: node.PubKeyBytes[:],
} }
err := populateNodeParams( err := populateNodeParams(
node, func(lastUpdate sql.NullInt64, alias, node, func(lastUpdate, lastBlockHeight sql.NullInt64, alias,
colorStr sql.NullString, colorStr sql.NullString,
signature []byte) { signature []byte) {
params.LastUpdate = lastUpdate params.LastUpdate = lastUpdate
params.BlockHeight = lastBlockHeight
params.Alias = alias params.Alias = alias
params.Color = colorStr params.Color = colorStr
params.Signature = signature params.Signature = signature
}) },
)
return params, err return params, err
} }
@@ -3714,14 +3748,15 @@ func buildSourceNodeUpsertParams(node *models.Node) (
sqlc.UpsertSourceNodeParams, error) { sqlc.UpsertSourceNodeParams, error) {
params := sqlc.UpsertSourceNodeParams{ params := sqlc.UpsertSourceNodeParams{
Version: int16(lnwire.GossipVersion1), Version: int16(node.Version),
PubKey: node.PubKeyBytes[:], PubKey: node.PubKeyBytes[:],
} }
err := populateNodeParams( err := populateNodeParams(
node, func(lastUpdate sql.NullInt64, alias, node, func(lastUpdate, lastBlock sql.NullInt64, alias,
colorStr sql.NullString, signature []byte) { colorStr sql.NullString, signature []byte) {
params.BlockHeight = lastBlock
params.LastUpdate = lastUpdate params.LastUpdate = lastUpdate
params.Alias = alias params.Alias = alias
params.Color = colorStr params.Color = colorStr
@@ -3772,6 +3807,10 @@ func upsertSourceNode(ctx context.Context, db SQLQueries,
func upsertNode(ctx context.Context, db SQLQueries, func upsertNode(ctx context.Context, db SQLQueries,
node *models.Node) (int64, error) { node *models.Node) (int64, error) {
if !isKnownGossipVersion(node.Version) {
return 0, fmt.Errorf("unknown gossip version: %d", node.Version)
}
params, err := buildNodeUpsertParams(node) params, err := buildNodeUpsertParams(node)
if err != nil { if err != nil {
return 0, err return 0, err