diff --git a/autopilot/prefattach_test.go b/autopilot/prefattach_test.go index 30ec7ffc6..efddfb81e 100644 --- a/autopilot/prefattach_test.go +++ b/autopilot/prefattach_test.go @@ -512,6 +512,7 @@ func (d *testDBGraph) addRandChannel(node1, node2 *btcec.PublicKey, return nil, nil, err } edgePolicy := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), ChannelID: chanID.ToUint64(), LastUpdate: time.Now(), @@ -528,6 +529,7 @@ func (d *testDBGraph) addRandChannel(node1, node2 *btcec.PublicKey, return nil, nil, err } edgePolicy = &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), ChannelID: chanID.ToUint64(), LastUpdate: time.Now(), diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 88ac2418b..3e72f8a1d 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -3423,6 +3423,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(ctx context.Context, // signs a different SCID than the database SCID, but since there will // only be a difference if AuthProof == nil, this is fine. update := &models.ChannelEdgePolicy{ + Version: upd.GossipVersion(), SigBytes: upd.Signature.ToSignatureBytes(), ChannelID: chanInfo.ChannelID, LastUpdate: timestamp, diff --git a/graph/builder.go b/graph/builder.go index 1f3309c04..10d0b2904 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -953,6 +953,7 @@ func (b *Builder) ApplyChannelUpdate(msg *lnwire.ChannelUpdate1) bool { } update := &models.ChannelEdgePolicy{ + Version: msg.GossipVersion(), SigBytes: msg.Signature.ToSignatureBytes(), ChannelID: msg.ShortChannelID.ToUint64(), LastUpdate: time.Unix(int64(msg.Timestamp), 0), diff --git a/graph/builder_test.go b/graph/builder_test.go index 25b2d28b1..6929a4d49 100644 --- a/graph/builder_test.go +++ b/graph/builder_test.go @@ -166,6 +166,7 @@ func TestIgnoreChannelEdgePolicyForUnknownChannel(t *testing.T) { require.NoError(t, err) edgePolicy := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, LastUpdate: testTime, @@ -1219,6 +1220,7 @@ func TestIsStaleEdgePolicy(t *testing.T) { // We'll also add two edge policies, one for each direction. edgePolicy := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, LastUpdate: updateTimeStamp, @@ -1233,6 +1235,7 @@ func TestIsStaleEdgePolicy(t *testing.T) { } edgePolicy = &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, LastUpdate: updateTimeStamp, @@ -1557,6 +1560,7 @@ func parseTestGraph(t *testing.T, useCache bool, path string) ( } edgePolicy := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), MessageFlags: lnwire.ChanUpdateMsgFlags( edge.MessageFlags, @@ -1939,7 +1943,9 @@ func createTestGraphFromChannels(t *testing.T, useCache bool, channelFlags |= lnwire.ChanUpdateDisabled } + //nolint:ll edgePolicy := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), MessageFlags: msgFlags, ChannelFlags: channelFlags, @@ -1970,7 +1976,9 @@ func createTestGraphFromChannels(t *testing.T, useCache bool, } channelFlags |= lnwire.ChanUpdateDirection + //nolint:ll edgePolicy := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), MessageFlags: msgFlags, ChannelFlags: channelFlags, diff --git a/graph/db/graph_test.go b/graph/db/graph_test.go index 5148f63a8..f1acfe911 100644 --- a/graph/db/graph_test.go +++ b/graph/db/graph_test.go @@ -1044,6 +1044,7 @@ func createChannelEdge(node1, node2 *models.Node) (*models.ChannelEdgeInfo, ) edge1 := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), ChannelID: chanID, LastUpdate: nextUpdateTime(), @@ -1058,6 +1059,7 @@ func createChannelEdge(node1, node2 *models.Node) (*models.ChannelEdgeInfo, ExtraOpaqueData: []byte{1, 0}, } edge2 := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), ChannelID: chanID, LastUpdate: nextUpdateTime(), @@ -1442,6 +1444,7 @@ func randEdgePolicy(chanID uint64) *models.ChannelEdgePolicy { func copyEdgePolicy(p *models.ChannelEdgePolicy) *models.ChannelEdgePolicy { return &models.ChannelEdgePolicy{ + Version: p.Version, SigBytes: p.SigBytes, ChannelID: p.ChannelID, LastUpdate: p.LastUpdate, @@ -1459,6 +1462,7 @@ func copyEdgePolicy(p *models.ChannelEdgePolicy) *models.ChannelEdgePolicy { func newEdgePolicy(chanID uint64, updateTime int64) *models.ChannelEdgePolicy { return &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, ChannelID: chanID, LastUpdate: time.Unix(updateTime, 0), MessageFlags: 1, @@ -3454,6 +3458,7 @@ func TestFilterChannelRange(t *testing.T) { updateTime = time.Unix(updateTimeSeed, 0) err = graph.UpdateEdgePolicy( ctx, &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, ToNode: node.PubKeyBytes, ChannelFlags: chanFlags, ChannelID: chanID, @@ -4747,6 +4752,7 @@ func TestLightningNodeSigVerification(t *testing.T) { func TestComputeFee(t *testing.T) { var ( policy = models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, FeeBaseMSat: 10000, FeeProportionalMillionths: 30000, } diff --git a/graph/db/models/channel_edge_policy.go b/graph/db/models/channel_edge_policy.go index a2661ef6f..dd93c21b1 100644 --- a/graph/db/models/channel_edge_policy.go +++ b/graph/db/models/channel_edge_policy.go @@ -14,6 +14,10 @@ import ( // information concerning fees, and minimum time-lock information which is // utilized during path finding. type ChannelEdgePolicy struct { + // Version is the gossip version of the channel update that produced + // this policy. + Version lnwire.GossipVersion + // SigBytes is the raw bytes of the signature of the channel edge // policy. We'll only parse these if the caller needs to access the // signature for validation purposes. @@ -28,6 +32,14 @@ type ChannelEdgePolicy struct { // was received. LastUpdate time.Time + // LastBlockHeight is the block height that timestamps the last update + // for v2 channel updates. + LastBlockHeight uint32 + + // SecondPeer indicates whether this policy was announced by the second + // peer in the channel for v2 channel updates. + SecondPeer bool + // MessageFlags is a bitfield which indicates the presence of optional // fields (like max_htlc) in the policy. MessageFlags lnwire.ChanUpdateMsgFlags @@ -36,6 +48,10 @@ type ChannelEdgePolicy struct { // channel as well as the directed edge this update applies to. ChannelFlags lnwire.ChanUpdateChanFlags + // DisableFlags is a v2-specific bitfield which signals whether the + // channel is disabled for incoming or outgoing traffic. + DisableFlags lnwire.ChanUpdateDisableFlags + // TimeLockDelta is the number of blocks this node will subtract from // the expiry of an incoming HTLC. This value expresses the time buffer // the node would like to HTLC exchanges. @@ -77,11 +93,31 @@ type ChannelEdgePolicy struct { // and ensure we're able to make upgrades to the network in a forwards // compatible manner. ExtraOpaqueData lnwire.ExtraOpaqueData + + // ExtraSignedFields are the extra signed fields found in v2 channel + // updates. + ExtraSignedFields map[uint64][]byte +} + +// IsNode1 returns true if this policy was announced by the channel's node_1. +func (c *ChannelEdgePolicy) IsNode1() bool { + if c.Version == lnwire.GossipVersion1 { + return c.ChannelFlags&lnwire.ChanUpdateDirection == 0 + } + + return !c.SecondPeer } // IsDisabled determines whether the edge has the disabled bit set. +// +// NOTE: for v2 channel updates, we return true here only if both the incoming +// and outgoing disabled bits are set. func (c *ChannelEdgePolicy) IsDisabled() bool { - return c.ChannelFlags.IsDisabled() + if c.Version == lnwire.GossipVersion1 { + return c.ChannelFlags.IsDisabled() + } + + return !c.DisableFlags.IsEnabled() } // ComputeFee computes the fee to forward an HTLC of `amt` milli-satoshis over @@ -95,7 +131,13 @@ func (c *ChannelEdgePolicy) ComputeFee( // String returns a human-readable version of the channel edge policy. func (c *ChannelEdgePolicy) String() string { - return fmt.Sprintf("ChannelID=%v, MessageFlags=%v, ChannelFlags=%v, "+ - "LastUpdate=%v", c.ChannelID, c.MessageFlags, c.ChannelFlags, - c.LastUpdate) + if c.Version == lnwire.GossipVersion1 { + return fmt.Sprintf("ChannelID=%v, MessageFlags=%v, "+ + "ChannelFlags=%v, LastUpdate=%v", c.ChannelID, + c.MessageFlags, c.ChannelFlags, c.LastUpdate) + } + + return fmt.Sprintf("ChannelID=%v, Node1=%v, DisableFlags=%v, "+ + "BlockHeight=%v", c.ChannelID, !c.SecondPeer, + c.DisableFlags, c.LastBlockHeight) } diff --git a/graph/notifications_test.go b/graph/notifications_test.go index b086fc562..20e45026a 100644 --- a/graph/notifications_test.go +++ b/graph/notifications_test.go @@ -113,6 +113,7 @@ func randEdgePolicy(chanID *lnwire.ShortChannelID, } return &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), ChannelID: chanID.ToUint64(), LastUpdate: time.Unix(int64(prand.Int31()), 0), diff --git a/lnrpc/devrpc/dev_server.go b/lnrpc/devrpc/dev_server.go index 7dee1627a..3cecb36b5 100644 --- a/lnrpc/devrpc/dev_server.go +++ b/lnrpc/devrpc/dev_server.go @@ -304,6 +304,7 @@ func (s *Server) ImportGraph(ctx context.Context, makePolicy := func(rpcPolicy *lnrpc.RoutingPolicy) *models.ChannelEdgePolicy { //nolint:ll policy := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, ChannelID: rpcEdge.ChannelId, LastUpdate: time.Unix( int64(rpcPolicy.LastUpdate), 0, diff --git a/lnrpc/invoicesrpc/addinvoice_test.go b/lnrpc/invoicesrpc/addinvoice_test.go index ca83f8bab..104b2873d 100644 --- a/lnrpc/invoicesrpc/addinvoice_test.go +++ b/lnrpc/invoicesrpc/addinvoice_test.go @@ -317,7 +317,9 @@ var shouldIncludeChannelTestCases = []struct { return edge }(), + //nolint:ll &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, FeeBaseMSat: 1000, FeeProportionalMillionths: 20, TimeLockDelta: 13, @@ -364,7 +366,9 @@ var shouldIncludeChannelTestCases = []struct { ).Once().Return( &models.ChannelEdgeInfo{}, &models.ChannelEdgePolicy{}, + //nolint:ll &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, FeeBaseMSat: 1000, FeeProportionalMillionths: 20, TimeLockDelta: 13, @@ -409,7 +413,9 @@ var shouldIncludeChannelTestCases = []struct { ).Once().Return( &models.ChannelEdgeInfo{}, &models.ChannelEdgePolicy{}, + //nolint:ll &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, FeeBaseMSat: 1000, FeeProportionalMillionths: 20, TimeLockDelta: 13, diff --git a/lnwire/channel_update_2.go b/lnwire/channel_update_2.go index 8e82fe9d7..3fba2470d 100644 --- a/lnwire/channel_update_2.go +++ b/lnwire/channel_update_2.go @@ -380,9 +380,23 @@ func (c ChanUpdateDisableFlags) IsEnabled() bool { return c == 0 } -// String returns the bitfield flags as a string. +// String returns a human-readable representation of the disable flags. func (c ChanUpdateDisableFlags) String() string { - return fmt.Sprintf("%08b", c) + if c.IsEnabled() { + return "Enabled" + } + + incoming := c.IncomingDisabled() + outgoing := c.OutgoingDisabled() + + switch { + case incoming && outgoing: + return "Disabled(incoming&outgoing)" + case incoming: + return "Disabled(incoming)" + default: + return "Disabled(outgoing)" + } } // Record returns the tlv record for the disable flags. diff --git a/netann/chan_status_manager_test.go b/netann/chan_status_manager_test.go index 5265d317f..59ce324c6 100644 --- a/netann/chan_status_manager_test.go +++ b/netann/chan_status_manager_test.go @@ -116,12 +116,14 @@ func createEdgePolicies(t *testing.T, channel *channeldb.OpenChannel, return edgeInfo, &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, ChannelID: channel.ShortChanID().ToUint64(), ChannelFlags: dir1, LastUpdate: time.Now(), SigBytes: testSigBytes, }, &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, ChannelID: channel.ShortChanID().ToUint64(), ChannelFlags: dir2, LastUpdate: time.Now(), @@ -222,6 +224,7 @@ func (g *mockGraph) ApplyChannelUpdate(update *lnwire.ChannelUpdate1, timestamp := time.Unix(int64(update.Timestamp), 0) policy := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, ChannelID: update.ShortChannelID.ToUint64(), ChannelFlags: update.ChannelFlags, LastUpdate: timestamp, diff --git a/routing/localchans/manager.go b/routing/localchans/manager.go index cc86d82cc..6dd30b0ae 100644 --- a/routing/localchans/manager.go +++ b/routing/localchans/manager.go @@ -364,6 +364,7 @@ func (r *Manager) createEdge(channel *channeldb.OpenChannel, // be updated with the new values in the call to processChan below. timeLockDelta := uint16(r.DefaultRoutingPolicy.TimeLockDelta) edge := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, ChannelID: shortChanID.ToUint64(), LastUpdate: timestamp, TimeLockDelta: timeLockDelta, diff --git a/routing/localchans/manager_test.go b/routing/localchans/manager_test.go index 6196330bd..c48e61641 100644 --- a/routing/localchans/manager_test.go +++ b/routing/localchans/manager_test.go @@ -64,6 +64,7 @@ func TestManager(t *testing.T) { } currentPolicy := models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, MinHTLC: minHTLC, MessageFlags: lnwire.ChanUpdateRequiredMaxHtlc, } @@ -451,6 +452,7 @@ func TestCreateEdgeLower(t *testing.T) { require.NoError(t, err) expectedEdge := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, ChannelID: 8, LastUpdate: timestamp, TimeLockDelta: 7, @@ -542,6 +544,7 @@ func TestCreateEdgeHigher(t *testing.T) { require.NoError(t, err) expectedEdge := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, ChannelID: 8, LastUpdate: timestamp, TimeLockDelta: 7, diff --git a/routing/pathfind_test.go b/routing/pathfind_test.go index ed291a6aa..01f5d9849 100644 --- a/routing/pathfind_test.go +++ b/routing/pathfind_test.go @@ -389,6 +389,7 @@ func parseTestGraph(t *testing.T, useCache bool, path string) ( } edgePolicy := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), MessageFlags: lnwire.ChanUpdateMsgFlags(edge.MessageFlags), ChannelFlags: channelFlags, @@ -740,7 +741,9 @@ func createTestGraphFromChannels(t *testing.T, useCache bool, channelFlags |= lnwire.ChanUpdateDisabled } + //nolint:ll edgePolicy := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), MessageFlags: msgFlags, ChannelFlags: channelFlags, @@ -772,7 +775,9 @@ func createTestGraphFromChannels(t *testing.T, useCache bool, } channelFlags |= lnwire.ChanUpdateDirection + //nolint:ll edgePolicy := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), MessageFlags: msgFlags, ChannelFlags: channelFlags, diff --git a/routing/router_test.go b/routing/router_test.go index 6f9d2c3f3..12c4adb8f 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -2751,6 +2751,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { // We must add the edge policy to be able to use the edge for route // finding. edgePolicy := &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, LastUpdate: testTime, @@ -2766,6 +2767,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { // Create edge in the other direction as well. edgePolicy = &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, LastUpdate: testTime, @@ -2832,6 +2834,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { require.NoError(t, ctx.graph.AddChannelEdge(ctxb, edge)) edgePolicy = &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, LastUpdate: testTime, @@ -2846,6 +2849,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { require.NoError(t, ctx.graph.UpdateEdgePolicy(ctxb, edgePolicy)) edgePolicy = &models.ChannelEdgePolicy{ + Version: lnwire.GossipVersion1, SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, LastUpdate: testTime, @@ -2965,6 +2969,7 @@ func (m *mockGraphBuilder) ApplyChannelUpdate(msg *lnwire.ChannelUpdate1) bool { } err := m.updateEdge(&models.ChannelEdgePolicy{ + Version: msg.GossipVersion(), SigBytes: msg.Signature.ToSignatureBytes(), ChannelID: msg.ShortChannelID.ToUint64(), LastUpdate: time.Unix(int64(msg.Timestamp), 0),