graph/db: update policy builders to support v2 fields
What changed, and why it matters
This commit updates how the Lightning Network Daemon (LND) stores and rebuilds channel routing policies in its graph database. It adds support for a newer gossip protocol version (v2) in the SQL backend, while the older KV backend is now explicitly restricted to version 1. The changes are primarily about correct data mapping and preventing unsupported versions from being written to the wrong database backend. There is no direct evidence in the commit of an exploitable security vulnerability, but the change touches consensus-relevant routing data and fixes version-handling gaps that could theoretically cause nodes to propagate or accept malformed policy information.
Treat this as a hardening/bugfix change rather than an active vulnerability. Reviewers should verify that the version branching in updateChanEdgePolicy and buildChanPolicy covers all newly introduced v2 fields, that MaxHTLC handling is correct for both versions, and that the KV rejection path cannot be bypassed by callers. Run the updated graph tests under both KV and SQL backends and consider an integration test that exercises a v2 policy end-to-end through gossip propagation.
Security signals we found
Version validation added to KV policy write/serialization paths
SQL policy builder now distinguishes v1 and v2 gossip protocol fields
Directionality field SecondPeer is now set from explicit isNode1 argument rather than inferred from legacy ChannelFlags
Unsupported gossip versions rejected in SQL update path
Test coverage expanded for dual-version policy round-trips
Evidence from the diff
The patch modifies graph/db/kv_store.go, graph/db/sql_store.go, and graph/db/graph_test.go. In the KV store, updateEdgePolicy and serializeChanEdgePolicy now reject any ChannelEdgePolicy whose Version is not lnwire.GossipVersion1, and deserializeChanEdgePolicyRaw sets Version to GossipVersion1. In the SQL store, updateChanEdgePolicy validates the gossip version, uses edge.Version instead of hard-coding GossipVersion1, branches field persistence between v1 (LastUpdate, Disabled, MaxHtlcMsat, MessageFlags, ChannelFlags, ExtraOpaqueData) and v2 (LastBlockHeight, DisableFlags, MaxHtlcMsat, ExtraSignedFields), and derives isNode1 via edge.IsNode1(). The buildChanPolicy family of functions gains an isNode1 parameter so it can set SecondPeer correctly and reconstruct version-specific fields when reading SQL rows. Tests are updated to exercise both versions and to normalize version-specific differences before comparison.
Changed components
graph/db/kv_store.gograph/db/sql_store.gograph/db/graph_test.goChannelEdgePolicy serialization/deserializationSQL graph policy upsert and reconstructionKV graph policy update and serializationInspect captured patch +205 / −123
diff --git a/graph/db/graph_test.go b/graph/db/graph_test.go
index f1acfe9..9b923f6 100644
--- a/graph/db/graph_test.go
+++ b/graph/db/graph_test.go
@@ -1048,6 +1048,7 @@ func createChannelEdge(node1, node2 *models.Node) (*models.ChannelEdgeInfo,
SigBytes: testSig.Serialize(),
ChannelID: chanID,
LastUpdate: nextUpdateTime(),
+ SecondPeer: false,
MessageFlags: 1,
ChannelFlags: 0,
TimeLockDelta: 99,
@@ -1062,6 +1063,7 @@ func createChannelEdge(node1, node2 *models.Node) (*models.ChannelEdgeInfo,
Version: lnwire.GossipVersion1,
SigBytes: testSig.Serialize(),
ChannelID: chanID,
+ SecondPeer: true,
LastUpdate: nextUpdateTime(),
MessageFlags: 1,
ChannelFlags: 1,
@@ -1439,7 +1441,7 @@ func assertEdgeWithPolicyInCache(t *testing.T, g *ChannelGraph,
func randEdgePolicy(chanID uint64) *models.ChannelEdgePolicy {
update := prand.Int63()
- return newEdgePolicy(chanID, update)
+ return newEdgePolicy(lnwire.GossipVersion1, chanID, update, true)
}
func copyEdgePolicy(p *models.ChannelEdgePolicy) *models.ChannelEdgePolicy {
@@ -1448,8 +1450,11 @@ func copyEdgePolicy(p *models.ChannelEdgePolicy) *models.ChannelEdgePolicy {
SigBytes: p.SigBytes,
ChannelID: p.ChannelID,
LastUpdate: p.LastUpdate,
+ LastBlockHeight: p.LastBlockHeight,
+ SecondPeer: p.SecondPeer,
MessageFlags: p.MessageFlags,
ChannelFlags: p.ChannelFlags,
+ DisableFlags: p.DisableFlags,
TimeLockDelta: p.TimeLockDelta,
MinHTLC: p.MinHTLC,
MaxHTLC: p.MaxHTLC,
@@ -1457,22 +1462,40 @@ func copyEdgePolicy(p *models.ChannelEdgePolicy) *models.ChannelEdgePolicy {
FeeProportionalMillionths: p.FeeProportionalMillionths,
ToNode: p.ToNode,
ExtraOpaqueData: p.ExtraOpaqueData,
+ ExtraSignedFields: p.ExtraSignedFields,
}
}
-func newEdgePolicy(chanID uint64, updateTime int64) *models.ChannelEdgePolicy {
- return &models.ChannelEdgePolicy{
- Version: lnwire.GossipVersion1,
+func newEdgePolicy(v lnwire.GossipVersion, chanID uint64,
+ updateTime int64, isNode1 bool) *models.ChannelEdgePolicy {
+
+ policy := &models.ChannelEdgePolicy{
+ Version: v,
+ SecondPeer: !isNode1,
ChannelID: chanID,
- LastUpdate: time.Unix(updateTime, 0),
- MessageFlags: 1,
- ChannelFlags: 0,
TimeLockDelta: uint16(prand.Int63()),
MinHTLC: lnwire.MilliSatoshi(prand.Int63()),
MaxHTLC: lnwire.MilliSatoshi(prand.Int63()),
FeeBaseMSat: lnwire.MilliSatoshi(prand.Int63()),
FeeProportionalMillionths: lnwire.MilliSatoshi(prand.Int63()),
}
+
+ if v == lnwire.GossipVersion1 {
+ policy.LastUpdate = time.Unix(updateTime, 0)
+ policy.MessageFlags = 1
+ if !isNode1 {
+ policy.ChannelFlags = lnwire.ChanUpdateDirection
+ }
+ policy.ExtraOpaqueData = []byte{1, 0}
+ } else {
+ policy.LastBlockHeight = nextBlockHeight()
+ policy.DisableFlags = 0
+ policy.ExtraSignedFields = map[uint64][]byte{
+ 100: {0x1, 0x2, 0x3},
+ }
+ }
+
+ return policy
}
// testAddEdgeProof tests the ability to add an edge proof to an existing edge.
@@ -2358,7 +2381,8 @@ func TestChanUpdatesInHorizon(t *testing.T) {
endTime = endTime.Add(time.Second * 10)
edge1 := newEdgePolicy(
- chanID.ToUint64(), edge1UpdateTime.Unix(),
+ lnwire.GossipVersion1, chanID.ToUint64(),
+ edge1UpdateTime.Unix(), true,
)
edge1.ChannelFlags = 0
edge1.ToNode = node2.PubKeyBytes
@@ -2368,7 +2392,8 @@ func TestChanUpdatesInHorizon(t *testing.T) {
}
edge2 := newEdgePolicy(
- chanID.ToUint64(), edge2UpdateTime.Unix(),
+ lnwire.GossipVersion1, chanID.ToUint64(),
+ edge2UpdateTime.Unix(), false,
)
edge2.ChannelFlags = 1
edge2.ToNode = node1.PubKeyBytes
@@ -2821,7 +2846,9 @@ func TestChanUpdatesInHorizonBoundaryConditions(t *testing.T) {
)
edge1 := newEdgePolicy(
+ lnwire.GossipVersion1,
chanID.ToUint64(), updateTime.Unix(),
+ true,
)
edge1.ChannelFlags = 0
edge1.ToNode = node2.PubKeyBytes
@@ -2831,7 +2858,9 @@ func TestChanUpdatesInHorizonBoundaryConditions(t *testing.T) {
)
edge2 := newEdgePolicy(
+ lnwire.GossipVersion1,
chanID.ToUint64(), updateTime.Unix(),
+ false,
)
edge2.ChannelFlags = 1
edge2.ToNode = node1.PubKeyBytes
@@ -3668,16 +3697,20 @@ func TestFetchChanInfos(t *testing.T) {
updateTime := endTime
endTime = updateTime.Add(time.Second * 10)
- edge1 := newEdgePolicy(chanID.ToUint64(), updateTime.Unix())
- edge1.ChannelFlags = 0
+ edge1 := newEdgePolicy(
+ lnwire.GossipVersion1, chanID.ToUint64(),
+ updateTime.Unix(), true,
+ )
edge1.ToNode = node2.PubKeyBytes
edge1.SigBytes = testSig.Serialize()
if err := graph.UpdateEdgePolicy(ctx, edge1); err != nil {
t.Fatalf("unable to update edge: %v", err)
}
- edge2 := newEdgePolicy(chanID.ToUint64(), updateTime.Unix())
- edge2.ChannelFlags = 1
+ edge2 := newEdgePolicy(
+ lnwire.GossipVersion1, chanID.ToUint64(),
+ updateTime.Unix(), false,
+ )
edge2.ToNode = node1.PubKeyBytes
edge2.SigBytes = testSig.Serialize()
if err := graph.UpdateEdgePolicy(ctx, edge2); err != nil {
@@ -3800,8 +3833,10 @@ func TestIncompleteChannelPolicies(t *testing.T) {
// unknown.
updateTime := time.Unix(1234, 0)
- edgePolicy := newEdgePolicy(chanID.ToUint64(), updateTime.Unix())
- edgePolicy.ChannelFlags = 0
+ edgePolicy := newEdgePolicy(
+ lnwire.GossipVersion1, chanID.ToUint64(), updateTime.Unix(),
+ true,
+ )
edgePolicy.ToNode = node2.PubKeyBytes
edgePolicy.SigBytes = testSig.Serialize()
if err := graph.UpdateEdgePolicy(ctx, edgePolicy); err != nil {
@@ -3813,8 +3848,10 @@ func TestIncompleteChannelPolicies(t *testing.T) {
// Create second policy and assert that both policies are reported
// as present.
- edgePolicy = newEdgePolicy(chanID.ToUint64(), updateTime.Unix())
- edgePolicy.ChannelFlags = 1
+ edgePolicy = newEdgePolicy(
+ lnwire.GossipVersion1, chanID.ToUint64(), updateTime.Unix(),
+ false,
+ )
edgePolicy.ToNode = node1.PubKeyBytes
edgePolicy.SigBytes = testSig.Serialize()
if err := graph.UpdateEdgePolicy(ctx, edgePolicy); err != nil {
@@ -4661,53 +4698,47 @@ func compareNodes(t *testing.T, a, b *models.Node) {
require.Equal(t, a, b)
}
-// compareEdgePolicies is used to compare two ChannelEdgePolices using
-// compareNodes, so as to exclude comparisons of the Nodes' Features struct.
+// compareEdgePolicies compares two ChannelEdgePolicy values for semantic
+// equality after normalizing version-specific/backend-specific differences.
func compareEdgePolicies(a, b *models.ChannelEdgePolicy) error {
- if a.ChannelID != b.ChannelID {
- return fmt.Errorf("ChannelID doesn't match: expected %v, "+
- "got %v", a.ChannelID, b.ChannelID)
- }
- if !reflect.DeepEqual(a.LastUpdate, b.LastUpdate) {
- return fmt.Errorf("edge LastUpdate doesn't match: "+
- "expected %#v, got %#v", a.LastUpdate, b.LastUpdate)
- }
- if a.MessageFlags != b.MessageFlags {
- return fmt.Errorf("MessageFlags doesn't match: expected %v, "+
- "got %v", a.MessageFlags, b.MessageFlags)
- }
- if a.ChannelFlags != b.ChannelFlags {
- return fmt.Errorf("ChannelFlags doesn't match: expected %v, "+
- "got %v", a.ChannelFlags, b.ChannelFlags)
- }
- if a.TimeLockDelta != b.TimeLockDelta {
- return fmt.Errorf("TimeLockDelta doesn't match: expected %v, "+
- "got %v", a.TimeLockDelta, b.TimeLockDelta)
- }
- if a.MinHTLC != b.MinHTLC {
- return fmt.Errorf("MinHTLC doesn't match: expected %v, "+
- "got %v", a.MinHTLC, b.MinHTLC)
- }
- if a.MaxHTLC != b.MaxHTLC {
- return fmt.Errorf("MaxHTLC doesn't match: expected %v, "+
- "got %v", a.MaxHTLC, b.MaxHTLC)
- }
- if a.FeeBaseMSat != b.FeeBaseMSat {
- return fmt.Errorf("FeeBaseMSat doesn't match: expected %v, "+
- "got %v", a.FeeBaseMSat, b.FeeBaseMSat)
- }
- if a.FeeProportionalMillionths != b.FeeProportionalMillionths {
- return fmt.Errorf("FeeProportionalMillionths doesn't match: "+
- "expected %v, got %v", a.FeeProportionalMillionths,
- b.FeeProportionalMillionths)
- }
- if !bytes.Equal(a.ExtraOpaqueData, b.ExtraOpaqueData) {
- return fmt.Errorf("extra data doesn't match: %v vs %v",
- a.ExtraOpaqueData, b.ExtraOpaqueData)
- }
- if !bytes.Equal(a.ToNode[:], b.ToNode[:]) {
- return fmt.Errorf("ToNode doesn't match: expected %x, got %x",
- a.ToNode, b.ToNode)
+ //nolint:ll
+ normalize := func(p *models.ChannelEdgePolicy) *models.ChannelEdgePolicy {
+ if p == nil {
+ return nil
+ }
+
+ policy := copyEdgePolicy(p)
+ if len(policy.ExtraOpaqueData) == 0 {
+ policy.ExtraOpaqueData = nil
+ }
+ if len(policy.ExtraSignedFields) == 0 {
+ policy.ExtraSignedFields = nil
+ }
+
+ switch policy.Version {
+ case lnwire.GossipVersion1:
+ // SecondPeer is v2-specific; derive canonical direction
+ // for v1.
+ policy.SecondPeer = !policy.IsNode1()
+ policy.LastBlockHeight = 0
+ policy.DisableFlags = 0
+ policy.ExtraSignedFields = nil
+
+ case lnwire.GossipVersion2:
+ policy.LastUpdate = time.Time{}
+ policy.MessageFlags = 0
+ policy.ChannelFlags = 0
+ policy.ExtraOpaqueData = nil
+ }
+
+ return policy
+ }
+
+ normalizedA := normalize(a)
+ normalizedB := normalize(b)
+ if !reflect.DeepEqual(normalizedA, normalizedB) {
+ return fmt.Errorf("expected %v, got %v", normalizedA,
+ normalizedB)
}
return nil
diff --git a/graph/db/kv_store.go b/graph/db/kv_store.go
index eb4c3b9..2bbfe89 100644
--- a/graph/db/kv_store.go
+++ b/graph/db/kv_store.go
@@ -3296,6 +3296,9 @@ func updateEdgePolicy(tx kvdb.RwTx, edge *models.ChannelEdgePolicy) (
route.Vertex, route.Vertex, bool, error) {
var noVertex route.Vertex
+ if edge.Version != lnwire.GossipVersion1 {
+ return noVertex, noVertex, false, ErrVersionNotSupportedForKVDB
+ }
edges := tx.ReadWriteBucket(edgeBucket)
if edges == nil {
@@ -5226,6 +5229,10 @@ func fetchChanEdgePolicies(edgeIndex kvdb.RBucket, edges kvdb.RBucket,
func serializeChanEdgePolicy(w io.Writer, edge *models.ChannelEdgePolicy,
to []byte) error {
+ if edge.Version != lnwire.GossipVersion1 {
+ return ErrVersionNotSupportedForKVDB
+ }
+
err := wire.WriteVarBytes(w, 0, edge.SigBytes)
if err != nil {
return err
@@ -5314,7 +5321,9 @@ func deserializeChanEdgePolicy(r io.Reader) (*models.ChannelEdgePolicy, error) {
func deserializeChanEdgePolicyRaw(r io.Reader) (*models.ChannelEdgePolicy,
error) {
- edge := &models.ChannelEdgePolicy{}
+ edge := &models.ChannelEdgePolicy{
+ Version: lnwire.GossipVersion1,
+ }
var err error
edge.SigBytes, err = wire.ReadVarBytes(r, 0, 80, "sig")
diff --git a/graph/db/sql_store.go b/graph/db/sql_store.go
index bcb8245..4468ad3 100644
--- a/graph/db/sql_store.go
+++ b/graph/db/sql_store.go
@@ -3455,10 +3455,16 @@ func updateChanEdgePolicy(ctx context.Context, tx SQLQueries,
var (
node1Pub, node2Pub route.Vertex
- isNode1 bool
chanIDB = channelIDToBytes(edge.ChannelID)
+ version = edge.Version
)
+ if !isKnownGossipVersion(version) {
+ return node1Pub, node2Pub, false, fmt.Errorf(
+ "unsupported gossip version: %d", version,
+ )
+ }
+
// Check that this edge policy refers to a channel that we already
// know of. We do this explicitly so that we can return the appropriate
// ErrEdgeNotFound error if the channel doesn't exist, rather than
@@ -3466,7 +3472,7 @@ func updateChanEdgePolicy(ctx context.Context, tx SQLQueries,
dbChan, err := tx.GetChannelAndNodesBySCID(
ctx, sqlc.GetChannelAndNodesBySCIDParams{
Scid: chanIDB,
- Version: int16(lnwire.GossipVersion1),
+ Version: int16(version),
},
)
if errors.Is(err, sql.ErrNoRows) {
@@ -3480,7 +3486,7 @@ func updateChanEdgePolicy(ctx context.Context, tx SQLQueries,
copy(node2Pub[:], dbChan.Node2PubKey)
// Figure out which node this edge is from.
- isNode1 = edge.ChannelFlags&lnwire.ChanUpdateDirection == 0
+ isNode1 := edge.IsNode1()
nodeID := dbChan.NodeID1
if !isNode1 {
nodeID = dbChan.NodeID2
@@ -3495,31 +3501,40 @@ func updateChanEdgePolicy(ctx context.Context, tx SQLQueries,
inboundBase = sqldb.SQLInt64(fee.BaseFee)
})
- id, err := tx.UpsertEdgePolicy(ctx, sqlc.UpsertEdgePolicyParams{
- Version: int16(lnwire.GossipVersion1),
- ChannelID: dbChan.ID,
- NodeID: nodeID,
- Timelock: int32(edge.TimeLockDelta),
- FeePpm: int64(edge.FeeProportionalMillionths),
- BaseFeeMsat: int64(edge.FeeBaseMSat),
- MinHtlcMsat: int64(edge.MinHTLC),
- LastUpdate: sqldb.SQLInt64(edge.LastUpdate.Unix()),
- Disabled: sql.NullBool{
- Valid: true,
- Bool: edge.IsDisabled(),
- },
- MaxHtlcMsat: sql.NullInt64{
- Valid: edge.MessageFlags.HasMaxHtlc(),
- Int64: int64(edge.MaxHTLC),
- },
+ params := sqlc.UpsertEdgePolicyParams{
+ Version: int16(version),
+ ChannelID: dbChan.ID,
+ NodeID: nodeID,
+ Timelock: int32(edge.TimeLockDelta),
+ FeePpm: int64(edge.FeeProportionalMillionths),
+ BaseFeeMsat: int64(edge.FeeBaseMSat),
+ MinHtlcMsat: int64(edge.MinHTLC),
MessageFlags: sqldb.SQLInt16(edge.MessageFlags),
ChannelFlags: sqldb.SQLInt16(edge.ChannelFlags),
InboundBaseFeeMsat: inboundBase,
InboundFeeRateMilliMsat: inboundRate,
Signature: edge.SigBytes,
- BlockHeight: sql.NullInt64{},
- DisableFlags: sql.NullInt16{},
- })
+ }
+
+ if version == lnwire.GossipVersion1 {
+ params.LastUpdate = sqldb.SQLInt64(edge.LastUpdate.Unix())
+ params.Disabled = sql.NullBool{
+ Valid: true,
+ Bool: edge.IsDisabled(),
+ }
+ params.MaxHtlcMsat = sql.NullInt64{
+ Valid: edge.MessageFlags.HasMaxHtlc(),
+ Int64: int64(edge.MaxHTLC),
+ }
+ } else {
+ params.BlockHeight = sqldb.SQLInt64(
+ int64(edge.LastBlockHeight),
+ )
+ params.DisableFlags = sqldb.SQLInt16(edge.DisableFlags)
+ params.MaxHtlcMsat = sqldb.SQLInt64(int64(edge.MaxHTLC))
+ }
+
+ id, err := tx.UpsertEdgePolicy(ctx, params)
if err != nil {
return node1Pub, node2Pub, isNode1,
fmt.Errorf("unable to upsert edge policy: %w", err)
@@ -3527,10 +3542,13 @@ func updateChanEdgePolicy(ctx context.Context, tx SQLQueries,
// Convert the flat extra opaque data into a map of TLV types to
// values.
- extra, err := marshalExtraOpaqueData(edge.ExtraOpaqueData)
- if err != nil {
- return node1Pub, node2Pub, false, fmt.Errorf("unable to "+
- "marshal extra opaque data: %w", err)
+ extra := edge.ExtraSignedFields
+ if version == lnwire.GossipVersion1 {
+ extra, err = marshalExtraOpaqueData(edge.ExtraOpaqueData)
+ if err != nil {
+ return node1Pub, node2Pub, false, fmt.Errorf("unable to "+
+ "marshal extra opaque data: %w", err)
+ }
}
// Update the channel policy's extra signed fields.
@@ -4713,14 +4731,14 @@ func getAndBuildChanPolicies(ctx context.Context, cfg *sqldb.QueryConfig,
}
pol1, err := buildChanPolicyWithBatchData(
- dbPol1, channelID, node2, batchData,
+ true, dbPol1, channelID, node2, batchData,
)
if err != nil {
return nil, nil, fmt.Errorf("unable to build policy1: %w", err)
}
pol2, err := buildChanPolicyWithBatchData(
- dbPol2, channelID, node1, batchData,
+ false, dbPol2, channelID, node1, batchData,
)
if err != nil {
return nil, nil, fmt.Errorf("unable to build policy2: %w", err)
@@ -4738,7 +4756,9 @@ func buildCachedChanPolicies(dbPol1, dbPol2 *sqlc.GraphChannelPolicy,
var p1, p2 *models.CachedEdgePolicy
if dbPol1 != nil {
- policy1, err := buildChanPolicy(*dbPol1, channelID, nil, node2)
+ policy1, err := buildChanPolicy(
+ true, *dbPol1, channelID, nil, node2,
+ )
if err != nil {
return nil, nil, err
}
@@ -4746,7 +4766,9 @@ func buildCachedChanPolicies(dbPol1, dbPol2 *sqlc.GraphChannelPolicy,
p1 = models.NewCachedPolicy(policy1)
}
if dbPol2 != nil {
- policy2, err := buildChanPolicy(*dbPol2, channelID, nil, node1)
+ policy2, err := buildChanPolicy(
+ false, *dbPol2, channelID, nil, node1,
+ )
if err != nil {
return nil, nil, err
}
@@ -4759,16 +4781,10 @@ func buildCachedChanPolicies(dbPol1, dbPol2 *sqlc.GraphChannelPolicy,
// buildChanPolicy builds a models.ChannelEdgePolicy instance from the
// provided sqlc.GraphChannelPolicy and other required information.
-func buildChanPolicy(dbPolicy sqlc.GraphChannelPolicy, channelID uint64,
- extras map[uint64][]byte,
+func buildChanPolicy(isNode1 bool, dbPolicy sqlc.GraphChannelPolicy,
+ channelID uint64, extras map[uint64][]byte,
toNode route.Vertex) (*models.ChannelEdgePolicy, error) {
- recs, err := lnwire.CustomRecords(extras).Serialize()
- if err != nil {
- return nil, fmt.Errorf("unable to serialize extra signed "+
- "fields: %w", err)
- }
-
var inboundFee fn.Option[lnwire.Fee]
if dbPolicy.InboundFeeRateMilliMsat.Valid ||
dbPolicy.InboundBaseFeeMsat.Valid {
@@ -4779,18 +4795,11 @@ func buildChanPolicy(dbPolicy sqlc.GraphChannelPolicy, channelID uint64,
})
}
- return &models.ChannelEdgePolicy{
- SigBytes: dbPolicy.Signature,
- ChannelID: channelID,
- LastUpdate: time.Unix(
- dbPolicy.LastUpdate.Int64, 0,
- ),
- MessageFlags: sqldb.ExtractSqlInt16[lnwire.ChanUpdateMsgFlags](
- dbPolicy.MessageFlags,
- ),
- ChannelFlags: sqldb.ExtractSqlInt16[lnwire.ChanUpdateChanFlags](
- dbPolicy.ChannelFlags,
- ),
+ p := &models.ChannelEdgePolicy{
+ Version: lnwire.GossipVersion(dbPolicy.Version),
+ SigBytes: dbPolicy.Signature,
+ ChannelID: channelID,
+ SecondPeer: !isNode1,
TimeLockDelta: uint16(dbPolicy.Timelock),
MinHTLC: lnwire.MilliSatoshi(
dbPolicy.MinHtlcMsat,
@@ -4804,8 +4813,40 @@ func buildChanPolicy(dbPolicy sqlc.GraphChannelPolicy, channelID uint64,
FeeProportionalMillionths: lnwire.MilliSatoshi(dbPolicy.FeePpm),
ToNode: toNode,
InboundFee: inboundFee,
- ExtraOpaqueData: recs,
- }, nil
+ }
+
+ if p.Version == lnwire.GossipVersion1 {
+ recs, err := lnwire.CustomRecords(extras).Serialize()
+ if err != nil {
+ return nil, fmt.Errorf("unable to serialize extra "+
+ "signed fields: %w", err)
+ }
+
+ p.ExtraOpaqueData = recs
+ p.LastUpdate = time.Unix(dbPolicy.LastUpdate.Int64, 0)
+ //nolint:ll
+ p.MessageFlags = sqldb.ExtractSqlInt16[lnwire.ChanUpdateMsgFlags](
+ dbPolicy.MessageFlags,
+ )
+ //nolint:ll
+ p.ChannelFlags = sqldb.ExtractSqlInt16[lnwire.ChanUpdateChanFlags](
+ dbPolicy.ChannelFlags,
+ )
+ } else {
+ if dbPolicy.BlockHeight.Valid {
+ p.LastBlockHeight = uint32(
+ dbPolicy.BlockHeight.Int64,
+ )
+ }
+
+ //nolint:ll
+ p.DisableFlags = sqldb.ExtractSqlInt16[lnwire.ChanUpdateDisableFlags](
+ dbPolicy.DisableFlags,
+ )
+ p.ExtraSignedFields = extras
+ }
+
+ return p, nil
}
// extractChannelPolicies extracts the sqlc.GraphChannelPolicy records from the give
@@ -5517,14 +5558,14 @@ func buildChanPoliciesWithBatchData(dbPol1, dbPol2 *sqlc.GraphChannelPolicy,
*models.ChannelEdgePolicy, error) {
pol1, err := buildChanPolicyWithBatchData(
- dbPol1, channelID, node2, batchData,
+ true, dbPol1, channelID, node2, batchData,
)
if err != nil {
return nil, nil, fmt.Errorf("unable to build policy1: %w", err)
}
pol2, err := buildChanPolicyWithBatchData(
- dbPol2, channelID, node1, batchData,
+ false, dbPol2, channelID, node1, batchData,
)
if err != nil {
return nil, nil, fmt.Errorf("unable to build policy2: %w", err)
@@ -5535,9 +5576,10 @@ func buildChanPoliciesWithBatchData(dbPol1, dbPol2 *sqlc.GraphChannelPolicy,
// buildChanPolicyWithBatchData builds a models.ChannelEdgePolicy instance from
// the provided sqlc.GraphChannelPolicy and the provided batchChannelData.
-func buildChanPolicyWithBatchData(dbPol *sqlc.GraphChannelPolicy,
- channelID uint64, toNode route.Vertex,
- batchData *batchChannelData) (*models.ChannelEdgePolicy, error) {
+func buildChanPolicyWithBatchData(isNode1 bool,
+ dbPol *sqlc.GraphChannelPolicy, channelID uint64,
+ toNode route.Vertex, batchData *batchChannelData) (
+ *models.ChannelEdgePolicy, error) {
if dbPol == nil {
return nil, nil
@@ -5550,7 +5592,7 @@ func buildChanPolicyWithBatchData(dbPol *sqlc.GraphChannelPolicy,
dbPol1Extras = make(map[uint64][]byte)
}
- return buildChanPolicy(*dbPol, channelID, dbPol1Extras, toNode)
+ return buildChanPolicy(isNode1, *dbPol, channelID, dbPol1Extras, toNode)
}
// batchChannelData holds all the related data for a batch of channels.
Why this scored 34/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.