graph/db: fix ChanUpdate message/channel flag bug

Here we start using the newly added message_flags and channel_flags
columns of the channel_policies table. The test added previoulsy to
demonstrate the bug is now updated to show that the bug has been fixed.
This commit is contained in:
Elle Mouton committed 2025-07-01 10:12:54 +02:00
1 parent 4a05e5a226
commit e4137a3f14
3 files changed
+47 -47

No files matched your search

+4 -24
View File
@@ -909,10 +909,6 @@ func TestEdgeInfoUpdates(t *testing.T) {
} }
// TestEdgePolicyCRUD tests basic CRUD operations for edge policies. // TestEdgePolicyCRUD tests basic CRUD operations for edge policies.
//
// NOTE: this currently demonstrates a bug in the SQL backend where
// Channel Flags and Message Flags are not properly stored. This will be fixed
// in an upcoming commit.
func TestEdgePolicyCRUD(t *testing.T) { func TestEdgePolicyCRUD(t *testing.T) {
t.Parallel() t.Parallel()
ctx := context.Background() ctx := context.Background()
@@ -925,7 +921,7 @@ func TestEdgePolicyCRUD(t *testing.T) {
// Create an edge. Don't add it to the DB yet. // Create an edge. Don't add it to the DB yet.
edgeInfo, edge1, edge2 := createChannelEdge(node1, node2) edgeInfo, edge1, edge2 := createChannelEdge(node1, node2)
updateAndAssertPolicies := func(expErr bool) { updateAndAssertPolicies := func() {
// Make copies of the policies before calling UpdateEdgePolicy // Make copies of the policies before calling UpdateEdgePolicy
// to avoid any data race's that can occur during async calls // to avoid any data race's that can occur during async calls
// that UpdateEdgePolicy may trigger. // that UpdateEdgePolicy may trigger.
@@ -945,17 +941,6 @@ func TestEdgePolicyCRUD(t *testing.T) {
policy1 *models.ChannelEdgePolicy, policy1 *models.ChannelEdgePolicy,
policy2 *models.ChannelEdgePolicy) error { policy2 *models.ChannelEdgePolicy) error {
if expErr {
require.Error(
t, compareEdgePolicies(edge1, policy1),
)
require.Error(
t, compareEdgePolicies(edge2, policy2),
)
return nil
}
require.NoError(t, compareEdgePolicies(edge1, policy1)) require.NoError(t, compareEdgePolicies(edge1, policy1))
require.NoError(t, compareEdgePolicies(edge2, policy2)) require.NoError(t, compareEdgePolicies(edge2, policy2))
@@ -971,12 +956,12 @@ func TestEdgePolicyCRUD(t *testing.T) {
// Now add the edge. // Now add the edge.
require.NoError(t, graph.AddChannelEdge(ctx, edgeInfo)) require.NoError(t, graph.AddChannelEdge(ctx, edgeInfo))
updateAndAssertPolicies(false) updateAndAssertPolicies()
// Update one of the edges to have no extra opaque data. // Update one of the edges to have no extra opaque data.
edge1.ExtraOpaqueData = nil edge1.ExtraOpaqueData = nil
updateAndAssertPolicies(false) updateAndAssertPolicies()
// Update one of the edges to have ChannelFlags include a bit unknown // Update one of the edges to have ChannelFlags include a bit unknown
// to us. // to us.
@@ -986,12 +971,7 @@ func TestEdgePolicyCRUD(t *testing.T) {
// us. // us.
edge2.MessageFlags |= 1 << 4 edge2.MessageFlags |= 1 << 4
// NOTE: If the backend is SQL, then we expect an error here as updateAndAssertPolicies()
// there is currently a bug in the SQL backend where
// ChannelFlags and MessageFlags are not properly stored. This will
// be fixed in an upcoming commit.
_, isSQLImp := graph.V1Store.(*SQLStore)
updateAndAssertPolicies(isSQLImp)
} }
func assertNodeInCache(t *testing.T, g *ChannelGraph, n *models.LightningNode, func assertNodeInCache(t *testing.T, g *ChannelGraph, n *models.LightningNode,
+36 -23
View File
@@ -1271,7 +1271,7 @@ func (s *SQLStore) ForEachChannelCacheable(cb func(*models.CachedEdgeInfo,
var pol1, pol2 *models.CachedEdgePolicy var pol1, pol2 *models.CachedEdgePolicy
if dbPol1 != nil { if dbPol1 != nil {
policy1, err := buildChanPolicy( policy1, err := buildChanPolicy(
*dbPol1, edge.ChannelID, nil, node2, true, *dbPol1, edge.ChannelID, nil, node2,
) )
if err != nil { if err != nil {
return err return err
@@ -1281,7 +1281,7 @@ func (s *SQLStore) ForEachChannelCacheable(cb func(*models.CachedEdgeInfo,
} }
if dbPol2 != nil { if dbPol2 != nil {
policy2, err := buildChanPolicy( policy2, err := buildChanPolicy(
*dbPol2, edge.ChannelID, nil, node1, false, *dbPol2, edge.ChannelID, nil, node1,
) )
if err != nil { if err != nil {
return err return err
@@ -2900,7 +2900,7 @@ func forEachNodeDirectedChannel(ctx context.Context, db SQLQueries,
var p1, p2 *models.CachedEdgePolicy var p1, p2 *models.CachedEdgePolicy
if dbPol1 != nil { if dbPol1 != nil {
policy1, err := buildChanPolicy( policy1, err := buildChanPolicy(
*dbPol1, edge.ChannelID, nil, node2, true, *dbPol1, edge.ChannelID, nil, node2,
) )
if err != nil { if err != nil {
return err return err
@@ -2910,7 +2910,7 @@ func forEachNodeDirectedChannel(ctx context.Context, db SQLQueries,
} }
if dbPol2 != nil { if dbPol2 != nil {
policy2, err := buildChanPolicy( policy2, err := buildChanPolicy(
*dbPol2, edge.ChannelID, nil, node1, false, *dbPol2, edge.ChannelID, nil, node1,
) )
if err != nil { if err != nil {
return err return err
@@ -3138,6 +3138,8 @@ func updateChanEdgePolicy(ctx context.Context, tx SQLQueries,
Valid: edge.MessageFlags.HasMaxHtlc(), Valid: edge.MessageFlags.HasMaxHtlc(),
Int64: int64(edge.MaxHTLC), Int64: int64(edge.MaxHTLC),
}, },
MessageFlags: sqldb.SQLInt16(edge.MessageFlags),
ChannelFlags: sqldb.SQLInt16(edge.ChannelFlags),
InboundBaseFeeMsat: inboundBase, InboundBaseFeeMsat: inboundBase,
InboundFeeRateMilliMsat: inboundRate, InboundFeeRateMilliMsat: inboundRate,
Signature: edge.SigBytes, Signature: edge.SigBytes,
@@ -4135,7 +4137,7 @@ func getAndBuildChanPolicies(ctx context.Context, db SQLQueries,
var pol1, pol2 *models.ChannelEdgePolicy var pol1, pol2 *models.ChannelEdgePolicy
if dbPol1 != nil { if dbPol1 != nil {
pol1, err = buildChanPolicy( pol1, err = buildChanPolicy(
*dbPol1, channelID, dbPol1Extras, node2, true, *dbPol1, channelID, dbPol1Extras, node2,
) )
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@@ -4143,7 +4145,7 @@ func getAndBuildChanPolicies(ctx context.Context, db SQLQueries,
} }
if dbPol2 != nil { if dbPol2 != nil {
pol2, err = buildChanPolicy( pol2, err = buildChanPolicy(
*dbPol2, channelID, dbPol2Extras, node1, false, *dbPol2, channelID, dbPol2Extras, node1,
) )
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@@ -4156,8 +4158,8 @@ func getAndBuildChanPolicies(ctx context.Context, db SQLQueries,
// buildChanPolicy builds a models.ChannelEdgePolicy instance from the // buildChanPolicy builds a models.ChannelEdgePolicy instance from the
// provided sqlc.ChannelPolicy and other required information. // provided sqlc.ChannelPolicy and other required information.
func buildChanPolicy(dbPolicy sqlc.ChannelPolicy, channelID uint64, func buildChanPolicy(dbPolicy sqlc.ChannelPolicy, channelID uint64,
extras map[uint64][]byte, toNode route.Vertex, extras map[uint64][]byte,
isNode1 bool) (*models.ChannelEdgePolicy, error) { toNode route.Vertex) (*models.ChannelEdgePolicy, error) {
recs, err := lnwire.CustomRecords(extras).Serialize() recs, err := lnwire.CustomRecords(extras).Serialize()
if err != nil { if err != nil {
@@ -4165,19 +4167,6 @@ func buildChanPolicy(dbPolicy sqlc.ChannelPolicy, channelID uint64,
"fields: %w", err) "fields: %w", err)
} }
var msgFlags lnwire.ChanUpdateMsgFlags
if dbPolicy.MaxHtlcMsat.Valid {
msgFlags |= lnwire.ChanUpdateRequiredMaxHtlc
}
var chanFlags lnwire.ChanUpdateChanFlags
if !isNode1 {
chanFlags |= lnwire.ChanUpdateDirection
}
if dbPolicy.Disabled.Bool {
chanFlags |= lnwire.ChanUpdateDisabled
}
var inboundFee fn.Option[lnwire.Fee] var inboundFee fn.Option[lnwire.Fee]
if dbPolicy.InboundFeeRateMilliMsat.Valid || if dbPolicy.InboundFeeRateMilliMsat.Valid ||
dbPolicy.InboundBaseFeeMsat.Valid { dbPolicy.InboundBaseFeeMsat.Valid {
@@ -4194,8 +4183,12 @@ func buildChanPolicy(dbPolicy sqlc.ChannelPolicy, channelID uint64,
LastUpdate: time.Unix( LastUpdate: time.Unix(
dbPolicy.LastUpdate.Int64, 0, dbPolicy.LastUpdate.Int64, 0,
), ),
MessageFlags: msgFlags, MessageFlags: sqldb.ExtractSqlInt16[lnwire.ChanUpdateMsgFlags](
ChannelFlags: chanFlags, dbPolicy.MessageFlags,
),
ChannelFlags: sqldb.ExtractSqlInt16[lnwire.ChanUpdateChanFlags](
dbPolicy.ChannelFlags,
),
TimeLockDelta: uint16(dbPolicy.Timelock), TimeLockDelta: uint16(dbPolicy.Timelock),
MinHTLC: lnwire.MilliSatoshi( MinHTLC: lnwire.MilliSatoshi(
dbPolicy.MinHtlcMsat, dbPolicy.MinHtlcMsat,
@@ -4259,6 +4252,8 @@ func extractChannelPolicies(row any) (*sqlc.ChannelPolicy, *sqlc.ChannelPolicy,
InboundBaseFeeMsat: r.Policy1InboundBaseFeeMsat, InboundBaseFeeMsat: r.Policy1InboundBaseFeeMsat,
InboundFeeRateMilliMsat: r.Policy1InboundFeeRateMilliMsat, InboundFeeRateMilliMsat: r.Policy1InboundFeeRateMilliMsat,
Disabled: r.Policy1Disabled, Disabled: r.Policy1Disabled,
MessageFlags: r.Policy1MessageFlags,
ChannelFlags: r.Policy1ChannelFlags,
Signature: r.Policy1Signature, Signature: r.Policy1Signature,
} }
} }
@@ -4277,6 +4272,8 @@ func extractChannelPolicies(row any) (*sqlc.ChannelPolicy, *sqlc.ChannelPolicy,
InboundBaseFeeMsat: r.Policy2InboundBaseFeeMsat, InboundBaseFeeMsat: r.Policy2InboundBaseFeeMsat,
InboundFeeRateMilliMsat: r.Policy2InboundFeeRateMilliMsat, InboundFeeRateMilliMsat: r.Policy2InboundFeeRateMilliMsat,
Disabled: r.Policy2Disabled, Disabled: r.Policy2Disabled,
MessageFlags: r.Policy2MessageFlags,
ChannelFlags: r.Policy2ChannelFlags,
Signature: r.Policy2Signature, Signature: r.Policy2Signature,
} }
} }
@@ -4299,6 +4296,8 @@ func extractChannelPolicies(row any) (*sqlc.ChannelPolicy, *sqlc.ChannelPolicy,
InboundBaseFeeMsat: r.Policy1InboundBaseFeeMsat, InboundBaseFeeMsat: r.Policy1InboundBaseFeeMsat,
InboundFeeRateMilliMsat: r.Policy1InboundFeeRateMilliMsat, InboundFeeRateMilliMsat: r.Policy1InboundFeeRateMilliMsat,
Disabled: r.Policy1Disabled, Disabled: r.Policy1Disabled,
MessageFlags: r.Policy1MessageFlags,
ChannelFlags: r.Policy1ChannelFlags,
Signature: r.Policy1Signature, Signature: r.Policy1Signature,
} }
} }
@@ -4317,6 +4316,8 @@ func extractChannelPolicies(row any) (*sqlc.ChannelPolicy, *sqlc.ChannelPolicy,
InboundBaseFeeMsat: r.Policy2InboundBaseFeeMsat, InboundBaseFeeMsat: r.Policy2InboundBaseFeeMsat,
InboundFeeRateMilliMsat: r.Policy2InboundFeeRateMilliMsat, InboundFeeRateMilliMsat: r.Policy2InboundFeeRateMilliMsat,
Disabled: r.Policy2Disabled, Disabled: r.Policy2Disabled,
MessageFlags: r.Policy2MessageFlags,
ChannelFlags: r.Policy2ChannelFlags,
Signature: r.Policy2Signature, Signature: r.Policy2Signature,
} }
} }
@@ -4339,6 +4340,8 @@ func extractChannelPolicies(row any) (*sqlc.ChannelPolicy, *sqlc.ChannelPolicy,
InboundBaseFeeMsat: r.Policy1InboundBaseFeeMsat, InboundBaseFeeMsat: r.Policy1InboundBaseFeeMsat,
InboundFeeRateMilliMsat: r.Policy1InboundFeeRateMilliMsat, InboundFeeRateMilliMsat: r.Policy1InboundFeeRateMilliMsat,
Disabled: r.Policy1Disabled, Disabled: r.Policy1Disabled,
MessageFlags: r.Policy1MessageFlags,
ChannelFlags: r.Policy1ChannelFlags,
Signature: r.Policy1Signature, Signature: r.Policy1Signature,
} }
} }
@@ -4357,6 +4360,8 @@ func extractChannelPolicies(row any) (*sqlc.ChannelPolicy, *sqlc.ChannelPolicy,
InboundBaseFeeMsat: r.Policy2InboundBaseFeeMsat, InboundBaseFeeMsat: r.Policy2InboundBaseFeeMsat,
InboundFeeRateMilliMsat: r.Policy2InboundFeeRateMilliMsat, InboundFeeRateMilliMsat: r.Policy2InboundFeeRateMilliMsat,
Disabled: r.Policy2Disabled, Disabled: r.Policy2Disabled,
MessageFlags: r.Policy2MessageFlags,
ChannelFlags: r.Policy2ChannelFlags,
Signature: r.Policy2Signature, Signature: r.Policy2Signature,
} }
} }
@@ -4379,6 +4384,8 @@ func extractChannelPolicies(row any) (*sqlc.ChannelPolicy, *sqlc.ChannelPolicy,
InboundBaseFeeMsat: r.Policy1InboundBaseFeeMsat, InboundBaseFeeMsat: r.Policy1InboundBaseFeeMsat,
InboundFeeRateMilliMsat: r.Policy1InboundFeeRateMilliMsat, InboundFeeRateMilliMsat: r.Policy1InboundFeeRateMilliMsat,
Disabled: r.Policy1Disabled, Disabled: r.Policy1Disabled,
MessageFlags: r.Policy1MessageFlags,
ChannelFlags: r.Policy1ChannelFlags,
Signature: r.Policy1Signature, Signature: r.Policy1Signature,
} }
} }
@@ -4397,6 +4404,8 @@ func extractChannelPolicies(row any) (*sqlc.ChannelPolicy, *sqlc.ChannelPolicy,
InboundBaseFeeMsat: r.Policy2InboundBaseFeeMsat, InboundBaseFeeMsat: r.Policy2InboundBaseFeeMsat,
InboundFeeRateMilliMsat: r.Policy2InboundFeeRateMilliMsat, InboundFeeRateMilliMsat: r.Policy2InboundFeeRateMilliMsat,
Disabled: r.Policy2Disabled, Disabled: r.Policy2Disabled,
MessageFlags: r.Policy2MessageFlags,
ChannelFlags: r.Policy2ChannelFlags,
Signature: r.Policy2Signature, Signature: r.Policy2Signature,
} }
} }
@@ -4419,6 +4428,8 @@ func extractChannelPolicies(row any) (*sqlc.ChannelPolicy, *sqlc.ChannelPolicy,
InboundBaseFeeMsat: r.Policy1InboundBaseFeeMsat, InboundBaseFeeMsat: r.Policy1InboundBaseFeeMsat,
InboundFeeRateMilliMsat: r.Policy1InboundFeeRateMilliMsat, InboundFeeRateMilliMsat: r.Policy1InboundFeeRateMilliMsat,
Disabled: r.Policy1Disabled, Disabled: r.Policy1Disabled,
MessageFlags: r.Policy1MessageFlags,
ChannelFlags: r.Policy1ChannelFlags,
Signature: r.Policy1Signature, Signature: r.Policy1Signature,
} }
} }
@@ -4437,6 +4448,8 @@ func extractChannelPolicies(row any) (*sqlc.ChannelPolicy, *sqlc.ChannelPolicy,
InboundBaseFeeMsat: r.Policy2InboundBaseFeeMsat, InboundBaseFeeMsat: r.Policy2InboundBaseFeeMsat,
InboundFeeRateMilliMsat: r.Policy2InboundFeeRateMilliMsat, InboundFeeRateMilliMsat: r.Policy2InboundFeeRateMilliMsat,
Disabled: r.Policy2Disabled, Disabled: r.Policy2Disabled,
MessageFlags: r.Policy2MessageFlags,
ChannelFlags: r.Policy2ChannelFlags,
Signature: r.Policy2Signature, Signature: r.Policy2Signature,
} }
} }
+7
View File
@@ -68,3 +68,10 @@ func SQLTime(t time.Time) sql.NullTime {
Valid: true, Valid: true,
} }
} }
// ExtractSqlInt16 turns a NullInt16 into a numerical type. This can be useful
// when reading directly from the database, as this function handles extracting
// the inner value from the "option"-like struct.
func ExtractSqlInt16[T constraints.Integer](num sql.NullInt16) T {
return T(num.Int16)
}