From 7adfc717eeab36542ccea2466a8114446a6454d5 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 21 Aug 2024 11:44:44 +0200 Subject: [PATCH 01/60] multi: rename ChannelAuthProof To prepare for the addition of ChannelAuthProof2 along with a ChannelAuthProof interface, rename ChannelAuthProof to ChannelAuthProof1. --- channeldb/graph.go | 2 +- channeldb/graph_test.go | 10 +++++----- channeldb/models/channel_auth_proof.go | 14 +++++++------- channeldb/models/channel_edge_info.go | 2 +- discovery/gossiper.go | 8 ++++---- discovery/gossiper_test.go | 2 +- graph/builder.go | 2 +- graph/builder_test.go | 10 +++++----- graph/interfaces.go | 2 +- graph/notifications_test.go | 10 +++++----- netann/channel_announcement.go | 2 +- netann/channel_announcement_test.go | 2 +- routing/pathfind_test.go | 2 +- 13 files changed, 34 insertions(+), 34 deletions(-) diff --git a/channeldb/graph.go b/channeldb/graph.go index 86cbe9aa93..ade51aa2c4 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -4337,7 +4337,7 @@ func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo, error) { return models.ChannelEdgeInfo{}, err } - proof := &models.ChannelAuthProof{} + proof := &models.ChannelAuthProof1{} proof.NodeSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") if err != nil { diff --git a/channeldb/graph_test.go b/channeldb/graph_test.go index 89197a0a80..39168a5ab0 100644 --- a/channeldb/graph_test.go +++ b/channeldb/graph_test.go @@ -329,7 +329,7 @@ func TestEdgeInsertionDeletion(t *testing.T) { edgeInfo := models.ChannelEdgeInfo{ ChannelID: chanID, ChainHash: key, - AuthProof: &models.ChannelAuthProof{ + AuthProof: &models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), @@ -404,7 +404,7 @@ func createEdge(height, txIndex uint32, txPosition uint16, outPointIndex uint32, edgeInfo := models.ChannelEdgeInfo{ ChannelID: shortChanID.ToUint64(), ChainHash: key, - AuthProof: &models.ChannelAuthProof{ + AuthProof: &models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), @@ -647,7 +647,7 @@ func createChannelEdge(db kvdb.Backend, node1, node2 *LightningNode) ( edgeInfo := &models.ChannelEdgeInfo{ ChannelID: chanID, ChainHash: key, - AuthProof: &models.ChannelAuthProof{ + AuthProof: &models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), @@ -1260,7 +1260,7 @@ func fillTestGraph(t require.TestingT, graph *ChannelGraph, numNodes, edgeInfo := models.ChannelEdgeInfo{ ChannelID: chanID, ChainHash: key, - AuthProof: &models.ChannelAuthProof{ + AuthProof: &models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), @@ -1442,7 +1442,7 @@ func TestGraphPruning(t *testing.T) { edgeInfo := models.ChannelEdgeInfo{ ChannelID: chanID, ChainHash: key, - AuthProof: &models.ChannelAuthProof{ + AuthProof: &models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), diff --git a/channeldb/models/channel_auth_proof.go b/channeldb/models/channel_auth_proof.go index 1341394674..7b7922b7d4 100644 --- a/channeldb/models/channel_auth_proof.go +++ b/channeldb/models/channel_auth_proof.go @@ -2,14 +2,14 @@ package models import "github.com/btcsuite/btcd/btcec/v2/ecdsa" -// ChannelAuthProof is the authentication proof (the signature portion) for a +// ChannelAuthProof1 is the authentication proof (the signature portion) for a // channel. Using the four signatures contained in the struct, and some // auxiliary knowledge (the funding script, node identities, and outpoint) nodes // on the network are able to validate the authenticity and existence of a // channel. Each of these signatures signs the following digest: chanID || // nodeID1 || nodeID2 || bitcoinKey1|| bitcoinKey2 || 2-byte-feature-len || // features. -type ChannelAuthProof struct { +type ChannelAuthProof1 struct { // nodeSig1 is a cached instance of the first node signature. nodeSig1 *ecdsa.Signature @@ -45,7 +45,7 @@ type ChannelAuthProof struct { // // NOTE: By having this method to access an attribute, we ensure we only need // to fully deserialize the signature if absolutely necessary. -func (c *ChannelAuthProof) Node1Sig() (*ecdsa.Signature, error) { +func (c *ChannelAuthProof1) Node1Sig() (*ecdsa.Signature, error) { if c.nodeSig1 != nil { return c.nodeSig1, nil } @@ -66,7 +66,7 @@ func (c *ChannelAuthProof) Node1Sig() (*ecdsa.Signature, error) { // // NOTE: By having this method to access an attribute, we ensure we only need // to fully deserialize the signature if absolutely necessary. -func (c *ChannelAuthProof) Node2Sig() (*ecdsa.Signature, error) { +func (c *ChannelAuthProof1) Node2Sig() (*ecdsa.Signature, error) { if c.nodeSig2 != nil { return c.nodeSig2, nil } @@ -86,7 +86,7 @@ func (c *ChannelAuthProof) Node2Sig() (*ecdsa.Signature, error) { // // NOTE: By having this method to access an attribute, we ensure we only need // to fully deserialize the signature if absolutely necessary. -func (c *ChannelAuthProof) BitcoinSig1() (*ecdsa.Signature, error) { +func (c *ChannelAuthProof1) BitcoinSig1() (*ecdsa.Signature, error) { if c.bitcoinSig1 != nil { return c.bitcoinSig1, nil } @@ -106,7 +106,7 @@ func (c *ChannelAuthProof) BitcoinSig1() (*ecdsa.Signature, error) { // // NOTE: By having this method to access an attribute, we ensure we only need // to fully deserialize the signature if absolutely necessary. -func (c *ChannelAuthProof) BitcoinSig2() (*ecdsa.Signature, error) { +func (c *ChannelAuthProof1) BitcoinSig2() (*ecdsa.Signature, error) { if c.bitcoinSig2 != nil { return c.bitcoinSig2, nil } @@ -123,7 +123,7 @@ func (c *ChannelAuthProof) BitcoinSig2() (*ecdsa.Signature, error) { // IsEmpty check is the authentication proof is empty Proof is empty if at // least one of the signatures are equal to nil. -func (c *ChannelAuthProof) IsEmpty() bool { +func (c *ChannelAuthProof1) IsEmpty() bool { return len(c.NodeSig1Bytes) == 0 || len(c.NodeSig2Bytes) == 0 || len(c.BitcoinSig1Bytes) == 0 || diff --git a/channeldb/models/channel_edge_info.go b/channeldb/models/channel_edge_info.go index 0f91e2bbec..78d612e667 100644 --- a/channeldb/models/channel_edge_info.go +++ b/channeldb/models/channel_edge_info.go @@ -53,7 +53,7 @@ type ChannelEdgeInfo struct { // AuthProof is the authentication proof for this channel. This proof // contains a set of signatures binding four identities, which attests // to the legitimacy of the advertised channel. - AuthProof *ChannelAuthProof + AuthProof *ChannelAuthProof1 // ChannelPoint is the funding outpoint of the channel. This can be // used to uniquely identify the channel within the channel graph. diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 284cc42212..2fa6971108 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -1867,7 +1867,7 @@ func remotePubFromChanInfo(chanInfo *models.ChannelEdgeInfo, // assemble the proof and craft the ChannelAnnouncement. func (d *AuthenticatedGossiper) processRejectedEdge( chanAnnMsg *lnwire.ChannelAnnouncement1, - proof *models.ChannelAuthProof) ([]networkMsg, error) { + proof *models.ChannelAuthProof1) ([]networkMsg, error) { // First, we'll fetch the state of the channel as we know if from the // database. @@ -2548,7 +2548,7 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg, // If this is a remote channel announcement, then we'll validate all // the signatures within the proof as it should be well formed. - var proof *models.ChannelAuthProof + var proof *models.ChannelAuthProof1 if nMsg.isRemote { err := netann.ValidateChannelAnn(ann, d.fetchPKScript) if err != nil { @@ -2569,7 +2569,7 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg, // If the proof checks out, then we'll save the proof itself to // the database so we can fetch it later when gossiping with // other nodes. - proof = &models.ChannelAuthProof{ + proof = &models.ChannelAuthProof1{ NodeSig1Bytes: ann.NodeSig1.ToSignatureBytes(), NodeSig2Bytes: ann.NodeSig2.ToSignatureBytes(), BitcoinSig1Bytes: ann.BitcoinSig1.ToSignatureBytes(), @@ -3424,7 +3424,7 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, // We now have both halves of the channel announcement proof, then // we'll reconstruct the initial announcement so we can validate it // shortly below. - var dbProof models.ChannelAuthProof + var dbProof models.ChannelAuthProof1 if isFirstNode { dbProof.NodeSig1Bytes = ann.NodeSignature.ToSignatureBytes() dbProof.NodeSig2Bytes = oppProof.NodeSignature.ToSignatureBytes() diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index db632cdafe..cf1d12fb16 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -185,7 +185,7 @@ func (r *mockGraphSource) CurrentBlockHeight() (uint32, error) { } func (r *mockGraphSource) AddProof(chanID lnwire.ShortChannelID, - proof *models.ChannelAuthProof) error { + proof *models.ChannelAuthProof1) error { r.mu.Lock() defer r.mu.Unlock() diff --git a/graph/builder.go b/graph/builder.go index 6930f1a894..2d24395f55 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -1668,7 +1668,7 @@ func (b *Builder) ForAllOutgoingChannels(cb func(kvdb.RTx, // // NOTE: This method is part of the ChannelGraphSource interface. func (b *Builder) AddProof(chanID lnwire.ShortChannelID, - proof *models.ChannelAuthProof) error { + proof *models.ChannelAuthProof1) error { info, _, _, err := b.cfg.Graph.FetchChannelEdgesByID(chanID.ToUint64()) if err != nil { diff --git a/graph/builder_test.go b/graph/builder_test.go index f6c5dcf9cb..650ef62f19 100644 --- a/graph/builder_test.go +++ b/graph/builder_test.go @@ -263,7 +263,7 @@ func TestWakeUpOnStaleBranch(t *testing.T) { ChannelID: chanID1, NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, - AuthProof: &models.ChannelAuthProof{ + AuthProof: &models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), @@ -281,7 +281,7 @@ func TestWakeUpOnStaleBranch(t *testing.T) { ChannelID: chanID2, NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, - AuthProof: &models.ChannelAuthProof{ + AuthProof: &models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), @@ -468,7 +468,7 @@ func TestDisconnectedBlocks(t *testing.T) { NodeKey2Bytes: node2.PubKeyBytes, BitcoinKey1Bytes: node1.PubKeyBytes, BitcoinKey2Bytes: node2.PubKeyBytes, - AuthProof: &models.ChannelAuthProof{ + AuthProof: &models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), @@ -488,7 +488,7 @@ func TestDisconnectedBlocks(t *testing.T) { NodeKey2Bytes: node2.PubKeyBytes, BitcoinKey1Bytes: node1.PubKeyBytes, BitcoinKey2Bytes: node2.PubKeyBytes, - AuthProof: &models.ChannelAuthProof{ + AuthProof: &models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), @@ -616,7 +616,7 @@ func TestRouterChansClosedOfflinePruneGraph(t *testing.T) { ChannelID: chanID1.ToUint64(), NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, - AuthProof: &models.ChannelAuthProof{ + AuthProof: &models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), diff --git a/graph/interfaces.go b/graph/interfaces.go index 7ae79f9a9f..5f2eb218a1 100644 --- a/graph/interfaces.go +++ b/graph/interfaces.go @@ -35,7 +35,7 @@ type ChannelGraphSource interface { // AddProof updates the channel edge info with proof which is needed to // properly announce the edge to the rest of the network. AddProof(chanID lnwire.ShortChannelID, - proof *models.ChannelAuthProof) error + proof *models.ChannelAuthProof1) error // UpdateEdge is used to update edge information, without this message // edge considered as not fully constructed. diff --git a/graph/notifications_test.go b/graph/notifications_test.go index 09ebf1211b..c6f4855b63 100644 --- a/graph/notifications_test.go +++ b/graph/notifications_test.go @@ -69,7 +69,7 @@ var ( _ = testSScalar.SetByteSlice(testSBytes) testSig = ecdsa.NewSignature(testRScalar, testSScalar) - testAuthProof = models.ChannelAuthProof{ + testAuthProof = models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), @@ -470,7 +470,7 @@ func TestEdgeUpdateNotification(t *testing.T) { ChannelID: chanID.ToUint64(), NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, - AuthProof: &models.ChannelAuthProof{ + AuthProof: &models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), @@ -657,7 +657,7 @@ func TestNodeUpdateNotification(t *testing.T) { ChannelID: chanID.ToUint64(), NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, - AuthProof: &models.ChannelAuthProof{ + AuthProof: &models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), @@ -841,7 +841,7 @@ func TestNotificationCancellation(t *testing.T) { ChannelID: chanID.ToUint64(), NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, - AuthProof: &models.ChannelAuthProof{ + AuthProof: &models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), @@ -910,7 +910,7 @@ func TestChannelCloseNotification(t *testing.T) { ChannelID: chanID.ToUint64(), NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, - AuthProof: &models.ChannelAuthProof{ + AuthProof: &models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), diff --git a/netann/channel_announcement.go b/netann/channel_announcement.go index 9644a523ff..4f625041c3 100644 --- a/netann/channel_announcement.go +++ b/netann/channel_announcement.go @@ -33,7 +33,7 @@ const ( // function is used to transform out database structs into the corresponding wire // structs for announcing new channels to other peers, or simply syncing up a // peer's initial routing table upon connect. -func CreateChanAnnouncement(chanProof *models.ChannelAuthProof, +func CreateChanAnnouncement(chanProof *models.ChannelAuthProof1, chanInfo *models.ChannelEdgeInfo, e1, e2 *models.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement1, *lnwire.ChannelUpdate1, *lnwire.ChannelUpdate1, error) { diff --git a/netann/channel_announcement_test.go b/netann/channel_announcement_test.go index 61db16b16e..805825b6e3 100644 --- a/netann/channel_announcement_test.go +++ b/netann/channel_announcement_test.go @@ -44,7 +44,7 @@ func TestCreateChanAnnouncement(t *testing.T) { ExtraOpaqueData: []byte{0x1}, } - chanProof := &models.ChannelAuthProof{ + chanProof := &models.ChannelAuthProof1{ NodeSig1Bytes: expChanAnn.NodeSig1.ToSignatureBytes(), NodeSig2Bytes: expChanAnn.NodeSig2.ToSignatureBytes(), BitcoinSig1Bytes: expChanAnn.BitcoinSig1.ToSignatureBytes(), diff --git a/routing/pathfind_test.go b/routing/pathfind_test.go index 72f71600dd..486162bc67 100644 --- a/routing/pathfind_test.go +++ b/routing/pathfind_test.go @@ -98,7 +98,7 @@ var ( _ = testSScalar.SetByteSlice(testSBytes) testSig = ecdsa.NewSignature(testRScalar, testSScalar) - testAuthProof = models.ChannelAuthProof{ + testAuthProof = models.ChannelAuthProof1{ NodeSig1Bytes: testSig.Serialize(), NodeSig2Bytes: testSig.Serialize(), BitcoinSig1Bytes: testSig.Serialize(), From 0225c6ca9a097d8dff8da71d5d14c2a43ebc10c6 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 21 Aug 2024 11:45:30 +0200 Subject: [PATCH 02/60] multi: rename ChannelEdgePolicy In preparation for the addition of ChannelEdgePolicy2 and a ChannelEdgePolicy interface, rename ChannelEdgePolicy to ChannelEdgePolicy1. --- autopilot/graph.go | 6 +- channeldb/graph.go | 84 ++++++++++++------------ channeldb/graph_cache.go | 14 ++-- channeldb/graph_cache_test.go | 18 ++--- channeldb/graph_test.go | 50 +++++++------- channeldb/models/cached_edge_policy.go | 4 +- channeldb/models/channel_edge_info.go | 2 +- channeldb/models/channel_edge_policy.go | 12 ++-- discovery/gossiper.go | 16 ++--- discovery/gossiper_test.go | 30 ++++----- funding/manager.go | 6 +- funding/manager_test.go | 2 +- graph/builder.go | 24 +++---- graph/builder_test.go | 12 ++-- graph/interfaces.go | 20 +++--- graph/notifications.go | 2 +- graph/notifications_test.go | 6 +- graph/validation_barrier.go | 8 +-- lnrpc/devrpc/dev_server.go | 4 +- lnrpc/invoicesrpc/addinvoice.go | 10 +-- lnrpc/invoicesrpc/addinvoice_test.go | 60 ++++++++--------- netann/chan_status_manager_test.go | 20 +++--- netann/channel_announcement.go | 2 +- netann/channel_update.go | 8 +-- netann/interface.go | 2 +- peer/brontide.go | 2 +- routing/blindedpath/blinded_path.go | 4 +- routing/blindedpath/blinded_path_test.go | 16 ++--- routing/localchans/manager.go | 6 +- routing/localchans/manager_test.go | 6 +- routing/pathfind.go | 4 +- routing/pathfind_test.go | 6 +- routing/router_test.go | 14 ++-- rpcserver.go | 12 ++-- server.go | 6 +- 35 files changed, 249 insertions(+), 249 deletions(-) diff --git a/autopilot/graph.go b/autopilot/graph.go index 2ce49c1272..d9dd2df181 100644 --- a/autopilot/graph.go +++ b/autopilot/graph.go @@ -91,7 +91,7 @@ func (d *dbNode) Addrs() []net.Addr { func (d *dbNode) ForEachChannel(cb func(ChannelEdge) error) error { return d.db.ForEachNodeChannelTx(d.tx, d.node.PubKeyBytes, func(tx kvdb.RTx, ei *models.ChannelEdgeInfo, ep, - _ *models.ChannelEdgePolicy) error { + _ *models.ChannelEdgePolicy1) error { // Skip channels for which no outgoing edge policy is // available. @@ -246,7 +246,7 @@ func (d *databaseChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey, if err := d.db.AddChannelEdge(edge); err != nil { return nil, nil, err } - edgePolicy := &models.ChannelEdgePolicy{ + edgePolicy := &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), ChannelID: chanID.ToUint64(), LastUpdate: time.Now(), @@ -262,7 +262,7 @@ func (d *databaseChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey, if err := d.db.UpdateEdgePolicy(edgePolicy); err != nil { return nil, nil, err } - edgePolicy = &models.ChannelEdgePolicy{ + edgePolicy = &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), ChannelID: chanID.ToUint64(), LastUpdate: time.Now(), diff --git a/channeldb/graph.go b/channeldb/graph.go index ade51aa2c4..232b3a727b 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -240,7 +240,7 @@ func NewChannelGraph(db kvdb.Backend, rejectCacheSize, chanCacheSize int, } err = g.ForEachChannel(func(info *models.ChannelEdgeInfo, - policy1, policy2 *models.ChannelEdgePolicy) error { + policy1, policy2 *models.ChannelEdgePolicy1) error { g.graphCache.AddChannel(info, policy1, policy2) @@ -266,10 +266,10 @@ type channelMapKey struct { // getChannelMap loads all channel edge policies from the database and stores // them in a map. func (c *ChannelGraph) getChannelMap(edges kvdb.RBucket) ( - map[channelMapKey]*models.ChannelEdgePolicy, error) { + map[channelMapKey]*models.ChannelEdgePolicy1, error) { // Create a map to store all channel edge policies. - channelMap := make(map[channelMapKey]*models.ChannelEdgePolicy) + channelMap := make(map[channelMapKey]*models.ChannelEdgePolicy1) err := kvdb.ForAll(edges, func(k, edgeBytes []byte) error { // Skip embedded buckets. @@ -420,7 +420,7 @@ func (c *ChannelGraph) NewPathFindTx() (kvdb.RTx, error) { // for that particular channel edge routing policy will be passed into the // callback. func (c *ChannelGraph) ForEachChannel(cb func(*models.ChannelEdgeInfo, - *models.ChannelEdgePolicy, *models.ChannelEdgePolicy) error) error { + *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error { return c.db.View(func(tx kvdb.RTx) error { edges := tx.ReadBucket(edgeBucket) @@ -490,7 +490,7 @@ func (c *ChannelGraph) ForEachNodeDirectedChannel(tx kvdb.RTx, } dbCallback := func(tx kvdb.RTx, e *models.ChannelEdgeInfo, p1, - p2 *models.ChannelEdgePolicy) error { + p2 *models.ChannelEdgePolicy1) error { var cachedInPolicy *models.CachedEdgePolicy if p2 != nil { @@ -576,8 +576,8 @@ func (c *ChannelGraph) ForEachNodeCached(cb func(node route.Vertex, err := c.ForEachNodeChannelTx(tx, node.PubKeyBytes, func(tx kvdb.RTx, e *models.ChannelEdgeInfo, - p1 *models.ChannelEdgePolicy, - p2 *models.ChannelEdgePolicy) error { + p1 *models.ChannelEdgePolicy1, + p2 *models.ChannelEdgePolicy1) error { toNodeCallback := func() route.Vertex { return node.PubKeyBytes @@ -1879,11 +1879,11 @@ type ChannelEdge struct { // Policy1 points to the "first" edge policy of the channel containing // the dynamic information required to properly route through the edge. - Policy1 *models.ChannelEdgePolicy + Policy1 *models.ChannelEdgePolicy1 // Policy2 points to the "second" edge policy of the channel containing // the dynamic information required to properly route through the edge. - Policy2 *models.ChannelEdgePolicy + Policy2 *models.ChannelEdgePolicy1 // Node1 is "node 1" in the channel. This is the node that would have // produced Policy1 if it exists. @@ -2526,7 +2526,7 @@ func (c *ChannelGraph) fetchChanInfos(tx kvdb.RTx, chanIDs []uint64) ( } func delEdgeUpdateIndexEntry(edgesBucket kvdb.RwBucket, chanID uint64, - edge1, edge2 *models.ChannelEdgePolicy) error { + edge1, edge2 *models.ChannelEdgePolicy1) error { // First, we'll fetch the edge update index bucket which currently // stores an entry for the channel we're about to delete. @@ -2672,7 +2672,7 @@ func (c *ChannelGraph) delChannelEdgeUnsafe(edges, edgeIndex, chanIndex, // marked with the correct lagging channel since we received an update from only // one side. func makeZombiePubkeys(info *models.ChannelEdgeInfo, - e1, e2 *models.ChannelEdgePolicy) ([33]byte, [33]byte) { + e1, e2 *models.ChannelEdgePolicy1) ([33]byte, [33]byte) { switch { // If we don't have either edge policy, we'll return both pubkeys so @@ -2697,12 +2697,12 @@ func makeZombiePubkeys(info *models.ChannelEdgeInfo, // UpdateEdgePolicy updates the edge routing policy for a single directed edge // within the database for the referenced channel. The `flags` attribute within -// the ChannelEdgePolicy determines which of the directed edges are being +// the ChannelEdgePolicy1 determines which of the directed edges are being // updated. If the flag is 1, then the first node's information is being // updated, otherwise it's the second node's information. The node ordering is // determined by the lexicographical ordering of the identity public keys of the // nodes on either side of the channel. -func (c *ChannelGraph) UpdateEdgePolicy(edge *models.ChannelEdgePolicy, +func (c *ChannelGraph) UpdateEdgePolicy(edge *models.ChannelEdgePolicy1, op ...batch.SchedulerOption) error { var ( @@ -2750,7 +2750,7 @@ func (c *ChannelGraph) UpdateEdgePolicy(edge *models.ChannelEdgePolicy, return c.chanScheduler.Execute(r) } -func (c *ChannelGraph) updateEdgeCache(e *models.ChannelEdgePolicy, +func (c *ChannelGraph) updateEdgeCache(e *models.ChannelEdgePolicy1, isUpdate1 bool) { // If an entry for this channel is found in reject cache, we'll modify @@ -2784,7 +2784,7 @@ func (c *ChannelGraph) updateEdgeCache(e *models.ChannelEdgePolicy, // buckets using an existing database transaction. The returned boolean will be // true if the updated policy belongs to node1, and false if the policy belonged // to node2. -func updateEdgePolicy(tx kvdb.RwTx, edge *models.ChannelEdgePolicy, +func updateEdgePolicy(tx kvdb.RwTx, edge *models.ChannelEdgePolicy1, graphCache *GraphCache) (bool, error) { edges := tx.ReadWriteBucket(edgeBucket) @@ -2979,8 +2979,8 @@ func (c *ChannelGraph) isPublic(tx kvdb.RTx, nodePub route.Vertex, nodeIsPublic := false errDone := errors.New("done") err := c.ForEachNodeChannelTx(tx, nodePub, func(tx kvdb.RTx, - info *models.ChannelEdgeInfo, _ *models.ChannelEdgePolicy, - _ *models.ChannelEdgePolicy) error { + info *models.ChannelEdgeInfo, _ *models.ChannelEdgePolicy1, + _ *models.ChannelEdgePolicy1) error { // If this edge doesn't extend to the source node, we'll // terminate our search as we can now conclude that the node is @@ -3122,8 +3122,8 @@ func (n *graphCacheNode) Features() *lnwire.FeatureVector { // // Unknown policies are passed into the callback as nil values. func (n *graphCacheNode) ForEachChannel(tx kvdb.RTx, - cb func(kvdb.RTx, *models.ChannelEdgeInfo, *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy) error) error { + cb func(kvdb.RTx, *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1) error) error { return nodeTraversal(tx, n.pubKeyBytes[:], nil, cb) } @@ -3183,8 +3183,8 @@ func (c *ChannelGraph) HasLightningNode(nodePub [33]byte) (time.Time, bool, erro // nodeTraversal is used to traverse all channels of a node given by its // public key and passes channel information into the specified callback. func nodeTraversal(tx kvdb.RTx, nodePub []byte, db kvdb.Backend, - cb func(kvdb.RTx, *models.ChannelEdgeInfo, *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy) error) error { + cb func(kvdb.RTx, *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1) error) error { traversal := func(tx kvdb.RTx) error { edges := tx.ReadBucket(edgeBucket) @@ -3272,8 +3272,8 @@ func nodeTraversal(tx kvdb.RTx, nodePub []byte, db kvdb.Backend, // // Unknown policies are passed into the callback as nil values. func (c *ChannelGraph) ForEachNodeChannel(nodePub route.Vertex, - cb func(kvdb.RTx, *models.ChannelEdgeInfo, *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy) error) error { + cb func(kvdb.RTx, *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1) error) error { return nodeTraversal(nil, nodePub[:], c.db, cb) } @@ -3293,8 +3293,8 @@ func (c *ChannelGraph) ForEachNodeChannel(nodePub route.Vertex, // traversal. func (c *ChannelGraph) ForEachNodeChannelTx(tx kvdb.RTx, nodePub route.Vertex, cb func(kvdb.RTx, *models.ChannelEdgeInfo, - *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy) error) error { + *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1) error) error { return nodeTraversal(tx, nodePub[:], c.db, cb) } @@ -3373,13 +3373,13 @@ func computeEdgePolicyKeys(info *models.ChannelEdgeInfo) ([]byte, []byte) { // information for the channel itself is returned as well as two structs that // contain the routing policies for the channel in either direction. func (c *ChannelGraph) FetchChannelEdgesByOutpoint(op *wire.OutPoint) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy, error) { + *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1, error) { var ( edgeInfo *models.ChannelEdgeInfo - policy1 *models.ChannelEdgePolicy - policy2 *models.ChannelEdgePolicy + policy1 *models.ChannelEdgePolicy1 + policy2 *models.ChannelEdgePolicy1 ) err := kvdb.View(c.db, func(tx kvdb.RTx) error { @@ -3455,16 +3455,16 @@ func (c *ChannelGraph) FetchChannelEdgesByOutpoint(op *wire.OutPoint) ( // routing policies for the channel in either direction. // // ErrZombieEdge an be returned if the edge is currently marked as a zombie -// within the database. In this case, the ChannelEdgePolicy's will be nil, and +// within the database. In this case, the ChannelEdgePolicy1's will be nil, and // the ChannelEdgeInfo will only include the public keys of each node. func (c *ChannelGraph) FetchChannelEdgesByID(chanID uint64) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy, error) { + *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1, error) { var ( edgeInfo *models.ChannelEdgeInfo - policy1 *models.ChannelEdgePolicy - policy2 *models.ChannelEdgePolicy + policy1 *models.ChannelEdgePolicy1 + policy2 *models.ChannelEdgePolicy1 channelID [8]byte ) @@ -4390,7 +4390,7 @@ func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo, error) { return edgeInfo, nil } -func putChanEdgePolicy(edges kvdb.RwBucket, edge *models.ChannelEdgePolicy, +func putChanEdgePolicy(edges kvdb.RwBucket, edge *models.ChannelEdgePolicy1, from, to []byte) error { var edgeKey [33 + 8]byte @@ -4462,7 +4462,7 @@ func putChanEdgePolicy(edges kvdb.RwBucket, edge *models.ChannelEdgePolicy, } // updateEdgePolicyDisabledIndex is used to update the disabledEdgePolicyIndex -// bucket by either add a new disabled ChannelEdgePolicy or remove an existing +// bucket by either add a new disabled ChannelEdgePolicy1 or remove an existing // one. // The direction represents the direction of the edge and disabled is used for // deciding whether to remove or add an entry to the bucket. @@ -4511,7 +4511,7 @@ func putChanEdgePolicyUnknown(edges kvdb.RwBucket, channelID uint64, } func fetchChanEdgePolicy(edges kvdb.RBucket, chanID []byte, - nodePub []byte) (*models.ChannelEdgePolicy, error) { + nodePub []byte) (*models.ChannelEdgePolicy1, error) { var edgeKey [33 + 8]byte copy(edgeKey[:], nodePub) @@ -4544,7 +4544,7 @@ func fetchChanEdgePolicy(edges kvdb.RBucket, chanID []byte, } func fetchChanEdgePolicies(edgeIndex kvdb.RBucket, edges kvdb.RBucket, - chanID []byte) (*models.ChannelEdgePolicy, *models.ChannelEdgePolicy, + chanID []byte) (*models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { edgeInfo := edgeIndex.Get(chanID) @@ -4575,7 +4575,7 @@ func fetchChanEdgePolicies(edgeIndex kvdb.RBucket, edges kvdb.RBucket, return edge1, edge2, nil } -func serializeChanEdgePolicy(w io.Writer, edge *models.ChannelEdgePolicy, +func serializeChanEdgePolicy(w io.Writer, edge *models.ChannelEdgePolicy1, to []byte) error { err := wire.WriteVarBytes(w, 0, edge.SigBytes) @@ -4642,7 +4642,7 @@ func serializeChanEdgePolicy(w io.Writer, edge *models.ChannelEdgePolicy, return nil } -func deserializeChanEdgePolicy(r io.Reader) (*models.ChannelEdgePolicy, error) { +func deserializeChanEdgePolicy(r io.Reader) (*models.ChannelEdgePolicy1, error) { // Deserialize the policy. Note that in case an optional field is not // found, both an error and a populated policy object are returned. edge, deserializeErr := deserializeChanEdgePolicyRaw(r) @@ -4655,10 +4655,10 @@ func deserializeChanEdgePolicy(r io.Reader) (*models.ChannelEdgePolicy, error) { return edge, deserializeErr } -func deserializeChanEdgePolicyRaw(r io.Reader) (*models.ChannelEdgePolicy, +func deserializeChanEdgePolicyRaw(r io.Reader) (*models.ChannelEdgePolicy1, error) { - edge := &models.ChannelEdgePolicy{} + edge := &models.ChannelEdgePolicy1{} var err error edge.SigBytes, err = wire.ReadVarBytes(r, 0, 80, "sig") diff --git a/channeldb/graph_cache.go b/channeldb/graph_cache.go index 9bd2a82658..888e2dfa52 100644 --- a/channeldb/graph_cache.go +++ b/channeldb/graph_cache.go @@ -29,8 +29,8 @@ type GraphCacheNode interface { // to the caller. ForEachChannel(kvdb.RTx, func(kvdb.RTx, *models.ChannelEdgeInfo, - *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy) error) error + *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1) error) error } // DirectedChannel is a type that stores the channel information as seen from @@ -143,8 +143,8 @@ func (c *GraphCache) AddNode(tx kvdb.RTx, node GraphCacheNode) error { return node.ForEachChannel( tx, func(tx kvdb.RTx, info *models.ChannelEdgeInfo, - outPolicy *models.ChannelEdgePolicy, - inPolicy *models.ChannelEdgePolicy) error { + outPolicy *models.ChannelEdgePolicy1, + inPolicy *models.ChannelEdgePolicy1) error { c.AddChannel(info, outPolicy, inPolicy) @@ -157,8 +157,8 @@ func (c *GraphCache) AddNode(tx kvdb.RTx, node GraphCacheNode) error { // and policy 2 does not matter, the directionality is extracted from the info // and policy flags automatically. The policy will be set as the outgoing policy // on one node and the incoming policy on the peer's side. -func (c *GraphCache) AddChannel(info *models.ChannelEdgeInfo, - policy1 *models.ChannelEdgePolicy, policy2 *models.ChannelEdgePolicy) { +func (c *GraphCache) AddChannel(info *models.ChannelEdgeInfo, policy1, + policy2 *models.ChannelEdgePolicy1) { if info == nil { return @@ -220,7 +220,7 @@ func (c *GraphCache) updateOrAddEdge(node route.Vertex, edge *DirectedChannel) { // of the from and to node is not strictly important. But we assume that a // channel edge was added beforehand so that the directed channel struct already // exists in the cache. -func (c *GraphCache) UpdatePolicy(policy *models.ChannelEdgePolicy, fromNode, +func (c *GraphCache) UpdatePolicy(policy *models.ChannelEdgePolicy1, fromNode, toNode route.Vertex, edge1 bool) { // Extract inbound fee if possible and available. If there is a decoding diff --git a/channeldb/graph_cache_test.go b/channeldb/graph_cache_test.go index f7ed5cee60..e3ba3d67a4 100644 --- a/channeldb/graph_cache_test.go +++ b/channeldb/graph_cache_test.go @@ -30,8 +30,8 @@ type node struct { features *lnwire.FeatureVector edgeInfos []*models.ChannelEdgeInfo - outPolicies []*models.ChannelEdgePolicy - inPolicies []*models.ChannelEdgePolicy + outPolicies []*models.ChannelEdgePolicy1 + inPolicies []*models.ChannelEdgePolicy1 } func (n *node) PubKey() route.Vertex { @@ -42,8 +42,8 @@ func (n *node) Features() *lnwire.FeatureVector { } func (n *node) ForEachChannel(tx kvdb.RTx, - cb func(kvdb.RTx, *models.ChannelEdgeInfo, *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy) error) error { + cb func(kvdb.RTx, *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1) error) error { for idx := range n.edgeInfos { err := cb( @@ -71,7 +71,7 @@ func TestGraphCacheAddNode(t *testing.T) { channelFlagA, channelFlagB = 1, 0 } - outPolicy1 := &models.ChannelEdgePolicy{ + outPolicy1 := &models.ChannelEdgePolicy1{ ChannelID: 1000, ChannelFlags: lnwire.ChanUpdateChanFlags(channelFlagA), ToNode: nodeB, @@ -80,7 +80,7 @@ func TestGraphCacheAddNode(t *testing.T) { 253, 217, 3, 8, 0, 0, 0, 10, 0, 0, 0, 20, }, } - inPolicy1 := &models.ChannelEdgePolicy{ + inPolicy1 := &models.ChannelEdgePolicy1{ ChannelID: 1000, ChannelFlags: lnwire.ChanUpdateChanFlags(channelFlagB), ToNode: nodeA, @@ -95,8 +95,8 @@ func TestGraphCacheAddNode(t *testing.T) { NodeKey2Bytes: pubKey2, Capacity: 500, }}, - outPolicies: []*models.ChannelEdgePolicy{outPolicy1}, - inPolicies: []*models.ChannelEdgePolicy{inPolicy1}, + outPolicies: []*models.ChannelEdgePolicy1{outPolicy1}, + inPolicies: []*models.ChannelEdgePolicy1{inPolicy1}, } cache := NewGraphCache(10) require.NoError(t, cache.AddNode(nil, node)) @@ -153,7 +153,7 @@ func TestGraphCacheAddNode(t *testing.T) { runTest(pubKey2, pubKey1) } -func assertCachedPolicyEqual(t *testing.T, original *models.ChannelEdgePolicy, +func assertCachedPolicyEqual(t *testing.T, original *models.ChannelEdgePolicy1, cached *models.CachedEdgePolicy) { require.Equal(t, original.ChannelID, cached.ChannelID) diff --git a/channeldb/graph_test.go b/channeldb/graph_test.go index 39168a5ab0..30be2db442 100644 --- a/channeldb/graph_test.go +++ b/channeldb/graph_test.go @@ -619,8 +619,8 @@ func assertEdgeInfoEqual(t *testing.T, e1 *models.ChannelEdgeInfo, } func createChannelEdge(db kvdb.Backend, node1, node2 *LightningNode) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy) { + *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1) { var ( firstNode [33]byte @@ -662,7 +662,7 @@ func createChannelEdge(db kvdb.Backend, node1, node2 *LightningNode) ( copy(edgeInfo.BitcoinKey1Bytes[:], firstNode[:]) copy(edgeInfo.BitcoinKey2Bytes[:], secondNode[:]) - edge1 := &models.ChannelEdgePolicy{ + edge1 := &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), ChannelID: chanID, LastUpdate: time.Unix(433453, 0), @@ -676,7 +676,7 @@ func createChannelEdge(db kvdb.Backend, node1, node2 *LightningNode) ( ToNode: secondNode, ExtraOpaqueData: []byte{1, 0}, } - edge2 := &models.ChannelEdgePolicy{ + edge2 := &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), ChannelID: chanID, LastUpdate: time.Unix(124234, 0), @@ -899,7 +899,7 @@ func assertNoEdge(t *testing.T, g *ChannelGraph, chanID uint64) { } func assertEdgeWithPolicyInCache(t *testing.T, g *ChannelGraph, - e *models.ChannelEdgeInfo, p *models.ChannelEdgePolicy, policy1 bool) { + e *models.ChannelEdgeInfo, p *models.ChannelEdgePolicy1, policy1 bool) { // Check the internal state first. c1, ok := g.graphCache.nodeChannels[e.NodeKey1Bytes][e.ChannelID] @@ -975,16 +975,16 @@ func assertEdgeWithPolicyInCache(t *testing.T, g *ChannelGraph, } } -func randEdgePolicy(chanID uint64, db kvdb.Backend) *models.ChannelEdgePolicy { +func randEdgePolicy(chanID uint64, db kvdb.Backend) *models.ChannelEdgePolicy1 { update := prand.Int63() return newEdgePolicy(chanID, db, update) } func newEdgePolicy(chanID uint64, db kvdb.Backend, - updateTime int64) *models.ChannelEdgePolicy { + updateTime int64) *models.ChannelEdgePolicy1 { - return &models.ChannelEdgePolicy{ + return &models.ChannelEdgePolicy1{ ChannelID: chanID, LastUpdate: time.Unix(updateTime, 0), MessageFlags: 1, @@ -1042,8 +1042,8 @@ func TestGraphTraversal(t *testing.T) { // again if the map is empty that indicates that all edges have // properly been reached. err = graph.ForEachChannel(func(ei *models.ChannelEdgeInfo, - _ *models.ChannelEdgePolicy, - _ *models.ChannelEdgePolicy) error { + _ *models.ChannelEdgePolicy1, + _ *models.ChannelEdgePolicy1) error { delete(chanIndex, ei.ChannelID) return nil @@ -1057,7 +1057,7 @@ func TestGraphTraversal(t *testing.T) { firstNode, secondNode := nodeList[0], nodeList[1] err = graph.ForEachNodeChannel(firstNode.PubKeyBytes, func(_ kvdb.RTx, _ *models.ChannelEdgeInfo, outEdge, - inEdge *models.ChannelEdgePolicy) error { + inEdge *models.ChannelEdgePolicy1) error { // All channels between first and second node should // have fully (both sides) specified policies. @@ -1138,8 +1138,8 @@ func TestGraphTraversalCacheable(t *testing.T) { err := node.ForEachChannel( tx, func(tx kvdb.RTx, info *models.ChannelEdgeInfo, - policy *models.ChannelEdgePolicy, - policy2 *models.ChannelEdgePolicy) error { //nolint:lll + policy *models.ChannelEdgePolicy1, + policy2 *models.ChannelEdgePolicy1) error { //nolint:lll delete(chanIndex, info.ChannelID) return nil @@ -1322,8 +1322,8 @@ func assertPruneTip(t *testing.T, graph *ChannelGraph, blockHash *chainhash.Hash func assertNumChans(t *testing.T, graph *ChannelGraph, n int) { numChans := 0 if err := graph.ForEachChannel(func(*models.ChannelEdgeInfo, - *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy) error { + *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1) error { numChans++ return nil @@ -2439,7 +2439,7 @@ func TestFilterChannelRange(t *testing.T) { var updateTime = time.Unix(0, 0) if rand.Int31n(2) == 0 { updateTime = time.Unix(updateTimeSeed, 0) - err = graph.UpdateEdgePolicy(&models.ChannelEdgePolicy{ + err = graph.UpdateEdgePolicy(&models.ChannelEdgePolicy1{ ToNode: node.PubKeyBytes, ChannelFlags: chanFlags, ChannelID: chanID, @@ -2749,7 +2749,7 @@ func TestIncompleteChannelPolicies(t *testing.T) { calls := 0 err := graph.ForEachNodeChannel(node.PubKeyBytes, func(_ kvdb.RTx, _ *models.ChannelEdgeInfo, outEdge, - inEdge *models.ChannelEdgePolicy) error { + inEdge *models.ChannelEdgePolicy1) error { if !expectedOut && outEdge != nil { t.Fatalf("Expected no outgoing policy") @@ -3342,7 +3342,7 @@ func TestDisabledChannelIDs(t *testing.T) { } } -// TestEdgePolicyMissingMaxHtcl tests that if we find a ChannelEdgePolicy in +// TestEdgePolicyMissingMaxHtcl tests that if we find a ChannelEdgePolicy1 in // the DB that indicates that it should support the htlc_maximum_value_msat // field, but it is not part of the opaque data, then we'll handle it as it is // unknown. It also checks that we are correctly able to overwrite it when we @@ -3609,7 +3609,7 @@ func compareNodes(a, b *LightningNode) error { // compareEdgePolicies is used to compare two ChannelEdgePolices using // compareNodes, so as to exclude comparisons of the Nodes' Features struct. -func compareEdgePolicies(a, b *models.ChannelEdgePolicy) error { +func compareEdgePolicies(a, b *models.ChannelEdgePolicy1) error { if a.ChannelID != b.ChannelID { return fmt.Errorf("ChannelID doesn't match: expected %v, "+ "got %v", a.ChannelID, b.ChannelID) @@ -3701,7 +3701,7 @@ func TestLightningNodeSigVerification(t *testing.T) { // TestComputeFee tests fee calculation based on the outgoing amt. func TestComputeFee(t *testing.T) { var ( - policy = models.ChannelEdgePolicy{ + policy = models.ChannelEdgePolicy1{ FeeBaseMSat: 10000, FeeProportionalMillionths: 30000, } @@ -3829,7 +3829,7 @@ func TestBatchedUpdateEdgePolicy(t *testing.T) { errTimeout := errors.New("timeout adding batched channel") - updates := []*models.ChannelEdgePolicy{edge1, edge2} + updates := []*models.ChannelEdgePolicy1{edge1, edge2} errChan := make(chan error, len(updates)) @@ -3837,7 +3837,7 @@ func TestBatchedUpdateEdgePolicy(t *testing.T) { var wg sync.WaitGroup for _, update := range updates { wg.Add(1) - go func(update *models.ChannelEdgePolicy) { + go func(update *models.ChannelEdgePolicy1) { defer wg.Done() select { @@ -3887,8 +3887,8 @@ func BenchmarkForEachChannel(b *testing.B) { for _, n := range nodes { cb := func(tx kvdb.RTx, info *models.ChannelEdgeInfo, - policy *models.ChannelEdgePolicy, - policy2 *models.ChannelEdgePolicy) error { //nolint:lll + policy *models.ChannelEdgePolicy1, + policy2 *models.ChannelEdgePolicy1) error { //nolint:lll // We need to do something with // the data here, otherwise the @@ -3939,7 +3939,7 @@ func TestGraphCacheForEachNodeChannel(t *testing.T) { // Because of lexigraphical sorting and the usage of random node keys in // this test, we need to determine which edge belongs to node 1 at // runtime. - var edge1 *models.ChannelEdgePolicy + var edge1 *models.ChannelEdgePolicy1 if e1.ToNode == node2.PubKeyBytes { edge1 = e1 } else { diff --git a/channeldb/models/cached_edge_policy.go b/channeldb/models/cached_edge_policy.go index b770ec1fbe..89f9a98a0b 100644 --- a/channeldb/models/cached_edge_policy.go +++ b/channeldb/models/cached_edge_policy.go @@ -11,7 +11,7 @@ const ( ) // CachedEdgePolicy is a struct that only caches the information of a -// ChannelEdgePolicy that we actually use for pathfinding and therefore need to +// ChannelEdgePolicy1 that we actually use for pathfinding and therefore need to // store in the cache. type CachedEdgePolicy struct { // ChannelID is the unique channel ID for the channel. The first 3 @@ -72,7 +72,7 @@ func (c *CachedEdgePolicy) ComputeFee( } // NewCachedPolicy turns a full policy into a minimal one that can be cached. -func NewCachedPolicy(policy *ChannelEdgePolicy) *CachedEdgePolicy { +func NewCachedPolicy(policy *ChannelEdgePolicy1) *CachedEdgePolicy { return &CachedEdgePolicy{ ChannelID: policy.ChannelID, MessageFlags: policy.MessageFlags, diff --git a/channeldb/models/channel_edge_info.go b/channeldb/models/channel_edge_info.go index 78d612e667..973acbc6ec 100644 --- a/channeldb/models/channel_edge_info.go +++ b/channeldb/models/channel_edge_info.go @@ -15,7 +15,7 @@ import ( // unique attributes. Once an authenticated channel announcement has been // processed on the network, then an instance of ChannelEdgeInfo encapsulating // the channels attributes is stored. The other portions relevant to routing -// policy of a channel are stored within a ChannelEdgePolicy for each direction +// policy of a channel are stored within a ChannelEdgePolicy1 for each direction // of the channel. type ChannelEdgeInfo struct { // ChannelID is the unique channel ID for the channel. The first 3 diff --git a/channeldb/models/channel_edge_policy.go b/channeldb/models/channel_edge_policy.go index 322ce3cd09..c4db39d7a4 100644 --- a/channeldb/models/channel_edge_policy.go +++ b/channeldb/models/channel_edge_policy.go @@ -7,12 +7,12 @@ import ( "github.com/lightningnetwork/lnd/lnwire" ) -// ChannelEdgePolicy represents a *directed* edge within the channel graph. For +// ChannelEdgePolicy1 represents a *directed* edge within the channel graph. For // each channel in the database, there are two distinct edges: one for each // possible direction of travel along the channel. The edges themselves hold // information concerning fees, and minimum time-lock information which is // utilized during path finding. -type ChannelEdgePolicy struct { +type ChannelEdgePolicy1 struct { // 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. Do not set SigBytes directly, but @@ -78,7 +78,7 @@ type ChannelEdgePolicy struct { // // NOTE: By having this method to access an attribute, we ensure we only need // to fully deserialize the signature if absolutely necessary. -func (c *ChannelEdgePolicy) Signature() (*ecdsa.Signature, error) { +func (c *ChannelEdgePolicy1) Signature() (*ecdsa.Signature, error) { if c.sig != nil { return c.sig, nil } @@ -95,20 +95,20 @@ func (c *ChannelEdgePolicy) Signature() (*ecdsa.Signature, error) { // SetSigBytes updates the signature and invalidates the cached parsed // signature. -func (c *ChannelEdgePolicy) SetSigBytes(sig []byte) { +func (c *ChannelEdgePolicy1) SetSigBytes(sig []byte) { c.SigBytes = sig c.sig = nil } // IsDisabled determines whether the edge has the disabled bit set. -func (c *ChannelEdgePolicy) IsDisabled() bool { +func (c *ChannelEdgePolicy1) IsDisabled() bool { return c.ChannelFlags.IsDisabled() } // ComputeFee computes the fee to forward an HTLC of `amt` milli-satoshis over // the passed active payment channel. This value is currently computed as // specified in BOLT07, but will likely change in the near future. -func (c *ChannelEdgePolicy) ComputeFee( +func (c *ChannelEdgePolicy1) ComputeFee( amt lnwire.MilliSatoshi) lnwire.MilliSatoshi { return c.FeeBaseMSat + (amt*c.FeeProportionalMillionths)/feeRateParts diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 2fa6971108..b3cc8d2ede 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -566,7 +566,7 @@ type EdgeWithInfo struct { Info *models.ChannelEdgeInfo // Edge describes the policy in one direction of the channel. - Edge *models.ChannelEdgePolicy + Edge *models.ChannelEdgePolicy1 } // PropagateChanPolicyUpdate signals the AuthenticatedGossiper to perform the @@ -1628,7 +1628,7 @@ func (d *AuthenticatedGossiper) retransmitStaleAnns(now time.Time) error { // within the prune interval or re-broadcast interval. type updateTuple struct { info *models.ChannelEdgeInfo - edge *models.ChannelEdgePolicy + edge *models.ChannelEdgePolicy1 } var ( @@ -1638,7 +1638,7 @@ func (d *AuthenticatedGossiper) retransmitStaleAnns(now time.Time) error { err := d.cfg.Graph.ForAllOutgoingChannels(func( _ kvdb.RTx, info *models.ChannelEdgeInfo, - edge *models.ChannelEdgePolicy) error { + edge *models.ChannelEdgePolicy1) error { // If there's no auth proof attached to this edge, it means // that it is a private channel not meant to be announced to @@ -2198,7 +2198,7 @@ func (d *AuthenticatedGossiper) isMsgStale(msg lnwire.Message) bool { // Otherwise, we'll retrieve the correct policy that we // currently have stored within our graph to check if this // message is stale by comparing its timestamp. - var p *models.ChannelEdgePolicy + var p *models.ChannelEdgePolicy1 if msg.ChannelFlags&lnwire.ChanUpdateDirection == 0 { p = p1 } else { @@ -2224,7 +2224,7 @@ func (d *AuthenticatedGossiper) isMsgStale(msg lnwire.Message) bool { // updateChannel creates a new fully signed update for the channel, and updates // the underlying graph with the new state. func (d *AuthenticatedGossiper) updateChannel(info *models.ChannelEdgeInfo, - edge *models.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement1, + edge *models.ChannelEdgePolicy1) (*lnwire.ChannelAnnouncement1, *lnwire.ChannelUpdate1, error) { // Parse the unsigned edge into a channel update. @@ -2314,7 +2314,7 @@ func (d *AuthenticatedGossiper) SyncManager() *SyncManager { // keep-alive update based on the previous channel update processed for the same // direction. func IsKeepAliveUpdate(update *lnwire.ChannelUpdate1, - prev *models.ChannelEdgePolicy) bool { + prev *models.ChannelEdgePolicy1) bool { // Both updates should be from the same direction. if update.ChannelFlags&lnwire.ChanUpdateDirection != @@ -3023,7 +3023,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // being updated. var ( pubKey *btcec.PublicKey - edgeToUpdate *models.ChannelEdgePolicy + edgeToUpdate *models.ChannelEdgePolicy1 ) direction := upd.ChannelFlags & lnwire.ChanUpdateDirection switch direction { @@ -3112,7 +3112,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // different alias. This might mean that SigBytes is incorrect as it // 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{ + update := &models.ChannelEdgePolicy1{ SigBytes: upd.Signature.ToSignatureBytes(), ChannelID: chanInfo.ChannelID, LastUpdate: timestamp, diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index cf1d12fb16..1aa44591ee 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -94,7 +94,7 @@ type mockGraphSource struct { mu sync.Mutex nodes []channeldb.LightningNode infos map[uint64]models.ChannelEdgeInfo - edges map[uint64][]models.ChannelEdgePolicy + edges map[uint64][]models.ChannelEdgePolicy1 zombies map[uint64][][33]byte chansToReject map[uint64]struct{} addEdgeErrCode fn.Option[graph.ErrorCode] @@ -104,7 +104,7 @@ func newMockRouter(height uint32) *mockGraphSource { return &mockGraphSource{ bestHeight: height, infos: make(map[uint64]models.ChannelEdgeInfo), - edges: make(map[uint64][]models.ChannelEdgePolicy), + edges: make(map[uint64][]models.ChannelEdgePolicy1), zombies: make(map[uint64][][33]byte), chansToReject: make(map[uint64]struct{}), } @@ -161,14 +161,14 @@ func (r *mockGraphSource) queueValidationFail(chanID uint64) { r.chansToReject[chanID] = struct{}{} } -func (r *mockGraphSource) UpdateEdge(edge *models.ChannelEdgePolicy, +func (r *mockGraphSource) UpdateEdge(edge *models.ChannelEdgePolicy1, _ ...batch.SchedulerOption) error { r.mu.Lock() defer r.mu.Unlock() if len(r.edges[edge.ChannelID]) == 0 { - r.edges[edge.ChannelID] = make([]models.ChannelEdgePolicy, 2) + r.edges[edge.ChannelID] = make([]models.ChannelEdgePolicy1, 2) } if edge.ChannelFlags&lnwire.ChanUpdateDirection == 0 { @@ -208,7 +208,7 @@ func (r *mockGraphSource) ForEachNode(func(node *channeldb.LightningNode) error) func (r *mockGraphSource) ForAllOutgoingChannels(cb func(tx kvdb.RTx, i *models.ChannelEdgeInfo, - c *models.ChannelEdgePolicy) error) error { + c *models.ChannelEdgePolicy1) error) error { r.mu.Lock() defer r.mu.Unlock() @@ -240,8 +240,8 @@ func (r *mockGraphSource) ForAllOutgoingChannels(cb func(tx kvdb.RTx, func (r *mockGraphSource) GetChannelByID(chanID lnwire.ShortChannelID) ( *models.ChannelEdgeInfo, - *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy, error) { + *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1, error) { r.mu.Lock() defer r.mu.Unlock() @@ -265,13 +265,13 @@ func (r *mockGraphSource) GetChannelByID(chanID lnwire.ShortChannelID) ( return &chanInfo, nil, nil, nil } - var edge1 *models.ChannelEdgePolicy - if !reflect.DeepEqual(edges[0], models.ChannelEdgePolicy{}) { + var edge1 *models.ChannelEdgePolicy1 + if !reflect.DeepEqual(edges[0], models.ChannelEdgePolicy1{}) { edge1 = &edges[0] } - var edge2 *models.ChannelEdgePolicy - if !reflect.DeepEqual(edges[1], models.ChannelEdgePolicy{}) { + var edge2 *models.ChannelEdgePolicy1 + if !reflect.DeepEqual(edges[1], models.ChannelEdgePolicy1{}) { edge2 = &edges[1] } @@ -371,12 +371,12 @@ func (r *mockGraphSource) IsStaleEdgePolicy(chanID lnwire.ShortChannelID, switch { case flags&lnwire.ChanUpdateDirection == 0 && - !reflect.DeepEqual(edges[0], models.ChannelEdgePolicy{}): + !reflect.DeepEqual(edges[0], models.ChannelEdgePolicy1{}): return !timestamp.After(edges[0].LastUpdate) case flags&lnwire.ChanUpdateDirection == 1 && - !reflect.DeepEqual(edges[1], models.ChannelEdgePolicy{}): + !reflect.DeepEqual(edges[1], models.ChannelEdgePolicy1{}): return !timestamp.After(edges[1].LastUpdate) @@ -2508,7 +2508,7 @@ func TestReceiveRemoteChannelUpdateFirst(t *testing.T) { t.Fatalf("remote update was not processed") } - // Check that the ChannelEdgePolicy was added to the graph. + // Check that the ChannelEdgePolicy1 was added to the graph. chanInfo, e1, e2, err = ctx.router.GetChannelByID( batch.chanUpdAnn1.ShortChannelID, ) @@ -3484,7 +3484,7 @@ out: err = ctx.router.ForAllOutgoingChannels(func( _ kvdb.RTx, info *models.ChannelEdgeInfo, - edge *models.ChannelEdgePolicy) error { + edge *models.ChannelEdgePolicy1) error { edge.TimeLockDelta = uint16(newTimeLockDelta) edgesToUpdate = append(edgesToUpdate, EdgeWithInfo{ diff --git a/funding/manager.go b/funding/manager.go index 1fa90c6932..7299ba059b 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -533,7 +533,7 @@ type Config struct { // DeleteAliasEdge allows the Manager to delete an alias channel edge // from the graph. It also returns our local to-be-deleted policy. DeleteAliasEdge func(scid lnwire.ShortChannelID) ( - *models.ChannelEdgePolicy, error) + *models.ChannelEdgePolicy1, error) // AliasManager is an implementation of the aliasHandler interface that // abstracts away the handling of many alias functions. @@ -3541,7 +3541,7 @@ func (f *Manager) extractAnnounceParams(c *channeldb.OpenChannel) ( func (f *Manager) addToGraph(completeChan *channeldb.OpenChannel, shortChanID *lnwire.ShortChannelID, peerAlias *lnwire.ShortChannelID, - ourPolicy *models.ChannelEdgePolicy) error { + ourPolicy *models.ChannelEdgePolicy1) error { chanID := lnwire.NewChanIDFromOutPoint(completeChan.FundingOutpoint) @@ -4308,7 +4308,7 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey *btcec.PublicKey, localFundingKey *keychain.KeyDescriptor, remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID, chanID lnwire.ChannelID, fwdMinHTLC, fwdMaxHTLC lnwire.MilliSatoshi, - ourPolicy *models.ChannelEdgePolicy, + ourPolicy *models.ChannelEdgePolicy1, chanType channeldb.ChannelType) (*chanAnnouncement, error) { chainHash := *f.cfg.Wallet.Cfg.NetParams.GenesisHash diff --git a/funding/manager_test.go b/funding/manager_test.go index dbe6353770..6876ba6874 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -554,7 +554,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey, OpenChannelPredicate: chainedAcceptor, NotifyPendingOpenChannelEvent: evt.NotifyPendingOpenChannelEvent, DeleteAliasEdge: func(scid lnwire.ShortChannelID) ( - *models.ChannelEdgePolicy, error) { + *models.ChannelEdgePolicy1, error) { return nil, nil }, diff --git a/graph/builder.go b/graph/builder.go index 2d24395f55..99ab386b00 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -149,7 +149,7 @@ type Builder struct { ntfnClientUpdates chan *topologyClientUpdate // channelEdgeMtx is a mutex we use to make sure we process only one - // ChannelEdgePolicy at a time for a given channelID, to ensure + // ChannelEdgePolicy1 at a time for a given channelID, to ensure // consistency between the various database accesses. channelEdgeMtx *multimutex.Mutex[uint64] @@ -485,7 +485,7 @@ func (b *Builder) syncGraphWithChain() error { // boolean is that of node 2, and the final boolean is true if the channel // is considered a zombie. func (b *Builder) isZombieChannel(e1, - e2 *models.ChannelEdgePolicy) (bool, bool, bool) { + e2 *models.ChannelEdgePolicy1) (bool, bool, bool) { chanExpiry := b.cfg.ChannelPruneExpiry @@ -549,7 +549,7 @@ func (b *Builder) pruneZombieChans() error { // First, we'll collect all the channels which are eligible for garbage // collection due to being zombies. filterPruneChans := func(info *models.ChannelEdgeInfo, - e1, e2 *models.ChannelEdgePolicy) error { + e1, e2 *models.ChannelEdgePolicy1) error { // Exit early in case this channel is already marked to be // pruned @@ -1358,8 +1358,8 @@ func (b *Builder) processUpdate(msg interface{}, "view: %v", err) } - case *models.ChannelEdgePolicy: - log.Debugf("Received ChannelEdgePolicy for channel %v", + case *models.ChannelEdgePolicy1: + log.Debugf("Received ChannelEdgePolicy1 for channel %v", msg.ChannelID) // We make sure to hold the mutex for this channel ID, @@ -1491,7 +1491,7 @@ func (b *Builder) ApplyChannelUpdate(msg *lnwire.ChannelUpdate1) bool { return false } - err = b.UpdateEdge(&models.ChannelEdgePolicy{ + err = b.UpdateEdge(&models.ChannelEdgePolicy1{ SigBytes: msg.Signature.ToSignatureBytes(), ChannelID: msg.ShortChannelID.ToUint64(), LastUpdate: time.Unix(int64(msg.Timestamp), 0), @@ -1570,7 +1570,7 @@ func (b *Builder) AddEdge(edge *models.ChannelEdgeInfo, // considered as not fully constructed. // // NOTE: This method is part of the ChannelGraphSource interface. -func (b *Builder) UpdateEdge(update *models.ChannelEdgePolicy, +func (b *Builder) UpdateEdge(update *models.ChannelEdgePolicy1, op ...batch.SchedulerOption) error { rMsg := &routingMsg{ @@ -1612,8 +1612,8 @@ func (b *Builder) SyncedHeight() uint32 { // NOTE: This method is part of the ChannelGraphSource interface. func (b *Builder) GetChannelByID(chanID lnwire.ShortChannelID) ( *models.ChannelEdgeInfo, - *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy, error) { + *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1, error) { return b.cfg.Graph.FetchChannelEdgesByID(chanID.ToUint64()) } @@ -1646,12 +1646,12 @@ func (b *Builder) ForEachNode( // // NOTE: This method is part of the ChannelGraphSource interface. func (b *Builder) ForAllOutgoingChannels(cb func(kvdb.RTx, - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy) error) error { + *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1) error) error { return b.cfg.Graph.ForEachNodeChannel(b.cfg.SelfNode, func(tx kvdb.RTx, c *models.ChannelEdgeInfo, - e *models.ChannelEdgePolicy, - _ *models.ChannelEdgePolicy) error { + e *models.ChannelEdgePolicy1, + _ *models.ChannelEdgePolicy1) error { if e == nil { return fmt.Errorf("channel from self node " + diff --git a/graph/builder_test.go b/graph/builder_test.go index 650ef62f19..a8b94ee391 100644 --- a/graph/builder_test.go +++ b/graph/builder_test.go @@ -154,7 +154,7 @@ func TestIgnoreChannelEdgePolicyForUnknownChannel(t *testing.T) { BitcoinKey2Bytes: pub2, AuthProof: nil, } - edgePolicy := &models.ChannelEdgePolicy{ + edgePolicy := &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, LastUpdate: testTime, @@ -1162,7 +1162,7 @@ func TestIsStaleEdgePolicy(t *testing.T) { } // We'll also add two edge policies, one for each direction. - edgePolicy := &models.ChannelEdgePolicy{ + edgePolicy := &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, LastUpdate: updateTimeStamp, @@ -1176,7 +1176,7 @@ func TestIsStaleEdgePolicy(t *testing.T) { t.Fatalf("unable to update edge policy: %v", err) } - edgePolicy = &models.ChannelEdgePolicy{ + edgePolicy = &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, LastUpdate: updateTimeStamp, @@ -1607,7 +1607,7 @@ func parseTestGraph(t *testing.T, useCache bool, path string) ( targetNode = edgeInfo.NodeKey2Bytes } - edgePolicy := &models.ChannelEdgePolicy{ + edgePolicy := &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), MessageFlags: lnwire.ChanUpdateMsgFlags( edge.MessageFlags, @@ -1987,7 +1987,7 @@ func createTestGraphFromChannels(t *testing.T, useCache bool, channelFlags |= lnwire.ChanUpdateDisabled } - edgePolicy := &models.ChannelEdgePolicy{ + edgePolicy := &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), MessageFlags: msgFlags, ChannelFlags: channelFlags, @@ -2018,7 +2018,7 @@ func createTestGraphFromChannels(t *testing.T, useCache bool, } channelFlags |= lnwire.ChanUpdateDirection - edgePolicy := &models.ChannelEdgePolicy{ + edgePolicy := &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), MessageFlags: msgFlags, ChannelFlags: channelFlags, diff --git a/graph/interfaces.go b/graph/interfaces.go index 5f2eb218a1..3408b366a5 100644 --- a/graph/interfaces.go +++ b/graph/interfaces.go @@ -39,7 +39,7 @@ type ChannelGraphSource interface { // UpdateEdge is used to update edge information, without this message // edge considered as not fully constructed. - UpdateEdge(policy *models.ChannelEdgePolicy, + UpdateEdge(policy *models.ChannelEdgePolicy1, op ...batch.SchedulerOption) error // IsStaleNode returns true if the graph source has a node announcement @@ -71,7 +71,7 @@ type ChannelGraphSource interface { // star-graph. ForAllOutgoingChannels(cb func(tx kvdb.RTx, c *models.ChannelEdgeInfo, - e *models.ChannelEdgePolicy) error) error + e *models.ChannelEdgePolicy1) error) error // CurrentBlockHeight returns the block height from POV of the router // subsystem. @@ -79,8 +79,8 @@ type ChannelGraphSource interface { // GetChannelByID return the channel by the channel id. GetChannelByID(chanID lnwire.ShortChannelID) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy, error) + *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1, error) // FetchLightningNode attempts to look up a target node by its identity // public key. channeldb.ErrGraphNodeNotFound is returned if the node @@ -188,11 +188,11 @@ type DB interface { // either direction. // // ErrZombieEdge an be returned if the edge is currently marked as a - // zombie within the database. In this case, the ChannelEdgePolicy's + // zombie within the database. In this case, the ChannelEdgePolicy1's // will be nil, and the ChannelEdgeInfo will only include the public // keys of each node. FetchChannelEdgesByID(chanID uint64) (*models.ChannelEdgeInfo, - *models.ChannelEdgePolicy, *models.ChannelEdgePolicy, error) + *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) // AddLightningNode adds a vertex/node to the graph database. If the // node is not in the database from before, this will add a new, @@ -220,13 +220,13 @@ type DB interface { // UpdateEdgePolicy updates the edge routing policy for a single // directed edge within the database for the referenced channel. The - // `flags` attribute within the ChannelEdgePolicy determines which of + // `flags` attribute within the ChannelEdgePolicy1 determines which of // the directed edges are being updated. If the flag is 1, then the // first node's information is being updated, otherwise it's the second // node's information. The node ordering is determined by the // lexicographical ordering of the identity public keys of the nodes on // either side of the channel. - UpdateEdgePolicy(edge *models.ChannelEdgePolicy, + UpdateEdgePolicy(edge *models.ChannelEdgePolicy1, op ...batch.SchedulerOption) error // HasLightningNode determines if the graph has a vertex identified by @@ -259,8 +259,8 @@ type DB interface { // Unknown policies are passed into the callback as nil values. ForEachNodeChannel(nodePub route.Vertex, cb func(kvdb.RTx, *models.ChannelEdgeInfo, - *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy) error) error + *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1) error) error // UpdateChannelEdge retrieves and update edge of the graph database. // Method only reserved for updating an edge info after its already been diff --git a/graph/notifications.go b/graph/notifications.go index 14ea3d127d..2873a08b3c 100644 --- a/graph/notifications.go +++ b/graph/notifications.go @@ -342,7 +342,7 @@ func addToTopologyChange(graph DB, update *TopologyChange, // Any new ChannelUpdateAnnouncements will generate a corresponding // ChannelEdgeUpdate notification. - case *models.ChannelEdgePolicy: + case *models.ChannelEdgePolicy1: // We'll need to fetch the edge's information from the database // in order to get the information concerning which nodes are // being connected. diff --git a/graph/notifications_test.go b/graph/notifications_test.go index c6f4855b63..34bbd54238 100644 --- a/graph/notifications_test.go +++ b/graph/notifications_test.go @@ -99,7 +99,7 @@ func createTestNode(t *testing.T) *channeldb.LightningNode { } func randEdgePolicy(chanID *lnwire.ShortChannelID, - node *channeldb.LightningNode) (*models.ChannelEdgePolicy, error) { + node *channeldb.LightningNode) (*models.ChannelEdgePolicy1, error) { InboundFee := models.InboundFee{ Base: prand.Int31() * -1, @@ -112,7 +112,7 @@ func randEdgePolicy(chanID *lnwire.ShortChannelID, return nil, err } - return &models.ChannelEdgePolicy{ + return &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), ChannelID: chanID.ToUint64(), LastUpdate: time.Unix(int64(prand.Int31()), 0), @@ -507,7 +507,7 @@ func TestEdgeUpdateNotification(t *testing.T) { } assertEdgeCorrect := func(t *testing.T, edgeUpdate *ChannelEdgeUpdate, - edgeAnn *models.ChannelEdgePolicy) { + edgeAnn *models.ChannelEdgePolicy1) { if edgeUpdate.ChanID != edgeAnn.ChannelID { t.Fatalf("channel ID of edge doesn't match: "+ diff --git a/graph/validation_barrier.go b/graph/validation_barrier.go index 98d910d899..513fb28dea 100644 --- a/graph/validation_barrier.go +++ b/graph/validation_barrier.go @@ -144,7 +144,7 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) { // These other types don't have any dependants, so no further // initialization needs to be done beyond just occupying a job slot. - case *models.ChannelEdgePolicy: + case *models.ChannelEdgePolicy1: return case *lnwire.ChannelUpdate1: return @@ -188,11 +188,11 @@ func (v *ValidationBarrier) WaitForDependants(job interface{}) error { switch msg := job.(type) { // Any ChannelUpdate or NodeAnnouncement jobs will need to wait on the // completion of any active ChannelAnnouncement jobs related to them. - case *models.ChannelEdgePolicy: + case *models.ChannelEdgePolicy1: shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID) signals, ok = v.chanEdgeDependencies[shortID] - jobDesc = fmt.Sprintf("job=lnwire.ChannelEdgePolicy, scid=%v", + jobDesc = fmt.Sprintf("job=lnwire.ChannelEdgePolicy1, scid=%v", msg.ChannelID) case *channeldb.LightningNode: @@ -297,7 +297,7 @@ func (v *ValidationBarrier) SignalDependants(job interface{}, allow bool) { delete(v.nodeAnnDependencies, route.Vertex(msg.NodeID)) case *lnwire.ChannelUpdate1: delete(v.chanEdgeDependencies, msg.ShortChannelID) - case *models.ChannelEdgePolicy: + case *models.ChannelEdgePolicy1: shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID) delete(v.chanEdgeDependencies, shortID) diff --git a/lnrpc/devrpc/dev_server.go b/lnrpc/devrpc/dev_server.go index 662c0d08d9..07c2423169 100644 --- a/lnrpc/devrpc/dev_server.go +++ b/lnrpc/devrpc/dev_server.go @@ -289,8 +289,8 @@ func (s *Server) ImportGraph(ctx context.Context, rpcEdge.ChanPoint, err) } - makePolicy := func(rpcPolicy *lnrpc.RoutingPolicy) *models.ChannelEdgePolicy { //nolint:lll - policy := &models.ChannelEdgePolicy{ + makePolicy := func(rpcPolicy *lnrpc.RoutingPolicy) *models.ChannelEdgePolicy1 { //nolint:lll + policy := &models.ChannelEdgePolicy1{ ChannelID: rpcEdge.ChannelId, LastUpdate: time.Unix( int64(rpcPolicy.LastUpdate), 0, diff --git a/lnrpc/invoicesrpc/addinvoice.go b/lnrpc/invoicesrpc/addinvoice.go index df274f2da7..25f2a272b5 100644 --- a/lnrpc/invoicesrpc/addinvoice.go +++ b/lnrpc/invoicesrpc/addinvoice.go @@ -624,7 +624,7 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig, // chanCanBeHopHint returns true if the target channel is eligible to be a hop // hint. func chanCanBeHopHint(channel *HopHintInfo, cfg *SelectHopHintsCfg) ( - *models.ChannelEdgePolicy, bool) { + *models.ChannelEdgePolicy1, bool) { // Since we're only interested in our private channels, we'll skip // public ones. @@ -679,7 +679,7 @@ func chanCanBeHopHint(channel *HopHintInfo, cfg *SelectHopHintsCfg) ( // Now, we'll need to determine which is the correct policy for HTLCs // being sent from the remote node. - var remotePolicy *models.ChannelEdgePolicy + var remotePolicy *models.ChannelEdgePolicy1 if bytes.Equal(remotePub[:], info.NodeKey1Bytes[:]) { remotePolicy = p1 } else { @@ -737,9 +737,9 @@ func newHopHintInfo(c *channeldb.OpenChannel, isActive bool) *HopHintInfo { } // newHopHint returns a new hop hint using the relevant data from a hopHintInfo -// and a ChannelEdgePolicy. +// and a ChannelEdgePolicy1. func newHopHint(hopHintInfo *HopHintInfo, - chanPolicy *models.ChannelEdgePolicy) zpay32.HopHint { + chanPolicy *models.ChannelEdgePolicy1) zpay32.HopHint { return zpay32.HopHint{ NodeID: hopHintInfo.RemotePubkey, @@ -763,7 +763,7 @@ type SelectHopHintsCfg struct { // FetchChannelEdgesByID attempts to lookup the two directed edges for // the channel identified by the channel ID. FetchChannelEdgesByID func(chanID uint64) (*models.ChannelEdgeInfo, - *models.ChannelEdgePolicy, *models.ChannelEdgePolicy, + *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) // GetAlias allows the peer's alias SCID to be retrieved for private diff --git a/lnrpc/invoicesrpc/addinvoice_test.go b/lnrpc/invoicesrpc/addinvoice_test.go index 76a529f8c6..5d4fd7e0df 100644 --- a/lnrpc/invoicesrpc/addinvoice_test.go +++ b/lnrpc/invoicesrpc/addinvoice_test.go @@ -67,8 +67,8 @@ func (h *hopHintsConfigMock) FetchAllChannels() ([]*channeldb.OpenChannel, // FetchChannelEdgesByID attempts to lookup the two directed edges for // the channel identified by the channel ID. func (h *hopHintsConfigMock) FetchChannelEdgesByID(chanID uint64) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy, error) { + *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1, error) { args := h.Mock.Called(chanID) @@ -83,10 +83,10 @@ func (h *hopHintsConfigMock) FetchChannelEdgesByID(chanID uint64) ( edgeInfo, ok := args.Get(0).(*models.ChannelEdgeInfo) require.True(h.t, ok) - policy1, ok := args.Get(1).(*models.ChannelEdgePolicy) + policy1, ok := args.Get(1).(*models.ChannelEdgePolicy1) require.True(h.t, ok) - policy2, ok := args.Get(2).(*models.ChannelEdgePolicy) + policy2, ok := args.Get(2).(*models.ChannelEdgePolicy1) require.True(h.t, ok) return edgeInfo, policy1, policy2, err @@ -227,8 +227,8 @@ var shouldIncludeChannelTestCases = []struct { "FetchChannelEdgesByID", mock.Anything, ).Once().Return( &models.ChannelEdgeInfo{}, - &models.ChannelEdgePolicy{}, - &models.ChannelEdgePolicy{}, nil, + &models.ChannelEdgePolicy1{}, + &models.ChannelEdgePolicy1{}, nil, ) h.Mock.On( @@ -265,8 +265,8 @@ var shouldIncludeChannelTestCases = []struct { "FetchChannelEdgesByID", mock.Anything, ).Once().Return( &models.ChannelEdgeInfo{}, - &models.ChannelEdgePolicy{}, - &models.ChannelEdgePolicy{}, nil, + &models.ChannelEdgePolicy1{}, + &models.ChannelEdgePolicy1{}, nil, ) alias := lnwire.ShortChannelID{TxPosition: 5} h.Mock.On( @@ -308,12 +308,12 @@ var shouldIncludeChannelTestCases = []struct { &models.ChannelEdgeInfo{ NodeKey1Bytes: selectedPolicy, }, - &models.ChannelEdgePolicy{ + &models.ChannelEdgePolicy1{ FeeBaseMSat: 1000, FeeProportionalMillionths: 20, TimeLockDelta: 13, }, - &models.ChannelEdgePolicy{}, + &models.ChannelEdgePolicy1{}, nil, ) }, @@ -354,8 +354,8 @@ var shouldIncludeChannelTestCases = []struct { "FetchChannelEdgesByID", mock.Anything, ).Once().Return( &models.ChannelEdgeInfo{}, - &models.ChannelEdgePolicy{}, - &models.ChannelEdgePolicy{ + &models.ChannelEdgePolicy1{}, + &models.ChannelEdgePolicy1{ FeeBaseMSat: 1000, FeeProportionalMillionths: 20, TimeLockDelta: 13, @@ -399,8 +399,8 @@ var shouldIncludeChannelTestCases = []struct { "FetchChannelEdgesByID", mock.Anything, ).Once().Return( &models.ChannelEdgeInfo{}, - &models.ChannelEdgePolicy{}, - &models.ChannelEdgePolicy{ + &models.ChannelEdgePolicy1{}, + &models.ChannelEdgePolicy1{ FeeBaseMSat: 1000, FeeProportionalMillionths: 20, TimeLockDelta: 13, @@ -566,8 +566,8 @@ var populateHopHintsTestCases = []struct { "FetchChannelEdgesByID", mock.Anything, ).Once().Return( &models.ChannelEdgeInfo{}, - &models.ChannelEdgePolicy{}, - &models.ChannelEdgePolicy{}, nil, + &models.ChannelEdgePolicy1{}, + &models.ChannelEdgePolicy1{}, nil, ) }, maxHopHints: 1, @@ -616,8 +616,8 @@ var populateHopHintsTestCases = []struct { "FetchChannelEdgesByID", mock.Anything, ).Once().Return( &models.ChannelEdgeInfo{}, - &models.ChannelEdgePolicy{}, - &models.ChannelEdgePolicy{}, nil, + &models.ChannelEdgePolicy1{}, + &models.ChannelEdgePolicy1{}, nil, ) }, maxHopHints: 10, @@ -667,8 +667,8 @@ var populateHopHintsTestCases = []struct { "FetchChannelEdgesByID", mock.Anything, ).Once().Return( &models.ChannelEdgeInfo{}, - &models.ChannelEdgePolicy{}, - &models.ChannelEdgePolicy{}, nil, + &models.ChannelEdgePolicy1{}, + &models.ChannelEdgePolicy1{}, nil, ) }, maxHopHints: 1, @@ -700,8 +700,8 @@ var populateHopHintsTestCases = []struct { "FetchChannelEdgesByID", mock.Anything, ).Once().Return( &models.ChannelEdgeInfo{}, - &models.ChannelEdgePolicy{}, - &models.ChannelEdgePolicy{}, nil, + &models.ChannelEdgePolicy1{}, + &models.ChannelEdgePolicy1{}, nil, ) // Prepare the mock for the second channel. @@ -717,8 +717,8 @@ var populateHopHintsTestCases = []struct { "FetchChannelEdgesByID", mock.Anything, ).Once().Return( &models.ChannelEdgeInfo{}, - &models.ChannelEdgePolicy{}, - &models.ChannelEdgePolicy{}, nil, + &models.ChannelEdgePolicy1{}, + &models.ChannelEdgePolicy1{}, nil, ) }, maxHopHints: 10, @@ -754,8 +754,8 @@ var populateHopHintsTestCases = []struct { "FetchChannelEdgesByID", mock.Anything, ).Once().Return( &models.ChannelEdgeInfo{}, - &models.ChannelEdgePolicy{}, - &models.ChannelEdgePolicy{}, nil, + &models.ChannelEdgePolicy1{}, + &models.ChannelEdgePolicy1{}, nil, ) // Prepare the mock for the second channel. @@ -771,8 +771,8 @@ var populateHopHintsTestCases = []struct { "FetchChannelEdgesByID", mock.Anything, ).Once().Return( &models.ChannelEdgeInfo{}, - &models.ChannelEdgePolicy{}, - &models.ChannelEdgePolicy{}, nil, + &models.ChannelEdgePolicy1{}, + &models.ChannelEdgePolicy1{}, nil, ) }, maxHopHints: 10, @@ -809,8 +809,8 @@ var populateHopHintsTestCases = []struct { "FetchChannelEdgesByID", mock.Anything, ).Once().Return( &models.ChannelEdgeInfo{}, - &models.ChannelEdgePolicy{}, - &models.ChannelEdgePolicy{}, nil, + &models.ChannelEdgePolicy1{}, + &models.ChannelEdgePolicy1{}, nil, ) }, maxHopHints: 1, diff --git a/netann/chan_status_manager_test.go b/netann/chan_status_manager_test.go index c709a95f27..46e1939fed 100644 --- a/netann/chan_status_manager_test.go +++ b/netann/chan_status_manager_test.go @@ -67,7 +67,7 @@ func createChannel(t *testing.T) *channeldb.OpenChannel { // update will be created with the disabled bit set if startEnabled is false. func createEdgePolicies(t *testing.T, channel *channeldb.OpenChannel, pubkey *btcec.PublicKey, startEnabled bool) (*models.ChannelEdgeInfo, - *models.ChannelEdgePolicy, *models.ChannelEdgePolicy) { + *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) { var ( pubkey1 [33]byte @@ -104,13 +104,13 @@ func createEdgePolicies(t *testing.T, channel *channeldb.OpenChannel, NodeKey1Bytes: pubkey1, NodeKey2Bytes: pubkey2, }, - &models.ChannelEdgePolicy{ + &models.ChannelEdgePolicy1{ ChannelID: channel.ShortChanID().ToUint64(), ChannelFlags: dir1, LastUpdate: time.Now(), SigBytes: testSigBytes, }, - &models.ChannelEdgePolicy{ + &models.ChannelEdgePolicy1{ ChannelID: channel.ShortChanID().ToUint64(), ChannelFlags: dir2, LastUpdate: time.Now(), @@ -122,8 +122,8 @@ type mockGraph struct { mu sync.Mutex channels []*channeldb.OpenChannel chanInfos map[wire.OutPoint]*models.ChannelEdgeInfo - chanPols1 map[wire.OutPoint]*models.ChannelEdgePolicy - chanPols2 map[wire.OutPoint]*models.ChannelEdgePolicy + chanPols1 map[wire.OutPoint]*models.ChannelEdgePolicy1 + chanPols2 map[wire.OutPoint]*models.ChannelEdgePolicy1 sidToCid map[lnwire.ShortChannelID]wire.OutPoint updates chan *lnwire.ChannelUpdate1 @@ -135,8 +135,8 @@ func newMockGraph(t *testing.T, numChannels int, g := &mockGraph{ channels: make([]*channeldb.OpenChannel, 0, numChannels), chanInfos: make(map[wire.OutPoint]*models.ChannelEdgeInfo), - chanPols1: make(map[wire.OutPoint]*models.ChannelEdgePolicy), - chanPols2: make(map[wire.OutPoint]*models.ChannelEdgePolicy), + chanPols1: make(map[wire.OutPoint]*models.ChannelEdgePolicy1), + chanPols2: make(map[wire.OutPoint]*models.ChannelEdgePolicy1), sidToCid: make(map[lnwire.ShortChannelID]wire.OutPoint), updates: make(chan *lnwire.ChannelUpdate1, 2*numChannels), } @@ -161,7 +161,7 @@ func (g *mockGraph) FetchAllOpenChannels() ([]*channeldb.OpenChannel, error) { func (g *mockGraph) FetchChannelEdgesByOutpoint( op *wire.OutPoint) (*models.ChannelEdgeInfo, - *models.ChannelEdgePolicy, *models.ChannelEdgePolicy, error) { + *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { g.mu.Lock() defer g.mu.Unlock() @@ -210,7 +210,7 @@ func (g *mockGraph) ApplyChannelUpdate(update *lnwire.ChannelUpdate1, timestamp := time.Unix(int64(update.Timestamp), 0) - policy := &models.ChannelEdgePolicy{ + policy := &models.ChannelEdgePolicy1{ ChannelID: update.ShortChannelID.ToUint64(), ChannelFlags: update.ChannelFlags, LastUpdate: timestamp, @@ -249,7 +249,7 @@ func (g *mockGraph) addChannel(channel *channeldb.OpenChannel) { func (g *mockGraph) addEdgePolicy(c *channeldb.OpenChannel, info *models.ChannelEdgeInfo, - pol1, pol2 *models.ChannelEdgePolicy) { + pol1, pol2 *models.ChannelEdgePolicy1) { g.mu.Lock() defer g.mu.Unlock() diff --git a/netann/channel_announcement.go b/netann/channel_announcement.go index 4f625041c3..7dd6ad0762 100644 --- a/netann/channel_announcement.go +++ b/netann/channel_announcement.go @@ -35,7 +35,7 @@ const ( // peer's initial routing table upon connect. func CreateChanAnnouncement(chanProof *models.ChannelAuthProof1, chanInfo *models.ChannelEdgeInfo, - e1, e2 *models.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement1, + e1, e2 *models.ChannelEdgePolicy1) (*lnwire.ChannelAnnouncement1, *lnwire.ChannelUpdate1, *lnwire.ChannelUpdate1, error) { // First, using the parameters of the channel, along with the channel diff --git a/netann/channel_update.go b/netann/channel_update.go index af91abdd24..7bbc1c65e8 100644 --- a/netann/channel_update.go +++ b/netann/channel_update.go @@ -103,11 +103,11 @@ func SignChannelUpdate(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator // NOTE: The passed policies can be nil. func ExtractChannelUpdate(ownerPubKey []byte, info *models.ChannelEdgeInfo, - policies ...*models.ChannelEdgePolicy) ( + policies ...*models.ChannelEdgePolicy1) ( *lnwire.ChannelUpdate1, error) { // Helper function to extract the owner of the given policy. - owner := func(edge *models.ChannelEdgePolicy) []byte { + owner := func(edge *models.ChannelEdgePolicy1) []byte { var pubKey *btcec.PublicKey if edge.ChannelFlags&lnwire.ChanUpdateDirection == 0 { pubKey, _ = info.NodeKey1() @@ -136,7 +136,7 @@ func ExtractChannelUpdate(ownerPubKey []byte, // UnsignedChannelUpdateFromEdge reconstructs an unsigned ChannelUpdate from the // given edge info and policy. func UnsignedChannelUpdateFromEdge(info *models.ChannelEdgeInfo, - policy *models.ChannelEdgePolicy) *lnwire.ChannelUpdate1 { + policy *models.ChannelEdgePolicy1) *lnwire.ChannelUpdate1 { return &lnwire.ChannelUpdate1{ ChainHash: info.ChainHash, @@ -156,7 +156,7 @@ func UnsignedChannelUpdateFromEdge(info *models.ChannelEdgeInfo, // ChannelUpdateFromEdge reconstructs a signed ChannelUpdate from the given edge // info and policy. func ChannelUpdateFromEdge(info *models.ChannelEdgeInfo, - policy *models.ChannelEdgePolicy) (*lnwire.ChannelUpdate1, error) { + policy *models.ChannelEdgePolicy1) (*lnwire.ChannelUpdate1, error) { update := UnsignedChannelUpdateFromEdge(info, policy) diff --git a/netann/interface.go b/netann/interface.go index d6cdb46d0e..41acdc9544 100644 --- a/netann/interface.go +++ b/netann/interface.go @@ -20,5 +20,5 @@ type ChannelGraph interface { // FetchChannelEdgesByOutpoint returns the channel edge info and most // recent channel edge policies for a given outpoint. FetchChannelEdgesByOutpoint(*wire.OutPoint) (*models.ChannelEdgeInfo, - *models.ChannelEdgePolicy, *models.ChannelEdgePolicy, error) + *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) } diff --git a/peer/brontide.go b/peer/brontide.go index 28b3e0dcd4..ab92195dec 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -1102,7 +1102,7 @@ func (p *Brontide) loadActiveChannels(chans []*channeldb.OpenChannel) ( // // TODO(roasbeef): can add helper method to get policy for // particular channel. - var selfPolicy *models.ChannelEdgePolicy + var selfPolicy *models.ChannelEdgePolicy1 if info != nil && bytes.Equal(info.NodeKey1Bytes[:], p.cfg.ServerPubKey[:]) { diff --git a/routing/blindedpath/blinded_path.go b/routing/blindedpath/blinded_path.go index bc14daa40a..09dbb5e6c5 100644 --- a/routing/blindedpath/blinded_path.go +++ b/routing/blindedpath/blinded_path.go @@ -43,7 +43,7 @@ type BuildBlindedPathCfg struct { // FetchChannelEdgesByID attempts to look up the two directed edges for // the channel identified by the channel ID. FetchChannelEdgesByID func(chanID uint64) (*models.ChannelEdgeInfo, - *models.ChannelEdgePolicy, *models.ChannelEdgePolicy, error) + *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) // FetchOurOpenChannels fetches this node's set of open channels. FetchOurOpenChannels func() ([]*channeldb.OpenChannel, error) @@ -652,7 +652,7 @@ func getNodeChannelPolicy(cfg *BuildBlindedPathCfg, chanID uint64, // node in question. We know the update is the correct one if the // "ToNode" for the fetched policy is _not_ equal to the node ID in // question. - var policy *models.ChannelEdgePolicy + var policy *models.ChannelEdgePolicy1 switch { case update1 != nil && !bytes.Equal(update1.ToNode[:], nodeID[:]): policy = update1 diff --git a/routing/blindedpath/blinded_path_test.go b/routing/blindedpath/blinded_path_test.go index 51d028eafb..48e1d9de00 100644 --- a/routing/blindedpath/blinded_path_test.go +++ b/routing/blindedpath/blinded_path_test.go @@ -580,7 +580,7 @@ func TestBuildBlindedPath(t *testing.T) { }, } - realPolicies := map[uint64]*models.ChannelEdgePolicy{ + realPolicies := map[uint64]*models.ChannelEdgePolicy1{ chanCB: { ChannelID: chanCB, ToNode: bob, @@ -598,8 +598,8 @@ func TestBuildBlindedPath(t *testing.T) { return []*route.Route{realRoute}, nil }, FetchChannelEdgesByID: func(chanID uint64) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy, error) { + *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1, error) { return nil, realPolicies[chanID], nil, nil }, @@ -748,7 +748,7 @@ func TestBuildBlindedPathWithDummyHops(t *testing.T) { }, } - realPolicies := map[uint64]*models.ChannelEdgePolicy{ + realPolicies := map[uint64]*models.ChannelEdgePolicy1{ chanCB: { ChannelID: chanCB, ToNode: bob, @@ -766,8 +766,8 @@ func TestBuildBlindedPathWithDummyHops(t *testing.T) { return []*route.Route{realRoute}, nil }, FetchChannelEdgesByID: func(chanID uint64) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy, error) { + *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1, error) { policy, ok := realPolicies[chanID] if !ok { @@ -937,8 +937,8 @@ func TestBuildBlindedPathWithDummyHops(t *testing.T) { nil }, FetchChannelEdgesByID: func(chanID uint64) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy, - *models.ChannelEdgePolicy, error) { + *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgePolicy1, error) { // Force the call to error for the first 2 channels. if errCount < 2 { diff --git a/routing/localchans/manager.go b/routing/localchans/manager.go index f0f9b88de0..3a4a1b3975 100644 --- a/routing/localchans/manager.go +++ b/routing/localchans/manager.go @@ -33,7 +33,7 @@ type Manager struct { // channels. ForAllOutgoingChannels func(cb func(kvdb.RTx, *models.ChannelEdgeInfo, - *models.ChannelEdgePolicy) error) error + *models.ChannelEdgePolicy1) error) error // FetchChannel is used to query local channel parameters. Optionally an // existing db tx can be supplied. @@ -75,7 +75,7 @@ func (r *Manager) UpdatePolicy(newSchema routing.ChannelPolicy, err := r.ForAllOutgoingChannels(func( tx kvdb.RTx, info *models.ChannelEdgeInfo, - edge *models.ChannelEdgePolicy) error { + edge *models.ChannelEdgePolicy1) error { // If we have a channel filter, and this channel isn't a part // of it, then we'll skip it. @@ -182,7 +182,7 @@ func (r *Manager) UpdatePolicy(newSchema routing.ChannelPolicy, // updateEdge updates the given edge with the new schema. func (r *Manager) updateEdge(tx kvdb.RTx, chanPoint wire.OutPoint, - edge *models.ChannelEdgePolicy, + edge *models.ChannelEdgePolicy1, newSchema routing.ChannelPolicy) error { // Update forwarding fee scheme and required time lock delta. diff --git a/routing/localchans/manager_test.go b/routing/localchans/manager_test.go index 7594eef04a..0f75c45159 100644 --- a/routing/localchans/manager_test.go +++ b/routing/localchans/manager_test.go @@ -44,7 +44,7 @@ func TestManager(t *testing.T) { MaxHTLC: 5000, } - currentPolicy := models.ChannelEdgePolicy{ + currentPolicy := models.ChannelEdgePolicy1{ MinHTLC: minHTLC, MessageFlags: lnwire.ChanUpdateRequiredMaxHtlc, } @@ -108,7 +108,7 @@ func TestManager(t *testing.T) { forAllOutgoingChannels := func(cb func(kvdb.RTx, *models.ChannelEdgeInfo, - *models.ChannelEdgePolicy) error) error { + *models.ChannelEdgePolicy1) error) error { for _, c := range channelSet { if err := cb(nil, c.edgeInfo, ¤tPolicy); err != nil { @@ -152,7 +152,7 @@ func TestManager(t *testing.T) { tests := []struct { name string - currentPolicy models.ChannelEdgePolicy + currentPolicy models.ChannelEdgePolicy1 newPolicy routing.ChannelPolicy channelSet []channel specifiedChanPoints []wire.OutPoint diff --git a/routing/pathfind.go b/routing/pathfind.go index 43eae71036..ce516d4f98 100644 --- a/routing/pathfind.go +++ b/routing/pathfind.go @@ -87,7 +87,7 @@ var ( ) // edgePolicyWithSource is a helper struct to keep track of the source node -// of a channel edge. ChannelEdgePolicy only contains to destination node +// of a channel edge. ChannelEdgePolicy1 only contains to destination node // of the edge. type edgePolicyWithSource struct { sourceNode route.Vertex @@ -1137,7 +1137,7 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig, // destination features were provided. This is fine though, since our // route construction does not care where the features are actually // taken from. In the future we may wish to do route construction within - // findPath, and avoid using ChannelEdgePolicy altogether. + // findPath, and avoid using ChannelEdgePolicy1 altogether. pathEdges[len(pathEdges)-1].policy.ToNodeFeatures = features log.Debugf("Found route: probability=%v, hops=%v, fee=%v", diff --git a/routing/pathfind_test.go b/routing/pathfind_test.go index 486162bc67..146b8748b9 100644 --- a/routing/pathfind_test.go +++ b/routing/pathfind_test.go @@ -368,7 +368,7 @@ func parseTestGraph(t *testing.T, useCache bool, path string) ( targetNode = edgeInfo.NodeKey2Bytes } - edgePolicy := &models.ChannelEdgePolicy{ + edgePolicy := &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), MessageFlags: lnwire.ChanUpdateMsgFlags(edge.MessageFlags), ChannelFlags: channelFlags, @@ -692,7 +692,7 @@ func createTestGraphFromChannels(t *testing.T, useCache bool, channelFlags |= lnwire.ChanUpdateDisabled } - edgePolicy := &models.ChannelEdgePolicy{ + edgePolicy := &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), MessageFlags: msgFlags, ChannelFlags: channelFlags, @@ -722,7 +722,7 @@ func createTestGraphFromChannels(t *testing.T, useCache bool, } channelFlags |= lnwire.ChanUpdateDirection - edgePolicy := &models.ChannelEdgePolicy{ + edgePolicy := &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), MessageFlags: msgFlags, ChannelFlags: channelFlags, diff --git a/routing/router_test.go b/routing/router_test.go index 6f6f2e4342..6f7406411f 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -2776,7 +2776,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{ + edgePolicy := &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, LastUpdate: testTime, @@ -2791,7 +2791,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { require.NoError(t, ctx.graph.UpdateEdgePolicy(edgePolicy)) // Create edge in the other direction as well. - edgePolicy = &models.ChannelEdgePolicy{ + edgePolicy = &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, LastUpdate: testTime, @@ -2854,7 +2854,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { require.NoError(t, ctx.graph.AddChannelEdge(edge)) - edgePolicy = &models.ChannelEdgePolicy{ + edgePolicy = &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, LastUpdate: testTime, @@ -2868,7 +2868,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { require.NoError(t, ctx.graph.UpdateEdgePolicy(edgePolicy)) - edgePolicy = &models.ChannelEdgePolicy{ + edgePolicy = &models.ChannelEdgePolicy1{ SigBytes: testSig.Serialize(), ChannelID: edge.ChannelID, LastUpdate: testTime, @@ -2965,12 +2965,12 @@ func createDummyLightningPayment(t *testing.T, type mockGraphBuilder struct { rejectUpdate bool - updateEdge func(update *models.ChannelEdgePolicy) error + updateEdge func(update *models.ChannelEdgePolicy1) error } func newMockGraphBuilder(graph graph.DB) *mockGraphBuilder { return &mockGraphBuilder{ - updateEdge: func(update *models.ChannelEdgePolicy) error { + updateEdge: func(update *models.ChannelEdgePolicy1) error { return graph.UpdateEdgePolicy(update) }, } @@ -2985,7 +2985,7 @@ func (m *mockGraphBuilder) ApplyChannelUpdate(msg *lnwire.ChannelUpdate1) bool { return false } - err := m.updateEdge(&models.ChannelEdgePolicy{ + err := m.updateEdge(&models.ChannelEdgePolicy1{ SigBytes: msg.Signature.ToSignatureBytes(), ChannelID: msg.ShortChannelID.ToUint64(), LastUpdate: time.Unix(int64(msg.Timestamp), 0), diff --git a/rpcserver.go b/rpcserver.go index 9bd69e4368..9f820c10fa 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -6517,7 +6517,7 @@ func (r *rpcServer) DescribeGraph(ctx context.Context, // similar response which details both the edge information as well as // the routing policies of th nodes connecting the two edges. err = graph.ForEachChannel(func(edgeInfo *models.ChannelEdgeInfo, - c1, c2 *models.ChannelEdgePolicy) error { + c1, c2 *models.ChannelEdgePolicy1) error { // Do not include unannounced channels unless specifically // requested. Unannounced channels include both private channels as @@ -6590,7 +6590,7 @@ func extractInboundFeeSafe(data lnwire.ExtraOpaqueData) lnwire.Fee { } func marshalDBEdge(edgeInfo *models.ChannelEdgeInfo, - c1, c2 *models.ChannelEdgePolicy) *lnrpc.ChannelEdge { + c1, c2 *models.ChannelEdgePolicy1) *lnrpc.ChannelEdge { // Make sure the policies match the node they belong to. c1 should point // to the policy for NodeKey1, and c2 for NodeKey2. @@ -6633,7 +6633,7 @@ func marshalDBEdge(edgeInfo *models.ChannelEdgeInfo, } func marshalDBRoutingPolicy( - policy *models.ChannelEdgePolicy) *lnrpc.RoutingPolicy { + policy *models.ChannelEdgePolicy1) *lnrpc.RoutingPolicy { disabled := policy.ChannelFlags&lnwire.ChanUpdateDisabled != 0 @@ -6724,7 +6724,7 @@ func (r *rpcServer) GetChanInfo(_ context.Context, var ( edgeInfo *models.ChannelEdgeInfo - edge1, edge2 *models.ChannelEdgePolicy + edge1, edge2 *models.ChannelEdgePolicy1 err error ) @@ -6794,7 +6794,7 @@ func (r *rpcServer) GetNodeInfo(ctx context.Context, err = graph.ForEachNodeChannel(node.PubKeyBytes, func(_ kvdb.RTx, edge *models.ChannelEdgeInfo, - c1, c2 *models.ChannelEdgePolicy) error { + c1, c2 *models.ChannelEdgePolicy1) error { numChannels++ totalCapacity += edge.Capacity @@ -7450,7 +7450,7 @@ func (r *rpcServer) FeeReport(ctx context.Context, var feeReports []*lnrpc.ChannelFeeReport err = channelGraph.ForEachNodeChannel(selfNode.PubKeyBytes, func(_ kvdb.RTx, chanInfo *models.ChannelEdgeInfo, - edgePolicy, _ *models.ChannelEdgePolicy) error { + edgePolicy, _ *models.ChannelEdgePolicy1) error { // Self node should always have policies for its // channels. diff --git a/server.go b/server.go index 39600fb6f8..21d861de33 100644 --- a/server.go +++ b/server.go @@ -1349,7 +1349,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, // Wrap the DeleteChannelEdges method so that the funding manager can // use it without depending on several layers of indirection. deleteAliasEdge := func(scid lnwire.ShortChannelID) ( - *models.ChannelEdgePolicy, error) { + *models.ChannelEdgePolicy1, error) { info, e1, e2, err := s.graphDB.FetchChannelEdgesByID( scid.ToUint64(), @@ -1368,7 +1368,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, var ourKey [33]byte copy(ourKey[:], nodeKeyDesc.PubKey.SerializeCompressed()) - var ourPolicy *models.ChannelEdgePolicy + var ourPolicy *models.ChannelEdgePolicy1 if info != nil && info.NodeKey1Bytes == ourKey { ourPolicy = e1 } else { @@ -3316,7 +3316,7 @@ func (s *server) establishPersistentConnections() error { err = s.graphDB.ForEachNodeChannel(sourceNode.PubKeyBytes, func( tx kvdb.RTx, chanInfo *models.ChannelEdgeInfo, - policy, _ *models.ChannelEdgePolicy) error { + policy, _ *models.ChannelEdgePolicy1) error { // If the remote party has announced the channel to us, but we // haven't yet, then we won't have a policy. However, we don't From d2858d36d8ac05c35ad202f3494f76070c34c83b Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 21 Aug 2024 11:46:18 +0200 Subject: [PATCH 03/60] multi: rename ChannelEdgeInfo In preparaion for adding ChannelEdgeInfo2 and a ChannelEdgeInfo interface, rename ChannelEdgeInfo to ChannelEdgeInfo1. --- autopilot/graph.go | 4 +- channeldb/channel_cache_test.go | 2 +- channeldb/graph.go | 90 ++++++++++++------------ channeldb/graph_cache.go | 8 +-- channeldb/graph_cache_test.go | 6 +- channeldb/graph_test.go | 43 +++++------ channeldb/models/channel_edge_info.go | 20 +++--- discovery/gossiper.go | 20 +++--- discovery/gossiper_test.go | 14 ++-- graph/builder.go | 16 ++--- graph/builder_test.go | 30 ++++---- graph/interfaces.go | 20 +++--- graph/notifications.go | 4 +- graph/notifications_test.go | 8 +-- graph/validation_barrier.go | 6 +- lnrpc/devrpc/dev_server.go | 2 +- lnrpc/invoicesrpc/addinvoice.go | 2 +- lnrpc/invoicesrpc/addinvoice_test.go | 30 ++++---- netann/chan_status_manager_test.go | 12 ++-- netann/channel_announcement.go | 2 +- netann/channel_announcement_test.go | 2 +- netann/channel_update.go | 6 +- netann/interface.go | 2 +- routing/blindedpath/blinded_path.go | 2 +- routing/blindedpath/blinded_path_test.go | 6 +- routing/localchans/manager.go | 4 +- routing/localchans/manager_test.go | 12 ++-- routing/pathfind_test.go | 4 +- routing/router_test.go | 4 +- rpcserver.go | 10 +-- server.go | 2 +- 31 files changed, 197 insertions(+), 196 deletions(-) diff --git a/autopilot/graph.go b/autopilot/graph.go index d9dd2df181..3939d38629 100644 --- a/autopilot/graph.go +++ b/autopilot/graph.go @@ -90,7 +90,7 @@ func (d *dbNode) Addrs() []net.Addr { // NOTE: Part of the autopilot.Node interface. func (d *dbNode) ForEachChannel(cb func(ChannelEdge) error) error { return d.db.ForEachNodeChannelTx(d.tx, d.node.PubKeyBytes, - func(tx kvdb.RTx, ei *models.ChannelEdgeInfo, ep, + func(tx kvdb.RTx, ei *models.ChannelEdgeInfo1, ep, _ *models.ChannelEdgePolicy1) error { // Skip channels for which no outgoing edge policy is @@ -238,7 +238,7 @@ func (d *databaseChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey, } chanID := randChanID() - edge := &models.ChannelEdgeInfo{ + edge := &models.ChannelEdgeInfo1{ ChannelID: chanID.ToUint64(), Capacity: capacity, } diff --git a/channeldb/channel_cache_test.go b/channeldb/channel_cache_test.go index 7cb857293b..d32548a281 100644 --- a/channeldb/channel_cache_test.go +++ b/channeldb/channel_cache_test.go @@ -100,7 +100,7 @@ func assertHasChanEntries(t *testing.T, c *channelCache, start, end uint64) { // channelForInt generates a unique ChannelEdge given an integer. func channelForInt(i uint64) ChannelEdge { return ChannelEdge{ - Info: &models.ChannelEdgeInfo{ + Info: &models.ChannelEdgeInfo1{ ChannelID: i, }, } diff --git a/channeldb/graph.go b/channeldb/graph.go index 232b3a727b..522077cdb0 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -239,7 +239,7 @@ func NewChannelGraph(db kvdb.Backend, rejectCacheSize, chanCacheSize int, return nil, err } - err = g.ForEachChannel(func(info *models.ChannelEdgeInfo, + err = g.ForEachChannel(func(info *models.ChannelEdgeInfo1, policy1, policy2 *models.ChannelEdgePolicy1) error { g.graphCache.AddChannel(info, policy1, policy2) @@ -419,7 +419,7 @@ func (c *ChannelGraph) NewPathFindTx() (kvdb.RTx, error) { // NOTE: If an edge can't be found, or wasn't advertised, then a nil pointer // for that particular channel edge routing policy will be passed into the // callback. -func (c *ChannelGraph) ForEachChannel(cb func(*models.ChannelEdgeInfo, +func (c *ChannelGraph) ForEachChannel(cb func(*models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error { return c.db.View(func(tx kvdb.RTx) error { @@ -489,7 +489,7 @@ func (c *ChannelGraph) ForEachNodeDirectedChannel(tx kvdb.RTx, return err } - dbCallback := func(tx kvdb.RTx, e *models.ChannelEdgeInfo, p1, + dbCallback := func(tx kvdb.RTx, e *models.ChannelEdgeInfo1, p1, p2 *models.ChannelEdgePolicy1) error { var cachedInPolicy *models.CachedEdgePolicy @@ -575,7 +575,7 @@ func (c *ChannelGraph) ForEachNodeCached(cb func(node route.Vertex, channels := make(map[uint64]*DirectedChannel) err := c.ForEachNodeChannelTx(tx, node.PubKeyBytes, - func(tx kvdb.RTx, e *models.ChannelEdgeInfo, + func(tx kvdb.RTx, e *models.ChannelEdgeInfo1, p1 *models.ChannelEdgePolicy1, p2 *models.ChannelEdgePolicy1) error { @@ -988,7 +988,7 @@ func (c *ChannelGraph) deleteLightningNode(nodes kvdb.RwBucket, // involved in creation of the channel, and the set of features that the channel // supports. The chanPoint and chanID are used to uniquely identify the edge // globally within the database. -func (c *ChannelGraph) AddChannelEdge(edge *models.ChannelEdgeInfo, +func (c *ChannelGraph) AddChannelEdge(edge *models.ChannelEdgeInfo1, op ...batch.SchedulerOption) error { var alreadyExists bool @@ -1032,7 +1032,7 @@ func (c *ChannelGraph) AddChannelEdge(edge *models.ChannelEdgeInfo, // addChannelEdge is the private form of AddChannelEdge that allows callers to // utilize an existing db transaction. func (c *ChannelGraph) addChannelEdge(tx kvdb.RwTx, - edge *models.ChannelEdgeInfo) error { + edge *models.ChannelEdgeInfo1) error { // Construct the channel's primary key which is the 8-byte channel ID. var chanKey [8]byte @@ -1244,7 +1244,7 @@ func (c *ChannelGraph) HasChannelEdge( // In order to maintain this constraints, we return an error in the scenario // that an edge info hasn't yet been created yet, but someone attempts to update // it. -func (c *ChannelGraph) UpdateChannelEdge(edge *models.ChannelEdgeInfo) error { +func (c *ChannelGraph) UpdateChannelEdge(edge *models.ChannelEdgeInfo1) error { // Construct the channel's primary key which is the 8-byte channel ID. var chanKey [8]byte binary.BigEndian.PutUint64(chanKey[:], edge.ChannelID) @@ -1290,12 +1290,12 @@ const ( // the target block are returned if the function succeeds without error. func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint, blockHash *chainhash.Hash, blockHeight uint32) ( - []*models.ChannelEdgeInfo, error) { + []*models.ChannelEdgeInfo1, error) { c.cacheMu.Lock() defer c.cacheMu.Unlock() - var chansClosed []*models.ChannelEdgeInfo + var chansClosed []*models.ChannelEdgeInfo1 err := kvdb.Update(c.db, func(tx kvdb.RwTx) error { // First grab the edges bucket which houses the information @@ -1550,7 +1550,7 @@ func (c *ChannelGraph) pruneGraphNodes(nodes kvdb.RwBucket, // Channels that were removed from the graph resulting from the // disconnected block are returned. func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ( - []*models.ChannelEdgeInfo, error) { + []*models.ChannelEdgeInfo1, error) { // Every channel having a ShortChannelID starting at 'height' // will no longer be confirmed. @@ -1572,7 +1572,7 @@ func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ( defer c.cacheMu.Unlock() // Keep track of the channels that are removed from the graph. - var removedChans []*models.ChannelEdgeInfo + var removedChans []*models.ChannelEdgeInfo1 if err := kvdb.Update(c.db, func(tx kvdb.RwTx) error { edges, err := tx.CreateTopLevelBucket(edgeBucket) @@ -1875,7 +1875,7 @@ func (c *ChannelGraph) HighestChanID() (uint64, error) { // edge as well as each of the known advertised edge policies. type ChannelEdge struct { // Info contains all the static information describing the channel. - Info *models.ChannelEdgeInfo + Info *models.ChannelEdgeInfo1 // Policy1 points to the "first" edge policy of the channel containing // the dynamic information required to properly route through the edge. @@ -2671,7 +2671,7 @@ func (c *ChannelGraph) delChannelEdgeUnsafe(edges, edgeIndex, chanIndex, // the channel. If the channel were to be marked zombie again, it would be // marked with the correct lagging channel since we received an update from only // one side. -func makeZombiePubkeys(info *models.ChannelEdgeInfo, +func makeZombiePubkeys(info *models.ChannelEdgeInfo1, e1, e2 *models.ChannelEdgePolicy1) ([33]byte, [33]byte) { switch { @@ -2979,7 +2979,7 @@ func (c *ChannelGraph) isPublic(tx kvdb.RTx, nodePub route.Vertex, nodeIsPublic := false errDone := errors.New("done") err := c.ForEachNodeChannelTx(tx, nodePub, func(tx kvdb.RTx, - info *models.ChannelEdgeInfo, _ *models.ChannelEdgePolicy1, + info *models.ChannelEdgeInfo1, _ *models.ChannelEdgePolicy1, _ *models.ChannelEdgePolicy1) error { // If this edge doesn't extend to the source node, we'll @@ -3122,7 +3122,7 @@ func (n *graphCacheNode) Features() *lnwire.FeatureVector { // // Unknown policies are passed into the callback as nil values. func (n *graphCacheNode) ForEachChannel(tx kvdb.RTx, - cb func(kvdb.RTx, *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + cb func(kvdb.RTx, *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error { return nodeTraversal(tx, n.pubKeyBytes[:], nil, cb) @@ -3183,7 +3183,7 @@ func (c *ChannelGraph) HasLightningNode(nodePub [33]byte) (time.Time, bool, erro // nodeTraversal is used to traverse all channels of a node given by its // public key and passes channel information into the specified callback. func nodeTraversal(tx kvdb.RTx, nodePub []byte, db kvdb.Backend, - cb func(kvdb.RTx, *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + cb func(kvdb.RTx, *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error { traversal := func(tx kvdb.RTx) error { @@ -3272,7 +3272,7 @@ func nodeTraversal(tx kvdb.RTx, nodePub []byte, db kvdb.Backend, // // Unknown policies are passed into the callback as nil values. func (c *ChannelGraph) ForEachNodeChannel(nodePub route.Vertex, - cb func(kvdb.RTx, *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + cb func(kvdb.RTx, *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error { return nodeTraversal(nil, nodePub[:], c.db, cb) @@ -3292,7 +3292,7 @@ func (c *ChannelGraph) ForEachNodeChannel(nodePub route.Vertex, // be nil and a fresh transaction will be created to execute the graph // traversal. func (c *ChannelGraph) ForEachNodeChannelTx(tx kvdb.RTx, - nodePub route.Vertex, cb func(kvdb.RTx, *models.ChannelEdgeInfo, + nodePub route.Vertex, cb func(kvdb.RTx, *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error { @@ -3304,7 +3304,7 @@ func (c *ChannelGraph) ForEachNodeChannelTx(tx kvdb.RTx, // one of the nodes, and wishes to obtain the full LightningNode for the other // end of the channel. func (c *ChannelGraph) FetchOtherNode(tx kvdb.RTx, - channel *models.ChannelEdgeInfo, thisNodeKey []byte) (*LightningNode, + channel *models.ChannelEdgeInfo1, thisNodeKey []byte) (*LightningNode, error) { // Ensure that the node passed in is actually a member of the channel. @@ -3352,7 +3352,7 @@ func (c *ChannelGraph) FetchOtherNode(tx kvdb.RTx, // computeEdgePolicyKeys is a helper function that can be used to compute the // keys used to index the channel edge policy info for the two nodes of the // edge. The keys for node 1 and node 2 are returned respectively. -func computeEdgePolicyKeys(info *models.ChannelEdgeInfo) ([]byte, []byte) { +func computeEdgePolicyKeys(info *models.ChannelEdgeInfo1) ([]byte, []byte) { var ( node1Key [33 + 8]byte node2Key [33 + 8]byte @@ -3373,11 +3373,11 @@ func computeEdgePolicyKeys(info *models.ChannelEdgeInfo) ([]byte, []byte) { // information for the channel itself is returned as well as two structs that // contain the routing policies for the channel in either direction. func (c *ChannelGraph) FetchChannelEdgesByOutpoint(op *wire.OutPoint) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { var ( - edgeInfo *models.ChannelEdgeInfo + edgeInfo *models.ChannelEdgeInfo1 policy1 *models.ChannelEdgePolicy1 policy2 *models.ChannelEdgePolicy1 ) @@ -3456,13 +3456,13 @@ func (c *ChannelGraph) FetchChannelEdgesByOutpoint(op *wire.OutPoint) ( // // ErrZombieEdge an be returned if the edge is currently marked as a zombie // within the database. In this case, the ChannelEdgePolicy1's will be nil, and -// the ChannelEdgeInfo will only include the public keys of each node. +// the ChannelEdgeInfo1 will only include the public keys of each node. func (c *ChannelGraph) FetchChannelEdgesByID(chanID uint64) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { var ( - edgeInfo *models.ChannelEdgeInfo + edgeInfo *models.ChannelEdgeInfo1 policy1 *models.ChannelEdgePolicy1 policy2 *models.ChannelEdgePolicy1 channelID [8]byte @@ -3515,7 +3515,7 @@ func (c *ChannelGraph) FetchChannelEdgesByID(chanID uint64) ( // populate the edge info with the public keys of each // party as this is the only information we have about // it and return an error signaling so. - edgeInfo = &models.ChannelEdgeInfo{ + edgeInfo = &models.ChannelEdgeInfo1{ NodeKey1Bytes: pubKey1, NodeKey2Bytes: pubKey2, } @@ -4234,7 +4234,7 @@ func deserializeLightningNode(r io.Reader) (LightningNode, error) { } func putChanEdgeInfo(edgeIndex kvdb.RwBucket, - edgeInfo *models.ChannelEdgeInfo, chanID [8]byte) error { + edgeInfo *models.ChannelEdgeInfo1, chanID [8]byte) error { var b bytes.Buffer @@ -4302,58 +4302,58 @@ func putChanEdgeInfo(edgeIndex kvdb.RwBucket, } func fetchChanEdgeInfo(edgeIndex kvdb.RBucket, - chanID []byte) (models.ChannelEdgeInfo, error) { + chanID []byte) (models.ChannelEdgeInfo1, error) { edgeInfoBytes := edgeIndex.Get(chanID) if edgeInfoBytes == nil { - return models.ChannelEdgeInfo{}, ErrEdgeNotFound + return models.ChannelEdgeInfo1{}, ErrEdgeNotFound } edgeInfoReader := bytes.NewReader(edgeInfoBytes) return deserializeChanEdgeInfo(edgeInfoReader) } -func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo, error) { +func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo1, error) { var ( err error - edgeInfo models.ChannelEdgeInfo + edgeInfo models.ChannelEdgeInfo1 ) if _, err := io.ReadFull(r, edgeInfo.NodeKey1Bytes[:]); err != nil { - return models.ChannelEdgeInfo{}, err + return models.ChannelEdgeInfo1{}, err } if _, err := io.ReadFull(r, edgeInfo.NodeKey2Bytes[:]); err != nil { - return models.ChannelEdgeInfo{}, err + return models.ChannelEdgeInfo1{}, err } if _, err := io.ReadFull(r, edgeInfo.BitcoinKey1Bytes[:]); err != nil { - return models.ChannelEdgeInfo{}, err + return models.ChannelEdgeInfo1{}, err } if _, err := io.ReadFull(r, edgeInfo.BitcoinKey2Bytes[:]); err != nil { - return models.ChannelEdgeInfo{}, err + return models.ChannelEdgeInfo1{}, err } edgeInfo.Features, err = wire.ReadVarBytes(r, 0, 900, "features") if err != nil { - return models.ChannelEdgeInfo{}, err + return models.ChannelEdgeInfo1{}, err } proof := &models.ChannelAuthProof1{} proof.NodeSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") if err != nil { - return models.ChannelEdgeInfo{}, err + return models.ChannelEdgeInfo1{}, err } proof.NodeSig2Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") if err != nil { - return models.ChannelEdgeInfo{}, err + return models.ChannelEdgeInfo1{}, err } proof.BitcoinSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") if err != nil { - return models.ChannelEdgeInfo{}, err + return models.ChannelEdgeInfo1{}, err } proof.BitcoinSig2Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") if err != nil { - return models.ChannelEdgeInfo{}, err + return models.ChannelEdgeInfo1{}, err } if !proof.IsEmpty() { @@ -4362,17 +4362,17 @@ func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo, error) { edgeInfo.ChannelPoint = wire.OutPoint{} if err := readOutpoint(r, &edgeInfo.ChannelPoint); err != nil { - return models.ChannelEdgeInfo{}, err + return models.ChannelEdgeInfo1{}, err } if err := binary.Read(r, byteOrder, &edgeInfo.Capacity); err != nil { - return models.ChannelEdgeInfo{}, err + return models.ChannelEdgeInfo1{}, err } if err := binary.Read(r, byteOrder, &edgeInfo.ChannelID); err != nil { - return models.ChannelEdgeInfo{}, err + return models.ChannelEdgeInfo1{}, err } if _, err := io.ReadFull(r, edgeInfo.ChainHash[:]); err != nil { - return models.ChannelEdgeInfo{}, err + return models.ChannelEdgeInfo1{}, err } // We'll try and see if there are any opaque bytes left, if not, then @@ -4384,7 +4384,7 @@ func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo, error) { case err == io.ErrUnexpectedEOF: case err == io.EOF: case err != nil: - return models.ChannelEdgeInfo{}, err + return models.ChannelEdgeInfo1{}, err } return edgeInfo, nil diff --git a/channeldb/graph_cache.go b/channeldb/graph_cache.go index 888e2dfa52..7df72b209e 100644 --- a/channeldb/graph_cache.go +++ b/channeldb/graph_cache.go @@ -28,7 +28,7 @@ type GraphCacheNode interface { // error, then the iteration is halted with the error propagated back up // to the caller. ForEachChannel(kvdb.RTx, - func(kvdb.RTx, *models.ChannelEdgeInfo, + func(kvdb.RTx, *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error } @@ -142,7 +142,7 @@ func (c *GraphCache) AddNode(tx kvdb.RTx, node GraphCacheNode) error { c.AddNodeFeatures(node) return node.ForEachChannel( - tx, func(tx kvdb.RTx, info *models.ChannelEdgeInfo, + tx, func(tx kvdb.RTx, info *models.ChannelEdgeInfo1, outPolicy *models.ChannelEdgePolicy1, inPolicy *models.ChannelEdgePolicy1) error { @@ -157,7 +157,7 @@ func (c *GraphCache) AddNode(tx kvdb.RTx, node GraphCacheNode) error { // and policy 2 does not matter, the directionality is extracted from the info // and policy flags automatically. The policy will be set as the outgoing policy // on one node and the incoming policy on the peer's side. -func (c *GraphCache) AddChannel(info *models.ChannelEdgeInfo, policy1, +func (c *GraphCache) AddChannel(info *models.ChannelEdgeInfo1, policy1, policy2 *models.ChannelEdgePolicy1) { if info == nil { @@ -309,7 +309,7 @@ func (c *GraphCache) removeChannelIfFound(node route.Vertex, chanID uint64) { // UpdateChannel updates the channel edge information for a specific edge. We // expect the edge to already exist and be known. If it does not yet exist, this // call is a no-op. -func (c *GraphCache) UpdateChannel(info *models.ChannelEdgeInfo) { +func (c *GraphCache) UpdateChannel(info *models.ChannelEdgeInfo1) { c.mtx.Lock() defer c.mtx.Unlock() diff --git a/channeldb/graph_cache_test.go b/channeldb/graph_cache_test.go index e3ba3d67a4..65e639be55 100644 --- a/channeldb/graph_cache_test.go +++ b/channeldb/graph_cache_test.go @@ -29,7 +29,7 @@ type node struct { pubKey route.Vertex features *lnwire.FeatureVector - edgeInfos []*models.ChannelEdgeInfo + edgeInfos []*models.ChannelEdgeInfo1 outPolicies []*models.ChannelEdgePolicy1 inPolicies []*models.ChannelEdgePolicy1 } @@ -42,7 +42,7 @@ func (n *node) Features() *lnwire.FeatureVector { } func (n *node) ForEachChannel(tx kvdb.RTx, - cb func(kvdb.RTx, *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + cb func(kvdb.RTx, *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error { for idx := range n.edgeInfos { @@ -88,7 +88,7 @@ func TestGraphCacheAddNode(t *testing.T) { node := &node{ pubKey: nodeA, features: lnwire.EmptyFeatureVector(), - edgeInfos: []*models.ChannelEdgeInfo{{ + edgeInfos: []*models.ChannelEdgeInfo1{{ ChannelID: 1000, // Those are direction independent! NodeKey1Bytes: pubKey1, diff --git a/channeldb/graph_test.go b/channeldb/graph_test.go index 30be2db442..a0c8dae25c 100644 --- a/channeldb/graph_test.go +++ b/channeldb/graph_test.go @@ -326,7 +326,7 @@ func TestEdgeInsertionDeletion(t *testing.T) { require.NoError(t, err, "unable to generate node key") node2Pub, err := node2.PubKey() require.NoError(t, err, "unable to generate node key") - edgeInfo := models.ChannelEdgeInfo{ + edgeInfo := models.ChannelEdgeInfo1{ ChannelID: chanID, ChainHash: key, AuthProof: &models.ChannelAuthProof1{ @@ -386,7 +386,7 @@ func TestEdgeInsertionDeletion(t *testing.T) { } func createEdge(height, txIndex uint32, txPosition uint16, outPointIndex uint32, - node1, node2 *LightningNode) (models.ChannelEdgeInfo, + node1, node2 *LightningNode) (models.ChannelEdgeInfo1, lnwire.ShortChannelID) { shortChanID := lnwire.ShortChannelID{ @@ -401,7 +401,7 @@ func createEdge(height, txIndex uint32, txPosition uint16, outPointIndex uint32, node1Pub, _ := node1.PubKey() node2Pub, _ := node2.PubKey() - edgeInfo := models.ChannelEdgeInfo{ + edgeInfo := models.ChannelEdgeInfo1{ ChannelID: shortChanID.ToUint64(), ChainHash: key, AuthProof: &models.ChannelAuthProof1{ @@ -556,8 +556,8 @@ func TestDisconnectBlockAtHeight(t *testing.T) { } } -func assertEdgeInfoEqual(t *testing.T, e1 *models.ChannelEdgeInfo, - e2 *models.ChannelEdgeInfo) { +func assertEdgeInfoEqual(t *testing.T, e1 *models.ChannelEdgeInfo1, + e2 *models.ChannelEdgeInfo1) { if e1.ChannelID != e2.ChannelID { t.Fatalf("chan id's don't match: %v vs %v", e1.ChannelID, @@ -619,7 +619,7 @@ func assertEdgeInfoEqual(t *testing.T, e1 *models.ChannelEdgeInfo, } func createChannelEdge(db kvdb.Backend, node1, node2 *LightningNode) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) { var ( @@ -644,7 +644,7 @@ func createChannelEdge(db kvdb.Backend, node1, node2 *LightningNode) ( // Add the new edge to the database, this should proceed without any // errors. - edgeInfo := &models.ChannelEdgeInfo{ + edgeInfo := &models.ChannelEdgeInfo1{ ChannelID: chanID, ChainHash: key, AuthProof: &models.ChannelAuthProof1{ @@ -821,7 +821,7 @@ func assertNodeNotInCache(t *testing.T, g *ChannelGraph, n route.Vertex) { } func assertEdgeWithNoPoliciesInCache(t *testing.T, g *ChannelGraph, - e *models.ChannelEdgeInfo) { + e *models.ChannelEdgeInfo1) { // Let's check the internal view first. require.NotEmpty(t, g.graphCache.nodeChannels[e.NodeKey1Bytes]) @@ -899,7 +899,8 @@ func assertNoEdge(t *testing.T, g *ChannelGraph, chanID uint64) { } func assertEdgeWithPolicyInCache(t *testing.T, g *ChannelGraph, - e *models.ChannelEdgeInfo, p *models.ChannelEdgePolicy1, policy1 bool) { + e *models.ChannelEdgeInfo1, p *models.ChannelEdgePolicy1, + policy1 bool) { // Check the internal state first. c1, ok := g.graphCache.nodeChannels[e.NodeKey1Bytes][e.ChannelID] @@ -1041,7 +1042,7 @@ func TestGraphTraversal(t *testing.T) { // Iterate through all the known channels within the graph DB, once // again if the map is empty that indicates that all edges have // properly been reached. - err = graph.ForEachChannel(func(ei *models.ChannelEdgeInfo, + err = graph.ForEachChannel(func(ei *models.ChannelEdgeInfo1, _ *models.ChannelEdgePolicy1, _ *models.ChannelEdgePolicy1) error { @@ -1056,7 +1057,7 @@ func TestGraphTraversal(t *testing.T) { numNodeChans := 0 firstNode, secondNode := nodeList[0], nodeList[1] err = graph.ForEachNodeChannel(firstNode.PubKeyBytes, - func(_ kvdb.RTx, _ *models.ChannelEdgeInfo, outEdge, + func(_ kvdb.RTx, _ *models.ChannelEdgeInfo1, outEdge, inEdge *models.ChannelEdgePolicy1) error { // All channels between first and second node should @@ -1137,7 +1138,7 @@ func TestGraphTraversalCacheable(t *testing.T) { for _, node := range nodes { err := node.ForEachChannel( tx, func(tx kvdb.RTx, - info *models.ChannelEdgeInfo, + info *models.ChannelEdgeInfo1, policy *models.ChannelEdgePolicy1, policy2 *models.ChannelEdgePolicy1) error { //nolint:lll @@ -1257,7 +1258,7 @@ func fillTestGraph(t require.TestingT, graph *ChannelGraph, numNodes, Index: 0, } - edgeInfo := models.ChannelEdgeInfo{ + edgeInfo := models.ChannelEdgeInfo1{ ChannelID: chanID, ChainHash: key, AuthProof: &models.ChannelAuthProof1{ @@ -1321,7 +1322,7 @@ func assertPruneTip(t *testing.T, graph *ChannelGraph, blockHash *chainhash.Hash func assertNumChans(t *testing.T, graph *ChannelGraph, n int) { numChans := 0 - if err := graph.ForEachChannel(func(*models.ChannelEdgeInfo, + if err := graph.ForEachChannel(func(*models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error { @@ -1439,7 +1440,7 @@ func TestGraphPruning(t *testing.T) { channelPoints = append(channelPoints, &op) - edgeInfo := models.ChannelEdgeInfo{ + edgeInfo := models.ChannelEdgeInfo1{ ChannelID: chanID, ChainHash: key, AuthProof: &models.ChannelAuthProof1{ @@ -2120,7 +2121,7 @@ func TestStressTestChannelGraphAPI(t *testing.T) { require.NoError(t, err) type chanInfo struct { - info models.ChannelEdgeInfo + info models.ChannelEdgeInfo1 id lnwire.ShortChannelID } @@ -2748,7 +2749,7 @@ func TestIncompleteChannelPolicies(t *testing.T) { checkPolicies := func(node *LightningNode, expectedIn, expectedOut bool) { calls := 0 err := graph.ForEachNodeChannel(node.PubKeyBytes, - func(_ kvdb.RTx, _ *models.ChannelEdgeInfo, outEdge, + func(_ kvdb.RTx, _ *models.ChannelEdgeInfo1, outEdge, inEdge *models.ChannelEdgePolicy1) error { if !expectedOut && outEdge != nil { @@ -3166,7 +3167,7 @@ func TestNodeIsPublic(t *testing.T) { // After creating all of our nodes and edges, we'll add them to each // participant's graph. nodes := []*LightningNode{aliceNode, bobNode, carolNode} - edges := []*models.ChannelEdgeInfo{&aliceBobEdge, &bobCarolEdge} + edges := []*models.ChannelEdgeInfo1{&aliceBobEdge, &bobCarolEdge} graphs := []*ChannelGraph{aliceGraph, bobGraph, carolGraph} for _, graph := range graphs { for _, node := range nodes { @@ -3770,7 +3771,7 @@ func TestBatchedAddChannelEdge(t *testing.T) { // Create a third edge, this with a block height of 155. edgeInfo3, _ := createEdge(height-1, 0, 0, 2, node1, node2) - edges := []models.ChannelEdgeInfo{edgeInfo, edgeInfo2, edgeInfo3} + edges := []models.ChannelEdgeInfo1{edgeInfo, edgeInfo2, edgeInfo3} errChan := make(chan error, len(edges)) errTimeout := errors.New("timeout adding batched channel") @@ -3778,7 +3779,7 @@ func TestBatchedAddChannelEdge(t *testing.T) { var wg sync.WaitGroup for _, edge := range edges { wg.Add(1) - go func(edge models.ChannelEdgeInfo) { + go func(edge models.ChannelEdgeInfo1) { defer wg.Done() select { @@ -3886,7 +3887,7 @@ func BenchmarkForEachChannel(b *testing.B) { err = graph.db.View(func(tx kvdb.RTx) error { for _, n := range nodes { cb := func(tx kvdb.RTx, - info *models.ChannelEdgeInfo, + info *models.ChannelEdgeInfo1, policy *models.ChannelEdgePolicy1, policy2 *models.ChannelEdgePolicy1) error { //nolint:lll diff --git a/channeldb/models/channel_edge_info.go b/channeldb/models/channel_edge_info.go index 973acbc6ec..d4b5b361f1 100644 --- a/channeldb/models/channel_edge_info.go +++ b/channeldb/models/channel_edge_info.go @@ -11,13 +11,13 @@ import ( "github.com/lightningnetwork/lnd/fn" ) -// ChannelEdgeInfo represents a fully authenticated channel along with all its +// ChannelEdgeInfo1 represents a fully authenticated channel along with all its // unique attributes. Once an authenticated channel announcement has been -// processed on the network, then an instance of ChannelEdgeInfo encapsulating +// processed on the network, then an instance of ChannelEdgeInfo1 encapsulating // the channels attributes is stored. The other portions relevant to routing // policy of a channel are stored within a ChannelEdgePolicy1 for each direction // of the channel. -type ChannelEdgeInfo struct { +type ChannelEdgeInfo1 struct { // ChannelID is the unique channel ID for the channel. The first 3 // bytes are the block height, the next 3 the index within the block, // and the last 2 bytes are the output index for the channel. @@ -78,8 +78,8 @@ type ChannelEdgeInfo struct { } // AddNodeKeys is a setter-like method that can be used to replace the set of -// keys for the target ChannelEdgeInfo. -func (c *ChannelEdgeInfo) AddNodeKeys(nodeKey1, nodeKey2, bitcoinKey1, +// keys for the target ChannelEdgeInfo1. +func (c *ChannelEdgeInfo1) AddNodeKeys(nodeKey1, nodeKey2, bitcoinKey1, bitcoinKey2 *btcec.PublicKey) { c.nodeKey1 = nodeKey1 @@ -102,7 +102,7 @@ func (c *ChannelEdgeInfo) AddNodeKeys(nodeKey1, nodeKey2, bitcoinKey1, // // NOTE: By having this method to access an attribute, we ensure we only need // to fully deserialize the pubkey if absolutely necessary. -func (c *ChannelEdgeInfo) NodeKey1() (*btcec.PublicKey, error) { +func (c *ChannelEdgeInfo1) NodeKey1() (*btcec.PublicKey, error) { if c.nodeKey1 != nil { return c.nodeKey1, nil } @@ -123,7 +123,7 @@ func (c *ChannelEdgeInfo) NodeKey1() (*btcec.PublicKey, error) { // // NOTE: By having this method to access an attribute, we ensure we only need // to fully deserialize the pubkey if absolutely necessary. -func (c *ChannelEdgeInfo) NodeKey2() (*btcec.PublicKey, error) { +func (c *ChannelEdgeInfo1) NodeKey2() (*btcec.PublicKey, error) { if c.nodeKey2 != nil { return c.nodeKey2, nil } @@ -143,7 +143,7 @@ func (c *ChannelEdgeInfo) NodeKey2() (*btcec.PublicKey, error) { // // NOTE: By having this method to access an attribute, we ensure we only need // to fully deserialize the pubkey if absolutely necessary. -func (c *ChannelEdgeInfo) BitcoinKey1() (*btcec.PublicKey, error) { +func (c *ChannelEdgeInfo1) BitcoinKey1() (*btcec.PublicKey, error) { if c.bitcoinKey1 != nil { return c.bitcoinKey1, nil } @@ -163,7 +163,7 @@ func (c *ChannelEdgeInfo) BitcoinKey1() (*btcec.PublicKey, error) { // // NOTE: By having this method to access an attribute, we ensure we only need // to fully deserialize the pubkey if absolutely necessary. -func (c *ChannelEdgeInfo) BitcoinKey2() (*btcec.PublicKey, error) { +func (c *ChannelEdgeInfo1) BitcoinKey2() (*btcec.PublicKey, error) { if c.bitcoinKey2 != nil { return c.bitcoinKey2, nil } @@ -178,7 +178,7 @@ func (c *ChannelEdgeInfo) BitcoinKey2() (*btcec.PublicKey, error) { } // OtherNodeKeyBytes returns the node key bytes of the other end of the channel. -func (c *ChannelEdgeInfo) OtherNodeKeyBytes(thisNodeKey []byte) ( +func (c *ChannelEdgeInfo1) OtherNodeKeyBytes(thisNodeKey []byte) ( [33]byte, error) { switch { diff --git a/discovery/gossiper.go b/discovery/gossiper.go index b3cc8d2ede..27b3c52466 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -563,7 +563,7 @@ func New(cfg Config, selfKeyDesc *keychain.KeyDescriptor) *AuthenticatedGossiper // EdgeWithInfo contains the information that is required to update an edge. type EdgeWithInfo struct { // Info describes the channel. - Info *models.ChannelEdgeInfo + Info *models.ChannelEdgeInfo1 // Edge describes the policy in one direction of the channel. Edge *models.ChannelEdgePolicy1 @@ -1627,7 +1627,7 @@ func (d *AuthenticatedGossiper) retransmitStaleAnns(now time.Time) error { // Iterate over all of our channels and check if any of them fall // within the prune interval or re-broadcast interval. type updateTuple struct { - info *models.ChannelEdgeInfo + info *models.ChannelEdgeInfo1 edge *models.ChannelEdgePolicy1 } @@ -1637,7 +1637,7 @@ func (d *AuthenticatedGossiper) retransmitStaleAnns(now time.Time) error { ) err := d.cfg.Graph.ForAllOutgoingChannels(func( _ kvdb.RTx, - info *models.ChannelEdgeInfo, + info *models.ChannelEdgeInfo1, edge *models.ChannelEdgePolicy1) error { // If there's no auth proof attached to this edge, it means @@ -1843,8 +1843,8 @@ func (d *AuthenticatedGossiper) processChanPolicyUpdate( } // remotePubFromChanInfo returns the public key of the remote peer given a -// ChannelEdgeInfo that describe a channel we have with them. -func remotePubFromChanInfo(chanInfo *models.ChannelEdgeInfo, +// ChannelEdgeInfo1 that describe a channel we have with them. +func remotePubFromChanInfo(chanInfo *models.ChannelEdgeInfo1, chanFlags lnwire.ChanUpdateChanFlags) [33]byte { var remotePubKey [33]byte @@ -2083,10 +2083,10 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement( // processZombieUpdate determines whether the provided channel update should // resurrect a given zombie edge. // -// NOTE: only the NodeKey1Bytes and NodeKey2Bytes members of the ChannelEdgeInfo -// should be inspected. +// NOTE: only the NodeKey1Bytes and NodeKey2Bytes members of the +// ChannelEdgeInfo1 should be inspected. func (d *AuthenticatedGossiper) processZombieUpdate( - chanInfo *models.ChannelEdgeInfo, scid lnwire.ShortChannelID, + chanInfo *models.ChannelEdgeInfo1, scid lnwire.ShortChannelID, msg *lnwire.ChannelUpdate1) error { // The least-significant bit in the flag on the channel update tells us @@ -2223,7 +2223,7 @@ func (d *AuthenticatedGossiper) isMsgStale(msg lnwire.Message) bool { // updateChannel creates a new fully signed update for the channel, and updates // the underlying graph with the new state. -func (d *AuthenticatedGossiper) updateChannel(info *models.ChannelEdgeInfo, +func (d *AuthenticatedGossiper) updateChannel(info *models.ChannelEdgeInfo1, edge *models.ChannelEdgePolicy1) (*lnwire.ChannelAnnouncement1, *lnwire.ChannelUpdate1, error) { @@ -2586,7 +2586,7 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg, return nil, false } - edge := &models.ChannelEdgeInfo{ + edge := &models.ChannelEdgeInfo1{ ChannelID: scid.ToUint64(), ChainHash: ann.ChainHash, NodeKey1Bytes: ann.NodeID1, diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index 1aa44591ee..3dc946193f 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -93,7 +93,7 @@ type mockGraphSource struct { mu sync.Mutex nodes []channeldb.LightningNode - infos map[uint64]models.ChannelEdgeInfo + infos map[uint64]models.ChannelEdgeInfo1 edges map[uint64][]models.ChannelEdgePolicy1 zombies map[uint64][][33]byte chansToReject map[uint64]struct{} @@ -103,7 +103,7 @@ type mockGraphSource struct { func newMockRouter(height uint32) *mockGraphSource { return &mockGraphSource{ bestHeight: height, - infos: make(map[uint64]models.ChannelEdgeInfo), + infos: make(map[uint64]models.ChannelEdgeInfo1), edges: make(map[uint64][]models.ChannelEdgePolicy1), zombies: make(map[uint64][][33]byte), chansToReject: make(map[uint64]struct{}), @@ -122,7 +122,7 @@ func (r *mockGraphSource) AddNode(node *channeldb.LightningNode, return nil } -func (r *mockGraphSource) AddEdge(info *models.ChannelEdgeInfo, +func (r *mockGraphSource) AddEdge(info *models.ChannelEdgeInfo1, _ ...batch.SchedulerOption) error { r.mu.Lock() @@ -207,7 +207,7 @@ func (r *mockGraphSource) ForEachNode(func(node *channeldb.LightningNode) error) } func (r *mockGraphSource) ForAllOutgoingChannels(cb func(tx kvdb.RTx, - i *models.ChannelEdgeInfo, + i *models.ChannelEdgeInfo1, c *models.ChannelEdgePolicy1) error) error { r.mu.Lock() @@ -239,7 +239,7 @@ func (r *mockGraphSource) ForAllOutgoingChannels(cb func(tx kvdb.RTx, } func (r *mockGraphSource) GetChannelByID(chanID lnwire.ShortChannelID) ( - *models.ChannelEdgeInfo, + *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { @@ -254,7 +254,7 @@ func (r *mockGraphSource) GetChannelByID(chanID lnwire.ShortChannelID) ( return nil, nil, nil, channeldb.ErrEdgeNotFound } - return &models.ChannelEdgeInfo{ + return &models.ChannelEdgeInfo1{ NodeKey1Bytes: pubKeys[0], NodeKey2Bytes: pubKeys[1], }, nil, nil, channeldb.ErrZombieEdge @@ -3483,7 +3483,7 @@ out: var edgesToUpdate []EdgeWithInfo err = ctx.router.ForAllOutgoingChannels(func( _ kvdb.RTx, - info *models.ChannelEdgeInfo, + info *models.ChannelEdgeInfo1, edge *models.ChannelEdgePolicy1) error { edge.TimeLockDelta = uint16(newTimeLockDelta) diff --git a/graph/builder.go b/graph/builder.go index 99ab386b00..af67e48946 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -541,14 +541,14 @@ func (b *Builder) pruneZombieChans() error { log.Infof("Examining channel graph for zombie channels") // A helper method to detect if the channel belongs to this node - isSelfChannelEdge := func(info *models.ChannelEdgeInfo) bool { + isSelfChannelEdge := func(info *models.ChannelEdgeInfo1) bool { return info.NodeKey1Bytes == b.cfg.SelfNode || info.NodeKey2Bytes == b.cfg.SelfNode } // First, we'll collect all the channels which are eligible for garbage // collection due to being zombies. - filterPruneChans := func(info *models.ChannelEdgeInfo, + filterPruneChans := func(info *models.ChannelEdgeInfo1, e1, e2 *models.ChannelEdgePolicy1) error { // Exit early in case this channel is already marked to be @@ -1182,8 +1182,8 @@ func (b *Builder) processUpdate(msg interface{}, log.Tracef("Updated vertex data for node=%x", msg.PubKeyBytes) b.stats.incNumNodeUpdates() - case *models.ChannelEdgeInfo: - log.Debugf("Received ChannelEdgeInfo for channel %v", + case *models.ChannelEdgeInfo1: + log.Debugf("Received ChannelEdgeInfo1 for channel %v", msg.ChannelID) // Prior to processing the announcement we first check if we @@ -1544,7 +1544,7 @@ func (b *Builder) AddNode(node *channeldb.LightningNode, // in construction of payment path. // // NOTE: This method is part of the ChannelGraphSource interface. -func (b *Builder) AddEdge(edge *models.ChannelEdgeInfo, +func (b *Builder) AddEdge(edge *models.ChannelEdgeInfo1, op ...batch.SchedulerOption) error { rMsg := &routingMsg{ @@ -1611,7 +1611,7 @@ func (b *Builder) SyncedHeight() uint32 { // // NOTE: This method is part of the ChannelGraphSource interface. func (b *Builder) GetChannelByID(chanID lnwire.ShortChannelID) ( - *models.ChannelEdgeInfo, + *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { @@ -1646,10 +1646,10 @@ func (b *Builder) ForEachNode( // // NOTE: This method is part of the ChannelGraphSource interface. func (b *Builder) ForAllOutgoingChannels(cb func(kvdb.RTx, - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1) error) error { + *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1) error) error { return b.cfg.Graph.ForEachNodeChannel(b.cfg.SelfNode, - func(tx kvdb.RTx, c *models.ChannelEdgeInfo, + func(tx kvdb.RTx, c *models.ChannelEdgeInfo1, e *models.ChannelEdgePolicy1, _ *models.ChannelEdgePolicy1) error { diff --git a/graph/builder_test.go b/graph/builder_test.go index a8b94ee391..8e7cca9e0b 100644 --- a/graph/builder_test.go +++ b/graph/builder_test.go @@ -63,7 +63,7 @@ func TestAddProof(t *testing.T) { ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) // After utxo was recreated adding the edge without the proof. - edge := &models.ChannelEdgeInfo{ + edge := &models.ChannelEdgeInfo1{ ChannelID: chanID.ToUint64(), NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, @@ -146,7 +146,7 @@ func TestIgnoreChannelEdgePolicyForUnknownChannel(t *testing.T) { } ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) - edge := &models.ChannelEdgeInfo{ + edge := &models.ChannelEdgeInfo1{ ChannelID: chanID.ToUint64(), NodeKey1Bytes: pub1, NodeKey2Bytes: pub2, @@ -259,7 +259,7 @@ func TestWakeUpOnStaleBranch(t *testing.T) { node1 := createTestNode(t) node2 := createTestNode(t) - edge1 := &models.ChannelEdgeInfo{ + edge1 := &models.ChannelEdgeInfo1{ ChannelID: chanID1, NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, @@ -277,7 +277,7 @@ func TestWakeUpOnStaleBranch(t *testing.T) { t.Fatalf("unable to add edge: %v", err) } - edge2 := &models.ChannelEdgeInfo{ + edge2 := &models.ChannelEdgeInfo1{ ChannelID: chanID2, NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, @@ -462,7 +462,7 @@ func TestDisconnectedBlocks(t *testing.T) { node1 := createTestNode(t) node2 := createTestNode(t) - edge1 := &models.ChannelEdgeInfo{ + edge1 := &models.ChannelEdgeInfo1{ ChannelID: chanID1, NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, @@ -482,7 +482,7 @@ func TestDisconnectedBlocks(t *testing.T) { t.Fatalf("unable to add edge: %v", err) } - edge2 := &models.ChannelEdgeInfo{ + edge2 := &models.ChannelEdgeInfo1{ ChannelID: chanID2, NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, @@ -612,7 +612,7 @@ func TestRouterChansClosedOfflinePruneGraph(t *testing.T) { node1 := createTestNode(t) node2 := createTestNode(t) - edge1 := &models.ChannelEdgeInfo{ + edge1 := &models.ChannelEdgeInfo1{ ChannelID: chanID1.ToUint64(), NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, @@ -1017,7 +1017,7 @@ func TestIsStaleNode(t *testing.T) { } ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) - edge := &models.ChannelEdgeInfo{ + edge := &models.ChannelEdgeInfo1{ ChannelID: chanID.ToUint64(), NodeKey1Bytes: pub1, NodeKey2Bytes: pub2, @@ -1093,7 +1093,7 @@ func TestIsKnownEdge(t *testing.T) { } ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) - edge := &models.ChannelEdgeInfo{ + edge := &models.ChannelEdgeInfo1{ ChannelID: chanID.ToUint64(), NodeKey1Bytes: pub1, NodeKey2Bytes: pub2, @@ -1149,7 +1149,7 @@ func TestIsStaleEdgePolicy(t *testing.T) { t.Fatalf("router failed to detect fresh edge policy") } - edge := &models.ChannelEdgeInfo{ + edge := &models.ChannelEdgeInfo1{ ChannelID: chanID.ToUint64(), NodeKey1Bytes: pub1, NodeKey2Bytes: pub2, @@ -1231,7 +1231,7 @@ const ( // newChannelEdgeInfo is a helper function used to create a new channel edge, // possibly skipping adding it to parts of the chain/state as well. func newChannelEdgeInfo(t *testing.T, ctx *testCtx, fundingHeight uint32, - ecm edgeCreationModifier) (*models.ChannelEdgeInfo, error) { + ecm edgeCreationModifier) (*models.ChannelEdgeInfo1, error) { node1 := createTestNode(t) node2 := createTestNode(t) @@ -1244,7 +1244,7 @@ func newChannelEdgeInfo(t *testing.T, ctx *testCtx, fundingHeight uint32, return nil, fmt.Errorf("unable to create edge: %w", err) } - edge := &models.ChannelEdgeInfo{ + edge := &models.ChannelEdgeInfo1{ ChannelID: chanID.ToUint64(), NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, @@ -1275,7 +1275,7 @@ func newChannelEdgeInfo(t *testing.T, ctx *testCtx, fundingHeight uint32, } func assertChanChainRejection(t *testing.T, ctx *testCtx, - edge *models.ChannelEdgeInfo, failCode ErrorCode) { + edge *models.ChannelEdgeInfo1, failCode ErrorCode) { t.Helper() @@ -1573,7 +1573,7 @@ func parseTestGraph(t *testing.T, useCache bool, path string) ( // We first insert the existence of the edge between the two // nodes. - edgeInfo := models.ChannelEdgeInfo{ + edgeInfo := models.ChannelEdgeInfo1{ ChannelID: edge.ChannelID, AuthProof: &testAuthProof, ChannelPoint: fundingPoint, @@ -1945,7 +1945,7 @@ func createTestGraphFromChannels(t *testing.T, useCache bool, // We first insert the existence of the edge between the two // nodes. - edgeInfo := models.ChannelEdgeInfo{ + edgeInfo := models.ChannelEdgeInfo1{ ChannelID: channelID, AuthProof: &testAuthProof, ChannelPoint: *fundingPoint, diff --git a/graph/interfaces.go b/graph/interfaces.go index 3408b366a5..43ed155aa3 100644 --- a/graph/interfaces.go +++ b/graph/interfaces.go @@ -29,7 +29,7 @@ type ChannelGraphSource interface { // AddEdge is used to add edge/channel to the topology of the router, // after all information about channel will be gathered this // edge/channel might be used in construction of payment path. - AddEdge(edge *models.ChannelEdgeInfo, + AddEdge(edge *models.ChannelEdgeInfo1, op ...batch.SchedulerOption) error // AddProof updates the channel edge info with proof which is needed to @@ -70,7 +70,7 @@ type ChannelGraphSource interface { // emanating from the "source" node which is the center of the // star-graph. ForAllOutgoingChannels(cb func(tx kvdb.RTx, - c *models.ChannelEdgeInfo, + c *models.ChannelEdgeInfo1, e *models.ChannelEdgePolicy1) error) error // CurrentBlockHeight returns the block height from POV of the router @@ -79,7 +79,7 @@ type ChannelGraphSource interface { // GetChannelByID return the channel by the channel id. GetChannelByID(chanID lnwire.ShortChannelID) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) // FetchLightningNode attempts to look up a target node by its identity @@ -110,7 +110,7 @@ type DB interface { // slice of channels that have been closed by the target block are // returned if the function succeeds without error. PruneGraph(spentOutputs []*wire.OutPoint, blockHash *chainhash.Hash, - blockHeight uint32) ([]*models.ChannelEdgeInfo, error) + blockHeight uint32) ([]*models.ChannelEdgeInfo1, error) // ChannelView returns the verifiable edge information for each active // channel within the known channel graph. The set of UTXO's (along with @@ -169,7 +169,7 @@ type DB interface { // set to the last prune height valid for the remaining chain. // Channels that were removed from the graph resulting from the // disconnected block are returned. - DisconnectBlockAtHeight(height uint32) ([]*models.ChannelEdgeInfo, + DisconnectBlockAtHeight(height uint32) ([]*models.ChannelEdgeInfo1, error) // HasChannelEdge returns true if the database knows of a channel edge @@ -189,9 +189,9 @@ type DB interface { // // ErrZombieEdge an be returned if the edge is currently marked as a // zombie within the database. In this case, the ChannelEdgePolicy1's - // will be nil, and the ChannelEdgeInfo will only include the public + // will be nil, and the ChannelEdgeInfo1 will only include the public // keys of each node. - FetchChannelEdgesByID(chanID uint64) (*models.ChannelEdgeInfo, + FetchChannelEdgesByID(chanID uint64) (*models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) // AddLightningNode adds a vertex/node to the graph database. If the @@ -210,7 +210,7 @@ type DB interface { // and the set of features that the channel supports. The chanPoint and // chanID are used to uniquely identify the edge globally within the // database. - AddChannelEdge(edge *models.ChannelEdgeInfo, + AddChannelEdge(edge *models.ChannelEdgeInfo1, op ...batch.SchedulerOption) error // MarkEdgeZombie attempts to mark a channel identified by its channel @@ -258,7 +258,7 @@ type DB interface { // // Unknown policies are passed into the callback as nil values. ForEachNodeChannel(nodePub route.Vertex, cb func(kvdb.RTx, - *models.ChannelEdgeInfo, + *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error @@ -267,7 +267,7 @@ type DB interface { // created. In order to maintain this constraints, we return an error in // the scenario that an edge info hasn't yet been created yet, but // someone attempts to update it. - UpdateChannelEdge(edge *models.ChannelEdgeInfo) error + UpdateChannelEdge(edge *models.ChannelEdgeInfo1) error // IsPublicNode is a helper method that determines whether the node with // the given public key is seen as a public node in the graph from the diff --git a/graph/notifications.go b/graph/notifications.go index 2873a08b3c..47e1c62f6c 100644 --- a/graph/notifications.go +++ b/graph/notifications.go @@ -211,7 +211,7 @@ type ClosedChanSummary struct { // createCloseSummaries takes in a slice of channels closed at the target block // height and creates a slice of summaries which of each channel closure. func createCloseSummaries(blockHeight uint32, - closedChans ...*models.ChannelEdgeInfo) []*ClosedChanSummary { + closedChans ...*models.ChannelEdgeInfo1) []*ClosedChanSummary { closeSummaries := make([]*ClosedChanSummary, len(closedChans)) for i, closedChan := range closedChans { @@ -337,7 +337,7 @@ func addToTopologyChange(graph DB, update *TopologyChange, // We ignore initial channel announcements as we'll only send out // updates once the individual edges themselves have been updated. - case *models.ChannelEdgeInfo: + case *models.ChannelEdgeInfo1: return nil // Any new ChannelUpdateAnnouncements will generate a corresponding diff --git a/graph/notifications_test.go b/graph/notifications_test.go index 34bbd54238..8cba544cd9 100644 --- a/graph/notifications_test.go +++ b/graph/notifications_test.go @@ -466,7 +466,7 @@ func TestEdgeUpdateNotification(t *testing.T) { // Finally, to conclude our test set up, we'll create a channel // update to announce the created channel between the two nodes. - edge := &models.ChannelEdgeInfo{ + edge := &models.ChannelEdgeInfo1{ ChannelID: chanID.ToUint64(), NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, @@ -653,7 +653,7 @@ func TestNodeUpdateNotification(t *testing.T) { testFeaturesBuf := new(bytes.Buffer) require.NoError(t, testFeatures.Encode(testFeaturesBuf)) - edge := &models.ChannelEdgeInfo{ + edge := &models.ChannelEdgeInfo1{ ChannelID: chanID.ToUint64(), NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, @@ -837,7 +837,7 @@ func TestNotificationCancellation(t *testing.T) { // to the client. ntfnClient.Cancel() - edge := &models.ChannelEdgeInfo{ + edge := &models.ChannelEdgeInfo1{ ChannelID: chanID.ToUint64(), NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, @@ -906,7 +906,7 @@ func TestChannelCloseNotification(t *testing.T) { // Finally, to conclude our test set up, we'll create a channel // announcement to announce the created channel between the two nodes. - edge := &models.ChannelEdgeInfo{ + edge := &models.ChannelEdgeInfo1{ ChannelID: chanID.ToUint64(), NodeKey1Bytes: node1.PubKeyBytes, NodeKey2Bytes: node2.PubKeyBytes, diff --git a/graph/validation_barrier.go b/graph/validation_barrier.go index 513fb28dea..2bfc85f061 100644 --- a/graph/validation_barrier.go +++ b/graph/validation_barrier.go @@ -126,7 +126,7 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) { v.nodeAnnDependencies[route.Vertex(msg.NodeID1)] = signals v.nodeAnnDependencies[route.Vertex(msg.NodeID2)] = signals } - case *models.ChannelEdgeInfo: + case *models.ChannelEdgeInfo1: shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID) if _, ok := v.chanAnnFinSignal[shortID]; !ok { @@ -218,7 +218,7 @@ func (v *ValidationBarrier) WaitForDependants(job interface{}) error { // return directly. case *lnwire.AnnounceSignatures1: // TODO(roasbeef): need to wait on chan ann? - case *models.ChannelEdgeInfo: + case *models.ChannelEdgeInfo1: case *lnwire.ChannelAnnouncement1: } @@ -264,7 +264,7 @@ func (v *ValidationBarrier) SignalDependants(job interface{}, allow bool) { // If we've just finished executing a ChannelAnnouncement, then we'll // close out the signal, and remove the signal from the map of active // ones. This will allow/deny any dependent jobs to continue execution. - case *models.ChannelEdgeInfo: + case *models.ChannelEdgeInfo1: shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID) finSignals, ok := v.chanAnnFinSignal[shortID] if ok { diff --git a/lnrpc/devrpc/dev_server.go b/lnrpc/devrpc/dev_server.go index 07c2423169..97384a6797 100644 --- a/lnrpc/devrpc/dev_server.go +++ b/lnrpc/devrpc/dev_server.go @@ -262,7 +262,7 @@ func (s *Server) ImportGraph(ctx context.Context, for _, rpcEdge := range graph.Edges { rpcEdge := rpcEdge - edge := &models.ChannelEdgeInfo{ + edge := &models.ChannelEdgeInfo1{ ChannelID: rpcEdge.ChannelId, ChainHash: *s.cfg.ActiveNetParams.GenesisHash, Capacity: btcutil.Amount(rpcEdge.Capacity), diff --git a/lnrpc/invoicesrpc/addinvoice.go b/lnrpc/invoicesrpc/addinvoice.go index 25f2a272b5..6d7ea341a1 100644 --- a/lnrpc/invoicesrpc/addinvoice.go +++ b/lnrpc/invoicesrpc/addinvoice.go @@ -762,7 +762,7 @@ type SelectHopHintsCfg struct { // FetchChannelEdgesByID attempts to lookup the two directed edges for // the channel identified by the channel ID. - FetchChannelEdgesByID func(chanID uint64) (*models.ChannelEdgeInfo, + FetchChannelEdgesByID func(chanID uint64) (*models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) diff --git a/lnrpc/invoicesrpc/addinvoice_test.go b/lnrpc/invoicesrpc/addinvoice_test.go index 5d4fd7e0df..2bb94da8b0 100644 --- a/lnrpc/invoicesrpc/addinvoice_test.go +++ b/lnrpc/invoicesrpc/addinvoice_test.go @@ -67,7 +67,7 @@ func (h *hopHintsConfigMock) FetchAllChannels() ([]*channeldb.OpenChannel, // FetchChannelEdgesByID attempts to lookup the two directed edges for // the channel identified by the channel ID. func (h *hopHintsConfigMock) FetchChannelEdgesByID(chanID uint64) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { args := h.Mock.Called(chanID) @@ -80,7 +80,7 @@ func (h *hopHintsConfigMock) FetchChannelEdgesByID(chanID uint64) ( return nil, nil, nil, err } - edgeInfo, ok := args.Get(0).(*models.ChannelEdgeInfo) + edgeInfo, ok := args.Get(0).(*models.ChannelEdgeInfo1) require.True(h.t, ok) policy1, ok := args.Get(1).(*models.ChannelEdgePolicy1) @@ -226,7 +226,7 @@ var shouldIncludeChannelTestCases = []struct { h.Mock.On( "FetchChannelEdgesByID", mock.Anything, ).Once().Return( - &models.ChannelEdgeInfo{}, + &models.ChannelEdgeInfo1{}, &models.ChannelEdgePolicy1{}, &models.ChannelEdgePolicy1{}, nil, ) @@ -264,7 +264,7 @@ var shouldIncludeChannelTestCases = []struct { h.Mock.On( "FetchChannelEdgesByID", mock.Anything, ).Once().Return( - &models.ChannelEdgeInfo{}, + &models.ChannelEdgeInfo1{}, &models.ChannelEdgePolicy1{}, &models.ChannelEdgePolicy1{}, nil, ) @@ -305,7 +305,7 @@ var shouldIncludeChannelTestCases = []struct { h.Mock.On( "FetchChannelEdgesByID", mock.Anything, ).Once().Return( - &models.ChannelEdgeInfo{ + &models.ChannelEdgeInfo1{ NodeKey1Bytes: selectedPolicy, }, &models.ChannelEdgePolicy1{ @@ -353,7 +353,7 @@ var shouldIncludeChannelTestCases = []struct { h.Mock.On( "FetchChannelEdgesByID", mock.Anything, ).Once().Return( - &models.ChannelEdgeInfo{}, + &models.ChannelEdgeInfo1{}, &models.ChannelEdgePolicy1{}, &models.ChannelEdgePolicy1{ FeeBaseMSat: 1000, @@ -398,7 +398,7 @@ var shouldIncludeChannelTestCases = []struct { h.Mock.On( "FetchChannelEdgesByID", mock.Anything, ).Once().Return( - &models.ChannelEdgeInfo{}, + &models.ChannelEdgeInfo1{}, &models.ChannelEdgePolicy1{}, &models.ChannelEdgePolicy1{ FeeBaseMSat: 1000, @@ -565,7 +565,7 @@ var populateHopHintsTestCases = []struct { h.Mock.On( "FetchChannelEdgesByID", mock.Anything, ).Once().Return( - &models.ChannelEdgeInfo{}, + &models.ChannelEdgeInfo1{}, &models.ChannelEdgePolicy1{}, &models.ChannelEdgePolicy1{}, nil, ) @@ -615,7 +615,7 @@ var populateHopHintsTestCases = []struct { h.Mock.On( "FetchChannelEdgesByID", mock.Anything, ).Once().Return( - &models.ChannelEdgeInfo{}, + &models.ChannelEdgeInfo1{}, &models.ChannelEdgePolicy1{}, &models.ChannelEdgePolicy1{}, nil, ) @@ -666,7 +666,7 @@ var populateHopHintsTestCases = []struct { h.Mock.On( "FetchChannelEdgesByID", mock.Anything, ).Once().Return( - &models.ChannelEdgeInfo{}, + &models.ChannelEdgeInfo1{}, &models.ChannelEdgePolicy1{}, &models.ChannelEdgePolicy1{}, nil, ) @@ -699,7 +699,7 @@ var populateHopHintsTestCases = []struct { h.Mock.On( "FetchChannelEdgesByID", mock.Anything, ).Once().Return( - &models.ChannelEdgeInfo{}, + &models.ChannelEdgeInfo1{}, &models.ChannelEdgePolicy1{}, &models.ChannelEdgePolicy1{}, nil, ) @@ -716,7 +716,7 @@ var populateHopHintsTestCases = []struct { h.Mock.On( "FetchChannelEdgesByID", mock.Anything, ).Once().Return( - &models.ChannelEdgeInfo{}, + &models.ChannelEdgeInfo1{}, &models.ChannelEdgePolicy1{}, &models.ChannelEdgePolicy1{}, nil, ) @@ -753,7 +753,7 @@ var populateHopHintsTestCases = []struct { h.Mock.On( "FetchChannelEdgesByID", mock.Anything, ).Once().Return( - &models.ChannelEdgeInfo{}, + &models.ChannelEdgeInfo1{}, &models.ChannelEdgePolicy1{}, &models.ChannelEdgePolicy1{}, nil, ) @@ -770,7 +770,7 @@ var populateHopHintsTestCases = []struct { h.Mock.On( "FetchChannelEdgesByID", mock.Anything, ).Once().Return( - &models.ChannelEdgeInfo{}, + &models.ChannelEdgeInfo1{}, &models.ChannelEdgePolicy1{}, &models.ChannelEdgePolicy1{}, nil, ) @@ -808,7 +808,7 @@ var populateHopHintsTestCases = []struct { h.Mock.On( "FetchChannelEdgesByID", mock.Anything, ).Once().Return( - &models.ChannelEdgeInfo{}, + &models.ChannelEdgeInfo1{}, &models.ChannelEdgePolicy1{}, &models.ChannelEdgePolicy1{}, nil, ) diff --git a/netann/chan_status_manager_test.go b/netann/chan_status_manager_test.go index 46e1939fed..7af98bd801 100644 --- a/netann/chan_status_manager_test.go +++ b/netann/chan_status_manager_test.go @@ -66,7 +66,7 @@ func createChannel(t *testing.T) *channeldb.OpenChannel { // our `pubkey` with the direction bit set appropriately in the policies. Our // update will be created with the disabled bit set if startEnabled is false. func createEdgePolicies(t *testing.T, channel *channeldb.OpenChannel, - pubkey *btcec.PublicKey, startEnabled bool) (*models.ChannelEdgeInfo, + pubkey *btcec.PublicKey, startEnabled bool) (*models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) { var ( @@ -99,7 +99,7 @@ func createEdgePolicies(t *testing.T, channel *channeldb.OpenChannel, // bit. dir2 |= lnwire.ChanUpdateDirection - return &models.ChannelEdgeInfo{ + return &models.ChannelEdgeInfo1{ ChannelPoint: channel.FundingOutpoint, NodeKey1Bytes: pubkey1, NodeKey2Bytes: pubkey2, @@ -121,7 +121,7 @@ func createEdgePolicies(t *testing.T, channel *channeldb.OpenChannel, type mockGraph struct { mu sync.Mutex channels []*channeldb.OpenChannel - chanInfos map[wire.OutPoint]*models.ChannelEdgeInfo + chanInfos map[wire.OutPoint]*models.ChannelEdgeInfo1 chanPols1 map[wire.OutPoint]*models.ChannelEdgePolicy1 chanPols2 map[wire.OutPoint]*models.ChannelEdgePolicy1 sidToCid map[lnwire.ShortChannelID]wire.OutPoint @@ -134,7 +134,7 @@ func newMockGraph(t *testing.T, numChannels int, g := &mockGraph{ channels: make([]*channeldb.OpenChannel, 0, numChannels), - chanInfos: make(map[wire.OutPoint]*models.ChannelEdgeInfo), + chanInfos: make(map[wire.OutPoint]*models.ChannelEdgeInfo1), chanPols1: make(map[wire.OutPoint]*models.ChannelEdgePolicy1), chanPols2: make(map[wire.OutPoint]*models.ChannelEdgePolicy1), sidToCid: make(map[lnwire.ShortChannelID]wire.OutPoint), @@ -160,7 +160,7 @@ func (g *mockGraph) FetchAllOpenChannels() ([]*channeldb.OpenChannel, error) { } func (g *mockGraph) FetchChannelEdgesByOutpoint( - op *wire.OutPoint) (*models.ChannelEdgeInfo, + op *wire.OutPoint) (*models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { g.mu.Lock() @@ -248,7 +248,7 @@ func (g *mockGraph) addChannel(channel *channeldb.OpenChannel) { } func (g *mockGraph) addEdgePolicy(c *channeldb.OpenChannel, - info *models.ChannelEdgeInfo, + info *models.ChannelEdgeInfo1, pol1, pol2 *models.ChannelEdgePolicy1) { g.mu.Lock() diff --git a/netann/channel_announcement.go b/netann/channel_announcement.go index 7dd6ad0762..67ba33d082 100644 --- a/netann/channel_announcement.go +++ b/netann/channel_announcement.go @@ -34,7 +34,7 @@ const ( // structs for announcing new channels to other peers, or simply syncing up a // peer's initial routing table upon connect. func CreateChanAnnouncement(chanProof *models.ChannelAuthProof1, - chanInfo *models.ChannelEdgeInfo, + chanInfo *models.ChannelEdgeInfo1, e1, e2 *models.ChannelEdgePolicy1) (*lnwire.ChannelAnnouncement1, *lnwire.ChannelUpdate1, *lnwire.ChannelUpdate1, error) { diff --git a/netann/channel_announcement_test.go b/netann/channel_announcement_test.go index 805825b6e3..0190c7cf85 100644 --- a/netann/channel_announcement_test.go +++ b/netann/channel_announcement_test.go @@ -50,7 +50,7 @@ func TestCreateChanAnnouncement(t *testing.T) { BitcoinSig1Bytes: expChanAnn.BitcoinSig1.ToSignatureBytes(), BitcoinSig2Bytes: expChanAnn.BitcoinSig2.ToSignatureBytes(), } - chanInfo := &models.ChannelEdgeInfo{ + chanInfo := &models.ChannelEdgeInfo1{ ChainHash: expChanAnn.ChainHash, ChannelID: expChanAnn.ShortChannelID.ToUint64(), ChannelPoint: wire.OutPoint{Index: 1}, diff --git a/netann/channel_update.go b/netann/channel_update.go index 7bbc1c65e8..d4fac00611 100644 --- a/netann/channel_update.go +++ b/netann/channel_update.go @@ -102,7 +102,7 @@ func SignChannelUpdate(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator // // NOTE: The passed policies can be nil. func ExtractChannelUpdate(ownerPubKey []byte, - info *models.ChannelEdgeInfo, + info *models.ChannelEdgeInfo1, policies ...*models.ChannelEdgePolicy1) ( *lnwire.ChannelUpdate1, error) { @@ -135,7 +135,7 @@ func ExtractChannelUpdate(ownerPubKey []byte, // UnsignedChannelUpdateFromEdge reconstructs an unsigned ChannelUpdate from the // given edge info and policy. -func UnsignedChannelUpdateFromEdge(info *models.ChannelEdgeInfo, +func UnsignedChannelUpdateFromEdge(info *models.ChannelEdgeInfo1, policy *models.ChannelEdgePolicy1) *lnwire.ChannelUpdate1 { return &lnwire.ChannelUpdate1{ @@ -155,7 +155,7 @@ func UnsignedChannelUpdateFromEdge(info *models.ChannelEdgeInfo, // ChannelUpdateFromEdge reconstructs a signed ChannelUpdate from the given edge // info and policy. -func ChannelUpdateFromEdge(info *models.ChannelEdgeInfo, +func ChannelUpdateFromEdge(info *models.ChannelEdgeInfo1, policy *models.ChannelEdgePolicy1) (*lnwire.ChannelUpdate1, error) { update := UnsignedChannelUpdateFromEdge(info, policy) diff --git a/netann/interface.go b/netann/interface.go index 41acdc9544..8fd5eaf275 100644 --- a/netann/interface.go +++ b/netann/interface.go @@ -19,6 +19,6 @@ type DB interface { type ChannelGraph interface { // FetchChannelEdgesByOutpoint returns the channel edge info and most // recent channel edge policies for a given outpoint. - FetchChannelEdgesByOutpoint(*wire.OutPoint) (*models.ChannelEdgeInfo, + FetchChannelEdgesByOutpoint(*wire.OutPoint) (*models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) } diff --git a/routing/blindedpath/blinded_path.go b/routing/blindedpath/blinded_path.go index 09dbb5e6c5..3f41b2d7b6 100644 --- a/routing/blindedpath/blinded_path.go +++ b/routing/blindedpath/blinded_path.go @@ -42,7 +42,7 @@ type BuildBlindedPathCfg struct { // FetchChannelEdgesByID attempts to look up the two directed edges for // the channel identified by the channel ID. - FetchChannelEdgesByID func(chanID uint64) (*models.ChannelEdgeInfo, + FetchChannelEdgesByID func(chanID uint64) (*models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) // FetchOurOpenChannels fetches this node's set of open channels. diff --git a/routing/blindedpath/blinded_path_test.go b/routing/blindedpath/blinded_path_test.go index 48e1d9de00..d593b034fb 100644 --- a/routing/blindedpath/blinded_path_test.go +++ b/routing/blindedpath/blinded_path_test.go @@ -598,7 +598,7 @@ func TestBuildBlindedPath(t *testing.T) { return []*route.Route{realRoute}, nil }, FetchChannelEdgesByID: func(chanID uint64) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { return nil, realPolicies[chanID], nil, nil @@ -766,7 +766,7 @@ func TestBuildBlindedPathWithDummyHops(t *testing.T) { return []*route.Route{realRoute}, nil }, FetchChannelEdgesByID: func(chanID uint64) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { policy, ok := realPolicies[chanID] @@ -937,7 +937,7 @@ func TestBuildBlindedPathWithDummyHops(t *testing.T) { nil }, FetchChannelEdgesByID: func(chanID uint64) ( - *models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, + *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { // Force the call to error for the first 2 channels. diff --git a/routing/localchans/manager.go b/routing/localchans/manager.go index 3a4a1b3975..55a9af095d 100644 --- a/routing/localchans/manager.go +++ b/routing/localchans/manager.go @@ -32,7 +32,7 @@ type Manager struct { // ForAllOutgoingChannels is required to iterate over all our local // channels. ForAllOutgoingChannels func(cb func(kvdb.RTx, - *models.ChannelEdgeInfo, + *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1) error) error // FetchChannel is used to query local channel parameters. Optionally an @@ -74,7 +74,7 @@ func (r *Manager) UpdatePolicy(newSchema routing.ChannelPolicy, // otherwise we'll collect them all. err := r.ForAllOutgoingChannels(func( tx kvdb.RTx, - info *models.ChannelEdgeInfo, + info *models.ChannelEdgeInfo1, edge *models.ChannelEdgePolicy1) error { // If we have a channel filter, and this channel isn't a part diff --git a/routing/localchans/manager_test.go b/routing/localchans/manager_test.go index 0f75c45159..0054396d08 100644 --- a/routing/localchans/manager_test.go +++ b/routing/localchans/manager_test.go @@ -22,7 +22,7 @@ func TestManager(t *testing.T) { t.Parallel() type channel struct { - edgeInfo *models.ChannelEdgeInfo + edgeInfo *models.ChannelEdgeInfo1 } var ( @@ -107,7 +107,7 @@ func TestManager(t *testing.T) { } forAllOutgoingChannels := func(cb func(kvdb.RTx, - *models.ChannelEdgeInfo, + *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1) error) error { for _, c := range channelSet { @@ -166,7 +166,7 @@ func TestManager(t *testing.T) { newPolicy: newPolicy, channelSet: []channel{ { - edgeInfo: &models.ChannelEdgeInfo{ + edgeInfo: &models.ChannelEdgeInfo1{ Capacity: chanCap, ChannelPoint: chanPointValid, }, @@ -183,7 +183,7 @@ func TestManager(t *testing.T) { newPolicy: newPolicy, channelSet: []channel{ { - edgeInfo: &models.ChannelEdgeInfo{ + edgeInfo: &models.ChannelEdgeInfo1{ Capacity: chanCap, ChannelPoint: chanPointValid, }, @@ -200,7 +200,7 @@ func TestManager(t *testing.T) { newPolicy: newPolicy, channelSet: []channel{ { - edgeInfo: &models.ChannelEdgeInfo{ + edgeInfo: &models.ChannelEdgeInfo1{ Capacity: chanCap, ChannelPoint: chanPointValid, }, @@ -221,7 +221,7 @@ func TestManager(t *testing.T) { newPolicy: noMaxHtlcPolicy, channelSet: []channel{ { - edgeInfo: &models.ChannelEdgeInfo{ + edgeInfo: &models.ChannelEdgeInfo1{ Capacity: chanCap, ChannelPoint: chanPointValid, }, diff --git a/routing/pathfind_test.go b/routing/pathfind_test.go index 146b8748b9..399a646e38 100644 --- a/routing/pathfind_test.go +++ b/routing/pathfind_test.go @@ -337,7 +337,7 @@ func parseTestGraph(t *testing.T, useCache bool, path string) ( // We first insert the existence of the edge between the two // nodes. - edgeInfo := models.ChannelEdgeInfo{ + edgeInfo := models.ChannelEdgeInfo1{ ChannelID: edge.ChannelID, AuthProof: &testAuthProof, ChannelPoint: fundingPoint, @@ -652,7 +652,7 @@ func createTestGraphFromChannels(t *testing.T, useCache bool, // We first insert the existence of the edge between the two // nodes. - edgeInfo := models.ChannelEdgeInfo{ + edgeInfo := models.ChannelEdgeInfo1{ ChannelID: channelID, AuthProof: &testAuthProof, ChannelPoint: *fundingPoint, diff --git a/routing/router_test.go b/routing/router_test.go index 6f7406411f..de2667fcdb 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -2764,7 +2764,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { ) require.NoError(t, err, "unable to create channel edge") - edge := &models.ChannelEdgeInfo{ + edge := &models.ChannelEdgeInfo1{ ChannelID: chanID.ToUint64(), NodeKey1Bytes: pub1, NodeKey2Bytes: pub2, @@ -2843,7 +2843,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { 10000, 510) require.NoError(t, err, "unable to create channel edge") - edge = &models.ChannelEdgeInfo{ + edge = &models.ChannelEdgeInfo1{ ChannelID: chanID.ToUint64(), AuthProof: nil, } diff --git a/rpcserver.go b/rpcserver.go index 9f820c10fa..2498f32ba1 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -6516,7 +6516,7 @@ func (r *rpcServer) DescribeGraph(ctx context.Context, // Next, for each active channel we know of within the graph, create a // similar response which details both the edge information as well as // the routing policies of th nodes connecting the two edges. - err = graph.ForEachChannel(func(edgeInfo *models.ChannelEdgeInfo, + err = graph.ForEachChannel(func(edgeInfo *models.ChannelEdgeInfo1, c1, c2 *models.ChannelEdgePolicy1) error { // Do not include unannounced channels unless specifically @@ -6589,7 +6589,7 @@ func extractInboundFeeSafe(data lnwire.ExtraOpaqueData) lnwire.Fee { return inboundFee } -func marshalDBEdge(edgeInfo *models.ChannelEdgeInfo, +func marshalDBEdge(edgeInfo *models.ChannelEdgeInfo1, c1, c2 *models.ChannelEdgePolicy1) *lnrpc.ChannelEdge { // Make sure the policies match the node they belong to. c1 should point @@ -6723,7 +6723,7 @@ func (r *rpcServer) GetChanInfo(_ context.Context, graph := r.server.graphDB var ( - edgeInfo *models.ChannelEdgeInfo + edgeInfo *models.ChannelEdgeInfo1 edge1, edge2 *models.ChannelEdgePolicy1 err error ) @@ -6793,7 +6793,7 @@ func (r *rpcServer) GetNodeInfo(ctx context.Context, ) err = graph.ForEachNodeChannel(node.PubKeyBytes, - func(_ kvdb.RTx, edge *models.ChannelEdgeInfo, + func(_ kvdb.RTx, edge *models.ChannelEdgeInfo1, c1, c2 *models.ChannelEdgePolicy1) error { numChannels++ @@ -7449,7 +7449,7 @@ func (r *rpcServer) FeeReport(ctx context.Context, var feeReports []*lnrpc.ChannelFeeReport err = channelGraph.ForEachNodeChannel(selfNode.PubKeyBytes, - func(_ kvdb.RTx, chanInfo *models.ChannelEdgeInfo, + func(_ kvdb.RTx, chanInfo *models.ChannelEdgeInfo1, edgePolicy, _ *models.ChannelEdgePolicy1) error { // Self node should always have policies for its diff --git a/server.go b/server.go index 21d861de33..7d3c59f290 100644 --- a/server.go +++ b/server.go @@ -3315,7 +3315,7 @@ func (s *server) establishPersistentConnections() error { selfPub := s.identityECDH.PubKey().SerializeCompressed() err = s.graphDB.ForEachNodeChannel(sourceNode.PubKeyBytes, func( tx kvdb.RTx, - chanInfo *models.ChannelEdgeInfo, + chanInfo *models.ChannelEdgeInfo1, policy, _ *models.ChannelEdgePolicy1) error { // If the remote party has announced the channel to us, but we From e3fb10c444307d3a218b6145b309722913adb63d Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 27 Oct 2023 09:14:23 +0200 Subject: [PATCH 04/60] channeldb: add ChanneEdgeInfo and ChannelAuthProof interfaces Add new ChannelEdgeInfo and ChannelAuthProof interfaces and ensure that they are implemented by ChannelEdgeInfo1 and ChannelAuthProof respectively. --- channeldb/models/channel_auth_proof.go | 10 ++ channeldb/models/channel_edge_info.go | 167 +++++++++++++++++++++++++ channeldb/models/interfaces.go | 59 +++++++++ 3 files changed, 236 insertions(+) create mode 100644 channeldb/models/interfaces.go diff --git a/channeldb/models/channel_auth_proof.go b/channeldb/models/channel_auth_proof.go index 7b7922b7d4..2dc2bcec20 100644 --- a/channeldb/models/channel_auth_proof.go +++ b/channeldb/models/channel_auth_proof.go @@ -129,3 +129,13 @@ func (c *ChannelAuthProof1) IsEmpty() bool { len(c.BitcoinSig1Bytes) == 0 || len(c.BitcoinSig2Bytes) == 0 } + +// isChanAuthProof is a no-op method used to ensure that a struct must +// explicitly inherit this interface to be considered a ChannelAuthProof type. +// +// NOTE: this is part of the ChannelAuthProof interface. +func (c *ChannelAuthProof1) isChanAuthProof() {} + +// A compile-time check to ensure that ChannelAutoProof1 implements the +// ChannelAuthProof interface. +var _ ChannelAuthProof = (*ChannelAuthProof1)(nil) diff --git a/channeldb/models/channel_edge_info.go b/channeldb/models/channel_edge_info.go index d4b5b361f1..b5207c97dd 100644 --- a/channeldb/models/channel_edge_info.go +++ b/channeldb/models/channel_edge_info.go @@ -9,6 +9,8 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/fn" + "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/lnwire" ) // ChannelEdgeInfo1 represents a fully authenticated channel along with all its @@ -191,3 +193,168 @@ func (c *ChannelEdgeInfo1) OtherNodeKeyBytes(thisNodeKey []byte) ( "this channel") } } + +// Copy returns a copy of the ChannelEdgeInfo. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo1) Copy() ChannelEdgeInfo { + return &ChannelEdgeInfo1{ + ChannelID: c.ChannelID, + ChainHash: c.ChainHash, + NodeKey1Bytes: c.NodeKey1Bytes, + NodeKey2Bytes: c.NodeKey2Bytes, + BitcoinKey1Bytes: c.BitcoinKey1Bytes, + BitcoinKey2Bytes: c.BitcoinKey2Bytes, + Features: c.Features, + AuthProof: c.AuthProof, + ChannelPoint: c.ChannelPoint, + Capacity: c.Capacity, + ExtraOpaqueData: c.ExtraOpaqueData, + } +} + +// Node1Bytes returns bytes of the public key of node 1. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo1) Node1Bytes() [33]byte { + return c.NodeKey1Bytes +} + +// Node2Bytes returns bytes of the public key of node 2. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo1) Node2Bytes() [33]byte { + return c.NodeKey2Bytes +} + +// GetChainHash returns the hash of the genesis block of the chain that the edge +// is on. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo1) GetChainHash() chainhash.Hash { + return c.ChainHash +} + +// GetChanID returns the channel ID. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo1) GetChanID() uint64 { + return c.ChannelID +} + +// GetAuthProof returns the ChannelAuthProof for the edge. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo1) GetAuthProof() ChannelAuthProof { + // Cant just return AuthProof cause you then run into the + // nil interface gotcha. + if c.AuthProof == nil { + return nil + } + + return c.AuthProof +} + +// GetCapacity returns the capacity of the channel. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo1) GetCapacity() btcutil.Amount { + return c.Capacity +} + +// SetAuthProof sets the proof of the channel. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo1) SetAuthProof(proof ChannelAuthProof) error { + if proof == nil { + c.AuthProof = nil + + return nil + } + + p, ok := proof.(*ChannelAuthProof1) + if !ok { + return fmt.Errorf("expected type ChannelAuthProof1 for "+ + "ChannelEdgeInfo1, got %T", proof) + } + + c.AuthProof = p + + return nil +} + +// GetChanPoint returns the outpoint of the funding transaction of the channel. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo1) GetChanPoint() wire.OutPoint { + return c.ChannelPoint +} + +// FundingScript returns the pk script for the funding output of the +// channel. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo1) FundingScript() ([]byte, error) { + legacyFundingScript := func() ([]byte, error) { + witnessScript, err := input.GenMultiSigScript( + c.BitcoinKey1Bytes[:], c.BitcoinKey2Bytes[:], + ) + if err != nil { + return nil, err + } + pkScript, err := input.WitnessScriptHash(witnessScript) + if err != nil { + return nil, err + } + + return pkScript, nil + } + + if len(c.Features) == 0 { + return legacyFundingScript() + } + + // TODO(elle): remove this taproot funding script logic once + // ChannelEdgeInfo2 is being used. + + // In order to make the correct funding script, we'll need to parse the + // chanFeatures bytes into a feature vector we can interact with. + rawFeatures := lnwire.NewRawFeatureVector() + err := rawFeatures.Decode(bytes.NewReader(c.Features)) + if err != nil { + return nil, fmt.Errorf("unable to parse chan feature "+ + "bits: %w", err) + } + + chanFeatureBits := lnwire.NewFeatureVector( + rawFeatures, lnwire.Features, + ) + if chanFeatureBits.HasFeature( + lnwire.SimpleTaprootChannelsOptionalStaging, + ) { + + pubKey1, err := btcec.ParsePubKey(c.BitcoinKey1Bytes[:]) + if err != nil { + return nil, err + } + pubKey2, err := btcec.ParsePubKey(c.BitcoinKey2Bytes[:]) + if err != nil { + return nil, err + } + + fundingScript, _, err := input.GenTaprootFundingScript( + pubKey1, pubKey2, 0, fn.None[chainhash.Hash](), + ) + if err != nil { + return nil, err + } + + return fundingScript, nil + } + + return legacyFundingScript() +} + +// A compile-time check to ensure that ChannelEdgeInfo1 implements the +// ChannelEdgeInfo interface. +var _ ChannelEdgeInfo = (*ChannelEdgeInfo1)(nil) diff --git a/channeldb/models/interfaces.go b/channeldb/models/interfaces.go new file mode 100644 index 0000000000..fc4961e220 --- /dev/null +++ b/channeldb/models/interfaces.go @@ -0,0 +1,59 @@ +package models + +import ( + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/wire" +) + +// ChannelEdgeInfo is an interface that describes a channel announcement. +type ChannelEdgeInfo interface { //nolint:interfacebloat + // GetChainHash returns the hash of the genesis block of the chain that + // the edge is on. + GetChainHash() chainhash.Hash + + // GetChanID returns the channel ID. + GetChanID() uint64 + + // GetAuthProof returns the ChannelAuthProof for the edge. + GetAuthProof() ChannelAuthProof + + // GetCapacity returns the capacity of the channel. + GetCapacity() btcutil.Amount + + // SetAuthProof sets the proof of the channel. + SetAuthProof(ChannelAuthProof) error + + // NodeKey1 returns the public key of node 1. + NodeKey1() (*btcec.PublicKey, error) + + // NodeKey2 returns the public key of node 2. + NodeKey2() (*btcec.PublicKey, error) + + // Node1Bytes returns bytes of the public key of node 1. + Node1Bytes() [33]byte + + // Node2Bytes returns bytes the public key of node 2. + Node2Bytes() [33]byte + + // GetChanPoint returns the outpoint of the funding transaction of the + // channel. + GetChanPoint() wire.OutPoint + + // FundingScript returns the pk script for the funding output of the + // channel. + FundingScript() ([]byte, error) + + // Copy returns a copy of the ChannelEdgeInfo. + Copy() ChannelEdgeInfo +} + +// ChannelAuthProof is an interface that describes the proof of ownership of +// a channel. +type ChannelAuthProof interface { + // isChanAuthProof is a no-op method used to ensure that a struct must + // explicitly inherit this interface to be considered a + // ChannelAuthProof type. + isChanAuthProof() +} From 0e8fc7dc7a4b04a1f35523f601d6d18ede59543e Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 21 Aug 2024 12:15:26 +0200 Subject: [PATCH 05/60] channeldb: add ChannelEdgePolicy interface And ensure that ChannelEdgePolicy1 implements it. --- channeldb/models/channel_edge_policy.go | 85 +++++++++++++++++++++++++ channeldb/models/interfaces.go | 38 +++++++++++ 2 files changed, 123 insertions(+) diff --git a/channeldb/models/channel_edge_policy.go b/channeldb/models/channel_edge_policy.go index c4db39d7a4..42f09454c6 100644 --- a/channeldb/models/channel_edge_policy.go +++ b/channeldb/models/channel_edge_policy.go @@ -1,9 +1,11 @@ package models import ( + "fmt" "time" "github.com/btcsuite/btcd/btcec/v2/ecdsa" + "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lnwire" ) @@ -101,6 +103,8 @@ func (c *ChannelEdgePolicy1) SetSigBytes(sig []byte) { } // IsDisabled determines whether the edge has the disabled bit set. +// +// NOTE: This is part of the ChannelEdgePolicy interface. func (c *ChannelEdgePolicy1) IsDisabled() bool { return c.ChannelFlags.IsDisabled() } @@ -113,3 +117,84 @@ func (c *ChannelEdgePolicy1) ComputeFee( return c.FeeBaseMSat + (amt*c.FeeProportionalMillionths)/feeRateParts } + +// SCID returns the short channel ID of the channel being referred to. +// +// NOTE: This is part of the ChannelEdgePolicy interface. +func (c *ChannelEdgePolicy1) SCID() lnwire.ShortChannelID { + return lnwire.NewShortChanIDFromInt(c.ChannelID) +} + +// IsNode1 returns true if the update was constructed by node 1 of the +// channel. +// +// NOTE: This is part of the ChannelEdgePolicy interface. +func (c *ChannelEdgePolicy1) IsNode1() bool { + return c.ChannelFlags&lnwire.ChanUpdateDirection == 0 +} + +// GetToNode returns the pub key of the node that did not produce the update. +// +// NOTE: This is part of the ChannelEdgePolicy interface. +func (c *ChannelEdgePolicy1) GetToNode() [33]byte { + return c.ToNode +} + +// ForwardingPolicy return the various forwarding policy rules set by the +// update. +// +// NOTE: This is part of the ChannelEdgePolicy interface. +func (c *ChannelEdgePolicy1) ForwardingPolicy() *lnwire.ForwardingPolicy { + return &lnwire.ForwardingPolicy{ + TimeLockDelta: c.TimeLockDelta, + BaseFee: c.FeeBaseMSat, + FeeRate: c.FeeProportionalMillionths, + MinHTLC: c.MinHTLC, + HasMaxHTLC: c.MessageFlags.HasMaxHtlc(), + MaxHTLC: c.MaxHTLC, + } +} + +// Before compares this update against the passed update and returns true if +// this update has a lower timestamp than the passed one. +// +// NOTE: This is part of the ChannelEdgePolicy interface. +func (c *ChannelEdgePolicy1) Before(policy ChannelEdgePolicy) (bool, error) { + other, ok := policy.(*ChannelEdgePolicy1) + if !ok { + return false, fmt.Errorf("can't compare type %T to type "+ + "ChannelEdgePolicy1", policy) + } + + return c.LastUpdate.Before(other.LastUpdate), nil +} + +// AfterUpdateMsg compares this update against the passed +// lnwire.ChannelUpdate message and returns true if this update is newer than +// the passed one. +// +// NOTE: This is part of the ChannelEdgePolicy interface. +func (c *ChannelEdgePolicy1) AfterUpdateMsg(msg lnwire.ChannelUpdate) (bool, + error) { + + upd, ok := msg.(*lnwire.ChannelUpdate1) + if !ok { + return false, fmt.Errorf("expected *lnwire.ChannelUpdate1 to "+ + "be coupled with ChannelEdgePolicy1, got: %T", msg) + } + + timestamp := time.Unix(int64(upd.Timestamp), 0) + + return c.LastUpdate.After(timestamp), nil +} + +// Sig returns the signature of the update message. +// +// NOTE: This is part of the ChannelEdgePolicy interface. +func (c *ChannelEdgePolicy1) Sig() (input.Signature, error) { + return c.Signature() +} + +// A compile-time check to ensure that ChannelEdgePolicy1 implements the +// ChannelEdgePolicy interface. +var _ ChannelEdgePolicy = (*ChannelEdgePolicy1)(nil) diff --git a/channeldb/models/interfaces.go b/channeldb/models/interfaces.go index fc4961e220..f250bc95c6 100644 --- a/channeldb/models/interfaces.go +++ b/channeldb/models/interfaces.go @@ -5,6 +5,8 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" + "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/lnwire" ) // ChannelEdgeInfo is an interface that describes a channel announcement. @@ -57,3 +59,39 @@ type ChannelAuthProof interface { // ChannelAuthProof type. isChanAuthProof() } + +// ChannelEdgePolicy is an interface that describes an update to the forwarding +// rules of a channel. +type ChannelEdgePolicy interface { + // SCID returns the short channel ID of the channel being referred to. + SCID() lnwire.ShortChannelID + + // IsDisabled returns true if the update is indicating that the channel + // should be considered disabled. + IsDisabled() bool + + // IsNode1 returns true if the update was constructed by node 1 of the + // channel. + IsNode1() bool + + // GetToNode returns the pub key of the node that did not produce the + // update. + GetToNode() [33]byte + + // ForwardingPolicy return the various forwarding policy rules set by + // the update. + ForwardingPolicy() *lnwire.ForwardingPolicy + + // Before compares this update against the passed update and returns + // true if this update has a lower timestamp than the passed one. + Before(policy ChannelEdgePolicy) (bool, error) + + // AfterUpdateMsg compares this update against the passed + // lnwire.ChannelUpdate message and returns true if this update is + // newer than the passed one. + // TODO(elle): combine with Before? + AfterUpdateMsg(msg lnwire.ChannelUpdate) (bool, error) + + // Sig returns the signature of the update message. + Sig() (input.Signature, error) +} From 6165c9bbc6bec8ccdff69acedb8bbd85d572628a Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 27 Oct 2023 09:35:25 +0200 Subject: [PATCH 06/60] channeldb: add ChannelAuthProof2 --- channeldb/models/channel_auth_proof.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/channeldb/models/channel_auth_proof.go b/channeldb/models/channel_auth_proof.go index 2dc2bcec20..c4b1b4c2e3 100644 --- a/channeldb/models/channel_auth_proof.go +++ b/channeldb/models/channel_auth_proof.go @@ -139,3 +139,20 @@ func (c *ChannelAuthProof1) isChanAuthProof() {} // A compile-time check to ensure that ChannelAutoProof1 implements the // ChannelAuthProof interface. var _ ChannelAuthProof = (*ChannelAuthProof1)(nil) + +// ChannelAuthProof2 is the authentication proof required for a taproot channel +// announcement. It contains a single Schnorr signature. +type ChannelAuthProof2 struct { + // SchnorrSigBytes are the raw bytes of the encoded schnorr signature. + SchnorrSigBytes []byte +} + +// isChanAuthProof is a no-op method used to ensure that a struct must +// explicitly inherit this interface to be considered a ChannelAuthProof type. +// +// NOTE: this is part of the ChannelAuthProof interface. +func (c *ChannelAuthProof2) isChanAuthProof() {} + +// A compile-time check to ensure that ChannelAutoProof2 implements the +// ChannelAuthProof interface. +var _ ChannelAuthProof = (*ChannelAuthProof2)(nil) From 5a7591ba747b03866dfc12f3b2f9e6b0bd382d3f Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 27 Oct 2023 09:40:02 +0200 Subject: [PATCH 07/60] channeldb: add ChannelEdgeInfo2 And ensure that it implements the ChannelEdgeInfo interface. --- channeldb/models/channel_edge_info.go | 262 ++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) diff --git a/channeldb/models/channel_edge_info.go b/channeldb/models/channel_edge_info.go index b5207c97dd..4f01a3db68 100644 --- a/channeldb/models/channel_edge_info.go +++ b/channeldb/models/channel_edge_info.go @@ -5,12 +5,15 @@ import ( "fmt" "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/tlv" ) // ChannelEdgeInfo1 represents a fully authenticated channel along with all its @@ -358,3 +361,262 @@ func (c *ChannelEdgeInfo1) FundingScript() ([]byte, error) { // A compile-time check to ensure that ChannelEdgeInfo1 implements the // ChannelEdgeInfo interface. var _ ChannelEdgeInfo = (*ChannelEdgeInfo1)(nil) + +// ChannelEdgeInfo2 describes the information about a channel announced with +// lnwire.ChannelAnnouncement2 that we will persist. +type ChannelEdgeInfo2 struct { + lnwire.ChannelAnnouncement2 + + // ChannelPoint is the funding outpoint of the channel. This can be + // used to uniquely identify the channel within the channel graph. + ChannelPoint wire.OutPoint + + // FundingPkScript is the funding transaction's pk script. We persist + // this since there are some cases in which this will not be derivable + // using the contents of the announcement. In that case, we still want + // quick access to the funding script so that we can register for spend + // notifications. + FundingPkScript []byte + + // AuthProof is the authentication proof for this channel. + AuthProof *ChannelAuthProof2 + + nodeKey1 *btcec.PublicKey + nodeKey2 *btcec.PublicKey +} + +// Copy returns a copy of the ChannelEdgeInfo. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo2) Copy() ChannelEdgeInfo { + return &ChannelEdgeInfo2{ + ChannelAnnouncement2: lnwire.ChannelAnnouncement2{ + ChainHash: c.ChainHash, + Features: c.Features, + ShortChannelID: c.ShortChannelID, + Capacity: c.Capacity, + NodeID1: c.NodeID1, + NodeID2: c.NodeID2, + BitcoinKey1: c.BitcoinKey1, + BitcoinKey2: c.BitcoinKey2, + MerkleRootHash: c.MerkleRootHash, + ExtraOpaqueData: c.ExtraOpaqueData, + }, + ChannelPoint: c.ChannelPoint, + AuthProof: c.AuthProof, + } +} + +// Node1Bytes returns bytes of the public key of node 1. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo2) Node1Bytes() [33]byte { + return c.NodeID1.Val +} + +// Node2Bytes returns bytes of the public key of node 2. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo2) Node2Bytes() [33]byte { + return c.NodeID2.Val +} + +// GetChainHash returns the hash of the genesis block of the chain that the edge +// is on. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo2) GetChainHash() chainhash.Hash { + return c.ChainHash.Val +} + +// GetChanID returns the channel ID. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo2) GetChanID() uint64 { + return c.ShortChannelID.Val.ToUint64() +} + +// GetAuthProof returns the ChannelAuthProof for the edge. +// +// NOTE: this is part of the models.ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo2) GetAuthProof() ChannelAuthProof { + // Cant just return AuthProof cause you then run into the + // nil interface gotcha. + if c.AuthProof == nil { + return nil + } + + return c.AuthProof +} + +// GetCapacity returns the capacity of the channel. +// +// NOTE: this is part of the models.ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo2) GetCapacity() btcutil.Amount { + return btcutil.Amount(c.Capacity.Val) +} + +// SetAuthProof sets the proof of the channel. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo2) SetAuthProof(proof ChannelAuthProof) error { + if proof == nil { + c.AuthProof = nil + + return nil + } + + p, ok := proof.(*ChannelAuthProof2) + if !ok { + return fmt.Errorf("expected type ChannelAuthProof2 for "+ + "ChannelEdgeInfo2, got %T", proof) + } + + c.AuthProof = p + + return nil +} + +// GetChanPoint returns the outpoint of the funding transaction of the channel. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo2) GetChanPoint() wire.OutPoint { + return c.ChannelPoint +} + +// FundingScript returns the pk script for the funding output of the +// channel. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo2) FundingScript() ([]byte, error) { + var ( + pubKey1 *btcec.PublicKey + pubKey2 *btcec.PublicKey + err error + ) + c.BitcoinKey1.WhenSome(func(key tlv.RecordT[tlv.TlvType12, [33]byte]) { + pubKey1, err = btcec.ParsePubKey(key.Val[:]) + }) + if err != nil { + return nil, err + } + + c.BitcoinKey2.WhenSome(func(key tlv.RecordT[tlv.TlvType14, [33]byte]) { + pubKey2, err = btcec.ParsePubKey(key.Val[:]) + }) + if err != nil { + return nil, err + } + + // If both bitcoin keys are not present in the announcement, then we + // should previously have stored the funding script found on-chain. + if pubKey1 == nil || pubKey2 == nil { + if len(c.FundingPkScript) == 0 { + return nil, fmt.Errorf("expected a funding pk script " + + "since no bitcoin keys were provided") + } + + return c.FundingPkScript, nil + } + + // Initially we set the tweak to an empty byte array. If a merkle root + // hash is provided in the announcement then we use that to set the + // tweak but otherwise, the empty tweak will have the same effect as a + // BIP86 tweak. + var tweak []byte + c.MerkleRootHash.WhenSome( + func(hash tlv.RecordT[tlv.TlvType16, [32]byte]) { + tweak = hash.Val[:] + }, + ) + + // Calculate the internal key by computing the MuSig2 combination of the + // two public keys. + internalKey, _, _, err := musig2.AggregateKeys( + []*btcec.PublicKey{pubKey1, pubKey2}, true, + ) + if err != nil { + return nil, err + } + + // Now, determine the tweak to be added to the internal key. If the + // tweak is empty, then this will effectively be a BIP86 tweak. + tapTweakHash := chainhash.TaggedHash( + chainhash.TagTapTweak, schnorr.SerializePubKey( + internalKey.FinalKey, + ), tweak, + ) + + // Compute the final output key. + combinedKey, _, _, err := musig2.AggregateKeys( + []*btcec.PublicKey{pubKey1, pubKey2}, true, + musig2.WithKeyTweaks(musig2.KeyTweakDesc{ + Tweak: *tapTweakHash, + IsXOnly: true, + }), + ) + if err != nil { + return nil, err + } + + // Now that we have the combined key, we can create a taproot pkScript + // from this, and then make the txout given the amount. + fundingScript, err := input.PayToTaprootScript(combinedKey.FinalKey) + if err != nil { + return nil, fmt.Errorf("unable to make taproot pkscript: %w", + err) + } + + return fundingScript, nil +} + +// NodeKey1 is the identity public key of the "first" node that was involved in +// the creation of this channel. A node is considered "first" if the +// lexicographical ordering the its serialized public key is "smaller" than +// that of the other node involved in channel creation. +// +// NOTE: By having this method to access an attribute, we ensure we only need +// to fully deserialize the pubkey if absolutely necessary. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo2) NodeKey1() (*btcec.PublicKey, error) { + if c.nodeKey1 != nil { + return c.nodeKey1, nil + } + + key, err := btcec.ParsePubKey(c.NodeID1.Val[:]) + if err != nil { + return nil, err + } + c.nodeKey1 = key + + return key, nil +} + +// NodeKey2 is the identity public key of the "second" node that was +// involved in the creation of this channel. A node is considered +// "second" if the lexicographical ordering the its serialized public +// key is "larger" than that of the other node involved in channel +// creation. +// +// NOTE: By having this method to access an attribute, we ensure we only need +// to fully deserialize the pubkey if absolutely necessary. +// +// NOTE: this is part of the ChannelEdgeInfo interface. +func (c *ChannelEdgeInfo2) NodeKey2() (*btcec.PublicKey, error) { + if c.nodeKey2 != nil { + return c.nodeKey2, nil + } + + key, err := btcec.ParsePubKey(c.NodeID2.Val[:]) + if err != nil { + return nil, err + } + c.nodeKey2 = key + + return key, nil +} + +// A compile-time check to ensure that ChannelEdgeInfo2 implements the +// ChannelEdgeInfo interface. +var _ ChannelEdgeInfo = (*ChannelEdgeInfo2)(nil) From 5b8b7be9608fa161426b4afefd9865595cad0455 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 27 Oct 2023 09:49:49 +0200 Subject: [PATCH 08/60] channeldb: add ChannelEdgePolicy2 And ensure that it implements the ChannelEdgePoicy interface. --- channeldb/models/channel_edge_policy.go | 54 +++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/channeldb/models/channel_edge_policy.go b/channeldb/models/channel_edge_policy.go index 42f09454c6..1393b94772 100644 --- a/channeldb/models/channel_edge_policy.go +++ b/channeldb/models/channel_edge_policy.go @@ -198,3 +198,57 @@ func (c *ChannelEdgePolicy1) Sig() (input.Signature, error) { // A compile-time check to ensure that ChannelEdgePolicy1 implements the // ChannelEdgePolicy interface. var _ ChannelEdgePolicy = (*ChannelEdgePolicy1)(nil) + +type ChannelEdgePolicy2 struct { + lnwire.ChannelUpdate2 + + ToNode [33]byte +} + +// Sig returns the signature of the update message. +// +// NOTE: This is part of the ChannelEdgePolicy interface. +func (c *ChannelEdgePolicy2) Sig() (input.Signature, error) { + return c.Signature.ToSignature() +} + +// AfterUpdateMsg compares this update against the passed lnwire.ChannelUpdate +// message and returns true if this update is newer than the passed one. +// +// NOTE: This is part of the ChannelEdgePolicy interface. +func (c *ChannelEdgePolicy2) AfterUpdateMsg(msg lnwire.ChannelUpdate) (bool, + error) { + + upd, ok := msg.(*lnwire.ChannelUpdate2) + if !ok { + return false, fmt.Errorf("expected *lnwire.ChannelUpdate2 to "+ + "be coupled with ChannelEdgePolicy2, got: %T", msg) + } + + return c.BlockHeight.Val > upd.BlockHeight.Val, nil +} + +// Before compares this update against the passed update and returns true if +// this update has a lower timestamp than the passed one. +// +// NOTE: This is part of the ChannelEdgePolicy interface. +func (c *ChannelEdgePolicy2) Before(policy ChannelEdgePolicy) (bool, error) { + other, ok := policy.(*ChannelEdgePolicy2) + if !ok { + return false, fmt.Errorf("can't compare type %T to type "+ + "ChannelEdgePolicy2", policy) + } + + return c.BlockHeight.Val < other.BlockHeight.Val, nil +} + +// GetToNode returns the pub key of the node that did not produce the update. +// +// NOTE: This is part of the ChannelEdgePolicy interface. +func (c *ChannelEdgePolicy2) GetToNode() [33]byte { + return c.ToNode +} + +// A compile-time check to ensure that ChannelEdgePolicy2 implements the +// ChannelEdgePolicy interface. +var _ ChannelEdgePolicy = (*ChannelEdgePolicy2)(nil) From d4bdbe84769fc753a5ec0654bfb9a777b28d2e58 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 21 Aug 2024 12:20:53 +0200 Subject: [PATCH 09/60] channeldb+refactor: move ser/deser funcs to separate files This commit moves the serialisation, deserialisation and update functions for ChannelEdgePolicy1 and ChannelEdgeInfo1 into their own files. --- channeldb/edge_info.go | 169 +++++++++++++ channeldb/edge_policy.go | 375 ++++++++++++++++++++++++++++ channeldb/graph.go | 509 --------------------------------------- 3 files changed, 544 insertions(+), 509 deletions(-) create mode 100644 channeldb/edge_info.go create mode 100644 channeldb/edge_policy.go diff --git a/channeldb/edge_info.go b/channeldb/edge_info.go new file mode 100644 index 0000000000..2b0d85c73d --- /dev/null +++ b/channeldb/edge_info.go @@ -0,0 +1,169 @@ +package channeldb + +import ( + "bytes" + "encoding/binary" + "errors" + "io" + + "github.com/btcsuite/btcd/wire" + "github.com/lightningnetwork/lnd/channeldb/models" + "github.com/lightningnetwork/lnd/kvdb" +) + +func putChanEdgeInfo(edgeIndex kvdb.RwBucket, + edgeInfo *models.ChannelEdgeInfo1, chanID [8]byte) error { + + var b bytes.Buffer + + if _, err := b.Write(edgeInfo.NodeKey1Bytes[:]); err != nil { + return err + } + if _, err := b.Write(edgeInfo.NodeKey2Bytes[:]); err != nil { + return err + } + if _, err := b.Write(edgeInfo.BitcoinKey1Bytes[:]); err != nil { + return err + } + if _, err := b.Write(edgeInfo.BitcoinKey2Bytes[:]); err != nil { + return err + } + + if err := wire.WriteVarBytes(&b, 0, edgeInfo.Features); err != nil { + return err + } + + authProof := edgeInfo.AuthProof + var nodeSig1, nodeSig2, bitcoinSig1, bitcoinSig2 []byte + if authProof != nil { + nodeSig1 = authProof.NodeSig1Bytes + nodeSig2 = authProof.NodeSig2Bytes + bitcoinSig1 = authProof.BitcoinSig1Bytes + bitcoinSig2 = authProof.BitcoinSig2Bytes + } + + if err := wire.WriteVarBytes(&b, 0, nodeSig1); err != nil { + return err + } + if err := wire.WriteVarBytes(&b, 0, nodeSig2); err != nil { + return err + } + if err := wire.WriteVarBytes(&b, 0, bitcoinSig1); err != nil { + return err + } + if err := wire.WriteVarBytes(&b, 0, bitcoinSig2); err != nil { + return err + } + + if err := writeOutpoint(&b, &edgeInfo.ChannelPoint); err != nil { + return err + } + if err := binary.Write(&b, byteOrder, uint64(edgeInfo.Capacity)); err != nil { + return err + } + if _, err := b.Write(chanID[:]); err != nil { + return err + } + if _, err := b.Write(edgeInfo.ChainHash[:]); err != nil { + return err + } + + if len(edgeInfo.ExtraOpaqueData) > MaxAllowedExtraOpaqueBytes { + return ErrTooManyExtraOpaqueBytes(len(edgeInfo.ExtraOpaqueData)) + } + err := wire.WriteVarBytes(&b, 0, edgeInfo.ExtraOpaqueData) + if err != nil { + return err + } + + return edgeIndex.Put(chanID[:], b.Bytes()) +} + +func fetchChanEdgeInfo(edgeIndex kvdb.RBucket, + chanID []byte) (models.ChannelEdgeInfo1, error) { + + edgeInfoBytes := edgeIndex.Get(chanID) + if edgeInfoBytes == nil { + return models.ChannelEdgeInfo1{}, ErrEdgeNotFound + } + + edgeInfoReader := bytes.NewReader(edgeInfoBytes) + return deserializeChanEdgeInfo(edgeInfoReader) +} + +func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo1, error) { + var ( + err error + edgeInfo models.ChannelEdgeInfo1 + ) + + if _, err := io.ReadFull(r, edgeInfo.NodeKey1Bytes[:]); err != nil { + return models.ChannelEdgeInfo1{}, err + } + if _, err := io.ReadFull(r, edgeInfo.NodeKey2Bytes[:]); err != nil { + return models.ChannelEdgeInfo1{}, err + } + if _, err := io.ReadFull(r, edgeInfo.BitcoinKey1Bytes[:]); err != nil { + return models.ChannelEdgeInfo1{}, err + } + if _, err := io.ReadFull(r, edgeInfo.BitcoinKey2Bytes[:]); err != nil { + return models.ChannelEdgeInfo1{}, err + } + + edgeInfo.Features, err = wire.ReadVarBytes(r, 0, 900, "features") + if err != nil { + return models.ChannelEdgeInfo1{}, err + } + + proof := &models.ChannelAuthProof1{} + + proof.NodeSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") + if err != nil { + return models.ChannelEdgeInfo1{}, err + } + proof.NodeSig2Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") + if err != nil { + return models.ChannelEdgeInfo1{}, err + } + proof.BitcoinSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") + if err != nil { + return models.ChannelEdgeInfo1{}, err + } + proof.BitcoinSig2Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") + if err != nil { + return models.ChannelEdgeInfo1{}, err + } + + if !proof.IsEmpty() { + edgeInfo.AuthProof = proof + } + + edgeInfo.ChannelPoint = wire.OutPoint{} + if err := readOutpoint(r, &edgeInfo.ChannelPoint); err != nil { + return models.ChannelEdgeInfo1{}, err + } + if err := binary.Read(r, byteOrder, &edgeInfo.Capacity); err != nil { + return models.ChannelEdgeInfo1{}, err + } + if err := binary.Read(r, byteOrder, &edgeInfo.ChannelID); err != nil { + return models.ChannelEdgeInfo1{}, err + } + + if _, err := io.ReadFull(r, edgeInfo.ChainHash[:]); err != nil { + return models.ChannelEdgeInfo1{}, err + } + + // We'll try and see if there are any opaque bytes left, if not, then + // we'll ignore the EOF error and return the edge as is. + edgeInfo.ExtraOpaqueData, err = wire.ReadVarBytes( + r, 0, MaxAllowedExtraOpaqueBytes, "blob", + ) + switch { + case errors.Is(err, io.ErrUnexpectedEOF): + case errors.Is(err, io.EOF): + case err != nil: + return models.ChannelEdgeInfo1{}, err + } + + return edgeInfo, nil +} diff --git a/channeldb/edge_policy.go b/channeldb/edge_policy.go new file mode 100644 index 0000000000..113059a2d4 --- /dev/null +++ b/channeldb/edge_policy.go @@ -0,0 +1,375 @@ +package channeldb + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "time" + + "github.com/btcsuite/btcd/wire" + "github.com/lightningnetwork/lnd/channeldb/models" + "github.com/lightningnetwork/lnd/kvdb" + "github.com/lightningnetwork/lnd/lnwire" +) + +func putChanEdgePolicy(edges kvdb.RwBucket, edge *models.ChannelEdgePolicy1, + from, to []byte) error { + + var edgeKey [33 + 8]byte + copy(edgeKey[:], from) + byteOrder.PutUint64(edgeKey[33:], edge.ChannelID) + + var b bytes.Buffer + if err := serializeChanEdgePolicy(&b, edge, to); err != nil { + return err + } + + // Before we write out the new edge, we'll create a new entry in the + // update index in order to keep it fresh. + updateUnix := uint64(edge.LastUpdate.Unix()) + var indexKey [8 + 8]byte + byteOrder.PutUint64(indexKey[:8], updateUnix) + byteOrder.PutUint64(indexKey[8:], edge.ChannelID) + + updateIndex, err := edges.CreateBucketIfNotExists(edgeUpdateIndexBucket) + if err != nil { + return err + } + + // If there was already an entry for this edge, then we'll need to + // delete the old one to ensure we don't leave around any after-images. + // An unknown policy value does not have a update time recorded, so + // it also does not need to be removed. + if edgeBytes := edges.Get(edgeKey[:]); edgeBytes != nil && + !bytes.Equal(edgeBytes, unknownPolicy) { + + // In order to delete the old entry, we'll need to obtain the + // *prior* update time in order to delete it. To do this, we'll + // need to deserialize the existing policy within the database + // (now outdated by the new one), and delete its corresponding + // entry within the update index. We'll ignore any + // ErrEdgePolicyOptionalFieldNotFound error, as we only need + // the channel ID and update time to delete the entry. + // TODO(halseth): get rid of these invalid policies in a + // migration. + oldEdgePolicy, err := deserializeChanEdgePolicy( + bytes.NewReader(edgeBytes), + ) + if err != nil && + !errors.Is(err, ErrEdgePolicyOptionalFieldNotFound) { + + return err + } + + oldUpdateTime := uint64(oldEdgePolicy.LastUpdate.Unix()) + + var oldIndexKey [8 + 8]byte + byteOrder.PutUint64(oldIndexKey[:8], oldUpdateTime) + byteOrder.PutUint64(oldIndexKey[8:], edge.ChannelID) + + if err := updateIndex.Delete(oldIndexKey[:]); err != nil { + return err + } + } + + if err := updateIndex.Put(indexKey[:], nil); err != nil { + return err + } + + err = updateEdgePolicyDisabledIndex( + edges, edge.ChannelID, + edge.ChannelFlags&lnwire.ChanUpdateDirection > 0, + edge.IsDisabled(), + ) + if err != nil { + return err + } + + return edges.Put(edgeKey[:], b.Bytes()) +} + +// updateEdgePolicyDisabledIndex is used to update the disabledEdgePolicyIndex +// bucket by either add a new disabled ChannelEdgePolicy1 or remove an existing +// one. +// The direction represents the direction of the edge and disabled is used for +// deciding whether to remove or add an entry to the bucket. +// In general a channel is disabled if two entries for the same chanID exist +// in this bucket. +// Maintaining the bucket this way allows a fast retrieval of disabled +// channels, for example when prune is needed. +func updateEdgePolicyDisabledIndex(edges kvdb.RwBucket, chanID uint64, + direction bool, disabled bool) error { + + var disabledEdgeKey [8 + 1]byte + byteOrder.PutUint64(disabledEdgeKey[0:], chanID) + if direction { + disabledEdgeKey[8] = 1 + } + + disabledEdgePolicyIndex, err := edges.CreateBucketIfNotExists( + disabledEdgePolicyBucket, + ) + if err != nil { + return err + } + + if disabled { + return disabledEdgePolicyIndex.Put(disabledEdgeKey[:], []byte{}) + } + + return disabledEdgePolicyIndex.Delete(disabledEdgeKey[:]) +} + +// putChanEdgePolicyUnknown marks the edge policy as unknown +// in the edges bucket. +func putChanEdgePolicyUnknown(edges kvdb.RwBucket, channelID uint64, + from []byte) error { + + var edgeKey [33 + 8]byte + copy(edgeKey[:], from) + byteOrder.PutUint64(edgeKey[33:], channelID) + + if edges.Get(edgeKey[:]) != nil { + return fmt.Errorf("cannot write unknown policy for channel %v "+ + " when there is already a policy present", channelID) + } + + return edges.Put(edgeKey[:], unknownPolicy) +} + +func fetchChanEdgePolicy(edges kvdb.RBucket, chanID []byte, + nodePub []byte) (*models.ChannelEdgePolicy1, error) { + + var edgeKey [33 + 8]byte + copy(edgeKey[:], nodePub) + copy(edgeKey[33:], chanID) + + edgeBytes := edges.Get(edgeKey[:]) + if edgeBytes == nil { + return nil, ErrEdgeNotFound + } + + // No need to deserialize unknown policy. + if bytes.Equal(edgeBytes, unknownPolicy) { + return nil, nil + } + + edgeReader := bytes.NewReader(edgeBytes) + + ep, err := deserializeChanEdgePolicy(edgeReader) + switch { + // If the db policy was missing an expected optional field, we return + // nil as if the policy was unknown. + case errors.Is(err, ErrEdgePolicyOptionalFieldNotFound): + return nil, nil + + case err != nil: + return nil, err + } + + return ep, nil +} + +func fetchChanEdgePolicies(edgeIndex kvdb.RBucket, edges kvdb.RBucket, + chanID []byte) (*models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, + error) { + + edgeInfo := edgeIndex.Get(chanID) + if edgeInfo == nil { + return nil, nil, fmt.Errorf("%w: chanID=%x", ErrEdgeNotFound, + chanID) + } + + // The first node is contained within the first half of the edge + // information. We only propagate the error here and below if it's + // something other than edge non-existence. + node1Pub := edgeInfo[:33] + edge1, err := fetchChanEdgePolicy(edges, chanID, node1Pub) + if err != nil { + return nil, nil, fmt.Errorf("%w: node1Pub=%x", ErrEdgeNotFound, + node1Pub) + } + + // Similarly, the second node is contained within the latter + // half of the edge information. + node2Pub := edgeInfo[33:66] + edge2, err := fetchChanEdgePolicy(edges, chanID, node2Pub) + if err != nil { + return nil, nil, fmt.Errorf("%w: node2Pub=%x", ErrEdgeNotFound, + node2Pub) + } + + return edge1, edge2, nil +} + +func serializeChanEdgePolicy(w io.Writer, edge *models.ChannelEdgePolicy1, + to []byte) error { + + err := wire.WriteVarBytes(w, 0, edge.SigBytes) + if err != nil { + return err + } + + if err := binary.Write(w, byteOrder, edge.ChannelID); err != nil { + return err + } + + var scratch [8]byte + updateUnix := uint64(edge.LastUpdate.Unix()) + byteOrder.PutUint64(scratch[:], updateUnix) + if _, err := w.Write(scratch[:]); err != nil { + return err + } + + if err := binary.Write(w, byteOrder, edge.MessageFlags); err != nil { + return err + } + if err := binary.Write(w, byteOrder, edge.ChannelFlags); err != nil { + return err + } + if err := binary.Write(w, byteOrder, edge.TimeLockDelta); err != nil { + return err + } + if err := binary.Write(w, byteOrder, uint64(edge.MinHTLC)); err != nil { + return err + } + err = binary.Write(w, byteOrder, uint64(edge.FeeBaseMSat)) + if err != nil { + return err + } + err = binary.Write(w, byteOrder, uint64(edge.FeeProportionalMillionths)) + if err != nil { + return err + } + + if _, err := w.Write(to); err != nil { + return err + } + + // If the max_htlc field is present, we write it. To be compatible with + // older versions that wasn't aware of this field, we write it as part + // of the opaque data. + // TODO(halseth): clean up when moving to TLV. + var opaqueBuf bytes.Buffer + if edge.MessageFlags.HasMaxHtlc() { + err := binary.Write(&opaqueBuf, byteOrder, uint64(edge.MaxHTLC)) + if err != nil { + return err + } + } + + if len(edge.ExtraOpaqueData) > MaxAllowedExtraOpaqueBytes { + return ErrTooManyExtraOpaqueBytes(len(edge.ExtraOpaqueData)) + } + if _, err := opaqueBuf.Write(edge.ExtraOpaqueData); err != nil { + return err + } + + if err := wire.WriteVarBytes(w, 0, opaqueBuf.Bytes()); err != nil { + return err + } + + return nil +} + +func deserializeChanEdgePolicy(r io.Reader) (*models.ChannelEdgePolicy1, error) { + // Deserialize the policy. Note that in case an optional field is not + // found, both an error and a populated policy object are returned. + edge, deserializeErr := deserializeChanEdgePolicyRaw(r) + if deserializeErr != nil && + !errors.Is(deserializeErr, ErrEdgePolicyOptionalFieldNotFound) { + + return nil, deserializeErr + } + + return edge, deserializeErr +} + +func deserializeChanEdgePolicyRaw(r io.Reader) (*models.ChannelEdgePolicy1, + error) { + + edge := &models.ChannelEdgePolicy1{} + + var err error + edge.SigBytes, err = wire.ReadVarBytes(r, 0, 80, "sig") + if err != nil { + return nil, err + } + + if err := binary.Read(r, byteOrder, &edge.ChannelID); err != nil { + return nil, err + } + + var scratch [8]byte + if _, err := r.Read(scratch[:]); err != nil { + return nil, err + } + unix := int64(byteOrder.Uint64(scratch[:])) + edge.LastUpdate = time.Unix(unix, 0) + + if err := binary.Read(r, byteOrder, &edge.MessageFlags); err != nil { + return nil, err + } + if err := binary.Read(r, byteOrder, &edge.ChannelFlags); err != nil { + return nil, err + } + if err := binary.Read(r, byteOrder, &edge.TimeLockDelta); err != nil { + return nil, err + } + + var n uint64 + if err := binary.Read(r, byteOrder, &n); err != nil { + return nil, err + } + edge.MinHTLC = lnwire.MilliSatoshi(n) + + if err := binary.Read(r, byteOrder, &n); err != nil { + return nil, err + } + edge.FeeBaseMSat = lnwire.MilliSatoshi(n) + + if err := binary.Read(r, byteOrder, &n); err != nil { + return nil, err + } + edge.FeeProportionalMillionths = lnwire.MilliSatoshi(n) + + if _, err := r.Read(edge.ToNode[:]); err != nil { + return nil, err + } + + // We'll try and see if there are any opaque bytes left, if not, then + // we'll ignore the EOF error and return the edge as is. + edge.ExtraOpaqueData, err = wire.ReadVarBytes( + r, 0, MaxAllowedExtraOpaqueBytes, "blob", + ) + switch { + case errors.Is(err, io.ErrUnexpectedEOF): + case errors.Is(err, io.EOF): + case err != nil: + return nil, err + } + + // See if optional fields are present. + if edge.MessageFlags.HasMaxHtlc() { + // The max_htlc field should be at the beginning of the opaque + // bytes. + opq := edge.ExtraOpaqueData + + // If the max_htlc field is not present, it might be old data + // stored before this field was validated. We'll return the + // edge along with an error. + if len(opq) < 8 { + return edge, ErrEdgePolicyOptionalFieldNotFound + } + + maxHtlc := byteOrder.Uint64(opq[:8]) + edge.MaxHTLC = lnwire.MilliSatoshi(maxHtlc) + + // Exclude the parsed field from the rest of the opaque data. + edge.ExtraOpaqueData = opq[8:] + } + + return edge, nil +} diff --git a/channeldb/graph.go b/channeldb/graph.go index 522077cdb0..3143c1db56 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -4232,512 +4232,3 @@ func deserializeLightningNode(r io.Reader) (LightningNode, error) { return node, nil } - -func putChanEdgeInfo(edgeIndex kvdb.RwBucket, - edgeInfo *models.ChannelEdgeInfo1, chanID [8]byte) error { - - var b bytes.Buffer - - if _, err := b.Write(edgeInfo.NodeKey1Bytes[:]); err != nil { - return err - } - if _, err := b.Write(edgeInfo.NodeKey2Bytes[:]); err != nil { - return err - } - if _, err := b.Write(edgeInfo.BitcoinKey1Bytes[:]); err != nil { - return err - } - if _, err := b.Write(edgeInfo.BitcoinKey2Bytes[:]); err != nil { - return err - } - - if err := wire.WriteVarBytes(&b, 0, edgeInfo.Features); err != nil { - return err - } - - authProof := edgeInfo.AuthProof - var nodeSig1, nodeSig2, bitcoinSig1, bitcoinSig2 []byte - if authProof != nil { - nodeSig1 = authProof.NodeSig1Bytes - nodeSig2 = authProof.NodeSig2Bytes - bitcoinSig1 = authProof.BitcoinSig1Bytes - bitcoinSig2 = authProof.BitcoinSig2Bytes - } - - if err := wire.WriteVarBytes(&b, 0, nodeSig1); err != nil { - return err - } - if err := wire.WriteVarBytes(&b, 0, nodeSig2); err != nil { - return err - } - if err := wire.WriteVarBytes(&b, 0, bitcoinSig1); err != nil { - return err - } - if err := wire.WriteVarBytes(&b, 0, bitcoinSig2); err != nil { - return err - } - - if err := writeOutpoint(&b, &edgeInfo.ChannelPoint); err != nil { - return err - } - if err := binary.Write(&b, byteOrder, uint64(edgeInfo.Capacity)); err != nil { - return err - } - if _, err := b.Write(chanID[:]); err != nil { - return err - } - if _, err := b.Write(edgeInfo.ChainHash[:]); err != nil { - return err - } - - if len(edgeInfo.ExtraOpaqueData) > MaxAllowedExtraOpaqueBytes { - return ErrTooManyExtraOpaqueBytes(len(edgeInfo.ExtraOpaqueData)) - } - err := wire.WriteVarBytes(&b, 0, edgeInfo.ExtraOpaqueData) - if err != nil { - return err - } - - return edgeIndex.Put(chanID[:], b.Bytes()) -} - -func fetchChanEdgeInfo(edgeIndex kvdb.RBucket, - chanID []byte) (models.ChannelEdgeInfo1, error) { - - edgeInfoBytes := edgeIndex.Get(chanID) - if edgeInfoBytes == nil { - return models.ChannelEdgeInfo1{}, ErrEdgeNotFound - } - - edgeInfoReader := bytes.NewReader(edgeInfoBytes) - return deserializeChanEdgeInfo(edgeInfoReader) -} - -func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo1, error) { - var ( - err error - edgeInfo models.ChannelEdgeInfo1 - ) - - if _, err := io.ReadFull(r, edgeInfo.NodeKey1Bytes[:]); err != nil { - return models.ChannelEdgeInfo1{}, err - } - if _, err := io.ReadFull(r, edgeInfo.NodeKey2Bytes[:]); err != nil { - return models.ChannelEdgeInfo1{}, err - } - if _, err := io.ReadFull(r, edgeInfo.BitcoinKey1Bytes[:]); err != nil { - return models.ChannelEdgeInfo1{}, err - } - if _, err := io.ReadFull(r, edgeInfo.BitcoinKey2Bytes[:]); err != nil { - return models.ChannelEdgeInfo1{}, err - } - - edgeInfo.Features, err = wire.ReadVarBytes(r, 0, 900, "features") - if err != nil { - return models.ChannelEdgeInfo1{}, err - } - - proof := &models.ChannelAuthProof1{} - - proof.NodeSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") - if err != nil { - return models.ChannelEdgeInfo1{}, err - } - proof.NodeSig2Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") - if err != nil { - return models.ChannelEdgeInfo1{}, err - } - proof.BitcoinSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") - if err != nil { - return models.ChannelEdgeInfo1{}, err - } - proof.BitcoinSig2Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") - if err != nil { - return models.ChannelEdgeInfo1{}, err - } - - if !proof.IsEmpty() { - edgeInfo.AuthProof = proof - } - - edgeInfo.ChannelPoint = wire.OutPoint{} - if err := readOutpoint(r, &edgeInfo.ChannelPoint); err != nil { - return models.ChannelEdgeInfo1{}, err - } - if err := binary.Read(r, byteOrder, &edgeInfo.Capacity); err != nil { - return models.ChannelEdgeInfo1{}, err - } - if err := binary.Read(r, byteOrder, &edgeInfo.ChannelID); err != nil { - return models.ChannelEdgeInfo1{}, err - } - - if _, err := io.ReadFull(r, edgeInfo.ChainHash[:]); err != nil { - return models.ChannelEdgeInfo1{}, err - } - - // We'll try and see if there are any opaque bytes left, if not, then - // we'll ignore the EOF error and return the edge as is. - edgeInfo.ExtraOpaqueData, err = wire.ReadVarBytes( - r, 0, MaxAllowedExtraOpaqueBytes, "blob", - ) - switch { - case err == io.ErrUnexpectedEOF: - case err == io.EOF: - case err != nil: - return models.ChannelEdgeInfo1{}, err - } - - return edgeInfo, nil -} - -func putChanEdgePolicy(edges kvdb.RwBucket, edge *models.ChannelEdgePolicy1, - from, to []byte) error { - - var edgeKey [33 + 8]byte - copy(edgeKey[:], from) - byteOrder.PutUint64(edgeKey[33:], edge.ChannelID) - - var b bytes.Buffer - if err := serializeChanEdgePolicy(&b, edge, to); err != nil { - return err - } - - // Before we write out the new edge, we'll create a new entry in the - // update index in order to keep it fresh. - updateUnix := uint64(edge.LastUpdate.Unix()) - var indexKey [8 + 8]byte - byteOrder.PutUint64(indexKey[:8], updateUnix) - byteOrder.PutUint64(indexKey[8:], edge.ChannelID) - - updateIndex, err := edges.CreateBucketIfNotExists(edgeUpdateIndexBucket) - if err != nil { - return err - } - - // If there was already an entry for this edge, then we'll need to - // delete the old one to ensure we don't leave around any after-images. - // An unknown policy value does not have a update time recorded, so - // it also does not need to be removed. - if edgeBytes := edges.Get(edgeKey[:]); edgeBytes != nil && - !bytes.Equal(edgeBytes[:], unknownPolicy) { - - // In order to delete the old entry, we'll need to obtain the - // *prior* update time in order to delete it. To do this, we'll - // need to deserialize the existing policy within the database - // (now outdated by the new one), and delete its corresponding - // entry within the update index. We'll ignore any - // ErrEdgePolicyOptionalFieldNotFound error, as we only need - // the channel ID and update time to delete the entry. - // TODO(halseth): get rid of these invalid policies in a - // migration. - oldEdgePolicy, err := deserializeChanEdgePolicy( - bytes.NewReader(edgeBytes), - ) - if err != nil && err != ErrEdgePolicyOptionalFieldNotFound { - return err - } - - oldUpdateTime := uint64(oldEdgePolicy.LastUpdate.Unix()) - - var oldIndexKey [8 + 8]byte - byteOrder.PutUint64(oldIndexKey[:8], oldUpdateTime) - byteOrder.PutUint64(oldIndexKey[8:], edge.ChannelID) - - if err := updateIndex.Delete(oldIndexKey[:]); err != nil { - return err - } - } - - if err := updateIndex.Put(indexKey[:], nil); err != nil { - return err - } - - updateEdgePolicyDisabledIndex( - edges, edge.ChannelID, - edge.ChannelFlags&lnwire.ChanUpdateDirection > 0, - edge.IsDisabled(), - ) - - return edges.Put(edgeKey[:], b.Bytes()[:]) -} - -// updateEdgePolicyDisabledIndex is used to update the disabledEdgePolicyIndex -// bucket by either add a new disabled ChannelEdgePolicy1 or remove an existing -// one. -// The direction represents the direction of the edge and disabled is used for -// deciding whether to remove or add an entry to the bucket. -// In general a channel is disabled if two entries for the same chanID exist -// in this bucket. -// Maintaining the bucket this way allows a fast retrieval of disabled -// channels, for example when prune is needed. -func updateEdgePolicyDisabledIndex(edges kvdb.RwBucket, chanID uint64, - direction bool, disabled bool) error { - - var disabledEdgeKey [8 + 1]byte - byteOrder.PutUint64(disabledEdgeKey[0:], chanID) - if direction { - disabledEdgeKey[8] = 1 - } - - disabledEdgePolicyIndex, err := edges.CreateBucketIfNotExists( - disabledEdgePolicyBucket, - ) - if err != nil { - return err - } - - if disabled { - return disabledEdgePolicyIndex.Put(disabledEdgeKey[:], []byte{}) - } - - return disabledEdgePolicyIndex.Delete(disabledEdgeKey[:]) -} - -// putChanEdgePolicyUnknown marks the edge policy as unknown -// in the edges bucket. -func putChanEdgePolicyUnknown(edges kvdb.RwBucket, channelID uint64, - from []byte) error { - - var edgeKey [33 + 8]byte - copy(edgeKey[:], from) - byteOrder.PutUint64(edgeKey[33:], channelID) - - if edges.Get(edgeKey[:]) != nil { - return fmt.Errorf("cannot write unknown policy for channel %v "+ - " when there is already a policy present", channelID) - } - - return edges.Put(edgeKey[:], unknownPolicy) -} - -func fetchChanEdgePolicy(edges kvdb.RBucket, chanID []byte, - nodePub []byte) (*models.ChannelEdgePolicy1, error) { - - var edgeKey [33 + 8]byte - copy(edgeKey[:], nodePub) - copy(edgeKey[33:], chanID[:]) - - edgeBytes := edges.Get(edgeKey[:]) - if edgeBytes == nil { - return nil, ErrEdgeNotFound - } - - // No need to deserialize unknown policy. - if bytes.Equal(edgeBytes[:], unknownPolicy) { - return nil, nil - } - - edgeReader := bytes.NewReader(edgeBytes) - - ep, err := deserializeChanEdgePolicy(edgeReader) - switch { - // If the db policy was missing an expected optional field, we return - // nil as if the policy was unknown. - case err == ErrEdgePolicyOptionalFieldNotFound: - return nil, nil - - case err != nil: - return nil, err - } - - return ep, nil -} - -func fetchChanEdgePolicies(edgeIndex kvdb.RBucket, edges kvdb.RBucket, - chanID []byte) (*models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, - error) { - - edgeInfo := edgeIndex.Get(chanID) - if edgeInfo == nil { - return nil, nil, fmt.Errorf("%w: chanID=%x", ErrEdgeNotFound, - chanID) - } - - // The first node is contained within the first half of the edge - // information. We only propagate the error here and below if it's - // something other than edge non-existence. - node1Pub := edgeInfo[:33] - edge1, err := fetchChanEdgePolicy(edges, chanID, node1Pub) - if err != nil { - return nil, nil, fmt.Errorf("%w: node1Pub=%x", ErrEdgeNotFound, - node1Pub) - } - - // Similarly, the second node is contained within the latter - // half of the edge information. - node2Pub := edgeInfo[33:66] - edge2, err := fetchChanEdgePolicy(edges, chanID, node2Pub) - if err != nil { - return nil, nil, fmt.Errorf("%w: node2Pub=%x", ErrEdgeNotFound, - node2Pub) - } - - return edge1, edge2, nil -} - -func serializeChanEdgePolicy(w io.Writer, edge *models.ChannelEdgePolicy1, - to []byte) error { - - err := wire.WriteVarBytes(w, 0, edge.SigBytes) - if err != nil { - return err - } - - if err := binary.Write(w, byteOrder, edge.ChannelID); err != nil { - return err - } - - var scratch [8]byte - updateUnix := uint64(edge.LastUpdate.Unix()) - byteOrder.PutUint64(scratch[:], updateUnix) - if _, err := w.Write(scratch[:]); err != nil { - return err - } - - if err := binary.Write(w, byteOrder, edge.MessageFlags); err != nil { - return err - } - if err := binary.Write(w, byteOrder, edge.ChannelFlags); err != nil { - return err - } - if err := binary.Write(w, byteOrder, edge.TimeLockDelta); err != nil { - return err - } - if err := binary.Write(w, byteOrder, uint64(edge.MinHTLC)); err != nil { - return err - } - if err := binary.Write(w, byteOrder, uint64(edge.FeeBaseMSat)); err != nil { - return err - } - if err := binary.Write(w, byteOrder, uint64(edge.FeeProportionalMillionths)); err != nil { - return err - } - - if _, err := w.Write(to); err != nil { - return err - } - - // If the max_htlc field is present, we write it. To be compatible with - // older versions that wasn't aware of this field, we write it as part - // of the opaque data. - // TODO(halseth): clean up when moving to TLV. - var opaqueBuf bytes.Buffer - if edge.MessageFlags.HasMaxHtlc() { - err := binary.Write(&opaqueBuf, byteOrder, uint64(edge.MaxHTLC)) - if err != nil { - return err - } - } - - if len(edge.ExtraOpaqueData) > MaxAllowedExtraOpaqueBytes { - return ErrTooManyExtraOpaqueBytes(len(edge.ExtraOpaqueData)) - } - if _, err := opaqueBuf.Write(edge.ExtraOpaqueData); err != nil { - return err - } - - if err := wire.WriteVarBytes(w, 0, opaqueBuf.Bytes()); err != nil { - return err - } - return nil -} - -func deserializeChanEdgePolicy(r io.Reader) (*models.ChannelEdgePolicy1, error) { - // Deserialize the policy. Note that in case an optional field is not - // found, both an error and a populated policy object are returned. - edge, deserializeErr := deserializeChanEdgePolicyRaw(r) - if deserializeErr != nil && - deserializeErr != ErrEdgePolicyOptionalFieldNotFound { - - return nil, deserializeErr - } - - return edge, deserializeErr -} - -func deserializeChanEdgePolicyRaw(r io.Reader) (*models.ChannelEdgePolicy1, - error) { - - edge := &models.ChannelEdgePolicy1{} - - var err error - edge.SigBytes, err = wire.ReadVarBytes(r, 0, 80, "sig") - if err != nil { - return nil, err - } - - if err := binary.Read(r, byteOrder, &edge.ChannelID); err != nil { - return nil, err - } - - var scratch [8]byte - if _, err := r.Read(scratch[:]); err != nil { - return nil, err - } - unix := int64(byteOrder.Uint64(scratch[:])) - edge.LastUpdate = time.Unix(unix, 0) - - if err := binary.Read(r, byteOrder, &edge.MessageFlags); err != nil { - return nil, err - } - if err := binary.Read(r, byteOrder, &edge.ChannelFlags); err != nil { - return nil, err - } - if err := binary.Read(r, byteOrder, &edge.TimeLockDelta); err != nil { - return nil, err - } - - var n uint64 - if err := binary.Read(r, byteOrder, &n); err != nil { - return nil, err - } - edge.MinHTLC = lnwire.MilliSatoshi(n) - - if err := binary.Read(r, byteOrder, &n); err != nil { - return nil, err - } - edge.FeeBaseMSat = lnwire.MilliSatoshi(n) - - if err := binary.Read(r, byteOrder, &n); err != nil { - return nil, err - } - edge.FeeProportionalMillionths = lnwire.MilliSatoshi(n) - - if _, err := r.Read(edge.ToNode[:]); err != nil { - return nil, err - } - - // We'll try and see if there are any opaque bytes left, if not, then - // we'll ignore the EOF error and return the edge as is. - edge.ExtraOpaqueData, err = wire.ReadVarBytes( - r, 0, MaxAllowedExtraOpaqueBytes, "blob", - ) - switch { - case err == io.ErrUnexpectedEOF: - case err == io.EOF: - case err != nil: - return nil, err - } - - // See if optional fields are present. - if edge.MessageFlags.HasMaxHtlc() { - // The max_htlc field should be at the beginning of the opaque - // bytes. - opq := edge.ExtraOpaqueData - - // If the max_htlc field is not present, it might be old data - // stored before this field was validated. We'll return the - // edge along with an error. - if len(opq) < 8 { - return edge, ErrEdgePolicyOptionalFieldNotFound - } - - maxHtlc := byteOrder.Uint64(opq[:8]) - edge.MaxHTLC = lnwire.MilliSatoshi(maxHtlc) - - // Exclude the parsed field from the rest of the opaque data. - edge.ExtraOpaqueData = opq[8:] - } - - return edge, nil -} From 51bdfbc96c1a1f65e48cef03d49e97dcbc4760f7 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 21 Aug 2024 12:42:36 +0200 Subject: [PATCH 10/60] channeldb: add encoding for ChannelEdgeInfo2 In this commit, we update the `putChanEdgeInfo` function to take in the models.ChannelEdgeInfo interface. If the passed value is the legacy models.ChannelEdgeInfo1, then the encoding and decoding remains the same but if it is the new models.ChannelEdgeInfo2 then: - the encoding will be prefixed with a 0xff byte. This should not clash with the encoding of the legacy struct since that encoding will always start with a pub key (of node 1) which means it will always start with 0x02 or 0x03. - The 0xff is then followed by a type-byte which will be used to identify the encoding that follows (this is to make it future proof). For now, there is only one possible type-byte here. - This is then followed by the TLV encoding of ChannelEdgeInfo2. --- channeldb/edge_info.go | 312 ++++++++++++++++++++++++++++++++---- channeldb/edge_info_test.go | 264 ++++++++++++++++++++++++++++++ channeldb/edge_policy.go | 31 ++-- channeldb/graph.go | 160 +++++++++++++----- 4 files changed, 671 insertions(+), 96 deletions(-) create mode 100644 channeldb/edge_info_test.go diff --git a/channeldb/edge_info.go b/channeldb/edge_info.go index 2b0d85c73d..fbf5525770 100644 --- a/channeldb/edge_info.go +++ b/channeldb/edge_info.go @@ -1,35 +1,137 @@ package channeldb import ( + "bufio" "bytes" "encoding/binary" "errors" + "fmt" "io" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb/models" "github.com/lightningnetwork/lnd/kvdb" + "github.com/lightningnetwork/lnd/tlv" ) +// edgeInfoEncodingType indicate how the bytes for a channel edge have been +// serialised. +type edgeInfoEncodingType uint8 + +const ( + // edgeInfo2EncodingType will be used as a prefix for edge's advertised + // using the ChannelAnnouncement2 message. The type indicates how the + // bytes following should be deserialized. + edgeInfo2EncodingType edgeInfoEncodingType = 0 +) + +const ( + // EdgeInfo2MsgType is the tlv type used within the serialisation of + // ChannelEdgeInfo2 for storing the serialisation of the associated + // lnwire.ChannelAnnouncement2 message. + EdgeInfo2MsgType = tlv.Type(0) + + // EdgeInfo2Sig is the tlv type used within the serialisation of + // ChannelEdgeInfo2 for storing the signature of the + // lnwire.ChannelAnnouncement2 message. + EdgeInfo2Sig = tlv.Type(1) + + // EdgeInfo2ChanPoint is the tlv type used within the serialisation of + // ChannelEdgeInfo2 for storing channel point. + EdgeInfo2ChanPoint = tlv.Type(2) + + // EdgeInfo2PKScript is the tlv type used within the serialisation of + // ChannelEdgeInfo2 for storing the funding pk script of the channel. + EdgeInfo2PKScript = tlv.Type(3) +) + +const ( + // chanEdgeNewEncodingPrefix is a byte used in the channel edge encoding + // to signal that the new style encoding which is prefixed with a type + // byte is being used instead of the legacy encoding which would start + // with either 0x02 or 0x03 due to the fact that the encoding would + // start with a node's compressed public key. + chanEdgeNewEncodingPrefix = 0xff +) + +// putChanEdgeInfo serialises the given ChannelEdgeInfo and writes the result +// to the edgeIndex using the channel ID as a key. func putChanEdgeInfo(edgeIndex kvdb.RwBucket, - edgeInfo *models.ChannelEdgeInfo1, chanID [8]byte) error { + edgeInfo models.ChannelEdgeInfo) error { + + var ( + chanID [8]byte + b bytes.Buffer + ) + + binary.BigEndian.PutUint64(chanID[:], edgeInfo.GetChanID()) + + if err := serializeChanEdgeInfo(&b, edgeInfo); err != nil { + return err + } + + return edgeIndex.Put(chanID[:], b.Bytes()) +} + +func serializeChanEdgeInfo(w io.Writer, edgeInfo models.ChannelEdgeInfo) error { + var ( + withTypeByte bool + typeByte edgeInfoEncodingType + serialize func(w io.Writer) error + ) - var b bytes.Buffer + switch info := edgeInfo.(type) { + case *models.ChannelEdgeInfo1: + serialize = func(w io.Writer) error { + return serializeChanEdgeInfo1(w, info) + } + case *models.ChannelEdgeInfo2: + withTypeByte = true + typeByte = edgeInfo2EncodingType - if _, err := b.Write(edgeInfo.NodeKey1Bytes[:]); err != nil { + serialize = func(w io.Writer) error { + return serializeChanEdgeInfo2(w, info) + } + default: + return fmt.Errorf("unhandled implementation of "+ + "ChannelEdgeInfo: %T", edgeInfo) + } + + if withTypeByte { + // First, write the identifying encoding byte to signal that + // this is not using the legacy encoding. + _, err := w.Write([]byte{chanEdgeNewEncodingPrefix}) + if err != nil { + return err + } + + // Now, write the encoding type. + _, err = w.Write([]byte{byte(typeByte)}) + if err != nil { + return err + } + } + + return serialize(w) +} + +func serializeChanEdgeInfo1(w io.Writer, + edgeInfo *models.ChannelEdgeInfo1) error { + + if _, err := w.Write(edgeInfo.NodeKey1Bytes[:]); err != nil { return err } - if _, err := b.Write(edgeInfo.NodeKey2Bytes[:]); err != nil { + if _, err := w.Write(edgeInfo.NodeKey2Bytes[:]); err != nil { return err } - if _, err := b.Write(edgeInfo.BitcoinKey1Bytes[:]); err != nil { + if _, err := w.Write(edgeInfo.BitcoinKey1Bytes[:]); err != nil { return err } - if _, err := b.Write(edgeInfo.BitcoinKey2Bytes[:]); err != nil { + if _, err := w.Write(edgeInfo.BitcoinKey2Bytes[:]); err != nil { return err } - if err := wire.WriteVarBytes(&b, 0, edgeInfo.Features); err != nil { + if err := wire.WriteVarBytes(w, 0, edgeInfo.Features); err != nil { return err } @@ -42,96 +144,176 @@ func putChanEdgeInfo(edgeIndex kvdb.RwBucket, bitcoinSig2 = authProof.BitcoinSig2Bytes } - if err := wire.WriteVarBytes(&b, 0, nodeSig1); err != nil { + if err := wire.WriteVarBytes(w, 0, nodeSig1); err != nil { return err } - if err := wire.WriteVarBytes(&b, 0, nodeSig2); err != nil { + if err := wire.WriteVarBytes(w, 0, nodeSig2); err != nil { return err } - if err := wire.WriteVarBytes(&b, 0, bitcoinSig1); err != nil { + if err := wire.WriteVarBytes(w, 0, bitcoinSig1); err != nil { return err } - if err := wire.WriteVarBytes(&b, 0, bitcoinSig2); err != nil { + if err := wire.WriteVarBytes(w, 0, bitcoinSig2); err != nil { return err } - if err := writeOutpoint(&b, &edgeInfo.ChannelPoint); err != nil { + if err := writeOutpoint(w, &edgeInfo.ChannelPoint); err != nil { return err } - if err := binary.Write(&b, byteOrder, uint64(edgeInfo.Capacity)); err != nil { + err := binary.Write(w, byteOrder, uint64(edgeInfo.Capacity)) + if err != nil { return err } - if _, err := b.Write(chanID[:]); err != nil { + + var chanID [8]byte + binary.BigEndian.PutUint64(chanID[:], edgeInfo.ChannelID) + if _, err := w.Write(chanID[:]); err != nil { return err } - if _, err := b.Write(edgeInfo.ChainHash[:]); err != nil { + if _, err := w.Write(edgeInfo.ChainHash[:]); err != nil { return err } if len(edgeInfo.ExtraOpaqueData) > MaxAllowedExtraOpaqueBytes { return ErrTooManyExtraOpaqueBytes(len(edgeInfo.ExtraOpaqueData)) } - err := wire.WriteVarBytes(&b, 0, edgeInfo.ExtraOpaqueData) + + return wire.WriteVarBytes(w, 0, edgeInfo.ExtraOpaqueData) +} + +func serializeChanEdgeInfo2(w io.Writer, edge *models.ChannelEdgeInfo2) error { + if len(edge.ExtraOpaqueData) > MaxAllowedExtraOpaqueBytes { + return ErrTooManyExtraOpaqueBytes(len(edge.ExtraOpaqueData)) + } + + serializedMsg, err := edge.DataToSign() if err != nil { return err } - return edgeIndex.Put(chanID[:], b.Bytes()) + records := []tlv.Record{ + tlv.MakePrimitiveRecord(EdgeInfo2MsgType, &serializedMsg), + } + + if edge.AuthProof != nil { + records = append( + records, tlv.MakePrimitiveRecord( + EdgeInfo2Sig, &edge.AuthProof.SchnorrSigBytes, + ), + ) + } + + records = append(records, tlv.MakeStaticRecord( + EdgeInfo2ChanPoint, &edge.ChannelPoint, 34, + encodeOutpoint, decodeOutpoint, + )) + + if len(edge.FundingPkScript) != 0 { + records = append( + records, tlv.MakePrimitiveRecord( + EdgeInfo2PKScript, &edge.FundingPkScript, + ), + ) + } + + stream, err := tlv.NewStream(records...) + if err != nil { + return err + } + + return stream.Encode(w) } func fetchChanEdgeInfo(edgeIndex kvdb.RBucket, - chanID []byte) (models.ChannelEdgeInfo1, error) { + chanID []byte) (models.ChannelEdgeInfo, error) { edgeInfoBytes := edgeIndex.Get(chanID) if edgeInfoBytes == nil { - return models.ChannelEdgeInfo1{}, ErrEdgeNotFound + return nil, ErrEdgeNotFound } edgeInfoReader := bytes.NewReader(edgeInfoBytes) + return deserializeChanEdgeInfo(edgeInfoReader) } -func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo1, error) { +func deserializeChanEdgeInfo(reader io.Reader) (models.ChannelEdgeInfo, error) { + // Wrap the io.Reader in a bufio.Reader so that we can peak the first + // byte of the stream without actually consuming from the stream. + r := bufio.NewReader(reader) + + firstByte, err := r.Peek(1) + if err != nil { + return nil, err + } + + if firstByte[0] != chanEdgeNewEncodingPrefix { + return deserializeChanEdgeInfo1(r) + } + + // Pop the encoding type byte. + var scratch [1]byte + if _, err = r.Read(scratch[:]); err != nil { + return nil, err + } + + // Now, read the encoding type byte. + if _, err = r.Read(scratch[:]); err != nil { + return nil, err + } + + encoding := edgeInfoEncodingType(scratch[0]) + switch encoding { + case edgeInfo2EncodingType: + return deserializeChanEdgeInfo2(r) + + default: + return nil, fmt.Errorf("unknown edge info encoding type: %d", + encoding) + } +} + +func deserializeChanEdgeInfo1(r io.Reader) (*models.ChannelEdgeInfo1, error) { var ( err error edgeInfo models.ChannelEdgeInfo1 ) if _, err := io.ReadFull(r, edgeInfo.NodeKey1Bytes[:]); err != nil { - return models.ChannelEdgeInfo1{}, err + return nil, err } if _, err := io.ReadFull(r, edgeInfo.NodeKey2Bytes[:]); err != nil { - return models.ChannelEdgeInfo1{}, err + return nil, err } if _, err := io.ReadFull(r, edgeInfo.BitcoinKey1Bytes[:]); err != nil { - return models.ChannelEdgeInfo1{}, err + return nil, err } if _, err := io.ReadFull(r, edgeInfo.BitcoinKey2Bytes[:]); err != nil { - return models.ChannelEdgeInfo1{}, err + return nil, err } edgeInfo.Features, err = wire.ReadVarBytes(r, 0, 900, "features") if err != nil { - return models.ChannelEdgeInfo1{}, err + return nil, err } proof := &models.ChannelAuthProof1{} proof.NodeSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") if err != nil { - return models.ChannelEdgeInfo1{}, err + return nil, err } proof.NodeSig2Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") if err != nil { - return models.ChannelEdgeInfo1{}, err + return nil, err } proof.BitcoinSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") if err != nil { - return models.ChannelEdgeInfo1{}, err + return nil, err } proof.BitcoinSig2Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs") if err != nil { - return models.ChannelEdgeInfo1{}, err + return nil, err } if !proof.IsEmpty() { @@ -140,17 +322,17 @@ func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo1, error) { edgeInfo.ChannelPoint = wire.OutPoint{} if err := readOutpoint(r, &edgeInfo.ChannelPoint); err != nil { - return models.ChannelEdgeInfo1{}, err + return nil, err } if err := binary.Read(r, byteOrder, &edgeInfo.Capacity); err != nil { - return models.ChannelEdgeInfo1{}, err + return nil, err } if err := binary.Read(r, byteOrder, &edgeInfo.ChannelID); err != nil { - return models.ChannelEdgeInfo1{}, err + return nil, err } if _, err := io.ReadFull(r, edgeInfo.ChainHash[:]); err != nil { - return models.ChannelEdgeInfo1{}, err + return nil, err } // We'll try and see if there are any opaque bytes left, if not, then @@ -162,8 +344,68 @@ func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo1, error) { case errors.Is(err, io.ErrUnexpectedEOF): case errors.Is(err, io.EOF): case err != nil: - return models.ChannelEdgeInfo1{}, err + return nil, err + } + + return &edgeInfo, nil +} + +func deserializeChanEdgeInfo2(r io.Reader) (*models.ChannelEdgeInfo2, error) { + var ( + edgeInfo models.ChannelEdgeInfo2 + msgBytes []byte + sigBytes []byte + ) + + records := []tlv.Record{ + tlv.MakePrimitiveRecord(EdgeInfo2MsgType, &msgBytes), + tlv.MakePrimitiveRecord(EdgeInfo2Sig, &sigBytes), + tlv.MakeStaticRecord( + EdgeInfo2ChanPoint, &edgeInfo.ChannelPoint, 34, + encodeOutpoint, decodeOutpoint, + ), + tlv.MakePrimitiveRecord( + EdgeInfo2PKScript, &edgeInfo.FundingPkScript, + ), + } + + stream, err := tlv.NewStream(records...) + if err != nil { + return nil, err + } + + typeMap, err := stream.DecodeWithParsedTypes(r) + if err != nil { + return nil, err + } + + reader := bytes.NewReader(msgBytes) + err = edgeInfo.ChannelAnnouncement2.DecodeTLVRecords(reader) + if err != nil { + return nil, err + } + + if _, ok := typeMap[EdgeInfo2Sig]; ok { + edgeInfo.AuthProof = &models.ChannelAuthProof2{ + SchnorrSigBytes: sigBytes, + } + } + + return &edgeInfo, nil +} + +func encodeOutpoint(w io.Writer, val interface{}, _ *[8]byte) error { + if o, ok := val.(*wire.OutPoint); ok { + return writeOutpoint(w, o) + } + + return tlv.NewTypeForEncodingErr(val, "*wire.Outpoint") +} + +func decodeOutpoint(r io.Reader, val interface{}, _ *[8]byte, l uint64) error { + if o, ok := val.(*wire.OutPoint); ok { + return readOutpoint(r, o) } - return edgeInfo, nil + return tlv.NewTypeForDecodingErr(val, "*wire.Outpoint", l, l) } diff --git a/channeldb/edge_info_test.go b/channeldb/edge_info_test.go new file mode 100644 index 0000000000..9a0ecf732c --- /dev/null +++ b/channeldb/edge_info_test.go @@ -0,0 +1,264 @@ +package channeldb + +import ( + "bytes" + "encoding/hex" + "math/rand" + "reflect" + "testing" + "testing/quick" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/wire" + "github.com/lightningnetwork/lnd/channeldb/models" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/tlv" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + testSchnorrSigStr, _ = hex.DecodeString("04E7F9037658A92AFEB4F2" + + "5BAE5339E3DDCA81A353493827D26F16D92308E49E2A25E9220867" + + "8A2DF86970DA91B03A8AF8815A8A60498B358DAF560B347AA557") + testSchnorrSig, _ = lnwire.NewSigFromSchnorrRawSignature( + testSchnorrSigStr, + ) +) + +// TestEdgeInfoSerialisation tests the serialisation and deserialization logic +// for models.ChannelEdgeInfo. +func TestEdgeInfoSerialisation(t *testing.T) { + t.Parallel() + + mainScenario := func(info models.ChannelEdgeInfo) bool { + var b bytes.Buffer + err := serializeChanEdgeInfo(&b, info) + require.NoError(t, err) + + newInfo, err := deserializeChanEdgeInfo(&b) + require.NoError(t, err) + + return assert.Equal(t, info, newInfo) + } + + tests := []struct { + name string + genValue func([]reflect.Value, *rand.Rand) + scenario any + }{ + { + name: "ChannelEdgeInfo1", + scenario: func(m models.ChannelEdgeInfo1) bool { + return mainScenario(&m) + }, + genValue: func(v []reflect.Value, r *rand.Rand) { + info := &models.ChannelEdgeInfo1{ + ChannelID: r.Uint64(), + NodeKey1Bytes: randRawKey(t), + NodeKey2Bytes: randRawKey(t), + BitcoinKey1Bytes: randRawKey(t), + BitcoinKey2Bytes: randRawKey(t), + ChannelPoint: wire.OutPoint{ + Index: r.Uint32(), + }, + Capacity: btcutil.Amount( + r.Uint32(), + ), + ExtraOpaqueData: make([]byte, 0), + } + + _, err := r.Read(info.ChainHash[:]) + require.NoError(t, err) + + _, err = r.Read(info.ChannelPoint.Hash[:]) + require.NoError(t, err) + + info.Features = make([]byte, r.Intn(900)) + _, err = r.Read(info.Features) + require.NoError(t, err) + + // Sometimes add an AuthProof. + if r.Intn(2)%2 == 0 { + n := r.Intn(80) + + //nolint:lll + authProof := &models.ChannelAuthProof1{ + NodeSig1Bytes: make([]byte, n), + NodeSig2Bytes: make([]byte, n), + BitcoinSig1Bytes: make([]byte, n), + BitcoinSig2Bytes: make([]byte, n), + } + + _, err = r.Read( + authProof.NodeSig1Bytes, + ) + require.NoError(t, err) + + _, err = r.Read( + authProof.NodeSig2Bytes, + ) + require.NoError(t, err) + + _, err = r.Read( + authProof.BitcoinSig1Bytes, + ) + require.NoError(t, err) + + _, err = r.Read( + authProof.BitcoinSig2Bytes, + ) + require.NoError(t, err) + } + + numExtraBytes := r.Int31n(1000) + if numExtraBytes > 0 { + info.ExtraOpaqueData = make( + []byte, numExtraBytes, + ) + _, err := r.Read( + info.ExtraOpaqueData, + ) + require.NoError(t, err) + } + + v[0] = reflect.ValueOf(*info) + }, + }, + { + name: "ChannelEdgeInfo2", + scenario: func(m models.ChannelEdgeInfo2) bool { + return mainScenario(&m) + }, + genValue: func(v []reflect.Value, r *rand.Rand) { + ann := lnwire.ChannelAnnouncement2{ + ExtraOpaqueData: make([]byte, 0), + } + + features := randRawFeatureVector(r) + ann.Features.Val = *features + + scid := lnwire.NewShortChanIDFromInt(r.Uint64()) + ann.ShortChannelID.Val = scid + ann.Capacity.Val = rand.Uint64() + ann.NodeID1.Val = randRawKey(t) + ann.NodeID2.Val = randRawKey(t) + + // Sometimes set chain hash to bitcoin mainnet + // genesis hash. + ann.ChainHash.Val = *chaincfg.MainNetParams. + GenesisHash + if r.Int31()%2 == 0 { + _, err := r.Read(ann.ChainHash.Val[:]) + require.NoError(t, err) + } + + if r.Intn(2)%2 == 0 { + btcKey1 := tlv.ZeroRecordT[ + tlv.TlvType12, [33]byte, + ]() + btcKey1.Val = randRawKey(t) + ann.BitcoinKey1 = tlv.SomeRecordT( + btcKey1, + ) + + btcKey2 := tlv.ZeroRecordT[ + tlv.TlvType14, [33]byte, + ]() + btcKey2.Val = randRawKey(t) + ann.BitcoinKey2 = tlv.SomeRecordT( + btcKey2, + ) + } + + if r.Intn(2)%2 == 0 { + hash := tlv.ZeroRecordT[ + tlv.TlvType16, [32]byte, + ]() + + _, err := r.Read(hash.Val[:]) + require.NoError(t, err) + + ann.MerkleRootHash = tlv.SomeRecordT( + hash, + ) + } + + numExtraBytes := r.Int31n(1000) + if numExtraBytes > 0 { + ann.ExtraOpaqueData = make( + []byte, numExtraBytes, + ) + _, err := r.Read(ann.ExtraOpaqueData[:]) + require.NoError(t, err) + } + + info := &models.ChannelEdgeInfo2{ + ChannelAnnouncement2: ann, + ChannelPoint: wire.OutPoint{ + Index: r.Uint32(), + }, + } + + _, err := r.Read(info.ChannelPoint.Hash[:]) + require.NoError(t, err) + + if r.Intn(2)%2 == 0 { + authProof := &models.ChannelAuthProof2{ + SchnorrSigBytes: testSchnorrSigStr, //nolint:lll + } + + info.AuthProof = authProof + } + + if r.Intn(2)%2 == 0 { + var pkScript [34]byte + _, err := r.Read(pkScript[:]) + require.NoError(t, err) + + info.FundingPkScript = pkScript[:] + } + + v[0] = reflect.ValueOf(*info) + }, + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + config := &quick.Config{ + Values: test.genValue, + } + + err := quick.Check(test.scenario, config) + require.NoError(t, err) + }) + } +} + +func randRawKey(t *testing.T) [33]byte { + var n [33]byte + + priv, err := btcec.NewPrivateKey() + require.NoError(t, err) + + copy(n[:], priv.PubKey().SerializeCompressed()) + + return n +} + +func randRawFeatureVector(r *rand.Rand) *lnwire.RawFeatureVector { + featureVec := lnwire.NewRawFeatureVector() + for i := 0; i < 10000; i++ { + if r.Int31n(2) == 0 { + featureVec.Set(lnwire.FeatureBit(i)) + } + } + + return featureVec +} diff --git a/channeldb/edge_policy.go b/channeldb/edge_policy.go index 113059a2d4..49edd18e1b 100644 --- a/channeldb/edge_policy.go +++ b/channeldb/edge_policy.go @@ -176,29 +176,26 @@ func fetchChanEdgePolicies(edgeIndex kvdb.RBucket, edges kvdb.RBucket, chanID []byte) (*models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { - edgeInfo := edgeIndex.Get(chanID) - if edgeInfo == nil { - return nil, nil, fmt.Errorf("%w: chanID=%x", ErrEdgeNotFound, - chanID) + edgeInfoBytes := edgeIndex.Get(chanID) + if edgeInfoBytes == nil { + return nil, nil, ErrEdgeNotFound } - // The first node is contained within the first half of the edge - // information. We only propagate the error here and below if it's - // something other than edge non-existence. - node1Pub := edgeInfo[:33] - edge1, err := fetchChanEdgePolicy(edges, chanID, node1Pub) + edgeInfo, err := deserializeChanEdgeInfo(bytes.NewReader(edgeInfoBytes)) if err != nil { - return nil, nil, fmt.Errorf("%w: node1Pub=%x", ErrEdgeNotFound, - node1Pub) + return nil, nil, err } - // Similarly, the second node is contained within the latter - // half of the edge information. - node2Pub := edgeInfo[33:66] - edge2, err := fetchChanEdgePolicy(edges, chanID, node2Pub) + node1Pub := edgeInfo.Node1Bytes() + edge1, err := fetchChanEdgePolicy(edges, chanID, node1Pub[:]) if err != nil { - return nil, nil, fmt.Errorf("%w: node2Pub=%x", ErrEdgeNotFound, - node2Pub) + return nil, nil, err + } + + node2Pub := edgeInfo.Node2Bytes() + edge2, err := fetchChanEdgePolicy(edges, chanID, node2Pub[:]) + if err != nil { + return nil, nil, err } return edge1, edge2, nil diff --git a/channeldb/graph.go b/channeldb/graph.go index 3143c1db56..89e7776280 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -453,16 +453,23 @@ func (c *ChannelGraph) ForEachChannel(cb func(*models.ChannelEdgeInfo1, } policy1 := channelMap[channelMapKey{ - nodeKey: info.NodeKey1Bytes, + nodeKey: info.Node1Bytes(), chanID: chanID, }] policy2 := channelMap[channelMapKey{ - nodeKey: info.NodeKey2Bytes, + nodeKey: info.Node2Bytes(), chanID: chanID, }] - return cb(&info, policy1, policy2) + edgeInfo, ok := info.(*models.ChannelEdgeInfo1) + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgeInfo1, got %T", + edgeInfo) + } + + return cb(edgeInfo, policy1, policy2) }) }, func() {}) } @@ -1104,7 +1111,7 @@ func (c *ChannelGraph) addChannelEdge(tx kvdb.RwTx, // If the edge hasn't been created yet, then we'll first add it to the // edge index in order to associate the edge between two nodes and also // store the static components of the channel. - if err := putChanEdgeInfo(edgeIndex, edge, chanKey); err != nil { + if err := putChanEdgeInfo(edgeIndex, edge); err != nil { return err } @@ -1268,7 +1275,7 @@ func (c *ChannelGraph) UpdateChannelEdge(edge *models.ChannelEdgeInfo1) error { c.graphCache.UpdateChannel(edge) } - return putChanEdgeInfo(edgeIndex, edge, chanKey) + return putChanEdgeInfo(edgeIndex, edge) }, func() {}) } @@ -1362,7 +1369,14 @@ func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint, return err } - chansClosed = append(chansClosed, &edgeInfo) + info, ok := edgeInfo.(*models.ChannelEdgeInfo1) + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgeInfo1, got %T", + edgeInfo) + } + + chansClosed = append(chansClosed, info) } metaBucket, err := tx.CreateTopLevelBucket(graphMetaBucket) @@ -1481,17 +1495,17 @@ func (c *ChannelGraph) pruneGraphNodes(nodes kvdb.RwBucket, // edge info. We'll use this scan to populate our reference count map // above. err = edgeIndex.ForEach(func(chanID, edgeInfoBytes []byte) error { - // The first 66 bytes of the edge info contain the pubkeys of - // the nodes that this edge attaches. We'll extract them, and - // add them to the ref count map. - var node1, node2 [33]byte - copy(node1[:], edgeInfoBytes[:33]) - copy(node2[:], edgeInfoBytes[33:]) + edge, err := deserializeChanEdgeInfo( + bytes.NewReader(edgeInfoBytes), + ) + if err != nil { + return err + } // With the nodes extracted, we'll increase the ref count of // each of the nodes. - nodeRefCounts[node1]++ - nodeRefCounts[node2]++ + nodeRefCounts[edge.Node1Bytes()]++ + nodeRefCounts[edge.Node2Bytes()]++ return nil }) @@ -1611,7 +1625,15 @@ func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ( } keys = append(keys, k) - removedChans = append(removedChans, &edgeInfo) + info, ok := edgeInfo.(*models.ChannelEdgeInfo1) + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgeInfo1, got %T", + edgeInfo) + } + + keys = append(keys, k) + removedChans = append(removedChans, info) } for _, k := range keys { @@ -1967,13 +1989,20 @@ func (c *ChannelGraph) ChanUpdatesInHorizon(startTime, } // First, we'll fetch the static edge information. - edgeInfo, err := fetchChanEdgeInfo(edgeIndex, chanID) + info, err := fetchChanEdgeInfo(edgeIndex, chanID) if err != nil { chanID := byteOrder.Uint64(chanID) return fmt.Errorf("unable to fetch info for "+ "edge with chan_id=%v: %v", chanID, err) } + edgeInfo, ok := info.(*models.ChannelEdgeInfo1) + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgeInfo1, got %T", + edgeInfo) + } + // With the static information obtained, we'll now // fetch the dynamic policy info. edge1, edge2, err := fetchChanEdgePolicies( @@ -2004,7 +2033,7 @@ func (c *ChannelGraph) ChanUpdatesInHorizon(startTime, // edges to be returned. edgesSeen[chanIDInt] = struct{}{} channel := ChannelEdge{ - Info: &edgeInfo, + Info: edgeInfo, Policy1: edge1, Policy2: edge2, Node1: &node1, @@ -2322,7 +2351,7 @@ func (c *ChannelGraph) FilterChannelRange(startHeight, return err } - if edgeInfo.AuthProof == nil { + if edgeInfo.GetAuthProof() == nil { continue } @@ -2344,7 +2373,7 @@ func (c *ChannelGraph) FilterChannelRange(startHeight, continue } - node1Key, node2Key := computeEdgePolicyKeys(&edgeInfo) + node1Key, node2Key := computeEdgePolicyKeys(edgeInfo) rawPolicy := edges.Get(node1Key) if len(rawPolicy) != 0 { @@ -2462,7 +2491,7 @@ func (c *ChannelGraph) fetchChanInfos(tx kvdb.RTx, chanIDs []uint64) ( // First, we'll fetch the static edge information. If // the edge is unknown, we will skip the edge and // continue gathering all known edges. - edgeInfo, err := fetchChanEdgeInfo( + info, err := fetchChanEdgeInfo( edgeIndex, cidBytes[:], ) switch { @@ -2481,6 +2510,13 @@ func (c *ChannelGraph) fetchChanInfos(tx kvdb.RTx, chanIDs []uint64) ( return err } + edgeInfo, ok := info.(*models.ChannelEdgeInfo1) + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgeInfo1, got %T", + info) + } + node1, err := fetchLightningNode( nodes, edgeInfo.NodeKey1Bytes[:], ) @@ -2496,7 +2532,7 @@ func (c *ChannelGraph) fetchChanInfos(tx kvdb.RTx, chanIDs []uint64) ( } chanEdges = append(chanEdges, ChannelEdge{ - Info: &edgeInfo, + Info: edgeInfo, Policy1: edge1, Policy2: edge2, Node1: &node1, @@ -2574,11 +2610,17 @@ func (c *ChannelGraph) delChannelEdgeUnsafe(edges, edgeIndex, chanIndex, zombieIndex kvdb.RwBucket, chanID []byte, isZombie, strictZombie bool) error { - edgeInfo, err := fetchChanEdgeInfo(edgeIndex, chanID) + info, err := fetchChanEdgeInfo(edgeIndex, chanID) if err != nil { return err } + edgeInfo, ok := info.(*models.ChannelEdgeInfo1) + if !ok { + return fmt.Errorf("expected *models.ChannelEdgeInfo1, got %T", + info) + } + if c.graphCache != nil { c.graphCache.RemoveChannel( edgeInfo.NodeKey1Bytes, edgeInfo.NodeKey2Bytes, @@ -2647,7 +2689,7 @@ func (c *ChannelGraph) delChannelEdgeUnsafe(edges, edgeIndex, chanIndex, nodeKey1, nodeKey2 := edgeInfo.NodeKey1Bytes, edgeInfo.NodeKey2Bytes if strictZombie { - nodeKey1, nodeKey2 = makeZombiePubkeys(&edgeInfo, edge1, edge2) + nodeKey1, nodeKey2 = makeZombiePubkeys(edgeInfo, edge1, edge2) } return markEdgeZombie( @@ -2808,23 +2850,32 @@ func updateEdgePolicy(tx kvdb.RwTx, edge *models.ChannelEdgePolicy1, return false, ErrEdgeNotFound } + edgeInfo, err := deserializeChanEdgeInfo(bytes.NewReader(nodeInfo)) + if err != nil { + return false, err + } + // Depending on the flags value passed above, either the first // or second edge policy is being updated. - var fromNode, toNode []byte - var isUpdate1 bool - if edge.ChannelFlags&lnwire.ChanUpdateDirection == 0 { - fromNode = nodeInfo[:33] - toNode = nodeInfo[33:66] + var ( + fromNode, toNode []byte + isUpdate1 bool + node1Bytes = edgeInfo.Node1Bytes() + node2Bytes = edgeInfo.Node2Bytes() + ) + if edge.IsNode1() { + fromNode = node1Bytes[:] + toNode = node2Bytes[:] isUpdate1 = true } else { - fromNode = nodeInfo[33:66] - toNode = nodeInfo[:33] + fromNode = node2Bytes[:] + toNode = node1Bytes[:] isUpdate1 = false } // Finally, with the direction of the edge being updated // identified, we update the on-disk edge representation. - err := putChanEdgePolicy(edges, edge, fromNode, toNode) + err = putChanEdgePolicy(edges, edge, fromNode, toNode) if err != nil { return false, err } @@ -3218,11 +3269,18 @@ func nodeTraversal(tx kvdb.RTx, nodePub []byte, db kvdb.Backend, // the node at the other end of the channel and both // edge policies. chanID := nodeEdge[33:] - edgeInfo, err := fetchChanEdgeInfo(edgeIndex, chanID) + info, err := fetchChanEdgeInfo(edgeIndex, chanID) if err != nil { return err } + edgeInfo, ok := info.(*models.ChannelEdgeInfo1) + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgeInfo1, got %T", + edgeInfo) + } + outgoingPolicy, err := fetchChanEdgePolicy( edges, chanID, nodePub, ) @@ -3243,7 +3301,7 @@ func nodeTraversal(tx kvdb.RTx, nodePub []byte, db kvdb.Backend, } // Finally, we execute the callback. - err = cb(tx, &edgeInfo, outgoingPolicy, incomingPolicy) + err = cb(tx, edgeInfo, outgoingPolicy, incomingPolicy) if err != nil { return err } @@ -3352,17 +3410,20 @@ func (c *ChannelGraph) FetchOtherNode(tx kvdb.RTx, // computeEdgePolicyKeys is a helper function that can be used to compute the // keys used to index the channel edge policy info for the two nodes of the // edge. The keys for node 1 and node 2 are returned respectively. -func computeEdgePolicyKeys(info *models.ChannelEdgeInfo1) ([]byte, []byte) { +func computeEdgePolicyKeys(info models.ChannelEdgeInfo) ([]byte, []byte) { var ( node1Key [33 + 8]byte node2Key [33 + 8]byte + + node1Bytes = info.Node1Bytes() + node2Bytes = info.Node2Bytes() ) - copy(node1Key[:], info.NodeKey1Bytes[:]) - copy(node2Key[:], info.NodeKey2Bytes[:]) + copy(node1Key[:], node1Bytes[:]) + copy(node2Key[:], node2Bytes[:]) - byteOrder.PutUint64(node1Key[33:], info.ChannelID) - byteOrder.PutUint64(node2Key[33:], info.ChannelID) + byteOrder.PutUint64(node1Key[33:], info.GetChanID()) + byteOrder.PutUint64(node2Key[33:], info.GetChanID()) return node1Key[:], node2Key[:] } @@ -3423,7 +3484,15 @@ func (c *ChannelGraph) FetchChannelEdgesByOutpoint(op *wire.OutPoint) ( if err != nil { return fmt.Errorf("%w: chanID=%x", err, chanID) } - edgeInfo = &edge + + info, ok := edge.(*models.ChannelEdgeInfo1) + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgeInfo1, got %T", + edge) + } + + edgeInfo = info // Once we have the information about the channels' parameters, // we'll fetch the routing policies for each for the directed @@ -3527,7 +3596,13 @@ func (c *ChannelGraph) FetchChannelEdgesByID(chanID uint64) ( return err } - edgeInfo = &edge + info, ok := edge.(*models.ChannelEdgeInfo1) + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgeInfo1, got %T", edge) + } + + edgeInfo = info // Then we'll attempt to fetch the accompanying policies of this // edge. @@ -3667,10 +3742,7 @@ func (c *ChannelGraph) ChannelView() ([]EdgePoint, error) { return err } - pkScript, err := genMultiSigP2WSH( - edgeInfo.BitcoinKey1Bytes[:], - edgeInfo.BitcoinKey2Bytes[:], - ) + pkScript, err := edgeInfo.FundingScript() if err != nil { return err } From 43715bbdd5526e2e4b82e67d52d501249c7c1e64 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 21 Aug 2024 12:58:01 +0200 Subject: [PATCH 11/60] channeldb: add encoding for ChannelEdgePolicy2 Similarly to the previous commit, here we add the encoding for the new ChannelEdgePolicy2. This is done in the same was as for ChannelEdgeInfo2: - a 0xff prefix - followed by a type-byte - followed by the TLV encoding of the ChannelEdgePolicy2. --- channeldb/edge_policy.go | 205 ++++++++++++++++++++++++++++++++-- channeldb/edge_policy_test.go | 174 +++++++++++++++++++++++++++++ channeldb/graph.go | 26 ++++- 3 files changed, 395 insertions(+), 10 deletions(-) create mode 100644 channeldb/edge_policy_test.go diff --git a/channeldb/edge_policy.go b/channeldb/edge_policy.go index 49edd18e1b..8d507a49d3 100644 --- a/channeldb/edge_policy.go +++ b/channeldb/edge_policy.go @@ -1,6 +1,7 @@ package channeldb import ( + "bufio" "bytes" "encoding/binary" "errors" @@ -12,6 +13,30 @@ import ( "github.com/lightningnetwork/lnd/channeldb/models" "github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/tlv" +) + +const ( + EdgePolicy2MsgType = tlv.Type(0) + EdgePolicy2ToNode = tlv.Type(1) + + // chanEdgePolicyNewEncodingPrefix is a byte used in the channel edge + // policy encoding to signal that the new style encoding which is + // prefixed with a type byte is being used instead of the legacy + // encoding which would start with 0x02 due to the fact that the + // encoding would start with a DER encoded ecdsa signature. + chanEdgePolicyNewEncodingPrefix = 0xff +) + +// edgePolicyEncoding indicates how the bytes for a channel edge policy have +// been serialised. +type edgePolicyEncodingType uint8 + +const ( + // edgePolicy2EncodingType will be used as a prefix for edge policies + // advertised using the ChannelUpdate2 message. The type indicates how + // the bytes following should be deserialized. + edgePolicy2EncodingType edgePolicyEncodingType = 0 ) func putChanEdgePolicy(edges kvdb.RwBucket, edge *models.ChannelEdgePolicy1, @@ -63,7 +88,14 @@ func putChanEdgePolicy(edges kvdb.RwBucket, edge *models.ChannelEdgePolicy1, return err } - oldUpdateTime := uint64(oldEdgePolicy.LastUpdate.Unix()) + oldPol, ok := oldEdgePolicy.(*models.ChannelEdgePolicy1) + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgePolicy1, got: %T", + oldEdgePolicy) + } + + oldUpdateTime := uint64(oldPol.LastUpdate.Unix()) var oldIndexKey [8 + 8]byte byteOrder.PutUint64(oldIndexKey[:8], oldUpdateTime) @@ -169,7 +201,13 @@ func fetchChanEdgePolicy(edges kvdb.RBucket, chanID []byte, return nil, err } - return ep, nil + pol, ok := ep.(*models.ChannelEdgePolicy1) + if !ok { + return nil, fmt.Errorf("expected *models.ChannelEdgePolicy1, "+ + "got: %T", ep) + } + + return pol, nil } func fetchChanEdgePolicies(edgeIndex kvdb.RBucket, edges kvdb.RBucket, @@ -201,8 +239,56 @@ func fetchChanEdgePolicies(edgeIndex kvdb.RBucket, edges kvdb.RBucket, return edge1, edge2, nil } -func serializeChanEdgePolicy(w io.Writer, edge *models.ChannelEdgePolicy1, - to []byte) error { +func serializeChanEdgePolicy(w io.Writer, + edgePolicy models.ChannelEdgePolicy, toNode []byte) error { + + var ( + withTypeByte bool + typeByte edgePolicyEncodingType + serialize func(w io.Writer) error + ) + + switch policy := edgePolicy.(type) { + case *models.ChannelEdgePolicy1: + serialize = func(w io.Writer) error { + copy(policy.ToNode[:], toNode) + + return serializeChanEdgePolicy1(w, policy) + } + case *models.ChannelEdgePolicy2: + withTypeByte = true + typeByte = edgePolicy2EncodingType + + serialize = func(w io.Writer) error { + copy(policy.ToNode[:], toNode) + + return serializeChanEdgePolicy2(w, policy) + } + default: + return fmt.Errorf("unhandled implementation of "+ + "ChannelEdgePolicy: %T", edgePolicy) + } + + if withTypeByte { + // First, write the identifying encoding byte to signal that + // this is not using the legacy encoding. + _, err := w.Write([]byte{chanEdgePolicyNewEncodingPrefix}) + if err != nil { + return err + } + + // Now, write the encoding type. + _, err = w.Write([]byte{byte(typeByte)}) + if err != nil { + return err + } + } + + return serialize(w) +} + +func serializeChanEdgePolicy1(w io.Writer, + edge *models.ChannelEdgePolicy1) error { err := wire.WriteVarBytes(w, 0, edge.SigBytes) if err != nil { @@ -241,7 +327,7 @@ func serializeChanEdgePolicy(w io.Writer, edge *models.ChannelEdgePolicy1, return err } - if _, err := w.Write(to); err != nil { + if _, err := w.Write(edge.ToNode[:]); err != nil { return err } @@ -271,7 +357,36 @@ func serializeChanEdgePolicy(w io.Writer, edge *models.ChannelEdgePolicy1, return nil } -func deserializeChanEdgePolicy(r io.Reader) (*models.ChannelEdgePolicy1, error) { +func serializeChanEdgePolicy2(w io.Writer, + edge *models.ChannelEdgePolicy2) error { + + if len(edge.ExtraOpaqueData) > MaxAllowedExtraOpaqueBytes { + return ErrTooManyExtraOpaqueBytes(len(edge.ExtraOpaqueData)) + } + + var b bytes.Buffer + if err := edge.Encode(&b, 0); err != nil { + return err + } + + msg := b.Bytes() + + records := []tlv.Record{ + tlv.MakePrimitiveRecord(EdgePolicy2MsgType, &msg), + tlv.MakePrimitiveRecord(EdgePolicy2ToNode, &edge.ToNode), + } + + stream, err := tlv.NewStream(records...) + if err != nil { + return err + } + + return stream.Encode(w) +} + +func deserializeChanEdgePolicy(r io.Reader) (models.ChannelEdgePolicy, + error) { + // Deserialize the policy. Note that in case an optional field is not // found, both an error and a populated policy object are returned. edge, deserializeErr := deserializeChanEdgePolicyRaw(r) @@ -284,7 +399,45 @@ func deserializeChanEdgePolicy(r io.Reader) (*models.ChannelEdgePolicy1, error) return edge, deserializeErr } -func deserializeChanEdgePolicyRaw(r io.Reader) (*models.ChannelEdgePolicy1, +func deserializeChanEdgePolicyRaw(reader io.Reader) (models.ChannelEdgePolicy, + error) { + + // Wrap the io.Reader in a bufio.Reader so that we can peak the first + // byte of the stream without actually consuming from the stream. + r := bufio.NewReader(reader) + + firstByte, err := r.Peek(1) + if err != nil { + return nil, err + } + + if firstByte[0] != chanEdgePolicyNewEncodingPrefix { + return deserializeChanEdgePolicy1Raw(r) + } + + // Pop the encoding type byte. + var scratch [1]byte + if _, err = r.Read(scratch[:]); err != nil { + return nil, err + } + + // Now, read the encoding type byte. + if _, err = r.Read(scratch[:]); err != nil { + return nil, err + } + + encoding := edgePolicyEncodingType(scratch[0]) + switch encoding { + case edgePolicy2EncodingType: + return deserializeChanEdgePolicy2Raw(r) + + default: + return nil, fmt.Errorf("unknown edge policy encoding type: %d", + encoding) + } +} + +func deserializeChanEdgePolicy1Raw(r io.Reader) (*models.ChannelEdgePolicy1, error) { edge := &models.ChannelEdgePolicy1{} @@ -370,3 +523,41 @@ func deserializeChanEdgePolicyRaw(r io.Reader) (*models.ChannelEdgePolicy1, return edge, nil } + +func deserializeChanEdgePolicy2Raw(r io.Reader) (*models.ChannelEdgePolicy2, + error) { + + var ( + msgBytes []byte + toNode [33]byte + ) + + records := []tlv.Record{ + tlv.MakePrimitiveRecord(EdgePolicy2MsgType, &msgBytes), + tlv.MakePrimitiveRecord(EdgePolicy2ToNode, &toNode), + } + + stream, err := tlv.NewStream(records...) + if err != nil { + return nil, err + } + + err = stream.Decode(r) + if err != nil { + return nil, err + } + + var ( + chanUpdate lnwire.ChannelUpdate2 + reader = bytes.NewReader(msgBytes) + ) + err = chanUpdate.Decode(reader, 0) + if err != nil { + return nil, err + } + + return &models.ChannelEdgePolicy2{ + ChannelUpdate2: chanUpdate, + ToNode: toNode, + }, nil +} diff --git a/channeldb/edge_policy_test.go b/channeldb/edge_policy_test.go new file mode 100644 index 0000000000..16f03c5545 --- /dev/null +++ b/channeldb/edge_policy_test.go @@ -0,0 +1,174 @@ +package channeldb + +import ( + "bytes" + "math/rand" + "reflect" + "testing" + "testing/quick" + "time" + + "github.com/lightningnetwork/lnd/channeldb/models" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/tlv" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestEdgePolicySerialisation tests the serialisation and deserialization logic +// for models.ChannelEdgePolicy. +func TestEdgePolicySerialisation(t *testing.T) { + t.Parallel() + + mainScenario := func(info models.ChannelEdgePolicy) bool { + var ( + b bytes.Buffer + toNode = info.GetToNode() + ) + + err := serializeChanEdgePolicy(&b, info, toNode[:]) + require.NoError(t, err) + + newInfo, err := deserializeChanEdgePolicy(&b) + require.NoError(t, err) + + return assert.Equal(t, info, newInfo) + } + + tests := []struct { + name string + genValue func([]reflect.Value, *rand.Rand) + scenario any + }{ + { + name: "ChannelEdgePolicy1", + scenario: func(m models.ChannelEdgePolicy1) bool { + return mainScenario(&m) + }, + genValue: func(v []reflect.Value, r *rand.Rand) { + //nolint:lll + policy := &models.ChannelEdgePolicy1{ + ChannelID: r.Uint64(), + LastUpdate: time.Unix(r.Int63(), 0), + MessageFlags: lnwire.ChanUpdateMsgFlags(r.Uint32()), + ChannelFlags: lnwire.ChanUpdateChanFlags(r.Uint32()), + TimeLockDelta: uint16(r.Uint32()), + MinHTLC: lnwire.MilliSatoshi(r.Uint64()), + FeeBaseMSat: lnwire.MilliSatoshi(r.Uint64()), + FeeProportionalMillionths: lnwire.MilliSatoshi(r.Uint64()), + ExtraOpaqueData: make([]byte, 0), + } + + policy.SigBytes = make([]byte, r.Intn(80)) + _, err := r.Read(policy.SigBytes) + require.NoError(t, err) + + _, err = r.Read(policy.ToNode[:]) + require.NoError(t, err) + + numExtraBytes := r.Int31n(1000) + if numExtraBytes > 0 { + policy.ExtraOpaqueData = make( + []byte, numExtraBytes, + ) + _, err := r.Read( + policy.ExtraOpaqueData, + ) + require.NoError(t, err) + } + + // Sometimes add an MaxHTLC. + if r.Intn(2)%2 == 0 { + policy.MessageFlags |= + lnwire.ChanUpdateRequiredMaxHtlc + policy.MaxHTLC = lnwire.MilliSatoshi( + r.Uint64(), + ) + } else { + policy.MessageFlags ^= + lnwire.ChanUpdateRequiredMaxHtlc + } + + v[0] = reflect.ValueOf(*policy) + }, + }, + { + name: "ChannelEdgePolicy2", + scenario: func(m models.ChannelEdgePolicy2) bool { + return mainScenario(&m) + }, + genValue: func(v []reflect.Value, r *rand.Rand) { + policy := &models.ChannelEdgePolicy2{ + //nolint:lll + ChannelUpdate2: lnwire.ChannelUpdate2{ + Signature: testSchnorrSig, + ExtraOpaqueData: make([]byte, 0), + }, + ToNode: [33]byte{}, + } + + policy.ShortChannelID.Val = lnwire.NewShortChanIDFromInt( //nolint:lll + uint64(r.Int63()), + ) + policy.BlockHeight.Val = r.Uint32() + policy.HTLCMaximumMsat.Val = lnwire.MilliSatoshi( //nolint:lll + r.Uint64(), + ) + policy.HTLCMinimumMsat.Val = lnwire.MilliSatoshi( //nolint:lll + r.Uint64(), + ) + policy.CLTVExpiryDelta.Val = uint16(r.Int31()) + policy.FeeBaseMsat.Val = r.Uint32() + policy.FeeProportionalMillionths.Val = r.Uint32() //nolint:lll + + if r.Intn(2) == 0 { + policy.SecondPeer = tlv.SomeRecordT( + tlv.ZeroRecordT[tlv.TlvType8, lnwire.TrueBoolean](), //nolint:lll + ) + } + + // Sometimes set the incoming disabled flag. + if r.Int31()%2 == 0 { + policy.DisabledFlags.Val |= + lnwire.ChanUpdateDisableIncoming + } + + // Sometimes set the outgoing disabled flag. + if r.Int31()%2 == 0 { + policy.DisabledFlags.Val |= + lnwire.ChanUpdateDisableOutgoing + } + + _, err := r.Read(policy.ToNode[:]) + require.NoError(t, err) + + numExtraBytes := r.Int31n(1000) + if numExtraBytes > 0 { + policy.ExtraOpaqueData = make( + []byte, numExtraBytes, + ) + _, err := r.Read( + policy.ExtraOpaqueData, + ) + require.NoError(t, err) + } + + v[0] = reflect.ValueOf(*policy) + }, + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + config := &quick.Config{ + Values: test.genValue, + } + + err := quick.Check(test.scenario, config) + require.NoError(t, err) + }) + } +} diff --git a/channeldb/graph.go b/channeldb/graph.go index 89e7776280..f855fa2fc1 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -311,7 +311,13 @@ func (c *ChannelGraph) getChannelMap(edges kvdb.RBucket) ( return err } - channelMap[key] = edge + e, ok := edge.(*models.ChannelEdgePolicy1) + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgePolicy1, got: %T", edge) + } + + channelMap[key] = e return nil }) @@ -2387,7 +2393,14 @@ func (c *ChannelGraph) FilterChannelRange(startHeight, return err } - chanInfo.Node1UpdateTimestamp = edge.LastUpdate + e, ok := edge.(*models.ChannelEdgePolicy1) + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgePolicy1, "+ + "got %T", edge) + } + + chanInfo.Node1UpdateTimestamp = e.LastUpdate } rawPolicy = edges.Get(node2Key) @@ -2402,7 +2415,14 @@ func (c *ChannelGraph) FilterChannelRange(startHeight, return err } - chanInfo.Node2UpdateTimestamp = edge.LastUpdate + e, ok := edge.(*models.ChannelEdgePolicy1) + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgePolicy1, "+ + "got %T", edge) + } + + chanInfo.Node2UpdateTimestamp = e.LastUpdate } channelsPerBlock[cid.BlockHeight] = append( From 425c10d6840a8d67dd5dc0a71d395611f5e5d7ec Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 21 Aug 2024 12:58:36 +0200 Subject: [PATCH 12/60] docs: update release notes --- docs/release-notes/release-notes-0.19.0.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/release-notes/release-notes-0.19.0.md b/docs/release-notes/release-notes-0.19.0.md index c7410fced0..3b45b46464 100644 --- a/docs/release-notes/release-notes-0.19.0.md +++ b/docs/release-notes/release-notes-0.19.0.md @@ -68,6 +68,9 @@ * Add new [lnwire](https://github.com/lightningnetwork/lnd/pull/8044) messages for the Gossip 1.75 protocol. +* Add new [channeldb](https://github.com/lightningnetwork/lnd/pull/8164) types + required for the Gossip 1.75 protocol. + ## Testing ## Database From 4dbb069834179ad8cc4ceba622ade5fafc29f110 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 27 Oct 2023 12:26:47 +0200 Subject: [PATCH 13/60] routing+channeldb: update CachedEdgePolicy In preparation for CachedEdgePolicy being used to represent ChannelEdgePolicy1 or ChannelEdgePolicy2, we update it to have IsDisabled and HasMaxHTLC booleans (which can be extracted from both messages) instead of having the MessageFlags and ChannelFlags which only applies to ChannelEdgePolicy1. --- channeldb/graph_cache_test.go | 4 ++-- channeldb/models/cached_edge_policy.go | 33 +++++++++++++------------- routing/unified_edges.go | 12 ++++------ routing/unified_edges_test.go | 4 ++-- 4 files changed, 26 insertions(+), 27 deletions(-) diff --git a/channeldb/graph_cache_test.go b/channeldb/graph_cache_test.go index 65e639be55..6ccb99d8ab 100644 --- a/channeldb/graph_cache_test.go +++ b/channeldb/graph_cache_test.go @@ -157,8 +157,8 @@ func assertCachedPolicyEqual(t *testing.T, original *models.ChannelEdgePolicy1, cached *models.CachedEdgePolicy) { require.Equal(t, original.ChannelID, cached.ChannelID) - require.Equal(t, original.MessageFlags, cached.MessageFlags) - require.Equal(t, original.ChannelFlags, cached.ChannelFlags) + require.Equal(t, original.MessageFlags.HasMaxHtlc(), cached.HasMaxHTLC) + require.Equal(t, original.ChannelFlags.IsDisabled(), cached.IsDisabled) require.Equal(t, original.TimeLockDelta, cached.TimeLockDelta) require.Equal(t, original.MinHTLC, cached.MinHTLC) require.Equal(t, original.MaxHTLC, cached.MaxHTLC) diff --git a/channeldb/models/cached_edge_policy.go b/channeldb/models/cached_edge_policy.go index 89f9a98a0b..a63749af62 100644 --- a/channeldb/models/cached_edge_policy.go +++ b/channeldb/models/cached_edge_policy.go @@ -11,7 +11,7 @@ const ( ) // CachedEdgePolicy is a struct that only caches the information of a -// ChannelEdgePolicy1 that we actually use for pathfinding and therefore need to +// ChannelEdgePolicy that we actually use for pathfinding and therefore need to // store in the cache. type CachedEdgePolicy struct { // ChannelID is the unique channel ID for the channel. The first 3 @@ -19,13 +19,12 @@ type CachedEdgePolicy struct { // and the last 2 bytes are the output index for the channel. ChannelID uint64 - // MessageFlags is a bitfield which indicates the presence of optional - // fields (like max_htlc) in the policy. - MessageFlags lnwire.ChanUpdateMsgFlags + // HasMaxHTLC is true if the policy update includes a value for MaxHTLC. + HasMaxHTLC bool - // ChannelFlags is a bitfield which signals the capabilities of the - // channel as well as the directed edge this update applies to. - ChannelFlags lnwire.ChanUpdateChanFlags + // IsDisabled is true if this policy is signalling that the channel is + // disabled. + IsDisabled bool // TimeLockDelta is the number of blocks this node will subtract from // the expiry of an incoming HTLC. This value expresses the time buffer @@ -72,15 +71,17 @@ func (c *CachedEdgePolicy) ComputeFee( } // NewCachedPolicy turns a full policy into a minimal one that can be cached. -func NewCachedPolicy(policy *ChannelEdgePolicy1) *CachedEdgePolicy { +func NewCachedPolicy(policy ChannelEdgePolicy) *CachedEdgePolicy { + fwdingPolicy := policy.ForwardingPolicy() + return &CachedEdgePolicy{ - ChannelID: policy.ChannelID, - MessageFlags: policy.MessageFlags, - ChannelFlags: policy.ChannelFlags, - TimeLockDelta: policy.TimeLockDelta, - MinHTLC: policy.MinHTLC, - MaxHTLC: policy.MaxHTLC, - FeeBaseMSat: policy.FeeBaseMSat, - FeeProportionalMillionths: policy.FeeProportionalMillionths, + ChannelID: policy.SCID().ToUint64(), + HasMaxHTLC: fwdingPolicy.HasMaxHTLC, + IsDisabled: policy.IsDisabled(), + TimeLockDelta: fwdingPolicy.TimeLockDelta, + MinHTLC: fwdingPolicy.MinHTLC, + MaxHTLC: fwdingPolicy.MaxHTLC, + FeeBaseMSat: fwdingPolicy.BaseFee, + FeeProportionalMillionths: fwdingPolicy.FeeRate, } } diff --git a/routing/unified_edges.go b/routing/unified_edges.go index 6c44372e99..a8247aeff0 100644 --- a/routing/unified_edges.go +++ b/routing/unified_edges.go @@ -169,11 +169,10 @@ func (u *unifiedEdge) amtInRange(amt lnwire.MilliSatoshi) bool { } // Skip channels for which this htlc is too large. - if u.policy.MessageFlags.HasMaxHtlc() && - amt > u.policy.MaxHTLC { - + if u.policy.HasMaxHTLC && amt > u.policy.MaxHTLC { log.Tracef("Exceeds policy's MaxHTLC: amt=%v, MaxHTLC=%v", amt, u.policy.MaxHTLC) + return false } @@ -355,18 +354,17 @@ func (u *edgeUnifier) getEdgeNetwork(netAmtReceived lnwire.MilliSatoshi, } // For network channels, skip the disabled ones. - edgeFlags := edge.policy.ChannelFlags - isDisabled := edgeFlags&lnwire.ChanUpdateDisabled != 0 - if isDisabled { + if edge.policy.IsDisabled { log.Debugf("Skipped edge %v due to it being disabled", edge.policy.ChannelID) + continue } // Track the maximal capacity for usable channels. If we don't // know the capacity, we fall back to MaxHTLC. capMsat := lnwire.NewMSatFromSatoshis(edge.capacity) - if capMsat == 0 && edge.policy.MessageFlags.HasMaxHtlc() { + if capMsat == 0 && edge.policy.HasMaxHTLC { log.Tracef("No capacity available for channel %v, "+ "using MaxHtlcMsat (%v) as a fallback.", edge.policy.ChannelID, edge.policy.MaxHTLC) diff --git a/routing/unified_edges_test.go b/routing/unified_edges_test.go index 82605e9b37..c4ab1bfd74 100644 --- a/routing/unified_edges_test.go +++ b/routing/unified_edges_test.go @@ -30,7 +30,7 @@ func TestNodeEdgeUnifier(t *testing.T) { FeeProportionalMillionths: 100000, FeeBaseMSat: 30, TimeLockDelta: 60, - MessageFlags: lnwire.ChanUpdateRequiredMaxHtlc, + HasMaxHTLC: true, MaxHTLC: 5000, MinHTLC: 100, } @@ -39,7 +39,7 @@ func TestNodeEdgeUnifier(t *testing.T) { FeeProportionalMillionths: 190000, FeeBaseMSat: 10, TimeLockDelta: 40, - MessageFlags: lnwire.ChanUpdateRequiredMaxHtlc, + HasMaxHTLC: true, MaxHTLC: 4000, MinHTLC: 100, } From b21f165cec36fb516d47d84cfbc38d7e5635760f Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 27 Oct 2023 12:47:10 +0200 Subject: [PATCH 14/60] channeldb: update GraphCache to use interfaces where possible Update the graph cache to use the new ChannelEdgePolicy and ChannelEdgeInfo interfaces where possible. --- channeldb/graph_cache.go | 70 ++++++++++++++++++++--------------- channeldb/graph_cache_test.go | 24 ++++++------ 2 files changed, 52 insertions(+), 42 deletions(-) diff --git a/channeldb/graph_cache.go b/channeldb/graph_cache.go index 7df72b209e..69bdee59b1 100644 --- a/channeldb/graph_cache.go +++ b/channeldb/graph_cache.go @@ -157,7 +157,7 @@ func (c *GraphCache) AddNode(tx kvdb.RTx, node GraphCacheNode) error { // and policy 2 does not matter, the directionality is extracted from the info // and policy flags automatically. The policy will be set as the outgoing policy // on one node and the incoming policy on the peer's side. -func (c *GraphCache) AddChannel(info *models.ChannelEdgeInfo1, policy1, +func (c *GraphCache) AddChannel(info models.ChannelEdgeInfo, policy1, policy2 *models.ChannelEdgePolicy1) { if info == nil { @@ -172,36 +172,36 @@ func (c *GraphCache) AddChannel(info *models.ChannelEdgeInfo1, policy1, // Create the edge entry for both nodes. c.mtx.Lock() - c.updateOrAddEdge(info.NodeKey1Bytes, &DirectedChannel{ - ChannelID: info.ChannelID, + c.updateOrAddEdge(info.Node1Bytes(), &DirectedChannel{ + ChannelID: info.GetChanID(), IsNode1: true, - OtherNode: info.NodeKey2Bytes, - Capacity: info.Capacity, + OtherNode: info.Node2Bytes(), + Capacity: info.GetCapacity(), }) - c.updateOrAddEdge(info.NodeKey2Bytes, &DirectedChannel{ - ChannelID: info.ChannelID, + c.updateOrAddEdge(info.Node2Bytes(), &DirectedChannel{ + ChannelID: info.GetChanID(), IsNode1: false, - OtherNode: info.NodeKey1Bytes, - Capacity: info.Capacity, + OtherNode: info.Node1Bytes(), + Capacity: info.GetCapacity(), }) c.mtx.Unlock() // The policy's node is always the to_node. So if policy 1 has to_node // of node 2 then we have the policy 1 as seen from node 1. if policy1 != nil { - fromNode, toNode := info.NodeKey1Bytes, info.NodeKey2Bytes - if policy1.ToNode != info.NodeKey2Bytes { + fromNode, toNode := info.Node1Bytes(), info.Node2Bytes() + if policy1.GetToNode() != info.Node2Bytes() { fromNode, toNode = toNode, fromNode } - isEdge1 := policy1.ChannelFlags&lnwire.ChanUpdateDirection == 0 + isEdge1 := policy1.IsNode1() c.UpdatePolicy(policy1, fromNode, toNode, isEdge1) } if policy2 != nil { - fromNode, toNode := info.NodeKey2Bytes, info.NodeKey1Bytes - if policy2.ToNode != info.NodeKey1Bytes { + fromNode, toNode := info.Node2Bytes(), info.Node1Bytes() + if policy2.GetToNode() != info.Node1Bytes() { fromNode, toNode = toNode, fromNode } - isEdge1 := policy2.ChannelFlags&lnwire.ChanUpdateDirection == 0 + isEdge1 := policy2.IsNode1() c.UpdatePolicy(policy2, fromNode, toNode, isEdge1) } } @@ -220,15 +220,20 @@ func (c *GraphCache) updateOrAddEdge(node route.Vertex, edge *DirectedChannel) { // of the from and to node is not strictly important. But we assume that a // channel edge was added beforehand so that the directed channel struct already // exists in the cache. -func (c *GraphCache) UpdatePolicy(policy *models.ChannelEdgePolicy1, fromNode, +func (c *GraphCache) UpdatePolicy(policy models.ChannelEdgePolicy, fromNode, toNode route.Vertex, edge1 bool) { // Extract inbound fee if possible and available. If there is a decoding // error, ignore this policy. var inboundFee lnwire.Fee - _, err := policy.ExtraOpaqueData.ExtractRecords(&inboundFee) - if err != nil { - return + + // TODO(elle): Add inbound fees field to ChannelEdgePolicy2 & + // ChannelUpdate2? + if p1, ok := policy.(*models.ChannelEdgePolicy1); ok { + _, err := p1.ExtraOpaqueData.ExtractRecords(&inboundFee) + if err != nil { + return + } } c.mtx.Lock() @@ -239,7 +244,7 @@ func (c *GraphCache) UpdatePolicy(policy *models.ChannelEdgePolicy1, fromNode, return } - channel, ok := c.nodeChannels[nodeKey][policy.ChannelID] + channel, ok := c.nodeChannels[nodeKey][policy.SCID().ToUint64()] if !ok { return } @@ -309,28 +314,35 @@ func (c *GraphCache) removeChannelIfFound(node route.Vertex, chanID uint64) { // UpdateChannel updates the channel edge information for a specific edge. We // expect the edge to already exist and be known. If it does not yet exist, this // call is a no-op. -func (c *GraphCache) UpdateChannel(info *models.ChannelEdgeInfo1) { +func (c *GraphCache) UpdateChannel(info models.ChannelEdgeInfo) { c.mtx.Lock() defer c.mtx.Unlock() - if len(c.nodeChannels[info.NodeKey1Bytes]) == 0 || - len(c.nodeChannels[info.NodeKey2Bytes]) == 0 { + var ( + node1Bytes = info.Node1Bytes() + node2Bytes = info.Node2Bytes() + chanID = info.GetChanID() + capacity = info.GetCapacity() + ) + + if len(c.nodeChannels[node1Bytes]) == 0 || + len(c.nodeChannels[node2Bytes]) == 0 { return } - channel, ok := c.nodeChannels[info.NodeKey1Bytes][info.ChannelID] + channel, ok := c.nodeChannels[node1Bytes][chanID] if ok { // We only expect to be called when the channel is already // known. - channel.Capacity = info.Capacity - channel.OtherNode = info.NodeKey2Bytes + channel.Capacity = capacity + channel.OtherNode = node2Bytes } - channel, ok = c.nodeChannels[info.NodeKey2Bytes][info.ChannelID] + channel, ok = c.nodeChannels[node2Bytes][chanID] if ok { - channel.Capacity = info.Capacity - channel.OtherNode = info.NodeKey1Bytes + channel.Capacity = capacity + channel.OtherNode = node1Bytes } } diff --git a/channeldb/graph_cache_test.go b/channeldb/graph_cache_test.go index 6ccb99d8ab..d6ece70717 100644 --- a/channeldb/graph_cache_test.go +++ b/channeldb/graph_cache_test.go @@ -153,21 +153,19 @@ func TestGraphCacheAddNode(t *testing.T) { runTest(pubKey2, pubKey1) } -func assertCachedPolicyEqual(t *testing.T, original *models.ChannelEdgePolicy1, +func assertCachedPolicyEqual(t *testing.T, original models.ChannelEdgePolicy, cached *models.CachedEdgePolicy) { - require.Equal(t, original.ChannelID, cached.ChannelID) - require.Equal(t, original.MessageFlags.HasMaxHtlc(), cached.HasMaxHTLC) - require.Equal(t, original.ChannelFlags.IsDisabled(), cached.IsDisabled) - require.Equal(t, original.TimeLockDelta, cached.TimeLockDelta) - require.Equal(t, original.MinHTLC, cached.MinHTLC) - require.Equal(t, original.MaxHTLC, cached.MaxHTLC) - require.Equal(t, original.FeeBaseMSat, cached.FeeBaseMSat) - require.Equal( - t, original.FeeProportionalMillionths, - cached.FeeProportionalMillionths, - ) + ogFwd := original.ForwardingPolicy() + + require.Equal(t, original.SCID().ToUint64(), cached.ChannelID) + require.Equal(t, ogFwd.HasMaxHTLC, cached.HasMaxHTLC) + require.Equal(t, original.IsDisabled(), cached.IsDisabled) + require.Equal(t, ogFwd.TimeLockDelta, cached.TimeLockDelta) + require.Equal(t, ogFwd.MinHTLC, cached.MinHTLC) + require.Equal(t, ogFwd.MaxHTLC, cached.MaxHTLC) + require.Equal(t, ogFwd.BaseFee, cached.FeeBaseMSat) require.Equal( - t, route.Vertex(original.ToNode), cached.ToNodePubKey(), + t, route.Vertex(original.GetToNode()), cached.ToNodePubKey(), ) } From 53c8b77c3546ecdca60ced9cb757cf50ea4926f0 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 21 Aug 2024 13:11:58 +0200 Subject: [PATCH 15/60] lnrpc: update in preparation for G175 Add a new ChannelUpdate2 message which can be returned with a Failure. Also add a block_height member to the RoutingPolicy which will be populated when the last_update field is not. --- lnrpc/devrpc/dev.swagger.json | 4 + lnrpc/lightning.pb.go | 3763 ++++++++++++++------------- lnrpc/lightning.proto | 82 + lnrpc/lightning.swagger.json | 72 + lnrpc/routerrpc/router.swagger.json | 68 + 5 files changed, 2221 insertions(+), 1768 deletions(-) diff --git a/lnrpc/devrpc/dev.swagger.json b/lnrpc/devrpc/dev.swagger.json index 16e16d7be8..79f3337168 100644 --- a/lnrpc/devrpc/dev.swagger.json +++ b/lnrpc/devrpc/dev.swagger.json @@ -225,6 +225,10 @@ "inbound_fee_rate_milli_msat": { "type": "integer", "format": "int32" + }, + "block_height": { + "type": "integer", + "format": "int64" } } }, diff --git a/lnrpc/lightning.pb.go b/lnrpc/lightning.pb.go index 60a970ba61..c09884f011 100644 --- a/lnrpc/lightning.pb.go +++ b/lnrpc/lightning.pb.go @@ -10927,6 +10927,7 @@ type RoutingPolicy struct { CustomRecords map[uint64][]byte `protobuf:"bytes,8,rep,name=custom_records,json=customRecords,proto3" json:"custom_records,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` InboundFeeBaseMsat int32 `protobuf:"varint,9,opt,name=inbound_fee_base_msat,json=inboundFeeBaseMsat,proto3" json:"inbound_fee_base_msat,omitempty"` InboundFeeRateMilliMsat int32 `protobuf:"varint,10,opt,name=inbound_fee_rate_milli_msat,json=inboundFeeRateMilliMsat,proto3" json:"inbound_fee_rate_milli_msat,omitempty"` + BlockHeight uint32 `protobuf:"varint,11,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"` } func (x *RoutingPolicy) Reset() { @@ -11031,6 +11032,13 @@ func (x *RoutingPolicy) GetInboundFeeRateMilliMsat() int32 { return 0 } +func (x *RoutingPolicy) GetBlockHeight() uint32 { + if x != nil { + return x.BlockHeight + } + return 0 +} + // A fully authenticated channel along with all its unique attributes. // Once an authenticated channel announcement has been processed on the network, // then an instance of ChannelEdgeInfo encapsulating the channels attributes is @@ -16685,6 +16693,8 @@ type Failure struct { FailureSourceIndex uint32 `protobuf:"varint,8,opt,name=failure_source_index,json=failureSourceIndex,proto3" json:"failure_source_index,omitempty"` // A failure type-dependent block height. Height uint32 `protobuf:"varint,9,opt,name=height,proto3" json:"height,omitempty"` + // An optional channel update 2 message. + ChannelUpdate_2 *ChannelUpdate2 `protobuf:"bytes,10,opt,name=channel_update_2,json=channelUpdate2,proto3" json:"channel_update_2,omitempty"` } func (x *Failure) Reset() { @@ -16775,6 +16785,13 @@ func (x *Failure) GetHeight() uint32 { return 0 } +func (x *Failure) GetChannelUpdate_2() *ChannelUpdate2 { + if x != nil { + return x.ChannelUpdate_2 + } + return nil +} + type ChannelUpdate struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -16943,6 +16960,168 @@ func (x *ChannelUpdate) GetExtraOpaqueData() []byte { return nil } +type ChannelUpdate2 struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The signature that validates the announced data and proves the ownership + // of node id. + Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"` + // The target chain that this channel was opened within. This value + // should be the genesis hash of the target chain. Along with the short + // channel ID, this uniquely identifies the channel globally in a + // blockchain. + ChainHash []byte `protobuf:"bytes,2,opt,name=chain_hash,json=chainHash,proto3" json:"chain_hash,omitempty"` + // The unique description of the funding transaction. + ChanId uint64 `protobuf:"varint,3,opt,name=chan_id,json=chanId,proto3" json:"chan_id,omitempty"` + // A block height that allows ordering in the case of multiple announcements. + // We should ignore the message if block_height is not greater than the + // last-received. + BlockHeight uint32 `protobuf:"varint,4,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"` + // A bit field describing the disabled bits set on the update. + DisabledFlags uint32 `protobuf:"varint,5,opt,name=disabled_flags,json=disabledFlags,proto3" json:"disabled_flags,omitempty"` + // If true, this update is from node 2. Otherwise, it is from node 1. + Direction bool `protobuf:"varint,6,opt,name=direction,proto3" json:"direction,omitempty"` + // The minimum number of blocks this node requires to be added to the expiry + // of HTLCs. This is a security parameter determined by the node operator. + // This value represents the required gap between the time locks of the + // incoming and outgoing HTLC's set to this node. + TimeLockDelta uint32 `protobuf:"varint,7,opt,name=time_lock_delta,json=timeLockDelta,proto3" json:"time_lock_delta,omitempty"` + // The base fee that must be used for incoming HTLC's to this particular + // channel. This value will be tacked onto the required for a payment + // independent of the size of the payment. + BaseFee uint32 `protobuf:"varint,8,opt,name=base_fee,json=baseFee,proto3" json:"base_fee,omitempty"` + // The fee rate that will be charged per millionth of a satoshi. + FeeRate uint32 `protobuf:"varint,9,opt,name=fee_rate,json=feeRate,proto3" json:"fee_rate,omitempty"` + // The minimum HTLC value which will be accepted. + HtlcMinimumMsat uint64 `protobuf:"varint,10,opt,name=htlc_minimum_msat,json=htlcMinimumMsat,proto3" json:"htlc_minimum_msat,omitempty"` + // The maximum HTLC value which will be accepted. + HtlcMaximumMsat uint64 `protobuf:"varint,11,opt,name=htlc_maximum_msat,json=htlcMaximumMsat,proto3" json:"htlc_maximum_msat,omitempty"` + // The set of data that was appended to this message, some of which we may + // not actually know how to iterate or parse. By holding onto this data, we + // ensure that we're able to properly validate the set of signatures that + // cover these new fields, and ensure we're able to make upgrades to the + // network in a forwards compatible manner. + ExtraOpaqueData []byte `protobuf:"bytes,12,opt,name=extra_opaque_data,json=extraOpaqueData,proto3" json:"extra_opaque_data,omitempty"` +} + +func (x *ChannelUpdate2) Reset() { + *x = ChannelUpdate2{} + if protoimpl.UnsafeEnabled { + mi := &file_lightning_proto_msgTypes[191] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChannelUpdate2) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChannelUpdate2) ProtoMessage() {} + +func (x *ChannelUpdate2) ProtoReflect() protoreflect.Message { + mi := &file_lightning_proto_msgTypes[191] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChannelUpdate2.ProtoReflect.Descriptor instead. +func (*ChannelUpdate2) Descriptor() ([]byte, []int) { + return file_lightning_proto_rawDescGZIP(), []int{191} +} + +func (x *ChannelUpdate2) GetSignature() []byte { + if x != nil { + return x.Signature + } + return nil +} + +func (x *ChannelUpdate2) GetChainHash() []byte { + if x != nil { + return x.ChainHash + } + return nil +} + +func (x *ChannelUpdate2) GetChanId() uint64 { + if x != nil { + return x.ChanId + } + return 0 +} + +func (x *ChannelUpdate2) GetBlockHeight() uint32 { + if x != nil { + return x.BlockHeight + } + return 0 +} + +func (x *ChannelUpdate2) GetDisabledFlags() uint32 { + if x != nil { + return x.DisabledFlags + } + return 0 +} + +func (x *ChannelUpdate2) GetDirection() bool { + if x != nil { + return x.Direction + } + return false +} + +func (x *ChannelUpdate2) GetTimeLockDelta() uint32 { + if x != nil { + return x.TimeLockDelta + } + return 0 +} + +func (x *ChannelUpdate2) GetBaseFee() uint32 { + if x != nil { + return x.BaseFee + } + return 0 +} + +func (x *ChannelUpdate2) GetFeeRate() uint32 { + if x != nil { + return x.FeeRate + } + return 0 +} + +func (x *ChannelUpdate2) GetHtlcMinimumMsat() uint64 { + if x != nil { + return x.HtlcMinimumMsat + } + return 0 +} + +func (x *ChannelUpdate2) GetHtlcMaximumMsat() uint64 { + if x != nil { + return x.HtlcMaximumMsat + } + return 0 +} + +func (x *ChannelUpdate2) GetExtraOpaqueData() []byte { + if x != nil { + return x.ExtraOpaqueData + } + return nil +} + type MacaroonId struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -16956,7 +17135,7 @@ type MacaroonId struct { func (x *MacaroonId) Reset() { *x = MacaroonId{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[191] + mi := &file_lightning_proto_msgTypes[192] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -16969,7 +17148,7 @@ func (x *MacaroonId) String() string { func (*MacaroonId) ProtoMessage() {} func (x *MacaroonId) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[191] + mi := &file_lightning_proto_msgTypes[192] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -16982,7 +17161,7 @@ func (x *MacaroonId) ProtoReflect() protoreflect.Message { // Deprecated: Use MacaroonId.ProtoReflect.Descriptor instead. func (*MacaroonId) Descriptor() ([]byte, []int) { - return file_lightning_proto_rawDescGZIP(), []int{191} + return file_lightning_proto_rawDescGZIP(), []int{192} } func (x *MacaroonId) GetNonce() []byte { @@ -17018,7 +17197,7 @@ type Op struct { func (x *Op) Reset() { *x = Op{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[192] + mi := &file_lightning_proto_msgTypes[193] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17031,7 +17210,7 @@ func (x *Op) String() string { func (*Op) ProtoMessage() {} func (x *Op) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[192] + mi := &file_lightning_proto_msgTypes[193] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17044,7 +17223,7 @@ func (x *Op) ProtoReflect() protoreflect.Message { // Deprecated: Use Op.ProtoReflect.Descriptor instead. func (*Op) Descriptor() ([]byte, []int) { - return file_lightning_proto_rawDescGZIP(), []int{192} + return file_lightning_proto_rawDescGZIP(), []int{193} } func (x *Op) GetEntity() string { @@ -17074,7 +17253,7 @@ type CheckMacPermRequest struct { func (x *CheckMacPermRequest) Reset() { *x = CheckMacPermRequest{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[193] + mi := &file_lightning_proto_msgTypes[194] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17087,7 +17266,7 @@ func (x *CheckMacPermRequest) String() string { func (*CheckMacPermRequest) ProtoMessage() {} func (x *CheckMacPermRequest) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[193] + mi := &file_lightning_proto_msgTypes[194] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17100,7 +17279,7 @@ func (x *CheckMacPermRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckMacPermRequest.ProtoReflect.Descriptor instead. func (*CheckMacPermRequest) Descriptor() ([]byte, []int) { - return file_lightning_proto_rawDescGZIP(), []int{193} + return file_lightning_proto_rawDescGZIP(), []int{194} } func (x *CheckMacPermRequest) GetMacaroon() []byte { @@ -17135,7 +17314,7 @@ type CheckMacPermResponse struct { func (x *CheckMacPermResponse) Reset() { *x = CheckMacPermResponse{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[194] + mi := &file_lightning_proto_msgTypes[195] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17148,7 +17327,7 @@ func (x *CheckMacPermResponse) String() string { func (*CheckMacPermResponse) ProtoMessage() {} func (x *CheckMacPermResponse) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[194] + mi := &file_lightning_proto_msgTypes[195] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17161,7 +17340,7 @@ func (x *CheckMacPermResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckMacPermResponse.ProtoReflect.Descriptor instead. func (*CheckMacPermResponse) Descriptor() ([]byte, []int) { - return file_lightning_proto_rawDescGZIP(), []int{194} + return file_lightning_proto_rawDescGZIP(), []int{195} } func (x *CheckMacPermResponse) GetValid() bool { @@ -17215,7 +17394,7 @@ type RPCMiddlewareRequest struct { func (x *RPCMiddlewareRequest) Reset() { *x = RPCMiddlewareRequest{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[195] + mi := &file_lightning_proto_msgTypes[196] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17228,7 +17407,7 @@ func (x *RPCMiddlewareRequest) String() string { func (*RPCMiddlewareRequest) ProtoMessage() {} func (x *RPCMiddlewareRequest) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[195] + mi := &file_lightning_proto_msgTypes[196] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17241,7 +17420,7 @@ func (x *RPCMiddlewareRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RPCMiddlewareRequest.ProtoReflect.Descriptor instead. func (*RPCMiddlewareRequest) Descriptor() ([]byte, []int) { - return file_lightning_proto_rawDescGZIP(), []int{195} + return file_lightning_proto_rawDescGZIP(), []int{196} } func (x *RPCMiddlewareRequest) GetRequestId() uint64 { @@ -17369,7 +17548,7 @@ type StreamAuth struct { func (x *StreamAuth) Reset() { *x = StreamAuth{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[196] + mi := &file_lightning_proto_msgTypes[197] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17382,7 +17561,7 @@ func (x *StreamAuth) String() string { func (*StreamAuth) ProtoMessage() {} func (x *StreamAuth) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[196] + mi := &file_lightning_proto_msgTypes[197] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17395,7 +17574,7 @@ func (x *StreamAuth) ProtoReflect() protoreflect.Message { // Deprecated: Use StreamAuth.ProtoReflect.Descriptor instead. func (*StreamAuth) Descriptor() ([]byte, []int) { - return file_lightning_proto_rawDescGZIP(), []int{196} + return file_lightning_proto_rawDescGZIP(), []int{197} } func (x *StreamAuth) GetMethodFullUri() string { @@ -17432,7 +17611,7 @@ type RPCMessage struct { func (x *RPCMessage) Reset() { *x = RPCMessage{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[197] + mi := &file_lightning_proto_msgTypes[198] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17445,7 +17624,7 @@ func (x *RPCMessage) String() string { func (*RPCMessage) ProtoMessage() {} func (x *RPCMessage) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[197] + mi := &file_lightning_proto_msgTypes[198] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17458,7 +17637,7 @@ func (x *RPCMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use RPCMessage.ProtoReflect.Descriptor instead. func (*RPCMessage) Descriptor() ([]byte, []int) { - return file_lightning_proto_rawDescGZIP(), []int{197} + return file_lightning_proto_rawDescGZIP(), []int{198} } func (x *RPCMessage) GetMethodFullUri() string { @@ -17519,7 +17698,7 @@ type RPCMiddlewareResponse struct { func (x *RPCMiddlewareResponse) Reset() { *x = RPCMiddlewareResponse{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[198] + mi := &file_lightning_proto_msgTypes[199] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17532,7 +17711,7 @@ func (x *RPCMiddlewareResponse) String() string { func (*RPCMiddlewareResponse) ProtoMessage() {} func (x *RPCMiddlewareResponse) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[198] + mi := &file_lightning_proto_msgTypes[199] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17545,7 +17724,7 @@ func (x *RPCMiddlewareResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RPCMiddlewareResponse.ProtoReflect.Descriptor instead. func (*RPCMiddlewareResponse) Descriptor() ([]byte, []int) { - return file_lightning_proto_rawDescGZIP(), []int{198} + return file_lightning_proto_rawDescGZIP(), []int{199} } func (x *RPCMiddlewareResponse) GetRefMsgId() uint64 { @@ -17631,7 +17810,7 @@ type MiddlewareRegistration struct { func (x *MiddlewareRegistration) Reset() { *x = MiddlewareRegistration{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[199] + mi := &file_lightning_proto_msgTypes[200] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17644,7 +17823,7 @@ func (x *MiddlewareRegistration) String() string { func (*MiddlewareRegistration) ProtoMessage() {} func (x *MiddlewareRegistration) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[199] + mi := &file_lightning_proto_msgTypes[200] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17657,7 +17836,7 @@ func (x *MiddlewareRegistration) ProtoReflect() protoreflect.Message { // Deprecated: Use MiddlewareRegistration.ProtoReflect.Descriptor instead. func (*MiddlewareRegistration) Descriptor() ([]byte, []int) { - return file_lightning_proto_rawDescGZIP(), []int{199} + return file_lightning_proto_rawDescGZIP(), []int{200} } func (x *MiddlewareRegistration) GetMiddlewareName() string { @@ -17704,7 +17883,7 @@ type InterceptFeedback struct { func (x *InterceptFeedback) Reset() { *x = InterceptFeedback{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[200] + mi := &file_lightning_proto_msgTypes[201] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17717,7 +17896,7 @@ func (x *InterceptFeedback) String() string { func (*InterceptFeedback) ProtoMessage() {} func (x *InterceptFeedback) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[200] + mi := &file_lightning_proto_msgTypes[201] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17730,7 +17909,7 @@ func (x *InterceptFeedback) ProtoReflect() protoreflect.Message { // Deprecated: Use InterceptFeedback.ProtoReflect.Descriptor instead. func (*InterceptFeedback) Descriptor() ([]byte, []int) { - return file_lightning_proto_rawDescGZIP(), []int{200} + return file_lightning_proto_rawDescGZIP(), []int{201} } func (x *InterceptFeedback) GetError() string { @@ -17791,7 +17970,7 @@ type PendingChannelsResponse_PendingChannel struct { func (x *PendingChannelsResponse_PendingChannel) Reset() { *x = PendingChannelsResponse_PendingChannel{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[207] + mi := &file_lightning_proto_msgTypes[208] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17804,7 +17983,7 @@ func (x *PendingChannelsResponse_PendingChannel) String() string { func (*PendingChannelsResponse_PendingChannel) ProtoMessage() {} func (x *PendingChannelsResponse_PendingChannel) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[207] + mi := &file_lightning_proto_msgTypes[208] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -17952,7 +18131,7 @@ type PendingChannelsResponse_PendingOpenChannel struct { func (x *PendingChannelsResponse_PendingOpenChannel) Reset() { *x = PendingChannelsResponse_PendingOpenChannel{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[208] + mi := &file_lightning_proto_msgTypes[209] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -17965,7 +18144,7 @@ func (x *PendingChannelsResponse_PendingOpenChannel) String() string { func (*PendingChannelsResponse_PendingOpenChannel) ProtoMessage() {} func (x *PendingChannelsResponse_PendingOpenChannel) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[208] + mi := &file_lightning_proto_msgTypes[209] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18038,7 +18217,7 @@ type PendingChannelsResponse_WaitingCloseChannel struct { func (x *PendingChannelsResponse_WaitingCloseChannel) Reset() { *x = PendingChannelsResponse_WaitingCloseChannel{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[209] + mi := &file_lightning_proto_msgTypes[210] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18051,7 +18230,7 @@ func (x *PendingChannelsResponse_WaitingCloseChannel) String() string { func (*PendingChannelsResponse_WaitingCloseChannel) ProtoMessage() {} func (x *PendingChannelsResponse_WaitingCloseChannel) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[209] + mi := &file_lightning_proto_msgTypes[210] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18127,7 +18306,7 @@ type PendingChannelsResponse_Commitments struct { func (x *PendingChannelsResponse_Commitments) Reset() { *x = PendingChannelsResponse_Commitments{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[210] + mi := &file_lightning_proto_msgTypes[211] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18140,7 +18319,7 @@ func (x *PendingChannelsResponse_Commitments) String() string { func (*PendingChannelsResponse_Commitments) ProtoMessage() {} func (x *PendingChannelsResponse_Commitments) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[210] + mi := &file_lightning_proto_msgTypes[211] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18212,7 +18391,7 @@ type PendingChannelsResponse_ClosedChannel struct { func (x *PendingChannelsResponse_ClosedChannel) Reset() { *x = PendingChannelsResponse_ClosedChannel{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[211] + mi := &file_lightning_proto_msgTypes[212] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18225,7 +18404,7 @@ func (x *PendingChannelsResponse_ClosedChannel) String() string { func (*PendingChannelsResponse_ClosedChannel) ProtoMessage() {} func (x *PendingChannelsResponse_ClosedChannel) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[211] + mi := &file_lightning_proto_msgTypes[212] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -18281,7 +18460,7 @@ type PendingChannelsResponse_ForceClosedChannel struct { func (x *PendingChannelsResponse_ForceClosedChannel) Reset() { *x = PendingChannelsResponse_ForceClosedChannel{} if protoimpl.UnsafeEnabled { - mi := &file_lightning_proto_msgTypes[212] + mi := &file_lightning_proto_msgTypes[213] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -18294,7 +18473,7 @@ func (x *PendingChannelsResponse_ForceClosedChannel) String() string { func (*PendingChannelsResponse_ForceClosedChannel) ProtoMessage() {} func (x *PendingChannelsResponse_ForceClosedChannel) ProtoReflect() protoreflect.Message { - mi := &file_lightning_proto_msgTypes[212] + mi := &file_lightning_proto_msgTypes[213] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -19981,7 +20160,7 @@ var file_lightning_proto_rawDesc = []byte{ 0x0b, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x22, 0x89, 0x04, 0x0a, 0x0d, 0x52, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x22, 0xac, 0x04, 0x0a, 0x0d, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x44, @@ -20010,1499 +20189,1533 @@ var file_lightning_proto_rawDesc = []byte{ 0x64, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x17, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x6c, 0x6c, 0x69, - 0x4d, 0x73, 0x61, 0x74, 0x1a, 0x40, 0x0a, 0x12, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, + 0x4d, 0x73, 0x61, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x1a, 0x40, 0x0a, 0x12, 0x43, 0x75, 0x73, 0x74, 0x6f, + 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xcc, 0x03, 0x0a, 0x0b, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x64, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x0a, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, + 0x01, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, + 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x23, 0x0a, 0x0b, 0x6c, + 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, + 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x31, 0x5f, 0x70, 0x75, 0x62, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x31, 0x50, 0x75, 0x62, 0x12, 0x1b, 0x0a, + 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x32, 0x5f, 0x70, 0x75, 0x62, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x32, 0x50, 0x75, 0x62, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, + 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x63, 0x61, + 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x37, 0x0a, 0x0c, 0x6e, 0x6f, 0x64, 0x65, 0x31, 0x5f, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x52, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x31, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, + 0x37, 0x0a, 0x0c, 0x6e, 0x6f, 0x64, 0x65, 0x32, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, + 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0b, 0x6e, 0x6f, 0x64, + 0x65, 0x32, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x4c, 0x0a, 0x0e, 0x63, 0x75, 0x73, 0x74, + 0x6f, 0x6d, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x25, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x45, 0x64, 0x67, 0x65, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, + 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x46, 0x0a, 0x13, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x2f, 0x0a, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x75, 0x6e, 0x61, 0x6e, 0x6e, + 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x69, 0x6e, + 0x63, 0x6c, 0x75, 0x64, 0x65, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x64, + 0x22, 0x64, 0x0a, 0x0c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, + 0x12, 0x2a, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, + 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x05, + 0x65, 0x64, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x64, 0x67, 0x65, 0x52, + 0x05, 0x65, 0x64, 0x67, 0x65, 0x73, 0x22, 0x41, 0x0a, 0x12, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x05, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x22, 0xe1, 0x01, 0x0a, 0x13, 0x4e, 0x6f, + 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x6c, 0x0a, 0x16, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x73, + 0x5f, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x35, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x42, 0x65, + 0x74, 0x77, 0x65, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, + 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x15, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, + 0x6e, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x1a, + 0x5c, 0x0a, 0x1a, 0x42, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x65, + 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x28, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4e, 0x0a, + 0x0b, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0f, 0x6e, 0x6f, + 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4d, 0x0a, + 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1b, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, + 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x14, 0x0a, 0x12, + 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x22, 0xd5, 0x03, 0x0a, 0x0b, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x25, 0x0a, 0x0e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x64, 0x69, 0x61, 0x6d, + 0x65, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x44, 0x69, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0e, 0x61, 0x76, 0x67, + 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x67, 0x72, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x01, 0x52, 0x0c, 0x61, 0x76, 0x67, 0x4f, 0x75, 0x74, 0x44, 0x65, 0x67, 0x72, 0x65, 0x65, 0x12, + 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x67, 0x72, 0x65, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x4f, 0x75, 0x74, 0x44, + 0x65, 0x67, 0x72, 0x65, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x75, 0x6d, 0x5f, 0x6e, 0x6f, 0x64, + 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6e, 0x75, 0x6d, 0x4e, 0x6f, 0x64, + 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x34, 0x0a, 0x16, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x28, 0x0a, 0x10, 0x61, + 0x76, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0e, 0x61, 0x76, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0e, 0x6d, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x12, + 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x73, + 0x69, 0x7a, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x17, 0x6d, 0x65, 0x64, + 0x69, 0x61, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x73, 0x69, 0x7a, 0x65, + 0x5f, 0x73, 0x61, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x6d, 0x65, 0x64, 0x69, + 0x61, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x53, 0x61, 0x74, + 0x12, 0x28, 0x0a, 0x10, 0x6e, 0x75, 0x6d, 0x5f, 0x7a, 0x6f, 0x6d, 0x62, 0x69, 0x65, 0x5f, 0x63, + 0x68, 0x61, 0x6e, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x6e, 0x75, 0x6d, 0x5a, + 0x6f, 0x6d, 0x62, 0x69, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x73, 0x22, 0x0d, 0x0a, 0x0b, 0x53, 0x74, + 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x0e, 0x0a, 0x0c, 0x53, 0x74, 0x6f, + 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x47, 0x72, 0x61, + 0x70, 0x68, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xcd, 0x01, 0x0a, 0x13, 0x47, 0x72, 0x61, 0x70, 0x68, + 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x34, + 0x0a, 0x0c, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, + 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x0f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x64, 0x67, + 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x0e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x3d, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x65, + 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x63, 0x6c, 0x6f, 0x73, 0x65, + 0x64, 0x43, 0x68, 0x61, 0x6e, 0x73, 0x22, 0xef, 0x02, 0x0a, 0x0a, 0x4e, 0x6f, 0x64, 0x65, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x2b, 0x0a, 0x0f, 0x67, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0c, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x14, 0x0a, + 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, + 0x6c, 0x6f, 0x72, 0x12, 0x39, 0x0a, 0x0e, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, + 0x0d, 0x6e, 0x6f, 0x64, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x3b, + 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x1a, 0x4b, 0x0a, 0x0d, 0x46, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x24, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x91, 0x02, 0x0a, 0x11, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x64, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1b, + 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, + 0x02, 0x30, 0x01, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x0a, 0x63, + 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, + 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, + 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x08, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x3b, 0x0a, 0x0e, 0x72, + 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, + 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0d, 0x72, 0x6f, 0x75, 0x74, 0x69, + 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x64, 0x76, 0x65, + 0x72, 0x74, 0x69, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x69, 0x6e, 0x67, 0x4e, + 0x6f, 0x64, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6e, + 0x67, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x22, 0xa7, 0x01, 0x0a, + 0x13, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x49, + 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x08, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x23, 0x0a, + 0x0d, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x48, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x12, 0x32, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x09, 0x63, 0x68, 0x61, + 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0xcf, 0x01, 0x0a, 0x07, 0x48, 0x6f, 0x70, 0x48, 0x69, + 0x6e, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x07, 0x63, + 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, + 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x66, 0x65, 0x65, 0x5f, + 0x62, 0x61, 0x73, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0b, 0x66, 0x65, 0x65, 0x42, 0x61, 0x73, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x3e, 0x0a, 0x1b, + 0x66, 0x65, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, + 0x5f, 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x19, 0x66, 0x65, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x12, 0x2a, 0x0a, 0x11, + 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x64, 0x65, 0x6c, 0x74, + 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x63, 0x6c, 0x74, 0x76, 0x45, 0x78, 0x70, + 0x69, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x22, 0x1e, 0x0a, 0x05, 0x53, 0x65, 0x74, 0x49, + 0x44, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x73, 0x65, 0x74, 0x49, 0x64, 0x22, 0x38, 0x0a, 0x09, 0x52, 0x6f, 0x75, 0x74, + 0x65, 0x48, 0x69, 0x6e, 0x74, 0x12, 0x2b, 0x0a, 0x09, 0x68, 0x6f, 0x70, 0x5f, 0x68, 0x69, 0x6e, + 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x48, 0x6f, 0x70, 0x48, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x68, 0x6f, 0x70, 0x48, 0x69, 0x6e, + 0x74, 0x73, 0x22, 0xc4, 0x02, 0x0a, 0x12, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x35, 0x0a, 0x0c, 0x62, 0x6c, 0x69, + 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x50, + 0x61, 0x74, 0x68, 0x52, 0x0b, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, + 0x12, 0x22, 0x0a, 0x0d, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, 0x61, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, + 0x4d, 0x73, 0x61, 0x74, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x72, 0x74, 0x69, + 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x13, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x46, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x5f, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6c, 0x74, 0x76, 0x44, 0x65, 0x6c, + 0x74, 0x61, 0x12, 0x22, 0x0a, 0x0d, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x6d, + 0x73, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x68, 0x74, 0x6c, 0x63, 0x4d, + 0x69, 0x6e, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, + 0x61, 0x78, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x68, + 0x74, 0x6c, 0x63, 0x4d, 0x61, 0x78, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x2d, 0x0a, 0x08, 0x66, 0x65, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x69, 0x74, 0x52, + 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x97, 0x01, 0x0a, 0x0b, 0x42, 0x6c, + 0x69, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x6e, 0x74, + 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, + 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x34, 0x0a, + 0x0c, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x68, 0x6f, 0x70, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x69, 0x6e, + 0x64, 0x65, 0x64, 0x48, 0x6f, 0x70, 0x52, 0x0b, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x48, + 0x6f, 0x70, 0x73, 0x22, 0x56, 0x0a, 0x0a, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x48, 0x6f, + 0x70, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x6e, 0x6f, 0x64, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, + 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, + 0x64, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x65, 0x6e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x22, 0xa8, 0x01, 0x0a, 0x0f, + 0x41, 0x4d, 0x50, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, + 0x2d, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x48, 0x54, + 0x4c, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x21, + 0x0a, 0x0c, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x49, 0x6e, 0x64, 0x65, + 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x6d, 0x74, 0x5f, 0x70, 0x61, 0x69, 0x64, 0x5f, 0x6d, + 0x73, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x6d, 0x74, 0x50, 0x61, + 0x69, 0x64, 0x4d, 0x73, 0x61, 0x74, 0x22, 0xac, 0x0a, 0x0a, 0x07, 0x49, 0x6e, 0x76, 0x6f, 0x69, + 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x69, + 0x6d, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x72, 0x50, 0x72, 0x65, + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x72, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, + 0x18, 0x17, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x4d, 0x73, 0x61, + 0x74, 0x12, 0x1c, 0x0a, 0x07, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x12, + 0x23, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x44, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x64, + 0x61, 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x73, 0x65, 0x74, 0x74, 0x6c, + 0x65, 0x44, 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, + 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, + 0x0a, 0x10, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x61, + 0x73, 0x68, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78, 0x70, + 0x69, 0x72, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, + 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, + 0x63, 0x6b, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x65, + 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x63, 0x6c, 0x74, + 0x76, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x12, 0x31, 0x0a, 0x0b, 0x72, 0x6f, 0x75, 0x74, 0x65, + 0x5f, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x52, 0x0a, + 0x72, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, + 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x72, 0x69, + 0x76, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x61, 0x64, 0x64, 0x49, 0x6e, 0x64, 0x65, + 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x18, 0x11, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1d, 0x0a, 0x08, 0x61, 0x6d, 0x74, 0x5f, 0x70, 0x61, 0x69, 0x64, + 0x18, 0x12, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x61, 0x6d, 0x74, 0x50, + 0x61, 0x69, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x61, 0x6d, 0x74, 0x5f, 0x70, 0x61, 0x69, 0x64, 0x5f, + 0x73, 0x61, 0x74, 0x18, 0x13, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x61, 0x6d, 0x74, 0x50, 0x61, + 0x69, 0x64, 0x53, 0x61, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x6d, 0x74, 0x5f, 0x70, 0x61, 0x69, + 0x64, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x6d, + 0x74, 0x50, 0x61, 0x69, 0x64, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x31, 0x0a, 0x05, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x05, + 0x68, 0x74, 0x6c, 0x63, 0x73, 0x18, 0x16, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x48, 0x54, 0x4c, 0x43, 0x52, + 0x05, 0x68, 0x74, 0x6c, 0x63, 0x73, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x73, 0x18, 0x18, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, + 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x65, 0x6e, 0x64, 0x18, 0x19, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x4b, 0x65, 0x79, 0x73, 0x65, 0x6e, 0x64, 0x12, + 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, + 0x1a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, + 0x64, 0x72, 0x12, 0x15, 0x0a, 0x06, 0x69, 0x73, 0x5f, 0x61, 0x6d, 0x70, 0x18, 0x1b, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x05, 0x69, 0x73, 0x41, 0x6d, 0x70, 0x12, 0x4f, 0x0a, 0x11, 0x61, 0x6d, 0x70, + 0x5f, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x1c, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, + 0x6f, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x6d, 0x70, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x61, 0x6d, 0x70, 0x49, 0x6e, + 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, + 0x5f, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, + 0x69, 0x73, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x12, 0x48, 0x0a, 0x13, 0x62, 0x6c, 0x69, + 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, + 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x11, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x1a, 0x4b, 0x0a, 0x0d, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x1a, 0x5a, 0x0a, 0x14, 0x41, 0x6d, 0x70, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x41, 0x4d, 0x50, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x41, 0x0a, 0x0c, + 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x08, 0x0a, 0x04, + 0x4f, 0x50, 0x45, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, + 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, + 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, 0x03, 0x4a, + 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, 0xef, 0x01, 0x0a, 0x11, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, + 0x64, 0x50, 0x61, 0x74, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x11, 0x6d, + 0x69, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x68, 0x6f, 0x70, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x0e, 0x6d, 0x69, 0x6e, 0x4e, 0x75, 0x6d, + 0x52, 0x65, 0x61, 0x6c, 0x48, 0x6f, 0x70, 0x73, 0x88, 0x01, 0x01, 0x12, 0x1e, 0x0a, 0x08, 0x6e, + 0x75, 0x6d, 0x5f, 0x68, 0x6f, 0x70, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x01, 0x52, + 0x07, 0x6e, 0x75, 0x6d, 0x48, 0x6f, 0x70, 0x73, 0x88, 0x01, 0x01, 0x12, 0x27, 0x0a, 0x0d, 0x6d, + 0x61, 0x78, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0d, 0x48, 0x02, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x4e, 0x75, 0x6d, 0x50, 0x61, 0x74, 0x68, + 0x73, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x12, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6f, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, + 0x52, 0x10, 0x6e, 0x6f, 0x64, 0x65, 0x4f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, + 0x73, 0x74, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x72, + 0x65, 0x61, 0x6c, 0x5f, 0x68, 0x6f, 0x70, 0x73, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6e, 0x75, 0x6d, + 0x5f, 0x68, 0x6f, 0x70, 0x73, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x6e, 0x75, + 0x6d, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x22, 0xac, 0x04, 0x0a, 0x0b, 0x49, 0x6e, 0x76, 0x6f, + 0x69, 0x63, 0x65, 0x48, 0x54, 0x4c, 0x43, 0x12, 0x1b, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x06, 0x63, 0x68, + 0x61, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x68, 0x74, 0x6c, 0x63, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x6d, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x61, 0x6d, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x23, + 0x0a, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x48, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, + 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, 0x65, 0x73, 0x6f, + 0x6c, 0x76, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x69, 0x72, + 0x79, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, + 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x2d, 0x0a, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x48, 0x54, 0x4c, 0x43, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x4c, 0x0a, 0x0e, 0x63, + 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x09, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, + 0x69, 0x63, 0x65, 0x48, 0x54, 0x4c, 0x43, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x63, 0x75, 0x73, 0x74, + 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x2b, 0x0a, 0x12, 0x6d, 0x70, 0x70, + 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6d, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x70, 0x70, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x41, + 0x6d, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x1c, 0x0a, 0x03, 0x61, 0x6d, 0x70, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x4d, 0x50, 0x52, + 0x03, 0x61, 0x6d, 0x70, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x11, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x44, 0x61, 0x74, 0x61, 0x1a, 0x40, 0x0a, 0x12, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xcc, 0x03, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x45, 0x64, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x09, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, - 0x6e, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, - 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x23, 0x0a, 0x0b, 0x6c, 0x61, 0x73, 0x74, - 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x02, 0x18, - 0x01, 0x52, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, - 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x31, 0x5f, 0x70, 0x75, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x31, 0x50, 0x75, 0x62, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, - 0x64, 0x65, 0x32, 0x5f, 0x70, 0x75, 0x62, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, - 0x6f, 0x64, 0x65, 0x32, 0x50, 0x75, 0x62, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x70, 0x61, 0x63, - 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x63, 0x61, 0x70, 0x61, 0x63, - 0x69, 0x74, 0x79, 0x12, 0x37, 0x0a, 0x0c, 0x6e, 0x6f, 0x64, 0x65, 0x31, 0x5f, 0x70, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, - 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x31, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x37, 0x0a, 0x0c, - 0x6e, 0x6f, 0x64, 0x65, 0x32, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, - 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x32, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x4c, 0x0a, 0x0e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, - 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x64, 0x67, - 0x65, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8c, 0x01, 0x0a, 0x03, 0x41, 0x4d, 0x50, 0x12, 0x1d, + 0x0a, 0x0a, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x53, 0x68, 0x61, 0x72, 0x65, 0x12, 0x15, 0x0a, + 0x06, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, + 0x65, 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x63, 0x68, 0x69, 0x6c, 0x64, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x65, + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x70, 0x72, 0x65, + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, + 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x15, 0x0a, 0x06, + 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x72, 0x48, + 0x61, 0x73, 0x68, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, + 0x61, 0x64, 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x08, 0x61, 0x64, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x22, 0x46, 0x0a, 0x0b, + 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x20, 0x0a, 0x0a, 0x72, + 0x5f, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x73, 0x74, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x02, 0x18, 0x01, 0x52, 0x08, 0x72, 0x48, 0x61, 0x73, 0x68, 0x53, 0x74, 0x72, 0x12, 0x15, 0x0a, + 0x06, 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x72, + 0x48, 0x61, 0x73, 0x68, 0x22, 0xfc, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, + 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, + 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0b, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x21, + 0x0a, 0x0c, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x12, 0x28, 0x0a, 0x10, 0x6e, 0x75, 0x6d, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x6e, 0x76, + 0x6f, 0x69, 0x63, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x6e, 0x75, 0x6d, + 0x4d, 0x61, 0x78, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72, + 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, + 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, + 0x74, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x6e, 0x64, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, + 0x45, 0x6e, 0x64, 0x22, 0x9b, 0x01, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, + 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x08, 0x69, + 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x08, 0x69, + 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x10, 0x66, 0x69, 0x72, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x22, 0x55, 0x0a, 0x13, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x5f, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x61, 0x64, 0x64, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x5f, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x65, 0x74, + 0x74, 0x6c, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xcb, 0x06, 0x0a, 0x07, 0x50, 0x61, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, + 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x18, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x12, 0x27, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, + 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0c, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x03, 0x66, 0x65, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x03, 0x66, 0x65, 0x65, + 0x12, 0x29, 0x0a, 0x10, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x69, + 0x6d, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x61, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x61, + 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x66, 0x65, 0x65, 0x53, 0x61, 0x74, 0x12, + 0x19, 0x0a, 0x08, 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x07, 0x66, 0x65, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6e, 0x73, 0x18, 0x0d, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, + 0x6d, 0x65, 0x4e, 0x73, 0x12, 0x28, 0x0a, 0x05, 0x68, 0x74, 0x6c, 0x63, 0x73, 0x18, 0x0e, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x54, 0x4c, 0x43, + 0x41, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x52, 0x05, 0x68, 0x74, 0x6c, 0x63, 0x73, 0x12, 0x23, + 0x0a, 0x0d, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, + 0x0f, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x12, 0x42, 0x0a, 0x0e, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x72, + 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x46, 0x61, 0x69, 0x6c, 0x75, + 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x0d, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, + 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x62, 0x0a, 0x18, 0x66, 0x69, 0x72, 0x73, 0x74, + 0x5f, 0x68, 0x6f, 0x70, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x73, 0x18, 0x11, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x46, 0x69, 0x72, 0x73, 0x74, 0x48, + 0x6f, 0x70, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x15, 0x66, 0x69, 0x72, 0x73, 0x74, 0x48, 0x6f, 0x70, 0x43, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x48, 0x0a, 0x1a, 0x46, + 0x69, 0x72, 0x73, 0x74, 0x48, 0x6f, 0x70, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x46, 0x0a, 0x13, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x13, - 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x75, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, - 0x63, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x69, 0x6e, 0x63, 0x6c, 0x75, - 0x64, 0x65, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x64, 0x22, 0x64, 0x0a, - 0x0c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x2a, 0x0a, - 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x4e, 0x6f, - 0x64, 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x05, 0x65, 0x64, 0x67, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x64, 0x67, 0x65, 0x52, 0x05, 0x65, 0x64, - 0x67, 0x65, 0x73, 0x22, 0x41, 0x0a, 0x12, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x05, 0x74, 0x79, 0x70, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x22, 0xe1, 0x01, 0x0a, 0x13, 0x4e, 0x6f, 0x64, 0x65, 0x4d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, - 0x0a, 0x16, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x65, - 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x42, 0x65, 0x74, 0x77, 0x65, - 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x15, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x6e, 0x65, - 0x73, 0x73, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x1a, 0x5c, 0x0a, 0x1a, - 0x42, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x65, 0x6e, 0x74, 0x72, - 0x61, 0x6c, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4e, 0x0a, 0x0b, 0x46, 0x6c, - 0x6f, 0x61, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, - 0x29, 0x0a, 0x10, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0f, 0x6e, 0x6f, 0x72, 0x6d, 0x61, - 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4d, 0x0a, 0x0f, 0x43, 0x68, - 0x61, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, - 0x07, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, - 0x30, 0x01, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, - 0x61, 0x6e, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x14, 0x0a, 0x12, 0x4e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, - 0xd5, 0x03, 0x0a, 0x0b, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x25, 0x0a, 0x0e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x64, 0x69, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x67, 0x72, 0x61, 0x70, 0x68, 0x44, 0x69, - 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0e, 0x61, 0x76, 0x67, 0x5f, 0x6f, 0x75, - 0x74, 0x5f, 0x64, 0x65, 0x67, 0x72, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, - 0x61, 0x76, 0x67, 0x4f, 0x75, 0x74, 0x44, 0x65, 0x67, 0x72, 0x65, 0x65, 0x12, 0x24, 0x0a, 0x0e, - 0x6d, 0x61, 0x78, 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x67, 0x72, 0x65, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x4f, 0x75, 0x74, 0x44, 0x65, 0x67, 0x72, - 0x65, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x75, 0x6d, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6e, 0x75, 0x6d, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x12, - 0x21, 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x73, 0x12, 0x34, 0x0a, 0x16, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x5f, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x28, 0x0a, 0x10, 0x61, 0x76, 0x67, 0x5f, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x01, 0x52, 0x0e, 0x61, 0x76, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x69, - 0x7a, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6d, 0x69, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x28, 0x0a, 0x10, - 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x73, 0x69, 0x7a, 0x65, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x17, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x6e, - 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x73, 0x61, - 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x6e, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x53, 0x61, 0x74, 0x12, 0x28, 0x0a, - 0x10, 0x6e, 0x75, 0x6d, 0x5f, 0x7a, 0x6f, 0x6d, 0x62, 0x69, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, - 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x6e, 0x75, 0x6d, 0x5a, 0x6f, 0x6d, 0x62, - 0x69, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x73, 0x22, 0x0d, 0x0a, 0x0b, 0x53, 0x74, 0x6f, 0x70, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x0e, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x47, 0x72, 0x61, 0x70, 0x68, 0x54, - 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x22, 0xcd, 0x01, 0x0a, 0x13, 0x47, 0x72, 0x61, 0x70, 0x68, 0x54, 0x6f, 0x70, - 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x34, 0x0a, 0x0c, 0x6e, - 0x6f, 0x64, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x73, 0x12, 0x41, 0x0a, 0x0f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x64, 0x67, 0x65, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x52, 0x0e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x73, 0x12, 0x3d, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x5f, 0x63, - 0x68, 0x61, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, - 0x61, 0x6e, 0x73, 0x22, 0xef, 0x02, 0x0a, 0x0a, 0x4e, 0x6f, 0x64, 0x65, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x12, 0x20, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x2b, 0x0a, 0x0f, 0x67, 0x6c, 0x6f, 0x62, 0x61, - 0x6c, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, - 0x42, 0x02, 0x18, 0x01, 0x52, 0x0e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x46, 0x65, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, - 0x6c, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, - 0x12, 0x39, 0x0a, 0x0e, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0d, 0x6e, 0x6f, - 0x64, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x08, 0x66, - 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, - 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x1a, 0x4b, 0x0a, 0x0d, 0x46, 0x65, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x91, 0x02, 0x0a, 0x11, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x45, 0x64, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x07, 0x63, - 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, - 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, - 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, - 0x74, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, - 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, - 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x3b, 0x0a, 0x0e, 0x72, 0x6f, 0x75, 0x74, - 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0d, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, - 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0f, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, - 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6e, - 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x22, 0xa7, 0x01, 0x0a, 0x13, 0x43, 0x6c, - 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x12, 0x1b, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x1a, - 0x0a, 0x08, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x08, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6c, - 0x6f, 0x73, 0x65, 0x64, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, - 0x32, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, - 0x69, 0x6e, 0x74, 0x22, 0xcf, 0x01, 0x0a, 0x07, 0x48, 0x6f, 0x70, 0x48, 0x69, 0x6e, 0x74, 0x12, - 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, - 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x06, 0x63, - 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x66, 0x65, 0x65, 0x5f, 0x62, 0x61, 0x73, - 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x66, 0x65, - 0x65, 0x42, 0x61, 0x73, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x3e, 0x0a, 0x1b, 0x66, 0x65, 0x65, - 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x6d, 0x69, - 0x6c, 0x6c, 0x69, 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, - 0x66, 0x65, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x4d, - 0x69, 0x6c, 0x6c, 0x69, 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x6c, 0x74, - 0x76, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x63, 0x6c, 0x74, 0x76, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, - 0x44, 0x65, 0x6c, 0x74, 0x61, 0x22, 0x1e, 0x0a, 0x05, 0x53, 0x65, 0x74, 0x49, 0x44, 0x12, 0x15, - 0x0a, 0x06, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, - 0x73, 0x65, 0x74, 0x49, 0x64, 0x22, 0x38, 0x0a, 0x09, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x69, - 0x6e, 0x74, 0x12, 0x2b, 0x0a, 0x09, 0x68, 0x6f, 0x70, 0x5f, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x6f, - 0x70, 0x48, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x68, 0x6f, 0x70, 0x48, 0x69, 0x6e, 0x74, 0x73, 0x22, - 0xc4, 0x02, 0x0a, 0x12, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x35, 0x0a, 0x0c, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x65, - 0x64, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, - 0x52, 0x0b, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, 0x12, 0x22, 0x0a, - 0x0d, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x4d, 0x73, 0x61, - 0x74, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x61, - 0x6c, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x13, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x46, 0x65, - 0x65, 0x52, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, - 0x6c, 0x74, 0x76, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6c, 0x74, 0x76, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, - 0x22, 0x0a, 0x0d, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x6d, 0x73, 0x61, 0x74, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x68, 0x74, 0x6c, 0x63, 0x4d, 0x69, 0x6e, 0x4d, - 0x73, 0x61, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x61, 0x78, 0x5f, - 0x6d, 0x73, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x68, 0x74, 0x6c, 0x63, - 0x4d, 0x61, 0x78, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x2d, 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x69, 0x74, 0x52, 0x08, 0x66, 0x65, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x97, 0x01, 0x0a, 0x0b, 0x42, 0x6c, 0x69, 0x6e, 0x64, - 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, - 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x10, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, - 0x6f, 0x64, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x62, 0x6c, 0x69, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x34, 0x0a, 0x0c, 0x62, 0x6c, - 0x69, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x68, 0x6f, 0x70, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x11, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, - 0x48, 0x6f, 0x70, 0x52, 0x0b, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x48, 0x6f, 0x70, 0x73, - 0x22, 0x56, 0x0a, 0x0a, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x48, 0x6f, 0x70, 0x12, 0x21, - 0x0a, 0x0c, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x64, - 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x64, - 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x65, 0x6e, 0x63, 0x72, 0x79, - 0x70, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x22, 0xa8, 0x01, 0x0a, 0x0f, 0x41, 0x4d, 0x50, - 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2d, 0x0a, 0x05, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x48, 0x54, 0x4c, 0x43, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, - 0x65, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0b, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1f, - 0x0a, 0x0b, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0a, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, - 0x22, 0x0a, 0x0d, 0x61, 0x6d, 0x74, 0x5f, 0x70, 0x61, 0x69, 0x64, 0x5f, 0x6d, 0x73, 0x61, 0x74, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x6d, 0x74, 0x50, 0x61, 0x69, 0x64, 0x4d, - 0x73, 0x61, 0x74, 0x22, 0xac, 0x0a, 0x0a, 0x07, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, - 0x12, 0x0a, 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, - 0x65, 0x6d, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x72, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, - 0x67, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x72, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, - 0x1d, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x17, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x1c, - 0x0a, 0x07, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x42, - 0x02, 0x18, 0x01, 0x52, 0x07, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x12, 0x23, 0x0a, 0x0d, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, - 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x61, - 0x74, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, - 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x12, 0x23, - 0x0a, 0x0d, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, - 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x41, - 0x64, 0x64, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x65, 0x78, 0x70, 0x69, - 0x72, 0x79, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x63, 0x6c, 0x74, 0x76, 0x45, 0x78, - 0x70, 0x69, 0x72, 0x79, 0x12, 0x31, 0x0a, 0x0b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x68, 0x69, - 0x6e, 0x74, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x72, 0x6f, 0x75, - 0x74, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, - 0x74, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, - 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x10, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x61, 0x64, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x21, - 0x0a, 0x0c, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x11, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x12, 0x1d, 0x0a, 0x08, 0x61, 0x6d, 0x74, 0x5f, 0x70, 0x61, 0x69, 0x64, 0x18, 0x12, 0x20, - 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x61, 0x6d, 0x74, 0x50, 0x61, 0x69, 0x64, - 0x12, 0x20, 0x0a, 0x0c, 0x61, 0x6d, 0x74, 0x5f, 0x70, 0x61, 0x69, 0x64, 0x5f, 0x73, 0x61, 0x74, - 0x18, 0x13, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x61, 0x6d, 0x74, 0x50, 0x61, 0x69, 0x64, 0x53, - 0x61, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x6d, 0x74, 0x5f, 0x70, 0x61, 0x69, 0x64, 0x5f, 0x6d, - 0x73, 0x61, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x6d, 0x74, 0x50, 0x61, - 0x69, 0x64, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x31, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, - 0x15, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, - 0x76, 0x6f, 0x69, 0x63, 0x65, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x05, 0x68, 0x74, 0x6c, - 0x63, 0x73, 0x18, 0x16, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x48, 0x54, 0x4c, 0x43, 0x52, 0x05, 0x68, 0x74, - 0x6c, 0x63, 0x73, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, - 0x18, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, - 0x76, 0x6f, 0x69, 0x63, 0x65, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x1d, 0x0a, - 0x0a, 0x69, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x65, 0x6e, 0x64, 0x18, 0x19, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x09, 0x69, 0x73, 0x4b, 0x65, 0x79, 0x73, 0x65, 0x6e, 0x64, 0x12, 0x21, 0x0a, 0x0c, - 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x1a, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, - 0x15, 0x0a, 0x06, 0x69, 0x73, 0x5f, 0x61, 0x6d, 0x70, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x05, 0x69, 0x73, 0x41, 0x6d, 0x70, 0x12, 0x4f, 0x0a, 0x11, 0x61, 0x6d, 0x70, 0x5f, 0x69, 0x6e, - 0x76, 0x6f, 0x69, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x1c, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x23, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, - 0x65, 0x2e, 0x41, 0x6d, 0x70, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x61, 0x6d, 0x70, 0x49, 0x6e, 0x76, 0x6f, 0x69, - 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x62, 0x6c, - 0x69, 0x6e, 0x64, 0x65, 0x64, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x42, - 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x12, 0x48, 0x0a, 0x13, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x65, - 0x64, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x1e, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x69, 0x6e, - 0x64, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x62, - 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x1a, 0x4b, 0x0a, 0x0d, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5a, 0x0a, - 0x14, 0x41, 0x6d, 0x70, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, - 0x4d, 0x50, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x41, 0x0a, 0x0c, 0x49, 0x6e, 0x76, - 0x6f, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4f, 0x50, 0x45, - 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, 0x44, 0x10, 0x01, - 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0c, - 0x0a, 0x08, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x02, - 0x10, 0x03, 0x22, 0xef, 0x01, 0x0a, 0x11, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x61, - 0x74, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x5f, - 0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x68, 0x6f, 0x70, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x0e, 0x6d, 0x69, 0x6e, 0x4e, 0x75, 0x6d, 0x52, 0x65, 0x61, - 0x6c, 0x48, 0x6f, 0x70, 0x73, 0x88, 0x01, 0x01, 0x12, 0x1e, 0x0a, 0x08, 0x6e, 0x75, 0x6d, 0x5f, - 0x68, 0x6f, 0x70, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x01, 0x52, 0x07, 0x6e, 0x75, - 0x6d, 0x48, 0x6f, 0x70, 0x73, 0x88, 0x01, 0x01, 0x12, 0x27, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, - 0x6e, 0x75, 0x6d, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x48, - 0x02, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x4e, 0x75, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x73, 0x88, 0x01, - 0x01, 0x12, 0x2c, 0x0a, 0x12, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6f, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x10, 0x6e, - 0x6f, 0x64, 0x65, 0x4f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x42, - 0x14, 0x0a, 0x12, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x65, 0x61, 0x6c, - 0x5f, 0x68, 0x6f, 0x70, 0x73, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x68, 0x6f, - 0x70, 0x73, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x70, - 0x61, 0x74, 0x68, 0x73, 0x22, 0xac, 0x04, 0x0a, 0x0b, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, - 0x48, 0x54, 0x4c, 0x43, 0x12, 0x1b, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x49, - 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x68, 0x74, 0x6c, 0x63, 0x49, 0x6e, 0x64, 0x65, 0x78, - 0x12, 0x19, 0x0a, 0x08, 0x61, 0x6d, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x07, 0x61, 0x6d, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x61, - 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, - 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x54, 0x69, 0x6d, - 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x5f, 0x74, 0x69, 0x6d, - 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, - 0x54, 0x69, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x68, - 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x65, 0x78, 0x70, - 0x69, 0x72, 0x79, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x48, 0x54, 0x4c, 0x43, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x4c, 0x0a, 0x0e, 0x63, 0x75, 0x73, 0x74, - 0x6f, 0x6d, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x25, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, - 0x48, 0x54, 0x4c, 0x43, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, - 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x2b, 0x0a, 0x12, 0x6d, 0x70, 0x70, 0x5f, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6d, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x70, 0x70, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6d, 0x74, 0x4d, - 0x73, 0x61, 0x74, 0x12, 0x1c, 0x0a, 0x03, 0x61, 0x6d, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x4d, 0x50, 0x52, 0x03, 0x61, 0x6d, - 0x70, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x63, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, - 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x61, 0x74, - 0x61, 0x1a, 0x40, 0x0a, 0x12, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, - 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x22, 0x8c, 0x01, 0x0a, 0x03, 0x41, 0x4d, 0x50, 0x12, 0x1d, 0x0a, 0x0a, 0x72, - 0x6f, 0x6f, 0x74, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x53, 0x68, 0x61, 0x72, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, - 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x65, 0x74, 0x49, - 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x65, 0x69, 0x6d, 0x61, - 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x70, 0x72, 0x65, 0x69, 0x6d, 0x61, - 0x67, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x72, 0x5f, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x72, 0x48, 0x61, 0x73, 0x68, - 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x61, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x64, 0x64, - 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x61, 0x64, - 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, - 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x22, 0x46, 0x0a, 0x0b, 0x50, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x20, 0x0a, 0x0a, 0x72, 0x5f, 0x68, 0x61, - 0x73, 0x68, 0x5f, 0x73, 0x74, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, - 0x52, 0x08, 0x72, 0x48, 0x61, 0x73, 0x68, 0x53, 0x74, 0x72, 0x12, 0x15, 0x0a, 0x06, 0x72, 0x5f, - 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x72, 0x48, 0x61, 0x73, - 0x68, 0x22, 0xfc, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, - 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x28, - 0x0a, 0x10, 0x6e, 0x75, 0x6d, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, - 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x6e, 0x75, 0x6d, 0x4d, 0x61, 0x78, - 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x65, - 0x72, 0x73, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x76, 0x65, - 0x72, 0x73, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x53, - 0x74, 0x61, 0x72, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x6e, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x64, - 0x22, 0x9b, 0x01, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x08, 0x69, 0x6e, 0x76, 0x6f, - 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x08, 0x69, 0x6e, 0x76, 0x6f, - 0x69, 0x63, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, - 0x12, 0x2c, 0x0a, 0x12, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, - 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x66, 0x69, - 0x72, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x55, - 0x0a, 0x13, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x5f, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x61, 0x64, 0x64, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, - 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xcb, 0x06, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, - 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, - 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x48, 0x61, 0x73, 0x68, 0x12, 0x18, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x27, - 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x03, 0x66, 0x65, 0x65, 0x12, 0x29, 0x0a, - 0x10, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, - 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x53, 0x61, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x6d, - 0x73, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x4d, 0x73, 0x61, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x0b, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x66, 0x65, 0x65, 0x53, 0x61, 0x74, 0x12, 0x19, 0x0a, 0x08, - 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, - 0x66, 0x65, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6e, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x4e, - 0x73, 0x12, 0x28, 0x0a, 0x05, 0x68, 0x74, 0x6c, 0x63, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x54, 0x4c, 0x43, 0x41, 0x74, 0x74, - 0x65, 0x6d, 0x70, 0x74, 0x52, 0x05, 0x68, 0x74, 0x6c, 0x63, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x70, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x0f, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, - 0x12, 0x42, 0x0a, 0x0e, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x61, 0x73, - 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, - 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x0d, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, 0x65, - 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x62, 0x0a, 0x18, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x68, 0x6f, - 0x70, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, - 0x18, 0x11, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x46, 0x69, 0x72, 0x73, 0x74, 0x48, 0x6f, 0x70, 0x43, - 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x15, 0x66, 0x69, 0x72, 0x73, 0x74, 0x48, 0x6f, 0x70, 0x43, 0x75, 0x73, 0x74, 0x6f, - 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x1a, 0x48, 0x0a, 0x1a, 0x46, 0x69, 0x72, 0x73, - 0x74, 0x48, 0x6f, 0x70, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x22, 0x59, 0x0a, 0x0d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x0f, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, - 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x5f, 0x46, 0x4c, 0x49, 0x47, 0x48, - 0x54, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x55, 0x43, 0x43, 0x45, 0x45, 0x44, 0x45, 0x44, - 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0d, - 0x0a, 0x09, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x45, 0x44, 0x10, 0x04, 0x4a, 0x04, 0x08, - 0x04, 0x10, 0x05, 0x22, 0xd5, 0x02, 0x0a, 0x0b, 0x48, 0x54, 0x4c, 0x43, 0x41, 0x74, 0x74, 0x65, - 0x6d, 0x70, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x5f, 0x69, - 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, - 0x49, 0x64, 0x12, 0x35, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x54, 0x4c, 0x43, 0x41, - 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x2e, 0x48, 0x54, 0x4c, 0x43, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x22, 0x0a, 0x05, 0x72, 0x6f, 0x75, - 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x26, 0x0a, - 0x0f, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6e, 0x73, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x54, - 0x69, 0x6d, 0x65, 0x4e, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, - 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x4e, 0x73, 0x12, 0x28, 0x0a, - 0x07, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, 0x07, - 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x65, 0x69, 0x6d, - 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x70, 0x72, 0x65, 0x69, 0x6d, - 0x61, 0x67, 0x65, 0x22, 0x36, 0x0a, 0x0a, 0x48, 0x54, 0x4c, 0x43, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x5f, 0x46, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x10, 0x00, - 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x55, 0x43, 0x43, 0x45, 0x45, 0x44, 0x45, 0x44, 0x10, 0x01, 0x12, - 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x22, 0xb4, 0x02, 0x0a, 0x13, - 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x12, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x69, - 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x11, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6f, 0x66, 0x66, 0x73, - 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4f, - 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, - 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x65, - 0x72, 0x73, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x76, 0x65, - 0x72, 0x73, 0x65, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x12, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, - 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x6e, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x45, - 0x6e, 0x64, 0x22, 0xca, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x08, 0x70, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x08, 0x70, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x66, 0x69, 0x72, 0x73, 0x74, - 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x10, 0x66, 0x69, 0x72, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4f, - 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, - 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x70, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x74, - 0x6f, 0x74, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, - 0x65, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x70, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2a, 0x0a, 0x11, 0x66, 0x61, - 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x73, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x48, 0x74, 0x6c, - 0x63, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x9b, 0x01, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x70, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x12, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x2a, 0x0a, 0x11, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, - 0x68, 0x74, 0x6c, 0x63, 0x73, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0f, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x48, 0x74, 0x6c, 0x63, 0x73, 0x4f, 0x6e, 0x6c, - 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x6c, 0x6c, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x61, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x73, 0x22, 0x17, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x0a, - 0x19, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, - 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xbf, 0x01, 0x0a, 0x15, 0x41, - 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, - 0x52, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x39, - 0x0a, 0x19, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x5f, 0x73, 0x68, 0x69, 0x6d, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x16, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x53, 0x68, 0x69, 0x6d, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x31, 0x0a, 0x16, 0x69, 0x5f, 0x6b, - 0x6e, 0x6f, 0x77, 0x5f, 0x77, 0x68, 0x61, 0x74, 0x5f, 0x69, 0x5f, 0x61, 0x6d, 0x5f, 0x64, 0x6f, - 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x69, 0x4b, 0x6e, 0x6f, 0x77, - 0x57, 0x68, 0x61, 0x74, 0x49, 0x41, 0x6d, 0x44, 0x6f, 0x69, 0x6e, 0x67, 0x22, 0x18, 0x0a, 0x16, - 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x46, 0x0a, 0x11, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, - 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, - 0x68, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x12, - 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x53, 0x70, 0x65, 0x63, 0x22, 0x35, - 0x0a, 0x12, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x75, 0x62, 0x5f, 0x73, 0x79, 0x73, 0x74, - 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x75, 0x62, 0x53, 0x79, - 0x73, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x27, 0x0a, 0x0c, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x53, - 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x5f, 0x72, 0x65, 0x71, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x61, 0x79, 0x52, 0x65, 0x71, 0x22, 0xf0, - 0x04, 0x0a, 0x06, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, - 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x70, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x21, - 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x61, 0x74, 0x6f, 0x73, 0x68, 0x69, 0x73, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x53, 0x61, 0x74, 0x6f, 0x73, 0x68, 0x69, - 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x16, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x48, 0x61, 0x73, 0x68, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, - 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x61, 0x6c, - 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x74, - 0x76, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, - 0x63, 0x6c, 0x74, 0x76, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x12, 0x31, 0x0a, 0x0b, 0x72, 0x6f, - 0x75, 0x74, 0x65, 0x5f, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x10, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x69, 0x6e, - 0x74, 0x52, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x21, 0x0a, - 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, - 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x75, 0x6d, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x07, 0x6e, 0x75, 0x6d, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x37, 0x0a, 0x08, 0x66, - 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x2e, 0x46, 0x65, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x66, 0x65, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x0d, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x5f, - 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x52, 0x0c, 0x62, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x50, - 0x61, 0x74, 0x68, 0x73, 0x1a, 0x4b, 0x0a, 0x0d, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, - 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x22, 0x59, 0x0a, 0x07, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x73, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, - 0x64, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x22, 0x12, 0x0a, 0x10, - 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x22, 0x95, 0x02, 0x0a, 0x10, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x46, 0x65, 0x65, 0x52, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1b, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, - 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x62, 0x61, 0x73, 0x65, 0x5f, - 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, - 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x1e, 0x0a, 0x0b, 0x66, - 0x65, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x6d, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x09, 0x66, 0x65, 0x65, 0x50, 0x65, 0x72, 0x4d, 0x69, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x66, - 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x66, - 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x12, 0x31, 0x0a, 0x15, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, - 0x64, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x61, - 0x73, 0x65, 0x46, 0x65, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x2d, 0x0a, 0x13, 0x69, 0x6e, 0x62, - 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x6d, 0x69, 0x6c, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x46, - 0x65, 0x65, 0x50, 0x65, 0x72, 0x4d, 0x69, 0x6c, 0x22, 0xb5, 0x01, 0x0a, 0x11, 0x46, 0x65, 0x65, - 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, - 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x66, 0x65, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x0b, 0x63, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x46, 0x65, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x64, 0x61, - 0x79, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x09, 0x64, 0x61, 0x79, 0x46, 0x65, 0x65, 0x53, 0x75, 0x6d, 0x12, 0x20, 0x0a, 0x0c, 0x77, 0x65, - 0x65, 0x6b, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x0a, 0x77, 0x65, 0x65, 0x6b, 0x46, 0x65, 0x65, 0x53, 0x75, 0x6d, 0x12, 0x22, 0x0a, 0x0d, - 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x75, 0x6d, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x46, 0x65, 0x65, 0x53, 0x75, 0x6d, - 0x22, 0x52, 0x0a, 0x0a, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x65, 0x65, 0x12, 0x22, - 0x0a, 0x0d, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x4d, 0x73, - 0x61, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x70, - 0x70, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x66, 0x65, 0x65, 0x52, 0x61, 0x74, - 0x65, 0x50, 0x70, 0x6d, 0x22, 0xaa, 0x03, 0x0a, 0x13, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x06, - 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x06, - 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x48, - 0x00, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0d, - 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0b, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x4d, 0x73, 0x61, 0x74, - 0x12, 0x19, 0x0a, 0x08, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x01, 0x52, 0x07, 0x66, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x66, - 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x70, 0x6d, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x0a, 0x66, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x50, 0x70, 0x6d, 0x12, 0x26, 0x0a, - 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x63, 0x6b, - 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x74, 0x6c, - 0x63, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, - 0x78, 0x48, 0x74, 0x6c, 0x63, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, - 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x48, 0x74, 0x6c, 0x63, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x35, 0x0a, - 0x17, 0x6d, 0x69, 0x6e, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x5f, 0x73, - 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, - 0x6d, 0x69, 0x6e, 0x48, 0x74, 0x6c, 0x63, 0x4d, 0x73, 0x61, 0x74, 0x53, 0x70, 0x65, 0x63, 0x69, - 0x66, 0x69, 0x65, 0x64, 0x12, 0x32, 0x0a, 0x0b, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, - 0x66, 0x65, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x65, 0x65, 0x52, 0x0a, 0x69, 0x6e, - 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x65, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, - 0x65, 0x22, 0x8c, 0x01, 0x0a, 0x0c, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, - 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, - 0x2c, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x46, 0x61, - 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, - 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, - 0x22, 0x52, 0x0a, 0x14, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x0e, 0x66, 0x61, 0x69, 0x6c, - 0x65, 0x64, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x0d, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x73, 0x22, 0xc9, 0x01, 0x0a, 0x18, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, - 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, - 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x0b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x24, - 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4d, 0x61, 0x78, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x6c, 0x69, - 0x61, 0x73, 0x5f, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0f, 0x70, 0x65, 0x65, 0x72, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, - 0x22, 0x85, 0x03, 0x0a, 0x0f, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x20, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, - 0x64, 0x5f, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x08, - 0x63, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x49, 0x6e, 0x12, 0x22, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, - 0x5f, 0x69, 0x64, 0x5f, 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, - 0x01, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x4f, 0x75, 0x74, 0x12, 0x15, 0x0a, 0x06, - 0x61, 0x6d, 0x74, 0x5f, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x61, 0x6d, - 0x74, 0x49, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x6d, 0x74, 0x5f, 0x6f, 0x75, 0x74, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x74, 0x4f, 0x75, 0x74, 0x12, 0x10, 0x0a, 0x03, - 0x66, 0x65, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 0x12, 0x19, - 0x0a, 0x08, 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x07, 0x66, 0x65, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x1e, 0x0a, 0x0b, 0x61, 0x6d, 0x74, - 0x5f, 0x69, 0x6e, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, - 0x61, 0x6d, 0x74, 0x49, 0x6e, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x61, 0x6d, 0x74, - 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0a, 0x61, 0x6d, 0x74, 0x4f, 0x75, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x5f, 0x6e, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4e, 0x73, 0x12, 0x22, - 0x0a, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x5f, 0x69, 0x6e, 0x18, - 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x65, 0x65, 0x72, 0x41, 0x6c, 0x69, 0x61, 0x73, - 0x49, 0x6e, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, - 0x5f, 0x6f, 0x75, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x65, 0x65, 0x72, - 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4f, 0x75, 0x74, 0x22, 0x8c, 0x01, 0x0a, 0x19, 0x46, 0x6f, 0x72, - 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x11, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, - 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, - 0x64, 0x69, 0x6e, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x10, 0x66, 0x6f, 0x72, 0x77, 0x61, - 0x72, 0x64, 0x69, 0x6e, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6c, - 0x61, 0x73, 0x74, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x4f, 0x66, 0x66, 0x73, - 0x65, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x50, 0x0a, 0x1a, 0x45, 0x78, 0x70, 0x6f, 0x72, - 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x09, - 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x64, 0x0a, 0x0d, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x32, 0x0a, 0x0a, 0x63, 0x68, - 0x61, 0x6e, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x59, 0x0a, 0x0d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0f, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, + 0x4e, 0x10, 0x00, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x5f, 0x46, 0x4c, + 0x49, 0x47, 0x48, 0x54, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x55, 0x43, 0x43, 0x45, 0x45, + 0x44, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, + 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x45, 0x44, 0x10, 0x04, + 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0xd5, 0x02, 0x0a, 0x0b, 0x48, 0x54, 0x4c, 0x43, 0x41, + 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, + 0x74, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x61, 0x74, 0x74, 0x65, + 0x6d, 0x70, 0x74, 0x49, 0x64, 0x12, 0x35, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x54, + 0x4c, 0x43, 0x41, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x2e, 0x48, 0x54, 0x4c, 0x43, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x22, 0x0a, 0x05, + 0x72, 0x6f, 0x75, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x74, 0x65, + 0x12, 0x26, 0x0a, 0x0f, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x5f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x65, 0x6d, + 0x70, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x4e, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x72, 0x65, 0x73, 0x6f, + 0x6c, 0x76, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x4e, 0x73, + 0x12, 0x28, 0x0a, 0x07, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, + 0x65, 0x52, 0x07, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, + 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x70, 0x72, + 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x22, 0x36, 0x0a, 0x0a, 0x48, 0x54, 0x4c, 0x43, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x5f, 0x46, 0x4c, 0x49, 0x47, 0x48, + 0x54, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x55, 0x43, 0x43, 0x45, 0x45, 0x44, 0x45, 0x44, + 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x22, 0xb4, + 0x02, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x12, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, + 0x65, 0x5f, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x11, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x49, 0x6e, 0x63, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, + 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, + 0x6d, 0x61, 0x78, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72, + 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, + 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x6f, 0x74, 0x61, + 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x44, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x6e, 0x64, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, + 0x74, 0x65, 0x45, 0x6e, 0x64, 0x22, 0xca, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, + 0x0a, 0x08, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x52, 0x08, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x66, 0x69, + 0x72, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x66, 0x69, 0x72, 0x73, 0x74, 0x49, 0x6e, 0x64, + 0x65, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, + 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6e, 0x75, + 0x6d, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x22, 0x65, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2a, 0x0a, + 0x11, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x73, 0x5f, 0x6f, 0x6e, + 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, + 0x48, 0x74, 0x6c, 0x63, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x9b, 0x01, 0x0a, 0x18, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, + 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x2a, 0x0a, 0x11, 0x66, 0x61, 0x69, 0x6c, + 0x65, 0x64, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x73, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0f, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x48, 0x74, 0x6c, 0x63, 0x73, + 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x6c, 0x6c, 0x5f, 0x70, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x61, 0x6c, 0x6c, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x17, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x1b, 0x0a, 0x19, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xbf, 0x01, + 0x0a, 0x15, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, - 0x69, 0x6e, 0x74, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1f, - 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, - 0x73, 0x0a, 0x0f, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x12, 0x34, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x63, 0x68, - 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x75, 0x6c, 0x74, + 0x69, 0x6e, 0x74, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, + 0x74, 0x12, 0x39, 0x0a, 0x19, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x75, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x68, 0x69, 0x6d, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x46, 0x75, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x53, 0x68, 0x69, 0x6d, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x31, 0x0a, 0x16, + 0x69, 0x5f, 0x6b, 0x6e, 0x6f, 0x77, 0x5f, 0x77, 0x68, 0x61, 0x74, 0x5f, 0x69, 0x5f, 0x61, 0x6d, + 0x5f, 0x64, 0x6f, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x69, 0x4b, + 0x6e, 0x6f, 0x77, 0x57, 0x68, 0x61, 0x74, 0x49, 0x41, 0x6d, 0x44, 0x6f, 0x69, 0x6e, 0x67, 0x22, + 0x18, 0x0a, 0x16, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x46, 0x0a, 0x11, 0x44, 0x65, 0x62, + 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x73, 0x68, + 0x6f, 0x77, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x5f, 0x73, 0x70, 0x65, 0x63, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x53, 0x70, 0x65, + 0x63, 0x22, 0x35, 0x0a, 0x12, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x75, 0x62, 0x5f, 0x73, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x75, + 0x62, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x27, 0x0a, 0x0c, 0x50, 0x61, 0x79, 0x52, + 0x65, 0x71, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x5f, + 0x72, 0x65, 0x71, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x61, 0x79, 0x52, 0x65, + 0x71, 0x22, 0xf0, 0x04, 0x0a, 0x06, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, + 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, + 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, + 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x61, 0x74, 0x6f, 0x73, 0x68, 0x69, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x53, 0x61, 0x74, 0x6f, + 0x73, 0x68, 0x69, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x10, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x68, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x61, 0x6c, 0x6c, 0x62, + 0x61, 0x63, 0x6b, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, + 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1f, 0x0a, 0x0b, + 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0a, 0x63, 0x6c, 0x74, 0x76, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x12, 0x31, 0x0a, + 0x0b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, + 0x48, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x73, + 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, + 0x64, 0x64, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x75, 0x6d, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, + 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6e, 0x75, 0x6d, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x37, + 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x2e, + 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x66, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x0d, 0x62, 0x6c, 0x69, 0x6e, 0x64, + 0x65, 0x64, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x52, 0x0c, 0x62, 0x6c, 0x69, 0x6e, 0x64, + 0x65, 0x64, 0x50, 0x61, 0x74, 0x68, 0x73, 0x1a, 0x4b, 0x0a, 0x0d, 0x46, 0x65, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0x59, 0x0a, 0x07, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x73, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, + 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x22, + 0x12, 0x0a, 0x10, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x22, 0x95, 0x02, 0x0a, 0x10, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x46, + 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1b, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x06, 0x63, + 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x62, 0x61, + 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0b, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x1e, + 0x0a, 0x0b, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x6d, 0x69, 0x6c, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x09, 0x66, 0x65, 0x65, 0x50, 0x65, 0x72, 0x4d, 0x69, 0x6c, 0x12, 0x19, + 0x0a, 0x08, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, + 0x52, 0x07, 0x66, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x12, 0x31, 0x0a, 0x15, 0x69, 0x6e, 0x62, + 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, + 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, + 0x64, 0x42, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x2d, 0x0a, 0x13, + 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, + 0x6d, 0x69, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x69, 0x6e, 0x62, 0x6f, 0x75, + 0x6e, 0x64, 0x46, 0x65, 0x65, 0x50, 0x65, 0x72, 0x4d, 0x69, 0x6c, 0x22, 0xb5, 0x01, 0x0a, 0x11, + 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x3a, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x66, 0x65, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x46, 0x65, 0x65, 0x73, 0x12, 0x1e, 0x0a, + 0x0b, 0x64, 0x61, 0x79, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x09, 0x64, 0x61, 0x79, 0x46, 0x65, 0x65, 0x53, 0x75, 0x6d, 0x12, 0x20, 0x0a, + 0x0c, 0x77, 0x65, 0x65, 0x6b, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x75, 0x6d, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0a, 0x77, 0x65, 0x65, 0x6b, 0x46, 0x65, 0x65, 0x53, 0x75, 0x6d, 0x12, + 0x22, 0x0a, 0x0d, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x75, 0x6d, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x46, 0x65, 0x65, + 0x53, 0x75, 0x6d, 0x22, 0x52, 0x0a, 0x0a, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x65, + 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, + 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, + 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, + 0x65, 0x5f, 0x70, 0x70, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x66, 0x65, 0x65, + 0x52, 0x61, 0x74, 0x65, 0x50, 0x70, 0x6d, 0x22, 0xaa, 0x03, 0x0a, 0x13, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x18, 0x0a, 0x06, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, + 0x00, 0x52, 0x06, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x68, 0x61, + 0x6e, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, + 0x22, 0x0a, 0x0d, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x4d, + 0x73, 0x61, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x66, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x12, 0x20, + 0x0a, 0x0c, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x70, 0x6d, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x66, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x50, 0x70, 0x6d, + 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x64, 0x65, + 0x6c, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x4c, + 0x6f, 0x63, 0x6b, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, + 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0b, 0x6d, 0x61, 0x78, 0x48, 0x74, 0x6c, 0x63, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x22, 0x0a, 0x0d, + 0x6d, 0x69, 0x6e, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x48, 0x74, 0x6c, 0x63, 0x4d, 0x73, 0x61, 0x74, + 0x12, 0x35, 0x0a, 0x17, 0x6d, 0x69, 0x6e, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x73, 0x61, + 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x14, 0x6d, 0x69, 0x6e, 0x48, 0x74, 0x6c, 0x63, 0x4d, 0x73, 0x61, 0x74, 0x53, 0x70, + 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x32, 0x0a, 0x0b, 0x69, 0x6e, 0x62, 0x6f, 0x75, + 0x6e, 0x64, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x65, 0x65, 0x52, + 0x0a, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x65, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x73, + 0x63, 0x6f, 0x70, 0x65, 0x22, 0x8c, 0x01, 0x0a, 0x0c, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, + 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x45, 0x72, + 0x72, 0x6f, 0x72, 0x22, 0x52, 0x0a, 0x14, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x0e, 0x66, + 0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x61, 0x69, 0x6c, + 0x65, 0x64, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x0d, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x22, 0xc9, 0x01, 0x0a, 0x18, 0x46, 0x6f, 0x72, 0x77, + 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, + 0x69, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, + 0x0a, 0x0c, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4d, 0x61, + 0x78, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x70, 0x65, 0x65, 0x72, 0x5f, + 0x61, 0x6c, 0x69, 0x61, 0x73, 0x5f, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0f, 0x70, 0x65, 0x65, 0x72, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4c, 0x6f, 0x6f, + 0x6b, 0x75, 0x70, 0x22, 0x85, 0x03, 0x0a, 0x0f, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, + 0x6e, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x20, 0x0a, 0x0a, 0x63, 0x68, 0x61, + 0x6e, 0x5f, 0x69, 0x64, 0x5f, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, + 0x01, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x49, 0x6e, 0x12, 0x22, 0x0a, 0x0b, 0x63, + 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x5f, 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, + 0x42, 0x02, 0x30, 0x01, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x4f, 0x75, 0x74, 0x12, + 0x15, 0x0a, 0x06, 0x61, 0x6d, 0x74, 0x5f, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x05, 0x61, 0x6d, 0x74, 0x49, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x6d, 0x74, 0x5f, 0x6f, 0x75, + 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x74, 0x4f, 0x75, 0x74, 0x12, + 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, + 0x65, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x07, 0x66, 0x65, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x1e, 0x0a, 0x0b, + 0x61, 0x6d, 0x74, 0x5f, 0x69, 0x6e, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x09, 0x61, 0x6d, 0x74, 0x49, 0x6e, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x20, 0x0a, 0x0c, + 0x61, 0x6d, 0x74, 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0a, 0x61, 0x6d, 0x74, 0x4f, 0x75, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x21, + 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x5f, 0x6e, 0x73, 0x18, 0x0b, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4e, + 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x5f, + 0x69, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x65, 0x65, 0x72, 0x41, 0x6c, + 0x69, 0x61, 0x73, 0x49, 0x6e, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x6c, + 0x69, 0x61, 0x73, 0x5f, 0x6f, 0x75, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, + 0x65, 0x65, 0x72, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4f, 0x75, 0x74, 0x22, 0x8c, 0x01, 0x0a, 0x19, + 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x11, 0x66, 0x6f, 0x72, + 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, 0x72, + 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x10, 0x66, 0x6f, + 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2a, + 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x4f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x50, 0x0a, 0x1a, 0x45, 0x78, + 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, + 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, + 0x74, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x64, 0x0a, 0x0d, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x32, 0x0a, + 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, + 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x22, 0x73, 0x0a, 0x0f, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x42, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x34, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, + 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6d, + 0x75, 0x6c, 0x74, 0x69, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x43, 0x68, 0x61, + 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, 0x19, 0x0a, 0x17, 0x43, 0x68, 0x61, 0x6e, 0x42, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x22, 0x9f, 0x01, 0x0a, 0x12, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x45, 0x0a, 0x13, 0x73, 0x69, 0x6e, + 0x67, 0x6c, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x52, 0x11, 0x73, + 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, + 0x12, 0x42, 0x0a, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x52, 0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x22, 0x49, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x22, + 0x8e, 0x01, 0x0a, 0x18, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x42, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0c, + 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x68, 0x61, + 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x22, 0x19, 0x0a, 0x17, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, - 0x9f, 0x01, 0x0a, 0x12, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x45, 0x0a, 0x13, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, - 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x52, 0x11, 0x73, 0x69, 0x6e, 0x67, - 0x6c, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x42, 0x0a, - 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x52, 0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x22, 0x49, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, - 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x22, 0x8e, 0x01, 0x0a, - 0x18, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0c, 0x63, 0x68, 0x61, - 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x42, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x5f, 0x63, - 0x68, 0x61, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x48, 0x00, 0x52, 0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x42, 0x08, 0x0a, 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, 0x17, 0x0a, - 0x15, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x22, 0x1a, 0x0a, 0x18, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, - 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x44, 0x0a, 0x12, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x16, 0x0a, - 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xb0, 0x01, 0x0a, 0x13, 0x42, 0x61, 0x6b, 0x65, 0x4d, 0x61, - 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, - 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x61, 0x63, 0x61, 0x72, - 0x6f, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x70, - 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x72, 0x6f, - 0x6f, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x3c, 0x0a, 0x1a, 0x61, 0x6c, - 0x6c, 0x6f, 0x77, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, - 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x50, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x32, 0x0a, 0x14, 0x42, 0x61, 0x6b, 0x65, - 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x22, 0x18, 0x0a, 0x16, - 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, - 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0a, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, - 0x49, 0x64, 0x73, 0x22, 0x39, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, - 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, - 0x0a, 0x0b, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x22, 0x34, - 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, - 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x64, 0x22, 0x55, 0x0a, 0x16, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, - 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x3b, - 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x61, 0x63, 0x61, - 0x72, 0x6f, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, - 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x4c, - 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xe4, 0x01, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, - 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x64, 0x0a, 0x12, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x6d, - 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, - 0x74, 0x68, 0x6f, 0x64, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x50, 0x65, 0x72, 0x6d, - 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x63, 0x0a, 0x16, 0x4d, 0x65, 0x74, 0x68, 0x6f, - 0x64, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x33, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x61, 0x63, 0x61, 0x72, + 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x43, 0x68, 0x61, 0x6e, + 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x42, 0x08, 0x0a, 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x22, 0x17, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1a, 0x0a, 0x18, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x44, 0x0a, 0x12, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x50, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xb0, 0x01, 0x0a, 0x13, 0x42, 0x61, 0x6b, + 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x3b, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x61, + 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, + 0x0b, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x3c, 0x0a, + 0x1a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, + 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x18, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x32, 0x0a, 0x14, 0x42, + 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x22, + 0x18, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, + 0x44, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x17, 0x4c, 0x69, 0x73, + 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x6b, 0x65, 0x79, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0a, 0x72, 0x6f, 0x6f, 0x74, + 0x4b, 0x65, 0x79, 0x49, 0x64, 0x73, 0x22, 0x39, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1e, 0x0a, 0x0b, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x49, + 0x64, 0x22, 0x34, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, + 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x22, 0x55, 0x0a, 0x16, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xcc, 0x08, 0x0a, - 0x07, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, - 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x43, 0x6f, - 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x3b, 0x0a, 0x0e, 0x63, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x73, - 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x68, 0x74, 0x6c, 0x63, 0x4d, 0x73, - 0x61, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x6e, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x68, 0x61, 0x5f, - 0x32, 0x35, 0x36, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6f, 0x6e, 0x69, 0x6f, 0x6e, - 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x65, - 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x63, 0x6c, 0x74, - 0x76, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x30, 0x0a, - 0x14, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x66, 0x61, 0x69, - 0x6c, 0x75, 0x72, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, - 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x8b, 0x06, 0x0a, 0x0b, 0x46, 0x61, 0x69, 0x6c, - 0x75, 0x72, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x53, 0x45, 0x52, - 0x56, 0x45, 0x44, 0x10, 0x00, 0x12, 0x28, 0x0a, 0x24, 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, - 0x43, 0x54, 0x5f, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x50, 0x41, - 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, 0x53, 0x10, 0x01, 0x12, - 0x1c, 0x0a, 0x18, 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, 0x5f, 0x50, 0x41, 0x59, - 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x4d, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x02, 0x12, 0x1f, 0x0a, - 0x1b, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, - 0x5f, 0x43, 0x4c, 0x54, 0x56, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x59, 0x10, 0x03, 0x12, 0x1f, - 0x0a, 0x1b, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, - 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x4d, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x04, 0x12, - 0x19, 0x0a, 0x15, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x59, 0x5f, - 0x54, 0x4f, 0x4f, 0x5f, 0x53, 0x4f, 0x4f, 0x4e, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x49, 0x4e, - 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x52, 0x45, 0x41, 0x4c, 0x4d, 0x10, 0x06, 0x12, 0x13, 0x0a, - 0x0f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x59, 0x5f, 0x54, 0x4f, 0x4f, 0x5f, 0x53, 0x4f, 0x4f, 0x4e, - 0x10, 0x07, 0x12, 0x19, 0x0a, 0x15, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x4f, 0x4e, - 0x49, 0x4f, 0x4e, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x08, 0x12, 0x16, 0x0a, - 0x12, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x48, - 0x4d, 0x41, 0x43, 0x10, 0x09, 0x12, 0x15, 0x0a, 0x11, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, - 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x0a, 0x12, 0x18, 0x0a, 0x14, - 0x41, 0x4d, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x42, 0x45, 0x4c, 0x4f, 0x57, 0x5f, 0x4d, 0x49, 0x4e, - 0x49, 0x4d, 0x55, 0x4d, 0x10, 0x0b, 0x12, 0x14, 0x0a, 0x10, 0x46, 0x45, 0x45, 0x5f, 0x49, 0x4e, - 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x10, 0x0c, 0x12, 0x19, 0x0a, 0x15, - 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, 0x5f, 0x43, 0x4c, 0x54, 0x56, 0x5f, 0x45, - 0x58, 0x50, 0x49, 0x52, 0x59, 0x10, 0x0d, 0x12, 0x14, 0x0a, 0x10, 0x43, 0x48, 0x41, 0x4e, 0x4e, - 0x45, 0x4c, 0x5f, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x0e, 0x12, 0x1d, 0x0a, - 0x19, 0x54, 0x45, 0x4d, 0x50, 0x4f, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, - 0x45, 0x4c, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x0f, 0x12, 0x21, 0x0a, 0x1d, - 0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x5f, 0x4e, 0x4f, 0x44, 0x45, 0x5f, 0x46, 0x45, - 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x10, 0x12, - 0x24, 0x0a, 0x20, 0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x5f, 0x43, 0x48, 0x41, 0x4e, - 0x4e, 0x45, 0x4c, 0x5f, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, 0x4d, 0x49, 0x53, 0x53, - 0x49, 0x4e, 0x47, 0x10, 0x11, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x5f, 0x4e, 0x45, 0x58, 0x54, 0x5f, 0x50, 0x45, 0x45, 0x52, 0x10, 0x12, 0x12, 0x1a, 0x0a, 0x16, - 0x54, 0x45, 0x4d, 0x50, 0x4f, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x4e, 0x4f, 0x44, 0x45, 0x5f, 0x46, - 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x13, 0x12, 0x1a, 0x0a, 0x16, 0x50, 0x45, 0x52, 0x4d, - 0x41, 0x4e, 0x45, 0x4e, 0x54, 0x5f, 0x4e, 0x4f, 0x44, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, - 0x52, 0x45, 0x10, 0x14, 0x12, 0x1d, 0x0a, 0x19, 0x50, 0x45, 0x52, 0x4d, 0x41, 0x4e, 0x45, 0x4e, - 0x54, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, - 0x45, 0x10, 0x15, 0x12, 0x12, 0x0a, 0x0e, 0x45, 0x58, 0x50, 0x49, 0x52, 0x59, 0x5f, 0x54, 0x4f, - 0x4f, 0x5f, 0x46, 0x41, 0x52, 0x10, 0x16, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x50, 0x50, 0x5f, 0x54, - 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x17, 0x12, 0x19, 0x0a, 0x15, 0x49, 0x4e, 0x56, 0x41, - 0x4c, 0x49, 0x44, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x41, 0x59, 0x4c, 0x4f, 0x41, - 0x44, 0x10, 0x18, 0x12, 0x1a, 0x0a, 0x16, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x4f, - 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4c, 0x49, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x19, 0x12, - 0x15, 0x0a, 0x10, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x5f, 0x46, 0x41, 0x49, 0x4c, - 0x55, 0x52, 0x45, 0x10, 0xe5, 0x07, 0x12, 0x14, 0x0a, 0x0f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, - 0x4e, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0xe6, 0x07, 0x12, 0x17, 0x0a, 0x12, - 0x55, 0x4e, 0x52, 0x45, 0x41, 0x44, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, - 0x52, 0x45, 0x10, 0xe7, 0x07, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, 0xb3, 0x03, 0x0a, 0x0d, - 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, - 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x09, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x07, 0x63, 0x68, - 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, - 0x06, 0x63, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, - 0x26, 0x0a, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x64, 0x65, 0x6c, - 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x4c, 0x6f, - 0x63, 0x6b, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x2a, 0x0a, 0x11, 0x68, 0x74, 0x6c, 0x63, 0x5f, - 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0f, 0x68, 0x74, 0x6c, 0x63, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x4d, - 0x73, 0x61, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x12, 0x19, - 0x0a, 0x08, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x07, 0x66, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x68, 0x74, 0x6c, - 0x63, 0x5f, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0b, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x68, 0x74, 0x6c, 0x63, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, - 0x6d, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x6f, - 0x70, 0x61, 0x71, 0x75, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0f, 0x65, 0x78, 0x74, 0x72, 0x61, 0x4f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x44, 0x61, 0x74, - 0x61, 0x22, 0x5d, 0x0a, 0x0a, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x64, 0x12, - 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, - 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, - 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, - 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x03, 0x6f, 0x70, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x09, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x52, 0x03, 0x6f, 0x70, 0x73, - 0x22, 0x36, 0x0a, 0x02, 0x4f, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x18, - 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x13, 0x43, 0x68, 0x65, - 0x63, 0x6b, 0x4d, 0x61, 0x63, 0x50, 0x65, 0x72, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x0b, - 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, - 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x70, 0x65, - 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x75, 0x6c, - 0x6c, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, - 0x75, 0x6c, 0x6c, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x22, 0x2c, 0x0a, 0x14, 0x43, 0x68, 0x65, - 0x63, 0x6b, 0x4d, 0x61, 0x63, 0x50, 0x65, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x22, 0xf4, 0x02, 0x0a, 0x14, 0x52, 0x50, 0x43, 0x4d, - 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, - 0x21, 0x0a, 0x0c, 0x72, 0x61, 0x77, 0x5f, 0x6d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x72, 0x61, 0x77, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, - 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x17, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x63, 0x61, 0x76, - 0x65, 0x61, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x15, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x61, 0x76, 0x65, 0x61, - 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x0b, 0x73, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x11, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x41, 0x75, - 0x74, 0x68, 0x48, 0x00, 0x52, 0x0a, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x41, 0x75, 0x74, 0x68, - 0x12, 0x2d, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x2f, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x23, 0x0a, 0x0c, 0x72, 0x65, 0x67, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0b, 0x72, 0x65, 0x67, 0x43, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x6d, 0x73, 0x67, 0x5f, 0x69, 0x64, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x42, 0x10, 0x0a, 0x0e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x34, - 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x41, 0x75, 0x74, 0x68, 0x12, 0x26, 0x0a, 0x0f, - 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x75, 0x72, 0x69, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x46, 0x75, 0x6c, - 0x6c, 0x55, 0x72, 0x69, 0x22, 0xab, 0x01, 0x0a, 0x0a, 0x52, 0x50, 0x43, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x66, 0x75, - 0x6c, 0x6c, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x65, - 0x74, 0x68, 0x6f, 0x64, 0x46, 0x75, 0x6c, 0x6c, 0x55, 0x72, 0x69, 0x12, 0x1d, 0x0a, 0x0a, 0x73, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x72, 0x70, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x09, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x70, 0x63, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, - 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, - 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x69, 0x61, - 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x65, 0x72, - 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x45, 0x72, 0x72, - 0x6f, 0x72, 0x22, 0xc0, 0x01, 0x0a, 0x15, 0x52, 0x50, 0x43, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, - 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x0a, - 0x72, 0x65, 0x66, 0x5f, 0x6d, 0x73, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x08, 0x72, 0x65, 0x66, 0x4d, 0x73, 0x67, 0x49, 0x64, 0x12, 0x3b, 0x0a, 0x08, 0x72, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x08, 0x72, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x36, 0x0a, 0x08, 0x66, 0x65, 0x65, 0x64, 0x62, - 0x61, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x46, 0x65, 0x65, 0x64, 0x62, - 0x61, 0x63, 0x6b, 0x48, 0x00, 0x52, 0x08, 0x66, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x42, - 0x14, 0x0a, 0x12, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xa6, 0x01, 0x0a, 0x16, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, - 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x27, 0x0a, 0x0f, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6d, 0x69, 0x64, 0x64, 0x6c, - 0x65, 0x77, 0x61, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x1b, 0x63, 0x75, 0x73, - 0x74, 0x6f, 0x6d, 0x5f, 0x6d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x5f, 0x63, 0x61, 0x76, - 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, - 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x43, 0x61, - 0x76, 0x65, 0x61, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x72, 0x65, 0x61, 0x64, - 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x22, 0x8b, - 0x01, 0x0a, 0x11, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x46, 0x65, 0x65, 0x64, - 0x62, 0x61, 0x63, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, - 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x16, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, - 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, - 0x6e, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x2a, 0xcb, 0x02, 0x0a, - 0x10, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x00, 0x12, 0x1b, - 0x0a, 0x17, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x43, - 0x52, 0x49, 0x50, 0x54, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x01, 0x12, 0x26, 0x0a, 0x22, 0x53, - 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x57, 0x49, 0x54, 0x4e, 0x45, - 0x53, 0x53, 0x5f, 0x56, 0x30, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, - 0x48, 0x10, 0x02, 0x12, 0x26, 0x0a, 0x22, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x56, 0x30, 0x5f, 0x53, 0x43, - 0x52, 0x49, 0x50, 0x54, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x53, - 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, - 0x59, 0x10, 0x04, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x53, 0x49, 0x47, 0x10, 0x05, 0x12, 0x18, 0x0a, - 0x14, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4e, 0x55, 0x4c, - 0x4c, 0x44, 0x41, 0x54, 0x41, 0x10, 0x06, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x43, 0x52, 0x49, 0x50, - 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4e, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x4e, 0x44, - 0x41, 0x52, 0x44, 0x10, 0x07, 0x12, 0x1f, 0x0a, 0x1b, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x08, 0x12, 0x22, 0x0a, 0x1e, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x56, 0x31, - 0x5f, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x10, 0x09, 0x2a, 0x62, 0x0a, 0x15, 0x43, 0x6f, - 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, - 0x65, 0x67, 0x79, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, - 0x55, 0x53, 0x45, 0x5f, 0x47, 0x4c, 0x4f, 0x42, 0x41, 0x4c, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, - 0x47, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, - 0x4c, 0x41, 0x52, 0x47, 0x45, 0x53, 0x54, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x54, 0x52, - 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x52, 0x41, 0x4e, 0x44, 0x4f, 0x4d, 0x10, 0x02, 0x2a, 0xac, - 0x01, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, - 0x0a, 0x13, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, - 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x4e, 0x45, 0x53, 0x54, 0x45, - 0x44, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x01, 0x12, - 0x1e, 0x0a, 0x1a, 0x55, 0x4e, 0x55, 0x53, 0x45, 0x44, 0x5f, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, - 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x02, 0x12, - 0x1d, 0x0a, 0x19, 0x55, 0x4e, 0x55, 0x53, 0x45, 0x44, 0x5f, 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, - 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x03, 0x12, 0x12, - 0x0a, 0x0e, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, - 0x10, 0x04, 0x12, 0x19, 0x0a, 0x15, 0x55, 0x4e, 0x55, 0x53, 0x45, 0x44, 0x5f, 0x54, 0x41, 0x50, - 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x10, 0x05, 0x2a, 0xa8, 0x01, - 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x1b, 0x0a, 0x17, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, - 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, - 0x06, 0x4c, 0x45, 0x47, 0x41, 0x43, 0x59, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x54, 0x41, - 0x54, 0x49, 0x43, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x02, - 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x10, 0x03, 0x12, 0x19, 0x0a, - 0x15, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x45, 0x4e, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x44, - 0x5f, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x49, 0x4d, 0x50, - 0x4c, 0x45, 0x5f, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x10, 0x05, 0x12, 0x1a, 0x0a, 0x16, - 0x53, 0x49, 0x4d, 0x50, 0x4c, 0x45, 0x5f, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4f, - 0x56, 0x45, 0x52, 0x4c, 0x41, 0x59, 0x10, 0x06, 0x2a, 0x61, 0x0a, 0x09, 0x49, 0x6e, 0x69, 0x74, - 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x15, 0x0a, 0x11, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, - 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, - 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, - 0x01, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x52, - 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x49, 0x54, 0x49, - 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x42, 0x4f, 0x54, 0x48, 0x10, 0x03, 0x2a, 0x60, 0x0a, 0x0e, 0x52, - 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, - 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, - 0x0a, 0x0a, 0x06, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x49, - 0x4e, 0x43, 0x4f, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x10, 0x02, 0x12, 0x11, - 0x0a, 0x0d, 0x4f, 0x55, 0x54, 0x47, 0x4f, 0x49, 0x4e, 0x47, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x10, - 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x04, 0x2a, 0x71, 0x0a, - 0x11, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x63, 0x6f, - 0x6d, 0x65, 0x12, 0x13, 0x0a, 0x0f, 0x4f, 0x55, 0x54, 0x43, 0x4f, 0x4d, 0x45, 0x5f, 0x55, 0x4e, - 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x49, 0x4d, - 0x45, 0x44, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x45, - 0x44, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x41, 0x42, 0x41, 0x4e, 0x44, 0x4f, 0x4e, 0x45, 0x44, - 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x46, 0x49, 0x52, 0x53, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x47, - 0x45, 0x10, 0x04, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x05, - 0x2a, 0x39, 0x0a, 0x0e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, - 0x1a, 0x0a, 0x16, 0x42, 0x45, 0x54, 0x57, 0x45, 0x45, 0x4e, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x43, - 0x45, 0x4e, 0x54, 0x52, 0x41, 0x4c, 0x49, 0x54, 0x59, 0x10, 0x01, 0x2a, 0x3b, 0x0a, 0x10, 0x49, - 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x48, 0x54, 0x4c, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, - 0x0c, 0x0a, 0x08, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, - 0x07, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x41, - 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x2a, 0xf6, 0x01, 0x0a, 0x14, 0x50, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, - 0x6e, 0x12, 0x17, 0x0a, 0x13, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, - 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x41, - 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x54, 0x49, 0x4d, - 0x45, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, - 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x5f, 0x52, 0x4f, 0x55, 0x54, - 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, - 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x2c, 0x0a, - 0x28, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, - 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, - 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, 0x53, 0x10, 0x04, 0x12, 0x27, 0x0a, 0x23, 0x46, - 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, - 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x42, 0x41, 0x4c, 0x41, 0x4e, - 0x43, 0x45, 0x10, 0x05, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, - 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, - 0x06, 0x2a, 0x89, 0x05, 0x0a, 0x0a, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x69, 0x74, - 0x12, 0x18, 0x0a, 0x14, 0x44, 0x41, 0x54, 0x41, 0x4c, 0x4f, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, - 0x54, 0x45, 0x43, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x44, 0x41, - 0x54, 0x41, 0x4c, 0x4f, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x45, 0x43, 0x54, 0x5f, 0x4f, - 0x50, 0x54, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x5f, - 0x52, 0x4f, 0x55, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x03, 0x12, 0x1f, 0x0a, - 0x1b, 0x55, 0x50, 0x46, 0x52, 0x4f, 0x4e, 0x54, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, - 0x4e, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x04, 0x12, 0x1f, - 0x0a, 0x1b, 0x55, 0x50, 0x46, 0x52, 0x4f, 0x4e, 0x54, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, - 0x57, 0x4e, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x05, 0x12, - 0x16, 0x0a, 0x12, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, - 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x47, 0x4f, 0x53, 0x53, 0x49, - 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x07, 0x12, - 0x11, 0x0a, 0x0d, 0x54, 0x4c, 0x56, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x51, - 0x10, 0x08, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x4c, 0x56, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, - 0x4f, 0x50, 0x54, 0x10, 0x09, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x54, 0x5f, 0x47, 0x4f, 0x53, - 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, - 0x0a, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x54, 0x5f, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, - 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0b, 0x12, 0x19, 0x0a, - 0x15, 0x53, 0x54, 0x41, 0x54, 0x49, 0x43, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, - 0x45, 0x59, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x0c, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x54, 0x41, 0x54, - 0x49, 0x43, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x50, - 0x54, 0x10, 0x0d, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, - 0x44, 0x44, 0x52, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x0e, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x41, 0x59, - 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0f, 0x12, - 0x0b, 0x0a, 0x07, 0x4d, 0x50, 0x50, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x10, 0x12, 0x0b, 0x0a, 0x07, - 0x4d, 0x50, 0x50, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x11, 0x12, 0x16, 0x0a, 0x12, 0x57, 0x55, 0x4d, - 0x42, 0x4f, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, - 0x12, 0x12, 0x16, 0x0a, 0x12, 0x57, 0x55, 0x4d, 0x42, 0x4f, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, - 0x45, 0x4c, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x13, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x4e, 0x43, - 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x14, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x4e, - 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x15, 0x12, 0x1d, 0x0a, 0x19, 0x41, - 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x5f, 0x46, 0x45, 0x45, 0x5f, - 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x16, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4e, - 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x48, - 0x54, 0x4c, 0x43, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x17, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x4f, 0x55, - 0x54, 0x45, 0x5f, 0x42, 0x4c, 0x49, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x52, 0x45, 0x51, 0x55, - 0x49, 0x52, 0x45, 0x44, 0x10, 0x18, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, - 0x42, 0x4c, 0x49, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x41, - 0x4c, 0x10, 0x19, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x1e, - 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x1f, 0x2a, 0xac, 0x01, - 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, - 0x1a, 0x0a, 0x16, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, - 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x55, - 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x50, 0x45, - 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x55, 0x50, 0x44, 0x41, 0x54, - 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, - 0x55, 0x4e, 0x44, 0x10, 0x02, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, - 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, - 0x5f, 0x45, 0x52, 0x52, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, - 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, - 0x5f, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x45, 0x54, 0x45, 0x52, 0x10, 0x04, 0x32, 0xb9, 0x27, 0x0a, - 0x09, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x4a, 0x0a, 0x0d, 0x57, 0x61, - 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, - 0x6c, 0x73, 0x12, 0x44, 0x0a, 0x0b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, - 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, - 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, + 0x74, 0x12, 0x3b, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4d, + 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x18, + 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xe4, 0x01, 0x0a, 0x17, 0x4c, 0x69, 0x73, + 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x12, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x70, + 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x35, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x50, + 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x63, 0x0a, 0x16, 0x4d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x33, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x61, + 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0x8d, 0x09, 0x0a, 0x07, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x63, + 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, + 0x65, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x3b, 0x0a, 0x0e, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x74, 0x6c, 0x63, + 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x68, 0x74, 0x6c, + 0x63, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x6e, 0x69, 0x6f, 0x6e, 0x5f, 0x73, + 0x68, 0x61, 0x5f, 0x32, 0x35, 0x36, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6f, 0x6e, + 0x69, 0x6f, 0x6e, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x74, + 0x76, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, + 0x63, 0x6c, 0x74, 0x76, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, + 0x61, 0x67, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, + 0x12, 0x30, 0x0a, 0x14, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, + 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x64, + 0x65, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x3f, 0x0a, 0x10, 0x63, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x32, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x32, 0x52, 0x0e, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x32, 0x22, 0x8b, 0x06, 0x0a, 0x0b, + 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x52, + 0x45, 0x53, 0x45, 0x52, 0x56, 0x45, 0x44, 0x10, 0x00, 0x12, 0x28, 0x0a, 0x24, 0x49, 0x4e, 0x43, + 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, 0x5f, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, + 0x4e, 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, + 0x53, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, + 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x4d, 0x4f, 0x55, 0x4e, 0x54, 0x10, + 0x02, 0x12, 0x1f, 0x0a, 0x1b, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x52, + 0x52, 0x45, 0x43, 0x54, 0x5f, 0x43, 0x4c, 0x54, 0x56, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x59, + 0x10, 0x03, 0x12, 0x1f, 0x0a, 0x1b, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x5f, 0x49, 0x4e, 0x43, 0x4f, + 0x52, 0x52, 0x45, 0x43, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x4d, 0x4f, 0x55, 0x4e, + 0x54, 0x10, 0x04, 0x12, 0x19, 0x0a, 0x15, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x5f, 0x45, 0x58, 0x50, + 0x49, 0x52, 0x59, 0x5f, 0x54, 0x4f, 0x4f, 0x5f, 0x53, 0x4f, 0x4f, 0x4e, 0x10, 0x05, 0x12, 0x11, + 0x0a, 0x0d, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x52, 0x45, 0x41, 0x4c, 0x4d, 0x10, + 0x06, 0x12, 0x13, 0x0a, 0x0f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x59, 0x5f, 0x54, 0x4f, 0x4f, 0x5f, + 0x53, 0x4f, 0x4f, 0x4e, 0x10, 0x07, 0x12, 0x19, 0x0a, 0x15, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, + 0x44, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x10, + 0x08, 0x12, 0x16, 0x0a, 0x12, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x4f, 0x4e, 0x49, + 0x4f, 0x4e, 0x5f, 0x48, 0x4d, 0x41, 0x43, 0x10, 0x09, 0x12, 0x15, 0x0a, 0x11, 0x49, 0x4e, 0x56, + 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x0a, + 0x12, 0x18, 0x0a, 0x14, 0x41, 0x4d, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x42, 0x45, 0x4c, 0x4f, 0x57, + 0x5f, 0x4d, 0x49, 0x4e, 0x49, 0x4d, 0x55, 0x4d, 0x10, 0x0b, 0x12, 0x14, 0x0a, 0x10, 0x46, 0x45, + 0x45, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x10, 0x0c, + 0x12, 0x19, 0x0a, 0x15, 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, 0x5f, 0x43, 0x4c, + 0x54, 0x56, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x59, 0x10, 0x0d, 0x12, 0x14, 0x0a, 0x10, 0x43, + 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, + 0x0e, 0x12, 0x1d, 0x0a, 0x19, 0x54, 0x45, 0x4d, 0x50, 0x4f, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x43, + 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x0f, + 0x12, 0x21, 0x0a, 0x1d, 0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x5f, 0x4e, 0x4f, 0x44, + 0x45, 0x5f, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, + 0x47, 0x10, 0x10, 0x12, 0x24, 0x0a, 0x20, 0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x5f, + 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, + 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x11, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x4e, 0x4b, + 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x4e, 0x45, 0x58, 0x54, 0x5f, 0x50, 0x45, 0x45, 0x52, 0x10, 0x12, + 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x45, 0x4d, 0x50, 0x4f, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x4e, 0x4f, + 0x44, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x13, 0x12, 0x1a, 0x0a, 0x16, + 0x50, 0x45, 0x52, 0x4d, 0x41, 0x4e, 0x45, 0x4e, 0x54, 0x5f, 0x4e, 0x4f, 0x44, 0x45, 0x5f, 0x46, + 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x14, 0x12, 0x1d, 0x0a, 0x19, 0x50, 0x45, 0x52, 0x4d, + 0x41, 0x4e, 0x45, 0x4e, 0x54, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x46, 0x41, + 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x15, 0x12, 0x12, 0x0a, 0x0e, 0x45, 0x58, 0x50, 0x49, 0x52, + 0x59, 0x5f, 0x54, 0x4f, 0x4f, 0x5f, 0x46, 0x41, 0x52, 0x10, 0x16, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, + 0x50, 0x50, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x17, 0x12, 0x19, 0x0a, 0x15, + 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x41, + 0x59, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x18, 0x12, 0x1a, 0x0a, 0x16, 0x49, 0x4e, 0x56, 0x41, 0x4c, + 0x49, 0x44, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4c, 0x49, 0x4e, 0x44, 0x49, 0x4e, + 0x47, 0x10, 0x19, 0x12, 0x15, 0x0a, 0x10, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x5f, + 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0xe5, 0x07, 0x12, 0x14, 0x0a, 0x0f, 0x55, 0x4e, + 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0xe6, 0x07, + 0x12, 0x17, 0x0a, 0x12, 0x55, 0x4e, 0x52, 0x45, 0x41, 0x44, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x46, + 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0xe7, 0x07, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, + 0xb3, 0x03, 0x0a, 0x0d, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, + 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1b, + 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, + 0x02, 0x30, 0x01, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x23, + 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x46, 0x6c, + 0x61, 0x67, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x74, 0x69, + 0x6d, 0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x2a, 0x0a, 0x11, 0x68, + 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x6d, 0x73, 0x61, 0x74, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x68, 0x74, 0x6c, 0x63, 0x4d, 0x69, 0x6e, 0x69, + 0x6d, 0x75, 0x6d, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x61, 0x73, 0x65, 0x5f, + 0x66, 0x65, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x46, + 0x65, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x66, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x12, 0x2a, 0x0a, + 0x11, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x6d, 0x73, + 0x61, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x68, 0x74, 0x6c, 0x63, 0x4d, 0x61, + 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x78, 0x74, + 0x72, 0x61, 0x5f, 0x6f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0c, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x65, 0x78, 0x74, 0x72, 0x61, 0x4f, 0x70, 0x61, 0x71, 0x75, + 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0xb4, 0x03, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x32, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, + 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, + 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, + 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x64, + 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x1c, 0x0a, 0x09, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x69, + 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x44, 0x65, 0x6c, + 0x74, 0x61, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x12, 0x19, 0x0a, + 0x08, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x07, 0x66, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x68, 0x74, 0x6c, 0x63, + 0x5f, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0f, 0x68, 0x74, 0x6c, 0x63, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, + 0x4d, 0x73, 0x61, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x61, 0x78, + 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0f, 0x68, 0x74, 0x6c, 0x63, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x4d, 0x73, 0x61, 0x74, + 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x6f, 0x70, 0x61, 0x71, 0x75, 0x65, + 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x65, 0x78, 0x74, + 0x72, 0x61, 0x4f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0x5d, 0x0a, 0x0a, + 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, + 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, + 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x1b, + 0x0a, 0x03, 0x6f, 0x70, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x52, 0x03, 0x6f, 0x70, 0x73, 0x22, 0x36, 0x0a, 0x02, 0x4f, + 0x70, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x13, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4d, 0x61, 0x63, + 0x50, 0x65, 0x72, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6d, + 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, + 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x50, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x75, 0x6c, 0x6c, 0x4d, 0x65, 0x74, 0x68, + 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x75, 0x6c, 0x6c, 0x4d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x22, 0x2c, 0x0a, 0x14, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4d, 0x61, 0x63, + 0x50, 0x65, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x22, 0xf4, 0x02, 0x0a, 0x14, 0x52, 0x50, 0x43, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, + 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x61, + 0x77, 0x5f, 0x6d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0b, 0x72, 0x61, 0x77, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x12, 0x36, 0x0a, + 0x17, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x63, 0x61, 0x76, 0x65, 0x61, 0x74, 0x5f, 0x63, + 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, + 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x61, 0x76, 0x65, 0x61, 0x74, 0x43, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x0b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, + 0x61, 0x75, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x41, 0x75, 0x74, 0x68, 0x48, 0x00, 0x52, + 0x0a, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x41, 0x75, 0x74, 0x68, 0x12, 0x2d, 0x0a, 0x07, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x08, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x72, + 0x65, 0x67, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x08, 0x48, 0x00, 0x52, 0x0b, 0x72, 0x65, 0x67, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, + 0x12, 0x15, 0x0a, 0x06, 0x6d, 0x73, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x42, 0x10, 0x0a, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x63, 0x65, 0x70, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x34, 0x0a, 0x0a, 0x53, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x41, 0x75, 0x74, 0x68, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x5f, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x46, 0x75, 0x6c, 0x6c, 0x55, 0x72, 0x69, 0x22, + 0xab, 0x01, 0x0a, 0x0a, 0x52, 0x50, 0x43, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x26, + 0x0a, 0x0f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x75, 0x72, + 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x46, + 0x75, 0x6c, 0x6c, 0x55, 0x72, 0x69, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x5f, 0x72, 0x70, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x52, 0x70, 0x63, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, + 0x65, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xc0, 0x01, + 0x0a, 0x15, 0x52, 0x50, 0x43, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x5f, 0x6d, + 0x73, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65, 0x66, + 0x4d, 0x73, 0x67, 0x49, 0x64, 0x12, 0x3b, 0x0a, 0x08, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x12, 0x36, 0x0a, 0x08, 0x66, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x48, 0x00, + 0x52, 0x08, 0x66, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x42, 0x14, 0x0a, 0x12, 0x6d, 0x69, + 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x22, 0xa6, 0x01, 0x0a, 0x16, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x6d, + 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x1b, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x6d, + 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x5f, 0x63, 0x61, 0x76, 0x65, 0x61, 0x74, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, 0x63, 0x75, 0x73, 0x74, 0x6f, + 0x6d, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x43, 0x61, 0x76, 0x65, 0x61, 0x74, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, + 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x61, + 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x22, 0x8b, 0x01, 0x0a, 0x11, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x12, + 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, + 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x35, 0x0a, 0x16, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, + 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x15, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x2a, 0xcb, 0x02, 0x0a, 0x10, 0x4f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4b, + 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x43, 0x52, + 0x49, 0x50, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, + 0x48, 0x41, 0x53, 0x48, 0x10, 0x01, 0x12, 0x26, 0x0a, 0x22, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x56, 0x30, + 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x02, 0x12, 0x26, + 0x0a, 0x22, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x57, 0x49, + 0x54, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x56, 0x30, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, + 0x48, 0x41, 0x53, 0x48, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x10, 0x04, 0x12, 0x18, + 0x0a, 0x14, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4d, 0x55, + 0x4c, 0x54, 0x49, 0x53, 0x49, 0x47, 0x10, 0x05, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x43, 0x52, 0x49, + 0x50, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4e, 0x55, 0x4c, 0x4c, 0x44, 0x41, 0x54, 0x41, + 0x10, 0x06, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x54, 0x59, 0x50, + 0x45, 0x5f, 0x4e, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x4e, 0x44, 0x41, 0x52, 0x44, 0x10, 0x07, + 0x12, 0x1f, 0x0a, 0x1b, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, + 0x08, 0x12, 0x22, 0x0a, 0x1e, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x56, 0x31, 0x5f, 0x54, 0x41, 0x50, 0x52, + 0x4f, 0x4f, 0x54, 0x10, 0x09, 0x2a, 0x62, 0x0a, 0x15, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x1e, + 0x0a, 0x1a, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x55, 0x53, 0x45, 0x5f, 0x47, + 0x4c, 0x4f, 0x42, 0x41, 0x4c, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00, 0x12, 0x14, + 0x0a, 0x10, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x4c, 0x41, 0x52, 0x47, 0x45, + 0x53, 0x54, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, + 0x5f, 0x52, 0x41, 0x4e, 0x44, 0x4f, 0x4d, 0x10, 0x02, 0x2a, 0xac, 0x01, 0x0a, 0x0b, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x57, 0x49, 0x54, + 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, + 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, 0x5f, 0x50, 0x55, 0x42, + 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x01, 0x12, 0x1e, 0x0a, 0x1a, 0x55, 0x4e, + 0x55, 0x53, 0x45, 0x44, 0x5f, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x50, 0x55, 0x42, + 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x02, 0x12, 0x1d, 0x0a, 0x19, 0x55, 0x4e, + 0x55, 0x53, 0x45, 0x44, 0x5f, 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, 0x5f, 0x50, 0x55, 0x42, 0x4b, + 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x41, 0x50, + 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x10, 0x04, 0x12, 0x19, 0x0a, + 0x15, 0x55, 0x4e, 0x55, 0x53, 0x45, 0x44, 0x5f, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, + 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x10, 0x05, 0x2a, 0xa8, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x55, + 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, + 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x45, 0x47, 0x41, + 0x43, 0x59, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x54, 0x41, 0x54, 0x49, 0x43, 0x5f, 0x52, + 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x41, + 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x43, 0x52, 0x49, + 0x50, 0x54, 0x5f, 0x45, 0x4e, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x44, 0x5f, 0x4c, 0x45, 0x41, 0x53, + 0x45, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x49, 0x4d, 0x50, 0x4c, 0x45, 0x5f, 0x54, 0x41, + 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x10, 0x05, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x49, 0x4d, 0x50, 0x4c, + 0x45, 0x5f, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4f, 0x56, 0x45, 0x52, 0x4c, 0x41, + 0x59, 0x10, 0x06, 0x2a, 0x61, 0x0a, 0x09, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, + 0x12, 0x15, 0x0a, 0x11, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x55, 0x4e, + 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x49, 0x54, 0x49, + 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, + 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, + 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, + 0x42, 0x4f, 0x54, 0x48, 0x10, 0x03, 0x2a, 0x60, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4e, + 0x43, 0x48, 0x4f, 0x52, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x49, + 0x4e, 0x47, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4f, 0x55, 0x54, + 0x47, 0x4f, 0x49, 0x4e, 0x47, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, + 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x04, 0x2a, 0x71, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x6f, + 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x63, 0x6f, 0x6d, 0x65, 0x12, 0x13, 0x0a, + 0x0f, 0x4f, 0x55, 0x54, 0x43, 0x4f, 0x4d, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, + 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x45, 0x44, 0x10, 0x01, 0x12, + 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0d, + 0x0a, 0x09, 0x41, 0x42, 0x41, 0x4e, 0x44, 0x4f, 0x4e, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0f, 0x0a, + 0x0b, 0x46, 0x49, 0x52, 0x53, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x10, 0x04, 0x12, 0x0b, + 0x0a, 0x07, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x05, 0x2a, 0x39, 0x0a, 0x0e, 0x4e, + 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, + 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x42, 0x45, + 0x54, 0x57, 0x45, 0x45, 0x4e, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x52, 0x41, + 0x4c, 0x49, 0x54, 0x59, 0x10, 0x01, 0x2a, 0x3b, 0x0a, 0x10, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, + 0x65, 0x48, 0x54, 0x4c, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x43, + 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x54, 0x54, + 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, + 0x44, 0x10, 0x02, 0x2a, 0xf6, 0x01, 0x0a, 0x14, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x46, + 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x13, + 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, + 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, + 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, + 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, + 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x10, 0x02, 0x12, 0x18, + 0x0a, 0x14, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, + 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x2c, 0x0a, 0x28, 0x46, 0x41, 0x49, 0x4c, + 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x52, + 0x52, 0x45, 0x43, 0x54, 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x44, 0x45, 0x54, + 0x41, 0x49, 0x4c, 0x53, 0x10, 0x04, 0x12, 0x27, 0x0a, 0x23, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, + 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, + 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x05, 0x12, + 0x1b, 0x0a, 0x17, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, + 0x4e, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x06, 0x2a, 0x89, 0x05, 0x0a, + 0x0a, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x69, 0x74, 0x12, 0x18, 0x0a, 0x14, 0x44, + 0x41, 0x54, 0x41, 0x4c, 0x4f, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x45, 0x43, 0x54, 0x5f, + 0x52, 0x45, 0x51, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x44, 0x41, 0x54, 0x41, 0x4c, 0x4f, 0x53, + 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x45, 0x43, 0x54, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x01, 0x12, + 0x17, 0x0a, 0x13, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x5f, 0x52, 0x4f, 0x55, 0x49, 0x4e, + 0x47, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x03, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x46, 0x52, + 0x4f, 0x4e, 0x54, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x5f, 0x53, 0x43, 0x52, + 0x49, 0x50, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x04, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x46, + 0x52, 0x4f, 0x4e, 0x54, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x5f, 0x53, 0x43, + 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x47, 0x4f, + 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x52, 0x45, 0x51, + 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, + 0x52, 0x49, 0x45, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x07, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x4c, + 0x56, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x08, 0x12, 0x11, 0x0a, + 0x0d, 0x54, 0x4c, 0x56, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x09, + 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x54, 0x5f, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, + 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x0a, 0x12, 0x1a, 0x0a, 0x16, + 0x45, 0x58, 0x54, 0x5f, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, + 0x45, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0b, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x54, 0x41, 0x54, + 0x49, 0x43, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x52, 0x45, + 0x51, 0x10, 0x0c, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x54, 0x41, 0x54, 0x49, 0x43, 0x5f, 0x52, 0x45, + 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0d, 0x12, 0x14, + 0x0a, 0x10, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x52, + 0x45, 0x51, 0x10, 0x0e, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, + 0x41, 0x44, 0x44, 0x52, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0f, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x50, + 0x50, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x10, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x50, 0x50, 0x5f, 0x4f, + 0x50, 0x54, 0x10, 0x11, 0x12, 0x16, 0x0a, 0x12, 0x57, 0x55, 0x4d, 0x42, 0x4f, 0x5f, 0x43, 0x48, + 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x12, 0x12, 0x16, 0x0a, 0x12, + 0x57, 0x55, 0x4d, 0x42, 0x4f, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x53, 0x5f, 0x4f, + 0x50, 0x54, 0x10, 0x13, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, + 0x52, 0x45, 0x51, 0x10, 0x14, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, + 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x15, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, + 0x53, 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, + 0x52, 0x45, 0x51, 0x10, 0x16, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, + 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4f, + 0x50, 0x54, 0x10, 0x17, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x42, 0x4c, + 0x49, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x10, + 0x18, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x42, 0x4c, 0x49, 0x4e, 0x44, + 0x49, 0x4e, 0x47, 0x5f, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x41, 0x4c, 0x10, 0x19, 0x12, 0x0b, + 0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x1e, 0x12, 0x0b, 0x0a, 0x07, 0x41, + 0x4d, 0x50, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x1f, 0x2a, 0xac, 0x01, 0x0a, 0x0d, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x55, 0x50, + 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x55, 0x4e, 0x4b, + 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, + 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, + 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, + 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x02, + 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, + 0x52, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x5f, 0x45, 0x52, 0x52, 0x10, + 0x03, 0x12, 0x24, 0x0a, 0x20, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, + 0x55, 0x52, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x50, 0x41, 0x52, 0x41, + 0x4d, 0x45, 0x54, 0x45, 0x52, 0x10, 0x04, 0x32, 0xb9, 0x27, 0x0a, 0x09, 0x4c, 0x69, 0x67, 0x68, + 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x4a, 0x0a, 0x0d, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, + 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x57, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x4d, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, + 0x6e, 0x63, 0x65, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x4b, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x44, 0x0a, + 0x0b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, - 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, - 0x6e, 0x64, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x69, 0x6e, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, - 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, - 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, - 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x01, 0x12, 0x3b, 0x0a, 0x08, - 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x6e, 0x79, 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x6e, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0a, 0x4e, 0x65, 0x77, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, - 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, - 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, - 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x12, 0x19, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, - 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69, 0x73, - 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, - 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, - 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x13, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, - 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x10, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x38, 0x0a, 0x07, - 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x44, 0x65, 0x62, - 0x75, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, - 0x65, 0x74, 0x44, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, - 0x62, 0x75, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x50, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, - 0x66, 0x6f, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, - 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, - 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x69, 0x6e, 0x73, + 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x69, + 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, + 0x6e, 0x74, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, + 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x15, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x01, 0x12, 0x3b, 0x0a, 0x08, 0x53, 0x65, 0x6e, 0x64, 0x4d, + 0x61, 0x6e, 0x79, 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, + 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0a, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, + 0x0d, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1b, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x4d, 0x0a, 0x0e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, + 0x72, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, + 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x17, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, + 0x0a, 0x13, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x50, 0x65, 0x65, 0x72, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, + 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x1a, 0x10, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x38, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x47, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x44, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x62, + 0x75, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x47, 0x65, + 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, + 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, + 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, + 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1a, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, + 0x4d, 0x0a, 0x0e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x73, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x16, - 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x0e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, - 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, - 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0f, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, - 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x43, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, - 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x53, 0x0a, 0x10, 0x42, - 0x61, 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, - 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x4c, 0x0a, 0x10, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x53, 0x74, 0x65, 0x70, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, - 0x67, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x65, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x50, - 0x0a, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x6f, - 0x72, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, - 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, - 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x28, 0x01, 0x30, 0x01, - 0x12, 0x46, 0x0a, 0x0c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x0e, 0x41, 0x62, 0x61, 0x6e, - 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x50, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, + 0x0a, 0x0f, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x79, 0x6e, + 0x63, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, + 0x74, 0x12, 0x43, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x53, 0x0a, 0x10, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, + 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x10, 0x46, + 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x65, 0x70, 0x12, + 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x67, 0x1a, 0x1b, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x53, 0x74, 0x65, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x50, 0x0a, 0x0f, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1c, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, + 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x28, 0x01, 0x30, 0x01, 0x12, 0x46, 0x0a, 0x0c, 0x43, + 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x0e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x62, + 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x62, 0x61, 0x6e, + 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, + 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x28, + 0x01, 0x30, 0x01, 0x12, 0x3a, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x03, 0x88, 0x02, 0x01, 0x28, 0x01, 0x30, 0x01, 0x12, 0x3a, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, - 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x12, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, - 0x75, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, - 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x28, 0x01, 0x30, 0x01, 0x12, 0x41, 0x0a, 0x0f, - 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x12, - 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, - 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x37, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x0e, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x1a, 0x19, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, - 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x33, 0x0a, 0x0d, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, - 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x48, 0x61, 0x73, 0x68, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, - 0x6f, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, - 0x76, 0x6f, 0x69, 0x63, 0x65, 0x30, 0x01, 0x12, 0x32, 0x0a, 0x0c, 0x44, 0x65, 0x63, 0x6f, 0x64, - 0x65, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x1a, 0x0d, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x47, 0x0a, 0x0c, 0x4c, - 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x56, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, + 0x46, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x19, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, + 0x88, 0x02, 0x01, 0x28, 0x01, 0x30, 0x01, 0x12, 0x41, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x54, + 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, + 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0a, 0x41, 0x64, + 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, + 0x63, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, + 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x0d, 0x4c, 0x6f, + 0x6f, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x12, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x1a, + 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, + 0x41, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x49, 0x6e, 0x76, 0x6f, + 0x69, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, + 0x6f, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, + 0x30, 0x01, 0x12, 0x32, 0x0a, 0x0c, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x50, 0x61, 0x79, 0x52, + 0x65, 0x71, 0x12, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x52, 0x65, + 0x71, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x1a, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x47, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x4a, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0d, 0x44, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x47, 0x0a, 0x0e, 0x47, 0x65, - 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x19, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x6e, - 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x64, 0x67, 0x65, 0x12, 0x36, - 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, - 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x44, 0x0a, 0x0b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, - 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, - 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0e, - 0x47, 0x65, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x35, 0x0a, - 0x0a, 0x53, 0x74, 0x6f, 0x70, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x12, 0x12, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x20, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x54, 0x6f, 0x70, 0x6f, 0x6c, - 0x6f, 0x67, 0x79, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, - 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x54, 0x6f, 0x70, - 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x41, 0x0a, - 0x0a, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x18, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, - 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x3e, 0x0a, 0x09, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, - 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x4e, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x56, 0x0a, 0x11, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, - 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, - 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, + 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, + 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0d, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x47, + 0x72, 0x61, 0x70, 0x68, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x47, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, + 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x64, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x47, 0x65, 0x74, + 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x44, 0x0a, 0x0b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, + 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, + 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x35, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x70, + 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x57, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x53, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x41, 0x0a, 0x0a, 0x44, 0x65, 0x62, 0x75, + 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, + 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, + 0x76, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x46, + 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x13, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x13, 0x45, 0x78, 0x70, 0x6f, - 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, - 0x21, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x54, 0x0a, 0x17, 0x45, 0x78, 0x70, 0x6f, - 0x72, 0x74, 0x41, 0x6c, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x73, 0x12, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x4e, - 0x0a, 0x10, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x1a, 0x1f, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, - 0x0a, 0x15, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x30, 0x01, - 0x12, 0x47, 0x0a, 0x0c, 0x42, 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, - 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, - 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x4c, 0x69, 0x73, - 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x12, 0x1d, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, - 0x6e, 0x49, 0x44, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, - 0x49, 0x44, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x10, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x12, - 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, - 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, - 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x50, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, - 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x53, 0x0a, 0x18, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4d, 0x61, 0x63, 0x61, 0x72, - 0x6f, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4d, 0x61, 0x63, 0x50, - 0x65, 0x72, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4d, 0x61, 0x63, 0x50, 0x65, 0x72, 0x6d, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x52, 0x50, 0x43, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, - 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x69, 0x64, 0x64, - 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x1b, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, - 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x28, 0x01, 0x30, 0x01, 0x12, - 0x56, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, - 0x64, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, - 0x6e, 0x64, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x73, 0x12, 0x25, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x30, - 0x01, 0x12, 0x44, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, - 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, - 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, + 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, + 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, + 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x13, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x21, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x12, 0x54, 0x0a, 0x17, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x6c, 0x6c, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x1e, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x4e, 0x0a, 0x10, 0x56, 0x65, 0x72, + 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x19, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x15, 0x52, 0x65, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x58, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x20, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x19, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x30, 0x01, 0x12, 0x47, 0x0a, 0x0c, 0x42, + 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x42, 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, + 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, + 0x6e, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, + 0x6e, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x4c, + 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, + 0x18, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x50, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4d, 0x61, 0x63, 0x50, 0x65, 0x72, 0x6d, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x4d, 0x61, 0x63, 0x50, 0x65, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x56, 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x50, + 0x43, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x28, 0x01, 0x30, 0x01, 0x12, 0x56, 0x0a, 0x11, 0x53, 0x65, + 0x6e, 0x64, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x75, 0x73, 0x74, + 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x75, 0x73, + 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x58, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, + 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x25, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, + 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x75, 0x73, + 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x30, 0x01, 0x12, 0x44, 0x0a, 0x0b, + 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x14, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, - 0x70, 0x48, 0x74, 0x6c, 0x63, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x22, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x48, 0x74, - 0x6c, 0x63, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, - 0x75, 0x70, 0x48, 0x74, 0x6c, 0x63, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x14, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x48, 0x74, 0x6c, 0x63, + 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x48, 0x74, 0x6c, 0x63, 0x52, 0x65, 0x73, + 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x48, 0x74, 0x6c, + 0x63, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -21518,7 +21731,7 @@ func file_lightning_proto_rawDescGZIP() []byte { } var file_lightning_proto_enumTypes = make([]protoimpl.EnumInfo, 21) -var file_lightning_proto_msgTypes = make([]protoimpl.MessageInfo, 228) +var file_lightning_proto_msgTypes = make([]protoimpl.MessageInfo, 229) var file_lightning_proto_goTypes = []interface{}{ (OutputScriptType)(0), // 0: lnrpc.OutputScriptType (CoinSelectionStrategy)(0), // 1: lnrpc.CoinSelectionStrategy @@ -21732,43 +21945,44 @@ var file_lightning_proto_goTypes = []interface{}{ (*ListPermissionsResponse)(nil), // 209: lnrpc.ListPermissionsResponse (*Failure)(nil), // 210: lnrpc.Failure (*ChannelUpdate)(nil), // 211: lnrpc.ChannelUpdate - (*MacaroonId)(nil), // 212: lnrpc.MacaroonId - (*Op)(nil), // 213: lnrpc.Op - (*CheckMacPermRequest)(nil), // 214: lnrpc.CheckMacPermRequest - (*CheckMacPermResponse)(nil), // 215: lnrpc.CheckMacPermResponse - (*RPCMiddlewareRequest)(nil), // 216: lnrpc.RPCMiddlewareRequest - (*StreamAuth)(nil), // 217: lnrpc.StreamAuth - (*RPCMessage)(nil), // 218: lnrpc.RPCMessage - (*RPCMiddlewareResponse)(nil), // 219: lnrpc.RPCMiddlewareResponse - (*MiddlewareRegistration)(nil), // 220: lnrpc.MiddlewareRegistration - (*InterceptFeedback)(nil), // 221: lnrpc.InterceptFeedback - nil, // 222: lnrpc.SendRequest.DestCustomRecordsEntry - nil, // 223: lnrpc.EstimateFeeRequest.AddrToAmountEntry - nil, // 224: lnrpc.SendManyRequest.AddrToAmountEntry - nil, // 225: lnrpc.Peer.FeaturesEntry - nil, // 226: lnrpc.GetInfoResponse.FeaturesEntry - nil, // 227: lnrpc.GetDebugInfoResponse.ConfigEntry - (*PendingChannelsResponse_PendingChannel)(nil), // 228: lnrpc.PendingChannelsResponse.PendingChannel - (*PendingChannelsResponse_PendingOpenChannel)(nil), // 229: lnrpc.PendingChannelsResponse.PendingOpenChannel - (*PendingChannelsResponse_WaitingCloseChannel)(nil), // 230: lnrpc.PendingChannelsResponse.WaitingCloseChannel - (*PendingChannelsResponse_Commitments)(nil), // 231: lnrpc.PendingChannelsResponse.Commitments - (*PendingChannelsResponse_ClosedChannel)(nil), // 232: lnrpc.PendingChannelsResponse.ClosedChannel - (*PendingChannelsResponse_ForceClosedChannel)(nil), // 233: lnrpc.PendingChannelsResponse.ForceClosedChannel - nil, // 234: lnrpc.WalletBalanceResponse.AccountBalanceEntry - nil, // 235: lnrpc.QueryRoutesRequest.DestCustomRecordsEntry - nil, // 236: lnrpc.Hop.CustomRecordsEntry - nil, // 237: lnrpc.LightningNode.FeaturesEntry - nil, // 238: lnrpc.LightningNode.CustomRecordsEntry - nil, // 239: lnrpc.RoutingPolicy.CustomRecordsEntry - nil, // 240: lnrpc.ChannelEdge.CustomRecordsEntry - nil, // 241: lnrpc.NodeMetricsResponse.BetweennessCentralityEntry - nil, // 242: lnrpc.NodeUpdate.FeaturesEntry - nil, // 243: lnrpc.Invoice.FeaturesEntry - nil, // 244: lnrpc.Invoice.AmpInvoiceStateEntry - nil, // 245: lnrpc.InvoiceHTLC.CustomRecordsEntry - nil, // 246: lnrpc.Payment.FirstHopCustomRecordsEntry - nil, // 247: lnrpc.PayReq.FeaturesEntry - nil, // 248: lnrpc.ListPermissionsResponse.MethodPermissionsEntry + (*ChannelUpdate2)(nil), // 212: lnrpc.ChannelUpdate2 + (*MacaroonId)(nil), // 213: lnrpc.MacaroonId + (*Op)(nil), // 214: lnrpc.Op + (*CheckMacPermRequest)(nil), // 215: lnrpc.CheckMacPermRequest + (*CheckMacPermResponse)(nil), // 216: lnrpc.CheckMacPermResponse + (*RPCMiddlewareRequest)(nil), // 217: lnrpc.RPCMiddlewareRequest + (*StreamAuth)(nil), // 218: lnrpc.StreamAuth + (*RPCMessage)(nil), // 219: lnrpc.RPCMessage + (*RPCMiddlewareResponse)(nil), // 220: lnrpc.RPCMiddlewareResponse + (*MiddlewareRegistration)(nil), // 221: lnrpc.MiddlewareRegistration + (*InterceptFeedback)(nil), // 222: lnrpc.InterceptFeedback + nil, // 223: lnrpc.SendRequest.DestCustomRecordsEntry + nil, // 224: lnrpc.EstimateFeeRequest.AddrToAmountEntry + nil, // 225: lnrpc.SendManyRequest.AddrToAmountEntry + nil, // 226: lnrpc.Peer.FeaturesEntry + nil, // 227: lnrpc.GetInfoResponse.FeaturesEntry + nil, // 228: lnrpc.GetDebugInfoResponse.ConfigEntry + (*PendingChannelsResponse_PendingChannel)(nil), // 229: lnrpc.PendingChannelsResponse.PendingChannel + (*PendingChannelsResponse_PendingOpenChannel)(nil), // 230: lnrpc.PendingChannelsResponse.PendingOpenChannel + (*PendingChannelsResponse_WaitingCloseChannel)(nil), // 231: lnrpc.PendingChannelsResponse.WaitingCloseChannel + (*PendingChannelsResponse_Commitments)(nil), // 232: lnrpc.PendingChannelsResponse.Commitments + (*PendingChannelsResponse_ClosedChannel)(nil), // 233: lnrpc.PendingChannelsResponse.ClosedChannel + (*PendingChannelsResponse_ForceClosedChannel)(nil), // 234: lnrpc.PendingChannelsResponse.ForceClosedChannel + nil, // 235: lnrpc.WalletBalanceResponse.AccountBalanceEntry + nil, // 236: lnrpc.QueryRoutesRequest.DestCustomRecordsEntry + nil, // 237: lnrpc.Hop.CustomRecordsEntry + nil, // 238: lnrpc.LightningNode.FeaturesEntry + nil, // 239: lnrpc.LightningNode.CustomRecordsEntry + nil, // 240: lnrpc.RoutingPolicy.CustomRecordsEntry + nil, // 241: lnrpc.ChannelEdge.CustomRecordsEntry + nil, // 242: lnrpc.NodeMetricsResponse.BetweennessCentralityEntry + nil, // 243: lnrpc.NodeUpdate.FeaturesEntry + nil, // 244: lnrpc.Invoice.FeaturesEntry + nil, // 245: lnrpc.Invoice.AmpInvoiceStateEntry + nil, // 246: lnrpc.InvoiceHTLC.CustomRecordsEntry + nil, // 247: lnrpc.Payment.FirstHopCustomRecordsEntry + nil, // 248: lnrpc.PayReq.FeaturesEntry + nil, // 249: lnrpc.ListPermissionsResponse.MethodPermissionsEntry } var file_lightning_proto_depIdxs = []int32{ 2, // 0: lnrpc.Utxo.address_type:type_name -> lnrpc.AddressType @@ -21778,14 +21992,14 @@ var file_lightning_proto_depIdxs = []int32{ 40, // 4: lnrpc.Transaction.previous_outpoints:type_name -> lnrpc.PreviousOutPoint 29, // 5: lnrpc.TransactionDetails.transactions:type_name -> lnrpc.Transaction 32, // 6: lnrpc.SendRequest.fee_limit:type_name -> lnrpc.FeeLimit - 222, // 7: lnrpc.SendRequest.dest_custom_records:type_name -> lnrpc.SendRequest.DestCustomRecordsEntry + 223, // 7: lnrpc.SendRequest.dest_custom_records:type_name -> lnrpc.SendRequest.DestCustomRecordsEntry 10, // 8: lnrpc.SendRequest.dest_features:type_name -> lnrpc.FeatureBit 127, // 9: lnrpc.SendResponse.payment_route:type_name -> lnrpc.Route 127, // 10: lnrpc.SendToRouteRequest.route:type_name -> lnrpc.Route 3, // 11: lnrpc.ChannelAcceptRequest.commitment_type:type_name -> lnrpc.CommitmentType - 223, // 12: lnrpc.EstimateFeeRequest.AddrToAmount:type_name -> lnrpc.EstimateFeeRequest.AddrToAmountEntry + 224, // 12: lnrpc.EstimateFeeRequest.AddrToAmount:type_name -> lnrpc.EstimateFeeRequest.AddrToAmountEntry 1, // 13: lnrpc.EstimateFeeRequest.coin_selection_strategy:type_name -> lnrpc.CoinSelectionStrategy - 224, // 14: lnrpc.SendManyRequest.AddrToAmount:type_name -> lnrpc.SendManyRequest.AddrToAmountEntry + 225, // 14: lnrpc.SendManyRequest.AddrToAmount:type_name -> lnrpc.SendManyRequest.AddrToAmountEntry 1, // 15: lnrpc.SendManyRequest.coin_selection_strategy:type_name -> lnrpc.CoinSelectionStrategy 1, // 16: lnrpc.SendCoinsRequest.coin_selection_strategy:type_name -> lnrpc.CoinSelectionStrategy 39, // 17: lnrpc.SendCoinsRequest.outpoints:type_name -> lnrpc.OutPoint @@ -21807,13 +22021,13 @@ var file_lightning_proto_depIdxs = []int32{ 39, // 33: lnrpc.Resolution.outpoint:type_name -> lnrpc.OutPoint 68, // 34: lnrpc.ClosedChannelsResponse.channels:type_name -> lnrpc.ChannelCloseSummary 13, // 35: lnrpc.Peer.sync_type:type_name -> lnrpc.Peer.SyncType - 225, // 36: lnrpc.Peer.features:type_name -> lnrpc.Peer.FeaturesEntry + 226, // 36: lnrpc.Peer.features:type_name -> lnrpc.Peer.FeaturesEntry 73, // 37: lnrpc.Peer.errors:type_name -> lnrpc.TimestampedError 72, // 38: lnrpc.ListPeersResponse.peers:type_name -> lnrpc.Peer 14, // 39: lnrpc.PeerEvent.type:type_name -> lnrpc.PeerEvent.EventType 84, // 40: lnrpc.GetInfoResponse.chains:type_name -> lnrpc.Chain - 226, // 41: lnrpc.GetInfoResponse.features:type_name -> lnrpc.GetInfoResponse.FeaturesEntry - 227, // 42: lnrpc.GetDebugInfoResponse.config:type_name -> lnrpc.GetDebugInfoResponse.ConfigEntry + 227, // 41: lnrpc.GetInfoResponse.features:type_name -> lnrpc.GetInfoResponse.FeaturesEntry + 228, // 42: lnrpc.GetDebugInfoResponse.config:type_name -> lnrpc.GetDebugInfoResponse.ConfigEntry 38, // 43: lnrpc.ChannelOpenUpdate.channel_point:type_name -> lnrpc.ChannelPoint 87, // 44: lnrpc.ChannelCloseUpdate.local_close_output:type_name -> lnrpc.CloseOutput 87, // 45: lnrpc.ChannelCloseUpdate.remote_close_output:type_name -> lnrpc.CloseOutput @@ -21841,10 +22055,10 @@ var file_lightning_proto_depIdxs = []int32{ 104, // 67: lnrpc.FundingTransitionMsg.shim_cancel:type_name -> lnrpc.FundingShimCancel 105, // 68: lnrpc.FundingTransitionMsg.psbt_verify:type_name -> lnrpc.FundingPsbtVerify 106, // 69: lnrpc.FundingTransitionMsg.psbt_finalize:type_name -> lnrpc.FundingPsbtFinalize - 229, // 70: lnrpc.PendingChannelsResponse.pending_open_channels:type_name -> lnrpc.PendingChannelsResponse.PendingOpenChannel - 232, // 71: lnrpc.PendingChannelsResponse.pending_closing_channels:type_name -> lnrpc.PendingChannelsResponse.ClosedChannel - 233, // 72: lnrpc.PendingChannelsResponse.pending_force_closing_channels:type_name -> lnrpc.PendingChannelsResponse.ForceClosedChannel - 230, // 73: lnrpc.PendingChannelsResponse.waiting_close_channels:type_name -> lnrpc.PendingChannelsResponse.WaitingCloseChannel + 230, // 70: lnrpc.PendingChannelsResponse.pending_open_channels:type_name -> lnrpc.PendingChannelsResponse.PendingOpenChannel + 233, // 71: lnrpc.PendingChannelsResponse.pending_closing_channels:type_name -> lnrpc.PendingChannelsResponse.ClosedChannel + 234, // 72: lnrpc.PendingChannelsResponse.pending_force_closing_channels:type_name -> lnrpc.PendingChannelsResponse.ForceClosedChannel + 231, // 73: lnrpc.PendingChannelsResponse.waiting_close_channels:type_name -> lnrpc.PendingChannelsResponse.WaitingCloseChannel 62, // 74: lnrpc.ChannelEventUpdate.open_channel:type_name -> lnrpc.Channel 68, // 75: lnrpc.ChannelEventUpdate.closed_channel:type_name -> lnrpc.ChannelCloseSummary 38, // 76: lnrpc.ChannelEventUpdate.active_channel:type_name -> lnrpc.ChannelPoint @@ -21852,7 +22066,7 @@ var file_lightning_proto_depIdxs = []int32{ 91, // 78: lnrpc.ChannelEventUpdate.pending_open_channel:type_name -> lnrpc.PendingUpdate 38, // 79: lnrpc.ChannelEventUpdate.fully_resolved_channel:type_name -> lnrpc.ChannelPoint 16, // 80: lnrpc.ChannelEventUpdate.type:type_name -> lnrpc.ChannelEventUpdate.UpdateType - 234, // 81: lnrpc.WalletBalanceResponse.account_balance:type_name -> lnrpc.WalletBalanceResponse.AccountBalanceEntry + 235, // 81: lnrpc.WalletBalanceResponse.account_balance:type_name -> lnrpc.WalletBalanceResponse.AccountBalanceEntry 117, // 82: lnrpc.ChannelBalanceResponse.local_balance:type_name -> lnrpc.Amount 117, // 83: lnrpc.ChannelBalanceResponse.remote_balance:type_name -> lnrpc.Amount 117, // 84: lnrpc.ChannelBalanceResponse.unsettled_local_balance:type_name -> lnrpc.Amount @@ -21862,33 +22076,33 @@ var file_lightning_proto_depIdxs = []int32{ 32, // 88: lnrpc.QueryRoutesRequest.fee_limit:type_name -> lnrpc.FeeLimit 122, // 89: lnrpc.QueryRoutesRequest.ignored_edges:type_name -> lnrpc.EdgeLocator 121, // 90: lnrpc.QueryRoutesRequest.ignored_pairs:type_name -> lnrpc.NodePair - 235, // 91: lnrpc.QueryRoutesRequest.dest_custom_records:type_name -> lnrpc.QueryRoutesRequest.DestCustomRecordsEntry + 236, // 91: lnrpc.QueryRoutesRequest.dest_custom_records:type_name -> lnrpc.QueryRoutesRequest.DestCustomRecordsEntry 151, // 92: lnrpc.QueryRoutesRequest.route_hints:type_name -> lnrpc.RouteHint 152, // 93: lnrpc.QueryRoutesRequest.blinded_payment_paths:type_name -> lnrpc.BlindedPaymentPath 10, // 94: lnrpc.QueryRoutesRequest.dest_features:type_name -> lnrpc.FeatureBit 127, // 95: lnrpc.QueryRoutesResponse.routes:type_name -> lnrpc.Route 125, // 96: lnrpc.Hop.mpp_record:type_name -> lnrpc.MPPRecord 126, // 97: lnrpc.Hop.amp_record:type_name -> lnrpc.AMPRecord - 236, // 98: lnrpc.Hop.custom_records:type_name -> lnrpc.Hop.CustomRecordsEntry + 237, // 98: lnrpc.Hop.custom_records:type_name -> lnrpc.Hop.CustomRecordsEntry 124, // 99: lnrpc.Route.hops:type_name -> lnrpc.Hop 130, // 100: lnrpc.NodeInfo.node:type_name -> lnrpc.LightningNode 133, // 101: lnrpc.NodeInfo.channels:type_name -> lnrpc.ChannelEdge 131, // 102: lnrpc.LightningNode.addresses:type_name -> lnrpc.NodeAddress - 237, // 103: lnrpc.LightningNode.features:type_name -> lnrpc.LightningNode.FeaturesEntry - 238, // 104: lnrpc.LightningNode.custom_records:type_name -> lnrpc.LightningNode.CustomRecordsEntry - 239, // 105: lnrpc.RoutingPolicy.custom_records:type_name -> lnrpc.RoutingPolicy.CustomRecordsEntry + 238, // 103: lnrpc.LightningNode.features:type_name -> lnrpc.LightningNode.FeaturesEntry + 239, // 104: lnrpc.LightningNode.custom_records:type_name -> lnrpc.LightningNode.CustomRecordsEntry + 240, // 105: lnrpc.RoutingPolicy.custom_records:type_name -> lnrpc.RoutingPolicy.CustomRecordsEntry 132, // 106: lnrpc.ChannelEdge.node1_policy:type_name -> lnrpc.RoutingPolicy 132, // 107: lnrpc.ChannelEdge.node2_policy:type_name -> lnrpc.RoutingPolicy - 240, // 108: lnrpc.ChannelEdge.custom_records:type_name -> lnrpc.ChannelEdge.CustomRecordsEntry + 241, // 108: lnrpc.ChannelEdge.custom_records:type_name -> lnrpc.ChannelEdge.CustomRecordsEntry 130, // 109: lnrpc.ChannelGraph.nodes:type_name -> lnrpc.LightningNode 133, // 110: lnrpc.ChannelGraph.edges:type_name -> lnrpc.ChannelEdge 7, // 111: lnrpc.NodeMetricsRequest.types:type_name -> lnrpc.NodeMetricType - 241, // 112: lnrpc.NodeMetricsResponse.betweenness_centrality:type_name -> lnrpc.NodeMetricsResponse.BetweennessCentralityEntry + 242, // 112: lnrpc.NodeMetricsResponse.betweenness_centrality:type_name -> lnrpc.NodeMetricsResponse.BetweennessCentralityEntry 146, // 113: lnrpc.GraphTopologyUpdate.node_updates:type_name -> lnrpc.NodeUpdate 147, // 114: lnrpc.GraphTopologyUpdate.channel_updates:type_name -> lnrpc.ChannelEdgeUpdate 148, // 115: lnrpc.GraphTopologyUpdate.closed_chans:type_name -> lnrpc.ClosedChannelUpdate 131, // 116: lnrpc.NodeUpdate.node_addresses:type_name -> lnrpc.NodeAddress - 242, // 117: lnrpc.NodeUpdate.features:type_name -> lnrpc.NodeUpdate.FeaturesEntry + 243, // 117: lnrpc.NodeUpdate.features:type_name -> lnrpc.NodeUpdate.FeaturesEntry 38, // 118: lnrpc.ChannelEdgeUpdate.chan_point:type_name -> lnrpc.ChannelPoint 132, // 119: lnrpc.ChannelEdgeUpdate.routing_policy:type_name -> lnrpc.RoutingPolicy 38, // 120: lnrpc.ClosedChannelUpdate.chan_point:type_name -> lnrpc.ChannelPoint @@ -21900,24 +22114,24 @@ var file_lightning_proto_depIdxs = []int32{ 151, // 126: lnrpc.Invoice.route_hints:type_name -> lnrpc.RouteHint 17, // 127: lnrpc.Invoice.state:type_name -> lnrpc.Invoice.InvoiceState 158, // 128: lnrpc.Invoice.htlcs:type_name -> lnrpc.InvoiceHTLC - 243, // 129: lnrpc.Invoice.features:type_name -> lnrpc.Invoice.FeaturesEntry - 244, // 130: lnrpc.Invoice.amp_invoice_state:type_name -> lnrpc.Invoice.AmpInvoiceStateEntry + 244, // 129: lnrpc.Invoice.features:type_name -> lnrpc.Invoice.FeaturesEntry + 245, // 130: lnrpc.Invoice.amp_invoice_state:type_name -> lnrpc.Invoice.AmpInvoiceStateEntry 157, // 131: lnrpc.Invoice.blinded_path_config:type_name -> lnrpc.BlindedPathConfig 8, // 132: lnrpc.InvoiceHTLC.state:type_name -> lnrpc.InvoiceHTLCState - 245, // 133: lnrpc.InvoiceHTLC.custom_records:type_name -> lnrpc.InvoiceHTLC.CustomRecordsEntry + 246, // 133: lnrpc.InvoiceHTLC.custom_records:type_name -> lnrpc.InvoiceHTLC.CustomRecordsEntry 159, // 134: lnrpc.InvoiceHTLC.amp:type_name -> lnrpc.AMP 156, // 135: lnrpc.ListInvoiceResponse.invoices:type_name -> lnrpc.Invoice 18, // 136: lnrpc.Payment.status:type_name -> lnrpc.Payment.PaymentStatus 166, // 137: lnrpc.Payment.htlcs:type_name -> lnrpc.HTLCAttempt 9, // 138: lnrpc.Payment.failure_reason:type_name -> lnrpc.PaymentFailureReason - 246, // 139: lnrpc.Payment.first_hop_custom_records:type_name -> lnrpc.Payment.FirstHopCustomRecordsEntry + 247, // 139: lnrpc.Payment.first_hop_custom_records:type_name -> lnrpc.Payment.FirstHopCustomRecordsEntry 19, // 140: lnrpc.HTLCAttempt.status:type_name -> lnrpc.HTLCAttempt.HTLCStatus 127, // 141: lnrpc.HTLCAttempt.route:type_name -> lnrpc.Route 210, // 142: lnrpc.HTLCAttempt.failure:type_name -> lnrpc.Failure 165, // 143: lnrpc.ListPaymentsResponse.payments:type_name -> lnrpc.Payment 38, // 144: lnrpc.AbandonChannelRequest.channel_point:type_name -> lnrpc.ChannelPoint 151, // 145: lnrpc.PayReq.route_hints:type_name -> lnrpc.RouteHint - 247, // 146: lnrpc.PayReq.features:type_name -> lnrpc.PayReq.FeaturesEntry + 248, // 146: lnrpc.PayReq.features:type_name -> lnrpc.PayReq.FeaturesEntry 152, // 147: lnrpc.PayReq.blinded_paths:type_name -> lnrpc.BlindedPaymentPath 181, // 148: lnrpc.FeeReportResponse.channel_fees:type_name -> lnrpc.ChannelFeeReport 38, // 149: lnrpc.PolicyUpdateRequest.chan_point:type_name -> lnrpc.ChannelPoint @@ -21935,176 +22149,177 @@ var file_lightning_proto_depIdxs = []int32{ 195, // 161: lnrpc.RestoreChanBackupRequest.chan_backups:type_name -> lnrpc.ChannelBackups 200, // 162: lnrpc.BakeMacaroonRequest.permissions:type_name -> lnrpc.MacaroonPermission 200, // 163: lnrpc.MacaroonPermissionList.permissions:type_name -> lnrpc.MacaroonPermission - 248, // 164: lnrpc.ListPermissionsResponse.method_permissions:type_name -> lnrpc.ListPermissionsResponse.MethodPermissionsEntry + 249, // 164: lnrpc.ListPermissionsResponse.method_permissions:type_name -> lnrpc.ListPermissionsResponse.MethodPermissionsEntry 20, // 165: lnrpc.Failure.code:type_name -> lnrpc.Failure.FailureCode 211, // 166: lnrpc.Failure.channel_update:type_name -> lnrpc.ChannelUpdate - 213, // 167: lnrpc.MacaroonId.ops:type_name -> lnrpc.Op - 200, // 168: lnrpc.CheckMacPermRequest.permissions:type_name -> lnrpc.MacaroonPermission - 217, // 169: lnrpc.RPCMiddlewareRequest.stream_auth:type_name -> lnrpc.StreamAuth - 218, // 170: lnrpc.RPCMiddlewareRequest.request:type_name -> lnrpc.RPCMessage - 218, // 171: lnrpc.RPCMiddlewareRequest.response:type_name -> lnrpc.RPCMessage - 220, // 172: lnrpc.RPCMiddlewareResponse.register:type_name -> lnrpc.MiddlewareRegistration - 221, // 173: lnrpc.RPCMiddlewareResponse.feedback:type_name -> lnrpc.InterceptFeedback - 179, // 174: lnrpc.Peer.FeaturesEntry.value:type_name -> lnrpc.Feature - 179, // 175: lnrpc.GetInfoResponse.FeaturesEntry.value:type_name -> lnrpc.Feature - 4, // 176: lnrpc.PendingChannelsResponse.PendingChannel.initiator:type_name -> lnrpc.Initiator - 3, // 177: lnrpc.PendingChannelsResponse.PendingChannel.commitment_type:type_name -> lnrpc.CommitmentType - 228, // 178: lnrpc.PendingChannelsResponse.PendingOpenChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel - 228, // 179: lnrpc.PendingChannelsResponse.WaitingCloseChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel - 231, // 180: lnrpc.PendingChannelsResponse.WaitingCloseChannel.commitments:type_name -> lnrpc.PendingChannelsResponse.Commitments - 228, // 181: lnrpc.PendingChannelsResponse.ClosedChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel - 228, // 182: lnrpc.PendingChannelsResponse.ForceClosedChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel - 109, // 183: lnrpc.PendingChannelsResponse.ForceClosedChannel.pending_htlcs:type_name -> lnrpc.PendingHTLC - 15, // 184: lnrpc.PendingChannelsResponse.ForceClosedChannel.anchor:type_name -> lnrpc.PendingChannelsResponse.ForceClosedChannel.AnchorState - 114, // 185: lnrpc.WalletBalanceResponse.AccountBalanceEntry.value:type_name -> lnrpc.WalletAccountBalance - 179, // 186: lnrpc.LightningNode.FeaturesEntry.value:type_name -> lnrpc.Feature - 138, // 187: lnrpc.NodeMetricsResponse.BetweennessCentralityEntry.value:type_name -> lnrpc.FloatMetric - 179, // 188: lnrpc.NodeUpdate.FeaturesEntry.value:type_name -> lnrpc.Feature - 179, // 189: lnrpc.Invoice.FeaturesEntry.value:type_name -> lnrpc.Feature - 155, // 190: lnrpc.Invoice.AmpInvoiceStateEntry.value:type_name -> lnrpc.AMPInvoiceState - 179, // 191: lnrpc.PayReq.FeaturesEntry.value:type_name -> lnrpc.Feature - 207, // 192: lnrpc.ListPermissionsResponse.MethodPermissionsEntry.value:type_name -> lnrpc.MacaroonPermissionList - 115, // 193: lnrpc.Lightning.WalletBalance:input_type -> lnrpc.WalletBalanceRequest - 118, // 194: lnrpc.Lightning.ChannelBalance:input_type -> lnrpc.ChannelBalanceRequest - 30, // 195: lnrpc.Lightning.GetTransactions:input_type -> lnrpc.GetTransactionsRequest - 42, // 196: lnrpc.Lightning.EstimateFee:input_type -> lnrpc.EstimateFeeRequest - 46, // 197: lnrpc.Lightning.SendCoins:input_type -> lnrpc.SendCoinsRequest - 48, // 198: lnrpc.Lightning.ListUnspent:input_type -> lnrpc.ListUnspentRequest - 30, // 199: lnrpc.Lightning.SubscribeTransactions:input_type -> lnrpc.GetTransactionsRequest - 44, // 200: lnrpc.Lightning.SendMany:input_type -> lnrpc.SendManyRequest - 50, // 201: lnrpc.Lightning.NewAddress:input_type -> lnrpc.NewAddressRequest - 52, // 202: lnrpc.Lightning.SignMessage:input_type -> lnrpc.SignMessageRequest - 54, // 203: lnrpc.Lightning.VerifyMessage:input_type -> lnrpc.VerifyMessageRequest - 56, // 204: lnrpc.Lightning.ConnectPeer:input_type -> lnrpc.ConnectPeerRequest - 58, // 205: lnrpc.Lightning.DisconnectPeer:input_type -> lnrpc.DisconnectPeerRequest - 74, // 206: lnrpc.Lightning.ListPeers:input_type -> lnrpc.ListPeersRequest - 76, // 207: lnrpc.Lightning.SubscribePeerEvents:input_type -> lnrpc.PeerEventSubscription - 78, // 208: lnrpc.Lightning.GetInfo:input_type -> lnrpc.GetInfoRequest - 80, // 209: lnrpc.Lightning.GetDebugInfo:input_type -> lnrpc.GetDebugInfoRequest - 82, // 210: lnrpc.Lightning.GetRecoveryInfo:input_type -> lnrpc.GetRecoveryInfoRequest - 110, // 211: lnrpc.Lightning.PendingChannels:input_type -> lnrpc.PendingChannelsRequest - 63, // 212: lnrpc.Lightning.ListChannels:input_type -> lnrpc.ListChannelsRequest - 112, // 213: lnrpc.Lightning.SubscribeChannelEvents:input_type -> lnrpc.ChannelEventSubscription - 70, // 214: lnrpc.Lightning.ClosedChannels:input_type -> lnrpc.ClosedChannelsRequest - 97, // 215: lnrpc.Lightning.OpenChannelSync:input_type -> lnrpc.OpenChannelRequest - 97, // 216: lnrpc.Lightning.OpenChannel:input_type -> lnrpc.OpenChannelRequest - 94, // 217: lnrpc.Lightning.BatchOpenChannel:input_type -> lnrpc.BatchOpenChannelRequest - 107, // 218: lnrpc.Lightning.FundingStateStep:input_type -> lnrpc.FundingTransitionMsg - 37, // 219: lnrpc.Lightning.ChannelAcceptor:input_type -> lnrpc.ChannelAcceptResponse - 89, // 220: lnrpc.Lightning.CloseChannel:input_type -> lnrpc.CloseChannelRequest - 173, // 221: lnrpc.Lightning.AbandonChannel:input_type -> lnrpc.AbandonChannelRequest - 33, // 222: lnrpc.Lightning.SendPayment:input_type -> lnrpc.SendRequest - 33, // 223: lnrpc.Lightning.SendPaymentSync:input_type -> lnrpc.SendRequest - 35, // 224: lnrpc.Lightning.SendToRoute:input_type -> lnrpc.SendToRouteRequest - 35, // 225: lnrpc.Lightning.SendToRouteSync:input_type -> lnrpc.SendToRouteRequest - 156, // 226: lnrpc.Lightning.AddInvoice:input_type -> lnrpc.Invoice - 162, // 227: lnrpc.Lightning.ListInvoices:input_type -> lnrpc.ListInvoiceRequest - 161, // 228: lnrpc.Lightning.LookupInvoice:input_type -> lnrpc.PaymentHash - 164, // 229: lnrpc.Lightning.SubscribeInvoices:input_type -> lnrpc.InvoiceSubscription - 177, // 230: lnrpc.Lightning.DecodePayReq:input_type -> lnrpc.PayReqString - 167, // 231: lnrpc.Lightning.ListPayments:input_type -> lnrpc.ListPaymentsRequest - 169, // 232: lnrpc.Lightning.DeletePayment:input_type -> lnrpc.DeletePaymentRequest - 170, // 233: lnrpc.Lightning.DeleteAllPayments:input_type -> lnrpc.DeleteAllPaymentsRequest - 134, // 234: lnrpc.Lightning.DescribeGraph:input_type -> lnrpc.ChannelGraphRequest - 136, // 235: lnrpc.Lightning.GetNodeMetrics:input_type -> lnrpc.NodeMetricsRequest - 139, // 236: lnrpc.Lightning.GetChanInfo:input_type -> lnrpc.ChanInfoRequest - 128, // 237: lnrpc.Lightning.GetNodeInfo:input_type -> lnrpc.NodeInfoRequest - 120, // 238: lnrpc.Lightning.QueryRoutes:input_type -> lnrpc.QueryRoutesRequest - 140, // 239: lnrpc.Lightning.GetNetworkInfo:input_type -> lnrpc.NetworkInfoRequest - 142, // 240: lnrpc.Lightning.StopDaemon:input_type -> lnrpc.StopRequest - 144, // 241: lnrpc.Lightning.SubscribeChannelGraph:input_type -> lnrpc.GraphTopologySubscription - 175, // 242: lnrpc.Lightning.DebugLevel:input_type -> lnrpc.DebugLevelRequest - 180, // 243: lnrpc.Lightning.FeeReport:input_type -> lnrpc.FeeReportRequest - 184, // 244: lnrpc.Lightning.UpdateChannelPolicy:input_type -> lnrpc.PolicyUpdateRequest - 187, // 245: lnrpc.Lightning.ForwardingHistory:input_type -> lnrpc.ForwardingHistoryRequest - 190, // 246: lnrpc.Lightning.ExportChannelBackup:input_type -> lnrpc.ExportChannelBackupRequest - 193, // 247: lnrpc.Lightning.ExportAllChannelBackups:input_type -> lnrpc.ChanBackupExportRequest - 194, // 248: lnrpc.Lightning.VerifyChanBackup:input_type -> lnrpc.ChanBackupSnapshot - 196, // 249: lnrpc.Lightning.RestoreChannelBackups:input_type -> lnrpc.RestoreChanBackupRequest - 198, // 250: lnrpc.Lightning.SubscribeChannelBackups:input_type -> lnrpc.ChannelBackupSubscription - 201, // 251: lnrpc.Lightning.BakeMacaroon:input_type -> lnrpc.BakeMacaroonRequest - 203, // 252: lnrpc.Lightning.ListMacaroonIDs:input_type -> lnrpc.ListMacaroonIDsRequest - 205, // 253: lnrpc.Lightning.DeleteMacaroonID:input_type -> lnrpc.DeleteMacaroonIDRequest - 208, // 254: lnrpc.Lightning.ListPermissions:input_type -> lnrpc.ListPermissionsRequest - 214, // 255: lnrpc.Lightning.CheckMacaroonPermissions:input_type -> lnrpc.CheckMacPermRequest - 219, // 256: lnrpc.Lightning.RegisterRPCMiddleware:input_type -> lnrpc.RPCMiddlewareResponse - 25, // 257: lnrpc.Lightning.SendCustomMessage:input_type -> lnrpc.SendCustomMessageRequest - 23, // 258: lnrpc.Lightning.SubscribeCustomMessages:input_type -> lnrpc.SubscribeCustomMessagesRequest - 66, // 259: lnrpc.Lightning.ListAliases:input_type -> lnrpc.ListAliasesRequest - 21, // 260: lnrpc.Lightning.LookupHtlcResolution:input_type -> lnrpc.LookupHtlcResolutionRequest - 116, // 261: lnrpc.Lightning.WalletBalance:output_type -> lnrpc.WalletBalanceResponse - 119, // 262: lnrpc.Lightning.ChannelBalance:output_type -> lnrpc.ChannelBalanceResponse - 31, // 263: lnrpc.Lightning.GetTransactions:output_type -> lnrpc.TransactionDetails - 43, // 264: lnrpc.Lightning.EstimateFee:output_type -> lnrpc.EstimateFeeResponse - 47, // 265: lnrpc.Lightning.SendCoins:output_type -> lnrpc.SendCoinsResponse - 49, // 266: lnrpc.Lightning.ListUnspent:output_type -> lnrpc.ListUnspentResponse - 29, // 267: lnrpc.Lightning.SubscribeTransactions:output_type -> lnrpc.Transaction - 45, // 268: lnrpc.Lightning.SendMany:output_type -> lnrpc.SendManyResponse - 51, // 269: lnrpc.Lightning.NewAddress:output_type -> lnrpc.NewAddressResponse - 53, // 270: lnrpc.Lightning.SignMessage:output_type -> lnrpc.SignMessageResponse - 55, // 271: lnrpc.Lightning.VerifyMessage:output_type -> lnrpc.VerifyMessageResponse - 57, // 272: lnrpc.Lightning.ConnectPeer:output_type -> lnrpc.ConnectPeerResponse - 59, // 273: lnrpc.Lightning.DisconnectPeer:output_type -> lnrpc.DisconnectPeerResponse - 75, // 274: lnrpc.Lightning.ListPeers:output_type -> lnrpc.ListPeersResponse - 77, // 275: lnrpc.Lightning.SubscribePeerEvents:output_type -> lnrpc.PeerEvent - 79, // 276: lnrpc.Lightning.GetInfo:output_type -> lnrpc.GetInfoResponse - 81, // 277: lnrpc.Lightning.GetDebugInfo:output_type -> lnrpc.GetDebugInfoResponse - 83, // 278: lnrpc.Lightning.GetRecoveryInfo:output_type -> lnrpc.GetRecoveryInfoResponse - 111, // 279: lnrpc.Lightning.PendingChannels:output_type -> lnrpc.PendingChannelsResponse - 64, // 280: lnrpc.Lightning.ListChannels:output_type -> lnrpc.ListChannelsResponse - 113, // 281: lnrpc.Lightning.SubscribeChannelEvents:output_type -> lnrpc.ChannelEventUpdate - 71, // 282: lnrpc.Lightning.ClosedChannels:output_type -> lnrpc.ClosedChannelsResponse - 38, // 283: lnrpc.Lightning.OpenChannelSync:output_type -> lnrpc.ChannelPoint - 98, // 284: lnrpc.Lightning.OpenChannel:output_type -> lnrpc.OpenStatusUpdate - 96, // 285: lnrpc.Lightning.BatchOpenChannel:output_type -> lnrpc.BatchOpenChannelResponse - 108, // 286: lnrpc.Lightning.FundingStateStep:output_type -> lnrpc.FundingStateStepResp - 36, // 287: lnrpc.Lightning.ChannelAcceptor:output_type -> lnrpc.ChannelAcceptRequest - 90, // 288: lnrpc.Lightning.CloseChannel:output_type -> lnrpc.CloseStatusUpdate - 174, // 289: lnrpc.Lightning.AbandonChannel:output_type -> lnrpc.AbandonChannelResponse - 34, // 290: lnrpc.Lightning.SendPayment:output_type -> lnrpc.SendResponse - 34, // 291: lnrpc.Lightning.SendPaymentSync:output_type -> lnrpc.SendResponse - 34, // 292: lnrpc.Lightning.SendToRoute:output_type -> lnrpc.SendResponse - 34, // 293: lnrpc.Lightning.SendToRouteSync:output_type -> lnrpc.SendResponse - 160, // 294: lnrpc.Lightning.AddInvoice:output_type -> lnrpc.AddInvoiceResponse - 163, // 295: lnrpc.Lightning.ListInvoices:output_type -> lnrpc.ListInvoiceResponse - 156, // 296: lnrpc.Lightning.LookupInvoice:output_type -> lnrpc.Invoice - 156, // 297: lnrpc.Lightning.SubscribeInvoices:output_type -> lnrpc.Invoice - 178, // 298: lnrpc.Lightning.DecodePayReq:output_type -> lnrpc.PayReq - 168, // 299: lnrpc.Lightning.ListPayments:output_type -> lnrpc.ListPaymentsResponse - 171, // 300: lnrpc.Lightning.DeletePayment:output_type -> lnrpc.DeletePaymentResponse - 172, // 301: lnrpc.Lightning.DeleteAllPayments:output_type -> lnrpc.DeleteAllPaymentsResponse - 135, // 302: lnrpc.Lightning.DescribeGraph:output_type -> lnrpc.ChannelGraph - 137, // 303: lnrpc.Lightning.GetNodeMetrics:output_type -> lnrpc.NodeMetricsResponse - 133, // 304: lnrpc.Lightning.GetChanInfo:output_type -> lnrpc.ChannelEdge - 129, // 305: lnrpc.Lightning.GetNodeInfo:output_type -> lnrpc.NodeInfo - 123, // 306: lnrpc.Lightning.QueryRoutes:output_type -> lnrpc.QueryRoutesResponse - 141, // 307: lnrpc.Lightning.GetNetworkInfo:output_type -> lnrpc.NetworkInfo - 143, // 308: lnrpc.Lightning.StopDaemon:output_type -> lnrpc.StopResponse - 145, // 309: lnrpc.Lightning.SubscribeChannelGraph:output_type -> lnrpc.GraphTopologyUpdate - 176, // 310: lnrpc.Lightning.DebugLevel:output_type -> lnrpc.DebugLevelResponse - 182, // 311: lnrpc.Lightning.FeeReport:output_type -> lnrpc.FeeReportResponse - 186, // 312: lnrpc.Lightning.UpdateChannelPolicy:output_type -> lnrpc.PolicyUpdateResponse - 189, // 313: lnrpc.Lightning.ForwardingHistory:output_type -> lnrpc.ForwardingHistoryResponse - 191, // 314: lnrpc.Lightning.ExportChannelBackup:output_type -> lnrpc.ChannelBackup - 194, // 315: lnrpc.Lightning.ExportAllChannelBackups:output_type -> lnrpc.ChanBackupSnapshot - 199, // 316: lnrpc.Lightning.VerifyChanBackup:output_type -> lnrpc.VerifyChanBackupResponse - 197, // 317: lnrpc.Lightning.RestoreChannelBackups:output_type -> lnrpc.RestoreBackupResponse - 194, // 318: lnrpc.Lightning.SubscribeChannelBackups:output_type -> lnrpc.ChanBackupSnapshot - 202, // 319: lnrpc.Lightning.BakeMacaroon:output_type -> lnrpc.BakeMacaroonResponse - 204, // 320: lnrpc.Lightning.ListMacaroonIDs:output_type -> lnrpc.ListMacaroonIDsResponse - 206, // 321: lnrpc.Lightning.DeleteMacaroonID:output_type -> lnrpc.DeleteMacaroonIDResponse - 209, // 322: lnrpc.Lightning.ListPermissions:output_type -> lnrpc.ListPermissionsResponse - 215, // 323: lnrpc.Lightning.CheckMacaroonPermissions:output_type -> lnrpc.CheckMacPermResponse - 216, // 324: lnrpc.Lightning.RegisterRPCMiddleware:output_type -> lnrpc.RPCMiddlewareRequest - 26, // 325: lnrpc.Lightning.SendCustomMessage:output_type -> lnrpc.SendCustomMessageResponse - 24, // 326: lnrpc.Lightning.SubscribeCustomMessages:output_type -> lnrpc.CustomMessage - 67, // 327: lnrpc.Lightning.ListAliases:output_type -> lnrpc.ListAliasesResponse - 22, // 328: lnrpc.Lightning.LookupHtlcResolution:output_type -> lnrpc.LookupHtlcResolutionResponse - 261, // [261:329] is the sub-list for method output_type - 193, // [193:261] is the sub-list for method input_type - 193, // [193:193] is the sub-list for extension type_name - 193, // [193:193] is the sub-list for extension extendee - 0, // [0:193] is the sub-list for field type_name + 212, // 167: lnrpc.Failure.channel_update_2:type_name -> lnrpc.ChannelUpdate2 + 214, // 168: lnrpc.MacaroonId.ops:type_name -> lnrpc.Op + 200, // 169: lnrpc.CheckMacPermRequest.permissions:type_name -> lnrpc.MacaroonPermission + 218, // 170: lnrpc.RPCMiddlewareRequest.stream_auth:type_name -> lnrpc.StreamAuth + 219, // 171: lnrpc.RPCMiddlewareRequest.request:type_name -> lnrpc.RPCMessage + 219, // 172: lnrpc.RPCMiddlewareRequest.response:type_name -> lnrpc.RPCMessage + 221, // 173: lnrpc.RPCMiddlewareResponse.register:type_name -> lnrpc.MiddlewareRegistration + 222, // 174: lnrpc.RPCMiddlewareResponse.feedback:type_name -> lnrpc.InterceptFeedback + 179, // 175: lnrpc.Peer.FeaturesEntry.value:type_name -> lnrpc.Feature + 179, // 176: lnrpc.GetInfoResponse.FeaturesEntry.value:type_name -> lnrpc.Feature + 4, // 177: lnrpc.PendingChannelsResponse.PendingChannel.initiator:type_name -> lnrpc.Initiator + 3, // 178: lnrpc.PendingChannelsResponse.PendingChannel.commitment_type:type_name -> lnrpc.CommitmentType + 229, // 179: lnrpc.PendingChannelsResponse.PendingOpenChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel + 229, // 180: lnrpc.PendingChannelsResponse.WaitingCloseChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel + 232, // 181: lnrpc.PendingChannelsResponse.WaitingCloseChannel.commitments:type_name -> lnrpc.PendingChannelsResponse.Commitments + 229, // 182: lnrpc.PendingChannelsResponse.ClosedChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel + 229, // 183: lnrpc.PendingChannelsResponse.ForceClosedChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel + 109, // 184: lnrpc.PendingChannelsResponse.ForceClosedChannel.pending_htlcs:type_name -> lnrpc.PendingHTLC + 15, // 185: lnrpc.PendingChannelsResponse.ForceClosedChannel.anchor:type_name -> lnrpc.PendingChannelsResponse.ForceClosedChannel.AnchorState + 114, // 186: lnrpc.WalletBalanceResponse.AccountBalanceEntry.value:type_name -> lnrpc.WalletAccountBalance + 179, // 187: lnrpc.LightningNode.FeaturesEntry.value:type_name -> lnrpc.Feature + 138, // 188: lnrpc.NodeMetricsResponse.BetweennessCentralityEntry.value:type_name -> lnrpc.FloatMetric + 179, // 189: lnrpc.NodeUpdate.FeaturesEntry.value:type_name -> lnrpc.Feature + 179, // 190: lnrpc.Invoice.FeaturesEntry.value:type_name -> lnrpc.Feature + 155, // 191: lnrpc.Invoice.AmpInvoiceStateEntry.value:type_name -> lnrpc.AMPInvoiceState + 179, // 192: lnrpc.PayReq.FeaturesEntry.value:type_name -> lnrpc.Feature + 207, // 193: lnrpc.ListPermissionsResponse.MethodPermissionsEntry.value:type_name -> lnrpc.MacaroonPermissionList + 115, // 194: lnrpc.Lightning.WalletBalance:input_type -> lnrpc.WalletBalanceRequest + 118, // 195: lnrpc.Lightning.ChannelBalance:input_type -> lnrpc.ChannelBalanceRequest + 30, // 196: lnrpc.Lightning.GetTransactions:input_type -> lnrpc.GetTransactionsRequest + 42, // 197: lnrpc.Lightning.EstimateFee:input_type -> lnrpc.EstimateFeeRequest + 46, // 198: lnrpc.Lightning.SendCoins:input_type -> lnrpc.SendCoinsRequest + 48, // 199: lnrpc.Lightning.ListUnspent:input_type -> lnrpc.ListUnspentRequest + 30, // 200: lnrpc.Lightning.SubscribeTransactions:input_type -> lnrpc.GetTransactionsRequest + 44, // 201: lnrpc.Lightning.SendMany:input_type -> lnrpc.SendManyRequest + 50, // 202: lnrpc.Lightning.NewAddress:input_type -> lnrpc.NewAddressRequest + 52, // 203: lnrpc.Lightning.SignMessage:input_type -> lnrpc.SignMessageRequest + 54, // 204: lnrpc.Lightning.VerifyMessage:input_type -> lnrpc.VerifyMessageRequest + 56, // 205: lnrpc.Lightning.ConnectPeer:input_type -> lnrpc.ConnectPeerRequest + 58, // 206: lnrpc.Lightning.DisconnectPeer:input_type -> lnrpc.DisconnectPeerRequest + 74, // 207: lnrpc.Lightning.ListPeers:input_type -> lnrpc.ListPeersRequest + 76, // 208: lnrpc.Lightning.SubscribePeerEvents:input_type -> lnrpc.PeerEventSubscription + 78, // 209: lnrpc.Lightning.GetInfo:input_type -> lnrpc.GetInfoRequest + 80, // 210: lnrpc.Lightning.GetDebugInfo:input_type -> lnrpc.GetDebugInfoRequest + 82, // 211: lnrpc.Lightning.GetRecoveryInfo:input_type -> lnrpc.GetRecoveryInfoRequest + 110, // 212: lnrpc.Lightning.PendingChannels:input_type -> lnrpc.PendingChannelsRequest + 63, // 213: lnrpc.Lightning.ListChannels:input_type -> lnrpc.ListChannelsRequest + 112, // 214: lnrpc.Lightning.SubscribeChannelEvents:input_type -> lnrpc.ChannelEventSubscription + 70, // 215: lnrpc.Lightning.ClosedChannels:input_type -> lnrpc.ClosedChannelsRequest + 97, // 216: lnrpc.Lightning.OpenChannelSync:input_type -> lnrpc.OpenChannelRequest + 97, // 217: lnrpc.Lightning.OpenChannel:input_type -> lnrpc.OpenChannelRequest + 94, // 218: lnrpc.Lightning.BatchOpenChannel:input_type -> lnrpc.BatchOpenChannelRequest + 107, // 219: lnrpc.Lightning.FundingStateStep:input_type -> lnrpc.FundingTransitionMsg + 37, // 220: lnrpc.Lightning.ChannelAcceptor:input_type -> lnrpc.ChannelAcceptResponse + 89, // 221: lnrpc.Lightning.CloseChannel:input_type -> lnrpc.CloseChannelRequest + 173, // 222: lnrpc.Lightning.AbandonChannel:input_type -> lnrpc.AbandonChannelRequest + 33, // 223: lnrpc.Lightning.SendPayment:input_type -> lnrpc.SendRequest + 33, // 224: lnrpc.Lightning.SendPaymentSync:input_type -> lnrpc.SendRequest + 35, // 225: lnrpc.Lightning.SendToRoute:input_type -> lnrpc.SendToRouteRequest + 35, // 226: lnrpc.Lightning.SendToRouteSync:input_type -> lnrpc.SendToRouteRequest + 156, // 227: lnrpc.Lightning.AddInvoice:input_type -> lnrpc.Invoice + 162, // 228: lnrpc.Lightning.ListInvoices:input_type -> lnrpc.ListInvoiceRequest + 161, // 229: lnrpc.Lightning.LookupInvoice:input_type -> lnrpc.PaymentHash + 164, // 230: lnrpc.Lightning.SubscribeInvoices:input_type -> lnrpc.InvoiceSubscription + 177, // 231: lnrpc.Lightning.DecodePayReq:input_type -> lnrpc.PayReqString + 167, // 232: lnrpc.Lightning.ListPayments:input_type -> lnrpc.ListPaymentsRequest + 169, // 233: lnrpc.Lightning.DeletePayment:input_type -> lnrpc.DeletePaymentRequest + 170, // 234: lnrpc.Lightning.DeleteAllPayments:input_type -> lnrpc.DeleteAllPaymentsRequest + 134, // 235: lnrpc.Lightning.DescribeGraph:input_type -> lnrpc.ChannelGraphRequest + 136, // 236: lnrpc.Lightning.GetNodeMetrics:input_type -> lnrpc.NodeMetricsRequest + 139, // 237: lnrpc.Lightning.GetChanInfo:input_type -> lnrpc.ChanInfoRequest + 128, // 238: lnrpc.Lightning.GetNodeInfo:input_type -> lnrpc.NodeInfoRequest + 120, // 239: lnrpc.Lightning.QueryRoutes:input_type -> lnrpc.QueryRoutesRequest + 140, // 240: lnrpc.Lightning.GetNetworkInfo:input_type -> lnrpc.NetworkInfoRequest + 142, // 241: lnrpc.Lightning.StopDaemon:input_type -> lnrpc.StopRequest + 144, // 242: lnrpc.Lightning.SubscribeChannelGraph:input_type -> lnrpc.GraphTopologySubscription + 175, // 243: lnrpc.Lightning.DebugLevel:input_type -> lnrpc.DebugLevelRequest + 180, // 244: lnrpc.Lightning.FeeReport:input_type -> lnrpc.FeeReportRequest + 184, // 245: lnrpc.Lightning.UpdateChannelPolicy:input_type -> lnrpc.PolicyUpdateRequest + 187, // 246: lnrpc.Lightning.ForwardingHistory:input_type -> lnrpc.ForwardingHistoryRequest + 190, // 247: lnrpc.Lightning.ExportChannelBackup:input_type -> lnrpc.ExportChannelBackupRequest + 193, // 248: lnrpc.Lightning.ExportAllChannelBackups:input_type -> lnrpc.ChanBackupExportRequest + 194, // 249: lnrpc.Lightning.VerifyChanBackup:input_type -> lnrpc.ChanBackupSnapshot + 196, // 250: lnrpc.Lightning.RestoreChannelBackups:input_type -> lnrpc.RestoreChanBackupRequest + 198, // 251: lnrpc.Lightning.SubscribeChannelBackups:input_type -> lnrpc.ChannelBackupSubscription + 201, // 252: lnrpc.Lightning.BakeMacaroon:input_type -> lnrpc.BakeMacaroonRequest + 203, // 253: lnrpc.Lightning.ListMacaroonIDs:input_type -> lnrpc.ListMacaroonIDsRequest + 205, // 254: lnrpc.Lightning.DeleteMacaroonID:input_type -> lnrpc.DeleteMacaroonIDRequest + 208, // 255: lnrpc.Lightning.ListPermissions:input_type -> lnrpc.ListPermissionsRequest + 215, // 256: lnrpc.Lightning.CheckMacaroonPermissions:input_type -> lnrpc.CheckMacPermRequest + 220, // 257: lnrpc.Lightning.RegisterRPCMiddleware:input_type -> lnrpc.RPCMiddlewareResponse + 25, // 258: lnrpc.Lightning.SendCustomMessage:input_type -> lnrpc.SendCustomMessageRequest + 23, // 259: lnrpc.Lightning.SubscribeCustomMessages:input_type -> lnrpc.SubscribeCustomMessagesRequest + 66, // 260: lnrpc.Lightning.ListAliases:input_type -> lnrpc.ListAliasesRequest + 21, // 261: lnrpc.Lightning.LookupHtlcResolution:input_type -> lnrpc.LookupHtlcResolutionRequest + 116, // 262: lnrpc.Lightning.WalletBalance:output_type -> lnrpc.WalletBalanceResponse + 119, // 263: lnrpc.Lightning.ChannelBalance:output_type -> lnrpc.ChannelBalanceResponse + 31, // 264: lnrpc.Lightning.GetTransactions:output_type -> lnrpc.TransactionDetails + 43, // 265: lnrpc.Lightning.EstimateFee:output_type -> lnrpc.EstimateFeeResponse + 47, // 266: lnrpc.Lightning.SendCoins:output_type -> lnrpc.SendCoinsResponse + 49, // 267: lnrpc.Lightning.ListUnspent:output_type -> lnrpc.ListUnspentResponse + 29, // 268: lnrpc.Lightning.SubscribeTransactions:output_type -> lnrpc.Transaction + 45, // 269: lnrpc.Lightning.SendMany:output_type -> lnrpc.SendManyResponse + 51, // 270: lnrpc.Lightning.NewAddress:output_type -> lnrpc.NewAddressResponse + 53, // 271: lnrpc.Lightning.SignMessage:output_type -> lnrpc.SignMessageResponse + 55, // 272: lnrpc.Lightning.VerifyMessage:output_type -> lnrpc.VerifyMessageResponse + 57, // 273: lnrpc.Lightning.ConnectPeer:output_type -> lnrpc.ConnectPeerResponse + 59, // 274: lnrpc.Lightning.DisconnectPeer:output_type -> lnrpc.DisconnectPeerResponse + 75, // 275: lnrpc.Lightning.ListPeers:output_type -> lnrpc.ListPeersResponse + 77, // 276: lnrpc.Lightning.SubscribePeerEvents:output_type -> lnrpc.PeerEvent + 79, // 277: lnrpc.Lightning.GetInfo:output_type -> lnrpc.GetInfoResponse + 81, // 278: lnrpc.Lightning.GetDebugInfo:output_type -> lnrpc.GetDebugInfoResponse + 83, // 279: lnrpc.Lightning.GetRecoveryInfo:output_type -> lnrpc.GetRecoveryInfoResponse + 111, // 280: lnrpc.Lightning.PendingChannels:output_type -> lnrpc.PendingChannelsResponse + 64, // 281: lnrpc.Lightning.ListChannels:output_type -> lnrpc.ListChannelsResponse + 113, // 282: lnrpc.Lightning.SubscribeChannelEvents:output_type -> lnrpc.ChannelEventUpdate + 71, // 283: lnrpc.Lightning.ClosedChannels:output_type -> lnrpc.ClosedChannelsResponse + 38, // 284: lnrpc.Lightning.OpenChannelSync:output_type -> lnrpc.ChannelPoint + 98, // 285: lnrpc.Lightning.OpenChannel:output_type -> lnrpc.OpenStatusUpdate + 96, // 286: lnrpc.Lightning.BatchOpenChannel:output_type -> lnrpc.BatchOpenChannelResponse + 108, // 287: lnrpc.Lightning.FundingStateStep:output_type -> lnrpc.FundingStateStepResp + 36, // 288: lnrpc.Lightning.ChannelAcceptor:output_type -> lnrpc.ChannelAcceptRequest + 90, // 289: lnrpc.Lightning.CloseChannel:output_type -> lnrpc.CloseStatusUpdate + 174, // 290: lnrpc.Lightning.AbandonChannel:output_type -> lnrpc.AbandonChannelResponse + 34, // 291: lnrpc.Lightning.SendPayment:output_type -> lnrpc.SendResponse + 34, // 292: lnrpc.Lightning.SendPaymentSync:output_type -> lnrpc.SendResponse + 34, // 293: lnrpc.Lightning.SendToRoute:output_type -> lnrpc.SendResponse + 34, // 294: lnrpc.Lightning.SendToRouteSync:output_type -> lnrpc.SendResponse + 160, // 295: lnrpc.Lightning.AddInvoice:output_type -> lnrpc.AddInvoiceResponse + 163, // 296: lnrpc.Lightning.ListInvoices:output_type -> lnrpc.ListInvoiceResponse + 156, // 297: lnrpc.Lightning.LookupInvoice:output_type -> lnrpc.Invoice + 156, // 298: lnrpc.Lightning.SubscribeInvoices:output_type -> lnrpc.Invoice + 178, // 299: lnrpc.Lightning.DecodePayReq:output_type -> lnrpc.PayReq + 168, // 300: lnrpc.Lightning.ListPayments:output_type -> lnrpc.ListPaymentsResponse + 171, // 301: lnrpc.Lightning.DeletePayment:output_type -> lnrpc.DeletePaymentResponse + 172, // 302: lnrpc.Lightning.DeleteAllPayments:output_type -> lnrpc.DeleteAllPaymentsResponse + 135, // 303: lnrpc.Lightning.DescribeGraph:output_type -> lnrpc.ChannelGraph + 137, // 304: lnrpc.Lightning.GetNodeMetrics:output_type -> lnrpc.NodeMetricsResponse + 133, // 305: lnrpc.Lightning.GetChanInfo:output_type -> lnrpc.ChannelEdge + 129, // 306: lnrpc.Lightning.GetNodeInfo:output_type -> lnrpc.NodeInfo + 123, // 307: lnrpc.Lightning.QueryRoutes:output_type -> lnrpc.QueryRoutesResponse + 141, // 308: lnrpc.Lightning.GetNetworkInfo:output_type -> lnrpc.NetworkInfo + 143, // 309: lnrpc.Lightning.StopDaemon:output_type -> lnrpc.StopResponse + 145, // 310: lnrpc.Lightning.SubscribeChannelGraph:output_type -> lnrpc.GraphTopologyUpdate + 176, // 311: lnrpc.Lightning.DebugLevel:output_type -> lnrpc.DebugLevelResponse + 182, // 312: lnrpc.Lightning.FeeReport:output_type -> lnrpc.FeeReportResponse + 186, // 313: lnrpc.Lightning.UpdateChannelPolicy:output_type -> lnrpc.PolicyUpdateResponse + 189, // 314: lnrpc.Lightning.ForwardingHistory:output_type -> lnrpc.ForwardingHistoryResponse + 191, // 315: lnrpc.Lightning.ExportChannelBackup:output_type -> lnrpc.ChannelBackup + 194, // 316: lnrpc.Lightning.ExportAllChannelBackups:output_type -> lnrpc.ChanBackupSnapshot + 199, // 317: lnrpc.Lightning.VerifyChanBackup:output_type -> lnrpc.VerifyChanBackupResponse + 197, // 318: lnrpc.Lightning.RestoreChannelBackups:output_type -> lnrpc.RestoreBackupResponse + 194, // 319: lnrpc.Lightning.SubscribeChannelBackups:output_type -> lnrpc.ChanBackupSnapshot + 202, // 320: lnrpc.Lightning.BakeMacaroon:output_type -> lnrpc.BakeMacaroonResponse + 204, // 321: lnrpc.Lightning.ListMacaroonIDs:output_type -> lnrpc.ListMacaroonIDsResponse + 206, // 322: lnrpc.Lightning.DeleteMacaroonID:output_type -> lnrpc.DeleteMacaroonIDResponse + 209, // 323: lnrpc.Lightning.ListPermissions:output_type -> lnrpc.ListPermissionsResponse + 216, // 324: lnrpc.Lightning.CheckMacaroonPermissions:output_type -> lnrpc.CheckMacPermResponse + 217, // 325: lnrpc.Lightning.RegisterRPCMiddleware:output_type -> lnrpc.RPCMiddlewareRequest + 26, // 326: lnrpc.Lightning.SendCustomMessage:output_type -> lnrpc.SendCustomMessageResponse + 24, // 327: lnrpc.Lightning.SubscribeCustomMessages:output_type -> lnrpc.CustomMessage + 67, // 328: lnrpc.Lightning.ListAliases:output_type -> lnrpc.ListAliasesResponse + 22, // 329: lnrpc.Lightning.LookupHtlcResolution:output_type -> lnrpc.LookupHtlcResolutionResponse + 262, // [262:330] is the sub-list for method output_type + 194, // [194:262] is the sub-list for method input_type + 194, // [194:194] is the sub-list for extension type_name + 194, // [194:194] is the sub-list for extension extendee + 0, // [0:194] is the sub-list for field type_name } func init() { file_lightning_proto_init() } @@ -24406,7 +24621,7 @@ func file_lightning_proto_init() { } } file_lightning_proto_msgTypes[191].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MacaroonId); i { + switch v := v.(*ChannelUpdate2); i { case 0: return &v.state case 1: @@ -24418,7 +24633,7 @@ func file_lightning_proto_init() { } } file_lightning_proto_msgTypes[192].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Op); i { + switch v := v.(*MacaroonId); i { case 0: return &v.state case 1: @@ -24430,7 +24645,7 @@ func file_lightning_proto_init() { } } file_lightning_proto_msgTypes[193].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CheckMacPermRequest); i { + switch v := v.(*Op); i { case 0: return &v.state case 1: @@ -24442,7 +24657,7 @@ func file_lightning_proto_init() { } } file_lightning_proto_msgTypes[194].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CheckMacPermResponse); i { + switch v := v.(*CheckMacPermRequest); i { case 0: return &v.state case 1: @@ -24454,7 +24669,7 @@ func file_lightning_proto_init() { } } file_lightning_proto_msgTypes[195].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RPCMiddlewareRequest); i { + switch v := v.(*CheckMacPermResponse); i { case 0: return &v.state case 1: @@ -24466,7 +24681,7 @@ func file_lightning_proto_init() { } } file_lightning_proto_msgTypes[196].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamAuth); i { + switch v := v.(*RPCMiddlewareRequest); i { case 0: return &v.state case 1: @@ -24478,7 +24693,7 @@ func file_lightning_proto_init() { } } file_lightning_proto_msgTypes[197].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RPCMessage); i { + switch v := v.(*StreamAuth); i { case 0: return &v.state case 1: @@ -24490,7 +24705,7 @@ func file_lightning_proto_init() { } } file_lightning_proto_msgTypes[198].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RPCMiddlewareResponse); i { + switch v := v.(*RPCMessage); i { case 0: return &v.state case 1: @@ -24502,7 +24717,7 @@ func file_lightning_proto_init() { } } file_lightning_proto_msgTypes[199].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MiddlewareRegistration); i { + switch v := v.(*RPCMiddlewareResponse); i { case 0: return &v.state case 1: @@ -24514,6 +24729,18 @@ func file_lightning_proto_init() { } } file_lightning_proto_msgTypes[200].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MiddlewareRegistration); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_lightning_proto_msgTypes[201].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*InterceptFeedback); i { case 0: return &v.state @@ -24525,7 +24752,7 @@ func file_lightning_proto_init() { return nil } } - file_lightning_proto_msgTypes[207].Exporter = func(v interface{}, i int) interface{} { + file_lightning_proto_msgTypes[208].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PendingChannelsResponse_PendingChannel); i { case 0: return &v.state @@ -24537,7 +24764,7 @@ func file_lightning_proto_init() { return nil } } - file_lightning_proto_msgTypes[208].Exporter = func(v interface{}, i int) interface{} { + file_lightning_proto_msgTypes[209].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PendingChannelsResponse_PendingOpenChannel); i { case 0: return &v.state @@ -24549,7 +24776,7 @@ func file_lightning_proto_init() { return nil } } - file_lightning_proto_msgTypes[209].Exporter = func(v interface{}, i int) interface{} { + file_lightning_proto_msgTypes[210].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PendingChannelsResponse_WaitingCloseChannel); i { case 0: return &v.state @@ -24561,7 +24788,7 @@ func file_lightning_proto_init() { return nil } } - file_lightning_proto_msgTypes[210].Exporter = func(v interface{}, i int) interface{} { + file_lightning_proto_msgTypes[211].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PendingChannelsResponse_Commitments); i { case 0: return &v.state @@ -24573,7 +24800,7 @@ func file_lightning_proto_init() { return nil } } - file_lightning_proto_msgTypes[211].Exporter = func(v interface{}, i int) interface{} { + file_lightning_proto_msgTypes[212].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PendingChannelsResponse_ClosedChannel); i { case 0: return &v.state @@ -24585,7 +24812,7 @@ func file_lightning_proto_init() { return nil } } - file_lightning_proto_msgTypes[212].Exporter = func(v interface{}, i int) interface{} { + file_lightning_proto_msgTypes[213].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PendingChannelsResponse_ForceClosedChannel); i { case 0: return &v.state @@ -24644,13 +24871,13 @@ func file_lightning_proto_init() { (*RestoreChanBackupRequest_ChanBackups)(nil), (*RestoreChanBackupRequest_MultiChanBackup)(nil), } - file_lightning_proto_msgTypes[195].OneofWrappers = []interface{}{ + file_lightning_proto_msgTypes[196].OneofWrappers = []interface{}{ (*RPCMiddlewareRequest_StreamAuth)(nil), (*RPCMiddlewareRequest_Request)(nil), (*RPCMiddlewareRequest_Response)(nil), (*RPCMiddlewareRequest_RegComplete)(nil), } - file_lightning_proto_msgTypes[198].OneofWrappers = []interface{}{ + file_lightning_proto_msgTypes[199].OneofWrappers = []interface{}{ (*RPCMiddlewareResponse_Register)(nil), (*RPCMiddlewareResponse_Feedback)(nil), } @@ -24660,7 +24887,7 @@ func file_lightning_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_lightning_proto_rawDesc, NumEnums: 21, - NumMessages: 228, + NumMessages: 229, NumExtensions: 0, NumServices: 1, }, diff --git a/lnrpc/lightning.proto b/lnrpc/lightning.proto index 6449305159..7da2c39e66 100644 --- a/lnrpc/lightning.proto +++ b/lnrpc/lightning.proto @@ -3423,6 +3423,8 @@ message RoutingPolicy { int32 inbound_fee_base_msat = 9; int32 inbound_fee_rate_milli_msat = 10; + + uint32 block_height = 11; } /* @@ -4868,6 +4870,9 @@ message Failure { // A failure type-dependent block height. uint32 height = 9; + + // An optional channel update 2 message. + ChannelUpdate2 channel_update_2 = 10; } message ChannelUpdate { @@ -4953,6 +4958,83 @@ message ChannelUpdate { bytes extra_opaque_data = 12; } +message ChannelUpdate2 { + /* + The signature that validates the announced data and proves the ownership + of node id. + */ + bytes signature = 1; + + /* + The target chain that this channel was opened within. This value + should be the genesis hash of the target chain. Along with the short + channel ID, this uniquely identifies the channel globally in a + blockchain. + */ + bytes chain_hash = 2; + + /* + The unique description of the funding transaction. + */ + uint64 chan_id = 3 [jstype = JS_STRING]; + + /* + A block height that allows ordering in the case of multiple announcements. + We should ignore the message if block_height is not greater than the + last-received. + */ + uint32 block_height = 4; + + /* + A bit field describing the disabled bits set on the update. + */ + uint32 disabled_flags = 5; + + /* + If true, this update is from node 2. Otherwise, it is from node 1. + */ + bool direction = 6; + + /* + The minimum number of blocks this node requires to be added to the expiry + of HTLCs. This is a security parameter determined by the node operator. + This value represents the required gap between the time locks of the + incoming and outgoing HTLC's set to this node. + */ + uint32 time_lock_delta = 7; + + /* + The base fee that must be used for incoming HTLC's to this particular + channel. This value will be tacked onto the required for a payment + independent of the size of the payment. + */ + uint32 base_fee = 8; + + /* + The fee rate that will be charged per millionth of a satoshi. + */ + uint32 fee_rate = 9; + + /* + The minimum HTLC value which will be accepted. + */ + uint64 htlc_minimum_msat = 10; + + /* + The maximum HTLC value which will be accepted. + */ + uint64 htlc_maximum_msat = 11; + + /* + The set of data that was appended to this message, some of which we may + not actually know how to iterate or parse. By holding onto this data, we + ensure that we're able to properly validate the set of signatures that + cover these new fields, and ensure we're able to make upgrades to the + network in a forwards compatible manner. + */ + bytes extra_opaque_data = 12; +} + message MacaroonId { bytes nonce = 1; bytes storageId = 2; diff --git a/lnrpc/lightning.swagger.json b/lnrpc/lightning.swagger.json index 5531d1ebb0..4828fca3aa 100644 --- a/lnrpc/lightning.swagger.json +++ b/lnrpc/lightning.swagger.json @@ -4454,6 +4454,70 @@ } } }, + "lnrpcChannelUpdate2": { + "type": "object", + "properties": { + "signature": { + "type": "string", + "format": "byte", + "description": "The signature that validates the announced data and proves the ownership\nof node id." + }, + "chain_hash": { + "type": "string", + "format": "byte", + "description": "The target chain that this channel was opened within. This value\nshould be the genesis hash of the target chain. Along with the short\nchannel ID, this uniquely identifies the channel globally in a\nblockchain." + }, + "chan_id": { + "type": "string", + "format": "uint64", + "description": "The unique description of the funding transaction." + }, + "block_height": { + "type": "integer", + "format": "int64", + "description": "A block height that allows ordering in the case of multiple announcements.\nWe should ignore the message if block_height is not greater than the\nlast-received." + }, + "disabled_flags": { + "type": "integer", + "format": "int64", + "description": "A bit field describing the disabled bits set on the update." + }, + "direction": { + "type": "boolean", + "description": "If true, this update is from node 2. Otherwise, it is from node 1." + }, + "time_lock_delta": { + "type": "integer", + "format": "int64", + "description": "The minimum number of blocks this node requires to be added to the expiry\nof HTLCs. This is a security parameter determined by the node operator.\nThis value represents the required gap between the time locks of the\nincoming and outgoing HTLC's set to this node." + }, + "base_fee": { + "type": "integer", + "format": "int64", + "description": "The base fee that must be used for incoming HTLC's to this particular\nchannel. This value will be tacked onto the required for a payment\nindependent of the size of the payment." + }, + "fee_rate": { + "type": "integer", + "format": "int64", + "description": "The fee rate that will be charged per millionth of a satoshi." + }, + "htlc_minimum_msat": { + "type": "string", + "format": "uint64", + "description": "The minimum HTLC value which will be accepted." + }, + "htlc_maximum_msat": { + "type": "string", + "format": "uint64", + "description": "The maximum HTLC value which will be accepted." + }, + "extra_opaque_data": { + "type": "string", + "format": "byte", + "description": "The set of data that was appended to this message, some of which we may\nnot actually know how to iterate or parse. By holding onto this data, we\nensure that we're able to properly validate the set of signatures that\ncover these new fields, and ensure we're able to make upgrades to the\nnetwork in a forwards compatible manner." + } + } + }, "lnrpcCheckMacPermRequest": { "type": "object", "properties": { @@ -4743,6 +4807,10 @@ "type": "integer", "format": "int64", "description": "A failure type-dependent block height." + }, + "channel_update_2": { + "$ref": "#/definitions/lnrpcChannelUpdate2", + "description": "An optional channel update 2 message." } } }, @@ -7043,6 +7111,10 @@ "inbound_fee_rate_milli_msat": { "type": "integer", "format": "int32" + }, + "block_height": { + "type": "integer", + "format": "int64" } } }, diff --git a/lnrpc/routerrpc/router.swagger.json b/lnrpc/routerrpc/router.swagger.json index b838f475d1..94c81c9870 100644 --- a/lnrpc/routerrpc/router.swagger.json +++ b/lnrpc/routerrpc/router.swagger.json @@ -787,6 +787,70 @@ } } }, + "lnrpcChannelUpdate2": { + "type": "object", + "properties": { + "signature": { + "type": "string", + "format": "byte", + "description": "The signature that validates the announced data and proves the ownership\nof node id." + }, + "chain_hash": { + "type": "string", + "format": "byte", + "description": "The target chain that this channel was opened within. This value\nshould be the genesis hash of the target chain. Along with the short\nchannel ID, this uniquely identifies the channel globally in a\nblockchain." + }, + "chan_id": { + "type": "string", + "format": "uint64", + "description": "The unique description of the funding transaction." + }, + "block_height": { + "type": "integer", + "format": "int64", + "description": "A block height that allows ordering in the case of multiple announcements.\nWe should ignore the message if block_height is not greater than the\nlast-received." + }, + "disabled_flags": { + "type": "integer", + "format": "int64", + "description": "A bit field describing the disabled bits set on the update." + }, + "direction": { + "type": "boolean", + "description": "If true, this update is from node 2. Otherwise, it is from node 1." + }, + "time_lock_delta": { + "type": "integer", + "format": "int64", + "description": "The minimum number of blocks this node requires to be added to the expiry\nof HTLCs. This is a security parameter determined by the node operator.\nThis value represents the required gap between the time locks of the\nincoming and outgoing HTLC's set to this node." + }, + "base_fee": { + "type": "integer", + "format": "int64", + "description": "The base fee that must be used for incoming HTLC's to this particular\nchannel. This value will be tacked onto the required for a payment\nindependent of the size of the payment." + }, + "fee_rate": { + "type": "integer", + "format": "int64", + "description": "The fee rate that will be charged per millionth of a satoshi." + }, + "htlc_minimum_msat": { + "type": "string", + "format": "uint64", + "description": "The minimum HTLC value which will be accepted." + }, + "htlc_maximum_msat": { + "type": "string", + "format": "uint64", + "description": "The maximum HTLC value which will be accepted." + }, + "extra_opaque_data": { + "type": "string", + "format": "byte", + "description": "The set of data that was appended to this message, some of which we may\nnot actually know how to iterate or parse. By holding onto this data, we\nensure that we're able to properly validate the set of signatures that\ncover these new fields, and ensure we're able to make upgrades to the\nnetwork in a forwards compatible manner." + } + } + }, "lnrpcFailure": { "type": "object", "properties": { @@ -827,6 +891,10 @@ "type": "integer", "format": "int64", "description": "A failure type-dependent block height." + }, + "channel_update_2": { + "$ref": "#/definitions/lnrpcChannelUpdate2", + "description": "An optional channel update 2 message." } } }, From 3d3c8e625a008efeb2e43d96f3dcc08331716fb6 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 21 Aug 2024 13:20:33 +0200 Subject: [PATCH 16/60] rpcserver: marshal new DB types for lnrpc --- rpcserver.go | 122 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 78 insertions(+), 44 deletions(-) diff --git a/rpcserver.go b/rpcserver.go index 2498f32ba1..c2510bcf46 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -6527,7 +6527,11 @@ func (r *rpcServer) DescribeGraph(ctx context.Context, return nil } - edge := marshalDBEdge(edgeInfo, c1, c2) + edge, err := marshalDBEdge(edgeInfo, c1, c2) + if err != nil { + return err + } + resp.Edges = append(resp.Edges, edge) return nil @@ -6589,70 +6593,93 @@ func extractInboundFeeSafe(data lnwire.ExtraOpaqueData) lnwire.Fee { return inboundFee } -func marshalDBEdge(edgeInfo *models.ChannelEdgeInfo1, - c1, c2 *models.ChannelEdgePolicy1) *lnrpc.ChannelEdge { +func marshalDBEdge(edgeInfo models.ChannelEdgeInfo, + c1, c2 models.ChannelEdgePolicy) (*lnrpc.ChannelEdge, error) { // Make sure the policies match the node they belong to. c1 should point // to the policy for NodeKey1, and c2 for NodeKey2. - if c1 != nil && c1.ChannelFlags&lnwire.ChanUpdateDirection == 1 || - c2 != nil && c2.ChannelFlags&lnwire.ChanUpdateDirection == 0 { - + if c1 != nil && !c1.IsNode1() || c2 != nil && c2.IsNode1() { c2, c1 = c1, c2 } - var lastUpdate int64 - if c1 != nil { - lastUpdate = c1.LastUpdate.Unix() - } - if c2 != nil && c2.LastUpdate.Unix() > lastUpdate { - lastUpdate = c2.LastUpdate.Unix() - } - - customRecords := marshalExtraOpaqueData(edgeInfo.ExtraOpaqueData) + var ( + node1 = edgeInfo.Node1Bytes() + node2 = edgeInfo.Node2Bytes() + ) edge := &lnrpc.ChannelEdge{ - ChannelId: edgeInfo.ChannelID, - ChanPoint: edgeInfo.ChannelPoint.String(), - // TODO(roasbeef): update should be on edge info itself - LastUpdate: uint32(lastUpdate), - Node1Pub: hex.EncodeToString(edgeInfo.NodeKey1Bytes[:]), - Node2Pub: hex.EncodeToString(edgeInfo.NodeKey2Bytes[:]), - Capacity: int64(edgeInfo.Capacity), - CustomRecords: customRecords, + ChannelId: edgeInfo.GetChanID(), + ChanPoint: edgeInfo.GetChanPoint().String(), + Node1Pub: hex.EncodeToString(node1[:]), + Node2Pub: hex.EncodeToString(node2[:]), + Capacity: int64(edgeInfo.GetCapacity()), } + var err error if c1 != nil { - edge.Node1Policy = marshalDBRoutingPolicy(c1) + edge.Node1Policy, err = marshalDBRoutingPolicy(c1) + if err != nil { + return nil, err + } } if c2 != nil { - edge.Node2Policy = marshalDBRoutingPolicy(c2) + edge.Node2Policy, err = marshalDBRoutingPolicy(c2) + if err != nil { + return nil, err + } + } + + switch info := edgeInfo.(type) { + case *models.ChannelEdgeInfo1: + customRecords := marshalExtraOpaqueData(info.ExtraOpaqueData) + edge.CustomRecords = customRecords + case *models.ChannelEdgeInfo2: + customRecords := marshalExtraOpaqueData(info.ExtraOpaqueData) + edge.CustomRecords = customRecords + default: + return nil, fmt.Errorf("unhandled implementation of "+ + "models.ChannelEdgeInfo: %T", edgeInfo) } - return edge + return edge, nil } -func marshalDBRoutingPolicy( - policy *models.ChannelEdgePolicy1) *lnrpc.RoutingPolicy { +func marshalDBRoutingPolicy(policy models.ChannelEdgePolicy) ( + *lnrpc.RoutingPolicy, error) { - disabled := policy.ChannelFlags&lnwire.ChanUpdateDisabled != 0 + fwd := policy.ForwardingPolicy() - customRecords := marshalExtraOpaqueData(policy.ExtraOpaqueData) - inboundFee := extractInboundFeeSafe(policy.ExtraOpaqueData) + routingPolicy := &lnrpc.RoutingPolicy{ + TimeLockDelta: uint32(fwd.TimeLockDelta), + MinHtlc: int64(fwd.MinHTLC), + MaxHtlcMsat: uint64(fwd.MaxHTLC), + FeeBaseMsat: int64(fwd.BaseFee), + FeeRateMilliMsat: int64(fwd.FeeRate), + Disabled: policy.IsDisabled(), + } + + switch p := policy.(type) { + case *models.ChannelEdgePolicy1: + customRecords := marshalExtraOpaqueData(p.ExtraOpaqueData) + inboundFee := extractInboundFeeSafe(p.ExtraOpaqueData) - return &lnrpc.RoutingPolicy{ - TimeLockDelta: uint32(policy.TimeLockDelta), - MinHtlc: int64(policy.MinHTLC), - MaxHtlcMsat: uint64(policy.MaxHTLC), - FeeBaseMsat: int64(policy.FeeBaseMSat), - FeeRateMilliMsat: int64(policy.FeeProportionalMillionths), - Disabled: disabled, - LastUpdate: uint32(policy.LastUpdate.Unix()), - CustomRecords: customRecords, + routingPolicy.CustomRecords = customRecords + routingPolicy.LastUpdate = uint32(p.LastUpdate.Unix()) + routingPolicy.InboundFeeBaseMsat = inboundFee.BaseFee + routingPolicy.InboundFeeRateMilliMsat = inboundFee.FeeRate - InboundFeeBaseMsat: inboundFee.BaseFee, - InboundFeeRateMilliMsat: inboundFee.FeeRate, + case *models.ChannelEdgePolicy2: + customRecords := marshalExtraOpaqueData(p.ExtraOpaqueData) + routingPolicy.CustomRecords = customRecords + routingPolicy.BlockHeight = p.BlockHeight.Val + + default: + return nil, fmt.Errorf("unhandled implementation of "+ + "models.ChannelEdgePolicy: %T", policy) } + + return routingPolicy, nil } // GetNodeMetrics returns all available node metrics calculated from the @@ -6754,7 +6781,10 @@ func (r *rpcServer) GetChanInfo(_ context.Context, // Convert the database's edge format into the network/RPC edge format // which couples the edge itself along with the directional node // routing policies of each node involved within the channel. - channelEdge := marshalDBEdge(edgeInfo, edge1, edge2) + channelEdge, err := marshalDBEdge(edgeInfo, edge1, edge2) + if err != nil { + return nil, err + } return channelEdge, nil } @@ -6811,7 +6841,11 @@ func (r *rpcServer) GetNodeInfo(ctx context.Context, // Convert the database's edge format into the // network/RPC edge format. - channelEdge := marshalDBEdge(edge, c1, c2) + channelEdge, err := marshalDBEdge(edge, c1, c2) + if err != nil { + return nil + } + channels = append(channels, channelEdge) } From bd8c65c15005eadeb07ff87b7f4bb3b2aa064dd3 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 21 Aug 2024 16:32:43 +0200 Subject: [PATCH 17/60] multi: use models.ChannelEdgeInfo throughout --- autopilot/graph.go | 4 +- channeldb/graph.go | 353 +++++++++++------------ channeldb/graph_cache.go | 4 +- channeldb/graph_cache_test.go | 2 +- channeldb/graph_test.go | 40 ++- channeldb/models/channel_edge_info.go | 2 +- discovery/chan_series.go | 12 +- discovery/gossiper.go | 314 ++++++++++++-------- discovery/gossiper_test.go | 60 ++-- graph/builder.go | 171 ++++------- graph/builder_test.go | 244 +++++++++++++++- graph/interfaces.go | 19 +- graph/notifications.go | 14 +- graph/validation_barrier.go | 15 +- lnrpc/invoicesrpc/addinvoice.go | 27 +- lnrpc/invoicesrpc/addinvoice_test.go | 2 +- netann/chan_status_manager.go | 3 +- netann/chan_status_manager_test.go | 23 +- netann/channel_announcement.go | 24 +- netann/channel_update.go | 38 ++- netann/interface.go | 2 +- peer/brontide.go | 13 +- routing/blindedpath/blinded_path.go | 2 +- routing/blindedpath/blinded_path_test.go | 6 +- routing/localchans/manager.go | 16 +- routing/localchans/manager_test.go | 2 +- rpcserver.go | 24 +- server.go | 11 +- 28 files changed, 898 insertions(+), 549 deletions(-) diff --git a/autopilot/graph.go b/autopilot/graph.go index 3939d38629..b3653a4898 100644 --- a/autopilot/graph.go +++ b/autopilot/graph.go @@ -90,7 +90,7 @@ func (d *dbNode) Addrs() []net.Addr { // NOTE: Part of the autopilot.Node interface. func (d *dbNode) ForEachChannel(cb func(ChannelEdge) error) error { return d.db.ForEachNodeChannelTx(d.tx, d.node.PubKeyBytes, - func(tx kvdb.RTx, ei *models.ChannelEdgeInfo1, ep, + func(tx kvdb.RTx, ei models.ChannelEdgeInfo, ep, _ *models.ChannelEdgePolicy1) error { // Skip channels for which no outgoing edge policy is @@ -116,7 +116,7 @@ func (d *dbNode) ForEachChannel(cb func(ChannelEdge) error) error { ChanID: lnwire.NewShortChanIDFromInt( ep.ChannelID, ), - Capacity: ei.Capacity, + Capacity: ei.GetCapacity(), Peer: &dbNode{ tx: tx, db: d.db, diff --git a/channeldb/graph.go b/channeldb/graph.go index f855fa2fc1..7306cbcdc2 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -239,7 +239,7 @@ func NewChannelGraph(db kvdb.Backend, rejectCacheSize, chanCacheSize int, return nil, err } - err = g.ForEachChannel(func(info *models.ChannelEdgeInfo1, + err = g.ForEachChannel(func(info models.ChannelEdgeInfo, policy1, policy2 *models.ChannelEdgePolicy1) error { g.graphCache.AddChannel(info, policy1, policy2) @@ -425,7 +425,7 @@ func (c *ChannelGraph) NewPathFindTx() (kvdb.RTx, error) { // NOTE: If an edge can't be found, or wasn't advertised, then a nil pointer // for that particular channel edge routing policy will be passed into the // callback. -func (c *ChannelGraph) ForEachChannel(cb func(*models.ChannelEdgeInfo1, +func (c *ChannelGraph) ForEachChannel(cb func(models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error { return c.db.View(func(tx kvdb.RTx) error { @@ -453,28 +453,21 @@ func (c *ChannelGraph) ForEachChannel(cb func(*models.ChannelEdgeInfo1, copy(chanID[:], k) edgeInfoReader := bytes.NewReader(edgeInfoBytes) - info, err := deserializeChanEdgeInfo(edgeInfoReader) + edgeInfo, err := deserializeChanEdgeInfo(edgeInfoReader) if err != nil { return err } policy1 := channelMap[channelMapKey{ - nodeKey: info.Node1Bytes(), + nodeKey: edgeInfo.Node1Bytes(), chanID: chanID, }] policy2 := channelMap[channelMapKey{ - nodeKey: info.Node2Bytes(), + nodeKey: edgeInfo.Node2Bytes(), chanID: chanID, }] - edgeInfo, ok := info.(*models.ChannelEdgeInfo1) - if !ok { - return fmt.Errorf("expected "+ - "*models.ChannelEdgeInfo1, got %T", - edgeInfo) - } - return cb(edgeInfo, policy1, policy2) }) }, func() {}) @@ -502,7 +495,7 @@ func (c *ChannelGraph) ForEachNodeDirectedChannel(tx kvdb.RTx, return err } - dbCallback := func(tx kvdb.RTx, e *models.ChannelEdgeInfo1, p1, + dbCallback := func(tx kvdb.RTx, e models.ChannelEdgeInfo, p1, p2 *models.ChannelEdgePolicy1) error { var cachedInPolicy *models.CachedEdgePolicy @@ -523,21 +516,22 @@ func (c *ChannelGraph) ForEachNodeDirectedChannel(tx kvdb.RTx, } directedChannel := &DirectedChannel{ - ChannelID: e.ChannelID, - IsNode1: node == e.NodeKey1Bytes, - OtherNode: e.NodeKey2Bytes, - Capacity: e.Capacity, + ChannelID: e.GetChanID(), + IsNode1: node == e.Node1Bytes(), + OtherNode: e.Node2Bytes(), + Capacity: e.GetCapacity(), OutPolicySet: p1 != nil, InPolicy: cachedInPolicy, InboundFee: inboundFee, } - if node == e.NodeKey2Bytes { - directedChannel.OtherNode = e.NodeKey1Bytes + if node == e.Node2Bytes() { + directedChannel.OtherNode = e.Node1Bytes() } return cb(directedChannel) } + return nodeTraversal(tx, node[:], c.db, dbCallback) } @@ -588,7 +582,7 @@ func (c *ChannelGraph) ForEachNodeCached(cb func(node route.Vertex, channels := make(map[uint64]*DirectedChannel) err := c.ForEachNodeChannelTx(tx, node.PubKeyBytes, - func(tx kvdb.RTx, e *models.ChannelEdgeInfo1, + func(tx kvdb.RTx, e models.ChannelEdgeInfo, p1 *models.ChannelEdgePolicy1, p2 *models.ChannelEdgePolicy1) error { @@ -613,21 +607,21 @@ func (c *ChannelGraph) ForEachNodeCached(cb func(node route.Vertex, } directedChannel := &DirectedChannel{ - ChannelID: e.ChannelID, + ChannelID: e.GetChanID(), IsNode1: node.PubKeyBytes == - e.NodeKey1Bytes, - OtherNode: e.NodeKey2Bytes, - Capacity: e.Capacity, + e.Node1Bytes(), + OtherNode: e.Node2Bytes(), + Capacity: e.GetCapacity(), OutPolicySet: p1 != nil, InPolicy: cachedInPolicy, } - if node.PubKeyBytes == e.NodeKey2Bytes { + if node.PubKeyBytes == e.Node2Bytes() { directedChannel.OtherNode = - e.NodeKey1Bytes + e.Node1Bytes() } - channels[e.ChannelID] = directedChannel + channels[e.GetChanID()] = directedChannel return nil }) @@ -1001,7 +995,7 @@ func (c *ChannelGraph) deleteLightningNode(nodes kvdb.RwBucket, // involved in creation of the channel, and the set of features that the channel // supports. The chanPoint and chanID are used to uniquely identify the edge // globally within the database. -func (c *ChannelGraph) AddChannelEdge(edge *models.ChannelEdgeInfo1, +func (c *ChannelGraph) AddChannelEdge(edge models.ChannelEdgeInfo, op ...batch.SchedulerOption) error { var alreadyExists bool @@ -1028,8 +1022,8 @@ func (c *ChannelGraph) AddChannelEdge(edge *models.ChannelEdgeInfo1, case alreadyExists: return ErrEdgeAlreadyExist default: - c.rejectCache.remove(edge.ChannelID) - c.chanCache.remove(edge.ChannelID) + c.rejectCache.remove(edge.GetChanID()) + c.chanCache.remove(edge.GetChanID()) return nil } }, @@ -1045,11 +1039,11 @@ func (c *ChannelGraph) AddChannelEdge(edge *models.ChannelEdgeInfo1, // addChannelEdge is the private form of AddChannelEdge that allows callers to // utilize an existing db transaction. func (c *ChannelGraph) addChannelEdge(tx kvdb.RwTx, - edge *models.ChannelEdgeInfo1) error { + edge models.ChannelEdgeInfo) error { // Construct the channel's primary key which is the 8-byte channel ID. var chanKey [8]byte - binary.BigEndian.PutUint64(chanKey[:], edge.ChannelID) + binary.BigEndian.PutUint64(chanKey[:], edge.GetChanID()) nodes, err := tx.CreateTopLevelBucket(nodeBucket) if err != nil { @@ -1078,37 +1072,42 @@ func (c *ChannelGraph) addChannelEdge(tx kvdb.RwTx, c.graphCache.AddChannel(edge, nil, nil) } + var ( + node1Bytes = edge.Node1Bytes() + node2Bytes = edge.Node2Bytes() + ) + // Before we insert the channel into the database, we'll ensure that // both nodes already exist in the channel graph. If either node // doesn't, then we'll insert a "shell" node that just includes its // public key, so subsequent validation and queries can work properly. - _, node1Err := fetchLightningNode(nodes, edge.NodeKey1Bytes[:]) + _, node1Err := fetchLightningNode(nodes, node1Bytes[:]) switch { case node1Err == ErrGraphNodeNotFound: node1Shell := LightningNode{ - PubKeyBytes: edge.NodeKey1Bytes, + PubKeyBytes: node1Bytes, HaveNodeAnnouncement: false, } err := addLightningNode(tx, &node1Shell) if err != nil { return fmt.Errorf("unable to create shell node "+ - "for: %x", edge.NodeKey1Bytes) + "for: %x", node1Bytes) } case node1Err != nil: return err } - _, node2Err := fetchLightningNode(nodes, edge.NodeKey2Bytes[:]) + _, node2Err := fetchLightningNode(nodes, node2Bytes[:]) switch { case node2Err == ErrGraphNodeNotFound: node2Shell := LightningNode{ - PubKeyBytes: edge.NodeKey2Bytes, + PubKeyBytes: node2Bytes, HaveNodeAnnouncement: false, } err := addLightningNode(tx, &node2Shell) if err != nil { return fmt.Errorf("unable to create shell node "+ - "for: %x", edge.NodeKey2Bytes) + "for: %x", node2Bytes) } case node2Err != nil: return err @@ -1124,11 +1123,11 @@ func (c *ChannelGraph) addChannelEdge(tx kvdb.RwTx, // Mark edge policies for both sides as unknown. This is to enable // efficient incoming channel lookup for a node. keys := []*[33]byte{ - &edge.NodeKey1Bytes, - &edge.NodeKey2Bytes, + &node1Bytes, + &node2Bytes, } for _, key := range keys { - err := putChanEdgePolicyUnknown(edges, edge.ChannelID, key[:]) + err := putChanEdgePolicyUnknown(edges, edge.GetChanID(), key[:]) if err != nil { return err } @@ -1137,7 +1136,8 @@ func (c *ChannelGraph) addChannelEdge(tx kvdb.RwTx, // Finally we add it to the channel index which maps channel points // (outpoints) to the shorter channel ID's. var b bytes.Buffer - if err := writeOutpoint(&b, &edge.ChannelPoint); err != nil { + chanPoint := edge.GetChanPoint() + if err := writeOutpoint(&b, &chanPoint); err != nil { return err } return chanIndex.Put(b.Bytes(), chanKey[:]) @@ -1257,10 +1257,10 @@ func (c *ChannelGraph) HasChannelEdge( // In order to maintain this constraints, we return an error in the scenario // that an edge info hasn't yet been created yet, but someone attempts to update // it. -func (c *ChannelGraph) UpdateChannelEdge(edge *models.ChannelEdgeInfo1) error { +func (c *ChannelGraph) UpdateChannelEdge(edge models.ChannelEdgeInfo) error { // Construct the channel's primary key which is the 8-byte channel ID. var chanKey [8]byte - binary.BigEndian.PutUint64(chanKey[:], edge.ChannelID) + binary.BigEndian.PutUint64(chanKey[:], edge.GetChanID()) return kvdb.Update(c.db, func(tx kvdb.RwTx) error { edges := tx.ReadWriteBucket(edgeBucket) @@ -1303,12 +1303,12 @@ const ( // the target block are returned if the function succeeds without error. func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint, blockHash *chainhash.Hash, blockHeight uint32) ( - []*models.ChannelEdgeInfo1, error) { + []models.ChannelEdgeInfo, error) { c.cacheMu.Lock() defer c.cacheMu.Unlock() - var chansClosed []*models.ChannelEdgeInfo1 + var chansClosed []models.ChannelEdgeInfo err := kvdb.Update(c.db, func(tx kvdb.RwTx) error { // First grab the edges bucket which houses the information @@ -1318,12 +1318,17 @@ func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint, return err } - // Next grab the two edge indexes which will also need to be updated. - edgeIndex, err := edges.CreateBucketIfNotExists(edgeIndexBucket) + // Next grab the two edge indexes which will also need to be + // updated. + edgeIndex, err := edges.CreateBucketIfNotExists( + edgeIndexBucket, + ) if err != nil { return err } - chanIndex, err := edges.CreateBucketIfNotExists(channelPointBucket) + chanIndex, err := edges.CreateBucketIfNotExists( + channelPointBucket, + ) if err != nil { return err } @@ -1344,7 +1349,8 @@ func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint, // if NOT if filter var opBytes bytes.Buffer - if err := writeOutpoint(&opBytes, chanPoint); err != nil { + err := writeOutpoint(&opBytes, chanPoint) + if err != nil { return err } @@ -1375,14 +1381,7 @@ func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint, return err } - info, ok := edgeInfo.(*models.ChannelEdgeInfo1) - if !ok { - return fmt.Errorf("expected "+ - "*models.ChannelEdgeInfo1, got %T", - edgeInfo) - } - - chansClosed = append(chansClosed, info) + chansClosed = append(chansClosed, edgeInfo) } metaBucket, err := tx.CreateTopLevelBucket(graphMetaBucket) @@ -1390,7 +1389,9 @@ func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint, return err } - pruneBucket, err := metaBucket.CreateBucketIfNotExists(pruneLogBucket) + pruneBucket, err := metaBucket.CreateBucketIfNotExists( + pruneLogBucket, + ) if err != nil { return err } @@ -1421,8 +1422,8 @@ func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint, } for _, channel := range chansClosed { - c.rejectCache.remove(channel.ChannelID) - c.chanCache.remove(channel.ChannelID) + c.rejectCache.remove(channel.GetChanID()) + c.chanCache.remove(channel.GetChanID()) } if c.graphCache != nil { @@ -1570,7 +1571,7 @@ func (c *ChannelGraph) pruneGraphNodes(nodes kvdb.RwBucket, // Channels that were removed from the graph resulting from the // disconnected block are returned. func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ( - []*models.ChannelEdgeInfo1, error) { + []models.ChannelEdgeInfo, error) { // Every channel having a ShortChannelID starting at 'height' // will no longer be confirmed. @@ -1592,7 +1593,7 @@ func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ( defer c.cacheMu.Unlock() // Keep track of the channels that are removed from the graph. - var removedChans []*models.ChannelEdgeInfo1 + var removedChans []models.ChannelEdgeInfo if err := kvdb.Update(c.db, func(tx kvdb.RwTx) error { edges, err := tx.CreateTopLevelBucket(edgeBucket) @@ -1631,15 +1632,7 @@ func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ( } keys = append(keys, k) - info, ok := edgeInfo.(*models.ChannelEdgeInfo1) - if !ok { - return fmt.Errorf("expected "+ - "*models.ChannelEdgeInfo1, got %T", - edgeInfo) - } - - keys = append(keys, k) - removedChans = append(removedChans, info) + removedChans = append(removedChans, edgeInfo) } for _, k := range keys { @@ -1694,8 +1687,8 @@ func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ( } for _, channel := range removedChans { - c.rejectCache.remove(channel.ChannelID) - c.chanCache.remove(channel.ChannelID) + c.rejectCache.remove(channel.GetChanID()) + c.chanCache.remove(channel.GetChanID()) } return removedChans, nil @@ -1903,7 +1896,7 @@ func (c *ChannelGraph) HighestChanID() (uint64, error) { // edge as well as each of the known advertised edge policies. type ChannelEdge struct { // Info contains all the static information describing the channel. - Info *models.ChannelEdgeInfo1 + Info models.ChannelEdgeInfo // Policy1 points to the "first" edge policy of the channel containing // the dynamic information required to properly route through the edge. @@ -1995,20 +1988,13 @@ func (c *ChannelGraph) ChanUpdatesInHorizon(startTime, } // First, we'll fetch the static edge information. - info, err := fetchChanEdgeInfo(edgeIndex, chanID) + edgeInfo, err := fetchChanEdgeInfo(edgeIndex, chanID) if err != nil { chanID := byteOrder.Uint64(chanID) return fmt.Errorf("unable to fetch info for "+ "edge with chan_id=%v: %v", chanID, err) } - edgeInfo, ok := info.(*models.ChannelEdgeInfo1) - if !ok { - return fmt.Errorf("expected "+ - "*models.ChannelEdgeInfo1, got %T", - edgeInfo) - } - // With the static information obtained, we'll now // fetch the dynamic policy info. edge1, edge2, err := fetchChanEdgePolicies( @@ -2021,16 +2007,17 @@ func (c *ChannelGraph) ChanUpdatesInHorizon(startTime, err) } - node1, err := fetchLightningNode( - nodes, edgeInfo.NodeKey1Bytes[:], + var ( + node1Bytes = edgeInfo.Node1Bytes() + node2Bytes = edgeInfo.Node2Bytes() ) + + node1, err := fetchLightningNode(nodes, node1Bytes[:]) if err != nil { return err } - node2, err := fetchLightningNode( - nodes, edgeInfo.NodeKey2Bytes[:], - ) + node2, err := fetchLightningNode(nodes, node2Bytes[:]) if err != nil { return err } @@ -2511,7 +2498,7 @@ func (c *ChannelGraph) fetchChanInfos(tx kvdb.RTx, chanIDs []uint64) ( // First, we'll fetch the static edge information. If // the edge is unknown, we will skip the edge and // continue gathering all known edges. - info, err := fetchChanEdgeInfo( + edgeInfo, err := fetchChanEdgeInfo( edgeIndex, cidBytes[:], ) switch { @@ -2530,23 +2517,17 @@ func (c *ChannelGraph) fetchChanInfos(tx kvdb.RTx, chanIDs []uint64) ( return err } - edgeInfo, ok := info.(*models.ChannelEdgeInfo1) - if !ok { - return fmt.Errorf("expected "+ - "*models.ChannelEdgeInfo1, got %T", - info) - } - - node1, err := fetchLightningNode( - nodes, edgeInfo.NodeKey1Bytes[:], + var ( + node1Bytes = edgeInfo.Node1Bytes() + node2Bytes = edgeInfo.Node2Bytes() ) + + node1, err := fetchLightningNode(nodes, node1Bytes[:]) if err != nil { return err } - node2, err := fetchLightningNode( - nodes, edgeInfo.NodeKey2Bytes[:], - ) + node2, err := fetchLightningNode(nodes, node2Bytes[:]) if err != nil { return err } @@ -2630,21 +2611,20 @@ func (c *ChannelGraph) delChannelEdgeUnsafe(edges, edgeIndex, chanIndex, zombieIndex kvdb.RwBucket, chanID []byte, isZombie, strictZombie bool) error { - info, err := fetchChanEdgeInfo(edgeIndex, chanID) + edgeInfo, err := fetchChanEdgeInfo(edgeIndex, chanID) if err != nil { return err } - edgeInfo, ok := info.(*models.ChannelEdgeInfo1) - if !ok { - return fmt.Errorf("expected *models.ChannelEdgeInfo1, got %T", - info) - } + var ( + node1Bytes = edgeInfo.Node1Bytes() + node2Bytes = edgeInfo.Node2Bytes() + chanPoint = edgeInfo.GetChanPoint() + ) if c.graphCache != nil { c.graphCache.RemoveChannel( - edgeInfo.NodeKey1Bytes, edgeInfo.NodeKey2Bytes, - edgeInfo.ChannelID, + node1Bytes, node2Bytes, edgeInfo.GetChanID(), ) } @@ -2669,13 +2649,13 @@ func (c *ChannelGraph) delChannelEdgeUnsafe(edges, edgeIndex, chanIndex, // With the latter half constructed, copy over the first public key to // delete the edge in this direction, then the second to delete the // edge in the opposite direction. - copy(edgeKey[:33], edgeInfo.NodeKey1Bytes[:]) + copy(edgeKey[:33], node1Bytes[:]) if edges.Get(edgeKey[:]) != nil { if err := edges.Delete(edgeKey[:]); err != nil { return err } } - copy(edgeKey[:33], edgeInfo.NodeKey2Bytes[:]) + copy(edgeKey[:33], node2Bytes[:]) if edges.Get(edgeKey[:]) != nil { if err := edges.Delete(edgeKey[:]); err != nil { return err @@ -2693,7 +2673,7 @@ func (c *ChannelGraph) delChannelEdgeUnsafe(edges, edgeIndex, chanIndex, return err } var b bytes.Buffer - if err := writeOutpoint(&b, &edgeInfo.ChannelPoint); err != nil { + if err := writeOutpoint(&b, &chanPoint); err != nil { return err } if err := chanIndex.Delete(b.Bytes()); err != nil { @@ -2707,9 +2687,15 @@ func (c *ChannelGraph) delChannelEdgeUnsafe(edges, edgeIndex, chanIndex, return nil } - nodeKey1, nodeKey2 := edgeInfo.NodeKey1Bytes, edgeInfo.NodeKey2Bytes + nodeKey1, nodeKey2 := node1Bytes, node2Bytes if strictZombie { - nodeKey1, nodeKey2 = makeZombiePubkeys(edgeInfo, edge1, edge2) + var err error + nodeKey1, nodeKey2, err = makeZombiePubkeys( + edgeInfo, edge1, edge2, + ) + if err != nil { + return err + } } return markEdgeZombie( @@ -2733,27 +2719,46 @@ func (c *ChannelGraph) delChannelEdgeUnsafe(edges, edgeIndex, chanIndex, // the channel. If the channel were to be marked zombie again, it would be // marked with the correct lagging channel since we received an update from only // one side. -func makeZombiePubkeys(info *models.ChannelEdgeInfo1, - e1, e2 *models.ChannelEdgePolicy1) ([33]byte, [33]byte) { +func makeZombiePubkeys(info models.ChannelEdgeInfo, + e1, e2 *models.ChannelEdgePolicy1) ([33]byte, [33]byte, error) { + + var ( + node1Bytes = info.Node1Bytes() + node2Bytes = info.Node2Bytes() + ) switch { // If we don't have either edge policy, we'll return both pubkeys so // that the channel can be resurrected by either party. case e1 == nil && e2 == nil: - return info.NodeKey1Bytes, info.NodeKey2Bytes - - // If we're missing edge1, or if both edges are present but edge1 is - // older, we'll return edge1's pubkey and a blank pubkey for edge2. This - // means that only an update from edge1 will be able to resurrect the - // channel. - case e1 == nil || (e2 != nil && e1.LastUpdate.Before(e2.LastUpdate)): - return info.NodeKey1Bytes, [33]byte{} - - // Otherwise, we're missing edge2 or edge2 is the older side, so we - // return a blank pubkey for edge1. In this case, only an update from - // edge2 can resurect the channel. + return node1Bytes, node2Bytes, nil + + // If we're only missing edge1, then we return edge1's pubkey and a + // blank pubkey for edge2 so that only an update from edge1 can + // resurrect the channel. + case e1 == nil: + return node1Bytes, [33]byte{}, nil + + // If we're only missing edge2, then we return edge2's pubkey and a + // blank pubkey for edge1 so that only an update from edge2 can + // resurrect the channel. + case e2 == nil: + return [33]byte{}, node2Bytes, nil + + // If we have both edges, then we check which one is older. We return + // the pubkey of the oldest update so that only an update from that + // edge can resurrect the channel. default: - return [33]byte{}, info.NodeKey2Bytes + e1Before, err := e1.Before(e2) + if err != nil { + return [33]byte{}, [33]byte{}, err + } + + if e1Before { + return node1Bytes, [33]byte{}, nil + } + + return [33]byte{}, node2Bytes, nil } } @@ -3050,15 +3055,16 @@ func (c *ChannelGraph) isPublic(tx kvdb.RTx, nodePub route.Vertex, nodeIsPublic := false errDone := errors.New("done") err := c.ForEachNodeChannelTx(tx, nodePub, func(tx kvdb.RTx, - info *models.ChannelEdgeInfo1, _ *models.ChannelEdgePolicy1, + info models.ChannelEdgeInfo, _ *models.ChannelEdgePolicy1, _ *models.ChannelEdgePolicy1) error { // If this edge doesn't extend to the source node, we'll // terminate our search as we can now conclude that the node is // publicly advertised within the graph due to the local node // knowing of the current edge. - if !bytes.Equal(info.NodeKey1Bytes[:], sourcePubKey) && - !bytes.Equal(info.NodeKey2Bytes[:], sourcePubKey) { + node1Bytes, node2Bytes := info.Node1Bytes(), info.Node2Bytes() + if !bytes.Equal(node1Bytes[:], sourcePubKey) && + !bytes.Equal(node2Bytes[:], sourcePubKey) { nodeIsPublic = true return errDone @@ -3066,7 +3072,7 @@ func (c *ChannelGraph) 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 { + if info.GetAuthProof() != nil { nodeIsPublic = true return errDone } @@ -3193,7 +3199,7 @@ func (n *graphCacheNode) Features() *lnwire.FeatureVector { // // Unknown policies are passed into the callback as nil values. func (n *graphCacheNode) ForEachChannel(tx kvdb.RTx, - cb func(kvdb.RTx, *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, + cb func(kvdb.RTx, models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error { return nodeTraversal(tx, n.pubKeyBytes[:], nil, cb) @@ -3254,7 +3260,7 @@ func (c *ChannelGraph) HasLightningNode(nodePub [33]byte) (time.Time, bool, erro // nodeTraversal is used to traverse all channels of a node given by its // public key and passes channel information into the specified callback. func nodeTraversal(tx kvdb.RTx, nodePub []byte, db kvdb.Backend, - cb func(kvdb.RTx, *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, + cb func(kvdb.RTx, models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error { traversal := func(tx kvdb.RTx) error { @@ -3289,18 +3295,11 @@ func nodeTraversal(tx kvdb.RTx, nodePub []byte, db kvdb.Backend, // the node at the other end of the channel and both // edge policies. chanID := nodeEdge[33:] - info, err := fetchChanEdgeInfo(edgeIndex, chanID) + edgeInfo, err := fetchChanEdgeInfo(edgeIndex, chanID) if err != nil { return err } - edgeInfo, ok := info.(*models.ChannelEdgeInfo1) - if !ok { - return fmt.Errorf("expected "+ - "*models.ChannelEdgeInfo1, got %T", - edgeInfo) - } - outgoingPolicy, err := fetchChanEdgePolicy( edges, chanID, nodePub, ) @@ -3308,9 +3307,19 @@ func nodeTraversal(tx kvdb.RTx, nodePub []byte, db kvdb.Backend, return err } - otherNode, err := edgeInfo.OtherNodeKeyBytes(nodePub) - if err != nil { - return err + var ( + otherNode [33]byte + node1Bytes = edgeInfo.Node1Bytes() + node2Bytes = edgeInfo.Node2Bytes() + ) + switch { + case bytes.Equal(node1Bytes[:], nodePub): + otherNode = node2Bytes + case bytes.Equal(node2Bytes[:], nodePub): + otherNode = node1Bytes + default: + return fmt.Errorf("node not participating in " + + "this channel") } incomingPolicy, err := fetchChanEdgePolicy( @@ -3350,7 +3359,7 @@ func nodeTraversal(tx kvdb.RTx, nodePub []byte, db kvdb.Backend, // // Unknown policies are passed into the callback as nil values. func (c *ChannelGraph) ForEachNodeChannel(nodePub route.Vertex, - cb func(kvdb.RTx, *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, + cb func(kvdb.RTx, models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error { return nodeTraversal(nil, nodePub[:], c.db, cb) @@ -3370,7 +3379,7 @@ func (c *ChannelGraph) ForEachNodeChannel(nodePub route.Vertex, // be nil and a fresh transaction will be created to execute the graph // traversal. func (c *ChannelGraph) ForEachNodeChannelTx(tx kvdb.RTx, - nodePub route.Vertex, cb func(kvdb.RTx, *models.ChannelEdgeInfo1, + nodePub route.Vertex, cb func(kvdb.RTx, models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error { @@ -3382,16 +3391,21 @@ func (c *ChannelGraph) ForEachNodeChannelTx(tx kvdb.RTx, // one of the nodes, and wishes to obtain the full LightningNode for the other // end of the channel. func (c *ChannelGraph) FetchOtherNode(tx kvdb.RTx, - channel *models.ChannelEdgeInfo1, thisNodeKey []byte) (*LightningNode, + edge models.ChannelEdgeInfo, thisNodeKey []byte) (*LightningNode, error) { + var ( + targetNodeBytes [33]byte + node1Bytes = edge.Node1Bytes() + node2Bytes = edge.Node2Bytes() + ) + // Ensure that the node passed in is actually a member of the channel. - var targetNodeBytes [33]byte switch { - case bytes.Equal(channel.NodeKey1Bytes[:], thisNodeKey): - targetNodeBytes = channel.NodeKey2Bytes - case bytes.Equal(channel.NodeKey2Bytes[:], thisNodeKey): - targetNodeBytes = channel.NodeKey1Bytes + case bytes.Equal(node1Bytes[:], thisNodeKey): + targetNodeBytes = node2Bytes + case bytes.Equal(node2Bytes[:], thisNodeKey): + targetNodeBytes = node1Bytes default: return nil, fmt.Errorf("node not participating in this channel") } @@ -3454,11 +3468,11 @@ func computeEdgePolicyKeys(info models.ChannelEdgeInfo) ([]byte, []byte) { // information for the channel itself is returned as well as two structs that // contain the routing policies for the channel in either direction. func (c *ChannelGraph) FetchChannelEdgesByOutpoint(op *wire.OutPoint) ( - *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, + models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { var ( - edgeInfo *models.ChannelEdgeInfo1 + edgeInfo models.ChannelEdgeInfo policy1 *models.ChannelEdgePolicy1 policy2 *models.ChannelEdgePolicy1 ) @@ -3500,20 +3514,12 @@ func (c *ChannelGraph) FetchChannelEdgesByOutpoint(op *wire.OutPoint) ( // If the channel is found to exists, then we'll first retrieve // the general information for the channel. - edge, err := fetchChanEdgeInfo(edgeIndex, chanID) + var err error + edgeInfo, err = fetchChanEdgeInfo(edgeIndex, chanID) if err != nil { return fmt.Errorf("%w: chanID=%x", err, chanID) } - info, ok := edge.(*models.ChannelEdgeInfo1) - if !ok { - return fmt.Errorf("expected "+ - "*models.ChannelEdgeInfo1, got %T", - edge) - } - - edgeInfo = info - // Once we have the information about the channels' parameters, // we'll fetch the routing policies for each for the directed // edges. @@ -3547,11 +3553,11 @@ func (c *ChannelGraph) FetchChannelEdgesByOutpoint(op *wire.OutPoint) ( // within the database. In this case, the ChannelEdgePolicy1's will be nil, and // the ChannelEdgeInfo1 will only include the public keys of each node. func (c *ChannelGraph) FetchChannelEdgesByID(chanID uint64) ( - *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, + models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { var ( - edgeInfo *models.ChannelEdgeInfo1 + edgeInfo models.ChannelEdgeInfo policy1 *models.ChannelEdgePolicy1 policy2 *models.ChannelEdgePolicy1 channelID [8]byte @@ -3580,7 +3586,8 @@ func (c *ChannelGraph) FetchChannelEdgesByID(chanID uint64) ( byteOrder.PutUint64(channelID[:], chanID) // Now, attempt to fetch edge. - edge, err := fetchChanEdgeInfo(edgeIndex, channelID[:]) + var err error + edgeInfo, err = fetchChanEdgeInfo(edgeIndex, channelID[:]) // If it doesn't exist, we'll quickly check our zombie index to // see if we've previously marked it as so. @@ -3616,14 +3623,6 @@ func (c *ChannelGraph) FetchChannelEdgesByID(chanID uint64) ( return err } - info, ok := edge.(*models.ChannelEdgeInfo1) - if !ok { - return fmt.Errorf("expected "+ - "*models.ChannelEdgeInfo1, got %T", edge) - } - - edgeInfo = info - // Then we'll attempt to fetch the accompanying policies of this // edge. e1, e2, err := fetchChanEdgePolicies( diff --git a/channeldb/graph_cache.go b/channeldb/graph_cache.go index 69bdee59b1..526d81e5f0 100644 --- a/channeldb/graph_cache.go +++ b/channeldb/graph_cache.go @@ -28,7 +28,7 @@ type GraphCacheNode interface { // error, then the iteration is halted with the error propagated back up // to the caller. ForEachChannel(kvdb.RTx, - func(kvdb.RTx, *models.ChannelEdgeInfo1, + func(kvdb.RTx, models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error } @@ -142,7 +142,7 @@ func (c *GraphCache) AddNode(tx kvdb.RTx, node GraphCacheNode) error { c.AddNodeFeatures(node) return node.ForEachChannel( - tx, func(tx kvdb.RTx, info *models.ChannelEdgeInfo1, + tx, func(tx kvdb.RTx, info models.ChannelEdgeInfo, outPolicy *models.ChannelEdgePolicy1, inPolicy *models.ChannelEdgePolicy1) error { diff --git a/channeldb/graph_cache_test.go b/channeldb/graph_cache_test.go index d6ece70717..89581022ed 100644 --- a/channeldb/graph_cache_test.go +++ b/channeldb/graph_cache_test.go @@ -42,7 +42,7 @@ func (n *node) Features() *lnwire.FeatureVector { } func (n *node) ForEachChannel(tx kvdb.RTx, - cb func(kvdb.RTx, *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, + cb func(kvdb.RTx, models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error { for idx := range n.edgeInfos { diff --git a/channeldb/graph_test.go b/channeldb/graph_test.go index a0c8dae25c..ba4567a580 100644 --- a/channeldb/graph_test.go +++ b/channeldb/graph_test.go @@ -509,10 +509,10 @@ func TestDisconnectBlockAtHeight(t *testing.T) { t.Fatalf("expected two edges to be removed from graph, "+ "only %d were", len(removed)) } - if removed[0].ChannelID != edgeInfo.ChannelID { + if removed[0].GetChanID() != edgeInfo.ChannelID { t.Fatalf("expected edge to be removed from graph") } - if removed[1].ChannelID != edgeInfo2.ChannelID { + if removed[1].GetChanID() != edgeInfo2.ChannelID { t.Fatalf("expected edge to be removed from graph") } @@ -556,7 +556,19 @@ func TestDisconnectBlockAtHeight(t *testing.T) { } } -func assertEdgeInfoEqual(t *testing.T, e1 *models.ChannelEdgeInfo1, +func assertEdgeInfoEqual(t *testing.T, e1, e2 models.ChannelEdgeInfo) { + switch edge1 := e1.(type) { + case *models.ChannelEdgeInfo1: + edge2, ok := e2.(*models.ChannelEdgeInfo1) + require.True(t, ok) + + assertEdgeInfo1Equal(t, edge1, edge2) + default: + t.Fatalf("unhandled ChannelEdgeInfo type: %T", e1) + } +} + +func assertEdgeInfo1Equal(t *testing.T, e1 *models.ChannelEdgeInfo1, e2 *models.ChannelEdgeInfo1) { if e1.ChannelID != e2.ChannelID { @@ -1042,11 +1054,11 @@ func TestGraphTraversal(t *testing.T) { // Iterate through all the known channels within the graph DB, once // again if the map is empty that indicates that all edges have // properly been reached. - err = graph.ForEachChannel(func(ei *models.ChannelEdgeInfo1, + err = graph.ForEachChannel(func(ei models.ChannelEdgeInfo, _ *models.ChannelEdgePolicy1, _ *models.ChannelEdgePolicy1) error { - delete(chanIndex, ei.ChannelID) + delete(chanIndex, ei.GetChanID()) return nil }) require.NoError(t, err) @@ -1057,7 +1069,7 @@ func TestGraphTraversal(t *testing.T) { numNodeChans := 0 firstNode, secondNode := nodeList[0], nodeList[1] err = graph.ForEachNodeChannel(firstNode.PubKeyBytes, - func(_ kvdb.RTx, _ *models.ChannelEdgeInfo1, outEdge, + func(_ kvdb.RTx, _ models.ChannelEdgeInfo, outEdge, inEdge *models.ChannelEdgePolicy1) error { // All channels between first and second node should @@ -1138,11 +1150,11 @@ func TestGraphTraversalCacheable(t *testing.T) { for _, node := range nodes { err := node.ForEachChannel( tx, func(tx kvdb.RTx, - info *models.ChannelEdgeInfo1, + info models.ChannelEdgeInfo, policy *models.ChannelEdgePolicy1, policy2 *models.ChannelEdgePolicy1) error { //nolint:lll - delete(chanIndex, info.ChannelID) + delete(chanIndex, info.GetChanID()) return nil }, ) @@ -1322,7 +1334,7 @@ func assertPruneTip(t *testing.T, graph *ChannelGraph, blockHash *chainhash.Hash func assertNumChans(t *testing.T, graph *ChannelGraph, n int) { numChans := 0 - if err := graph.ForEachChannel(func(*models.ChannelEdgeInfo1, + if err := graph.ForEachChannel(func(models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error { @@ -2749,7 +2761,7 @@ func TestIncompleteChannelPolicies(t *testing.T) { checkPolicies := func(node *LightningNode, expectedIn, expectedOut bool) { calls := 0 err := graph.ForEachNodeChannel(node.PubKeyBytes, - func(_ kvdb.RTx, _ *models.ChannelEdgeInfo1, outEdge, + func(_ kvdb.RTx, _ models.ChannelEdgeInfo, outEdge, inEdge *models.ChannelEdgePolicy1) error { if !expectedOut && outEdge != nil { @@ -3887,7 +3899,7 @@ func BenchmarkForEachChannel(b *testing.B) { err = graph.db.View(func(tx kvdb.RTx) error { for _, n := range nodes { cb := func(tx kvdb.RTx, - info *models.ChannelEdgeInfo1, + info models.ChannelEdgeInfo, policy *models.ChannelEdgePolicy1, policy2 *models.ChannelEdgePolicy1) error { //nolint:lll @@ -3896,7 +3908,7 @@ func BenchmarkForEachChannel(b *testing.B) { // compiler is going to optimize // this away, and we get bogus // results. - totalCapacity += info.Capacity + totalCapacity += info.GetCapacity() maxHTLCs += policy.MaxHTLC maxHTLCs += policy2.MaxHTLC @@ -3977,10 +3989,10 @@ func TestGraphCacheForEachNodeChannel(t *testing.T) { directedChan := getSingleChannel() require.NotNil(t, directedChan) - require.Equal(t, directedChan.InboundFee, lnwire.Fee{ + require.Equal(t, lnwire.Fee{ BaseFee: 10, FeeRate: 20, - }) + }, directedChan.InboundFee) // Set an invalid inbound fee and check that the edge is no longer // returned. diff --git a/channeldb/models/channel_edge_info.go b/channeldb/models/channel_edge_info.go index 4f01a3db68..82f722a292 100644 --- a/channeldb/models/channel_edge_info.go +++ b/channeldb/models/channel_edge_info.go @@ -346,7 +346,7 @@ func (c *ChannelEdgeInfo1) FundingScript() ([]byte, error) { } fundingScript, _, err := input.GenTaprootFundingScript( - pubKey1, pubKey2, 0, fn.None[chainhash.Hash](), + pubKey1, pubKey2, 0, c.TapscriptRoot, ) if err != nil { return nil, err diff --git a/discovery/chan_series.go b/discovery/chan_series.go index b7b9af9890..f37ba5fd81 100644 --- a/discovery/chan_series.go +++ b/discovery/chan_series.go @@ -120,13 +120,13 @@ func (c *ChanSeries) UpdatesInHorizon(chain chainhash.Hash, // If the channel hasn't been fully advertised yet, or is a // private channel, then we'll skip it as we can't construct a // full authentication proof if one is requested. - if channel.Info.AuthProof == nil { + if channel.Info.GetAuthProof() == nil { continue } chanAnn, edge1, edge2, err := netann.CreateChanAnnouncement( - channel.Info.AuthProof, channel.Info, channel.Policy1, - channel.Policy2, + channel.Info.GetAuthProof(), channel.Info, + channel.Policy1, channel.Policy2, ) if err != nil { return nil, err @@ -264,13 +264,13 @@ func (c *ChanSeries) FetchChanAnns(chain chainhash.Hash, // If the channel doesn't have an authentication proof, then we // won't send it over as it may not yet be finalized, or be a // non-advertised channel. - if channel.Info.AuthProof == nil { + if channel.Info.GetAuthProof() == nil { continue } chanAnn, edge1, edge2, err := netann.CreateChanAnnouncement( - channel.Info.AuthProof, channel.Info, channel.Policy1, - channel.Policy2, + channel.Info.GetAuthProof(), channel.Info, + channel.Policy1, channel.Policy2, ) if err != nil { return nil, err diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 27b3c52466..d5db46f68b 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -563,7 +563,7 @@ func New(cfg Config, selfKeyDesc *keychain.KeyDescriptor) *AuthenticatedGossiper // EdgeWithInfo contains the information that is required to update an edge. type EdgeWithInfo struct { // Info describes the channel. - Info *models.ChannelEdgeInfo1 + Info models.ChannelEdgeInfo // Edge describes the policy in one direction of the channel. Edge *models.ChannelEdgePolicy1 @@ -1627,7 +1627,7 @@ func (d *AuthenticatedGossiper) retransmitStaleAnns(now time.Time) error { // Iterate over all of our channels and check if any of them fall // within the prune interval or re-broadcast interval. type updateTuple struct { - info *models.ChannelEdgeInfo1 + info models.ChannelEdgeInfo edge *models.ChannelEdgePolicy1 } @@ -1637,7 +1637,7 @@ func (d *AuthenticatedGossiper) retransmitStaleAnns(now time.Time) error { ) err := d.cfg.Graph.ForAllOutgoingChannels(func( _ kvdb.RTx, - info *models.ChannelEdgeInfo1, + info models.ChannelEdgeInfo, edge *models.ChannelEdgePolicy1) error { // If there's no auth proof attached to this edge, it means @@ -1645,9 +1645,9 @@ func (d *AuthenticatedGossiper) retransmitStaleAnns(now time.Time) error { // the greater network, so avoid sending channel updates for // this channel to not leak its // existence. - if info.AuthProof == nil { + if info.GetAuthProof() == nil { log.Debugf("Skipping retransmission of channel "+ - "without AuthProof: %v", info.ChannelID) + "without AuthProof: %v", info.GetChanID()) return nil } @@ -1663,7 +1663,9 @@ func (d *AuthenticatedGossiper) retransmitStaleAnns(now time.Time) error { // We'll make sure we support the new max_htlc field if // not already present. edge.MessageFlags |= lnwire.ChanUpdateRequiredMaxHtlc - edge.MaxHTLC = lnwire.NewMSatFromSatoshis(info.Capacity) + edge.MaxHTLC = lnwire.NewMSatFromSatoshis( + info.GetCapacity(), + ) edgesToUpdate = append(edgesToUpdate, updateTuple{ info: info, @@ -1781,7 +1783,7 @@ func (d *AuthenticatedGossiper) processChanPolicyUpdate( // We'll avoid broadcasting any updates for private channels to // avoid directly giving away their existence. Instead, we'll // send the update directly to the remote party. - if edgeInfo.Info.AuthProof == nil { + if edgeInfo.Info.GetAuthProof() == nil { // If AuthProof is nil and an alias was found for this // ChannelID (meaning the option-scid-alias feature was // negotiated), we'll replace the ShortChannelID in the @@ -1789,7 +1791,7 @@ func (d *AuthenticatedGossiper) processChanPolicyUpdate( // updateChannel so that the alias isn't persisted to // the database. chanID := lnwire.NewChanIDFromOutPoint( - edgeInfo.Info.ChannelPoint, + edgeInfo.Info.GetChanPoint(), ) var defaultAlias lnwire.ShortChannelID @@ -1815,7 +1817,7 @@ func (d *AuthenticatedGossiper) processChanPolicyUpdate( } remotePubKey := remotePubFromChanInfo( - edgeInfo.Info, chanUpdate.ChannelFlags, + edgeInfo.Info, chanUpdate.IsNode1(), ) err := d.reliableSender.sendMessage( chanUpdate, remotePubKey, @@ -1844,18 +1846,14 @@ func (d *AuthenticatedGossiper) processChanPolicyUpdate( // remotePubFromChanInfo returns the public key of the remote peer given a // ChannelEdgeInfo1 that describe a channel we have with them. -func remotePubFromChanInfo(chanInfo *models.ChannelEdgeInfo1, - chanFlags lnwire.ChanUpdateChanFlags) [33]byte { +func remotePubFromChanInfo(chanInfo models.ChannelEdgeInfo, + isNode1 bool) [33]byte { - var remotePubKey [33]byte - switch { - case chanFlags&lnwire.ChanUpdateDirection == 0: - remotePubKey = chanInfo.NodeKey2Bytes - case chanFlags&lnwire.ChanUpdateDirection == 1: - remotePubKey = chanInfo.NodeKey1Bytes + if isNode1 { + return chanInfo.Node2Bytes() } - return remotePubKey + return chanInfo.Node1Bytes() } // processRejectedEdge examines a rejected edge to see if we can extract any @@ -1880,7 +1878,7 @@ func (d *AuthenticatedGossiper) processRejectedEdge( // The edge is in the graph, and has a proof attached, then we'll just // reject it as normal. - if chanInfo.AuthProof != nil { + if chanInfo.GetAuthProof() != nil { return nil, nil } @@ -2086,13 +2084,9 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement( // NOTE: only the NodeKey1Bytes and NodeKey2Bytes members of the // ChannelEdgeInfo1 should be inspected. func (d *AuthenticatedGossiper) processZombieUpdate( - chanInfo *models.ChannelEdgeInfo1, scid lnwire.ShortChannelID, + chanInfo models.ChannelEdgeInfo, scid lnwire.ShortChannelID, msg *lnwire.ChannelUpdate1) error { - // The least-significant bit in the flag on the channel update tells us - // which edge is being updated. - isNode1 := msg.ChannelFlags&lnwire.ChanUpdateDirection == 0 - // Since we've deemed the update as not stale above, before marking it // live, we'll make sure it has been signed by the correct party. If we // have both pubkeys, either party can resurrect the channel. If we've @@ -2100,9 +2094,9 @@ func (d *AuthenticatedGossiper) processZombieUpdate( // will only have the pubkey of the node with the oldest timestamp. var pubKey *btcec.PublicKey switch { - case isNode1 && chanInfo.NodeKey1Bytes != emptyPubkey: + case msg.IsNode1() && chanInfo.Node1Bytes() != emptyPubkey: pubKey, _ = chanInfo.NodeKey1() - case !isNode1 && chanInfo.NodeKey2Bytes != emptyPubkey: + case !msg.IsNode1() && chanInfo.Node2Bytes() != emptyPubkey: pubKey, _ = chanInfo.NodeKey2() } if pubKey == nil { @@ -2171,14 +2165,14 @@ func (d *AuthenticatedGossiper) isMsgStale(msg lnwire.Message) bool { } if err != nil { log.Debugf("Unable to retrieve channel=%v from graph: "+ - "%v", chanInfo.ChannelID, err) + "%v", chanInfo.GetChanID(), err) return false } // If the proof exists in the graph, then we have successfully // received the remote proof and assembled the full proof, so we // can safely delete the local proof from the database. - return chanInfo.AuthProof != nil + return chanInfo.GetAuthProof() != nil case *lnwire.ChannelUpdate1: _, p1, p2, err := d.cfg.Graph.GetChannelByID(msg.ShortChannelID) @@ -2223,16 +2217,21 @@ func (d *AuthenticatedGossiper) isMsgStale(msg lnwire.Message) bool { // updateChannel creates a new fully signed update for the channel, and updates // the underlying graph with the new state. -func (d *AuthenticatedGossiper) updateChannel(info *models.ChannelEdgeInfo1, +func (d *AuthenticatedGossiper) updateChannel(edgeInfo models.ChannelEdgeInfo, edge *models.ChannelEdgePolicy1) (*lnwire.ChannelAnnouncement1, *lnwire.ChannelUpdate1, error) { // Parse the unsigned edge into a channel update. - chanUpdate := netann.UnsignedChannelUpdateFromEdge(info, edge) + chanUpdate, err := netann.UnsignedChannelUpdateFromEdge( + edgeInfo.GetChainHash(), edge, + ) + if err != nil { + return nil, nil, err + } // We'll generate a new signature over a digest of the channel // announcement itself and update the timestamp to ensure it propagate. - err := netann.SignChannelUpdate( + err = netann.SignChannelUpdate( d.cfg.AnnSigner, d.selfKeyLoc, chanUpdate, netann.ChanUpdSetTimestamp, ) @@ -2248,7 +2247,7 @@ func (d *AuthenticatedGossiper) updateChannel(info *models.ChannelEdgeInfo1, // To ensure that our signature is valid, we'll verify it ourself // before committing it to the slice returned. err = netann.ValidateChannelUpdateAnn( - d.selfKey, info.Capacity, chanUpdate, + d.selfKey, edgeInfo.GetCapacity(), chanUpdate, ) if err != nil { return nil, nil, fmt.Errorf("generated invalid channel "+ @@ -2264,47 +2263,67 @@ func (d *AuthenticatedGossiper) updateChannel(info *models.ChannelEdgeInfo1, // be broadcast along side each other (if necessary), but only if we // have a full channel announcement for this channel. var chanAnn *lnwire.ChannelAnnouncement1 - if info.AuthProof != nil { - chanID := lnwire.NewShortChanIDFromInt(info.ChannelID) - chanAnn = &lnwire.ChannelAnnouncement1{ - ShortChannelID: chanID, - NodeID1: info.NodeKey1Bytes, - NodeID2: info.NodeKey2Bytes, - ChainHash: info.ChainHash, - BitcoinKey1: info.BitcoinKey1Bytes, - Features: lnwire.NewRawFeatureVector(), - BitcoinKey2: info.BitcoinKey2Bytes, - ExtraOpaqueData: info.ExtraOpaqueData, - } - chanAnn.NodeSig1, err = lnwire.NewSigFromECDSARawSignature( - info.AuthProof.NodeSig1Bytes, - ) - if err != nil { - return nil, nil, err - } - chanAnn.NodeSig2, err = lnwire.NewSigFromECDSARawSignature( - info.AuthProof.NodeSig2Bytes, - ) - if err != nil { - return nil, nil, err - } - chanAnn.BitcoinSig1, err = lnwire.NewSigFromECDSARawSignature( - info.AuthProof.BitcoinSig1Bytes, - ) - if err != nil { - return nil, nil, err - } - chanAnn.BitcoinSig2, err = lnwire.NewSigFromECDSARawSignature( - info.AuthProof.BitcoinSig2Bytes, - ) - if err != nil { - return nil, nil, err + if edgeInfo.GetAuthProof() != nil { + switch info := edgeInfo.(type) { + case *models.ChannelEdgeInfo1: + chanAnn, err = chanAnn1FromEdgeInfo1(info) + if err != nil { + return nil, nil, err + } + default: + return nil, nil, fmt.Errorf("unhandled "+ + "implementation of models.ChannelEdgeInfo: "+ + "%T", info) } } return chanAnn, chanUpdate, err } +func chanAnn1FromEdgeInfo1(info *models.ChannelEdgeInfo1) ( + *lnwire.ChannelAnnouncement1, error) { + + var err error + + chanID := lnwire.NewShortChanIDFromInt(info.ChannelID) + chanAnn := &lnwire.ChannelAnnouncement1{ + ShortChannelID: chanID, + NodeID1: info.NodeKey1Bytes, + NodeID2: info.NodeKey2Bytes, + ChainHash: info.ChainHash, + BitcoinKey1: info.BitcoinKey1Bytes, + Features: lnwire.NewRawFeatureVector(), + BitcoinKey2: info.BitcoinKey2Bytes, + ExtraOpaqueData: info.ExtraOpaqueData, + } + chanAnn.NodeSig1, err = lnwire.NewSigFromECDSARawSignature( + info.AuthProof.NodeSig1Bytes, + ) + if err != nil { + return nil, err + } + chanAnn.NodeSig2, err = lnwire.NewSigFromECDSARawSignature( + info.AuthProof.NodeSig2Bytes, + ) + if err != nil { + return nil, err + } + chanAnn.BitcoinSig1, err = lnwire.NewSigFromECDSARawSignature( + info.AuthProof.BitcoinSig1Bytes, + ) + if err != nil { + return nil, err + } + chanAnn.BitcoinSig2, err = lnwire.NewSigFromECDSARawSignature( + info.AuthProof.BitcoinSig2Bytes, + ) + if err != nil { + return nil, err + } + + return chanAnn, nil +} + // SyncManager returns the gossiper's SyncManager instance. func (d *AuthenticatedGossiper) SyncManager() *SyncManager { return d.syncMgr @@ -2579,38 +2598,19 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg, // With the proof validated (if necessary), we can now store it within // the database for our path finding and syncing needs. - var featureBuf bytes.Buffer - if err := ann.Features.Encode(&featureBuf); err != nil { - log.Errorf("unable to encode features: %v", err) + edge, err := d.buildEdgeInfo(ann, nMsg.optionalMsgFields) + if err != nil { + log.Errorf("unable to build edge info from announcement: %v", + err) nMsg.err <- err - return nil, false - } - edge := &models.ChannelEdgeInfo1{ - ChannelID: scid.ToUint64(), - ChainHash: ann.ChainHash, - NodeKey1Bytes: ann.NodeID1, - NodeKey2Bytes: ann.NodeID2, - BitcoinKey1Bytes: ann.BitcoinKey1, - BitcoinKey2Bytes: ann.BitcoinKey2, - AuthProof: proof, - Features: featureBuf.Bytes(), - ExtraOpaqueData: ann.ExtraOpaqueData, + return nil, false } - // If there were any optional message fields provided, we'll include - // them in its serialized disk representation now. - if nMsg.optionalMsgFields != nil { - if nMsg.optionalMsgFields.capacity != nil { - edge.Capacity = *nMsg.optionalMsgFields.capacity - } - if nMsg.optionalMsgFields.channelPoint != nil { - cp := *nMsg.optionalMsgFields.channelPoint - edge.ChannelPoint = cp - } - - // Optional tapscript root for custom channels. - edge.TapscriptRoot = nMsg.optionalMsgFields.tapscriptRoot + err = edge.SetAuthProof(proof) + if err != nil { + log.Errorf("unable to set auth proof: %v", err) + nMsg.err <- err } log.Debugf("Adding edge for short_chan_id: %v", scid.ToUint64()) @@ -3035,14 +3035,18 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, edgeToUpdate = e2 } + var chanID = chanInfo.GetChanID() + log.Debugf("Validating ChannelUpdate: channel=%v, from node=%x, has "+ - "edge=%v", chanInfo.ChannelID, pubKey.SerializeCompressed(), + "edge=%v", chanID, pubKey.SerializeCompressed(), edgeToUpdate != nil) // Validate the channel announcement with the expected public key and // channel capacity. In the case of an invalid channel update, we'll // return an error to the caller and exit early. - err = netann.ValidateChannelUpdateAnn(pubKey, chanInfo.Capacity, upd) + err = netann.ValidateChannelUpdateAnn( + pubKey, chanInfo.GetCapacity(), upd, + ) if err != nil { rErr := fmt.Errorf("unable to validate channel update "+ "announcement for short_chan_id=%v: %v", @@ -3081,7 +3085,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // multiple aliases for a channel and we may otherwise // rate-limit only a single alias of the channel, // instead of the whole channel. - baseScid := chanInfo.ChannelID + baseScid := chanID d.Lock() rls, ok := d.chanUpdateRateLimiter[baseScid] if !ok { @@ -3114,7 +3118,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // only be a difference if AuthProof == nil, this is fine. update := &models.ChannelEdgePolicy1{ SigBytes: upd.Signature.ToSignatureBytes(), - ChannelID: chanInfo.ChannelID, + ChannelID: chanID, LastUpdate: timestamp, MessageFlags: upd.MessageFlags, ChannelFlags: upd.ChannelFlags, @@ -3139,8 +3143,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // Since we know the stored SCID in the graph, we'll // cache that SCID. key := newRejectCacheKey( - chanInfo.ChannelID, - sourceToPub(nMsg.source), + chanID, sourceToPub(nMsg.source), ) _, _ = d.recentRejects.Put(key, &cachedReject{}) @@ -3157,7 +3160,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // to the greater network. However, our channel counter party will need // to be given the update, so we'll try sending the update directly to // the remote peer. - if !nMsg.isRemote && chanInfo.AuthProof == nil { + if !nMsg.isRemote && chanInfo.GetAuthProof() == nil { if nMsg.optionalMsgFields != nil { remoteAlias := nMsg.optionalMsgFields.remoteAlias if remoteAlias != nil { @@ -3188,9 +3191,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, } // Get our peer's public key. - remotePubKey := remotePubFromChanInfo( - chanInfo, upd.ChannelFlags, - ) + remotePubKey := remotePubFromChanInfo(chanInfo, upd.IsNode1()) log.Debugf("The message %v has no AuthProof, sending the "+ "update to remote peer %x", upd.MsgType(), remotePubKey) @@ -3214,7 +3215,9 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // authentication proof. We also won't broadcast the update if it // contains an alias because the network would reject this. var announcements []networkMsg - if chanInfo.AuthProof != nil && !d.cfg.IsAlias(upd.ShortChannelID) { + if chanInfo.GetAuthProof() != nil && + !d.cfg.IsAlias(upd.ShortChannelID) { + announcements = append(announcements, networkMsg{ peer: nMsg.peer, source: nMsg.source, @@ -3303,9 +3306,14 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, return nil, false } + var ( + node1Bytes = chanInfo.Node1Bytes() + node2Bytes = chanInfo.Node2Bytes() + ) + nodeID := nMsg.source.SerializeCompressed() - isFirstNode := bytes.Equal(nodeID, chanInfo.NodeKey1Bytes[:]) - isSecondNode := bytes.Equal(nodeID, chanInfo.NodeKey2Bytes[:]) + isFirstNode := bytes.Equal(nodeID, node1Bytes[:]) + isSecondNode := bytes.Equal(nodeID, node2Bytes[:]) // Ensure that channel that was retrieved belongs to the peer which // sent the proof announcement. @@ -3324,9 +3332,9 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, if !nMsg.isRemote { var remotePubKey [33]byte if isFirstNode { - remotePubKey = chanInfo.NodeKey2Bytes + remotePubKey = node2Bytes } else { - remotePubKey = chanInfo.NodeKey1Bytes + remotePubKey = node1Bytes } // Since the remote peer might not be online we'll call a @@ -3343,7 +3351,8 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, } // Check if we already have the full proof for this channel. - if chanInfo.AuthProof != nil { + authInfo := chanInfo.GetAuthProof() + if authInfo != nil { // If we already have the fully assembled proof, then the peer // sending us their proof has probably not received our local // proof yet. So be kind and send them the full proof. @@ -3362,7 +3371,7 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, ann.ChannelID, peerID) ca, _, _, err := netann.CreateChanAnnouncement( - chanInfo.AuthProof, chanInfo, e1, e2, + authInfo, chanInfo, e1, e2, ) if err != nil { log.Errorf("unable to gen ann: %v", @@ -3517,10 +3526,10 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, // it since the source gets skipped. This isn't necessary for channel // updates and announcement signatures since we send those directly to // our channel counterparty through the gossiper's reliable sender. - node1Ann, err := d.fetchNodeAnn(chanInfo.NodeKey1Bytes) + node1Ann, err := d.fetchNodeAnn(node1Bytes) if err != nil { log.Debugf("Unable to fetch node announcement for %x: %v", - chanInfo.NodeKey1Bytes, err) + node1Bytes, err) } else { if nodeKey1, err := chanInfo.NodeKey1(); err == nil { announcements = append(announcements, networkMsg{ @@ -3531,10 +3540,10 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, } } - node2Ann, err := d.fetchNodeAnn(chanInfo.NodeKey2Bytes) + node2Ann, err := d.fetchNodeAnn(node2Bytes) if err != nil { log.Debugf("Unable to fetch node announcement for %x: %v", - chanInfo.NodeKey2Bytes, err) + node2Bytes, err) } else { if nodeKey2, err := chanInfo.NodeKey2(); err == nil { announcements = append(announcements, networkMsg{ @@ -3581,3 +3590,76 @@ func (d *AuthenticatedGossiper) ShouldDisconnect(pubkey *btcec.PublicKey) ( return false, nil } + +// buildEdgeInfo builds constructs an appropriate models.ChannelEdgeInfo using +// the given lnwire.ChannelAnnouncement and some optional fields. +func (d *AuthenticatedGossiper) buildEdgeInfo(ann lnwire.ChannelAnnouncement, + opts *optionalMsgFields) (models.ChannelEdgeInfo, error) { + + switch a := ann.(type) { + case *lnwire.ChannelAnnouncement1: + var featureBuf bytes.Buffer + if err := a.Features.Encode(&featureBuf); err != nil { + return nil, err + } + edge := &models.ChannelEdgeInfo1{ + ChannelID: a.ShortChannelID.ToUint64(), + ChainHash: a.ChainHash, + NodeKey1Bytes: a.NodeID1, + NodeKey2Bytes: a.NodeID2, + BitcoinKey1Bytes: a.BitcoinKey1, + BitcoinKey2Bytes: a.BitcoinKey2, + Features: featureBuf.Bytes(), + ExtraOpaqueData: a.ExtraOpaqueData, + } + + // If there were any optional message fields provided, we'll + // include them in its serialized disk representation now. + if opts != nil { + if opts.capacity != nil { + edge.Capacity = *opts.capacity + } + if opts.channelPoint != nil { + cp := *opts.channelPoint + edge.ChannelPoint = cp + } + + // Optional tapscript root for custom channels. + edge.TapscriptRoot = opts.tapscriptRoot + } + + return edge, nil + + case *lnwire.ChannelAnnouncement2: + edge := &models.ChannelEdgeInfo2{ + ChannelAnnouncement2: *a, + ChannelPoint: wire.OutPoint{}, + } + + // If there were any optional message fields provided, we'll + // include them in its serialized disk representation now. + if opts != nil { + if opts.channelPoint != nil { + cp := *opts.channelPoint + edge.ChannelPoint = cp + } + } + + // If no bitcoin keys are provided, then there is no way to + // construct the pk script from the announcement, and so we + // instead need to fetch the pk script. + if a.BitcoinKey1.IsNone() && a.BitcoinKey2.IsNone() { + pkScript, err := d.fetchPKScript(&a.ShortChannelID.Val) + if err != nil { + return nil, err + } + + edge.FundingPkScript = pkScript + } + + return edge, nil + default: + return nil, fmt.Errorf("unhandled lnwire.ChannelAnnouncement "+ + "implementation: %T", a) + } +} diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index 3dc946193f..ac1dbf8c17 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -93,7 +93,7 @@ type mockGraphSource struct { mu sync.Mutex nodes []channeldb.LightningNode - infos map[uint64]models.ChannelEdgeInfo1 + infos map[uint64]models.ChannelEdgeInfo edges map[uint64][]models.ChannelEdgePolicy1 zombies map[uint64][][33]byte chansToReject map[uint64]struct{} @@ -103,7 +103,7 @@ type mockGraphSource struct { func newMockRouter(height uint32) *mockGraphSource { return &mockGraphSource{ bestHeight: height, - infos: make(map[uint64]models.ChannelEdgeInfo1), + infos: make(map[uint64]models.ChannelEdgeInfo), edges: make(map[uint64][]models.ChannelEdgePolicy1), zombies: make(map[uint64][][33]byte), chansToReject: make(map[uint64]struct{}), @@ -122,7 +122,7 @@ func (r *mockGraphSource) AddNode(node *channeldb.LightningNode, return nil } -func (r *mockGraphSource) AddEdge(info *models.ChannelEdgeInfo1, +func (r *mockGraphSource) AddEdge(info models.ChannelEdgeInfo, _ ...batch.SchedulerOption) error { r.mu.Lock() @@ -134,15 +134,16 @@ func (r *mockGraphSource) AddEdge(info *models.ChannelEdgeInfo1, ) } - if _, ok := r.infos[info.ChannelID]; ok { + if _, ok := r.infos[info.GetChanID()]; ok { return errors.New("info already exist") } - if _, ok := r.chansToReject[info.ChannelID]; ok { + if _, ok := r.chansToReject[info.GetChanID()]; ok { return errors.New("validation failed") } - r.infos[info.ChannelID] = *info + r.infos[info.GetChanID()] = info + return nil } @@ -196,8 +197,14 @@ func (r *mockGraphSource) AddProof(chanID lnwire.ShortChannelID, return errors.New("channel does not exist") } - info.AuthProof = proof - r.infos[chanIDInt] = info + infoCP := info.Copy() + + err := infoCP.SetAuthProof(proof) + if err != nil { + return err + } + + r.infos[chanIDInt] = infoCP return nil } @@ -207,7 +214,7 @@ func (r *mockGraphSource) ForEachNode(func(node *channeldb.LightningNode) error) } func (r *mockGraphSource) ForAllOutgoingChannels(cb func(tx kvdb.RTx, - i *models.ChannelEdgeInfo1, + i models.ChannelEdgeInfo, c *models.ChannelEdgePolicy1) error) error { r.mu.Lock() @@ -217,9 +224,9 @@ func (r *mockGraphSource) ForAllOutgoingChannels(cb func(tx kvdb.RTx, for _, info := range r.infos { info := info - edgeInfo := chans[info.ChannelID] - edgeInfo.Info = &info - chans[info.ChannelID] = edgeInfo + edgeInfo := chans[info.GetChanID()] + edgeInfo.Info = info + chans[info.GetChanID()] = edgeInfo } for _, edges := range r.edges { edges := edges @@ -239,7 +246,7 @@ func (r *mockGraphSource) ForAllOutgoingChannels(cb func(tx kvdb.RTx, } func (r *mockGraphSource) GetChannelByID(chanID lnwire.ShortChannelID) ( - *models.ChannelEdgeInfo1, + models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { @@ -262,7 +269,7 @@ func (r *mockGraphSource) GetChannelByID(chanID lnwire.ShortChannelID) ( edges := r.edges[chanID.ToUint64()] if len(edges) == 0 { - return &chanInfo, nil, nil, nil + return chanInfo, nil, nil, nil } var edge1 *models.ChannelEdgePolicy1 @@ -275,7 +282,7 @@ func (r *mockGraphSource) GetChannelByID(chanID lnwire.ShortChannelID) ( edge2 = &edges[1] } - return &chanInfo, edge1, edge2, nil + return chanInfo, edge1, edge2, nil } func (r *mockGraphSource) FetchLightningNode( @@ -307,10 +314,10 @@ func (r *mockGraphSource) IsStaleNode(nodePub route.Vertex, timestamp time.Time) // require the node to already have a channel in the graph to not be // considered stale. for _, info := range r.infos { - if info.NodeKey1Bytes == nodePub { + if info.Node1Bytes() == nodePub { return false } - if info.NodeKey2Bytes == nodePub { + if info.Node2Bytes() == nodePub { return false } } @@ -321,12 +328,15 @@ func (r *mockGraphSource) IsStaleNode(nodePub route.Vertex, timestamp time.Time) // the graph from the graph's source node's point of view. func (r *mockGraphSource) IsPublicNode(node route.Vertex) (bool, error) { for _, info := range r.infos { - if !bytes.Equal(node[:], info.NodeKey1Bytes[:]) && - !bytes.Equal(node[:], info.NodeKey2Bytes[:]) { + node1 := info.Node1Bytes() + node2 := info.Node2Bytes() + if !bytes.Equal(node[:], node1[:]) && + !bytes.Equal(node[:], node2[:]) { + continue } - if info.AuthProof != nil { + if info.GetAuthProof() != nil { return true, nil } } @@ -3483,7 +3493,7 @@ out: var edgesToUpdate []EdgeWithInfo err = ctx.router.ForAllOutgoingChannels(func( _ kvdb.RTx, - info *models.ChannelEdgeInfo1, + info models.ChannelEdgeInfo, edge *models.ChannelEdgePolicy1) error { edge.TimeLockDelta = uint16(newTimeLockDelta) @@ -3594,13 +3604,13 @@ func TestProcessChannelAnnouncementOptionalMsgFields(t *testing.T) { if err != nil { t.Fatalf("unable to get channel by id: %v", err) } - if edge.Capacity != capacity { + if edge.GetCapacity() != capacity { t.Fatalf("expected capacity %v, got %v", capacity, - edge.Capacity) + edge.GetCapacity()) } - if edge.ChannelPoint != channelPoint { + if edge.GetChanPoint() != channelPoint { t.Fatalf("expected channel point %v, got %v", - channelPoint, edge.ChannelPoint) + channelPoint, edge.GetChanPoint()) } } diff --git a/graph/builder.go b/graph/builder.go index af67e48946..cd5f27e8b9 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -1,7 +1,6 @@ package graph import ( - "bytes" "fmt" "runtime" "strings" @@ -11,15 +10,12 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" - "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/go-errors/errors" "github.com/lightningnetwork/lnd/batch" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb/models" - "github.com/lightningnetwork/lnd/fn" - "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwallet" @@ -541,19 +537,21 @@ func (b *Builder) pruneZombieChans() error { log.Infof("Examining channel graph for zombie channels") // A helper method to detect if the channel belongs to this node - isSelfChannelEdge := func(info *models.ChannelEdgeInfo1) bool { - return info.NodeKey1Bytes == b.cfg.SelfNode || - info.NodeKey2Bytes == b.cfg.SelfNode + isSelfChannelEdge := func(info models.ChannelEdgeInfo) bool { + return info.Node1Bytes() == b.cfg.SelfNode || + info.Node2Bytes() == b.cfg.SelfNode } // First, we'll collect all the channels which are eligible for garbage // collection due to being zombies. - filterPruneChans := func(info *models.ChannelEdgeInfo1, + filterPruneChans := func(info models.ChannelEdgeInfo, e1, e2 *models.ChannelEdgePolicy1) error { + chanID := info.GetChanID() + // Exit early in case this channel is already marked to be // pruned - _, markedToPrune := chansToPrune[info.ChannelID] + _, markedToPrune := chansToPrune[chanID] if markedToPrune { return nil } @@ -569,12 +567,12 @@ func (b *Builder) pruneZombieChans() error { if e1Zombie { log.Tracef("Node1 pubkey=%x of chan_id=%v is zombie", - info.NodeKey1Bytes, info.ChannelID) + info.Node1Bytes(), chanID) } if e2Zombie { log.Tracef("Node2 pubkey=%x of chan_id=%v is zombie", - info.NodeKey2Bytes, info.ChannelID) + info.Node2Bytes(), chanID) } // If either edge hasn't been updated for a period of @@ -585,10 +583,10 @@ func (b *Builder) pruneZombieChans() error { } log.Debugf("ChannelID(%v) is a zombie, collecting to prune", - info.ChannelID) + chanID) // TODO(roasbeef): add ability to delete single directional edge - chansToPrune[info.ChannelID] = struct{}{} + chansToPrune[chanID] = struct{}{} return nil } @@ -614,8 +612,8 @@ func (b *Builder) pruneZombieChans() error { // Ensuring we won't prune our own channel from the graph. for _, disabledEdge := range disabledEdges { if !isSelfChannelEdge(disabledEdge.Info) { - chansToPrune[disabledEdge.Info.ChannelID] = - struct{}{} + chanID := disabledEdge.Info.GetChanID() + chansToPrune[chanID] = struct{}{} } } } @@ -1089,72 +1087,6 @@ func (b *Builder) addZombieEdge(chanID uint64) error { return nil } -// makeFundingScript is used to make the funding script for both segwit v0 and -// segwit v1 (taproot) channels. -// -// TODO(roasbeef: export and use elsewhere? -func makeFundingScript(bitcoinKey1, bitcoinKey2 []byte, chanFeatures []byte, - tapscriptRoot fn.Option[chainhash.Hash]) ([]byte, error) { - - legacyFundingScript := func() ([]byte, error) { - witnessScript, err := input.GenMultiSigScript( - bitcoinKey1, bitcoinKey2, - ) - if err != nil { - return nil, err - } - pkScript, err := input.WitnessScriptHash(witnessScript) - if err != nil { - return nil, err - } - - return pkScript, nil - } - - if len(chanFeatures) == 0 { - return legacyFundingScript() - } - - // In order to make the correct funding script, we'll need to parse the - // chanFeatures bytes into a feature vector we can interact with. - rawFeatures := lnwire.NewRawFeatureVector() - err := rawFeatures.Decode(bytes.NewReader(chanFeatures)) - if err != nil { - return nil, fmt.Errorf("unable to parse chan feature "+ - "bits: %w", err) - } - - chanFeatureBits := lnwire.NewFeatureVector( - rawFeatures, lnwire.Features, - ) - if chanFeatureBits.HasFeature( - lnwire.SimpleTaprootChannelsOptionalStaging, - ) { - - pubKey1, err := btcec.ParsePubKey(bitcoinKey1) - if err != nil { - return nil, err - } - pubKey2, err := btcec.ParsePubKey(bitcoinKey2) - if err != nil { - return nil, err - } - - fundingScript, _, err := input.GenTaprootFundingScript( - pubKey1, pubKey2, 0, tapscriptRoot, - ) - if err != nil { - return nil, err - } - - // TODO(roasbeef): add tapscript root to gossip v1.5 - - return fundingScript, nil - } - - return legacyFundingScript() -} - // processUpdate processes a new relate authenticated channel/edge, node or // channel/edge update network update. If the update didn't affect the internal // state of the draft due to either being out of date, invalid, or redundant, @@ -1182,14 +1114,19 @@ func (b *Builder) processUpdate(msg interface{}, log.Tracef("Updated vertex data for node=%x", msg.PubKeyBytes) b.stats.incNumNodeUpdates() - case *models.ChannelEdgeInfo1: - log.Debugf("Received ChannelEdgeInfo1 for channel %v", - msg.ChannelID) + case models.ChannelEdgeInfo: + var ( + chanID = msg.GetChanID() + node1Bytes = msg.Node1Bytes() + node2Bytes = msg.Node2Bytes() + ) + + log.Debugf("Received ChannelEdgeInfo for channel %v", chanID) // Prior to processing the announcement we first check if we // already know of this channel, if so, then we can exit early. _, _, exists, isZombie, err := b.cfg.Graph.HasChannelEdge( - msg.ChannelID, + chanID, ) if err != nil && !errors.Is(err, channeldb.ErrGraphNoEdgesFound) { @@ -1199,11 +1136,11 @@ func (b *Builder) processUpdate(msg interface{}, } if isZombie { return NewErrf(ErrIgnored, "ignoring msg for zombie "+ - "chan_id=%v", msg.ChannelID) + "chan_id=%v", chanID) } if exists { return NewErrf(ErrIgnored, "ignoring msg for known "+ - "chan_id=%v", msg.ChannelID) + "chan_id=%v", chanID) } // If AssumeChannelValid is present, then we are unable to @@ -1213,7 +1150,7 @@ func (b *Builder) processUpdate(msg interface{}, // skip validation as it will not map to a legitimate tx. This // is not a DoS vector as only we can add an alias // ChannelAnnouncement from the gossiper. - scid := lnwire.NewShortChanIDFromInt(msg.ChannelID) + scid := lnwire.NewShortChanIDFromInt(chanID) if b.cfg.AssumeChannelValid || b.cfg.IsAlias(scid) { err := b.cfg.Graph.AddChannelEdge(msg, op...) if err != nil { @@ -1221,8 +1158,7 @@ func (b *Builder) processUpdate(msg interface{}, } log.Tracef("New channel discovered! Link "+ "connects %x and %x with ChannelID(%v)", - msg.NodeKey1Bytes, msg.NodeKey2Bytes, - msg.ChannelID) + node1Bytes, node2Bytes, chanID) b.stats.incNumEdgesDiscovered() break @@ -1231,7 +1167,7 @@ func (b *Builder) processUpdate(msg interface{}, // Before we can add the channel to the channel graph, we need // to obtain the full funding outpoint that's encoded within // the channel ID. - channelID := lnwire.NewShortChanIDFromInt(msg.ChannelID) + channelID := lnwire.NewShortChanIDFromInt(chanID) fundingTx, err := lnwallet.FetchFundingTxWrapper( b.cfg.Chain, &channelID, b.quit, ) @@ -1258,7 +1194,7 @@ func (b *Builder) processUpdate(msg interface{}, // zombie so we don't continue to request it. // We use the "zero key" for both node pubkeys // so this edge can't be resurrected. - zErr := b.addZombieEdge(msg.ChannelID) + zErr := b.addZombieEdge(chanID) if zErr != nil { return zErr } @@ -1273,10 +1209,7 @@ func (b *Builder) processUpdate(msg interface{}, // Recreate witness output to be sure that declared in channel // edge bitcoin keys and channel value corresponds to the // reality. - fundingPkScript, err := makeFundingScript( - msg.BitcoinKey1Bytes[:], msg.BitcoinKey2Bytes[:], - msg.Features, msg.TapscriptRoot, - ) + fundingPkScript, err := msg.FundingScript() if err != nil { return err } @@ -1297,7 +1230,7 @@ func (b *Builder) processUpdate(msg interface{}, if err != nil { // Mark the edge as a zombie so we won't try to // re-validate it on start up. - if err := b.addZombieEdge(msg.ChannelID); err != nil { + if err := b.addZombieEdge(chanID); err != nil { return err } @@ -1314,7 +1247,7 @@ func (b *Builder) processUpdate(msg interface{}, ) if err != nil { if errors.Is(err, btcwallet.ErrOutputSpent) { - zErr := b.addZombieEdge(msg.ChannelID) + zErr := b.addZombieEdge(chanID) if zErr != nil { return zErr } @@ -1322,22 +1255,37 @@ func (b *Builder) processUpdate(msg interface{}, return NewErrf(ErrChannelSpent, "unable to fetch utxo "+ "for chan_id=%v, chan_point=%v: %v", - msg.ChannelID, fundingPoint, err) + chanID, fundingPoint, err) } // TODO(roasbeef): this is a hack, needs to be removed // after commitment fees are dynamic. - msg.Capacity = btcutil.Amount(chanUtxo.Value) - msg.ChannelPoint = *fundingPoint + switch m := msg.(type) { + case *models.ChannelEdgeInfo1: + m.Capacity = btcutil.Amount(chanUtxo.Value) + m.ChannelPoint = *fundingPoint + case *models.ChannelEdgeInfo2: + m.ChannelPoint = *fundingPoint + + // We only store the funding script if the bitcoin keys + // were not provided in the announcement. + if m.BitcoinKey1.IsNone() && m.BitcoinKey2.IsNone() { + m.FundingPkScript = fundingPkScript + } + default: + return errors.Errorf("unhandled implementation of "+ + "ChannelEdgeInfo: %T", msg) + } + if err := b.cfg.Graph.AddChannelEdge(msg, op...); err != nil { return errors.Errorf("unable to add edge: %v", err) } log.Debugf("New channel discovered! Link "+ "connects %x and %x with ChannelPoint(%v): "+ - "chan_id=%v, capacity=%v", - msg.NodeKey1Bytes, msg.NodeKey2Bytes, - fundingPoint, msg.ChannelID, msg.Capacity) + "chan_id=%v, capacity=%v", node1Bytes, node2Bytes, + fundingPoint, chanID, msg.GetCapacity()) + b.stats.incNumEdgesDiscovered() // As a new edge has been added to the channel graph, we'll @@ -1485,7 +1433,7 @@ func (b *Builder) ApplyChannelUpdate(msg *lnwire.ChannelUpdate1) bool { return false } - err = netann.ValidateChannelUpdateAnn(pubKey, ch.Capacity, msg) + err = netann.ValidateChannelUpdateAnn(pubKey, ch.GetCapacity(), msg) if err != nil { log.Errorf("Unable to validate channel update: %v", err) return false @@ -1544,7 +1492,7 @@ func (b *Builder) AddNode(node *channeldb.LightningNode, // in construction of payment path. // // NOTE: This method is part of the ChannelGraphSource interface. -func (b *Builder) AddEdge(edge *models.ChannelEdgeInfo1, +func (b *Builder) AddEdge(edge models.ChannelEdgeInfo, op ...batch.SchedulerOption) error { rMsg := &routingMsg{ @@ -1611,7 +1559,7 @@ func (b *Builder) SyncedHeight() uint32 { // // NOTE: This method is part of the ChannelGraphSource interface. func (b *Builder) GetChannelByID(chanID lnwire.ShortChannelID) ( - *models.ChannelEdgeInfo1, + models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { @@ -1646,10 +1594,10 @@ func (b *Builder) ForEachNode( // // NOTE: This method is part of the ChannelGraphSource interface. func (b *Builder) ForAllOutgoingChannels(cb func(kvdb.RTx, - *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1) error) error { + models.ChannelEdgeInfo, *models.ChannelEdgePolicy1) error) error { return b.cfg.Graph.ForEachNodeChannel(b.cfg.SelfNode, - func(tx kvdb.RTx, c *models.ChannelEdgeInfo1, + func(tx kvdb.RTx, c models.ChannelEdgeInfo, e *models.ChannelEdgePolicy1, _ *models.ChannelEdgePolicy1) error { @@ -1675,7 +1623,10 @@ func (b *Builder) AddProof(chanID lnwire.ShortChannelID, return err } - info.AuthProof = proof + err = info.SetAuthProof(proof) + if err != nil { + return err + } return b.cfg.Graph.UpdateChannelEdge(info) } diff --git a/graph/builder_test.go b/graph/builder_test.go index 8e7cca9e0b..280fcb2406 100644 --- a/graph/builder_test.go +++ b/graph/builder_test.go @@ -22,10 +22,13 @@ import ( "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb/models" + "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/htlcswitch" + "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/routing/route" + "github.com/lightningnetwork/lnd/tlv" "github.com/stretchr/testify/require" ) @@ -80,7 +83,7 @@ func TestAddProof(t *testing.T) { info, _, _, err := ctx.builder.GetChannelByID(*chanID) require.NoError(t, err, "unable to get channel") - require.NotNil(t, info.AuthProof) + require.NotNil(t, info.GetAuthProof()) } // TestIgnoreNodeAnnouncement tests that adding a node to the router that is @@ -2071,3 +2074,242 @@ func (m *mockLink) EligibleToForward() bool { func (m *mockLink) MayAddOutgoingHtlc(_ lnwire.MilliSatoshi) error { return m.mayAddOutgoingErr } + +// TestChanAnn2Validation tests that the router can validate the various forms +// of ChannelEdgeInfo2. +func TestChanAnn2Validation(t *testing.T) { + t.Parallel() + + var rootHash [32]byte + _, err := rand.Read(rootHash[:]) + require.NoError(t, err) + + tests := []struct { + name string + makeFundingTx func(t *testing.T, ctx *testCtx) (*wire.MsgTx, + *lnwire.ShortChannelID, []byte) + buildEdgeInfo func(node1 *channeldb.LightningNode, + node2 *channeldb.LightningNode, + chanID *lnwire.ShortChannelID, + pkScript []byte) models.ChannelEdgeInfo + }{ + { + // This test covers the case where two bitcoin keys + // are provided in the channel announcement but no + // merkle root hash is provided. In this case, the + // on-chain funding script is expected to be equal to + // the MuSig2 combination of the two bitcoin keys along + // with a BIP86 tweak. + name: "bitcoin keys with bip 86 tweak", + makeFundingTx: func(t *testing.T, ctx *testCtx) ( + *wire.MsgTx, *lnwire.ShortChannelID, []byte) { + + pkScript, tx, err := input.GenTaprootFundingScript( //nolint:lll + bitcoinKey1, bitcoinKey2, int64(100), + fn.None[chainhash.Hash](), + ) + require.NoError(t, err) + + fundingTx := wire.NewMsgTx(2) + + _, chanID := addFundingTxToChain( + ctx, fundingTx, tx, 0, + ) + + return fundingTx, chanID, pkScript + }, + buildEdgeInfo: func(node1 *channeldb.LightningNode, + node2 *channeldb.LightningNode, + chanID *lnwire.ShortChannelID, + _ []byte) models.ChannelEdgeInfo { + + ann := lnwire.ChannelAnnouncement2{} + ann.ShortChannelID.Val = *chanID + ann.NodeID1.Val = node1.PubKeyBytes + ann.NodeID2.Val = node2.PubKeyBytes + + btc1 := tlv.ZeroRecordT[ + tlv.TlvType12, [33]byte, + ]() + copy( + btc1.Val[:], + bitcoinKey1.SerializeCompressed(), + ) + ann.BitcoinKey1 = tlv.SomeRecordT(btc1) + + btc2 := tlv.ZeroRecordT[ + tlv.TlvType14, [33]byte, + ]() + copy( + btc2.Val[:], + bitcoinKey2.SerializeCompressed(), + ) + ann.BitcoinKey2 = tlv.SomeRecordT(btc2) + + return &models.ChannelEdgeInfo2{ + ChannelAnnouncement2: ann, + } + }, + }, + { + // In this case, no bitcoin keys and no merkle root hash + // is included in the channel announcement. In this + // case, it is not necessary to validate that the + // on-chain pk script is equal to anything particular + // since the signature check in discovery would have + // checked that the announcement signature is also + // signed by the output key found on-chain. + name: "no bitcoin keys", + makeFundingTx: func(t *testing.T, ctx *testCtx) ( + *wire.MsgTx, *lnwire.ShortChannelID, []byte) { + + pkScript, tx, err := input.GenTaprootFundingScript( //nolint:lll + bitcoinKey1, bitcoinKey2, int64(100), + fn.None[chainhash.Hash](), + ) + require.NoError(t, err) + + fundingTx := wire.NewMsgTx(2) + + _, chanID := addFundingTxToChain( + ctx, fundingTx, tx, 0, + ) + + return fundingTx, chanID, pkScript + }, + buildEdgeInfo: func(node1 *channeldb.LightningNode, + node2 *channeldb.LightningNode, + chanID *lnwire.ShortChannelID, + pkScript []byte) models.ChannelEdgeInfo { + + ann := lnwire.ChannelAnnouncement2{} + ann.ShortChannelID.Val = *chanID + ann.NodeID1.Val = node1.PubKeyBytes + ann.NodeID2.Val = node2.PubKeyBytes + + return &models.ChannelEdgeInfo2{ + ChannelAnnouncement2: ann, + FundingPkScript: pkScript, + } + }, + }, + { + // This test covers the case where bitcoin keys are + // included in the channel announcement along with a + // merkle root hash. + name: "bitcoin keys with non-bip86 tweak", + makeFundingTx: func(t *testing.T, ctx *testCtx) ( + *wire.MsgTx, *lnwire.ShortChannelID, []byte) { + + fundingTx := wire.NewMsgTx(2) + + pkScript, tx, err := input.GenTaprootFundingScript( //nolint:lll + bitcoinKey1, bitcoinKey2, int64(100), + fn.Some[chainhash.Hash](rootHash), + ) + require.NoError(t, err) + + _, chanID := addFundingTxToChain( + ctx, fundingTx, tx, 0, + ) + + return fundingTx, chanID, pkScript + }, + buildEdgeInfo: func(node1 *channeldb.LightningNode, + node2 *channeldb.LightningNode, + chanID *lnwire.ShortChannelID, + pkScript []byte) models.ChannelEdgeInfo { + + ann := lnwire.ChannelAnnouncement2{} + ann.ShortChannelID.Val = *chanID + ann.NodeID1.Val = node1.PubKeyBytes + ann.NodeID2.Val = node2.PubKeyBytes + + btc1 := tlv.ZeroRecordT[ + tlv.TlvType12, [33]byte, + ]() + copy( + btc1.Val[:], + bitcoinKey1.SerializeCompressed(), + ) + ann.BitcoinKey1 = tlv.SomeRecordT(btc1) + + btc2 := tlv.ZeroRecordT[ + tlv.TlvType14, [33]byte, + ]() + copy( + btc2.Val[:], + bitcoinKey2.SerializeCompressed(), + ) + ann.BitcoinKey2 = tlv.SomeRecordT(btc2) + + merkleRootHash := tlv.ZeroRecordT[ + tlv.TlvType16, [32]byte, + ]() + merkleRootHash.Val = rootHash + ann.MerkleRootHash = tlv.SomeRecordT( + merkleRootHash, + ) + + return &models.ChannelEdgeInfo2{ + ChannelAnnouncement2: ann, + } + }, + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + ctx := createTestCtxSingleNode(t, 0) + + // Create two new nodes within the network that the + // channel will connect. + node1 := createTestNode(t) + node2 := createTestNode(t) + + fundingTx, chanID, pkScript := test.makeFundingTx( + t, ctx, + ) + + fundingBlock := &wire.MsgBlock{ + Transactions: []*wire.MsgTx{fundingTx}, + } + ctx.chain.addBlock( + fundingBlock, chanID.BlockHeight, + chanID.BlockHeight, + ) + + edge := test.buildEdgeInfo( + node1, node2, chanID, pkScript, + ) + + require.NoError(t, ctx.builder.AddEdge(edge)) + }) + } +} + +func addFundingTxToChain(ctx *testCtx, fundingTx *wire.MsgTx, + fundingOutput *wire.TxOut, fundingHeight uint32) (*wire.OutPoint, + *lnwire.ShortChannelID) { + + fundingTx.TxOut = append(fundingTx.TxOut, fundingOutput) + chanUtxo := wire.OutPoint{ + Hash: fundingTx.TxHash(), + Index: 0, + } + + // With the utxo constructed, we'll mark it as closed. + ctx.chain.addUtxo(chanUtxo, fundingOutput) + + // Our fake channel will be "confirmed" at height 101. + chanID := &lnwire.ShortChannelID{ + BlockHeight: fundingHeight, + TxIndex: 0, + TxPosition: 0, + } + + return &chanUtxo, chanID +} diff --git a/graph/interfaces.go b/graph/interfaces.go index 43ed155aa3..fdce2cbfe7 100644 --- a/graph/interfaces.go +++ b/graph/interfaces.go @@ -29,7 +29,7 @@ type ChannelGraphSource interface { // AddEdge is used to add edge/channel to the topology of the router, // after all information about channel will be gathered this // edge/channel might be used in construction of payment path. - AddEdge(edge *models.ChannelEdgeInfo1, + AddEdge(edge models.ChannelEdgeInfo, op ...batch.SchedulerOption) error // AddProof updates the channel edge info with proof which is needed to @@ -70,7 +70,7 @@ type ChannelGraphSource interface { // emanating from the "source" node which is the center of the // star-graph. ForAllOutgoingChannels(cb func(tx kvdb.RTx, - c *models.ChannelEdgeInfo1, + c models.ChannelEdgeInfo, e *models.ChannelEdgePolicy1) error) error // CurrentBlockHeight returns the block height from POV of the router @@ -79,7 +79,7 @@ type ChannelGraphSource interface { // GetChannelByID return the channel by the channel id. GetChannelByID(chanID lnwire.ShortChannelID) ( - *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, + models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) // FetchLightningNode attempts to look up a target node by its identity @@ -110,7 +110,7 @@ type DB interface { // slice of channels that have been closed by the target block are // returned if the function succeeds without error. PruneGraph(spentOutputs []*wire.OutPoint, blockHash *chainhash.Hash, - blockHeight uint32) ([]*models.ChannelEdgeInfo1, error) + blockHeight uint32) ([]models.ChannelEdgeInfo, error) // ChannelView returns the verifiable edge information for each active // channel within the known channel graph. The set of UTXO's (along with @@ -169,8 +169,7 @@ type DB interface { // set to the last prune height valid for the remaining chain. // Channels that were removed from the graph resulting from the // disconnected block are returned. - DisconnectBlockAtHeight(height uint32) ([]*models.ChannelEdgeInfo1, - error) + DisconnectBlockAtHeight(height uint32) ([]models.ChannelEdgeInfo, error) // HasChannelEdge returns true if the database knows of a channel edge // with the passed channel ID, and false otherwise. If an edge with that @@ -191,7 +190,7 @@ type DB interface { // zombie within the database. In this case, the ChannelEdgePolicy1's // will be nil, and the ChannelEdgeInfo1 will only include the public // keys of each node. - FetchChannelEdgesByID(chanID uint64) (*models.ChannelEdgeInfo1, + FetchChannelEdgesByID(chanID uint64) (models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) // AddLightningNode adds a vertex/node to the graph database. If the @@ -210,7 +209,7 @@ type DB interface { // and the set of features that the channel supports. The chanPoint and // chanID are used to uniquely identify the edge globally within the // database. - AddChannelEdge(edge *models.ChannelEdgeInfo1, + AddChannelEdge(edge models.ChannelEdgeInfo, op ...batch.SchedulerOption) error // MarkEdgeZombie attempts to mark a channel identified by its channel @@ -258,7 +257,7 @@ type DB interface { // // Unknown policies are passed into the callback as nil values. ForEachNodeChannel(nodePub route.Vertex, cb func(kvdb.RTx, - *models.ChannelEdgeInfo1, + models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error @@ -267,7 +266,7 @@ type DB interface { // created. In order to maintain this constraints, we return an error in // the scenario that an edge info hasn't yet been created yet, but // someone attempts to update it. - UpdateChannelEdge(edge *models.ChannelEdgeInfo1) error + UpdateChannelEdge(edge models.ChannelEdgeInfo) error // IsPublicNode is a helper method that determines whether the node with // the given public key is seen as a public node in the graph from the diff --git a/graph/notifications.go b/graph/notifications.go index 47e1c62f6c..8ba68dd64d 100644 --- a/graph/notifications.go +++ b/graph/notifications.go @@ -211,15 +211,15 @@ type ClosedChanSummary struct { // createCloseSummaries takes in a slice of channels closed at the target block // height and creates a slice of summaries which of each channel closure. func createCloseSummaries(blockHeight uint32, - closedChans ...*models.ChannelEdgeInfo1) []*ClosedChanSummary { + closedChans ...models.ChannelEdgeInfo) []*ClosedChanSummary { closeSummaries := make([]*ClosedChanSummary, len(closedChans)) for i, closedChan := range closedChans { closeSummaries[i] = &ClosedChanSummary{ - ChanID: closedChan.ChannelID, - Capacity: closedChan.Capacity, + ChanID: closedChan.GetChanID(), + Capacity: closedChan.GetCapacity(), ClosedHeight: blockHeight, - ChanPoint: closedChan.ChannelPoint, + ChanPoint: closedChan.GetChanPoint(), } } @@ -337,7 +337,7 @@ func addToTopologyChange(graph DB, update *TopologyChange, // We ignore initial channel announcements as we'll only send out // updates once the individual edges themselves have been updated. - case *models.ChannelEdgeInfo1: + case models.ChannelEdgeInfo: return nil // Any new ChannelUpdateAnnouncements will generate a corresponding @@ -372,9 +372,9 @@ func addToTopologyChange(graph DB, update *TopologyChange, edgeUpdate := &ChannelEdgeUpdate{ ChanID: m.ChannelID, - ChanPoint: edgeInfo.ChannelPoint, + ChanPoint: edgeInfo.GetChanPoint(), TimeLockDelta: m.TimeLockDelta, - Capacity: edgeInfo.Capacity, + Capacity: edgeInfo.GetCapacity(), MinHTLC: m.MinHTLC, MaxHTLC: m.MaxHTLC, BaseFee: m.FeeBaseMSat, diff --git a/graph/validation_barrier.go b/graph/validation_barrier.go index 2bfc85f061..7750617322 100644 --- a/graph/validation_barrier.go +++ b/graph/validation_barrier.go @@ -126,9 +126,8 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) { v.nodeAnnDependencies[route.Vertex(msg.NodeID1)] = signals v.nodeAnnDependencies[route.Vertex(msg.NodeID2)] = signals } - case *models.ChannelEdgeInfo1: - - shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID) + case models.ChannelEdgeInfo: + shortID := lnwire.NewShortChanIDFromInt(msg.GetChanID()) if _, ok := v.chanAnnFinSignal[shortID]; !ok { signals := &validationSignals{ allow: make(chan struct{}), @@ -138,8 +137,8 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) { v.chanAnnFinSignal[shortID] = signals v.chanEdgeDependencies[shortID] = signals - v.nodeAnnDependencies[route.Vertex(msg.NodeKey1Bytes)] = signals - v.nodeAnnDependencies[route.Vertex(msg.NodeKey2Bytes)] = signals + v.nodeAnnDependencies[msg.Node1Bytes()] = signals + v.nodeAnnDependencies[msg.Node2Bytes()] = signals } // These other types don't have any dependants, so no further @@ -218,7 +217,7 @@ func (v *ValidationBarrier) WaitForDependants(job interface{}) error { // return directly. case *lnwire.AnnounceSignatures1: // TODO(roasbeef): need to wait on chan ann? - case *models.ChannelEdgeInfo1: + case models.ChannelEdgeInfo: case *lnwire.ChannelAnnouncement1: } @@ -264,8 +263,8 @@ func (v *ValidationBarrier) SignalDependants(job interface{}, allow bool) { // If we've just finished executing a ChannelAnnouncement, then we'll // close out the signal, and remove the signal from the map of active // ones. This will allow/deny any dependent jobs to continue execution. - case *models.ChannelEdgeInfo1: - shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID) + case models.ChannelEdgeInfo: + shortID := lnwire.NewShortChanIDFromInt(msg.GetChanID()) finSignals, ok := v.chanAnnFinSignal[shortID] if ok { if allow { diff --git a/lnrpc/invoicesrpc/addinvoice.go b/lnrpc/invoicesrpc/addinvoice.go index 6d7ea341a1..690e938b84 100644 --- a/lnrpc/invoicesrpc/addinvoice.go +++ b/lnrpc/invoicesrpc/addinvoice.go @@ -624,7 +624,7 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig, // chanCanBeHopHint returns true if the target channel is eligible to be a hop // hint. func chanCanBeHopHint(channel *HopHintInfo, cfg *SelectHopHintsCfg) ( - *models.ChannelEdgePolicy1, bool) { + models.ChannelEdgePolicy, bool) { // Since we're only interested in our private channels, we'll skip // public ones. @@ -679,8 +679,11 @@ func chanCanBeHopHint(channel *HopHintInfo, cfg *SelectHopHintsCfg) ( // Now, we'll need to determine which is the correct policy for HTLCs // being sent from the remote node. - var remotePolicy *models.ChannelEdgePolicy1 - if bytes.Equal(remotePub[:], info.NodeKey1Bytes[:]) { + var ( + remotePolicy models.ChannelEdgePolicy + node1Bytes = info.Node1Bytes() + ) + if bytes.Equal(remotePub[:], node1Bytes[:]) { remotePolicy = p1 } else { remotePolicy = p2 @@ -739,16 +742,16 @@ func newHopHintInfo(c *channeldb.OpenChannel, isActive bool) *HopHintInfo { // newHopHint returns a new hop hint using the relevant data from a hopHintInfo // and a ChannelEdgePolicy1. func newHopHint(hopHintInfo *HopHintInfo, - chanPolicy *models.ChannelEdgePolicy1) zpay32.HopHint { + chanPolicy models.ChannelEdgePolicy) zpay32.HopHint { + + policy := chanPolicy.ForwardingPolicy() return zpay32.HopHint{ - NodeID: hopHintInfo.RemotePubkey, - ChannelID: hopHintInfo.ShortChannelID, - FeeBaseMSat: uint32(chanPolicy.FeeBaseMSat), - FeeProportionalMillionths: uint32( - chanPolicy.FeeProportionalMillionths, - ), - CLTVExpiryDelta: chanPolicy.TimeLockDelta, + NodeID: hopHintInfo.RemotePubkey, + ChannelID: hopHintInfo.ShortChannelID, + FeeBaseMSat: uint32(policy.BaseFee), + FeeProportionalMillionths: uint32(policy.FeeRate), + CLTVExpiryDelta: policy.TimeLockDelta, } } @@ -762,7 +765,7 @@ type SelectHopHintsCfg struct { // FetchChannelEdgesByID attempts to lookup the two directed edges for // the channel identified by the channel ID. - FetchChannelEdgesByID func(chanID uint64) (*models.ChannelEdgeInfo1, + FetchChannelEdgesByID func(chanID uint64) (models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) diff --git a/lnrpc/invoicesrpc/addinvoice_test.go b/lnrpc/invoicesrpc/addinvoice_test.go index 2bb94da8b0..c7960ea9b1 100644 --- a/lnrpc/invoicesrpc/addinvoice_test.go +++ b/lnrpc/invoicesrpc/addinvoice_test.go @@ -67,7 +67,7 @@ func (h *hopHintsConfigMock) FetchAllChannels() ([]*channeldb.OpenChannel, // FetchChannelEdgesByID attempts to lookup the two directed edges for // the channel identified by the channel ID. func (h *hopHintsConfigMock) FetchChannelEdgesByID(chanID uint64) ( - *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, + models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { args := h.Mock.Called(chanID) diff --git a/netann/chan_status_manager.go b/netann/chan_status_manager.go index c4db4009dc..de1dc42773 100644 --- a/netann/chan_status_manager.go +++ b/netann/chan_status_manager.go @@ -661,7 +661,8 @@ func (m *ChanStatusManager) fetchLastChanUpdateByOutPoint(op wire.OutPoint) ( update, err := ExtractChannelUpdate( m.ourPubKeyBytes, info, edge1, edge2, ) - return update, info.AuthProof == nil, err + + return update, info.GetAuthProof() == nil, err } // loadInitialChanState determines the initial ChannelState for a particular diff --git a/netann/chan_status_manager_test.go b/netann/chan_status_manager_test.go index 7af98bd801..9617c0b349 100644 --- a/netann/chan_status_manager_test.go +++ b/netann/chan_status_manager_test.go @@ -4,6 +4,7 @@ import ( "bytes" "crypto/rand" "encoding/binary" + "encoding/hex" "fmt" "io" "sync" @@ -12,6 +13,7 @@ import ( "time" "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/ecdsa" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb/models" @@ -24,10 +26,17 @@ import ( var ( testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey} - // testSigBytes specifies a testing signature with the minimal length. - testSigBytes = []byte{ - 0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, - } + testRBytes, _ = hex.DecodeString("8ce2bc69281ce27da07e6683571319d18e" + + "949ddfa2965fb6caa1bf0314f882d7") + testSBytes, _ = hex.DecodeString("299105481d63e0f4bc2a88121167221b67" + + "00d72a0ead154c03be696a292d24ae") + testRScalar = new(btcec.ModNScalar) + testSScalar = new(btcec.ModNScalar) + _ = testRScalar.SetByteSlice(testRBytes) + _ = testSScalar.SetByteSlice(testSBytes) + testSig = ecdsa.NewSignature(testRScalar, testSScalar) + + testSigBytes = testSig.Serialize() ) // randOutpoint creates a random wire.Outpoint. @@ -121,7 +130,7 @@ func createEdgePolicies(t *testing.T, channel *channeldb.OpenChannel, type mockGraph struct { mu sync.Mutex channels []*channeldb.OpenChannel - chanInfos map[wire.OutPoint]*models.ChannelEdgeInfo1 + chanInfos map[wire.OutPoint]models.ChannelEdgeInfo chanPols1 map[wire.OutPoint]*models.ChannelEdgePolicy1 chanPols2 map[wire.OutPoint]*models.ChannelEdgePolicy1 sidToCid map[lnwire.ShortChannelID]wire.OutPoint @@ -134,7 +143,7 @@ func newMockGraph(t *testing.T, numChannels int, g := &mockGraph{ channels: make([]*channeldb.OpenChannel, 0, numChannels), - chanInfos: make(map[wire.OutPoint]*models.ChannelEdgeInfo1), + chanInfos: make(map[wire.OutPoint]models.ChannelEdgeInfo), chanPols1: make(map[wire.OutPoint]*models.ChannelEdgePolicy1), chanPols2: make(map[wire.OutPoint]*models.ChannelEdgePolicy1), sidToCid: make(map[lnwire.ShortChannelID]wire.OutPoint), @@ -160,7 +169,7 @@ func (g *mockGraph) FetchAllOpenChannels() ([]*channeldb.OpenChannel, error) { } func (g *mockGraph) FetchChannelEdgesByOutpoint( - op *wire.OutPoint) (*models.ChannelEdgeInfo1, + op *wire.OutPoint) (models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { g.mu.Lock() diff --git a/netann/channel_announcement.go b/netann/channel_announcement.go index 67ba33d082..1d4342787b 100644 --- a/netann/channel_announcement.go +++ b/netann/channel_announcement.go @@ -33,7 +33,29 @@ const ( // function is used to transform out database structs into the corresponding wire // structs for announcing new channels to other peers, or simply syncing up a // peer's initial routing table upon connect. -func CreateChanAnnouncement(chanProof *models.ChannelAuthProof1, +func CreateChanAnnouncement(chanProof models.ChannelAuthProof, + chanInfo models.ChannelEdgeInfo, e1, e2 *models.ChannelEdgePolicy1) ( + *lnwire.ChannelAnnouncement1, *lnwire.ChannelUpdate1, + *lnwire.ChannelUpdate1, error) { + + switch proof := chanProof.(type) { + case *models.ChannelAuthProof1: + info, ok := chanInfo.(*models.ChannelEdgeInfo1) + if !ok { + return nil, nil, nil, fmt.Errorf("expected type "+ + "ChannelEdgeInfo1 to be paired with "+ + "ChannelAuthProof1, got: %T", chanInfo) + } + + return createChanAnnouncement1(proof, info, e1, e2) + + default: + return nil, nil, nil, fmt.Errorf("unhandled "+ + "models.ChannelAuthProof type: %T", chanProof) + } +} + +func createChanAnnouncement1(chanProof *models.ChannelAuthProof1, chanInfo *models.ChannelEdgeInfo1, e1, e2 *models.ChannelEdgePolicy1) (*lnwire.ChannelAnnouncement1, *lnwire.ChannelUpdate1, *lnwire.ChannelUpdate1, error) { diff --git a/netann/channel_update.go b/netann/channel_update.go index d4fac00611..66494054a6 100644 --- a/netann/channel_update.go +++ b/netann/channel_update.go @@ -102,7 +102,7 @@ func SignChannelUpdate(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator // // NOTE: The passed policies can be nil. func ExtractChannelUpdate(ownerPubKey []byte, - info *models.ChannelEdgeInfo1, + info models.ChannelEdgeInfo, policies ...*models.ChannelEdgePolicy1) ( *lnwire.ChannelUpdate1, error) { @@ -135,11 +135,24 @@ func ExtractChannelUpdate(ownerPubKey []byte, // UnsignedChannelUpdateFromEdge reconstructs an unsigned ChannelUpdate from the // given edge info and policy. -func UnsignedChannelUpdateFromEdge(info *models.ChannelEdgeInfo1, +func UnsignedChannelUpdateFromEdge(chainHash chainhash.Hash, + policy models.ChannelEdgePolicy) (*lnwire.ChannelUpdate1, error) { + + switch p := policy.(type) { + case *models.ChannelEdgePolicy1: + return unsignedChanPolicy1ToUpdate(chainHash, p), nil + + default: + return nil, fmt.Errorf("unhandled implementation of the "+ + "models.ChanelEdgePolicy interface: %T", policy) + } +} + +func unsignedChanPolicy1ToUpdate(chainHash chainhash.Hash, policy *models.ChannelEdgePolicy1) *lnwire.ChannelUpdate1 { return &lnwire.ChannelUpdate1{ - ChainHash: info.ChainHash, + ChainHash: chainHash, ShortChannelID: lnwire.NewShortChanIDFromInt(policy.ChannelID), Timestamp: uint32(policy.LastUpdate.Unix()), ChannelFlags: policy.ChannelFlags, @@ -153,21 +166,24 @@ func UnsignedChannelUpdateFromEdge(info *models.ChannelEdgeInfo1, } } -// ChannelUpdateFromEdge reconstructs a signed ChannelUpdate from the given edge -// info and policy. -func ChannelUpdateFromEdge(info *models.ChannelEdgeInfo1, +// ChannelUpdateFromEdge reconstructs a signed ChannelUpdate from the given +// edge info and policy. +func ChannelUpdateFromEdge(info models.ChannelEdgeInfo, policy *models.ChannelEdgePolicy1) (*lnwire.ChannelUpdate1, error) { - update := UnsignedChannelUpdateFromEdge(info, policy) + sig, err := policy.Signature() + if err != nil { + return nil, err + } - var err error - update.Signature, err = lnwire.NewSigFromECDSARawSignature( - policy.SigBytes, - ) + s, err := lnwire.NewSigFromSignature(sig) if err != nil { return nil, err } + update := unsignedChanPolicy1ToUpdate(info.GetChainHash(), policy) + update.Signature = s + return update, nil } diff --git a/netann/interface.go b/netann/interface.go index 8fd5eaf275..15b1abfc63 100644 --- a/netann/interface.go +++ b/netann/interface.go @@ -19,6 +19,6 @@ type DB interface { type ChannelGraph interface { // FetchChannelEdgesByOutpoint returns the channel edge info and most // recent channel edge policies for a given outpoint. - FetchChannelEdgesByOutpoint(*wire.OutPoint) (*models.ChannelEdgeInfo1, + FetchChannelEdgesByOutpoint(*wire.OutPoint) (models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) } diff --git a/peer/brontide.go b/peer/brontide.go index ab92195dec..5fb8453129 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -1102,13 +1102,14 @@ func (p *Brontide) loadActiveChannels(chans []*channeldb.OpenChannel) ( // // TODO(roasbeef): can add helper method to get policy for // particular channel. - var selfPolicy *models.ChannelEdgePolicy1 - if info != nil && bytes.Equal(info.NodeKey1Bytes[:], - p.cfg.ServerPubKey[:]) { + selfPolicy := p2 + if info != nil { + node1Bytes := info.Node1Bytes() + if bytes.Equal(node1Bytes[:], + p.cfg.ServerPubKey[:]) { - selfPolicy = p1 - } else { - selfPolicy = p2 + selfPolicy = p1 + } } // If we don't yet have an advertised routing policy, then diff --git a/routing/blindedpath/blinded_path.go b/routing/blindedpath/blinded_path.go index 3f41b2d7b6..9b69851ffc 100644 --- a/routing/blindedpath/blinded_path.go +++ b/routing/blindedpath/blinded_path.go @@ -42,7 +42,7 @@ type BuildBlindedPathCfg struct { // FetchChannelEdgesByID attempts to look up the two directed edges for // the channel identified by the channel ID. - FetchChannelEdgesByID func(chanID uint64) (*models.ChannelEdgeInfo1, + FetchChannelEdgesByID func(chanID uint64) (models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) // FetchOurOpenChannels fetches this node's set of open channels. diff --git a/routing/blindedpath/blinded_path_test.go b/routing/blindedpath/blinded_path_test.go index d593b034fb..4ee4f444f5 100644 --- a/routing/blindedpath/blinded_path_test.go +++ b/routing/blindedpath/blinded_path_test.go @@ -598,7 +598,7 @@ func TestBuildBlindedPath(t *testing.T) { return []*route.Route{realRoute}, nil }, FetchChannelEdgesByID: func(chanID uint64) ( - *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, + models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { return nil, realPolicies[chanID], nil, nil @@ -766,7 +766,7 @@ func TestBuildBlindedPathWithDummyHops(t *testing.T) { return []*route.Route{realRoute}, nil }, FetchChannelEdgesByID: func(chanID uint64) ( - *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, + models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { policy, ok := realPolicies[chanID] @@ -937,7 +937,7 @@ func TestBuildBlindedPathWithDummyHops(t *testing.T) { nil }, FetchChannelEdgesByID: func(chanID uint64) ( - *models.ChannelEdgeInfo1, *models.ChannelEdgePolicy1, + models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { // Force the call to error for the first 2 channels. diff --git a/routing/localchans/manager.go b/routing/localchans/manager.go index 55a9af095d..072b5eb9f0 100644 --- a/routing/localchans/manager.go +++ b/routing/localchans/manager.go @@ -32,7 +32,7 @@ type Manager struct { // ForAllOutgoingChannels is required to iterate over all our local // channels. ForAllOutgoingChannels func(cb func(kvdb.RTx, - *models.ChannelEdgeInfo1, + models.ChannelEdgeInfo, *models.ChannelEdgePolicy1) error) error // FetchChannel is used to query local channel parameters. Optionally an @@ -74,25 +74,27 @@ func (r *Manager) UpdatePolicy(newSchema routing.ChannelPolicy, // otherwise we'll collect them all. err := r.ForAllOutgoingChannels(func( tx kvdb.RTx, - info *models.ChannelEdgeInfo1, + info models.ChannelEdgeInfo, edge *models.ChannelEdgePolicy1) error { + var chanPoint = info.GetChanPoint() + // If we have a channel filter, and this channel isn't a part // of it, then we'll skip it. - _, ok := unprocessedChans[info.ChannelPoint] + _, ok := unprocessedChans[chanPoint] if !ok && haveChanFilter { return nil } // Mark this channel as found by removing it. unprocessedChans // will be used to report invalid channels later on. - delete(unprocessedChans, info.ChannelPoint) + delete(unprocessedChans, chanPoint) // Apply the new policy to the edge. - err := r.updateEdge(tx, info.ChannelPoint, edge, newSchema) + err := r.updateEdge(tx, chanPoint, edge, newSchema) if err != nil { failedUpdates = append(failedUpdates, - makeFailureItem(info.ChannelPoint, + makeFailureItem(chanPoint, lnrpc.UpdateFailure_UPDATE_FAILURE_INVALID_PARAMETER, err.Error(), )) @@ -115,7 +117,7 @@ func (r *Manager) UpdatePolicy(newSchema routing.ChannelPolicy, inboundFee := models.NewInboundFeeFromWire(inboundWireFee) // Add updated policy to list of policies to send to switch. - policiesToUpdate[info.ChannelPoint] = models.ForwardingPolicy{ + policiesToUpdate[chanPoint] = models.ForwardingPolicy{ BaseFee: edge.FeeBaseMSat, FeeRate: edge.FeeProportionalMillionths, TimeLockDelta: uint32(edge.TimeLockDelta), diff --git a/routing/localchans/manager_test.go b/routing/localchans/manager_test.go index 0054396d08..30b23c1b7c 100644 --- a/routing/localchans/manager_test.go +++ b/routing/localchans/manager_test.go @@ -107,7 +107,7 @@ func TestManager(t *testing.T) { } forAllOutgoingChannels := func(cb func(kvdb.RTx, - *models.ChannelEdgeInfo1, + models.ChannelEdgeInfo, *models.ChannelEdgePolicy1) error) error { for _, c := range channelSet { diff --git a/rpcserver.go b/rpcserver.go index c2510bcf46..10388e88ea 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -703,7 +703,7 @@ func (r *rpcServer) addDeps(s *server, macService *macaroons.Service, if err != nil { return 0, err } - return info.Capacity, nil + return info.GetCapacity(), nil }, FetchAmountPairCapacity: func(nodeFrom, nodeTo route.Vertex, amount lnwire.MilliSatoshi) (btcutil.Amount, error) { @@ -726,7 +726,7 @@ func (r *rpcServer) addDeps(s *server, macService *macaroons.Service, chanID, err) } - return info.NodeKey1Bytes, info.NodeKey2Bytes, nil + return info.Node1Bytes(), info.Node1Bytes(), nil }, FindRoute: s.chanRouter.FindRoute, MissionControl: s.defaultMC, @@ -6516,14 +6516,14 @@ func (r *rpcServer) DescribeGraph(ctx context.Context, // Next, for each active channel we know of within the graph, create a // similar response which details both the edge information as well as // the routing policies of th nodes connecting the two edges. - err = graph.ForEachChannel(func(edgeInfo *models.ChannelEdgeInfo1, + err = graph.ForEachChannel(func(edgeInfo models.ChannelEdgeInfo, c1, c2 *models.ChannelEdgePolicy1) error { // Do not include unannounced channels unless specifically // requested. Unannounced channels include both private channels as // well as public channels whose authentication proof were not // confirmed yet, hence were not announced. - if !includeUnannounced && edgeInfo.AuthProof == nil { + if !includeUnannounced && edgeInfo.GetAuthProof() == nil { return nil } @@ -6750,7 +6750,7 @@ func (r *rpcServer) GetChanInfo(_ context.Context, graph := r.server.graphDB var ( - edgeInfo *models.ChannelEdgeInfo1 + edgeInfo models.ChannelEdgeInfo edge1, edge2 *models.ChannelEdgePolicy1 err error ) @@ -6823,11 +6823,11 @@ func (r *rpcServer) GetNodeInfo(ctx context.Context, ) err = graph.ForEachNodeChannel(node.PubKeyBytes, - func(_ kvdb.RTx, edge *models.ChannelEdgeInfo1, + func(_ kvdb.RTx, edge models.ChannelEdgeInfo, c1, c2 *models.ChannelEdgePolicy1) error { numChannels++ - totalCapacity += edge.Capacity + totalCapacity += edge.GetCapacity() // Only populate the node's channels if the user // requested them. @@ -6835,7 +6835,7 @@ func (r *rpcServer) GetNodeInfo(ctx context.Context, // Do not include unannounced channels - private // channels or public channels whose // authentication proof were not confirmed yet. - if edge.AuthProof == nil { + if edge.GetAuthProof() == nil { return nil } @@ -7483,14 +7483,14 @@ func (r *rpcServer) FeeReport(ctx context.Context, var feeReports []*lnrpc.ChannelFeeReport err = channelGraph.ForEachNodeChannel(selfNode.PubKeyBytes, - func(_ kvdb.RTx, chanInfo *models.ChannelEdgeInfo1, + func(_ kvdb.RTx, chanInfo models.ChannelEdgeInfo, edgePolicy, _ *models.ChannelEdgePolicy1) error { // Self node should always have policies for its // channels. if edgePolicy == nil { return fmt.Errorf("no policy for outgoing "+ - "channel %v ", chanInfo.ChannelID) + "channel %v ", chanInfo.GetChanID()) } // We'll compute the effective fee rate by converting @@ -7514,8 +7514,8 @@ func (r *rpcServer) FeeReport(ctx context.Context, // TODO(roasbeef): also add stats for revenue for each // channel feeReports = append(feeReports, &lnrpc.ChannelFeeReport{ - ChanId: chanInfo.ChannelID, - ChannelPoint: chanInfo.ChannelPoint.String(), + ChanId: chanInfo.GetChanID(), + ChannelPoint: chanInfo.GetChanPoint().String(), BaseFeeMsat: int64(edgePolicy.FeeBaseMSat), FeePerMil: int64(feeRateFixedPoint), FeeRate: feeRate, diff --git a/server.go b/server.go index 7d3c59f290..e628de4f6f 100644 --- a/server.go +++ b/server.go @@ -1369,7 +1369,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, copy(ourKey[:], nodeKeyDesc.PubKey.SerializeCompressed()) var ourPolicy *models.ChannelEdgePolicy1 - if info != nil && info.NodeKey1Bytes == ourKey { + if info != nil && info.Node1Bytes() == ourKey { ourPolicy = e1 } else { ourPolicy = e2 @@ -3315,15 +3315,17 @@ func (s *server) establishPersistentConnections() error { selfPub := s.identityECDH.PubKey().SerializeCompressed() err = s.graphDB.ForEachNodeChannel(sourceNode.PubKeyBytes, func( tx kvdb.RTx, - chanInfo *models.ChannelEdgeInfo1, + chanInfo models.ChannelEdgeInfo, policy, _ *models.ChannelEdgePolicy1) error { + chanPoint := chanInfo.GetChanPoint() + // If the remote party has announced the channel to us, but we // haven't yet, then we won't have a policy. However, we don't // need this to connect to the peer, so we'll log it and move on. if policy == nil { srvrLog.Warnf("No channel policy found for "+ - "ChannelPoint(%v): ", chanInfo.ChannelPoint) + "ChannelPoint(%v): ", chanPoint) } // We'll now fetch the peer opposite from us within this @@ -3333,8 +3335,7 @@ func (s *server) establishPersistentConnections() error { ) if err != nil { return fmt.Errorf("unable to fetch channel peer for "+ - "ChannelPoint(%v): %v", chanInfo.ChannelPoint, - err) + "ChannelPoint(%v): %v", chanPoint, err) } pubStr := string(channelPeer.PubKeyBytes[:]) From 03f0a0e484b12913049c54aa24863e78a40ae3e6 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 6 Nov 2023 12:36:24 +0200 Subject: [PATCH 18/60] channeldb: update reject cache To take block heights too. --- channeldb/graph.go | 50 +++++++++++++---------- channeldb/graph_test.go | 12 +++++- channeldb/reject_cache.go | 42 ++++++++++++++++++- channeldb/reject_cache_test.go | 8 ++-- graph/builder.go | 74 ++++++++++++++++++++++------------ 5 files changed, 134 insertions(+), 52 deletions(-) diff --git a/channeldb/graph.go b/channeldb/graph.go index 7306cbcdc2..f19cebb19a 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -1162,10 +1162,10 @@ func (c *ChannelGraph) HasChannelEdge( // We'll query the cache with the shared lock held to allow multiple // readers to access values in the cache concurrently if they exist. c.cacheMu.RLock() - if entry, ok := c.rejectCache.get(chanID); ok { + if entry, ok := c.rejectCache.get(chanID); ok && entry.times != nil { c.cacheMu.RUnlock() - upd1Time = time.Unix(entry.upd1Time, 0) - upd2Time = time.Unix(entry.upd2Time, 0) + upd1Time = time.Unix(entry.times.upd1Time, 0) + upd2Time = time.Unix(entry.times.upd2Time, 0) exists, isZombie = entry.flags.unpack() return upd1Time, upd2Time, exists, isZombie, nil } @@ -1177,9 +1177,9 @@ func (c *ChannelGraph) HasChannelEdge( // The item was not found with the shared lock, so we'll acquire the // exclusive lock and check the cache again in case another method added // the entry to the cache while no lock was held. - if entry, ok := c.rejectCache.get(chanID); ok { - upd1Time = time.Unix(entry.upd1Time, 0) - upd2Time = time.Unix(entry.upd2Time, 0) + if entry, ok := c.rejectCache.get(chanID); ok && entry.times != nil { + upd1Time = time.Unix(entry.times.upd1Time, 0) + upd2Time = time.Unix(entry.times.upd2Time, 0) exists, isZombie = entry.flags.unpack() return upd1Time, upd2Time, exists, isZombie, nil } @@ -1244,9 +1244,11 @@ func (c *ChannelGraph) HasChannelEdge( } c.rejectCache.insert(chanID, rejectCacheEntry{ - upd1Time: upd1Time.Unix(), - upd2Time: upd2Time.Unix(), - flags: packRejectFlags(exists, isZombie), + times: &updateTimes{ + upd1Time: upd1Time.Unix(), + upd2Time: upd2Time.Unix(), + }, + flags: packRejectFlags(exists, isZombie), }) return upd1Time, upd2Time, exists, isZombie, nil @@ -2817,33 +2819,39 @@ func (c *ChannelGraph) UpdateEdgePolicy(edge *models.ChannelEdgePolicy1, return c.chanScheduler.Execute(r) } -func (c *ChannelGraph) updateEdgeCache(e *models.ChannelEdgePolicy1, +func (c *ChannelGraph) updateEdgeCache(e models.ChannelEdgePolicy, isUpdate1 bool) { // If an entry for this channel is found in reject cache, we'll modify // the entry with the updated timestamp for the direction that was just // written. If the edge doesn't exist, we'll load the cache entry lazily // during the next query for this edge. - if entry, ok := c.rejectCache.get(e.ChannelID); ok { - if isUpdate1 { - entry.upd1Time = e.LastUpdate.Unix() - } else { - entry.upd2Time = e.LastUpdate.Unix() - } - c.rejectCache.insert(e.ChannelID, entry) + chanID := e.SCID().ToUint64() + if entry, ok := c.rejectCache.get(chanID); ok { + entry.update(isUpdate1, e) + c.rejectCache.insert(chanID, entry) } // If an entry for this channel is found in channel cache, we'll modify // the entry with the updated policy for the direction that was just // written. If the edge doesn't exist, we'll defer loading the info and // policies and lazily read from disk during the next query. - if channel, ok := c.chanCache.get(e.ChannelID); ok { + if channel, ok := c.chanCache.get(chanID); ok { + edge, ok := e.(*models.ChannelEdgePolicy1) + if !ok { + log.Errorf("expected *models.ChannelEdgePolicy1, "+ + "got: %T", e) + + return + } + if isUpdate1 { - channel.Policy1 = e + channel.Policy1 = edge } else { - channel.Policy2 = e + channel.Policy2 = edge } - c.chanCache.insert(e.ChannelID, channel) + + c.chanCache.insert(chanID, channel) } } diff --git a/channeldb/graph_test.go b/channeldb/graph_test.go index ba4567a580..afdd8bced1 100644 --- a/channeldb/graph_test.go +++ b/channeldb/graph_test.go @@ -3622,7 +3622,17 @@ func compareNodes(a, b *LightningNode) error { // compareEdgePolicies is used to compare two ChannelEdgePolices using // compareNodes, so as to exclude comparisons of the Nodes' Features struct. -func compareEdgePolicies(a, b *models.ChannelEdgePolicy1) error { +func compareEdgePolicies(edgeA, edgeB models.ChannelEdgePolicy) error { + a, ok := edgeA.(*models.ChannelEdgePolicy1) + if !ok { + return fmt.Errorf("wanted edge policy 1") + } + + b, ok := edgeB.(*models.ChannelEdgePolicy1) + if !ok { + return fmt.Errorf("wanted edge policy 1") + } + if a.ChannelID != b.ChannelID { return fmt.Errorf("ChannelID doesn't match: expected %v, "+ "got %v", a.ChannelID, b.ChannelID) diff --git a/channeldb/reject_cache.go b/channeldb/reject_cache.go index acadb8780b..a76f80d7c2 100644 --- a/channeldb/reject_cache.go +++ b/channeldb/reject_cache.go @@ -1,5 +1,7 @@ package channeldb +import "github.com/lightningnetwork/lnd/channeldb/models" + // rejectFlags is a compact representation of various metadata stored by the // reject cache about a particular channel. type rejectFlags uint8 @@ -41,9 +43,47 @@ func (f rejectFlags) unpack() (bool, bool) { // including the timestamps of its latest edge policies and whether or not the // channel exists in the graph. type rejectCacheEntry struct { + times *updateTimes + blocks *updateBlocks + flags rejectFlags +} + +type updateTimes struct { upd1Time int64 upd2Time int64 - flags rejectFlags +} + +type updateBlocks struct { + updBlock1 uint32 + updBlock2 uint32 +} + +func (e *rejectCacheEntry) update(isUpdate1 bool, + policy models.ChannelEdgePolicy) { + + switch pol := policy.(type) { + case *models.ChannelEdgePolicy1: + if e.times == nil { + e.times = &updateTimes{} + } + + if isUpdate1 { + e.times.upd1Time = pol.LastUpdate.Unix() + } else { + e.times.upd2Time = pol.LastUpdate.Unix() + } + + case *models.ChannelEdgePolicy2: + if e.blocks == nil { + e.blocks = &updateBlocks{} + } + + if isUpdate1 { + e.blocks.updBlock1 = pol.BlockHeight.Val + } else { + e.blocks.updBlock2 = pol.BlockHeight.Val + } + } } // rejectCache is an in-memory cache used to improve the performance of diff --git a/channeldb/reject_cache_test.go b/channeldb/reject_cache_test.go index 6974f42573..a4ab798c06 100644 --- a/channeldb/reject_cache_test.go +++ b/channeldb/reject_cache_test.go @@ -100,8 +100,10 @@ func entryForInt(i uint64) rejectCacheEntry { exists := i%2 == 0 isZombie := i%3 == 0 return rejectCacheEntry{ - upd1Time: int64(2 * i), - upd2Time: int64(2*i + 1), - flags: packRejectFlags(exists, isZombie), + times: &updateTimes{ + upd1Time: int64(2 * i), + upd2Time: int64(2*i + 1), + }, + flags: packRejectFlags(exists, isZombie), } } diff --git a/graph/builder.go b/graph/builder.go index cd5f27e8b9..b1b549e25b 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -475,30 +475,6 @@ func (b *Builder) syncGraphWithChain() error { return nil } -// isZombieChannel takes two edge policy updates and determines if the -// corresponding channel should be considered a zombie. The first boolean is -// true if the policy update from node 1 is considered a zombie, the second -// boolean is that of node 2, and the final boolean is true if the channel -// is considered a zombie. -func (b *Builder) isZombieChannel(e1, - e2 *models.ChannelEdgePolicy1) (bool, bool, bool) { - - chanExpiry := b.cfg.ChannelPruneExpiry - - e1Zombie := e1 == nil || time.Since(e1.LastUpdate) >= chanExpiry - e2Zombie := e2 == nil || time.Since(e2.LastUpdate) >= chanExpiry - - var e1Time, e2Time time.Time - if e1 != nil { - e1Time = e1.LastUpdate - } - if e2 != nil { - e2Time = e2.LastUpdate - } - - return e1Zombie, e2Zombie, b.IsZombieChannel(e1Time, e2Time) -} - // IsZombieChannel takes the timestamps of the latest channel updates for a // channel and returns true if the channel should be considered a zombie based // on these timestamps. @@ -513,6 +489,10 @@ func (b *Builder) IsZombieChannel(updateTime1, e2Zombie := updateTime2.IsZero() || time.Since(updateTime2) >= chanExpiry + return b.isZombieChannel(e1Zombie, e2Zombie) +} + +func (b *Builder) isZombieChannel(e1Zombie, e2Zombie bool) bool { // If we're using strict zombie pruning, then a channel is only // considered live if both edges have a recent update we know of. if b.cfg.StrictZombiePruning { @@ -563,7 +543,15 @@ func (b *Builder) pruneZombieChans() error { return nil } - e1Zombie, e2Zombie, isZombieChan := b.isZombieChannel(e1, e2) + e1Zombie, err := b.isZombieEdge(e1) + if err != nil { + return err + } + + e2Zombie, err := b.isZombieEdge(e2) + if err != nil { + return err + } if e1Zombie { log.Tracef("Node1 pubkey=%x of chan_id=%v is zombie", @@ -578,7 +566,7 @@ func (b *Builder) pruneZombieChans() error { // If either edge hasn't been updated for a period of // chanExpiry, then we'll mark the channel itself as eligible // for graph pruning. - if !isZombieChan { + if !b.isZombieChannel(e1Zombie, e2Zombie) { return nil } @@ -663,6 +651,40 @@ func (b *Builder) pruneZombieChans() error { return nil } +func (b *Builder) isZombieEdge(edge models.ChannelEdgePolicy) (bool, + error) { + + if edge == nil { + return true, nil + } + + switch e := edge.(type) { + case *models.ChannelEdgePolicy1: + chanExpiry := b.cfg.ChannelPruneExpiry + + if e == nil { + return true, nil + } + + return time.Since(e.LastUpdate) >= chanExpiry, nil + + case *models.ChannelEdgePolicy2: + chanExpiryBlocks := uint32(b.cfg.ChannelPruneExpiry.Hours() * 6) + + if e == nil { + return true, nil + } + + blockSince := b.SyncedHeight() - e.BlockHeight.Val + + return blockSince >= chanExpiryBlocks, nil + + default: + return false, fmt.Errorf("unhandled implementation of "+ + "models.ChannelEdgePolicy: %T", edge) + } +} + // handleNetworkUpdate is responsible for processing the update message and // notifies topology changes, if any. // From 5a9b44bb6d709df69b9ac95f746abae7c4da7f03 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Thu, 16 Nov 2023 14:27:36 +0200 Subject: [PATCH 19/60] channeldb: write to new update index for ChannelEdgePolicy2 --- channeldb/edge_policy.go | 160 +++++++++++++++++------------ channeldb/edge_policy_test.go | 5 +- channeldb/graph.go | 177 ++++++++++++++++++++++++++------- channeldb/graph_cache.go | 16 ++- channeldb/graph_test.go | 11 +- discovery/gossiper_test.go | 9 +- graph/builder.go | 2 +- netann/channel_announcement.go | 27 ++++- 8 files changed, 298 insertions(+), 109 deletions(-) diff --git a/channeldb/edge_policy.go b/channeldb/edge_policy.go index 8d507a49d3..cde4702021 100644 --- a/channeldb/edge_policy.go +++ b/channeldb/edge_policy.go @@ -39,26 +39,89 @@ const ( edgePolicy2EncodingType edgePolicyEncodingType = 0 ) +type edgePolicyEncodingInfo struct { + updateBucketKey []byte + updateKey []byte + serialize func(w io.Writer, toNode []byte) error + typeByte func() (edgePolicyEncodingType, bool) +} + +func encodingInfoFromEdgePolicy(policy models.ChannelEdgePolicy) ( + *edgePolicyEncodingInfo, error) { + + switch p := policy.(type) { + case *models.ChannelEdgePolicy1: + updateUnix := uint64(p.LastUpdate.Unix()) + var indexKey [8 + 8]byte + byteOrder.PutUint64(indexKey[:8], updateUnix) + byteOrder.PutUint64(indexKey[8:], p.ChannelID) + + return &edgePolicyEncodingInfo{ + updateBucketKey: edgeUpdateIndexBucket, + updateKey: indexKey[:], + serialize: func(w io.Writer, toNode []byte) error { + copy(p.ToNode[:], toNode) + + return serializeChanEdgePolicy1(w, p) + }, + typeByte: func() (edgePolicyEncodingType, bool) { + return 0, false + }, + }, nil + + case *models.ChannelEdgePolicy2: + indexKey := make([]byte, 4+8) + byteOrder.PutUint32( + indexKey[:4], p.BlockHeight.Val, + ) + byteOrder.PutUint64( + indexKey[4:], p.ShortChannelID.Val.ToUint64(), + ) + + return &edgePolicyEncodingInfo{ + updateBucketKey: edgeUpdate2IndexBucket, + updateKey: indexKey, + serialize: func(w io.Writer, toNode []byte) error { + copy(p.ToNode[:], toNode) + + return serializeChanEdgePolicy2(w, p) + }, + typeByte: func() (edgePolicyEncodingType, bool) { + return edgePolicy2EncodingType, true + }, + }, nil + + default: + return nil, fmt.Errorf("unhandled implementation of the "+ + "models.ChannelEdgePolicy interface: %T", policy) + } +} + func putChanEdgePolicy(edges kvdb.RwBucket, edge *models.ChannelEdgePolicy1, from, to []byte) error { + encodingInfo, err := encodingInfoFromEdgePolicy(edge) + if err != nil { + return err + } + + chanID := edge.SCID().ToUint64() + var edgeKey [33 + 8]byte copy(edgeKey[:], from) - byteOrder.PutUint64(edgeKey[33:], edge.ChannelID) + byteOrder.PutUint64(edgeKey[33:], chanID) var b bytes.Buffer - if err := serializeChanEdgePolicy(&b, edge, to); err != nil { + if err := serializeChanEdgePolicy(&b, encodingInfo, to); err != nil { return err } // Before we write out the new edge, we'll create a new entry in the // update index in order to keep it fresh. - updateUnix := uint64(edge.LastUpdate.Unix()) - var indexKey [8 + 8]byte - byteOrder.PutUint64(indexKey[:8], updateUnix) - byteOrder.PutUint64(indexKey[8:], edge.ChannelID) - - updateIndex, err := edges.CreateBucketIfNotExists(edgeUpdateIndexBucket) + indexKey := encodingInfo.updateKey + updateIndex, err := edges.CreateBucketIfNotExists( + encodingInfo.updateBucketKey, + ) if err != nil { return err } @@ -88,32 +151,36 @@ func putChanEdgePolicy(edges kvdb.RwBucket, edge *models.ChannelEdgePolicy1, return err } - oldPol, ok := oldEdgePolicy.(*models.ChannelEdgePolicy1) - if !ok { - return fmt.Errorf("expected "+ - "*models.ChannelEdgePolicy1, got: %T", - oldEdgePolicy) + info, err := encodingInfoFromEdgePolicy(oldEdgePolicy) + if err != nil { + return err } - oldUpdateTime := uint64(oldPol.LastUpdate.Unix()) - - var oldIndexKey [8 + 8]byte - byteOrder.PutUint64(oldIndexKey[:8], oldUpdateTime) - byteOrder.PutUint64(oldIndexKey[8:], edge.ChannelID) + // Sanity check that the old update is assigned to the same + // update bucket as the new one. + if !bytes.Equal( + info.updateBucketKey, encodingInfo.updateBucketKey, + ) { + + return fmt.Errorf("received a new update belonging "+ + "to bucket %s where previous update for the "+ + "same channel belonged to bucket %s", + string(encodingInfo.updateBucketKey), + string(info.updateKey)) + } - if err := updateIndex.Delete(oldIndexKey[:]); err != nil { + oldIndexKey := info.updateKey + if err := updateIndex.Delete(oldIndexKey); err != nil { return err } } - if err := updateIndex.Put(indexKey[:], nil); err != nil { + if err := updateIndex.Put(indexKey, nil); err != nil { return err } err = updateEdgePolicyDisabledIndex( - edges, edge.ChannelID, - edge.ChannelFlags&lnwire.ChanUpdateDirection > 0, - edge.IsDisabled(), + edges, chanID, !edge.IsNode1(), edge.IsDisabled(), ) if err != nil { return err @@ -172,7 +239,7 @@ func putChanEdgePolicyUnknown(edges kvdb.RwBucket, channelID uint64, } func fetchChanEdgePolicy(edges kvdb.RBucket, chanID []byte, - nodePub []byte) (*models.ChannelEdgePolicy1, error) { + nodePub []byte) (models.ChannelEdgePolicy, error) { var edgeKey [33 + 8]byte copy(edgeKey[:], nodePub) @@ -201,17 +268,11 @@ func fetchChanEdgePolicy(edges kvdb.RBucket, chanID []byte, return nil, err } - pol, ok := ep.(*models.ChannelEdgePolicy1) - if !ok { - return nil, fmt.Errorf("expected *models.ChannelEdgePolicy1, "+ - "got: %T", ep) - } - - return pol, nil + return ep, nil } func fetchChanEdgePolicies(edgeIndex kvdb.RBucket, edges kvdb.RBucket, - chanID []byte) (*models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, + chanID []byte) (models.ChannelEdgePolicy, models.ChannelEdgePolicy, error) { edgeInfoBytes := edgeIndex.Get(chanID) @@ -239,37 +300,10 @@ func fetchChanEdgePolicies(edgeIndex kvdb.RBucket, edges kvdb.RBucket, return edge1, edge2, nil } -func serializeChanEdgePolicy(w io.Writer, - edgePolicy models.ChannelEdgePolicy, toNode []byte) error { - - var ( - withTypeByte bool - typeByte edgePolicyEncodingType - serialize func(w io.Writer) error - ) - - switch policy := edgePolicy.(type) { - case *models.ChannelEdgePolicy1: - serialize = func(w io.Writer) error { - copy(policy.ToNode[:], toNode) - - return serializeChanEdgePolicy1(w, policy) - } - case *models.ChannelEdgePolicy2: - withTypeByte = true - typeByte = edgePolicy2EncodingType - - serialize = func(w io.Writer) error { - copy(policy.ToNode[:], toNode) - - return serializeChanEdgePolicy2(w, policy) - } - default: - return fmt.Errorf("unhandled implementation of "+ - "ChannelEdgePolicy: %T", edgePolicy) - } +func serializeChanEdgePolicy(w io.Writer, info *edgePolicyEncodingInfo, + toNode []byte) error { - if withTypeByte { + if typeByte, ok := info.typeByte(); ok { // First, write the identifying encoding byte to signal that // this is not using the legacy encoding. _, err := w.Write([]byte{chanEdgePolicyNewEncodingPrefix}) @@ -284,7 +318,7 @@ func serializeChanEdgePolicy(w io.Writer, } } - return serialize(w) + return info.serialize(w, toNode) } func serializeChanEdgePolicy1(w io.Writer, diff --git a/channeldb/edge_policy_test.go b/channeldb/edge_policy_test.go index 16f03c5545..7b0b81f8ce 100644 --- a/channeldb/edge_policy_test.go +++ b/channeldb/edge_policy_test.go @@ -26,7 +26,10 @@ func TestEdgePolicySerialisation(t *testing.T) { toNode = info.GetToNode() ) - err := serializeChanEdgePolicy(&b, info, toNode[:]) + encodingInfo, err := encodingInfoFromEdgePolicy(info) + require.NoError(t, err) + + err = serializeChanEdgePolicy(&b, encodingInfo, toNode[:]) require.NoError(t, err) newInfo, err := deserializeChanEdgePolicy(&b) diff --git a/channeldb/graph.go b/channeldb/graph.go index f19cebb19a..400e5ab099 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -100,11 +100,20 @@ var ( // edgeUpdateIndexBucket is a sub-bucket of the main edgeBucket. This // bucket contains an index which allows us to gauge the "freshness" of - // a channel's last updates. + // a channel's last updates for updates using UNIX timestamps as + // timestamps. // // maps: updateTime || chanID -> nil edgeUpdateIndexBucket = []byte("edge-update-index") + // edgeUpdate2IndexBucket is a sub-bucket of the main edgeBucket. This + // bucket contains an index which allows us to gauge the "freshness" of + // a channel's last updates for updates using block heights as + // timestamps. + // + // maps: blockHeight || chanID -> nil + edgeUpdate2IndexBucket = []byte("edge-update-2-index") + // channelPointBucket maps a channel's full outpoint (txid:index) to // its short 8-byte channel ID. This bucket resides within the // edgeBucket above, and can be used to quickly remove an edge due to @@ -275,6 +284,7 @@ func (c *ChannelGraph) getChannelMap(edges kvdb.RBucket) ( // Skip embedded buckets. if bytes.Equal(k, edgeIndexBucket) || bytes.Equal(k, edgeUpdateIndexBucket) || + bytes.Equal(k, edgeUpdate2IndexBucket) || bytes.Equal(k, zombieBucket) || bytes.Equal(k, disabledEdgePolicyBucket) || bytes.Equal(k, channelPointBucket) { @@ -386,6 +396,10 @@ func initChannelGraph(db kvdb.Backend) error { if err != nil { return err } + _, err = edges.CreateBucketIfNotExists(edgeUpdate2IndexBucket) + if err != nil { + return err + } _, err = edges.CreateBucketIfNotExists(channelPointBucket) if err != nil { return err @@ -1222,7 +1236,7 @@ func (c *ChannelGraph) HasChannelEdge( return ErrGraphNodeNotFound } - e1, e2, err := fetchChanEdgePolicies( + edge1, edge2, err := fetchChanEdgePolicies( edgeIndex, edges, channelID[:], ) if err != nil { @@ -1231,10 +1245,21 @@ func (c *ChannelGraph) HasChannelEdge( // As we may have only one of the edges populated, only set the // update time if the edge was found in the database. - if e1 != nil { + if edge1 != nil { + e1, ok := edge1.(*models.ChannelEdgePolicy1) + if !ok { + return fmt.Errorf("expected "+ + "*ChannelEdgePolicy1, got: %T", edge1) + } upd1Time = e1.LastUpdate } - if e2 != nil { + if edge2 != nil { + e2, ok := edge2.(*models.ChannelEdgePolicy1) + if !ok { + return fmt.Errorf("expected "+ + "*ChannelEdgePolicy1, got: %T", edge2) + } + upd2Time = e2.LastUpdate } @@ -1902,11 +1927,11 @@ type ChannelEdge struct { // Policy1 points to the "first" edge policy of the channel containing // the dynamic information required to properly route through the edge. - Policy1 *models.ChannelEdgePolicy1 + Policy1 models.ChannelEdgePolicy // Policy2 points to the "second" edge policy of the channel containing // the dynamic information required to properly route through the edge. - Policy2 *models.ChannelEdgePolicy1 + Policy2 models.ChannelEdgePolicy // Node1 is "node 1" in the channel. This is the node that would have // produced Policy1 if it exists. @@ -2427,7 +2452,7 @@ func (c *ChannelGraph) FilterChannelRange(startHeight, switch { // If we don't know of any channels yet, then there's nothing to // filter, so we'll return an empty slice. - case err == ErrGraphNoEdgesFound || len(channelsPerBlock) == 0: + case errors.Is(err, ErrGraphNoEdgesFound) || len(channelsPerBlock) == 0: return nil, nil case err != nil: @@ -2564,37 +2589,59 @@ func (c *ChannelGraph) fetchChanInfos(tx kvdb.RTx, chanIDs []uint64) ( return chanEdges, nil } -func delEdgeUpdateIndexEntry(edgesBucket kvdb.RwBucket, chanID uint64, - edge1, edge2 *models.ChannelEdgePolicy1) error { +func delEdgeUpdateIndexEntry(edgesBucket kvdb.RwBucket, + edge1, edge2 models.ChannelEdgePolicy) error { + + var ( + updateIndexBucketKey []byte + e1 *edgePolicyEncodingInfo + e2 *edgePolicyEncodingInfo + err error + ) + + if edge1 == nil && edge2 == nil { + return nil + } + + if edge1 != nil { + e1, err = encodingInfoFromEdgePolicy(edge1) + if err != nil { + return err + } + + updateIndexBucketKey = e1.updateBucketKey + } + + if edge2 != nil { + e2, err = encodingInfoFromEdgePolicy(edge2) + if err != nil { + return err + } + + updateIndexBucketKey = e2.updateBucketKey + } // First, we'll fetch the edge update index bucket which currently // stores an entry for the channel we're about to delete. - updateIndex := edgesBucket.NestedReadWriteBucket(edgeUpdateIndexBucket) + updateIndex := edgesBucket.NestedReadWriteBucket(updateIndexBucketKey) if updateIndex == nil { // No edges in bucket, return early. return nil } - // Now that we have the bucket, we'll attempt to construct a template - // for the index key: updateTime || chanid. - var indexKey [8 + 8]byte - byteOrder.PutUint64(indexKey[8:], chanID) - // With the template constructed, we'll attempt to delete an entry that // would have been created by both edges: we'll alternate the update // times, as one may had overridden the other. - if edge1 != nil { - byteOrder.PutUint64(indexKey[:8], uint64(edge1.LastUpdate.Unix())) - if err := updateIndex.Delete(indexKey[:]); err != nil { + if e1 != nil { + if err := updateIndex.Delete(e1.updateKey); err != nil { return err } } // We'll also attempt to delete the entry that may have been created by // the second edge. - if edge2 != nil { - byteOrder.PutUint64(indexKey[:8], uint64(edge2.LastUpdate.Unix())) - if err := updateIndex.Delete(indexKey[:]); err != nil { + if e2 != nil { + if err := updateIndex.Delete(e2.updateKey); err != nil { return err } } @@ -2638,7 +2685,7 @@ func (c *ChannelGraph) delChannelEdgeUnsafe(edges, edgeIndex, chanIndex, if err != nil { return err } - err = delEdgeUpdateIndexEntry(edges, cid, edge1, edge2) + err = delEdgeUpdateIndexEntry(edges, edge1, edge2) if err != nil { return err } @@ -2722,7 +2769,7 @@ func (c *ChannelGraph) delChannelEdgeUnsafe(edges, edgeIndex, chanIndex, // marked with the correct lagging channel since we received an update from only // one side. func makeZombiePubkeys(info models.ChannelEdgeInfo, - e1, e2 *models.ChannelEdgePolicy1) ([33]byte, [33]byte, error) { + e1, e2 models.ChannelEdgePolicy) ([33]byte, [33]byte, error) { var ( node1Bytes = info.Node1Bytes() @@ -2837,18 +2884,10 @@ func (c *ChannelGraph) updateEdgeCache(e models.ChannelEdgePolicy, // written. If the edge doesn't exist, we'll defer loading the info and // policies and lazily read from disk during the next query. if channel, ok := c.chanCache.get(chanID); ok { - edge, ok := e.(*models.ChannelEdgePolicy1) - if !ok { - log.Errorf("expected *models.ChannelEdgePolicy1, "+ - "got: %T", e) - - return - } - if isUpdate1 { - channel.Policy1 = edge + channel.Policy1 = e } else { - channel.Policy2 = edge + channel.Policy2 = e } c.chanCache.insert(chanID, channel) @@ -3337,8 +3376,30 @@ func nodeTraversal(tx kvdb.RTx, nodePub []byte, db kvdb.Backend, return err } + var ( + in, out *models.ChannelEdgePolicy1 + ok bool + ) + if outgoingPolicy != nil { + out, ok = outgoingPolicy.(*models.ChannelEdgePolicy1) //nolint:lll + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgePolicy1, "+ + "got %T", outgoingPolicy) + } + } + + if incomingPolicy != nil { + in, ok = incomingPolicy.(*models.ChannelEdgePolicy1) //nolint:lll + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgePolicy1, "+ + "got %T", incomingPolicy) + } + } + // Finally, we execute the callback. - err = cb(tx, edgeInfo, outgoingPolicy, incomingPolicy) + err = cb(tx, edgeInfo, out, in) if err != nil { return err } @@ -3531,11 +3592,34 @@ func (c *ChannelGraph) FetchChannelEdgesByOutpoint(op *wire.OutPoint) ( // Once we have the information about the channels' parameters, // we'll fetch the routing policies for each for the directed // edges. - e1, e2, err := fetchChanEdgePolicies(edgeIndex, edges, chanID) + edge1, edge2, err := fetchChanEdgePolicies( + edgeIndex, edges, chanID, + ) if err != nil { return fmt.Errorf("failed to find policy: %w", err) } + var ( + e1, e2 *models.ChannelEdgePolicy1 + ok bool + ) + if edge1 != nil { + e1, ok = edge1.(*models.ChannelEdgePolicy1) + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgePolicy1, got %T", + edge1) + } + } + if edge2 != nil { + e2, ok = edge2.(*models.ChannelEdgePolicy1) + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgePolicy1, got %T", + edge1) + } + } + policy1 = e1 policy2 = e2 return nil @@ -3633,13 +3717,34 @@ func (c *ChannelGraph) FetchChannelEdgesByID(chanID uint64) ( // Then we'll attempt to fetch the accompanying policies of this // edge. - e1, e2, err := fetchChanEdgePolicies( + edge1, edge2, err := fetchChanEdgePolicies( edgeIndex, edges, channelID[:], ) if err != nil { return err } + var ( + e1, e2 *models.ChannelEdgePolicy1 + ok bool + ) + if edge1 != nil { + e1, ok = edge1.(*models.ChannelEdgePolicy1) + if !ok { + return fmt.Errorf("expecgted "+ + "*models.ChannelEdgePolicy1, got %T", + edge1) + } + } + if edge2 != nil { + e2, ok = edge2.(*models.ChannelEdgePolicy1) + if !ok { + return fmt.Errorf("expecgted "+ + "*models.ChannelEdgePolicy1, got %T", + edge1) + } + } + policy1 = e1 policy2 = e2 return nil diff --git a/channeldb/graph_cache.go b/channeldb/graph_cache.go index 526d81e5f0..86e73a3419 100644 --- a/channeldb/graph_cache.go +++ b/channeldb/graph_cache.go @@ -146,7 +146,19 @@ func (c *GraphCache) AddNode(tx kvdb.RTx, node GraphCacheNode) error { outPolicy *models.ChannelEdgePolicy1, inPolicy *models.ChannelEdgePolicy1) error { - c.AddChannel(info, outPolicy, inPolicy) + // TODO(elle): remove once the ForEachChannel call back + // passes down the interface values instead of the + // pointers. This is temporarily required to prevent + // a nil pointer dereference. + var in, out models.ChannelEdgePolicy + if outPolicy != nil { + out = outPolicy + } + if inPolicy != nil { + in = inPolicy + } + + c.AddChannel(info, out, in) return nil }, @@ -158,7 +170,7 @@ func (c *GraphCache) AddNode(tx kvdb.RTx, node GraphCacheNode) error { // and policy flags automatically. The policy will be set as the outgoing policy // on one node and the incoming policy on the peer's side. func (c *GraphCache) AddChannel(info models.ChannelEdgeInfo, policy1, - policy2 *models.ChannelEdgePolicy1) { + policy2 models.ChannelEdgePolicy) { if info == nil { return diff --git a/channeldb/graph_test.go b/channeldb/graph_test.go index afdd8bced1..ccb1bde95b 100644 --- a/channeldb/graph_test.go +++ b/channeldb/graph_test.go @@ -3393,8 +3393,11 @@ func TestEdgePolicyMissingMaxHtcl(t *testing.T) { edge1.MessageFlags = 0 edge1.ExtraOpaqueData = nil + encodingInfo, err := encodingInfoFromEdgePolicy(edge1) + require.NoError(t, err) + var b bytes.Buffer - err = serializeChanEdgePolicy(&b, edge1, to) + err = serializeChanEdgePolicy(&b, encodingInfo, to) if err != nil { t.Fatalf("unable to serialize policy") } @@ -3403,8 +3406,12 @@ func TestEdgePolicyMissingMaxHtcl(t *testing.T) { // will be the opaque data containing the serialized field. edge1.MessageFlags = lnwire.ChanUpdateRequiredMaxHtlc edge1.MaxHTLC = 13928598 + + encodingInfo, err = encodingInfoFromEdgePolicy(edge1) + require.NoError(t, err) + var b2 bytes.Buffer - err = serializeChanEdgePolicy(&b2, edge1, to) + err = serializeChanEdgePolicy(&b2, encodingInfo, to) if err != nil { t.Fatalf("unable to serialize policy") } diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index ac1dbf8c17..310bcf6f25 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -237,7 +237,14 @@ func (r *mockGraphSource) ForAllOutgoingChannels(cb func(tx kvdb.RTx, } for _, channel := range chans { - if err := cb(nil, channel.Info, channel.Policy1); err != nil { + pol, ok := channel.Policy1.(*models.ChannelEdgePolicy1) + if !ok { + return fmt.Errorf("expected "+ + "*models.ChannelEdgePolicy1, got %T", + channel.Policy1) + } + + if err := cb(nil, channel.Info, pol); err != nil { return err } } diff --git a/graph/builder.go b/graph/builder.go index b1b549e25b..fcca9ce880 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -525,7 +525,7 @@ func (b *Builder) pruneZombieChans() error { // First, we'll collect all the channels which are eligible for garbage // collection due to being zombies. filterPruneChans := func(info models.ChannelEdgeInfo, - e1, e2 *models.ChannelEdgePolicy1) error { + e1, e2 models.ChannelEdgePolicy) error { chanID := info.GetChanID() diff --git a/netann/channel_announcement.go b/netann/channel_announcement.go index 1d4342787b..386a2e96b2 100644 --- a/netann/channel_announcement.go +++ b/netann/channel_announcement.go @@ -34,9 +34,9 @@ const ( // structs for announcing new channels to other peers, or simply syncing up a // peer's initial routing table upon connect. func CreateChanAnnouncement(chanProof models.ChannelAuthProof, - chanInfo models.ChannelEdgeInfo, e1, e2 *models.ChannelEdgePolicy1) ( - *lnwire.ChannelAnnouncement1, *lnwire.ChannelUpdate1, - *lnwire.ChannelUpdate1, error) { + chanInfo models.ChannelEdgeInfo, edge1, + edge2 models.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement1, + *lnwire.ChannelUpdate1, *lnwire.ChannelUpdate1, error) { switch proof := chanProof.(type) { case *models.ChannelAuthProof1: @@ -47,6 +47,27 @@ func CreateChanAnnouncement(chanProof models.ChannelAuthProof, "ChannelAuthProof1, got: %T", chanInfo) } + var e1, e2 *models.ChannelEdgePolicy1 + if edge1 != nil { + e1, ok = edge1.(*models.ChannelEdgePolicy1) + if !ok { + return nil, nil, nil, fmt.Errorf("expected "+ + "type ChannelEdgePolicy1 to be "+ + "paired with ChannelEdgeInfo1, "+ + "got: %T", edge1) + } + } + + if edge2 != nil { + e2, ok = edge2.(*models.ChannelEdgePolicy1) + if !ok { + return nil, nil, nil, fmt.Errorf("expected "+ + "type ChannelEdgePolicy1 to be "+ + "paired with ChannelEdgeInfo1, "+ + "got: %T", edge2) + } + } + return createChanAnnouncement1(proof, info, e1, e2) default: From dd4c935d2843b634328bd1b763b66c271aca088e Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 23 Aug 2024 10:32:13 +0200 Subject: [PATCH 20/60] multi: updates to HasChannelPolicy --- channeldb/graph.go | 191 +++++++++++++++++++++++++++++++++++++++- channeldb/graph_test.go | 10 +-- graph/builder.go | 12 +-- graph/builder_test.go | 30 +++---- graph/interfaces.go | 12 +-- 5 files changed, 216 insertions(+), 39 deletions(-) diff --git a/channeldb/graph.go b/channeldb/graph.go index 400e5ab099..5da02b1e7c 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -1157,13 +1157,84 @@ func (c *ChannelGraph) addChannelEdge(tx kvdb.RwTx, return chanIndex.Put(b.Bytes(), chanKey[:]) } -// HasChannelEdge returns true if the database knows of a channel edge with the +func (c *ChannelGraph) HasChannelEdge(chanID uint64) (bool, bool, error) { + var ( + exists bool + isZombie bool + ) + + // We'll query the cache with the shared lock held to allow multiple + // readers to access values in the cache concurrently if they exist. + c.cacheMu.RLock() + if entry, ok := c.rejectCache.get(chanID); ok { + c.cacheMu.RUnlock() + exists, isZombie = entry.flags.unpack() + + return exists, isZombie, nil + } + c.cacheMu.RUnlock() + + c.cacheMu.Lock() + defer c.cacheMu.Unlock() + + // The item was not found with the shared lock, so we'll acquire the + // exclusive lock and check the cache again in case another method added + // the entry to the cache while no lock was held. + if entry, ok := c.rejectCache.get(chanID); ok && entry.times != nil { + exists, isZombie = entry.flags.unpack() + + return exists, isZombie, nil + } + + if err := kvdb.View(c.db, func(tx kvdb.RTx) error { + edges := tx.ReadBucket(edgeBucket) + if edges == nil { + return ErrGraphNoEdgesFound + } + edgeIndex := edges.NestedReadBucket(edgeIndexBucket) + if edgeIndex == nil { + return ErrGraphNoEdgesFound + } + + var channelID [8]byte + byteOrder.PutUint64(channelID[:], chanID) + + // If the edge doesn't exist, then we'll also check our zombie + // index. + if edgeIndex.Get(channelID[:]) == nil { + exists = false + zombieIndex := edges.NestedReadBucket(zombieBucket) + if zombieIndex != nil { + isZombie, _, _ = isZombieEdge( + zombieIndex, chanID, + ) + } + + return nil + } + + exists = true + isZombie = false + + return nil + }, func() {}); err != nil { + return exists, isZombie, err + } + + c.rejectCache.insert(chanID, rejectCacheEntry{ + flags: packRejectFlags(exists, isZombie), + }) + + return exists, isZombie, nil +} + +// HasChannelEdge1 returns true if the database knows of a channel edge with the // passed channel ID, and false otherwise. If an edge with that ID is found // within the graph, then two time stamps representing the last time the edge // was updated for both directed edges are returned along with the boolean. If // it is not found, then the zombie index is checked and its result is returned // as the second boolean. -func (c *ChannelGraph) HasChannelEdge( +func (c *ChannelGraph) HasChannelEdge1( chanID uint64) (time.Time, time.Time, bool, bool, error) { var ( @@ -1279,6 +1350,122 @@ func (c *ChannelGraph) HasChannelEdge( return upd1Time, upd2Time, exists, isZombie, nil } +func (c *ChannelGraph) HasChannelEdge2( + chanID uint64) (uint32, uint32, bool, bool, error) { + + var ( + upd1Height uint32 + upd2Height uint32 + exists bool + isZombie bool + ) + + // We'll query the cache with the shared lock held to allow multiple + // readers to access values in the cache concurrently if they exist. + c.cacheMu.RLock() + if entry, ok := c.rejectCache.get(chanID); ok && entry.blocks != nil { + c.cacheMu.RUnlock() + exists, isZombie = entry.flags.unpack() + + return entry.blocks.updBlock1, entry.blocks.updBlock2, exists, + isZombie, nil + } + c.cacheMu.RUnlock() + + c.cacheMu.Lock() + defer c.cacheMu.Unlock() + + // The item was not found with the shared lock, so we'll acquire the + // exclusive lock and check the cache again in case another method added + // the entry to the cache while no lock was held. + if entry, ok := c.rejectCache.get(chanID); ok && entry.blocks != nil { + exists, isZombie = entry.flags.unpack() + + return entry.blocks.updBlock1, entry.blocks.updBlock2, exists, + isZombie, nil + } + + if err := kvdb.View(c.db, func(tx kvdb.RTx) error { + edges := tx.ReadBucket(edgeBucket) + if edges == nil { + return ErrGraphNoEdgesFound + } + edgeIndex := edges.NestedReadBucket(edgeIndexBucket) + if edgeIndex == nil { + return ErrGraphNoEdgesFound + } + + var channelID [8]byte + byteOrder.PutUint64(channelID[:], chanID) + + // If the edge doesn't exist, then we'll also check our zombie + // index. + if edgeIndex.Get(channelID[:]) == nil { + exists = false + zombieIndex := edges.NestedReadBucket(zombieBucket) + if zombieIndex != nil { + isZombie, _, _ = isZombieEdge( + zombieIndex, chanID, + ) + } + + return nil + } + + exists = true + isZombie = false + + // If the channel has been found in the graph, then retrieve + // the edges itself so we can return the last updated + // timestamps. + nodes := tx.ReadBucket(nodeBucket) + if nodes == nil { + return ErrGraphNodeNotFound + } + + edge1, edge2, err := fetchChanEdgePolicies( + edgeIndex, edges, channelID[:], + ) + if err != nil { + return err + } + + // As we may have only one of the edges populated, only set the + // update time if the edge was found in the database. + if edge1 != nil { + e1, ok := edge1.(*models.ChannelEdgePolicy2) + if !ok { + return fmt.Errorf("expected "+ + "*ChannelEdgePolicy2, got: %T", edge1) + } + upd1Height = e1.BlockHeight.Val + } + if edge2 != nil { + e2, ok := edge2.(*models.ChannelEdgePolicy2) + if !ok { + return fmt.Errorf("expected "+ + "*ChannelEdgePolicy2, got: %T", edge2) + } + + upd2Height = e2.BlockHeight.Val + } + + return nil + }, func() {}); err != nil { + return 0, 0, exists, isZombie, err + } + + c.rejectCache.insert(chanID, rejectCacheEntry{ + blocks: &updateBlocks{ + updBlock1: upd1Height, + updBlock2: upd2Height, + }, + flags: packRejectFlags(exists, isZombie), + }) + + return upd1Height, upd2Height, exists, isZombie, nil +} + // UpdateChannelEdge retrieves and update edge of the graph database. Method // only reserved for updating an edge info after its already been created. // In order to maintain this constraints, we return an error in the scenario diff --git a/channeldb/graph_test.go b/channeldb/graph_test.go index ccb1bde95b..f2341d7ac7 100644 --- a/channeldb/graph_test.go +++ b/channeldb/graph_test.go @@ -517,7 +517,7 @@ func TestDisconnectBlockAtHeight(t *testing.T) { } // The two first edges should be removed from the db. - _, _, has, isZombie, err := graph.HasChannelEdge(edgeInfo.ChannelID) + has, isZombie, err := graph.HasChannelEdge(edgeInfo.ChannelID) require.NoError(t, err, "unable to query for edge") if has { t.Fatalf("edge1 was not pruned from the graph") @@ -525,7 +525,7 @@ func TestDisconnectBlockAtHeight(t *testing.T) { if isZombie { t.Fatal("reorged edge1 should not be marked as zombie") } - _, _, has, isZombie, err = graph.HasChannelEdge(edgeInfo2.ChannelID) + has, isZombie, err = graph.HasChannelEdge(edgeInfo2.ChannelID) require.NoError(t, err, "unable to query for edge") if has { t.Fatalf("edge2 was not pruned from the graph") @@ -535,7 +535,7 @@ func TestDisconnectBlockAtHeight(t *testing.T) { } // Edge 3 should not be removed. - _, _, has, isZombie, err = graph.HasChannelEdge(edgeInfo3.ChannelID) + has, isZombie, err = graph.HasChannelEdge(edgeInfo3.ChannelID) require.NoError(t, err, "unable to query for edge") if !has { t.Fatalf("edge3 was pruned from the graph") @@ -759,7 +759,7 @@ func TestEdgeInfoUpdates(t *testing.T) { // Check for existence of the edge within the database, it should be // found. - _, _, found, isZombie, err := graph.HasChannelEdge(chanID) + found, isZombie, err := graph.HasChannelEdge(chanID) require.NoError(t, err, "unable to query for edge") if !found { t.Fatalf("graph should have of inserted edge") @@ -2283,7 +2283,7 @@ func TestStressTestChannelGraphAPI(t *testing.T) { return nil } - _, _, _, _, err := graph.HasChannelEdge( + _, _, err := graph.HasChannelEdge( channel.id.ToUint64(), ) diff --git a/graph/builder.go b/graph/builder.go index fcca9ce880..f1832a89c6 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -1147,9 +1147,7 @@ func (b *Builder) processUpdate(msg interface{}, // Prior to processing the announcement we first check if we // already know of this channel, if so, then we can exit early. - _, _, exists, isZombie, err := b.cfg.Graph.HasChannelEdge( - chanID, - ) + exists, isZombie, err := b.cfg.Graph.HasChannelEdge(chanID) if err != nil && !errors.Is(err, channeldb.ErrGraphNoEdgesFound) { @@ -1339,7 +1337,7 @@ func (b *Builder) processUpdate(msg interface{}, defer b.channelEdgeMtx.Unlock(msg.ChannelID) edge1Timestamp, edge2Timestamp, exists, isZombie, err := - b.cfg.Graph.HasChannelEdge(msg.ChannelID) + b.cfg.Graph.HasChannelEdge1(msg.ChannelID) if err != nil && !errors.Is( err, channeldb.ErrGraphNoEdgesFound, ) { @@ -1684,9 +1682,7 @@ func (b *Builder) IsPublicNode(node route.Vertex) (bool, error) { // // NOTE: This method is part of the ChannelGraphSource interface. func (b *Builder) IsKnownEdge(chanID lnwire.ShortChannelID) bool { - _, _, exists, isZombie, _ := b.cfg.Graph.HasChannelEdge( - chanID.ToUint64(), - ) + exists, isZombie, _ := b.cfg.Graph.HasChannelEdge(chanID.ToUint64()) return exists || isZombie } @@ -1699,7 +1695,7 @@ func (b *Builder) IsStaleEdgePolicy(chanID lnwire.ShortChannelID, timestamp time.Time, flags lnwire.ChanUpdateChanFlags) bool { edge1Timestamp, edge2Timestamp, exists, isZombie, err := - b.cfg.Graph.HasChannelEdge(chanID.ToUint64()) + b.cfg.Graph.HasChannelEdge1(chanID.ToUint64()) if err != nil { log.Debugf("Check stale edge policy got error: %v", err) return false diff --git a/graph/builder_test.go b/graph/builder_test.go index 280fcb2406..de3afaaabf 100644 --- a/graph/builder_test.go +++ b/graph/builder_test.go @@ -299,7 +299,7 @@ func TestWakeUpOnStaleBranch(t *testing.T) { } // Check that the fundingTxs are in the graph db. - _, _, has, isZombie, err := ctx.graph.HasChannelEdge(chanID1) + has, isZombie, err := ctx.graph.HasChannelEdge(chanID1) if err != nil { t.Fatalf("error looking for edge: %v", chanID1) } @@ -310,7 +310,7 @@ func TestWakeUpOnStaleBranch(t *testing.T) { t.Fatal("edge was marked as zombie") } - _, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID2) + has, isZombie, err = ctx.graph.HasChannelEdge(chanID2) if err != nil { t.Fatalf("error looking for edge: %v", chanID2) } @@ -367,7 +367,7 @@ func TestWakeUpOnStaleBranch(t *testing.T) { // The channel with chanID2 should not be in the database anymore, // since it is not confirmed on the longest chain. chanID1 should // still be. - _, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID1) + has, isZombie, err = ctx.graph.HasChannelEdge(chanID1) require.NoError(t, err) if !has { @@ -377,7 +377,7 @@ func TestWakeUpOnStaleBranch(t *testing.T) { t.Fatal("edge was marked as zombie") } - _, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID2) + has, isZombie, err = ctx.graph.HasChannelEdge(chanID2) if err != nil { t.Fatalf("error looking for edge: %v", chanID2) } @@ -506,7 +506,7 @@ func TestDisconnectedBlocks(t *testing.T) { } // Check that the fundingTxs are in the graph db. - _, _, has, isZombie, err := ctx.graph.HasChannelEdge(chanID1) + has, isZombie, err := ctx.graph.HasChannelEdge(chanID1) if err != nil { t.Fatalf("error looking for edge: %v", chanID1) } @@ -517,7 +517,7 @@ func TestDisconnectedBlocks(t *testing.T) { t.Fatal("edge was marked as zombie") } - _, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID2) + has, isZombie, err = ctx.graph.HasChannelEdge(chanID2) if err != nil { t.Fatalf("error looking for edge: %v", chanID2) } @@ -559,7 +559,7 @@ func TestDisconnectedBlocks(t *testing.T) { // chanID2 should not be in the database anymore, since it is not // confirmed on the longest chain. chanID1 should still be. - _, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID1) + has, isZombie, err = ctx.graph.HasChannelEdge(chanID1) if err != nil { t.Fatalf("error looking for edge: %v", chanID1) } @@ -570,7 +570,7 @@ func TestDisconnectedBlocks(t *testing.T) { t.Fatal("edge was marked as zombie") } - _, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID2) + has, isZombie, err = ctx.graph.HasChannelEdge(chanID2) if err != nil { t.Fatalf("error looking for edge: %v", chanID2) } @@ -633,7 +633,7 @@ func TestRouterChansClosedOfflinePruneGraph(t *testing.T) { } // The router should now be aware of the channel we created above. - _, _, hasChan, isZombie, err := ctx.graph.HasChannelEdge( + hasChan, isZombie, err := ctx.graph.HasChannelEdge( chanID1.ToUint64(), ) if err != nil { @@ -715,9 +715,7 @@ func TestRouterChansClosedOfflinePruneGraph(t *testing.T) { // At this point, the channel that was pruned should no longer be known // by the router. - _, _, hasChan, isZombie, err = ctx.graph.HasChannelEdge( - chanID1.ToUint64(), - ) + hasChan, isZombie, err = ctx.graph.HasChannelEdge(chanID1.ToUint64()) if err != nil { t.Fatalf("error looking for edge: %v", chanID1) } @@ -1288,9 +1286,7 @@ func assertChanChainRejection(t *testing.T, ctx *testCtx, } // This channel should now be present in the zombie channel index. - _, _, _, isZombie, err := ctx.graph.HasChannelEdge( - edge.ChannelID, - ) + _, isZombie, err := ctx.graph.HasChannelEdge(edge.ChannelID) require.Nil(t, err) require.True(t, isZombie, "edge should be marked as zombie") } @@ -1768,9 +1764,7 @@ func assertChannelsPruned(t *testing.T, graph *channeldb.ChannelGraph, for _, channel := range channels { _, shouldPrune := pruned[channel.ChannelID] - _, _, exists, isZombie, err := graph.HasChannelEdge( - channel.ChannelID, - ) + exists, isZombie, err := graph.HasChannelEdge(channel.ChannelID) if err != nil { t.Fatalf("unable to determine existence of "+ "channel=%v in the graph: %v", diff --git a/graph/interfaces.go b/graph/interfaces.go index fdce2cbfe7..640b48f8ff 100644 --- a/graph/interfaces.go +++ b/graph/interfaces.go @@ -172,12 +172,12 @@ type DB interface { DisconnectBlockAtHeight(height uint32) ([]models.ChannelEdgeInfo, error) // HasChannelEdge returns true if the database knows of a channel edge - // with the passed channel ID, and false otherwise. If an edge with that - // ID is found within the graph, then two time stamps representing the - // last time the edge was updated for both directed edges are returned - // along with the boolean. If it is not found, then the zombie index is - // checked and its result is returned as the second boolean. - HasChannelEdge(chanID uint64) (time.Time, time.Time, bool, bool, error) + // with the passed channel ID, and false otherwise. If an edge is not + // found, then the zombie index is checked and its result is returned as + // the second boolean. + HasChannelEdge(chanID uint64) (bool, bool, error) + + HasChannelEdge1(chanID uint64) (time.Time, time.Time, bool, bool, error) // FetchChannelEdgesByID attempts to lookup the two directed edges for // the channel identified by the channel ID. If the channel can't be From e99a00f5b71bd0eb36950e770903e83ec7c381aa Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 23 Aug 2024 10:33:08 +0200 Subject: [PATCH 21/60] docs: update release notes --- docs/release-notes/release-notes-0.19.0.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/release-notes/release-notes-0.19.0.md b/docs/release-notes/release-notes-0.19.0.md index 3b45b46464..f712d54dae 100644 --- a/docs/release-notes/release-notes-0.19.0.md +++ b/docs/release-notes/release-notes-0.19.0.md @@ -71,6 +71,9 @@ * Add new [channeldb](https://github.com/lightningnetwork/lnd/pull/8164) types required for the Gossip 1.75 protocol. +* Use the new interfaces added for Gossip 1.75 throughout the codebase + [1](https://github.com/lightningnetwork/lnd/pull/8252/). + ## Testing ## Database From d383a446d5ad168c12e3751b5053ca163adbf71b Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 6 Dec 2023 10:15:08 +0200 Subject: [PATCH 22/60] multi: use models.ChannelAuthProof interface where possible --- discovery/gossiper.go | 40 +++++++++++++++++++++++++++++++------- discovery/gossiper_test.go | 2 +- graph/builder.go | 2 +- graph/interfaces.go | 2 +- 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/discovery/gossiper.go b/discovery/gossiper.go index d5db46f68b..f9804e7fcd 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -1865,7 +1865,7 @@ func remotePubFromChanInfo(chanInfo models.ChannelEdgeInfo, // assemble the proof and craft the ChannelAnnouncement. func (d *AuthenticatedGossiper) processRejectedEdge( chanAnnMsg *lnwire.ChannelAnnouncement1, - proof *models.ChannelAuthProof1) ([]networkMsg, error) { + proof models.ChannelAuthProof) ([]networkMsg, error) { // First, we'll fetch the state of the channel as we know if from the // database. @@ -2567,7 +2567,7 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg, // If this is a remote channel announcement, then we'll validate all // the signatures within the proof as it should be well formed. - var proof *models.ChannelAuthProof1 + var proof models.ChannelAuthProof if nMsg.isRemote { err := netann.ValidateChannelAnn(ann, d.fetchPKScript) if err != nil { @@ -2588,11 +2588,14 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg, // If the proof checks out, then we'll save the proof itself to // the database so we can fetch it later when gossiping with // other nodes. - proof = &models.ChannelAuthProof1{ - NodeSig1Bytes: ann.NodeSig1.ToSignatureBytes(), - NodeSig2Bytes: ann.NodeSig2.ToSignatureBytes(), - BitcoinSig1Bytes: ann.BitcoinSig1.ToSignatureBytes(), - BitcoinSig2Bytes: ann.BitcoinSig2.ToSignatureBytes(), + proof, err = buildChanProof(ann) + if err != nil { + err := fmt.Errorf("unable to build channel "+ + "announcement proof: %v", err) + log.Error(err) + nMsg.err <- err + + return nil, false } } @@ -3591,6 +3594,29 @@ func (d *AuthenticatedGossiper) ShouldDisconnect(pubkey *btcec.PublicKey) ( return false, nil } +func buildChanProof(ann lnwire.ChannelAnnouncement) ( + models.ChannelAuthProof, error) { + + switch a := ann.(type) { + case *lnwire.ChannelAnnouncement1: + return &models.ChannelAuthProof1{ + NodeSig1Bytes: a.NodeSig1.ToSignatureBytes(), + NodeSig2Bytes: a.NodeSig2.ToSignatureBytes(), + BitcoinSig1Bytes: a.BitcoinSig1.ToSignatureBytes(), + BitcoinSig2Bytes: a.BitcoinSig2.ToSignatureBytes(), + }, nil + + case *lnwire.ChannelAnnouncement2: + return &models.ChannelAuthProof2{ + SchnorrSigBytes: a.Signature.ToSignatureBytes(), + }, nil + + default: + return nil, fmt.Errorf("unhandled lnwire.ChannelAnnouncement "+ + "implementation: %T", a) + } +} + // buildEdgeInfo builds constructs an appropriate models.ChannelEdgeInfo using // the given lnwire.ChannelAnnouncement and some optional fields. func (d *AuthenticatedGossiper) buildEdgeInfo(ann lnwire.ChannelAnnouncement, diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index 310bcf6f25..0f5524939f 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -186,7 +186,7 @@ func (r *mockGraphSource) CurrentBlockHeight() (uint32, error) { } func (r *mockGraphSource) AddProof(chanID lnwire.ShortChannelID, - proof *models.ChannelAuthProof1) error { + proof models.ChannelAuthProof) error { r.mu.Lock() defer r.mu.Unlock() diff --git a/graph/builder.go b/graph/builder.go index f1832a89c6..0ccf60aa69 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -1636,7 +1636,7 @@ func (b *Builder) ForAllOutgoingChannels(cb func(kvdb.RTx, // // NOTE: This method is part of the ChannelGraphSource interface. func (b *Builder) AddProof(chanID lnwire.ShortChannelID, - proof *models.ChannelAuthProof1) error { + proof models.ChannelAuthProof) error { info, _, _, err := b.cfg.Graph.FetchChannelEdgesByID(chanID.ToUint64()) if err != nil { diff --git a/graph/interfaces.go b/graph/interfaces.go index 640b48f8ff..09ab5f6a02 100644 --- a/graph/interfaces.go +++ b/graph/interfaces.go @@ -35,7 +35,7 @@ type ChannelGraphSource interface { // AddProof updates the channel edge info with proof which is needed to // properly announce the edge to the rest of the network. AddProof(chanID lnwire.ShortChannelID, - proof *models.ChannelAuthProof1) error + proof models.ChannelAuthProof) error // UpdateEdge is used to update edge information, without this message // edge considered as not fully constructed. From 12a7c029d5642762ee6acdaa450bcd7aa76eb46a Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 6 Dec 2023 14:19:03 +0200 Subject: [PATCH 23/60] netann: update Ann creation funcs to take interfaces --- discovery/chan_series.go | 14 ++++- netann/channel_announcement.go | 93 ++++++++++++++++++++++++++++++++-- netann/channel_update.go | 31 +++++++----- 3 files changed, 119 insertions(+), 19 deletions(-) diff --git a/discovery/chan_series.go b/discovery/chan_series.go index f37ba5fd81..c8abedb2c0 100644 --- a/discovery/chan_series.go +++ b/discovery/chan_series.go @@ -3,6 +3,7 @@ package discovery import ( "time" + "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/lnwire" @@ -132,11 +133,18 @@ func (c *ChanSeries) UpdatesInHorizon(chain chainhash.Hash, return nil, err } + var capacity btcutil.Amount + if ann, ok := chanAnn.(*lnwire.ChannelAnnouncement2); ok { + capacity = btcutil.Amount(ann.Capacity.Val) + } + updates = append(updates, chanAnn) if edge1 != nil { // We don't want to send channel updates that don't // conform to the spec (anymore). - err := netann.ValidateChannelUpdateFields(0, edge1) + err := netann.ValidateChannelUpdateFields( + capacity, edge1, + ) if err != nil { log.Errorf("not sending invalid channel "+ "update %v: %v", edge1, err) @@ -145,7 +153,9 @@ func (c *ChanSeries) UpdatesInHorizon(chain chainhash.Hash, } } if edge2 != nil { - err := netann.ValidateChannelUpdateFields(0, edge2) + err := netann.ValidateChannelUpdateFields( + capacity, edge2, + ) if err != nil { log.Errorf("not sending invalid channel "+ "update %v: %v", edge2, err) diff --git a/netann/channel_announcement.go b/netann/channel_announcement.go index 386a2e96b2..345770d058 100644 --- a/netann/channel_announcement.go +++ b/netann/channel_announcement.go @@ -34,9 +34,9 @@ const ( // structs for announcing new channels to other peers, or simply syncing up a // peer's initial routing table upon connect. func CreateChanAnnouncement(chanProof models.ChannelAuthProof, - chanInfo models.ChannelEdgeInfo, edge1, - edge2 models.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement1, - *lnwire.ChannelUpdate1, *lnwire.ChannelUpdate1, error) { + chanInfo models.ChannelEdgeInfo, + edge1, edge2 models.ChannelEdgePolicy) (lnwire.ChannelAnnouncement, + lnwire.ChannelUpdate, lnwire.ChannelUpdate, error) { switch proof := chanProof.(type) { case *models.ChannelAuthProof1: @@ -70,6 +70,37 @@ func CreateChanAnnouncement(chanProof models.ChannelAuthProof, return createChanAnnouncement1(proof, info, e1, e2) + case *models.ChannelAuthProof2: + info, ok := chanInfo.(*models.ChannelEdgeInfo2) + if !ok { + return nil, nil, nil, fmt.Errorf("expected type "+ + "ChannelEdgeInfo2 to be paired with "+ + "ChannelAuthProof2, got: %T", chanInfo) + } + + var e1, e2 *models.ChannelEdgePolicy2 + if edge1 != nil { + e1, ok = edge1.(*models.ChannelEdgePolicy2) + if !ok { + return nil, nil, nil, fmt.Errorf("expected "+ + "type ChannelEdgePolicy2 to be "+ + "paired with ChannelEdgeInfo2, "+ + "got: %T", edge1) + } + } + + if edge2 != nil { + e2, ok = edge2.(*models.ChannelEdgePolicy2) + if !ok { + return nil, nil, nil, fmt.Errorf("expected "+ + "type ChannelEdgePolicy2 to be "+ + "paired with ChannelEdgeInfo2, "+ + "got: %T", edge2) + } + } + + return createChanAnnouncement2(proof, info, e1, e2) + default: return nil, nil, nil, fmt.Errorf("unhandled "+ "models.ChannelAuthProof type: %T", chanProof) @@ -79,7 +110,7 @@ func CreateChanAnnouncement(chanProof models.ChannelAuthProof, func createChanAnnouncement1(chanProof *models.ChannelAuthProof1, chanInfo *models.ChannelEdgeInfo1, e1, e2 *models.ChannelEdgePolicy1) (*lnwire.ChannelAnnouncement1, - *lnwire.ChannelUpdate1, *lnwire.ChannelUpdate1, error) { + lnwire.ChannelUpdate, lnwire.ChannelUpdate, error) { // First, using the parameters of the channel, along with the channel // authentication chanProof, we'll create re-create the original @@ -132,7 +163,59 @@ func createChanAnnouncement1(chanProof *models.ChannelAuthProof1, // Since it's up to a node's policy as to whether they advertise the // edge in a direction, we don't create an advertisement if the edge is // nil. - var edge1Ann, edge2Ann *lnwire.ChannelUpdate1 + var edge1Ann, edge2Ann lnwire.ChannelUpdate + if e1 != nil { + edge1Ann, err = ChannelUpdateFromEdge(chanInfo, e1) + if err != nil { + return nil, nil, nil, err + } + } + if e2 != nil { + edge2Ann, err = ChannelUpdateFromEdge(chanInfo, e2) + if err != nil { + return nil, nil, nil, err + } + } + + return chanAnn, edge1Ann, edge2Ann, nil +} + +func createChanAnnouncement2(chanProof *models.ChannelAuthProof2, + chanInfo *models.ChannelEdgeInfo2, + e1, e2 *models.ChannelEdgePolicy2) (lnwire.ChannelAnnouncement, + lnwire.ChannelUpdate, lnwire.ChannelUpdate, error) { + + // First, using the parameters of the channel, along with the channel + // authentication chanProof, we'll create re-create the original + // authenticated channel announcement. + chanAnn := &lnwire.ChannelAnnouncement2{ + ShortChannelID: chanInfo.ShortChannelID, + NodeID1: chanInfo.NodeID1, + NodeID2: chanInfo.NodeID2, + ChainHash: chanInfo.ChainHash, + BitcoinKey1: chanInfo.BitcoinKey1, + BitcoinKey2: chanInfo.BitcoinKey2, + Features: chanInfo.Features, + Capacity: chanInfo.Capacity, + ExtraOpaqueData: chanInfo.ExtraOpaqueData, + } + + var err error + chanAnn.Signature, err = lnwire.NewSigFromSchnorrRawSignature( + chanProof.SchnorrSigBytes, + ) + if err != nil { + return nil, nil, nil, err + } + + // We'll unconditionally queue the channel's existence chanProof as it + // will need to be processed before either of the channel update + // networkMsgs. + + // Since it's up to a node's policy as to whether they advertise the + // edge in a direction, we don't create an advertisement if the edge is + // nil. + var edge1Ann, edge2Ann lnwire.ChannelUpdate if e1 != nil { edge1Ann, err = ChannelUpdateFromEdge(chanInfo, e1) if err != nil { diff --git a/netann/channel_update.go b/netann/channel_update.go index 66494054a6..1df89527d0 100644 --- a/netann/channel_update.go +++ b/netann/channel_update.go @@ -169,22 +169,29 @@ func unsignedChanPolicy1ToUpdate(chainHash chainhash.Hash, // ChannelUpdateFromEdge reconstructs a signed ChannelUpdate from the given // edge info and policy. func ChannelUpdateFromEdge(info models.ChannelEdgeInfo, - policy *models.ChannelEdgePolicy1) (*lnwire.ChannelUpdate1, error) { + policy models.ChannelEdgePolicy) (*lnwire.ChannelUpdate1, error) { - sig, err := policy.Signature() - if err != nil { - return nil, err - } + switch p := policy.(type) { + case *models.ChannelEdgePolicy1: + sig, err := p.Signature() + if err != nil { + return nil, err + } - s, err := lnwire.NewSigFromSignature(sig) - if err != nil { - return nil, err - } + s, err := lnwire.NewSigFromSignature(sig) + if err != nil { + return nil, err + } + + update := unsignedChanPolicy1ToUpdate(info.GetChainHash(), p) + update.Signature = s - update := unsignedChanPolicy1ToUpdate(info.GetChainHash(), policy) - update.Signature = s + return update, nil - return update, nil + default: + return nil, fmt.Errorf("unhandled implementation of the "+ + "models.ChanelEdgePolicy interface: %T", policy) + } } // ValidateChannelUpdateAnn validates the channel update announcement by From e070ee39cf522a3fd013824bdffd80c8693ad556 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 6 Nov 2023 14:30:48 +0200 Subject: [PATCH 24/60] multi: use lnwire.ChannelAnnouncement interface where possible --- discovery/gossiper.go | 64 ++++++++++++++++++++----------------- discovery/gossiper_test.go | 2 +- discovery/syncer.go | 13 ++++---- funding/manager.go | 2 +- funding/manager_test.go | 2 +- graph/validation_barrier.go | 25 ++++++++------- peer/brontide.go | 5 +-- 7 files changed, 62 insertions(+), 51 deletions(-) diff --git a/discovery/gossiper.go b/discovery/gossiper.go index f9804e7fcd..8e5eba2e4b 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -863,13 +863,16 @@ func (d *AuthenticatedGossiper) ProcessRemoteAnnouncement(msg lnwire.Message, // To avoid inserting edges in the graph for our own channels that we // have already closed, we ignore such channel announcements coming // from the remote. - case *lnwire.ChannelAnnouncement1: + case lnwire.ChannelAnnouncement: ownKey := d.selfKey.SerializeCompressed() - ownErr := fmt.Errorf("ignoring remote ChannelAnnouncement1 " + + ownErr := fmt.Errorf("ignoring remote ChannelAnnouncement " + "for own channel") - if bytes.Equal(m.NodeID1[:], ownKey) || - bytes.Equal(m.NodeID2[:], ownKey) { + node1 := m.Node1KeyBytes() + node2 := m.Node2KeyBytes() + + if bytes.Equal(node1[:], ownKey) || + bytes.Equal(node2[:], ownKey) { log.Warn(ownErr) errChan <- ownErr @@ -1025,8 +1028,8 @@ func (d *deDupedAnnouncements) addMsg(message networkMsg) { switch msg := message.msg.(type) { // Channel announcements are identified by the short channel id field. - case *lnwire.ChannelAnnouncement1: - deDupKey := msg.ShortChannelID + case lnwire.ChannelAnnouncement: + deDupKey := msg.SCID() sender := route.NewVertex(message.source) mws, ok := d.channelAnnouncements[deDupKey] @@ -1607,8 +1610,8 @@ func (d *AuthenticatedGossiper) isRecentlyRejectedMsg(msg lnwire.Message, case *lnwire.ChannelUpdate1: scid = m.ShortChannelID.ToUint64() - case *lnwire.ChannelAnnouncement1: - scid = m.ShortChannelID.ToUint64() + case lnwire.ChannelAnnouncement: + scid = m.SCID().ToUint64() default: return false @@ -1864,14 +1867,14 @@ func remotePubFromChanInfo(chanInfo models.ChannelEdgeInfo, // to receive the remote peer's proof, while the remote peer is able to fully // assemble the proof and craft the ChannelAnnouncement. func (d *AuthenticatedGossiper) processRejectedEdge( - chanAnnMsg *lnwire.ChannelAnnouncement1, + chanAnnMsg lnwire.ChannelAnnouncement, proof models.ChannelAuthProof) ([]networkMsg, error) { + scid := chanAnnMsg.SCID() + // First, we'll fetch the state of the channel as we know if from the // database. - chanInfo, e1, e2, err := d.cfg.Graph.GetChannelByID( - chanAnnMsg.ShortChannelID, - ) + chanInfo, e1, e2, err := d.cfg.Graph.GetChannelByID(scid) if err != nil { return nil, err } @@ -1901,19 +1904,19 @@ func (d *AuthenticatedGossiper) processRejectedEdge( err = netann.ValidateChannelAnn(chanAnn, d.fetchPKScript) if err != nil { err := fmt.Errorf("assembled channel announcement proof "+ - "for shortChanID=%v isn't valid: %v", - chanAnnMsg.ShortChannelID, err) + "for shortChanID=%v isn't valid: %v", scid, err) log.Error(err) return nil, err } // If everything checks out, then we'll add the fully assembled proof // to the database. - err = d.cfg.Graph.AddProof(chanAnnMsg.ShortChannelID, proof) + err = d.cfg.Graph.AddProof(scid, proof) if err != nil { err := fmt.Errorf("unable add proof to shortChanID=%v: %w", - chanAnnMsg.ShortChannelID, err) + scid, err) log.Error(err) + return nil, err } @@ -2056,7 +2059,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement( // *creation* of a new channel within the network. This only advertises // the existence of a channel and not yet the routing policies in // either direction of the channel. - case *lnwire.ChannelAnnouncement1: + case lnwire.ChannelAnnouncement: return d.handleChanAnnouncement(nMsg, msg, schedulerOp) // A new authenticated channel edge update has arrived. This indicates @@ -2218,7 +2221,7 @@ func (d *AuthenticatedGossiper) isMsgStale(msg lnwire.Message) bool { // updateChannel creates a new fully signed update for the channel, and updates // the underlying graph with the new state. func (d *AuthenticatedGossiper) updateChannel(edgeInfo models.ChannelEdgeInfo, - edge *models.ChannelEdgePolicy1) (*lnwire.ChannelAnnouncement1, + edge *models.ChannelEdgePolicy1) (lnwire.ChannelAnnouncement, *lnwire.ChannelUpdate1, error) { // Parse the unsigned edge into a channel update. @@ -2262,7 +2265,7 @@ func (d *AuthenticatedGossiper) updateChannel(edgeInfo models.ChannelEdgeInfo, // We'll also create the original channel announcement so the two can // be broadcast along side each other (if necessary), but only if we // have a full channel announcement for this channel. - var chanAnn *lnwire.ChannelAnnouncement1 + var chanAnn lnwire.ChannelAnnouncement if edgeInfo.GetAuthProof() != nil { switch info := edgeInfo.(type) { case *models.ChannelEdgeInfo1: @@ -2455,22 +2458,25 @@ func (d *AuthenticatedGossiper) handleNodeAnnouncement(nMsg *networkMsg, return announcements, true } +// handleChanAnnouncement processes a new channel announcement. // handleChanAnnouncement processes a new channel announcement. func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg, - ann *lnwire.ChannelAnnouncement1, + ann lnwire.ChannelAnnouncement, ops []batch.SchedulerOption) ([]networkMsg, bool) { - scid := ann.ShortChannelID + var ( + scid = ann.SCID() + chainHash = ann.GetChainHash() + ) - log.Debugf("Processing ChannelAnnouncement1: peer=%v, short_chan_id=%v", - nMsg.peer, scid.ToUint64()) + log.Debugf("Processing %s: peer=%v, short_chan_id=%v", + nMsg.msg.MsgType(), nMsg.peer, scid.ToUint64()) // We'll ignore any channel announcements that target any chain other // than the set of chains we know of. - if !bytes.Equal(ann.ChainHash[:], d.cfg.ChainHash[:]) { - err := fmt.Errorf("ignoring ChannelAnnouncement1 from chain=%v"+ - ", gossiper on chain=%v", ann.ChainHash, - d.cfg.ChainHash) + if !bytes.Equal(chainHash[:], d.cfg.ChainHash[:]) { + err := fmt.Errorf("ignoring %s from chain=%v, gossiper on "+ + "chain=%v", ann.MsgType(), chainHash, d.cfg.ChainHash) log.Errorf(err.Error()) key := newRejectCacheKey( @@ -2824,8 +2830,8 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg, nMsg.err <- nil - log.Debugf("Processed ChannelAnnouncement1: peer=%v, short_chan_id=%v", - nMsg.peer, scid.ToUint64()) + log.Debugf("Processed %s: peer=%v, short_chan_id=%v", + nMsg.msg.MsgType(), nMsg.peer, scid.ToUint64()) return announcements, true } diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index 0f5524939f..c328de59fd 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -2829,7 +2829,7 @@ func TestRetransmit(t *testing.T) { var chanAnn, chanUpd, nodeAnn int for _, msg := range anns { switch msg.(type) { - case *lnwire.ChannelAnnouncement1: + case lnwire.ChannelAnnouncement: chanAnn++ case *lnwire.ChannelUpdate1: chanUpd++ diff --git a/discovery/syncer.go b/discovery/syncer.go index 3043b39cd6..4da82cfdb5 100644 --- a/discovery/syncer.go +++ b/discovery/syncer.go @@ -1449,20 +1449,21 @@ func (g *GossipSyncer) FilterGossipMsgs(msgs ...msgWithSenders) { // For each channel announcement message, we'll only send this // message if the channel updates for the channel are between // our time range. - case *lnwire.ChannelAnnouncement1: + case lnwire.ChannelAnnouncement: + scid := msg.SCID() + // First, we'll check if the channel updates are in // this message batch. - chanUpdates, ok := chanUpdateIndex[msg.ShortChannelID] + chanUpdates, ok := chanUpdateIndex[scid] if !ok { // If not, we'll attempt to query the database // to see if we know of the updates. chanUpdates, err = g.cfg.channelSeries.FetchChanUpdates( - g.cfg.chainHash, msg.ShortChannelID, + g.cfg.chainHash, scid, ) if err != nil { - log.Warnf("no channel updates found for "+ - "short_chan_id=%v", - msg.ShortChannelID) + log.Warnf("no channel updates found "+ + "for short_chan_id=%v", scid) continue } } diff --git a/funding/manager.go b/funding/manager.go index 7299ba059b..a5eda040cd 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -4291,7 +4291,7 @@ func (f *Manager) ensureInitialForwardingPolicy(chanID lnwire.ChannelID, // chanAnnouncement encapsulates the two authenticated announcements that we // send out to the network after a new channel has been created locally. type chanAnnouncement struct { - chanAnn *lnwire.ChannelAnnouncement1 + chanAnn lnwire.ChannelAnnouncement chanUpdateAnn *lnwire.ChannelUpdate1 chanProof *lnwire.AnnounceSignatures1 } diff --git a/funding/manager_test.go b/funding/manager_test.go index 6876ba6874..8164070bd8 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -1212,7 +1212,7 @@ func assertChannelAnnouncements(t *testing.T, alice, bob *testNode, gotChannelUpdate := false for _, msg := range announcements { switch m := msg.(type) { - case *lnwire.ChannelAnnouncement1: + case lnwire.ChannelAnnouncement: gotChannelAnnouncement = true case *lnwire.ChannelUpdate1: diff --git a/graph/validation_barrier.go b/graph/validation_barrier.go index 7750617322..fcd40d0f2f 100644 --- a/graph/validation_barrier.go +++ b/graph/validation_barrier.go @@ -102,7 +102,8 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) { // ChannelUpdates for the same channel, or NodeAnnouncements of nodes // that are involved in this channel. This goes for both the wire // type,s and also the types that we use within the database. - case *lnwire.ChannelAnnouncement1: + case lnwire.ChannelAnnouncement: + scid := msg.SCID() // We ensure that we only create a new announcement signal iff, // one doesn't already exist, as there may be duplicate @@ -110,7 +111,7 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) { // ChannelAnnouncement has been validated. This will result in // all the dependent jobs being unlocked so they can finish // execution themselves. - if _, ok := v.chanAnnFinSignal[msg.ShortChannelID]; !ok { + if _, ok := v.chanAnnFinSignal[scid]; !ok { // We'll create the channel that we close after we // validate this announcement. All dependants will // point to this same channel, so they'll be unblocked @@ -120,11 +121,11 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) { deny: make(chan struct{}), } - v.chanAnnFinSignal[msg.ShortChannelID] = signals - v.chanEdgeDependencies[msg.ShortChannelID] = signals + v.chanAnnFinSignal[scid] = signals + v.chanEdgeDependencies[scid] = signals - v.nodeAnnDependencies[route.Vertex(msg.NodeID1)] = signals - v.nodeAnnDependencies[route.Vertex(msg.NodeID2)] = signals + v.nodeAnnDependencies[msg.Node1KeyBytes()] = signals + v.nodeAnnDependencies[msg.Node2KeyBytes()] = signals } case models.ChannelEdgeInfo: shortID := lnwire.NewShortChanIDFromInt(msg.GetChanID()) @@ -218,7 +219,7 @@ func (v *ValidationBarrier) WaitForDependants(job interface{}) error { case *lnwire.AnnounceSignatures1: // TODO(roasbeef): need to wait on chan ann? case models.ChannelEdgeInfo: - case *lnwire.ChannelAnnouncement1: + case lnwire.ChannelAnnouncement: } // Release the lock once the above read is finished. @@ -274,18 +275,20 @@ func (v *ValidationBarrier) SignalDependants(job interface{}, allow bool) { } delete(v.chanAnnFinSignal, shortID) } - case *lnwire.ChannelAnnouncement1: - finSignals, ok := v.chanAnnFinSignal[msg.ShortChannelID] + case lnwire.ChannelAnnouncement: + scid := msg.SCID() + + finSignals, ok := v.chanAnnFinSignal[scid] if ok { if allow { close(finSignals.allow) } else { close(finSignals.deny) } - delete(v.chanAnnFinSignal, msg.ShortChannelID) + delete(v.chanAnnFinSignal, scid) } - delete(v.chanEdgeDependencies, msg.ShortChannelID) + delete(v.chanEdgeDependencies, scid) // For all other job types, we'll delete the tracking entries from the // map, as if we reach this point, then all dependants have already diff --git a/peer/brontide.go b/peer/brontide.go index 5fb8453129..cd1fa53492 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -2039,6 +2039,7 @@ out: case *lnwire.ChannelUpdate1, *lnwire.ChannelAnnouncement1, + *lnwire.ChannelAnnouncement2, *lnwire.NodeAnnouncement, *lnwire.AnnounceSignatures1, *lnwire.GossipTimestampRange, @@ -2303,9 +2304,9 @@ func messageSummary(msg lnwire.Message) string { return fmt.Sprintf("chan_id=%v, short_chan_id=%v", msg.ChannelID, msg.ShortChannelID.ToUint64()) - case *lnwire.ChannelAnnouncement1: + case lnwire.ChannelAnnouncement: return fmt.Sprintf("chain_hash=%v, short_chan_id=%v", - msg.ChainHash, msg.ShortChannelID.ToUint64()) + msg.GetChainHash(), msg.SCID().ToUint64()) case *lnwire.ChannelUpdate1: return fmt.Sprintf("chain_hash=%v, short_chan_id=%v, "+ From 90873ce7def7e6311029a23fa6822d425624d624 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 6 Nov 2023 18:32:01 +0200 Subject: [PATCH 25/60] multi: use ChannelEdgePolicy interface where possible --- autopilot/graph.go | 8 +- channeldb/edge_policy.go | 2 +- channeldb/graph.go | 147 ++++---------- channeldb/graph_cache.go | 24 +-- channeldb/graph_cache_test.go | 4 +- channeldb/graph_test.go | 32 ++-- channeldb/models/channel_edge_policy.go | 4 + channeldb/models/interfaces.go | 2 + discovery/gossiper.go | 131 +++++++++---- discovery/gossiper_test.go | 22 +-- funding/manager.go | 16 +- funding/manager_test.go | 2 +- graph/builder.go | 94 ++++++++- graph/interfaces.go | 15 +- graph/notifications.go | 25 +-- graph/validation_barrier.go | 20 +- lnrpc/invoicesrpc/addinvoice.go | 2 +- lnrpc/invoicesrpc/addinvoice_test.go | 4 +- netann/chan_status_manager_test.go | 2 +- netann/channel_update.go | 11 +- netann/interface.go | 2 +- peer/brontide.go | 26 +-- routing/blindedpath/blinded_path.go | 28 ++- routing/blindedpath/blinded_path_test.go | 18 +- routing/localchans/manager.go | 234 +++++++++++++++-------- routing/localchans/manager_test.go | 6 +- routing/pathfind_test.go | 34 +++- routing/router_test.go | 79 ++++---- rpcserver.go | 25 +-- server.go | 7 +- 30 files changed, 620 insertions(+), 406 deletions(-) diff --git a/autopilot/graph.go b/autopilot/graph.go index b3653a4898..ffac3f3522 100644 --- a/autopilot/graph.go +++ b/autopilot/graph.go @@ -91,7 +91,7 @@ func (d *dbNode) Addrs() []net.Addr { func (d *dbNode) ForEachChannel(cb func(ChannelEdge) error) error { return d.db.ForEachNodeChannelTx(d.tx, d.node.PubKeyBytes, func(tx kvdb.RTx, ei models.ChannelEdgeInfo, ep, - _ *models.ChannelEdgePolicy1) error { + _ models.ChannelEdgePolicy) error { // Skip channels for which no outgoing edge policy is // available. @@ -106,16 +106,14 @@ func (d *dbNode) ForEachChannel(cb func(ChannelEdge) error) error { } node, err := d.db.FetchLightningNodeTx( - tx, ep.ToNode, + tx, ep.GetToNode(), ) if err != nil { return err } edge := ChannelEdge{ - ChanID: lnwire.NewShortChanIDFromInt( - ep.ChannelID, - ), + ChanID: ep.SCID(), Capacity: ei.GetCapacity(), Peer: &dbNode{ tx: tx, diff --git a/channeldb/edge_policy.go b/channeldb/edge_policy.go index cde4702021..57dbb0e77a 100644 --- a/channeldb/edge_policy.go +++ b/channeldb/edge_policy.go @@ -97,7 +97,7 @@ func encodingInfoFromEdgePolicy(policy models.ChannelEdgePolicy) ( } } -func putChanEdgePolicy(edges kvdb.RwBucket, edge *models.ChannelEdgePolicy1, +func putChanEdgePolicy(edges kvdb.RwBucket, edge models.ChannelEdgePolicy, from, to []byte) error { encodingInfo, err := encodingInfoFromEdgePolicy(edge) diff --git a/channeldb/graph.go b/channeldb/graph.go index 5da02b1e7c..cfe5484b1e 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -249,7 +249,7 @@ func NewChannelGraph(db kvdb.Backend, rejectCacheSize, chanCacheSize int, } err = g.ForEachChannel(func(info models.ChannelEdgeInfo, - policy1, policy2 *models.ChannelEdgePolicy1) error { + policy1, policy2 models.ChannelEdgePolicy) error { g.graphCache.AddChannel(info, policy1, policy2) @@ -275,10 +275,10 @@ type channelMapKey struct { // getChannelMap loads all channel edge policies from the database and stores // them in a map. func (c *ChannelGraph) getChannelMap(edges kvdb.RBucket) ( - map[channelMapKey]*models.ChannelEdgePolicy1, error) { + map[channelMapKey]models.ChannelEdgePolicy, error) { // Create a map to store all channel edge policies. - channelMap := make(map[channelMapKey]*models.ChannelEdgePolicy1) + channelMap := make(map[channelMapKey]models.ChannelEdgePolicy) err := kvdb.ForAll(edges, func(k, edgeBytes []byte) error { // Skip embedded buckets. @@ -321,13 +321,7 @@ func (c *ChannelGraph) getChannelMap(edges kvdb.RBucket) ( return err } - e, ok := edge.(*models.ChannelEdgePolicy1) - if !ok { - return fmt.Errorf("expected "+ - "*models.ChannelEdgePolicy1, got: %T", edge) - } - - channelMap[key] = e + channelMap[key] = edge return nil }) @@ -440,7 +434,7 @@ func (c *ChannelGraph) NewPathFindTx() (kvdb.RTx, error) { // for that particular channel edge routing policy will be passed into the // callback. func (c *ChannelGraph) ForEachChannel(cb func(models.ChannelEdgeInfo, - *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1) error) error { + models.ChannelEdgePolicy, models.ChannelEdgePolicy) error) error { return c.db.View(func(tx kvdb.RTx) error { edges := tx.ReadBucket(edgeBucket) @@ -510,7 +504,7 @@ func (c *ChannelGraph) ForEachNodeDirectedChannel(tx kvdb.RTx, } dbCallback := func(tx kvdb.RTx, e models.ChannelEdgeInfo, p1, - p2 *models.ChannelEdgePolicy1) error { + p2 models.ChannelEdgePolicy) error { var cachedInPolicy *models.CachedEdgePolicy if p2 != nil { @@ -521,11 +515,14 @@ func (c *ChannelGraph) ForEachNodeDirectedChannel(tx kvdb.RTx, var inboundFee lnwire.Fee if p1 != nil { - // Extract inbound fee. If there is a decoding error, - // skip this edge. - _, err := p1.ExtraOpaqueData.ExtractRecords(&inboundFee) - if err != nil { - return nil + // TODO(elle): add inbound fees to new messages! + if policy, ok := p1.(*models.ChannelEdgePolicy1); ok { + // Extract inbound fee. If there is a decoding error, + // skip this edge. + _, err := policy.ExtraOpaqueData.ExtractRecords(&inboundFee) + if err != nil { + return nil + } } } @@ -597,8 +594,8 @@ func (c *ChannelGraph) ForEachNodeCached(cb func(node route.Vertex, err := c.ForEachNodeChannelTx(tx, node.PubKeyBytes, func(tx kvdb.RTx, e models.ChannelEdgeInfo, - p1 *models.ChannelEdgePolicy1, - p2 *models.ChannelEdgePolicy1) error { + p1 models.ChannelEdgePolicy, + p2 models.ChannelEdgePolicy) error { toNodeCallback := func() route.Vertex { return node.PubKeyBytes @@ -3005,7 +3002,7 @@ func makeZombiePubkeys(info models.ChannelEdgeInfo, // updated, otherwise it's the second node's information. The node ordering is // determined by the lexicographical ordering of the identity public keys of the // nodes on either side of the channel. -func (c *ChannelGraph) UpdateEdgePolicy(edge *models.ChannelEdgePolicy1, +func (c *ChannelGraph) UpdateEdgePolicy(edge models.ChannelEdgePolicy, op ...batch.SchedulerOption) error { var ( @@ -3085,7 +3082,7 @@ func (c *ChannelGraph) updateEdgeCache(e models.ChannelEdgePolicy, // buckets using an existing database transaction. The returned boolean will be // true if the updated policy belongs to node1, and false if the policy belonged // to node2. -func updateEdgePolicy(tx kvdb.RwTx, edge *models.ChannelEdgePolicy1, +func updateEdgePolicy(tx kvdb.RwTx, edge models.ChannelEdgePolicy, graphCache *GraphCache) (bool, error) { edges := tx.ReadWriteBucket(edgeBucket) @@ -3100,7 +3097,7 @@ func updateEdgePolicy(tx kvdb.RwTx, edge *models.ChannelEdgePolicy1, // Create the channelID key be converting the channel ID // integer into a byte slice. var chanID [8]byte - byteOrder.PutUint64(chanID[:], edge.ChannelID) + byteOrder.PutUint64(chanID[:], edge.SCID().ToUint64()) // With the channel ID, we then fetch the value storing the two // nodes which connect this channel edge. @@ -3289,8 +3286,8 @@ func (c *ChannelGraph) isPublic(tx kvdb.RTx, nodePub route.Vertex, nodeIsPublic := false errDone := errors.New("done") err := c.ForEachNodeChannelTx(tx, nodePub, func(tx kvdb.RTx, - info models.ChannelEdgeInfo, _ *models.ChannelEdgePolicy1, - _ *models.ChannelEdgePolicy1) error { + info models.ChannelEdgeInfo, _ models.ChannelEdgePolicy, + _ models.ChannelEdgePolicy) error { // If this edge doesn't extend to the source node, we'll // terminate our search as we can now conclude that the node is @@ -3433,8 +3430,8 @@ func (n *graphCacheNode) Features() *lnwire.FeatureVector { // // Unknown policies are passed into the callback as nil values. func (n *graphCacheNode) ForEachChannel(tx kvdb.RTx, - cb func(kvdb.RTx, models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1) error) error { + cb func(kvdb.RTx, models.ChannelEdgeInfo, models.ChannelEdgePolicy, + models.ChannelEdgePolicy) error) error { return nodeTraversal(tx, n.pubKeyBytes[:], nil, cb) } @@ -3494,8 +3491,8 @@ func (c *ChannelGraph) HasLightningNode(nodePub [33]byte) (time.Time, bool, erro // nodeTraversal is used to traverse all channels of a node given by its // public key and passes channel information into the specified callback. func nodeTraversal(tx kvdb.RTx, nodePub []byte, db kvdb.Backend, - cb func(kvdb.RTx, models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1) error) error { + cb func(kvdb.RTx, models.ChannelEdgeInfo, models.ChannelEdgePolicy, + models.ChannelEdgePolicy) error) error { traversal := func(tx kvdb.RTx) error { edges := tx.ReadBucket(edgeBucket) @@ -3563,30 +3560,8 @@ func nodeTraversal(tx kvdb.RTx, nodePub []byte, db kvdb.Backend, return err } - var ( - in, out *models.ChannelEdgePolicy1 - ok bool - ) - if outgoingPolicy != nil { - out, ok = outgoingPolicy.(*models.ChannelEdgePolicy1) //nolint:lll - if !ok { - return fmt.Errorf("expected "+ - "*models.ChannelEdgePolicy1, "+ - "got %T", outgoingPolicy) - } - } - - if incomingPolicy != nil { - in, ok = incomingPolicy.(*models.ChannelEdgePolicy1) //nolint:lll - if !ok { - return fmt.Errorf("expected "+ - "*models.ChannelEdgePolicy1, "+ - "got %T", incomingPolicy) - } - } - // Finally, we execute the callback. - err = cb(tx, edgeInfo, out, in) + err = cb(tx, edgeInfo, outgoingPolicy, incomingPolicy) if err != nil { return err } @@ -3615,8 +3590,8 @@ func nodeTraversal(tx kvdb.RTx, nodePub []byte, db kvdb.Backend, // // Unknown policies are passed into the callback as nil values. func (c *ChannelGraph) ForEachNodeChannel(nodePub route.Vertex, - cb func(kvdb.RTx, models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1) error) error { + cb func(kvdb.RTx, models.ChannelEdgeInfo, models.ChannelEdgePolicy, + models.ChannelEdgePolicy) error) error { return nodeTraversal(nil, nodePub[:], c.db, cb) } @@ -3636,8 +3611,8 @@ func (c *ChannelGraph) ForEachNodeChannel(nodePub route.Vertex, // traversal. func (c *ChannelGraph) ForEachNodeChannelTx(tx kvdb.RTx, nodePub route.Vertex, cb func(kvdb.RTx, models.ChannelEdgeInfo, - *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1) error) error { + models.ChannelEdgePolicy, + models.ChannelEdgePolicy) error) error { return nodeTraversal(tx, nodePub[:], c.db, cb) } @@ -3724,13 +3699,13 @@ func computeEdgePolicyKeys(info models.ChannelEdgeInfo) ([]byte, []byte) { // information for the channel itself is returned as well as two structs that // contain the routing policies for the channel in either direction. func (c *ChannelGraph) FetchChannelEdgesByOutpoint(op *wire.OutPoint) ( - models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1, error) { + models.ChannelEdgeInfo, models.ChannelEdgePolicy, + models.ChannelEdgePolicy, error) { var ( edgeInfo models.ChannelEdgeInfo - policy1 *models.ChannelEdgePolicy1 - policy2 *models.ChannelEdgePolicy1 + policy1 models.ChannelEdgePolicy + policy2 models.ChannelEdgePolicy ) err := kvdb.View(c.db, func(tx kvdb.RTx) error { @@ -3779,34 +3754,13 @@ func (c *ChannelGraph) FetchChannelEdgesByOutpoint(op *wire.OutPoint) ( // Once we have the information about the channels' parameters, // we'll fetch the routing policies for each for the directed // edges. - edge1, edge2, err := fetchChanEdgePolicies( + e1, e2, err := fetchChanEdgePolicies( edgeIndex, edges, chanID, ) if err != nil { return fmt.Errorf("failed to find policy: %w", err) } - var ( - e1, e2 *models.ChannelEdgePolicy1 - ok bool - ) - if edge1 != nil { - e1, ok = edge1.(*models.ChannelEdgePolicy1) - if !ok { - return fmt.Errorf("expected "+ - "*models.ChannelEdgePolicy1, got %T", - edge1) - } - } - if edge2 != nil { - e2, ok = edge2.(*models.ChannelEdgePolicy1) - if !ok { - return fmt.Errorf("expected "+ - "*models.ChannelEdgePolicy1, got %T", - edge1) - } - } - policy1 = e1 policy2 = e2 return nil @@ -3832,13 +3786,13 @@ func (c *ChannelGraph) FetchChannelEdgesByOutpoint(op *wire.OutPoint) ( // within the database. In this case, the ChannelEdgePolicy1's will be nil, and // the ChannelEdgeInfo1 will only include the public keys of each node. func (c *ChannelGraph) FetchChannelEdgesByID(chanID uint64) ( - models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1, error) { + models.ChannelEdgeInfo, models.ChannelEdgePolicy, + models.ChannelEdgePolicy, error) { var ( edgeInfo models.ChannelEdgeInfo - policy1 *models.ChannelEdgePolicy1 - policy2 *models.ChannelEdgePolicy1 + policy1 models.ChannelEdgePolicy + policy2 models.ChannelEdgePolicy channelID [8]byte ) @@ -3904,34 +3858,13 @@ func (c *ChannelGraph) FetchChannelEdgesByID(chanID uint64) ( // Then we'll attempt to fetch the accompanying policies of this // edge. - edge1, edge2, err := fetchChanEdgePolicies( + e1, e2, err := fetchChanEdgePolicies( edgeIndex, edges, channelID[:], ) if err != nil { return err } - var ( - e1, e2 *models.ChannelEdgePolicy1 - ok bool - ) - if edge1 != nil { - e1, ok = edge1.(*models.ChannelEdgePolicy1) - if !ok { - return fmt.Errorf("expecgted "+ - "*models.ChannelEdgePolicy1, got %T", - edge1) - } - } - if edge2 != nil { - e2, ok = edge2.(*models.ChannelEdgePolicy1) - if !ok { - return fmt.Errorf("expecgted "+ - "*models.ChannelEdgePolicy1, got %T", - edge1) - } - } - policy1 = e1 policy2 = e2 return nil diff --git a/channeldb/graph_cache.go b/channeldb/graph_cache.go index 86e73a3419..9a7cbdaa50 100644 --- a/channeldb/graph_cache.go +++ b/channeldb/graph_cache.go @@ -29,8 +29,8 @@ type GraphCacheNode interface { // to the caller. ForEachChannel(kvdb.RTx, func(kvdb.RTx, models.ChannelEdgeInfo, - *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1) error) error + models.ChannelEdgePolicy, + models.ChannelEdgePolicy) error) error } // DirectedChannel is a type that stores the channel information as seen from @@ -143,22 +143,10 @@ func (c *GraphCache) AddNode(tx kvdb.RTx, node GraphCacheNode) error { return node.ForEachChannel( tx, func(tx kvdb.RTx, info models.ChannelEdgeInfo, - outPolicy *models.ChannelEdgePolicy1, - inPolicy *models.ChannelEdgePolicy1) error { - - // TODO(elle): remove once the ForEachChannel call back - // passes down the interface values instead of the - // pointers. This is temporarily required to prevent - // a nil pointer dereference. - var in, out models.ChannelEdgePolicy - if outPolicy != nil { - out = outPolicy - } - if inPolicy != nil { - in = inPolicy - } - - c.AddChannel(info, out, in) + outPolicy models.ChannelEdgePolicy, + inPolicy models.ChannelEdgePolicy) error { + + c.AddChannel(info, outPolicy, inPolicy) return nil }, diff --git a/channeldb/graph_cache_test.go b/channeldb/graph_cache_test.go index 89581022ed..300b3f82e0 100644 --- a/channeldb/graph_cache_test.go +++ b/channeldb/graph_cache_test.go @@ -42,8 +42,8 @@ func (n *node) Features() *lnwire.FeatureVector { } func (n *node) ForEachChannel(tx kvdb.RTx, - cb func(kvdb.RTx, models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1) error) error { + cb func(kvdb.RTx, models.ChannelEdgeInfo, models.ChannelEdgePolicy, + models.ChannelEdgePolicy) error) error { for idx := range n.edgeInfos { err := cb( diff --git a/channeldb/graph_test.go b/channeldb/graph_test.go index f2341d7ac7..e5f411c88a 100644 --- a/channeldb/graph_test.go +++ b/channeldb/graph_test.go @@ -1055,8 +1055,8 @@ func TestGraphTraversal(t *testing.T) { // again if the map is empty that indicates that all edges have // properly been reached. err = graph.ForEachChannel(func(ei models.ChannelEdgeInfo, - _ *models.ChannelEdgePolicy1, - _ *models.ChannelEdgePolicy1) error { + _ models.ChannelEdgePolicy, + _ models.ChannelEdgePolicy) error { delete(chanIndex, ei.GetChanID()) return nil @@ -1070,7 +1070,7 @@ func TestGraphTraversal(t *testing.T) { firstNode, secondNode := nodeList[0], nodeList[1] err = graph.ForEachNodeChannel(firstNode.PubKeyBytes, func(_ kvdb.RTx, _ models.ChannelEdgeInfo, outEdge, - inEdge *models.ChannelEdgePolicy1) error { + inEdge models.ChannelEdgePolicy) error { // All channels between first and second node should // have fully (both sides) specified policies. @@ -1080,8 +1080,9 @@ func TestGraphTraversal(t *testing.T) { // Each should indicate that it's outgoing (pointed // towards the second node). + outToNode := outEdge.GetToNode() if !bytes.Equal( - outEdge.ToNode[:], secondNode.PubKeyBytes[:], + outToNode[:], secondNode.PubKeyBytes[:], ) { return fmt.Errorf("wrong outgoing edge") @@ -1089,8 +1090,9 @@ func TestGraphTraversal(t *testing.T) { // The incoming edge should also indicate that it's // pointing to the origin node. + inToNode := inEdge.GetToNode() if !bytes.Equal( - inEdge.ToNode[:], firstNode.PubKeyBytes[:], + inToNode[:], firstNode.PubKeyBytes[:], ) { return fmt.Errorf("wrong outgoing edge") @@ -1151,8 +1153,8 @@ func TestGraphTraversalCacheable(t *testing.T) { err := node.ForEachChannel( tx, func(tx kvdb.RTx, info models.ChannelEdgeInfo, - policy *models.ChannelEdgePolicy1, - policy2 *models.ChannelEdgePolicy1) error { //nolint:lll + policy models.ChannelEdgePolicy, + policy2 models.ChannelEdgePolicy) error { //nolint:lll delete(chanIndex, info.GetChanID()) return nil @@ -1335,8 +1337,8 @@ func assertPruneTip(t *testing.T, graph *ChannelGraph, blockHash *chainhash.Hash func assertNumChans(t *testing.T, graph *ChannelGraph, n int) { numChans := 0 if err := graph.ForEachChannel(func(models.ChannelEdgeInfo, - *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1) error { + models.ChannelEdgePolicy, + models.ChannelEdgePolicy) error { numChans++ return nil @@ -2762,7 +2764,7 @@ func TestIncompleteChannelPolicies(t *testing.T) { calls := 0 err := graph.ForEachNodeChannel(node.PubKeyBytes, func(_ kvdb.RTx, _ models.ChannelEdgeInfo, outEdge, - inEdge *models.ChannelEdgePolicy1) error { + inEdge models.ChannelEdgePolicy) error { if !expectedOut && outEdge != nil { t.Fatalf("Expected no outgoing policy") @@ -3917,8 +3919,8 @@ func BenchmarkForEachChannel(b *testing.B) { for _, n := range nodes { cb := func(tx kvdb.RTx, info models.ChannelEdgeInfo, - policy *models.ChannelEdgePolicy1, - policy2 *models.ChannelEdgePolicy1) error { //nolint:lll + policy models.ChannelEdgePolicy, + policy2 models.ChannelEdgePolicy) error { //nolint:lll // We need to do something with // the data here, otherwise the @@ -3926,8 +3928,10 @@ func BenchmarkForEachChannel(b *testing.B) { // this away, and we get bogus // results. totalCapacity += info.GetCapacity() - maxHTLCs += policy.MaxHTLC - maxHTLCs += policy2.MaxHTLC + maxHTLCs += policy.ForwardingPolicy(). + MaxHTLC + maxHTLCs += policy2.ForwardingPolicy(). + MaxHTLC return nil } diff --git a/channeldb/models/channel_edge_policy.go b/channeldb/models/channel_edge_policy.go index 1393b94772..eece025ffe 100644 --- a/channeldb/models/channel_edge_policy.go +++ b/channeldb/models/channel_edge_policy.go @@ -188,6 +188,10 @@ func (c *ChannelEdgePolicy1) AfterUpdateMsg(msg lnwire.ChannelUpdate) (bool, return c.LastUpdate.After(timestamp), nil } +func (c *ChannelEdgePolicy1) ExtraData() lnwire.ExtraOpaqueData { + return c.ExtraOpaqueData +} + // Sig returns the signature of the update message. // // NOTE: This is part of the ChannelEdgePolicy interface. diff --git a/channeldb/models/interfaces.go b/channeldb/models/interfaces.go index f250bc95c6..bfca995fad 100644 --- a/channeldb/models/interfaces.go +++ b/channeldb/models/interfaces.go @@ -94,4 +94,6 @@ type ChannelEdgePolicy interface { // Sig returns the signature of the update message. Sig() (input.Signature, error) + + ExtraData() lnwire.ExtraOpaqueData } diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 8e5eba2e4b..31497389f5 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -566,7 +566,7 @@ type EdgeWithInfo struct { Info models.ChannelEdgeInfo // Edge describes the policy in one direction of the channel. - Edge *models.ChannelEdgePolicy1 + Edge models.ChannelEdgePolicy } // PropagateChanPolicyUpdate signals the AuthenticatedGossiper to perform the @@ -1631,7 +1631,7 @@ func (d *AuthenticatedGossiper) retransmitStaleAnns(now time.Time) error { // within the prune interval or re-broadcast interval. type updateTuple struct { info models.ChannelEdgeInfo - edge *models.ChannelEdgePolicy1 + edge models.ChannelEdgePolicy } var ( @@ -1641,7 +1641,7 @@ func (d *AuthenticatedGossiper) retransmitStaleAnns(now time.Time) error { err := d.cfg.Graph.ForAllOutgoingChannels(func( _ kvdb.RTx, info models.ChannelEdgeInfo, - edge *models.ChannelEdgePolicy1) error { + edge models.ChannelEdgePolicy) error { // If there's no auth proof attached to this edge, it means // that it is a private channel not meant to be announced to @@ -1662,31 +1662,58 @@ func (d *AuthenticatedGossiper) retransmitStaleAnns(now time.Time) error { // If this edge has a ChannelUpdate that was created before the // introduction of the MaxHTLC field, then we'll update this // edge to propagate this information in the network. - if !edge.MessageFlags.HasMaxHtlc() { - // We'll make sure we support the new max_htlc field if - // not already present. - edge.MessageFlags |= lnwire.ChanUpdateRequiredMaxHtlc - edge.MaxHTLC = lnwire.NewMSatFromSatoshis( - info.GetCapacity(), - ) + if e, ok := edge.(*models.ChannelEdgePolicy1); ok { + if !e.MessageFlags.HasMaxHtlc() { + // We'll make sure we support the new max_htlc + // field if not already present. + e.MessageFlags |= + lnwire.ChanUpdateRequiredMaxHtlc + e.MaxHTLC = lnwire.NewMSatFromSatoshis( + info.GetCapacity(), + ) + edgesToUpdate = append( + edgesToUpdate, updateTuple{ + info: info, + edge: e, + }, + ) - edgesToUpdate = append(edgesToUpdate, updateTuple{ - info: info, - edge: edge, - }) - return nil + return nil + } } - timeElapsed := now.Sub(edge.LastUpdate) + switch e := edge.(type) { + case *models.ChannelEdgePolicy1: + timeElapsed := now.Sub(e.LastUpdate) - // If it's been longer than RebroadcastInterval since we've - // re-broadcasted the channel, add the channel to the set of - // edges we need to update. - if timeElapsed >= d.cfg.RebroadcastInterval { - edgesToUpdate = append(edgesToUpdate, updateTuple{ - info: info, - edge: edge, - }) + // If it's been longer than RebroadcastInterval since + // we've re-broadcasted the channel, add the channel to + // the set of edges we need to update. + if timeElapsed >= d.cfg.RebroadcastInterval { + edgesToUpdate = append(edgesToUpdate, + updateTuple{ + info: info, + edge: e, + }, + ) + } + + case *models.ChannelEdgePolicy2: + blocksSince := d.latestHeight() - e.BlockHeight.Val + + // If it's been longer than RebroadcastInterval since + // we've re-broadcasted the channel, add the channel to + // the set of edges we need to update. + if blocksSince >= + uint32(d.cfg.RebroadcastInterval.Hours()*6) { + + edgesToUpdate = append(edgesToUpdate, + updateTuple{ + info: info, + edge: e, + }, + ) + } } return nil @@ -2177,8 +2204,8 @@ func (d *AuthenticatedGossiper) isMsgStale(msg lnwire.Message) bool { // can safely delete the local proof from the database. return chanInfo.GetAuthProof() != nil - case *lnwire.ChannelUpdate1: - _, p1, p2, err := d.cfg.Graph.GetChannelByID(msg.ShortChannelID) + case lnwire.ChannelUpdate: + _, p1, p2, err := d.cfg.Graph.GetChannelByID(msg.SCID()) // If the channel cannot be found, it is most likely a leftover // message for a channel that was closed, so we can consider it @@ -2188,15 +2215,15 @@ func (d *AuthenticatedGossiper) isMsgStale(msg lnwire.Message) bool { } if err != nil { log.Debugf("Unable to retrieve channel=%v from graph: "+ - "%v", msg.ShortChannelID, err) + "%v", msg.SCID(), err) return false } // Otherwise, we'll retrieve the correct policy that we // currently have stored within our graph to check if this // message is stale by comparing its timestamp. - var p *models.ChannelEdgePolicy1 - if msg.ChannelFlags&lnwire.ChanUpdateDirection == 0 { + var p models.ChannelEdgePolicy + if msg.IsNode1() { p = p1 } else { p = p2 @@ -2208,8 +2235,16 @@ func (d *AuthenticatedGossiper) isMsgStale(msg lnwire.Message) bool { return false } - timestamp := time.Unix(int64(msg.Timestamp), 0) - return p.LastUpdate.After(timestamp) + after, err := p.AfterUpdateMsg(msg) + if err != nil { + log.Errorf("Unable to check if stored policy is "+ + "after message for channel=%v: %v", + msg.SCID(), err) + + return false + } + + return after default: // We'll make sure to not mark any unsupported messages as stale @@ -2221,17 +2256,23 @@ func (d *AuthenticatedGossiper) isMsgStale(msg lnwire.Message) bool { // updateChannel creates a new fully signed update for the channel, and updates // the underlying graph with the new state. func (d *AuthenticatedGossiper) updateChannel(edgeInfo models.ChannelEdgeInfo, - edge *models.ChannelEdgePolicy1) (lnwire.ChannelAnnouncement, + edgePolicy models.ChannelEdgePolicy) (lnwire.ChannelAnnouncement, *lnwire.ChannelUpdate1, error) { // Parse the unsigned edge into a channel update. chanUpdate, err := netann.UnsignedChannelUpdateFromEdge( - edgeInfo.GetChainHash(), edge, + edgeInfo.GetChainHash(), edgePolicy, ) if err != nil { return nil, nil, err } + edge, ok := edgePolicy.(*models.ChannelEdgePolicy1) + if !ok { + return nil, nil, fmt.Errorf("expected "+ + "*models.ChannelEdgePolicy1, got: %T", edgePolicy) + } + // We'll generate a new signature over a digest of the channel // announcement itself and update the timestamp to ensure it propagate. err = netann.SignChannelUpdate( @@ -3032,7 +3073,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // being updated. var ( pubKey *btcec.PublicKey - edgeToUpdate *models.ChannelEdgePolicy1 + edgeToUpdate models.ChannelEdgePolicy ) direction := upd.ChannelFlags & lnwire.ChanUpdateDirection switch direction { @@ -3066,15 +3107,31 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, return nil, false } + var edge *models.ChannelEdgePolicy1 + if edgeToUpdate != nil { + var ok bool + edge, ok = edgeToUpdate.(*models.ChannelEdgePolicy1) + if !ok { + rErr := fmt.Errorf("expected "+ + "*models.ChannelEdgePolicy1, got: %T", + edgeToUpdate) + + log.Error(rErr) + nMsg.err <- rErr + + return nil, false + } + } + // If we have a previous version of the edge being updated, we'll want // to rate limit its updates to prevent spam throughout the network. - if nMsg.isRemote && edgeToUpdate != nil { + if nMsg.isRemote && edge != nil { // If it's a keep-alive update, we'll only propagate one if // it's been a day since the previous. This follows our own // heuristic of sending keep-alive updates after the same // duration (see retransmitStaleAnns). - timeSinceLastUpdate := timestamp.Sub(edgeToUpdate.LastUpdate) - if IsKeepAliveUpdate(upd, edgeToUpdate) { + timeSinceLastUpdate := timestamp.Sub(edge.LastUpdate) + if IsKeepAliveUpdate(upd, edge) { if timeSinceLastUpdate < d.cfg.RebroadcastInterval { log.Debugf("Ignoring keep alive update not "+ "within %v period for channel %v", diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index c328de59fd..3c994c203e 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -215,7 +215,7 @@ func (r *mockGraphSource) ForEachNode(func(node *channeldb.LightningNode) error) func (r *mockGraphSource) ForAllOutgoingChannels(cb func(tx kvdb.RTx, i models.ChannelEdgeInfo, - c *models.ChannelEdgePolicy1) error) error { + c models.ChannelEdgePolicy) error) error { r.mu.Lock() defer r.mu.Unlock() @@ -237,14 +237,7 @@ func (r *mockGraphSource) ForAllOutgoingChannels(cb func(tx kvdb.RTx, } for _, channel := range chans { - pol, ok := channel.Policy1.(*models.ChannelEdgePolicy1) - if !ok { - return fmt.Errorf("expected "+ - "*models.ChannelEdgePolicy1, got %T", - channel.Policy1) - } - - if err := cb(nil, channel.Info, pol); err != nil { + if err := cb(nil, channel.Info, channel.Policy1); err != nil { return err } } @@ -254,8 +247,8 @@ func (r *mockGraphSource) ForAllOutgoingChannels(cb func(tx kvdb.RTx, func (r *mockGraphSource) GetChannelByID(chanID lnwire.ShortChannelID) ( models.ChannelEdgeInfo, - *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1, error) { + models.ChannelEdgePolicy, + models.ChannelEdgePolicy, error) { r.mu.Lock() defer r.mu.Unlock() @@ -3501,7 +3494,12 @@ out: err = ctx.router.ForAllOutgoingChannels(func( _ kvdb.RTx, info models.ChannelEdgeInfo, - edge *models.ChannelEdgePolicy1) error { + edgePolicy models.ChannelEdgePolicy) error { + + edge, ok := edgePolicy.(*models.ChannelEdgePolicy1) + if !ok { + t.Fatalf("expected *models.ChannelEdgePolicy1") + } edge.TimeLockDelta = uint16(newTimeLockDelta) edgesToUpdate = append(edgesToUpdate, EdgeWithInfo{ diff --git a/funding/manager.go b/funding/manager.go index a5eda040cd..f2f23abdd2 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -533,7 +533,7 @@ type Config struct { // DeleteAliasEdge allows the Manager to delete an alias channel edge // from the graph. It also returns our local to-be-deleted policy. DeleteAliasEdge func(scid lnwire.ShortChannelID) ( - *models.ChannelEdgePolicy1, error) + models.ChannelEdgePolicy, error) // AliasManager is an implementation of the aliasHandler interface that // abstracts away the handling of many alias functions. @@ -3541,7 +3541,7 @@ func (f *Manager) extractAnnounceParams(c *channeldb.OpenChannel) ( func (f *Manager) addToGraph(completeChan *channeldb.OpenChannel, shortChanID *lnwire.ShortChannelID, peerAlias *lnwire.ShortChannelID, - ourPolicy *models.ChannelEdgePolicy1) error { + ourPolicy models.ChannelEdgePolicy) error { chanID := lnwire.NewChanIDFromOutPoint(completeChan.FundingOutpoint) @@ -4308,9 +4308,19 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey *btcec.PublicKey, localFundingKey *keychain.KeyDescriptor, remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID, chanID lnwire.ChannelID, fwdMinHTLC, fwdMaxHTLC lnwire.MilliSatoshi, - ourPolicy *models.ChannelEdgePolicy1, + ourEdgePolicy models.ChannelEdgePolicy, chanType channeldb.ChannelType) (*chanAnnouncement, error) { + var ourPolicy *models.ChannelEdgePolicy1 + if ourEdgePolicy != nil { + var ok bool + ourPolicy, ok = ourEdgePolicy.(*models.ChannelEdgePolicy1) + if !ok { + return nil, fmt.Errorf("expected "+ + "ChannelEdgePolicy1, got: %T", ourEdgePolicy) + } + } + chainHash := *f.cfg.Wallet.Cfg.NetParams.GenesisHash // The unconditional section of the announcement is the ShortChannelID diff --git a/funding/manager_test.go b/funding/manager_test.go index 8164070bd8..a162e06cc2 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -554,7 +554,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey, OpenChannelPredicate: chainedAcceptor, NotifyPendingOpenChannelEvent: evt.NotifyPendingOpenChannelEvent, DeleteAliasEdge: func(scid lnwire.ShortChannelID) ( - *models.ChannelEdgePolicy1, error) { + models.ChannelEdgePolicy, error) { return nil, nil }, diff --git a/graph/builder.go b/graph/builder.go index 0ccf60aa69..8357d2a145 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -1412,6 +1412,90 @@ func (b *Builder) processUpdate(msg interface{}, lnutils.SpewLogClosure(msg)) b.stats.incNumChannelUpdates() + case *models.ChannelEdgePolicy2: + chanID := msg.ShortChannelID.Val.ToUint64() + + log.Debugf("Received ChannelEdgePolicy2 for channel %v", chanID) + + // We make sure to hold the mutex for this channel ID, + // such that no other goroutine is concurrently doing + // database accesses for the same channel ID. + b.channelEdgeMtx.Lock(chanID) + defer b.channelEdgeMtx.Unlock(chanID) + + edge1Height, edge2Height, exists, isZombie, err := + b.cfg.Graph.HasChannelEdge2(chanID) + if err != nil && + !errors.Is(err, channeldb.ErrGraphNoEdgesFound) { + + return errors.Errorf("unable to check for edge "+ + "existence: %v", err) + } + + // If the channel is marked as a zombie in our database, and + // we consider this a stale update, then we should not apply the + // policy. + blocksSinceMsg := b.SyncedHeight() - msg.BlockHeight.Val + isStaleUpdate := blocksSinceMsg > uint32( + b.cfg.ChannelPruneExpiry.Hours()*6, + ) + if isZombie && isStaleUpdate { + return NewErrf(ErrIgnored, "ignoring stale update "+ + "(is_node_1=%v|disable_flags=%v) for zombie "+ + "chan_id=%v", msg.IsNode1(), msg.DisabledFlags, + chanID) + } + + // If the channel doesn't exist in our database, we cannot + // apply the updated policy. + if !exists { + return NewErrf(ErrIgnored, "ignoring update "+ + "(is_node_1=%v|disable_flags=%v) for unknown "+ + "chan_id=%v", msg.IsNode1(), msg.DisabledFlags, + chanID) + } + + // As edges are directional edge node has a unique policy for + // the direction of the edge they control. Therefore we first + // check if we already have the most up to date information for + // that edge. If this message has a timestamp not strictly + // newer than what we already know of we can exit early. + switch { + case msg.IsNode1(): + // Ignore outdated message. + if edge1Height >= msg.BlockHeight.Val { + return NewErrf(ErrOutdated, "Ignoring "+ + "outdated update "+ + "(is_node_1=%v|disable_flags=%v) for "+ + "known chan_id=%v", msg.IsNode1(), + msg.DisabledFlags, chanID) + } + + case !msg.IsNode1(): + // Ignore outdated message. + if edge2Height >= msg.BlockHeight.Val { + return NewErrf(ErrOutdated, "Ignoring "+ + "outdated update "+ + "(is_node_1=%v|disable_flags=%v) for "+ + "known chan_id=%v", msg.IsNode1(), + msg.DisabledFlags, chanID) + } + } + + // Now that we know this isn't a stale update, we'll apply the + // new edge policy to the proper directional edge within the + // channel graph. + if err = b.cfg.Graph.UpdateEdgePolicy(msg, op...); err != nil { + err := errors.Errorf("unable to add channel: %v", err) + log.Error(err) + return err + } + + log.Tracef("New channel update applied: %v", + lnutils.SpewLogClosure(msg)) + + b.stats.incNumChannelUpdates() + default: return errors.Errorf("wrong routing update message type") } @@ -1580,8 +1664,8 @@ func (b *Builder) SyncedHeight() uint32 { // NOTE: This method is part of the ChannelGraphSource interface. func (b *Builder) GetChannelByID(chanID lnwire.ShortChannelID) ( models.ChannelEdgeInfo, - *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1, error) { + models.ChannelEdgePolicy, + models.ChannelEdgePolicy, error) { return b.cfg.Graph.FetchChannelEdgesByID(chanID.ToUint64()) } @@ -1614,12 +1698,12 @@ func (b *Builder) ForEachNode( // // NOTE: This method is part of the ChannelGraphSource interface. func (b *Builder) ForAllOutgoingChannels(cb func(kvdb.RTx, - models.ChannelEdgeInfo, *models.ChannelEdgePolicy1) error) error { + models.ChannelEdgeInfo, models.ChannelEdgePolicy) error) error { return b.cfg.Graph.ForEachNodeChannel(b.cfg.SelfNode, func(tx kvdb.RTx, c models.ChannelEdgeInfo, - e *models.ChannelEdgePolicy1, - _ *models.ChannelEdgePolicy1) error { + e models.ChannelEdgePolicy, + _ models.ChannelEdgePolicy) error { if e == nil { return fmt.Errorf("channel from self node " + diff --git a/graph/interfaces.go b/graph/interfaces.go index 09ab5f6a02..df8d16932b 100644 --- a/graph/interfaces.go +++ b/graph/interfaces.go @@ -71,7 +71,7 @@ type ChannelGraphSource interface { // star-graph. ForAllOutgoingChannels(cb func(tx kvdb.RTx, c models.ChannelEdgeInfo, - e *models.ChannelEdgePolicy1) error) error + e models.ChannelEdgePolicy) error) error // CurrentBlockHeight returns the block height from POV of the router // subsystem. @@ -79,8 +79,8 @@ type ChannelGraphSource interface { // GetChannelByID return the channel by the channel id. GetChannelByID(chanID lnwire.ShortChannelID) ( - models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1, error) + models.ChannelEdgeInfo, models.ChannelEdgePolicy, + models.ChannelEdgePolicy, error) // FetchLightningNode attempts to look up a target node by its identity // public key. channeldb.ErrGraphNodeNotFound is returned if the node @@ -178,6 +178,7 @@ type DB interface { HasChannelEdge(chanID uint64) (bool, bool, error) HasChannelEdge1(chanID uint64) (time.Time, time.Time, bool, bool, error) + HasChannelEdge2(chanID uint64) (uint32, uint32, bool, bool, error) // FetchChannelEdgesByID attempts to lookup the two directed edges for // the channel identified by the channel ID. If the channel can't be @@ -191,7 +192,7 @@ type DB interface { // will be nil, and the ChannelEdgeInfo1 will only include the public // keys of each node. FetchChannelEdgesByID(chanID uint64) (models.ChannelEdgeInfo, - *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) + models.ChannelEdgePolicy, models.ChannelEdgePolicy, error) // AddLightningNode adds a vertex/node to the graph database. If the // node is not in the database from before, this will add a new, @@ -225,7 +226,7 @@ type DB interface { // node's information. The node ordering is determined by the // lexicographical ordering of the identity public keys of the nodes on // either side of the channel. - UpdateEdgePolicy(edge *models.ChannelEdgePolicy1, + UpdateEdgePolicy(edge models.ChannelEdgePolicy, op ...batch.SchedulerOption) error // HasLightningNode determines if the graph has a vertex identified by @@ -258,8 +259,8 @@ type DB interface { // Unknown policies are passed into the callback as nil values. ForEachNodeChannel(nodePub route.Vertex, cb func(kvdb.RTx, models.ChannelEdgeInfo, - *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1) error) error + models.ChannelEdgePolicy, + models.ChannelEdgePolicy) error) error // UpdateChannelEdge retrieves and update edge of the graph database. // Method only reserved for updating an edge info after its already been diff --git a/graph/notifications.go b/graph/notifications.go index 8ba68dd64d..040f266dca 100644 --- a/graph/notifications.go +++ b/graph/notifications.go @@ -342,11 +342,13 @@ func addToTopologyChange(graph DB, update *TopologyChange, // Any new ChannelUpdateAnnouncements will generate a corresponding // ChannelEdgeUpdate notification. - case *models.ChannelEdgePolicy1: + case models.ChannelEdgePolicy: // We'll need to fetch the edge's information from the database // in order to get the information concerning which nodes are // being connected. - edgeInfo, _, _, err := graph.FetchChannelEdgesByID(m.ChannelID) + edgeInfo, _, _, err := graph.FetchChannelEdgesByID( + m.SCID().ToUint64(), + ) if err != nil { return errors.Errorf("unable fetch channel edge: %v", err) @@ -356,7 +358,7 @@ func addToTopologyChange(graph DB, update *TopologyChange, // the second node. sourceNode := edgeInfo.NodeKey1 connectingNode := edgeInfo.NodeKey2 - if m.ChannelFlags&lnwire.ChanUpdateDirection == 1 { + if !m.IsNode1() { sourceNode = edgeInfo.NodeKey2 connectingNode = edgeInfo.NodeKey1 } @@ -370,19 +372,20 @@ func addToTopologyChange(graph DB, update *TopologyChange, return err } + policy := m.ForwardingPolicy() edgeUpdate := &ChannelEdgeUpdate{ - ChanID: m.ChannelID, + ChanID: m.SCID().ToUint64(), ChanPoint: edgeInfo.GetChanPoint(), - TimeLockDelta: m.TimeLockDelta, + TimeLockDelta: policy.TimeLockDelta, Capacity: edgeInfo.GetCapacity(), - MinHTLC: m.MinHTLC, - MaxHTLC: m.MaxHTLC, - BaseFee: m.FeeBaseMSat, - FeeRate: m.FeeProportionalMillionths, + MinHTLC: policy.MinHTLC, + MaxHTLC: policy.MaxHTLC, + BaseFee: policy.BaseFee, + FeeRate: policy.FeeRate, AdvertisingNode: aNode, ConnectingNode: cNode, - Disabled: m.ChannelFlags&lnwire.ChanUpdateDisabled != 0, - ExtraOpaqueData: m.ExtraOpaqueData, + Disabled: m.IsDisabled(), + ExtraOpaqueData: m.ExtraData(), } // TODO(roasbeef): add bit to toggle diff --git a/graph/validation_barrier.go b/graph/validation_barrier.go index fcd40d0f2f..bb431522a0 100644 --- a/graph/validation_barrier.go +++ b/graph/validation_barrier.go @@ -144,7 +144,7 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) { // These other types don't have any dependants, so no further // initialization needs to be done beyond just occupying a job slot. - case *models.ChannelEdgePolicy1: + case models.ChannelEdgePolicy: return case *lnwire.ChannelUpdate1: return @@ -186,14 +186,13 @@ func (v *ValidationBarrier) WaitForDependants(job interface{}) error { v.Lock() switch msg := job.(type) { - // Any ChannelUpdate or NodeAnnouncement jobs will need to wait on the - // completion of any active ChannelAnnouncement jobs related to them. - case *models.ChannelEdgePolicy1: - shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID) - signals, ok = v.chanEdgeDependencies[shortID] + // Any ChannelUpdate1 or NodeAnnouncement1 jobs will need to wait on the + // completion of any active ChannelAnnouncement1 jobs related to them. + case models.ChannelEdgePolicy: + signals, ok = v.chanEdgeDependencies[msg.SCID()] - jobDesc = fmt.Sprintf("job=lnwire.ChannelEdgePolicy1, scid=%v", - msg.ChannelID) + jobDesc = fmt.Sprintf("job=lnwire.ChannelEdgePolicy, scid=%v", + msg.SCID().ToUint64()) case *channeldb.LightningNode: vertex := route.Vertex(msg.PubKeyBytes) @@ -299,9 +298,8 @@ func (v *ValidationBarrier) SignalDependants(job interface{}, allow bool) { delete(v.nodeAnnDependencies, route.Vertex(msg.NodeID)) case *lnwire.ChannelUpdate1: delete(v.chanEdgeDependencies, msg.ShortChannelID) - case *models.ChannelEdgePolicy1: - shortID := lnwire.NewShortChanIDFromInt(msg.ChannelID) - delete(v.chanEdgeDependencies, shortID) + case models.ChannelEdgePolicy: + delete(v.chanEdgeDependencies, msg.SCID()) case *lnwire.AnnounceSignatures1: return diff --git a/lnrpc/invoicesrpc/addinvoice.go b/lnrpc/invoicesrpc/addinvoice.go index 690e938b84..a928973bba 100644 --- a/lnrpc/invoicesrpc/addinvoice.go +++ b/lnrpc/invoicesrpc/addinvoice.go @@ -766,7 +766,7 @@ type SelectHopHintsCfg struct { // FetchChannelEdgesByID attempts to lookup the two directed edges for // the channel identified by the channel ID. FetchChannelEdgesByID func(chanID uint64) (models.ChannelEdgeInfo, - *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, + models.ChannelEdgePolicy, models.ChannelEdgePolicy, error) // GetAlias allows the peer's alias SCID to be retrieved for private diff --git a/lnrpc/invoicesrpc/addinvoice_test.go b/lnrpc/invoicesrpc/addinvoice_test.go index c7960ea9b1..9be854cdd2 100644 --- a/lnrpc/invoicesrpc/addinvoice_test.go +++ b/lnrpc/invoicesrpc/addinvoice_test.go @@ -67,8 +67,8 @@ func (h *hopHintsConfigMock) FetchAllChannels() ([]*channeldb.OpenChannel, // FetchChannelEdgesByID attempts to lookup the two directed edges for // the channel identified by the channel ID. func (h *hopHintsConfigMock) FetchChannelEdgesByID(chanID uint64) ( - models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1, error) { + models.ChannelEdgeInfo, models.ChannelEdgePolicy, + models.ChannelEdgePolicy, error) { args := h.Mock.Called(chanID) diff --git a/netann/chan_status_manager_test.go b/netann/chan_status_manager_test.go index 9617c0b349..1288056a88 100644 --- a/netann/chan_status_manager_test.go +++ b/netann/chan_status_manager_test.go @@ -170,7 +170,7 @@ func (g *mockGraph) FetchAllOpenChannels() ([]*channeldb.OpenChannel, error) { func (g *mockGraph) FetchChannelEdgesByOutpoint( op *wire.OutPoint) (models.ChannelEdgeInfo, - *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) { + models.ChannelEdgePolicy, models.ChannelEdgePolicy, error) { g.mu.Lock() defer g.mu.Unlock() diff --git a/netann/channel_update.go b/netann/channel_update.go index 1df89527d0..deff0a9b87 100644 --- a/netann/channel_update.go +++ b/netann/channel_update.go @@ -102,8 +102,7 @@ func SignChannelUpdate(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator // // NOTE: The passed policies can be nil. func ExtractChannelUpdate(ownerPubKey []byte, - info models.ChannelEdgeInfo, - policies ...*models.ChannelEdgePolicy1) ( + info models.ChannelEdgeInfo, policies ...models.ChannelEdgePolicy) ( *lnwire.ChannelUpdate1, error) { // Helper function to extract the owner of the given policy. @@ -125,7 +124,13 @@ func ExtractChannelUpdate(ownerPubKey []byte, // Extract the channel update from the policy we own, if any. for _, edge := range policies { - if edge != nil && bytes.Equal(ownerPubKey, owner(edge)) { + e, ok := edge.(*models.ChannelEdgePolicy1) + if !ok { + return nil, fmt.Errorf("expected "+ + "*models.ChannelEdgePolicy1, got: %T", edge) + } + + if edge != nil && bytes.Equal(ownerPubKey, owner(e)) { return ChannelUpdateFromEdge(info, edge) } } diff --git a/netann/interface.go b/netann/interface.go index 15b1abfc63..96d1abafcf 100644 --- a/netann/interface.go +++ b/netann/interface.go @@ -20,5 +20,5 @@ type ChannelGraph interface { // FetchChannelEdgesByOutpoint returns the channel edge info and most // recent channel edge policies for a given outpoint. FetchChannelEdgesByOutpoint(*wire.OutPoint) (models.ChannelEdgeInfo, - *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) + models.ChannelEdgePolicy, models.ChannelEdgePolicy, error) } diff --git a/peer/brontide.go b/peer/brontide.go index cd1fa53492..8b61ad0341 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -1118,25 +1118,27 @@ func (p *Brontide) loadActiveChannels(chans []*channeldb.OpenChannel) ( var forwardingPolicy *models.ForwardingPolicy if selfPolicy != nil { var inboundWireFee lnwire.Fee - _, err := selfPolicy.ExtraOpaqueData.ExtractRecords( - &inboundWireFee, - ) - if err != nil { - return nil, err + if pol, ok := selfPolicy.(*models.ChannelEdgePolicy1); ok { + _, err := pol.ExtraOpaqueData.ExtractRecords( + &inboundWireFee, + ) + if err != nil { + return nil, err + } } inboundFee := models.NewInboundFeeFromWire( inboundWireFee, ) + pol := selfPolicy.ForwardingPolicy() forwardingPolicy = &models.ForwardingPolicy{ - MinHTLCOut: selfPolicy.MinHTLC, - MaxHTLC: selfPolicy.MaxHTLC, - BaseFee: selfPolicy.FeeBaseMSat, - FeeRate: selfPolicy.FeeProportionalMillionths, - TimeLockDelta: uint32(selfPolicy.TimeLockDelta), - - InboundFee: inboundFee, + MinHTLCOut: pol.MinHTLC, + MaxHTLC: pol.MaxHTLC, + BaseFee: pol.BaseFee, + FeeRate: pol.FeeRate, + TimeLockDelta: uint32(pol.TimeLockDelta), + InboundFee: inboundFee, } } else { p.log.Warnf("Unable to find our forwarding policy "+ diff --git a/routing/blindedpath/blinded_path.go b/routing/blindedpath/blinded_path.go index 9b69851ffc..2edd4a194d 100644 --- a/routing/blindedpath/blinded_path.go +++ b/routing/blindedpath/blinded_path.go @@ -43,7 +43,7 @@ type BuildBlindedPathCfg struct { // FetchChannelEdgesByID attempts to look up the two directed edges for // the channel identified by the channel ID. FetchChannelEdgesByID func(chanID uint64) (models.ChannelEdgeInfo, - *models.ChannelEdgePolicy1, *models.ChannelEdgePolicy1, error) + models.ChannelEdgePolicy, models.ChannelEdgePolicy, error) // FetchOurOpenChannels fetches this node's set of open channels. FetchOurOpenChannels func() ([]*channeldb.OpenChannel, error) @@ -648,16 +648,24 @@ func getNodeChannelPolicy(cfg *BuildBlindedPathCfg, chanID uint64, return nil, err } + var update1ToNode, update2ToNode [33]byte + if update1 != nil { + update1ToNode = update1.GetToNode() + } + if update2 != nil { + update2ToNode = update2.GetToNode() + } + // Now we need to determine which of the updates was created by the // node in question. We know the update is the correct one if the // "ToNode" for the fetched policy is _not_ equal to the node ID in // question. - var policy *models.ChannelEdgePolicy1 + var policy models.ChannelEdgePolicy switch { - case update1 != nil && !bytes.Equal(update1.ToNode[:], nodeID[:]): + case update1 != nil && !bytes.Equal(update1ToNode[:], nodeID[:]): policy = update1 - case update2 != nil && !bytes.Equal(update2.ToNode[:], nodeID[:]): + case update2 != nil && !bytes.Equal(update2ToNode[:], nodeID[:]): policy = update2 default: @@ -665,12 +673,14 @@ func getNodeChannelPolicy(cfg *BuildBlindedPathCfg, chanID uint64, "%s for channel %d", nodeID, chanID) } + fwdPolicy := policy.ForwardingPolicy() + return &BlindedHopPolicy{ - CLTVExpiryDelta: policy.TimeLockDelta, - FeeRate: uint32(policy.FeeProportionalMillionths), - BaseFee: policy.FeeBaseMSat, - MinHTLCMsat: policy.MinHTLC, - MaxHTLCMsat: policy.MaxHTLC, + CLTVExpiryDelta: fwdPolicy.TimeLockDelta, + FeeRate: uint32(fwdPolicy.FeeRate), + BaseFee: fwdPolicy.BaseFee, + MinHTLCMsat: fwdPolicy.MinHTLC, + MaxHTLCMsat: fwdPolicy.MaxHTLC, }, nil } diff --git a/routing/blindedpath/blinded_path_test.go b/routing/blindedpath/blinded_path_test.go index 4ee4f444f5..548103f47f 100644 --- a/routing/blindedpath/blinded_path_test.go +++ b/routing/blindedpath/blinded_path_test.go @@ -580,12 +580,12 @@ func TestBuildBlindedPath(t *testing.T) { }, } - realPolicies := map[uint64]*models.ChannelEdgePolicy1{ - chanCB: { + realPolicies := map[uint64]models.ChannelEdgePolicy{ + chanCB: &models.ChannelEdgePolicy1{ ChannelID: chanCB, ToNode: bob, }, - chanBA: { + chanBA: &models.ChannelEdgePolicy1{ ChannelID: chanBA, ToNode: alice, }, @@ -598,8 +598,8 @@ func TestBuildBlindedPath(t *testing.T) { return []*route.Route{realRoute}, nil }, FetchChannelEdgesByID: func(chanID uint64) ( - models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1, error) { + models.ChannelEdgeInfo, models.ChannelEdgePolicy, + models.ChannelEdgePolicy, error) { return nil, realPolicies[chanID], nil, nil }, @@ -766,8 +766,8 @@ func TestBuildBlindedPathWithDummyHops(t *testing.T) { return []*route.Route{realRoute}, nil }, FetchChannelEdgesByID: func(chanID uint64) ( - models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1, error) { + models.ChannelEdgeInfo, models.ChannelEdgePolicy, + models.ChannelEdgePolicy, error) { policy, ok := realPolicies[chanID] if !ok { @@ -937,8 +937,8 @@ func TestBuildBlindedPathWithDummyHops(t *testing.T) { nil }, FetchChannelEdgesByID: func(chanID uint64) ( - models.ChannelEdgeInfo, *models.ChannelEdgePolicy1, - *models.ChannelEdgePolicy1, error) { + models.ChannelEdgeInfo, models.ChannelEdgePolicy, + models.ChannelEdgePolicy, error) { // Force the call to error for the first 2 channels. if errCount < 2 { diff --git a/routing/localchans/manager.go b/routing/localchans/manager.go index 072b5eb9f0..8ae46f8bd8 100644 --- a/routing/localchans/manager.go +++ b/routing/localchans/manager.go @@ -33,7 +33,7 @@ type Manager struct { // channels. ForAllOutgoingChannels func(cb func(kvdb.RTx, models.ChannelEdgeInfo, - *models.ChannelEdgePolicy1) error) error + models.ChannelEdgePolicy) error) error // FetchChannel is used to query local channel parameters. Optionally an // existing db tx can be supplied. @@ -75,7 +75,7 @@ func (r *Manager) UpdatePolicy(newSchema routing.ChannelPolicy, err := r.ForAllOutgoingChannels(func( tx kvdb.RTx, info models.ChannelEdgeInfo, - edge *models.ChannelEdgePolicy1) error { + edge models.ChannelEdgePolicy) error { var chanPoint = info.GetChanPoint() @@ -108,21 +108,23 @@ func (r *Manager) UpdatePolicy(newSchema routing.ChannelPolicy, Edge: edge, }) - // Extract inbound fees from the ExtraOpaqueData. var inboundWireFee lnwire.Fee - _, err = edge.ExtraOpaqueData.ExtractRecords(&inboundWireFee) - if err != nil { - return err + if pol, ok := edge.(*models.ChannelEdgePolicy1); ok { + _, err = pol.ExtraOpaqueData.ExtractRecords(&inboundWireFee) + if err != nil { + return err + } } inboundFee := models.NewInboundFeeFromWire(inboundWireFee) // Add updated policy to list of policies to send to switch. + fwdPol := edge.ForwardingPolicy() policiesToUpdate[chanPoint] = models.ForwardingPolicy{ - BaseFee: edge.FeeBaseMSat, - FeeRate: edge.FeeProportionalMillionths, - TimeLockDelta: uint32(edge.TimeLockDelta), - MinHTLCOut: edge.MinHTLC, - MaxHTLC: edge.MaxHTLC, + BaseFee: fwdPol.BaseFee, + FeeRate: fwdPol.FeeRate, + TimeLockDelta: uint32(fwdPol.TimeLockDelta), + MinHTLCOut: fwdPol.MinHTLC, + MaxHTLC: fwdPol.MaxHTLC, InboundFee: inboundFee, } @@ -184,85 +186,161 @@ func (r *Manager) UpdatePolicy(newSchema routing.ChannelPolicy, // updateEdge updates the given edge with the new schema. func (r *Manager) updateEdge(tx kvdb.RTx, chanPoint wire.OutPoint, - edge *models.ChannelEdgePolicy1, + edgePolicy models.ChannelEdgePolicy, newSchema routing.ChannelPolicy) error { - // Update forwarding fee scheme and required time lock delta. - edge.FeeBaseMSat = newSchema.BaseFee - edge.FeeProportionalMillionths = lnwire.MilliSatoshi( - newSchema.FeeRate, - ) - - // If inbound fees are set, we update the edge with them. - err := fn.MapOptionZ(newSchema.InboundFee, - func(f models.InboundFee) error { - inboundWireFee := f.ToWire() - return edge.ExtraOpaqueData.PackRecords( - &inboundWireFee, + switch edge := edgePolicy.(type) { + case *models.ChannelEdgePolicy1: + // Update forwarding fee scheme and required time lock delta. + edge.FeeBaseMSat = newSchema.BaseFee + edge.FeeProportionalMillionths = lnwire.MilliSatoshi( + newSchema.FeeRate, + ) + + // If inbound fees are set, we update the edge with them. + err := fn.MapOptionZ(newSchema.InboundFee, + func(f models.InboundFee) error { + inboundWireFee := f.ToWire() + return edge.ExtraOpaqueData.PackRecords( + &inboundWireFee, + ) + }) + if err != nil { + return err + } + + edge.TimeLockDelta = uint16(newSchema.TimeLockDelta) + + // Retrieve negotiated channel htlc amt limits. + amtMin, amtMax, err := r.getHtlcAmtLimits(tx, chanPoint) + if err != nil { + return err + } + + // We now update the edge max htlc value. + switch { + // If a non-zero max htlc was specified, use it to update the + // edge. Otherwise, keep the value unchanged. + case newSchema.MaxHTLC != 0: + edge.MaxHTLC = newSchema.MaxHTLC + + // If this edge still doesn't have a max htlc set, set it to the + // max. This is an on-the-fly migration. + case !edge.MessageFlags.HasMaxHtlc(): + edge.MaxHTLC = amtMax + + // If this edge has a max htlc that exceeds what the channel can + // actually carry, correct it now. This can happen, because we + // previously set the max htlc to the channel capacity. + case edge.MaxHTLC > amtMax: + edge.MaxHTLC = amtMax + } + + // If a new min htlc is specified, update the edge. + if newSchema.MinHTLC != nil { + edge.MinHTLC = *newSchema.MinHTLC + } + + // If the MaxHtlc flag wasn't already set, we can set it now. + edge.MessageFlags |= lnwire.ChanUpdateRequiredMaxHtlc + + // Validate htlc amount constraints. + switch { + case edge.MinHTLC < amtMin: + return fmt.Errorf("min htlc amount of %v is below "+ + "min htlc parameter of %v", edge.MinHTLC, + amtMin) + + case edge.MaxHTLC > amtMax: + return fmt.Errorf("max htlc size of %v is above max "+ + "pending amount of %v", edge.MaxHTLC, amtMax) + + case edge.MinHTLC > edge.MaxHTLC: + return fmt.Errorf( + "min_htlc %v greater than max_htlc %v", + edge.MinHTLC, edge.MaxHTLC, ) - }) - if err != nil { - return err - } + } - edge.TimeLockDelta = uint16(newSchema.TimeLockDelta) + // Clear signature to help prevent usage of the previous + // signature. + edge.SetSigBytes(nil) + + case *models.ChannelEdgePolicy2: + // Update forwarding fee scheme and required time lock delta. + edge.FeeBaseMsat.Val = uint32(newSchema.BaseFee) + edge.FeeProportionalMillionths.Val = newSchema.FeeRate + edge.CLTVExpiryDelta.Val = uint16(newSchema.TimeLockDelta) + + // If inbound fees are set, we update the edge with them. + err := fn.MapOptionZ(newSchema.InboundFee, + func(f models.InboundFee) error { + inboundWireFee := f.ToWire() + return edge.ExtraOpaqueData.PackRecords( + &inboundWireFee, + ) + }) + if err != nil { + return err + } - // Retrieve negotiated channel htlc amt limits. - amtMin, amtMax, err := r.getHtlcAmtLimits(tx, chanPoint) - if err != nil { - return err - } + // Retrieve negotiated channel htlc amt limits. + amtMin, amtMax, err := r.getHtlcAmtLimits(tx, chanPoint) + if err != nil { + return err + } - // We now update the edge max htlc value. - switch { - // If a non-zero max htlc was specified, use it to update the edge. - // Otherwise keep the value unchanged. - case newSchema.MaxHTLC != 0: - edge.MaxHTLC = newSchema.MaxHTLC - - // If this edge still doesn't have a max htlc set, set it to the max. - // This is an on-the-fly migration. - case !edge.MessageFlags.HasMaxHtlc(): - edge.MaxHTLC = amtMax - - // If this edge has a max htlc that exceeds what the channel can - // actually carry, correct it now. This can happen, because we - // previously set the max htlc to the channel capacity. - case edge.MaxHTLC > amtMax: - edge.MaxHTLC = amtMax - } + // We now update the edge max htlc value. + switch { + // If a non-zero max htlc was specified, use it to update the + // edge. + // Otherwise keep the value unchanged. + case newSchema.MaxHTLC != 0: + edge.HTLCMaximumMsat.Val = newSchema.MaxHTLC + + // If this edge has a max htlc that exceeds what the channel can + // actually carry, correct it now. This can happen, because we + // previously set the max htlc to the channel capacity. + case edge.HTLCMaximumMsat.Val > amtMax: + edge.HTLCMaximumMsat.Val = amtMax + } - // If a new min htlc is specified, update the edge. - if newSchema.MinHTLC != nil { - edge.MinHTLC = *newSchema.MinHTLC - } + // If a new min htlc is specified, update the edge. + if newSchema.MinHTLC != nil { + edge.HTLCMinimumMsat.Val = *newSchema.MinHTLC + } - // If the MaxHtlc flag wasn't already set, we can set it now. - edge.MessageFlags |= lnwire.ChanUpdateRequiredMaxHtlc + // Validate htlc amount constraints. + switch { + case edge.HTLCMinimumMsat.Val < amtMin: + return fmt.Errorf( + "min htlc amount of %v is below min htlc "+ + "parameter of %v", edge.HTLCMinimumMsat, + amtMin, + ) - // Validate htlc amount constraints. - switch { - case edge.MinHTLC < amtMin: - return fmt.Errorf( - "min htlc amount of %v is below min htlc parameter of %v", - edge.MinHTLC, amtMin, - ) + case edge.HTLCMaximumMsat.Val > amtMax: + return fmt.Errorf( + "max htlc size of %v is above max pending "+ + "amount of %v", edge.HTLCMaximumMsat, + amtMax, + ) - case edge.MaxHTLC > amtMax: - return fmt.Errorf( - "max htlc size of %v is above max pending amount of %v", - edge.MaxHTLC, amtMax, - ) + case edge.HTLCMinimumMsat.Val > edge.HTLCMaximumMsat.Val: + return fmt.Errorf( + "min_htlc %v greater than max_htlc %v", + edge.HTLCMinimumMsat, edge.HTLCMaximumMsat, + ) + } - case edge.MinHTLC > edge.MaxHTLC: - return fmt.Errorf( - "min_htlc %v greater than max_htlc %v", - edge.MinHTLC, edge.MaxHTLC, - ) - } + // Clear signature to help prevent usage of the previous + // signature. + edge.Signature = lnwire.Sig{} - // Clear signature to help prevent usage of the previous signature. - edge.SetSigBytes(nil) + default: + return fmt.Errorf("unhandled implementation of "+ + "models.ChannelEdgePolicy: %T", edgePolicy) + } return nil } diff --git a/routing/localchans/manager_test.go b/routing/localchans/manager_test.go index 30b23c1b7c..9e9d6a5119 100644 --- a/routing/localchans/manager_test.go +++ b/routing/localchans/manager_test.go @@ -85,7 +85,9 @@ func TestManager(t *testing.T) { } for _, edge := range edgesToUpdate { - policy := edge.Edge + policy, ok := edge.Edge.(*models.ChannelEdgePolicy1) + require.True(t, ok) + if !policy.MessageFlags.HasMaxHtlc() { t.Fatal("expected max htlc flag") } @@ -108,7 +110,7 @@ func TestManager(t *testing.T) { forAllOutgoingChannels := func(cb func(kvdb.RTx, models.ChannelEdgeInfo, - *models.ChannelEdgePolicy1) error) error { + models.ChannelEdgePolicy) error) error { for _, c := range channelSet { if err := cb(nil, c.edgeInfo, ¤tPolicy); err != nil { diff --git a/routing/pathfind_test.go b/routing/pathfind_test.go index 399a646e38..3c8480cd7a 100644 --- a/routing/pathfind_test.go +++ b/routing/pathfind_test.go @@ -2026,9 +2026,12 @@ func runRouteFailMaxHTLC(t *testing.T, useCache bool) { graph := ctx.testGraphInstance.graph _, midEdge, _, err := graph.FetchChannelEdgesByID(firstToSecondID) require.NoError(t, err, "unable to fetch channel edges by ID") - midEdge.MessageFlags = 1 - midEdge.MaxHTLC = payAmt - 1 - if err := graph.UpdateEdgePolicy(midEdge); err != nil { + + midEdgePol, ok := midEdge.(*models.ChannelEdgePolicy1) + require.True(t, ok) + midEdgePol.MessageFlags = 1 + midEdgePol.MaxHTLC = payAmt - 1 + if err := graph.UpdateEdgePolicy(midEdgePol); err != nil { t.Fatalf("unable to update edge: %v", err) } @@ -2067,8 +2070,16 @@ func runRouteFailDisabledEdge(t *testing.T, useCache bool) { // path finding, as we don't consider the disable flag for local // channels (and roasbeef is the source). roasToPham := uint64(999991) - _, e1, e2, err := graph.graph.FetchChannelEdgesByID(roasToPham) + + _, edge1, edge2, err := graph.graph.FetchChannelEdgesByID(roasToPham) require.NoError(t, err, "unable to fetch edge") + + e1, ok := edge1.(*models.ChannelEdgePolicy1) + require.True(t, ok) + + e2, ok := edge2.(*models.ChannelEdgePolicy1) + require.True(t, ok) + e1.ChannelFlags |= lnwire.ChanUpdateDisabled if err := graph.graph.UpdateEdgePolicy(e1); err != nil { t.Fatalf("unable to update edge: %v", err) @@ -2088,8 +2099,12 @@ func runRouteFailDisabledEdge(t *testing.T, useCache bool) { // Now, we'll modify the edge from phamnuwen -> sophon, to read that // it's disabled. phamToSophon := uint64(99999) - _, e, _, err := graph.graph.FetchChannelEdgesByID(phamToSophon) + _, edge, _, err := graph.graph.FetchChannelEdgesByID(phamToSophon) require.NoError(t, err, "unable to fetch edge") + + e, ok := edge.(*models.ChannelEdgePolicy1) + require.True(t, ok) + e.ChannelFlags |= lnwire.ChanUpdateDisabled if err := graph.graph.UpdateEdgePolicy(e); err != nil { t.Fatalf("unable to update edge: %v", err) @@ -2169,8 +2184,15 @@ func runPathSourceEdgesBandwidth(t *testing.T, useCache bool) { // Finally, set the roasbeef->songoku bandwidth, but also set its // disable flag. bandwidths.hints[roasToSongoku] = 2 * payAmt - _, e1, e2, err := graph.graph.FetchChannelEdgesByID(roasToSongoku) + _, edge1, edge2, err := graph.graph.FetchChannelEdgesByID(roasToSongoku) require.NoError(t, err, "unable to fetch edge") + + e1, ok := edge1.(*models.ChannelEdgePolicy1) + require.True(t, ok) + + e2, ok := edge2.(*models.ChannelEdgePolicy1) + require.True(t, ok) + e1.ChannelFlags |= lnwire.ChanUpdateDisabled if err := graph.graph.UpdateEdgePolicy(e1); err != nil { t.Fatalf("unable to update edge: %v", err) diff --git a/routing/router_test.go b/routing/router_test.go index de2667fcdb..21ddf57a8e 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -31,6 +31,7 @@ import ( "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/netann" "github.com/lightningnetwork/lnd/record" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/zpay32" @@ -458,13 +459,17 @@ func TestChannelUpdateValidation(t *testing.T) { ctx := createTestCtxFromGraphInstance(t, startingBlockHeight, testGraph) // Assert that the initially configured fee is retrieved correctly. - _, e1, e2, err := ctx.graph.FetchChannelEdgesByID( + _, edge1, edge2, err := ctx.graph.FetchChannelEdgesByID( lnwire.NewShortChanIDFromInt(1).ToUint64(), ) require.NoError(t, err, "cannot retrieve channel") - require.Equal(t, feeRate, e1.FeeProportionalMillionths, "invalid fee") - require.Equal(t, feeRate, e2.FeeProportionalMillionths, "invalid fee") + require.Equal( + t, feeRate, edge1.ForwardingPolicy().FeeRate, "invalid fee", + ) + require.Equal( + t, feeRate, edge2.ForwardingPolicy().FeeRate, "invalid fee", + ) // Setup a route from source a to destination c. The route will be used // in a call to SendToRoute. SendToRoute also applies channel updates, @@ -490,6 +495,12 @@ func TestChannelUpdateValidation(t *testing.T) { ) require.NoError(t, err, "unable to create route") + e1, ok := edge1.(*models.ChannelEdgePolicy1) + require.True(t, ok) + + e2, ok := edge2.(*models.ChannelEdgePolicy1) + require.True(t, ok) + // Set up a channel update message with an invalid signature to be // returned to the sender. var invalidSignature lnwire.Sig @@ -530,11 +541,17 @@ func TestChannelUpdateValidation(t *testing.T) { _, err = ctx.router.SendToRoute(payment, rt, nil) require.Error(t, err, "expected route to fail with channel update") - _, e1, e2, err = ctx.graph.FetchChannelEdgesByID( + _, edge1, edge2, err = ctx.graph.FetchChannelEdgesByID( lnwire.NewShortChanIDFromInt(1).ToUint64(), ) require.NoError(t, err, "cannot retrieve channel") + _, ok = edge1.(*models.ChannelEdgePolicy1) + require.True(t, ok) + + e2, ok = edge2.(*models.ChannelEdgePolicy1) + require.True(t, ok) + require.Equal(t, feeRate, e1.FeeProportionalMillionths, "fee updated without valid signature") require.Equal(t, feeRate, e2.FeeProportionalMillionths, @@ -552,11 +569,17 @@ func TestChannelUpdateValidation(t *testing.T) { // This time a valid signature was supplied and the policy change should // have been applied to the graph. - _, e1, e2, err = ctx.graph.FetchChannelEdgesByID( + _, edge1, edge2, err = ctx.graph.FetchChannelEdgesByID( lnwire.NewShortChanIDFromInt(1).ToUint64(), ) require.NoError(t, err, "cannot retrieve channel") + e1, ok = edge1.(*models.ChannelEdgePolicy1) + require.True(t, ok) + + e2, ok = edge2.(*models.ChannelEdgePolicy1) + require.True(t, ok) + require.Equal(t, feeRate, e1.FeeProportionalMillionths, "fee should not be updated") require.EqualValues(t, 500, int(e2.FeeProportionalMillionths), @@ -598,21 +621,15 @@ func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) { ) require.NoError(t, err, "unable to fetch chan id") - errChanUpdate := lnwire.ChannelUpdate1{ - ShortChannelID: lnwire.NewShortChanIDFromInt( - songokuSophonChanID, - ), - Timestamp: uint32(edgeUpdateToFail.LastUpdate.Unix()), - MessageFlags: edgeUpdateToFail.MessageFlags, - ChannelFlags: edgeUpdateToFail.ChannelFlags, - TimeLockDelta: edgeUpdateToFail.TimeLockDelta, - HtlcMinimumMsat: edgeUpdateToFail.MinHTLC, - HtlcMaximumMsat: edgeUpdateToFail.MaxHTLC, - BaseFee: uint32(edgeUpdateToFail.FeeBaseMSat), - FeeRate: uint32(edgeUpdateToFail.FeeProportionalMillionths), - } + edgeUpdToFail, ok := edgeUpdateToFail.(*models.ChannelEdgePolicy1) + require.True(t, ok) - signErrChanUpdate(t, ctx.privKeys["songoku"], &errChanUpdate) + errChanUpdate, err := netann.UnsignedChannelUpdateFromEdge( + chainhash.Hash{}, edgeUpdToFail, + ) + require.NoError(t, err) + + signErrChanUpdate(t, ctx.privKeys["songoku"], errChanUpdate) // We'll now modify the SendToSwitch method to return an error for the // outgoing channel to Son goku. This will be a fee related error, so @@ -633,7 +650,7 @@ func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) { // reflect the new fee schedule for the // node/channel. &lnwire.FailFeeInsufficient{ - Update: errChanUpdate, + Update: *errChanUpdate, }, 1, ) } @@ -944,17 +961,13 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) { _, _, edgeUpdateToFail, err := ctx.graph.FetchChannelEdgesByID(chanID) require.NoError(t, err, "unable to fetch chan id") - errChanUpdate := lnwire.ChannelUpdate1{ - ShortChannelID: lnwire.NewShortChanIDFromInt(chanID), - Timestamp: uint32(edgeUpdateToFail.LastUpdate.Unix()), - MessageFlags: edgeUpdateToFail.MessageFlags, - ChannelFlags: edgeUpdateToFail.ChannelFlags, - TimeLockDelta: edgeUpdateToFail.TimeLockDelta, - HtlcMinimumMsat: edgeUpdateToFail.MinHTLC, - HtlcMaximumMsat: edgeUpdateToFail.MaxHTLC, - BaseFee: uint32(edgeUpdateToFail.FeeBaseMSat), - FeeRate: uint32(edgeUpdateToFail.FeeProportionalMillionths), - } + edgeUpdToFail, ok := edgeUpdateToFail.(*models.ChannelEdgePolicy1) + require.True(t, ok) + + errChanUpdate, err := netann.UnsignedChannelUpdateFromEdge( + chainhash.Hash{}, edgeUpdToFail, + ) + require.NoError(t, err) // We'll now modify the SendToSwitch method to return an error for the // outgoing channel to son goku. Since this is a time lock related @@ -965,7 +978,7 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) { if firstHop == roasbeefSongoku { return [32]byte{}, htlcswitch.NewForwardingError( &lnwire.FailExpiryTooSoon{ - Update: errChanUpdate, + Update: *errChanUpdate, }, 1, ) } @@ -1013,7 +1026,7 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) { if firstHop == roasbeefSongoku { return [32]byte{}, htlcswitch.NewForwardingError( &lnwire.FailIncorrectCltvExpiry{ - Update: errChanUpdate, + Update: *errChanUpdate, }, 1, ) } diff --git a/rpcserver.go b/rpcserver.go index 10388e88ea..d133788acc 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -6517,7 +6517,7 @@ func (r *rpcServer) DescribeGraph(ctx context.Context, // similar response which details both the edge information as well as // the routing policies of th nodes connecting the two edges. err = graph.ForEachChannel(func(edgeInfo models.ChannelEdgeInfo, - c1, c2 *models.ChannelEdgePolicy1) error { + c1, c2 models.ChannelEdgePolicy) error { // Do not include unannounced channels unless specifically // requested. Unannounced channels include both private channels as @@ -6751,7 +6751,7 @@ func (r *rpcServer) GetChanInfo(_ context.Context, var ( edgeInfo models.ChannelEdgeInfo - edge1, edge2 *models.ChannelEdgePolicy1 + edge1, edge2 models.ChannelEdgePolicy err error ) @@ -6824,7 +6824,7 @@ func (r *rpcServer) GetNodeInfo(ctx context.Context, err = graph.ForEachNodeChannel(node.PubKeyBytes, func(_ kvdb.RTx, edge models.ChannelEdgeInfo, - c1, c2 *models.ChannelEdgePolicy1) error { + c1, c2 models.ChannelEdgePolicy) error { numChannels++ totalCapacity += edge.GetCapacity() @@ -7484,7 +7484,7 @@ func (r *rpcServer) FeeReport(ctx context.Context, var feeReports []*lnrpc.ChannelFeeReport err = channelGraph.ForEachNodeChannel(selfNode.PubKeyBytes, func(_ kvdb.RTx, chanInfo models.ChannelEdgeInfo, - edgePolicy, _ *models.ChannelEdgePolicy1) error { + edgePolicy, _ models.ChannelEdgePolicy) error { // Self node should always have policies for its // channels. @@ -7498,17 +7498,18 @@ func (r *rpcServer) FeeReport(ctx context.Context, // rate. The fee rate field in the database the amount // of mSAT charged per 1mil mSAT sent, so will divide by // this to get the proper fee rate. - feeRateFixedPoint := - edgePolicy.FeeProportionalMillionths + fwdPol := edgePolicy.ForwardingPolicy() + feeRateFixedPoint := fwdPol.FeeRate feeRate := float64(feeRateFixedPoint) / feeBase // Decode inbound fee from extra data. var inboundFee lnwire.Fee - _, err := edgePolicy.ExtraOpaqueData.ExtractRecords( - &inboundFee, - ) - if err != nil { - return err + + if pol, ok := edgePolicy.(*models.ChannelEdgePolicy1); ok { + _, err := pol.ExtraOpaqueData.ExtractRecords(&inboundFee) + if err != nil { + return err + } } // TODO(roasbeef): also add stats for revenue for each @@ -7516,7 +7517,7 @@ func (r *rpcServer) FeeReport(ctx context.Context, feeReports = append(feeReports, &lnrpc.ChannelFeeReport{ ChanId: chanInfo.GetChanID(), ChannelPoint: chanInfo.GetChanPoint().String(), - BaseFeeMsat: int64(edgePolicy.FeeBaseMSat), + BaseFeeMsat: int64(fwdPol.BaseFee), FeePerMil: int64(feeRateFixedPoint), FeeRate: feeRate, diff --git a/server.go b/server.go index e628de4f6f..dc374697fd 100644 --- a/server.go +++ b/server.go @@ -1349,7 +1349,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, // Wrap the DeleteChannelEdges method so that the funding manager can // use it without depending on several layers of indirection. deleteAliasEdge := func(scid lnwire.ShortChannelID) ( - *models.ChannelEdgePolicy1, error) { + models.ChannelEdgePolicy, error) { info, e1, e2, err := s.graphDB.FetchChannelEdgesByID( scid.ToUint64(), @@ -1368,7 +1368,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, var ourKey [33]byte copy(ourKey[:], nodeKeyDesc.PubKey.SerializeCompressed()) - var ourPolicy *models.ChannelEdgePolicy1 + var ourPolicy models.ChannelEdgePolicy if info != nil && info.Node1Bytes() == ourKey { ourPolicy = e1 } else { @@ -1383,6 +1383,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, err = s.graphDB.DeleteChannelEdges( false, false, scid.ToUint64(), ) + return ourPolicy, err } @@ -3316,7 +3317,7 @@ func (s *server) establishPersistentConnections() error { err = s.graphDB.ForEachNodeChannel(sourceNode.PubKeyBytes, func( tx kvdb.RTx, chanInfo models.ChannelEdgeInfo, - policy, _ *models.ChannelEdgePolicy1) error { + policy, _ models.ChannelEdgePolicy) error { chanPoint := chanInfo.GetChanPoint() From 0506d85450bc5fd1b0c8f0691939ca9468bb1dc9 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 6 Nov 2023 13:55:05 +0200 Subject: [PATCH 26/60] channeldb: prep waiting proof store for taproot proofs With a migration to migrate existing entries in the waiting proof store to use a type byte prefix. --- channeldb/db.go | 5 + channeldb/log.go | 2 + channeldb/migration34/log.go | 14 ++ channeldb/migration34/migration.go | 55 +++++++ channeldb/migration34/migration_test.go | 100 ++++++++++++ channeldb/migration34/waitingproof.go | 100 ++++++++++++ channeldb/waitingproof.go | 208 +++++++++++++++++++++--- channeldb/waitingproof_test.go | 74 ++++++--- discovery/gossiper.go | 14 +- 9 files changed, 528 insertions(+), 44 deletions(-) create mode 100644 channeldb/migration34/log.go create mode 100644 channeldb/migration34/migration.go create mode 100644 channeldb/migration34/migration_test.go create mode 100644 channeldb/migration34/waitingproof.go diff --git a/channeldb/db.go b/channeldb/db.go index 92e0498ece..044efe2a13 100644 --- a/channeldb/db.go +++ b/channeldb/db.go @@ -28,6 +28,7 @@ import ( "github.com/lightningnetwork/lnd/channeldb/migration31" "github.com/lightningnetwork/lnd/channeldb/migration32" "github.com/lightningnetwork/lnd/channeldb/migration33" + "github.com/lightningnetwork/lnd/channeldb/migration34" "github.com/lightningnetwork/lnd/channeldb/migration_01_to_11" "github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/invoices" @@ -296,6 +297,10 @@ var ( number: 33, migration: migration33.MigrateMCStoreNameSpacedResults, }, + { + number: 34, + migration: migration34.MigrateWaitingProofStore, + }, } // optionalVersions stores all optional migrations that are applied diff --git a/channeldb/log.go b/channeldb/log.go index 10b1b54d3c..bbb598109b 100644 --- a/channeldb/log.go +++ b/channeldb/log.go @@ -12,6 +12,7 @@ import ( "github.com/lightningnetwork/lnd/channeldb/migration31" "github.com/lightningnetwork/lnd/channeldb/migration32" "github.com/lightningnetwork/lnd/channeldb/migration33" + "github.com/lightningnetwork/lnd/channeldb/migration34" "github.com/lightningnetwork/lnd/channeldb/migration_01_to_11" "github.com/lightningnetwork/lnd/kvdb" ) @@ -46,5 +47,6 @@ func UseLogger(logger btclog.Logger) { migration31.UseLogger(logger) migration32.UseLogger(logger) migration33.UseLogger(logger) + migration34.UseLogger(logger) kvdb.UseLogger(logger) } diff --git a/channeldb/migration34/log.go b/channeldb/migration34/log.go new file mode 100644 index 0000000000..79f94eef47 --- /dev/null +++ b/channeldb/migration34/log.go @@ -0,0 +1,14 @@ +package migration34 + +import ( + "github.com/btcsuite/btclog" +) + +// log is a logger that is initialized as disabled. This means the package will +// not perform any logging by default until a logger is set. +var log = btclog.Disabled + +// UseLogger uses a specified Logger to output package logging info. +func UseLogger(logger btclog.Logger) { + log = logger +} diff --git a/channeldb/migration34/migration.go b/channeldb/migration34/migration.go new file mode 100644 index 0000000000..8886179960 --- /dev/null +++ b/channeldb/migration34/migration.go @@ -0,0 +1,55 @@ +package migration34 + +import ( + "bytes" + "fmt" + + "github.com/lightningnetwork/lnd/kvdb" +) + +// waitingProofsBucketKey byte string name of the waiting proofs store. +var waitingProofsBucketKey = []byte("waitingproofs") + +// MigrateWaitingProofStore migrates the waiting proof store so that all entries +// are prefixed with a type byte. +func MigrateWaitingProofStore(tx kvdb.RwTx) error { + log.Infof("Migrating waiting proof store") + + bucket := tx.ReadWriteBucket(waitingProofsBucketKey) + + // If the bucket does not exist yet, then there are no entries to + // migrate. + if bucket == nil { + return nil + } + + return bucket.ForEach(func(k, v []byte) error { + // Skip buckets fields. + if v == nil { + return nil + } + + // Read in the waiting proof using the legacy decoding method. + var proof WaitingProof + if err := proof.LegacyDecode(bytes.NewReader(v)); err != nil { + return err + } + + // Do sanity check to ensure that the proof key is the same as + // the key used to store the proof. + key := proof.Key() + if !bytes.Equal(key[:], k) { + return fmt.Errorf("proof key (%x) does not match "+ + "the key used to store the proof: %x", key, k) + } + + // Re-encode the proof using the new, type-prefixed encoding. + var b bytes.Buffer + err := proof.UpdatedEncode(&b) + if err != nil { + return err + } + + return bucket.Put(k, b.Bytes()) + }) +} diff --git a/channeldb/migration34/migration_test.go b/channeldb/migration34/migration_test.go new file mode 100644 index 0000000000..a26d8b6c26 --- /dev/null +++ b/channeldb/migration34/migration_test.go @@ -0,0 +1,100 @@ +package migration34 + +import ( + "bytes" + "encoding/hex" + "testing" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/ecdsa" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" + "github.com/lightningnetwork/lnd/channeldb/migtest" + "github.com/lightningnetwork/lnd/kvdb" + "github.com/stretchr/testify/require" +) + +var ( + testRBytes, _ = hex.DecodeString("8ce2bc69281ce27da07e6683571" + + "319d18e949ddfa2965fb6caa1bf0314f882d7") + testSBytes, _ = hex.DecodeString("299105481d63e0f4bc2a" + + "88121167221b6700d72a0ead154c03be696a292d24ae") + testRScalar = new(btcec.ModNScalar) + testSScalar = new(btcec.ModNScalar) + _ = testRScalar.SetByteSlice(testRBytes) + _ = testSScalar.SetByteSlice(testSBytes) + testSig = ecdsa.NewSignature(testRScalar, testSScalar) + + sig, _ = lnwire.NewSigFromSignature(testSig) + + wp1 = &WaitingProof{ + AnnounceSignatures: &lnwire.AnnounceSignatures{ + ChannelID: lnwire.ChannelID{1}, + ShortChannelID: lnwire.NewShortChanIDFromInt(1), + NodeSignature: sig, + BitcoinSignature: sig, + ExtraOpaqueData: []byte{1, 2, 3, 4}, + }, + isRemote: false, + } + + wp2 = &WaitingProof{ + AnnounceSignatures: &lnwire.AnnounceSignatures{ + ChannelID: lnwire.ChannelID{2}, + ShortChannelID: lnwire.NewShortChanIDFromInt(2), + NodeSignature: sig, + BitcoinSignature: sig, + }, + isRemote: true, + } +) + +// TestMigrationWaitingProofStore tests that the MigrateWaitingProofStore +// function works as expected. +func TestMigrateWaitingProofStore(t *testing.T) { + var ( + key1 = wp1.Key() + key2 = wp2.Key() + wp1BytesBefore bytes.Buffer + wp2BytesBefore bytes.Buffer + wp1BytesAfter bytes.Buffer + wp2BytesAfter bytes.Buffer + ) + + err := wp1.LegacyEncode(&wp1BytesBefore) + require.NoError(t, err) + + err = wp2.LegacyEncode(&wp2BytesBefore) + require.NoError(t, err) + + wpStoreBefore := map[string]interface{}{ + string(key1[:]): wp1BytesBefore.String(), + string(key2[:]): wp2BytesBefore.String(), + } + + err = wp1.UpdatedEncode(&wp1BytesAfter) + require.NoError(t, err) + + err = wp2.UpdatedEncode(&wp2BytesAfter) + require.NoError(t, err) + + wpStoreAfter := map[string]interface{}{ + string(key1[:]): wp1BytesAfter.String(), + string(key2[:]): wp2BytesAfter.String(), + } + + before := func(tx kvdb.RwTx) error { + return migtest.RestoreDB( + tx, waitingProofsBucketKey, wpStoreBefore, + ) + } + + after := func(tx kvdb.RwTx) error { + return migtest.VerifyDB( + tx, waitingProofsBucketKey, wpStoreAfter, + ) + } + + migtest.ApplyMigration( + t, before, after, MigrateWaitingProofStore, false, + ) +} diff --git a/channeldb/migration34/waitingproof.go b/channeldb/migration34/waitingproof.go new file mode 100644 index 0000000000..adb28c40ef --- /dev/null +++ b/channeldb/migration34/waitingproof.go @@ -0,0 +1,100 @@ +package migration34 + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" +) + +var byteOrder = binary.BigEndian + +// WaitingProofType represents the type of the encoded waiting proof. +type WaitingProofType uint8 + +const ( + // WaitingProofTypeLegacy represents a waiting proof for legacy P2WSH + // channels. + WaitingProofTypeLegacy WaitingProofType = 0 +) + +// WaitingProofKey is the proof key which uniquely identifies the waiting +// proof object. The goal of this key is distinguish the local and remote +// proof for the same channel id. +type WaitingProofKey [9]byte + +// WaitingProof is the storable object, which encapsulate the half proof and +// the information about from which side this proof came. This structure is +// needed to make channel proof exchange persistent, so that after client +// restart we may receive remote/local half proof and process it. +type WaitingProof struct { + *lnwire.AnnounceSignatures + isRemote bool +} + +// Key returns the key which uniquely identifies waiting proof. +func (p *WaitingProof) Key() WaitingProofKey { + var key [9]byte + binary.BigEndian.PutUint64(key[:8], p.ShortChannelID.ToUint64()) + + if p.isRemote { + key[8] = 1 + } + + return key +} + +// UpdatedEncode writes the internal representation of waiting proof in byte +// stream using the new format that is prefixed with a type byte. +func (p *WaitingProof) UpdatedEncode(w io.Writer) error { + // Write the type byte. + err := binary.Write(w, byteOrder, WaitingProofTypeLegacy) + if err != nil { + return err + } + + if err := binary.Write(w, byteOrder, p.isRemote); err != nil { + return err + } + + buf, ok := w.(*bytes.Buffer) + if !ok { + return fmt.Errorf("expect io.Writer to be *bytes.Buffer") + } + + return p.AnnounceSignatures.Encode(buf, 0) +} + +// LegacyEncode writes the internal representation of waiting proof in byte +// stream using the legacy format. +func (p *WaitingProof) LegacyEncode(w io.Writer) error { + if err := binary.Write(w, byteOrder, p.isRemote); err != nil { + return err + } + + buf, ok := w.(*bytes.Buffer) + if !ok { + return fmt.Errorf("expect io.Writer to be *bytes.Buffer") + } + + return p.AnnounceSignatures.Encode(buf, 0) +} + +// LegacyDecode reads the data from the byte stream and initializes the +// waiting proof object with it. +func (p *WaitingProof) LegacyDecode(r io.Reader) error { + if err := binary.Read(r, byteOrder, &p.isRemote); err != nil { + return err + } + + msg := &lnwire.AnnounceSignatures{} + if err := msg.Decode(r, 0); err != nil { + return err + } + + p.AnnounceSignatures = msg + + return nil +} diff --git a/channeldb/waitingproof.go b/channeldb/waitingproof.go index faefc620ce..419addec36 100644 --- a/channeldb/waitingproof.go +++ b/channeldb/waitingproof.go @@ -7,6 +7,7 @@ import ( "io" "sync" + "github.com/btcsuite/btcd/btcec/v2" "github.com/go-errors/errors" "github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/lnwire" @@ -20,11 +21,6 @@ var ( // found by db. ErrWaitingProofNotFound = errors.New("waiting proofs haven't been " + "found") - - // ErrWaitingProofAlreadyExist is returned if waiting proofs haven't been - // found by db. - ErrWaitingProofAlreadyExist = errors.New("waiting proof with such " + - "key already exist") ) // WaitingProofStore is the bold db map-like storage for half announcement @@ -186,29 +182,191 @@ func (s *WaitingProofStore) Get(key WaitingProofKey) (*WaitingProof, error) { // proof for the same channel id. type WaitingProofKey [9]byte +// WaitingProofType represents the type of the encoded waiting proof. +type WaitingProofType uint8 + +const ( + // WaitingProofTypeLegacy represents a waiting proof for legacy P2WSH + // channels. + WaitingProofTypeLegacy WaitingProofType = 0 + + // WaitingProofTypeTaproot represents a waiting proof for taproot + // channels. + WaitingProofTypeTaproot WaitingProofType = 1 +) + +// typeToWaitingProofType is a map from WaitingProofType to an empty +// instantiation of the associated type. +func typeToWaitingProof(pt WaitingProofType) (WaitingProofInterface, bool) { + switch pt { + case WaitingProofTypeLegacy: + return &LegacyWaitingProof{}, true + case WaitingProofTypeTaproot: + return &TaprootWaitingProof{}, true + + default: + return nil, false + } +} + +// WaitingProofInterface is an interface that must be implemented by any waiting +// proof to be stored in the waiting proof DB. +type WaitingProofInterface interface { + // SCID returns the short channel ID of the channel that the waiting + // proof is for. + SCID() lnwire.ShortChannelID + + // Encode encodes the waiting proof to the given buffer. + Encode(w *bytes.Buffer, pver uint32) error + + // Decode parses the bytes from the given reader to reconstruct the + // waiting proof. + Decode(r io.Reader, pver uint32) error + + // Type returns the waiting proof type. + Type() WaitingProofType +} + +// LegacyWaitingProof is an implementation of the WaitingProofInterface to be +// used for legacy, P2WSH channels. +type LegacyWaitingProof struct { + lnwire.AnnounceSignatures1 +} + +// SCID returns the short channel ID of the channel that the waiting +// proof is for. +// +// NOTE: this is part of the WaitingProofInterface. +func (l *LegacyWaitingProof) SCID() lnwire.ShortChannelID { + return l.ShortChannelID +} + +// Type returns the waiting proof type. +// +// NOTE: this is part of the WaitingProofInterface. +func (l *LegacyWaitingProof) Type() WaitingProofType { + return WaitingProofTypeLegacy +} + +var _ WaitingProofInterface = (*LegacyWaitingProof)(nil) + +// TaprootWaitingProof is an implementation of the WaitingProofInterface to be +// used for taproot channels. +type TaprootWaitingProof struct { + lnwire.AnnounceSignatures2 + + // AggNonce is the aggregate nonce used to construct the partial + // signatures. It will be used as the R value in the final signature. + AggNonce *btcec.PublicKey +} + +// SCID returns the short channel ID of the channel that the waiting +// proof is for. +// +// NOTE: this is part of the WaitingProofInterface. +func (t *TaprootWaitingProof) SCID() lnwire.ShortChannelID { + return t.ShortChannelID +} + +// Decode parses the bytes from the given reader to reconstruct the +// waiting proof. +// +// NOTE: this is part of the WaitingProofInterface. +func (t *TaprootWaitingProof) Decode(r io.Reader, pver uint32) error { + // Read byte to see if agg nonce is present. + var aggNoncePresent bool + if err := binary.Read(r, byteOrder, &aggNoncePresent); err != nil { + return err + } + + // If agg nonce is present, read it in. + if aggNoncePresent { + var nonceBytes [btcec.PubKeyBytesLenCompressed]byte + if err := binary.Read(r, byteOrder, &nonceBytes); err != nil { + return err + } + + nonce, err := btcec.ParsePubKey(nonceBytes[:]) + if err != nil { + return err + } + + t.AggNonce = nonce + } + + return t.AnnounceSignatures2.Decode(r, pver) +} + +// Encode encodes the waiting proof to the given buffer. +// +// NOTE: this is part of the WaitingProofInterface. +func (t *TaprootWaitingProof) Encode(w *bytes.Buffer, pver uint32) error { + // If agg nonce is present, write a signaling byte for that. + aggNoncePresent := t.AggNonce != nil + if err := binary.Write(w, byteOrder, aggNoncePresent); err != nil { + return err + } + + // Now follow with the actual nonce if present. + if aggNoncePresent { + err := binary.Write( + w, byteOrder, t.AggNonce.SerializeCompressed(), + ) + if err != nil { + return err + } + } + + return t.AnnounceSignatures2.Encode(w, pver) +} + +// Type returns the waiting proof type. +// +// NOTE: this is part of the WaitingProofInterface. +func (t *TaprootWaitingProof) Type() WaitingProofType { + return WaitingProofTypeTaproot +} + +var _ WaitingProofInterface = (*TaprootWaitingProof)(nil) + // WaitingProof is the storable object, which encapsulate the half proof and // the information about from which side this proof came. This structure is // needed to make channel proof exchange persistent, so that after client // restart we may receive remote/local half proof and process it. type WaitingProof struct { - *lnwire.AnnounceSignatures1 + WaitingProofInterface isRemote bool } -// NewWaitingProof constructs a new waiting prof instance. -func NewWaitingProof(isRemote bool, +// NewLegacyWaitingProof constructs a new waiting prof instance for a legacy, +// P2WSH channel. +func NewLegacyWaitingProof(isRemote bool, proof *lnwire.AnnounceSignatures1) *WaitingProof { return &WaitingProof{ - AnnounceSignatures1: proof, - isRemote: isRemote, + WaitingProofInterface: &LegacyWaitingProof{*proof}, + isRemote: isRemote, + } +} + +// NewTaprootWaitingProof constructs a new waiting prof instance for a taproot +// channel. +func NewTaprootWaitingProof(isRemote bool, proof *lnwire.AnnounceSignatures2, + aggNonce *btcec.PublicKey) *WaitingProof { + + return &WaitingProof{ + WaitingProofInterface: &TaprootWaitingProof{ + AnnounceSignatures2: *proof, + AggNonce: aggNonce, + }, + isRemote: isRemote, } } // OppositeKey returns the key which uniquely identifies opposite waiting proof. func (p *WaitingProof) OppositeKey() WaitingProofKey { var key [9]byte - binary.BigEndian.PutUint64(key[:8], p.ShortChannelID.ToUint64()) + binary.BigEndian.PutUint64(key[:8], p.SCID().ToUint64()) if !p.isRemote { key[8] = 1 @@ -219,7 +377,7 @@ func (p *WaitingProof) OppositeKey() WaitingProofKey { // Key returns the key which uniquely identifies waiting proof. func (p *WaitingProof) Key() WaitingProofKey { var key [9]byte - binary.BigEndian.PutUint64(key[:8], p.ShortChannelID.ToUint64()) + binary.BigEndian.PutUint64(key[:8], p.SCID().ToUint64()) if p.isRemote { key[8] = 1 @@ -229,6 +387,11 @@ func (p *WaitingProof) Key() WaitingProofKey { // Encode writes the internal representation of waiting proof in byte stream. func (p *WaitingProof) Encode(w io.Writer) error { + // Write the type byte. + if err := binary.Write(w, byteOrder, p.Type()); err != nil { + return err + } + if err := binary.Write(w, byteOrder, p.isRemote); err != nil { return err } @@ -240,26 +403,31 @@ func (p *WaitingProof) Encode(w io.Writer) error { return fmt.Errorf("expect io.Writer to be *bytes.Buffer") } - if err := p.AnnounceSignatures1.Encode(buf, 0); err != nil { - return err - } - - return nil + return p.WaitingProofInterface.Encode(buf, 0) } // Decode reads the data from the byte stream and initializes the // waiting proof object with it. func (p *WaitingProof) Decode(r io.Reader) error { + var proofType WaitingProofType + if err := binary.Read(r, byteOrder, &proofType); err != nil { + return err + } + if err := binary.Read(r, byteOrder, &p.isRemote); err != nil { return err } - msg := &lnwire.AnnounceSignatures1{} - if err := msg.Decode(r, 0); err != nil { + proof, ok := typeToWaitingProof(proofType) + if !ok { + return fmt.Errorf("unknown proof type") + } + + if err := proof.Decode(r, 0); err != nil { return err } - p.AnnounceSignatures1 = msg + p.WaitingProofInterface = proof return nil } diff --git a/channeldb/waitingproof_test.go b/channeldb/waitingproof_test.go index d7113d9e75..21568d169e 100644 --- a/channeldb/waitingproof_test.go +++ b/channeldb/waitingproof_test.go @@ -1,10 +1,10 @@ package channeldb import ( - "reflect" + "math/rand" "testing" - "github.com/davecgh/go-spew/spew" + "github.com/btcsuite/btcd/btcec/v2" "github.com/go-errors/errors" "github.com/lightningnetwork/lnd/lnwire" "github.com/stretchr/testify/require" @@ -18,35 +18,54 @@ func TestWaitingProofStore(t *testing.T) { db, err := MakeTestDB(t) require.NoError(t, err, "failed to make test database") - proof1 := NewWaitingProof(true, &lnwire.AnnounceSignatures1{ + proof1 := NewLegacyWaitingProof(true, &lnwire.AnnounceSignatures1{ NodeSignature: wireSig, BitcoinSignature: wireSig, ExtraOpaqueData: make([]byte, 0), }) - store, err := NewWaitingProofStore(db) - if err != nil { - t.Fatalf("unable to create the waiting proofs storage: %v", - err) - } + // No agg nonce. + proof2 := NewTaprootWaitingProof(true, &lnwire.AnnounceSignatures2{ + ShortChannelID: lnwire.ShortChannelID{ + BlockHeight: 2000, + }, + PartialSignature: *randPartialSig(t), + ExtraOpaqueData: make([]byte, 0), + }, nil) - if err := store.Add(proof1); err != nil { - t.Fatalf("unable add proof to storage: %v", err) - } + // With agg nonce. + priv, err := btcec.NewPrivateKey() + require.NoError(t, err) - proof2, err := store.Get(proof1.Key()) - require.NoError(t, err, "unable retrieve proof from storage") - if !reflect.DeepEqual(proof1, proof2) { - t.Fatalf("wrong proof retrieved: expected %v, got %v", - spew.Sdump(proof1), spew.Sdump(proof2)) - } + proof3 := NewTaprootWaitingProof(true, &lnwire.AnnounceSignatures2{ + ShortChannelID: lnwire.ShortChannelID{ + BlockHeight: 2000, + }, + PartialSignature: *randPartialSig(t), + ExtraOpaqueData: make([]byte, 0), + }, priv.PubKey()) - if _, err := store.Get(proof1.OppositeKey()); err != ErrWaitingProofNotFound { - t.Fatalf("proof shouldn't be found: %v", err) + proofs := []*WaitingProof{ + proof1, + proof2, + proof3, } - if err := store.Remove(proof1.Key()); err != nil { - t.Fatalf("unable remove proof from storage: %v", err) + store, err := NewWaitingProofStore(db) + require.NoError(t, err) + + for _, proof := range proofs { + require.NoError(t, store.Add(proof)) + + p2, err := store.Get(proof.Key()) + require.NoError(t, err, "unable retrieve proof from storage") + require.Equal(t, proof, p2) + + _, err = store.Get(proof.OppositeKey()) + require.ErrorIs(t, err, ErrWaitingProofNotFound) + + err = store.Remove(proof.Key()) + require.NoError(t, err) } if err := store.ForAll(func(proof *WaitingProof) error { @@ -55,3 +74,16 @@ func TestWaitingProofStore(t *testing.T) { t.Fatal(err) } } + +func randPartialSig(t *testing.T) *lnwire.PartialSig { + var sigBytes [32]byte + _, err := rand.Read(sigBytes[:]) + require.NoError(t, err) + + var s btcec.ModNScalar + s.SetByteSlice(sigBytes[:]) + + return &lnwire.PartialSig{ + Sig: s, + } +} diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 31497389f5..e1d4d8406e 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -3356,7 +3356,7 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, return nil, false } - proof := channeldb.NewWaitingProof(nMsg.isRemote, ann) + proof := channeldb.NewLegacyWaitingProof(nMsg.isRemote, ann) err := d.cfg.WaitingProofStore.Add(proof) if err != nil { err := fmt.Errorf("unable to store the proof for "+ @@ -3468,8 +3468,8 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, // announcement. If we didn't receive the opposite half of the proof // then we should store this one, and wait for the opposite to be // received. - proof := channeldb.NewWaitingProof(nMsg.isRemote, ann) - oppProof, err := d.cfg.WaitingProofStore.Get(proof.OppositeKey()) + proof := channeldb.NewLegacyWaitingProof(nMsg.isRemote, ann) + oppositeProof, err := d.cfg.WaitingProofStore.Get(proof.OppositeKey()) if err != nil && err != channeldb.ErrWaitingProofNotFound { err := fmt.Errorf("unable to get the opposite proof for "+ "short_chan_id=%v: %v", shortChanID, err) @@ -3496,6 +3496,14 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, return nil, false } + oppProof, ok := oppositeProof. + WaitingProofInterface.(*channeldb.LegacyWaitingProof) + if !ok { + nMsg.err <- fmt.Errorf("got wrong waiting proof type") + + return nil, false + } + // We now have both halves of the channel announcement proof, then // we'll reconstruct the initial announcement so we can validate it // shortly below. From 9a6a95cdd76c209600eff0ff73ddf0a40ee4137c Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 09:04:20 +0200 Subject: [PATCH 27/60] discovery: let handlAnnSig take lnwire.AnnounceSigs interface --- discovery/gossiper.go | 199 ++++++++++++++++++++++++++++++++---------- 1 file changed, 151 insertions(+), 48 deletions(-) diff --git a/discovery/gossiper.go b/discovery/gossiper.go index e1d4d8406e..b5a653891f 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -10,6 +10,7 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2/ecdsa" + "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" @@ -87,6 +88,7 @@ type optionalMsgFields struct { channelPoint *wire.OutPoint remoteAlias *lnwire.ShortChannelID tapscriptRoot fn.Option[chainhash.Hash] + aggNonce *btcec.PublicKey } // apply applies the optional fields within the functional options. @@ -125,6 +127,15 @@ func TapscriptRoot(root fn.Option[chainhash.Hash]) OptionalMsgField { } } +// AggregateNonce is an optional field that lets the gossiper know of the +// aggregate nonce used in the construction of the channel announcement +// signature. +func AggregateNonce(nonce *btcec.PublicKey) OptionalMsgField { + return func(f *optionalMsgFields) { + f.aggNonce = nonce + } +} + // RemoteAlias is an optional field that lets the gossiper know that a locally // sent channel update is actually an update for the peer that should replace // the ShortChannelID field with the remote's alias. This is only used for @@ -2098,7 +2109,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement( // A new signature announcement has been received. This indicates // willingness of nodes involved in the funding of a channel to // announce this new channel to the rest of the world. - case *lnwire.AnnounceSignatures1: + case lnwire.AnnounceSignatures: return d.handleAnnSig(nMsg, msg) default: @@ -3302,27 +3313,28 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // handleAnnSig processes a new announcement signatures message. func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, - ann *lnwire.AnnounceSignatures1) ([]networkMsg, bool) { + ann lnwire.AnnounceSignatures) ([]networkMsg, bool) { - needBlockHeight := ann.ShortChannelID.BlockHeight + - d.cfg.ProofMatureDelta - shortChanID := ann.ShortChannelID.ToUint64() + var ( + scid = ann.SCID() + chanID = ann.ChanID() + ) + + needBlockHeight := scid.BlockHeight + d.cfg.ProofMatureDelta + shortChanID := scid.ToUint64() prefix := "local" if nMsg.isRemote { prefix = "remote" } - log.Infof("Received new %v announcement signature for %v", prefix, - ann.ShortChannelID) + log.Infof("Received new %v announcement signature for %v", prefix, scid) // By the specification, channel announcement proofs should be sent // after some number of confirmations after channel was registered in // bitcoin blockchain. Therefore, we check if the proof is mature. d.Lock() - premature := d.isPremature( - ann.ShortChannelID, d.cfg.ProofMatureDelta, nMsg, - ) + premature := d.isPremature(scid, d.cfg.ProofMatureDelta, nMsg) if premature { log.Warnf("Premature proof announcement, current block height"+ "lower than needed: %v < %v", d.bestHeight, @@ -3339,14 +3351,12 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, // We must acquire the mutex for this channel ID before getting the // channel from the database, to ensure what we read does not change // before we call AddProof() later. - d.channelMtx.Lock(ann.ShortChannelID.ToUint64()) - defer d.channelMtx.Unlock(ann.ShortChannelID.ToUint64()) + d.channelMtx.Lock(scid.ToUint64()) + defer d.channelMtx.Unlock(scid.ToUint64()) - chanInfo, e1, e2, err := d.cfg.Graph.GetChannelByID( - ann.ShortChannelID, - ) + chanInfo, e1, e2, err := d.cfg.Graph.GetChannelByID(scid) if err != nil { - _, err = d.cfg.FindChannel(nMsg.source, ann.ChannelID) + _, err = d.cfg.FindChannel(nMsg.source, chanID) if err != nil { err := fmt.Errorf("unable to store the proof for "+ "short_chan_id=%v: %v", shortChanID, err) @@ -3356,19 +3366,37 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, return nil, false } - proof := channeldb.NewLegacyWaitingProof(nMsg.isRemote, ann) + var proof *channeldb.WaitingProof + switch a := ann.(type) { + case *lnwire.AnnounceSignatures1: + proof = channeldb.NewLegacyWaitingProof( + nMsg.isRemote, a, + ) + case *lnwire.AnnounceSignatures2: + var aggNonce *btcec.PublicKey + if nMsg.optionalMsgFields != nil { + aggNonce = nMsg.optionalMsgFields.aggNonce + } + + proof = channeldb.NewTaprootWaitingProof( + nMsg.isRemote, a, aggNonce, + ) + } + err := d.cfg.WaitingProofStore.Add(proof) if err != nil { err := fmt.Errorf("unable to store the proof for "+ "short_chan_id=%v: %v", shortChanID, err) log.Error(err) nMsg.err <- err + return nil, false } log.Infof("Orphan %v proof announcement with short_chan_id=%v"+ ", adding to waiting batch", prefix, shortChanID) nMsg.err <- nil + return nil, false } @@ -3410,15 +3438,15 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, if err != nil { err := fmt.Errorf("unable to reliably send %v for "+ "channel=%v to peer=%x: %v", ann.MsgType(), - ann.ShortChannelID, remotePubKey, err) + scid, remotePubKey, err) nMsg.err <- err return nil, false } } // Check if we already have the full proof for this channel. - authInfo := chanInfo.GetAuthProof() - if authInfo != nil { + authProof := chanInfo.GetAuthProof() + if authProof != nil { // If we already have the fully assembled proof, then the peer // sending us their proof has probably not received our local // proof yet. So be kind and send them the full proof. @@ -3434,10 +3462,10 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, log.Debugf("Received half proof for channel "+ "%v with existing full proof. Sending"+ " full proof to peer=%x", - ann.ChannelID, peerID) + chanID, peerID) ca, _, _, err := netann.CreateChanAnnouncement( - authInfo, chanInfo, e1, e2, + authProof, chanInfo, e1, e2, ) if err != nil { log.Errorf("unable to gen ann: %v", @@ -3453,12 +3481,12 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, } log.Debugf("Full proof sent to peer=%x for "+ - "chanID=%v", peerID, ann.ChannelID) + "chanID=%v", peerID, chanID) }() } log.Debugf("Already have proof for channel with chanID=%v", - ann.ChannelID) + chanID) nMsg.err <- nil return nil, true } @@ -3468,7 +3496,25 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, // announcement. If we didn't receive the opposite half of the proof // then we should store this one, and wait for the opposite to be // received. - proof := channeldb.NewLegacyWaitingProof(nMsg.isRemote, ann) + var ( + proof *channeldb.WaitingProof + aggNonce *btcec.PublicKey + ) + switch a := ann.(type) { + case *lnwire.AnnounceSignatures1: + proof = channeldb.NewLegacyWaitingProof( + nMsg.isRemote, a, + ) + case *lnwire.AnnounceSignatures2: + if nMsg.optionalMsgFields != nil { + aggNonce = nMsg.optionalMsgFields.aggNonce + } + + proof = channeldb.NewTaprootWaitingProof( + nMsg.isRemote, a, aggNonce, + ) + } + oppositeProof, err := d.cfg.WaitingProofStore.Get(proof.OppositeKey()) if err != nil && err != channeldb.ErrWaitingProofNotFound { err := fmt.Errorf("unable to get the opposite proof for "+ @@ -3496,36 +3542,93 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, return nil, false } - oppProof, ok := oppositeProof. - WaitingProofInterface.(*channeldb.LegacyWaitingProof) - if !ok { - nMsg.err <- fmt.Errorf("got wrong waiting proof type") - - return nil, false - } - // We now have both halves of the channel announcement proof, then // we'll reconstruct the initial announcement so we can validate it // shortly below. - var dbProof models.ChannelAuthProof1 - if isFirstNode { - dbProof.NodeSig1Bytes = ann.NodeSignature.ToSignatureBytes() - dbProof.NodeSig2Bytes = oppProof.NodeSignature.ToSignatureBytes() - dbProof.BitcoinSig1Bytes = ann.BitcoinSignature.ToSignatureBytes() - dbProof.BitcoinSig2Bytes = oppProof.BitcoinSignature.ToSignatureBytes() - } else { - dbProof.NodeSig1Bytes = oppProof.NodeSignature.ToSignatureBytes() - dbProof.NodeSig2Bytes = ann.NodeSignature.ToSignatureBytes() - dbProof.BitcoinSig1Bytes = oppProof.BitcoinSignature.ToSignatureBytes() - dbProof.BitcoinSig2Bytes = ann.BitcoinSignature.ToSignatureBytes() + var dbProof models.ChannelAuthProof + + switch oppProof := oppositeProof.WaitingProofInterface.(type) { + case *channeldb.LegacyWaitingProof: + a, ok := ann.(*lnwire.AnnounceSignatures1) + if !ok { + err := fmt.Errorf("expected "+ + "*lnwire.AnnouncementSignatures1, got: %T", ann) + + log.Error(err) + nMsg.err <- err + + return nil, false + } + + var ( + dbProof1 models.ChannelAuthProof1 + nodeSig = a.NodeSignature.ToSignatureBytes() + btcSig = a.BitcoinSignature.ToSignatureBytes() + oppNodeSig = oppProof.NodeSignature.ToSignatureBytes() + oppBtcSig = oppProof.BitcoinSignature. + ToSignatureBytes() + ) + if isFirstNode { + dbProof1.NodeSig1Bytes = nodeSig + dbProof1.NodeSig2Bytes = oppNodeSig + dbProof1.BitcoinSig1Bytes = btcSig + dbProof1.BitcoinSig2Bytes = oppBtcSig + } else { + dbProof1.NodeSig1Bytes = oppNodeSig + dbProof1.NodeSig2Bytes = nodeSig + dbProof1.BitcoinSig1Bytes = oppBtcSig + dbProof1.BitcoinSig2Bytes = btcSig + } + dbProof = &dbProof1 + + case *channeldb.TaprootWaitingProof: + a, ok := ann.(*lnwire.AnnounceSignatures2) + if !ok { + err := fmt.Errorf("expected "+ + "*lnwire.AnnouncementSignatures2, got: %T", ann) + log.Error(err) + nMsg.err <- err + + return nil, false + } + + // First, combine the two partial sigs to get the final sig. At + // least one of proofs should have an agg nonce. + switch { + case aggNonce != nil: + case oppProof.AggNonce != nil: + aggNonce = oppProof.AggNonce + default: + nMsg.err <- fmt.Errorf("didnt get an agg nonce") + + return nil, false + } + + ps1 := musig2.NewPartialSignature( + &a.PartialSignature.Sig, aggNonce, + ) + + ps2 := musig2.NewPartialSignature( + &oppProof.PartialSignature.Sig, aggNonce, + ) + + // Now aggregate the partial sigs. + s := musig2.CombineSigs( + aggNonce, []*musig2.PartialSignature{&ps1, &ps2}, + ) + + dbProof = &models.ChannelAuthProof2{ + SchnorrSigBytes: s.Serialize(), + } } chanAnn, e1Ann, e2Ann, err := netann.CreateChanAnnouncement( - &dbProof, chanInfo, e1, e2, + dbProof, chanInfo, e1, e2, ) if err != nil { log.Error(err) nMsg.err <- err + return nil, false } @@ -3547,10 +3650,10 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, // attest to the bitcoin keys by validating the signatures of // announcement. If proof is valid then we'll populate the channel edge // with it, so we can announce it on peer connect. - err = d.cfg.Graph.AddProof(ann.ShortChannelID, &dbProof) + err = d.cfg.Graph.AddProof(scid, dbProof) if err != nil { err := fmt.Errorf("unable add proof to the channel chanID=%v:"+ - " %v", ann.ChannelID, err) + " %v", chanID, err) log.Error(err) nMsg.err <- err return nil, false @@ -3559,7 +3662,7 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, err = d.cfg.WaitingProofStore.Remove(proof.OppositeKey()) if err != nil { err := fmt.Errorf("unable to remove opposite proof for the "+ - "channel with chanID=%v: %v", ann.ChannelID, err) + "channel with chanID=%v: %v", chanID, err) log.Error(err) nMsg.err <- err return nil, false From d00d03bd067d462ea0f07fd5ce48f7a44bdbb540 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 09:09:01 +0200 Subject: [PATCH 28/60] multi: use lnwire.AnnouncementSigs interface throughout --- discovery/gossiper.go | 8 +++----- discovery/message_store.go | 4 ++-- funding/manager.go | 2 +- graph/validation_barrier.go | 6 +++--- peer/brontide.go | 7 ++++--- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/discovery/gossiper.go b/discovery/gossiper.go index b5a653891f..c2015333d9 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -1452,7 +1452,7 @@ func (d *AuthenticatedGossiper) networkHandler() { switch announcement.msg.(type) { // Channel announcement signatures are amongst the only // messages that we'll process serially. - case *lnwire.AnnounceSignatures1: + case lnwire.AnnounceSignatures: emittedAnnouncements, _ := d.processNetworkAnnouncement( announcement, ) @@ -2193,10 +2193,8 @@ func (d *AuthenticatedGossiper) fetchNodeAnn( // MessageStore is seen as stale by the current graph. func (d *AuthenticatedGossiper) isMsgStale(msg lnwire.Message) bool { switch msg := msg.(type) { - case *lnwire.AnnounceSignatures1: - chanInfo, _, _, err := d.cfg.Graph.GetChannelByID( - msg.ShortChannelID, - ) + case lnwire.AnnounceSignatures: + chanInfo, _, _, err := d.cfg.Graph.GetChannelByID(msg.SCID()) // If the channel cannot be found, it is most likely a leftover // message for a channel that was closed, so we can consider it diff --git a/discovery/message_store.go b/discovery/message_store.go index 025a89d67a..e336c1281b 100644 --- a/discovery/message_store.go +++ b/discovery/message_store.go @@ -83,8 +83,8 @@ func NewMessageStore(db kvdb.Backend) (*MessageStore, error) { func msgShortChanID(msg lnwire.Message) (lnwire.ShortChannelID, error) { var shortChanID lnwire.ShortChannelID switch msg := msg.(type) { - case *lnwire.AnnounceSignatures1: - shortChanID = msg.ShortChannelID + case lnwire.AnnounceSignatures: + shortChanID = msg.SCID() case *lnwire.ChannelUpdate1: shortChanID = msg.ShortChannelID default: diff --git a/funding/manager.go b/funding/manager.go index f2f23abdd2..dcc9e94c9c 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -4293,7 +4293,7 @@ func (f *Manager) ensureInitialForwardingPolicy(chanID lnwire.ChannelID, type chanAnnouncement struct { chanAnn lnwire.ChannelAnnouncement chanUpdateAnn *lnwire.ChannelUpdate1 - chanProof *lnwire.AnnounceSignatures1 + chanProof lnwire.AnnounceSignatures } // newChanAnnouncement creates the authenticated channel announcement messages diff --git a/graph/validation_barrier.go b/graph/validation_barrier.go index bb431522a0..c1de127bad 100644 --- a/graph/validation_barrier.go +++ b/graph/validation_barrier.go @@ -153,7 +153,7 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) { return case *channeldb.LightningNode: return - case *lnwire.AnnounceSignatures1: + case lnwire.AnnounceSignatures: // TODO(roasbeef): need to wait on chan ann? return } @@ -215,7 +215,7 @@ func (v *ValidationBarrier) WaitForDependants(job interface{}) error { // Other types of jobs can be executed immediately, so we'll just // return directly. - case *lnwire.AnnounceSignatures1: + case lnwire.AnnounceSignatures: // TODO(roasbeef): need to wait on chan ann? case models.ChannelEdgeInfo: case lnwire.ChannelAnnouncement: @@ -301,7 +301,7 @@ func (v *ValidationBarrier) SignalDependants(job interface{}, allow bool) { case models.ChannelEdgePolicy: delete(v.chanEdgeDependencies, msg.SCID()) - case *lnwire.AnnounceSignatures1: + case lnwire.AnnounceSignatures: return } } diff --git a/peer/brontide.go b/peer/brontide.go index 8b61ad0341..56f713a4df 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -2044,6 +2044,7 @@ out: *lnwire.ChannelAnnouncement2, *lnwire.NodeAnnouncement, *lnwire.AnnounceSignatures1, + *lnwire.AnnounceSignatures2, *lnwire.GossipTimestampRange, *lnwire.QueryShortChanIDs, *lnwire.QueryChannelRange, @@ -2302,9 +2303,9 @@ func messageSummary(msg lnwire.Message) string { case *lnwire.Error: return fmt.Sprintf("%v", msg.Error()) - case *lnwire.AnnounceSignatures1: - return fmt.Sprintf("chan_id=%v, short_chan_id=%v", msg.ChannelID, - msg.ShortChannelID.ToUint64()) + case lnwire.AnnounceSignatures: + return fmt.Sprintf("chan_id=%v, short_chan_id=%v", msg.SCID(), + msg.SCID().ToUint64()) case lnwire.ChannelAnnouncement: return fmt.Sprintf("chain_hash=%v, short_chan_id=%v", From e8c0abe5fde4de8a7d2d8afae8c278252bd5a78d Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 23 Aug 2024 13:53:31 +0200 Subject: [PATCH 29/60] docs: update release notes --- docs/release-notes/release-notes-0.19.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/release-notes-0.19.0.md b/docs/release-notes/release-notes-0.19.0.md index f712d54dae..146de82ca9 100644 --- a/docs/release-notes/release-notes-0.19.0.md +++ b/docs/release-notes/release-notes-0.19.0.md @@ -73,6 +73,7 @@ * Use the new interfaces added for Gossip 1.75 throughout the codebase [1](https://github.com/lightningnetwork/lnd/pull/8252/). + [2](https://github.com/lightningnetwork/lnd/pull/8253). ## Testing ## Database From 83a7c5406374cb5fa2614146dab9c03b8b79bcd4 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 09:30:18 +0200 Subject: [PATCH 30/60] netann: give ChanStatusManager access to BestBlockView --- netann/chan_status_manager.go | 4 ++++ netann/chan_status_manager_test.go | 10 ++++++++++ server.go | 1 + 3 files changed, 15 insertions(+) diff --git a/netann/chan_status_manager.go b/netann/chan_status_manager.go index de1dc42773..d927a81008 100644 --- a/netann/chan_status_manager.go +++ b/netann/chan_status_manager.go @@ -7,6 +7,7 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/wire" + "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwallet" @@ -51,6 +52,9 @@ type ChanStatusConfig struct { // MessageSigner signs messages that validate under OurPubKey. MessageSigner lnwallet.MessageSigner + // BestBlockView gives access to the current best block. + BestBlockView chainntnfs.BestBlockView + // IsChannelActive checks whether the channel identified by the provided // ChannelID is considered active. This should only return true if the // channel has been sufficiently confirmed, the channel has received diff --git a/netann/chan_status_manager_test.go b/netann/chan_status_manager_test.go index 1288056a88..f0025d7eb9 100644 --- a/netann/chan_status_manager_test.go +++ b/netann/chan_status_manager_test.go @@ -15,6 +15,7 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2/ecdsa" "github.com/btcsuite/btcd/wire" + "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb/models" "github.com/lightningnetwork/lnd/keychain" @@ -344,6 +345,7 @@ func newManagerCfg(t *testing.T, numChannels int, ApplyChannelUpdate: graph.ApplyChannelUpdate, DB: graph, Graph: graph, + BestBlockView: &mockBlockView{}, } return cfg, graph, htlcSwitch @@ -937,3 +939,11 @@ func TestChanStatusManagerStateMachine(t *testing.T) { }) } } + +type mockBlockView struct { + chainntnfs.BestBlockView +} + +func (m *mockBlockView) BestHeight() (uint32, error) { + return 0, nil +} diff --git a/server.go b/server.go index dc374697fd..eb8b15b4a4 100644 --- a/server.go +++ b/server.go @@ -748,6 +748,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, ApplyChannelUpdate: s.applyChannelUpdate, DB: s.chanStateDB, Graph: dbs.GraphDB.ChannelGraph(), + BestBlockView: s.cc.BestBlockTracker, } chanStatusMgr, err := netann.NewChanStatusManager(chanStatusMgrCfg) From 1d1d222b4ab1a099d24a6f1598385e8ec2714475 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Thu, 16 Nov 2023 14:39:48 +0200 Subject: [PATCH 31/60] multi: use MessageSignerRing where needed In this commit, we pass the MessageSignerRing around in places where Schnorr signing will be needed to sign Gossip 1.75 messages. --- discovery/gossiper.go | 10 ++--- keychain/derivation.go | 6 +++ keychain/signer.go | 33 +++++++++++++++++ lnrpc/invoicesrpc/addinvoice.go | 2 +- lntest/mock/signer.go | 65 +++++++++++++++++++++++++++++++++ netann/chan_status_manager.go | 3 +- netann/channel_update.go | 6 +-- netann/channel_update_test.go | 4 +- netann/node_signer.go | 49 ++++++++++++++++++++++--- rpcserver.go | 2 +- 10 files changed, 161 insertions(+), 19 deletions(-) diff --git a/discovery/gossiper.go b/discovery/gossiper.go index c2015333d9..08268cecef 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -272,14 +272,14 @@ type Config struct { // use to determine which messages need to be resent for a given peer. MessageStore GossipMessageStore - // AnnSigner is an instance of the MessageSigner interface which will - // be used to manually sign any outgoing channel updates. The signer - // implementation should be backed by the public key of the backing - // Lightning node. + // AnnSigner is an instance of the MessageSignerRing interface which + // will be used to manually sign any outgoing channel updates. The + // signer implementation should be backed by the public key of the + // backing Lightning node. // // TODO(roasbeef): extract ann crafting + sign from fundingMgr into // here? - AnnSigner lnwallet.MessageSigner + AnnSigner keychain.MessageSignerRing // ScidCloser is an instance of ClosedChannelTracker that helps the // gossiper cut down on spam channel announcements for already closed diff --git a/keychain/derivation.go b/keychain/derivation.go index 2b1c43444e..050058ca6c 100644 --- a/keychain/derivation.go +++ b/keychain/derivation.go @@ -262,6 +262,12 @@ type SingleKeyMessageSigner interface { // hashing it first, with the wrapped private key and returns the // signature in the compact, public key recoverable format. SignMessageCompact(message []byte, doubleHash bool) ([]byte, error) + + // SignMessageSchnorr signs the given message, single or double SHA256 + // hashing it first, with the private key described in the key locator + // and the optional Taproot tweak applied to the private key. + SignMessageSchnorr(keyLoc KeyLocator, msg []byte, doubleHash bool, + taprootTweak, tag []byte) (*schnorr.Signature, error) } // ECDHRing is an interface that abstracts away basic low-level ECDH shared key diff --git a/keychain/signer.go b/keychain/signer.go index fa2b70762d..d59e7b9dfd 100644 --- a/keychain/signer.go +++ b/keychain/signer.go @@ -3,7 +3,9 @@ package keychain import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2/ecdsa" + "github.com/btcsuite/btcd/btcec/v2/schnorr" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/txscript" ) func NewPubKeyMessageSigner(pubKey *btcec.PublicKey, keyLoc KeyLocator, @@ -42,6 +44,14 @@ func (p *PubKeyMessageSigner) SignMessageCompact(msg []byte, return p.digestSigner.SignMessageCompact(p.keyLoc, msg, doubleHash) } +func (p *PubKeyMessageSigner) SignMessageSchnorr(keyLoc KeyLocator, msg []byte, + doubleHash bool, taprootTweak, tag []byte) (*schnorr.Signature, error) { + + return p.digestSigner.SignMessageSchnorr( + keyLoc, msg, doubleHash, taprootTweak, tag, + ) +} + func NewPrivKeyMessageSigner(privKey *btcec.PrivateKey, keyLoc KeyLocator) *PrivKeyMessageSigner { @@ -89,5 +99,28 @@ func (p *PrivKeyMessageSigner) SignMessageCompact(msg []byte, return ecdsa.SignCompact(p.privKey, digest, true), nil } +func (p *PrivKeyMessageSigner) SignMessageSchnorr(_ KeyLocator, msg []byte, + doubleHash bool, taprootTweak, tag []byte) (*schnorr.Signature, error) { + + // If a tag was provided, we need to take the tagged hash of the input. + var digest []byte + switch { + case len(tag) > 0: + taggedHash := chainhash.TaggedHash(tag, msg) + digest = taggedHash[:] + case doubleHash: + digest = chainhash.DoubleHashB(msg) + default: + digest = chainhash.HashB(msg) + } + + privKey := p.privKey + if len(taprootTweak) > 0 { + privKey = txscript.TweakTaprootPrivKey(*privKey, taprootTweak) + } + + return schnorr.Sign(privKey, digest) +} + var _ SingleKeyMessageSigner = (*PubKeyMessageSigner)(nil) var _ SingleKeyMessageSigner = (*PrivKeyMessageSigner)(nil) diff --git a/lnrpc/invoicesrpc/addinvoice.go b/lnrpc/invoicesrpc/addinvoice.go index a928973bba..fb9f6070b3 100644 --- a/lnrpc/invoicesrpc/addinvoice.go +++ b/lnrpc/invoicesrpc/addinvoice.go @@ -571,7 +571,7 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig, // key is used to sign the invoice so that the sender // can derive the true pub key of the recipient. if !blind { - return cfg.NodeSigner.SignMessageCompact( + return cfg.NodeSigner.SignMessageCompactNoKeyLoc( //nolint:lll msg, false, ) } diff --git a/lntest/mock/signer.go b/lntest/mock/signer.go index 1d30204ea9..370840acc1 100644 --- a/lntest/mock/signer.go +++ b/lntest/mock/signer.go @@ -205,3 +205,68 @@ func (s *SingleSigner) SignMessage(keyLoc keychain.KeyLocator, } return ecdsa.Sign(s.Privkey, digest), nil } + +// SignMessageCompact signs the given message, single or double SHA256 hashing +// it first, with the private key described in the key locator and returns the +// signature in the compact, public key recoverable format. +// +// NOTE: This is part of the keychain.MessageSignerRing interface. +func (s *SingleSigner) SignMessageCompact(keyLoc keychain.KeyLocator, + msg []byte, doubleHash bool) ([]byte, error) { + + mockKeyLoc := s.KeyLoc + if s.KeyLoc.IsEmpty() { + mockKeyLoc = idKeyLoc + } + + if keyLoc != mockKeyLoc { + return nil, fmt.Errorf("unknown public key") + } + + var digest []byte + if doubleHash { + digest = chainhash.DoubleHashB(msg) + } else { + digest = chainhash.HashB(msg) + } + + return ecdsa.SignCompact(s.Privkey, digest, true), nil +} + +// SignMessageSchnorr signs the given message, single or double SHA256 hashing +// it first, with the private key described in the key locator and the optional +// Taproot tweak applied to the private key. +// +// NOTE: this is part of the keychain.MessageSignerRing interface. +func (s *SingleSigner) SignMessageSchnorr(keyLoc keychain.KeyLocator, + msg []byte, doubleHash bool, taprootTweak, tag []byte) ( + *schnorr.Signature, error) { + + mockKeyLoc := s.KeyLoc + if s.KeyLoc.IsEmpty() { + mockKeyLoc = idKeyLoc + } + + if keyLoc != mockKeyLoc { + return nil, fmt.Errorf("unknown public key") + } + + privKey := s.Privkey + if len(taprootTweak) > 0 { + privKey = txscript.TweakTaprootPrivKey(*privKey, taprootTweak) + } + + // If a tag was provided, we need to take the tagged hash of the input. + var digest []byte + switch { + case len(tag) > 0: + taggedHash := chainhash.TaggedHash(tag, msg) + digest = taggedHash[:] + case doubleHash: + digest = chainhash.DoubleHashB(msg) + default: + digest = chainhash.HashB(msg) + } + + return schnorr.Sign(privKey, digest) +} diff --git a/netann/chan_status_manager.go b/netann/chan_status_manager.go index d927a81008..d829b53ddd 100644 --- a/netann/chan_status_manager.go +++ b/netann/chan_status_manager.go @@ -10,7 +10,6 @@ import ( "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/keychain" - "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" ) @@ -50,7 +49,7 @@ type ChanStatusConfig struct { OurKeyLoc keychain.KeyLocator // MessageSigner signs messages that validate under OurPubKey. - MessageSigner lnwallet.MessageSigner + MessageSigner keychain.MessageSignerRing // BestBlockView gives access to the current best block. BestBlockView chainntnfs.BestBlockView diff --git a/netann/channel_update.go b/netann/channel_update.go index deff0a9b87..946832924c 100644 --- a/netann/channel_update.go +++ b/netann/channel_update.go @@ -11,7 +11,6 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/channeldb/models" "github.com/lightningnetwork/lnd/keychain" - "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" "github.com/pkg/errors" ) @@ -74,8 +73,9 @@ func ChanUpdSetTimestamp(update *lnwire.ChannelUpdate1) { // monotonically increase from the prior. // // NOTE: This method modifies the given update. -func SignChannelUpdate(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator, - update *lnwire.ChannelUpdate1, mods ...ChannelUpdateModifier) error { +func SignChannelUpdate(signer keychain.MessageSignerRing, + keyLoc keychain.KeyLocator, update *lnwire.ChannelUpdate1, + mods ...ChannelUpdateModifier) error { // Apply the requested changes to the channel update. for _, modifier := range mods { diff --git a/netann/channel_update_test.go b/netann/channel_update_test.go index 2a619e062e..006865c9f9 100644 --- a/netann/channel_update_test.go +++ b/netann/channel_update_test.go @@ -14,6 +14,8 @@ import ( ) type mockSigner struct { + keychain.MessageSignerRing + err error } @@ -43,7 +45,7 @@ type updateDisableTest struct { startEnabled bool disable bool startTime time.Time - signer lnwallet.MessageSigner + signer keychain.MessageSignerRing expErr error } diff --git a/netann/node_signer.go b/netann/node_signer.go index 4cb8cea01c..aeb95882fe 100644 --- a/netann/node_signer.go +++ b/netann/node_signer.go @@ -4,8 +4,8 @@ import ( "fmt" "github.com/btcsuite/btcd/btcec/v2/ecdsa" + "github.com/btcsuite/btcd/btcec/v2/schnorr" "github.com/lightningnetwork/lnd/keychain" - "github.com/lightningnetwork/lnd/lnwallet" ) // NodeSigner is an implementation of the MessageSigner interface backed by the @@ -43,15 +43,52 @@ func (n *NodeSigner) SignMessage(keyLoc keychain.KeyLocator, return sig, nil } -// SignMessageCompact signs a single or double sha256 digest of the msg +// SignMessageCompactNoKeyLoc signs a single or double sha256 digest of the msg // parameter under the resident node's private key. The returned signature is a -// pubkey-recoverable signature. -func (n *NodeSigner) SignMessageCompact(msg []byte, doubleHash bool) ([]byte, - error) { +// pubkey-recoverable signature. No key locator is required for this since the +// NodeSigner already has the key to sign with. +func (n *NodeSigner) SignMessageCompactNoKeyLoc(msg []byte, doubleHash bool) ( + []byte, error) { return n.keySigner.SignMessageCompact(msg, doubleHash) } +// SignMessageCompact signs the given message, single or double SHA256 hashing +// it first, with the private key described in the key locator and returns the +// signature in the compact, public key recoverable format. +// +// NOTE: this is part of the keychain.MessageSignerRing interface. +func (n *NodeSigner) SignMessageCompact(keyLoc keychain.KeyLocator, msg []byte, + doubleHash bool) ([]byte, error) { + + // If this isn't our identity public key, then we'll exit early with an + // error as we can't sign with this key. + if keyLoc != n.keySigner.KeyLocator() { + return nil, fmt.Errorf("unknown public key locator") + } + + return n.SignMessageCompactNoKeyLoc(msg, doubleHash) +} + +// SignMessageSchnorr signs the given message, single or double SHA256 hashing +// it first, with the private key described in the key locator and the optional +// Taproot tweak applied to the private key. +// +// NOTE: this is part of the keychain.MessageSignerRing interface. +func (n *NodeSigner) SignMessageSchnorr(keyLoc keychain.KeyLocator, msg []byte, + doubleHash bool, taprootTweak, tag []byte) (*schnorr.Signature, error) { + + // If this isn't our identity public key, then we'll exit early with an + // error as we can't sign with this key. + if keyLoc != n.keySigner.KeyLocator() { + return nil, fmt.Errorf("unknown public key locator") + } + + return n.keySigner.SignMessageSchnorr( + keyLoc, msg, doubleHash, taprootTweak, tag, + ) +} + // A compile time check to ensure that NodeSigner implements the MessageSigner // interface. -var _ lnwallet.MessageSigner = (*NodeSigner)(nil) +var _ keychain.MessageSignerRing = (*NodeSigner)(nil) diff --git a/rpcserver.go b/rpcserver.go index d133788acc..b75d39840f 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -1699,7 +1699,7 @@ func (r *rpcServer) SignMessage(_ context.Context, } in.Msg = append(signedMsgPrefix, in.Msg...) - sigBytes, err := r.server.nodeSigner.SignMessageCompact( + sigBytes, err := r.server.nodeSigner.SignMessageCompactNoKeyLoc( in.Msg, !in.SingleHash, ) if err != nil { From ec855fe76e5800b4855ba4f892f9f91db9b2945f Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 09:35:14 +0200 Subject: [PATCH 32/60] netann: update ChanUpdate modifiers to use interface Update the ChannelUpdate modifiers to use the lnwire.ChannelUpdate interface instead of *lnwire.ChannelUpdate1. --- discovery/gossiper.go | 2 +- netann/chan_status_manager.go | 7 ++++- netann/channel_update.go | 50 +++++++++++++++++++++-------------- netann/channel_update_test.go | 2 +- 4 files changed, 38 insertions(+), 23 deletions(-) diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 08268cecef..1a518814fc 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -2286,7 +2286,7 @@ func (d *AuthenticatedGossiper) updateChannel(edgeInfo models.ChannelEdgeInfo, // announcement itself and update the timestamp to ensure it propagate. err = netann.SignChannelUpdate( d.cfg.AnnSigner, d.selfKeyLoc, chanUpdate, - netann.ChanUpdSetTimestamp, + netann.ChanUpdSetTimestamp(d.latestHeight()), ) if err != nil { return nil, nil, err diff --git a/netann/chan_status_manager.go b/netann/chan_status_manager.go index d829b53ddd..9a7b30e3a0 100644 --- a/netann/chan_status_manager.go +++ b/netann/chan_status_manager.go @@ -637,9 +637,14 @@ func (m *ChanStatusManager) signAndSendNextUpdate(outpoint wire.OutPoint, return err } + height, err := m.cfg.BestBlockView.BestHeight() + if err != nil { + return err + } + err = SignChannelUpdate( m.cfg.MessageSigner, m.cfg.OurKeyLoc, chanUpdate, - ChanUpdSetDisable(disabled), ChanUpdSetTimestamp, + ChanUpdSetDisable(disabled), ChanUpdSetTimestamp(height), ) if err != nil { return err diff --git a/netann/channel_update.go b/netann/channel_update.go index 946832924c..763d366f1c 100644 --- a/netann/channel_update.go +++ b/netann/channel_update.go @@ -34,37 +34,47 @@ const ( var ErrUnableToExtractChanUpdate = fmt.Errorf("unable to extract ChannelUpdate") // ChannelUpdateModifier is a closure that makes in-place modifications to an -// lnwire.ChannelUpdate. -type ChannelUpdateModifier func(*lnwire.ChannelUpdate1) +type ChannelUpdateModifier func(lnwire.ChannelUpdate) // ChanUpdSetDisable is a functional option that sets the disabled channel flag // if disabled is true, and clears the bit otherwise. func ChanUpdSetDisable(disabled bool) ChannelUpdateModifier { - return func(update *lnwire.ChannelUpdate1) { - if disabled { - // Set the bit responsible for marking a channel as - // disabled. - update.ChannelFlags |= lnwire.ChanUpdateDisabled - } else { - // Clear the bit responsible for marking a channel as - // disabled. - update.ChannelFlags &= ^lnwire.ChanUpdateDisabled - } + return func(update lnwire.ChannelUpdate) { + update.SetDisabledFlag(disabled) } } // ChanUpdSetTimestamp is a functional option that sets the timestamp of the // update to the current time, or increments it if the timestamp is already in // the future. -func ChanUpdSetTimestamp(update *lnwire.ChannelUpdate1) { - newTimestamp := uint32(time.Now().Unix()) - if newTimestamp <= update.Timestamp { - // Increment the prior value to ensure the timestamp - // monotonically increases, otherwise the update won't - // propagate. - newTimestamp = update.Timestamp + 1 +func ChanUpdSetTimestamp(bestBlockHeight uint32) ChannelUpdateModifier { + return func(update lnwire.ChannelUpdate) { + switch upd := update.(type) { + case *lnwire.ChannelUpdate1: + newTimestamp := uint32(time.Now().Unix()) + if newTimestamp <= upd.Timestamp { + // Increment the prior value to ensure the + // timestamp monotonically increases, otherwise + // the update won't propagate. + newTimestamp = upd.Timestamp + 1 + } + upd.Timestamp = newTimestamp + + case *lnwire.ChannelUpdate2: + newBlockHeight := bestBlockHeight + if newBlockHeight <= upd.BlockHeight.Val { + // Increment the prior value to ensure the + // blockHeight monotonically increases, + // otherwise the update won't propagate. + newBlockHeight = upd.BlockHeight.Val + 1 + } + upd.BlockHeight.Val = newBlockHeight + + default: + log.Errorf("unhandled implementation of "+ + "lnwire.ChannelUpdate: %T", update) + } } - update.Timestamp = newTimestamp } // SignChannelUpdate applies the given modifiers to the passed diff --git a/netann/channel_update_test.go b/netann/channel_update_test.go index 006865c9f9..5b5e65b0d2 100644 --- a/netann/channel_update_test.go +++ b/netann/channel_update_test.go @@ -133,7 +133,7 @@ func TestUpdateDisableFlag(t *testing.T) { err := netann.SignChannelUpdate( tc.signer, testKeyLoc, newUpdate, netann.ChanUpdSetDisable(tc.disable), - netann.ChanUpdSetTimestamp, + netann.ChanUpdSetTimestamp(0), ) var fail bool From 7a19392e68e72753a49c32cc04fb3a0fef716a06 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 09:41:41 +0200 Subject: [PATCH 33/60] netann: let SignChannelUpdate take ChannelUpdate interface --- netann/channel_update.go | 49 ++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/netann/channel_update.go b/netann/channel_update.go index 763d366f1c..e476762324 100644 --- a/netann/channel_update.go +++ b/netann/channel_update.go @@ -84,7 +84,7 @@ func ChanUpdSetTimestamp(bestBlockHeight uint32) ChannelUpdateModifier { // // NOTE: This method modifies the given update. func SignChannelUpdate(signer keychain.MessageSignerRing, - keyLoc keychain.KeyLocator, update *lnwire.ChannelUpdate1, + keyLoc keychain.KeyLocator, update lnwire.ChannelUpdate, mods ...ChannelUpdateModifier) error { // Apply the requested changes to the channel update. @@ -92,16 +92,45 @@ func SignChannelUpdate(signer keychain.MessageSignerRing, modifier(update) } - // Create the DER-encoded ECDSA signature over the message digest. - sig, err := SignAnnouncement(signer, keyLoc, update) - if err != nil { - return err - } + switch upd := update.(type) { + case *lnwire.ChannelUpdate1: + data, err := upd.DataToSign() + if err != nil { + return err + } - // Parse the DER-encoded signature into a fixed-size 64-byte array. - update.Signature, err = lnwire.NewSigFromSignature(sig) - if err != nil { - return err + sig, err := signer.SignMessage(keyLoc, data, true) + if err != nil { + return err + } + + // Parse the DER-encoded signature into a fixed-size 64-byte + // array. + upd.Signature, err = lnwire.NewSigFromSignature(sig) + if err != nil { + return err + } + + case *lnwire.ChannelUpdate2: + data, err := upd.DataToSign() + if err != nil { + return err + } + + sig, err := signer.SignMessageSchnorr( + keyLoc, data, false, nil, ChanUpdate2DigestTag(), + ) + if err != nil { + return err + } + + upd.Signature, err = lnwire.NewSigFromSignature(sig) + if err != nil { + return err + } + default: + return fmt.Errorf("unhandled implementation of "+ + "ChannelUpdate: %T", update) } return nil From a2b58cb3f08566f55e1cb0ea04ed9b9a3310921d Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 09:51:45 +0200 Subject: [PATCH 34/60] multi: update SignAliasUpdate to take ChannelUpdate interface --- discovery/gossiper.go | 26 +++----------------------- discovery/gossiper_test.go | 13 ++++--------- htlcswitch/mock.go | 17 +++++++++++++---- htlcswitch/switch.go | 25 ++++--------------------- server.go | 18 +++++------------- 5 files changed, 29 insertions(+), 70 deletions(-) diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 1a518814fc..9020e918f7 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -9,7 +9,6 @@ import ( "time" "github.com/btcsuite/btcd/btcec/v2" - "github.com/btcsuite/btcd/btcec/v2/ecdsa" "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -347,8 +346,7 @@ type Config struct { // SignAliasUpdate is used to re-sign a channel update using the // remote's alias if the option-scid-alias feature bit was negotiated. - SignAliasUpdate func(u *lnwire.ChannelUpdate1) (*ecdsa.Signature, - error) + SignAliasUpdate func(u lnwire.ChannelUpdate) error // FindBaseByAlias finds the SCID stored in the graph by an alias SCID. // This is used for channels that have negotiated the option-scid-alias @@ -1840,21 +1838,12 @@ func (d *AuthenticatedGossiper) processChanPolicyUpdate( if foundAlias != defaultAlias { chanUpdate.ShortChannelID = foundAlias - sig, err := d.cfg.SignAliasUpdate(chanUpdate) + err := d.cfg.SignAliasUpdate(chanUpdate) if err != nil { log.Errorf("Unable to sign alias "+ "update: %v", err) continue } - - lnSig, err := lnwire.NewSigFromSignature(sig) - if err != nil { - log.Errorf("Unable to create sig: %v", - err) - continue - } - - chanUpdate.Signature = lnSig } remotePubKey := remotePubFromChanInfo( @@ -3247,21 +3236,12 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // negotiated channels. upd.ShortChannelID = *remoteAlias - sig, err := d.cfg.SignAliasUpdate(upd) + err := d.cfg.SignAliasUpdate(upd) if err != nil { log.Error(err) nMsg.err <- err return nil, false } - - lnSig, err := lnwire.NewSigFromSignature(sig) - if err != nil { - log.Error(err) - nMsg.err <- err - return nil, false - } - - upd.Signature = lnSig } } diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index 3c994c203e..935b77db26 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -14,7 +14,6 @@ import ( "time" "github.com/btcsuite/btcd/btcec/v2" - "github.com/btcsuite/btcd/btcec/v2/ecdsa" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" @@ -759,10 +758,8 @@ func createTestCtx(t *testing.T, startHeight uint32, isChanPeer bool) ( return false } - signAliasUpdate := func(*lnwire.ChannelUpdate1) (*ecdsa.Signature, - error) { - - return nil, nil + signAliasUpdate := func(lnwire.ChannelUpdate) error { + return nil } findBaseByAlias := func(lnwire.ShortChannelID) (lnwire.ShortChannelID, @@ -1472,10 +1469,8 @@ func TestSignatureAnnouncementRetryAtStartup(t *testing.T) { return false } - signAliasUpdate := func(*lnwire.ChannelUpdate1) (*ecdsa.Signature, - error) { - - return nil, nil + signAliasUpdate := func(lnwire.ChannelUpdate) error { + return nil } findBaseByAlias := func(lnwire.ShortChannelID) (lnwire.ShortChannelID, diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go index 6de60b38a1..50165be29d 100644 --- a/htlcswitch/mock.go +++ b/htlcswitch/mock.go @@ -16,7 +16,6 @@ import ( "time" "github.com/btcsuite/btcd/btcec/v2" - "github.com/btcsuite/btcd/btcec/v2/ecdsa" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/wire" "github.com/go-errors/errors" @@ -167,10 +166,20 @@ type mockServer struct { var _ lnpeer.Peer = (*mockServer)(nil) func initSwitchWithDB(startingHeight uint32, db *channeldb.DB) (*Switch, error) { - signAliasUpdate := func(u *lnwire.ChannelUpdate1) (*ecdsa.Signature, - error) { + signAliasUpdate := func(update lnwire.ChannelUpdate) error { + s, err := lnwire.NewSigFromSignature(testSig) + if err != nil { + return err + } - return testSig, nil + switch u := update.(type) { + case *lnwire.ChannelUpdate1: + u.Signature = s + case *lnwire.ChannelUpdate2: + u.Signature = s + } + + return nil } cfg := Config{ diff --git a/htlcswitch/switch.go b/htlcswitch/switch.go index 4ff2746a73..b2fd0d1213 100644 --- a/htlcswitch/switch.go +++ b/htlcswitch/switch.go @@ -9,7 +9,6 @@ import ( "sync/atomic" "time" - "github.com/btcsuite/btcd/btcec/v2/ecdsa" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" @@ -221,8 +220,7 @@ type Config struct { // option_scid_alias channels. This avoids a potential privacy leak by // replacing the public, confirmed SCID with the alias in the // ChannelUpdate. - SignAliasUpdate func(u *lnwire.ChannelUpdate1) (*ecdsa.Signature, - error) + SignAliasUpdate func(u lnwire.ChannelUpdate) error // IsAlias returns whether or not a given SCID is an alias. IsAlias func(scid lnwire.ShortChannelID) bool @@ -2671,12 +2669,7 @@ func (s *Switch) failAliasUpdate(scid lnwire.ShortChannelID, // Replace the baseScid with the passed-in alias. update.ShortChannelID = scid - sig, err := s.cfg.SignAliasUpdate(update) - if err != nil { - return nil - } - - update.Signature, err = lnwire.NewSigFromSignature(sig) + err = s.cfg.SignAliasUpdate(update) if err != nil { return nil } @@ -2697,12 +2690,7 @@ func (s *Switch) failAliasUpdate(scid lnwire.ShortChannelID, // the UTXO in case the channel is private. In the outgoing // case, since the alias was used, we do the same thing. update.ShortChannelID = scid - sig, err := s.cfg.SignAliasUpdate(update) - if err != nil { - return nil - } - - update.Signature, err = lnwire.NewSigFromSignature(sig) + err = s.cfg.SignAliasUpdate(update) if err != nil { return nil } @@ -2752,12 +2740,7 @@ func (s *Switch) failAliasUpdate(scid lnwire.ShortChannelID, // Since this happens on the incoming side, it's not actually // possible to know what the sender used in the onion. update.ShortChannelID = aliases[0] - sig, err := s.cfg.SignAliasUpdate(update) - if err != nil { - return nil - } - - update.Signature, err = lnwire.NewSigFromSignature(sig) + err := s.cfg.SignAliasUpdate(update) if err != nil { return nil } diff --git a/server.go b/server.go index eb8b15b4a4..e9e328b279 100644 --- a/server.go +++ b/server.go @@ -16,7 +16,6 @@ import ( "time" "github.com/btcsuite/btcd/btcec/v2" - "github.com/btcsuite/btcd/btcec/v2/ecdsa" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -1813,18 +1812,11 @@ func (s *server) UpdateRoutingConfig(cfg *routing.MissionControlConfig) { routerCfg.MaxMcHistory = cfg.MaxMcHistory } -// signAliasUpdate takes a ChannelUpdate and returns the signature. This is -// used for option_scid_alias channels where the ChannelUpdate to be sent back -// may differ from what is on disk. -func (s *server) signAliasUpdate(u *lnwire.ChannelUpdate1) (*ecdsa.Signature, - error) { - - data, err := u.DataToSign() - if err != nil { - return nil, err - } - - return s.cc.MsgSigner.SignMessage(s.identityKeyLoc, data, true) +// signAliasUpdate takes a ChannelUpdate and re-signs it. The signature is set +// the update accordingly. This is used for option_scid_alias channels where the +// ChannelUpdate to be sent back may differ from what is on disk. +func (s *server) signAliasUpdate(u lnwire.ChannelUpdate) error { + return netann.SignChannelUpdate(s.cc.KeyRing, s.identityKeyLoc, u) } // createLivenessMonitor creates a set of health checks using our configured From 5ce647a999b33cc2ad65244345b305e4e491a4e9 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 10:20:51 +0200 Subject: [PATCH 35/60] routing: update to use lnwire.ChannelUpdate interface --- channeldb/models/channel_edge_policy.go | 33 +++++++++++++++ discovery/gossiper_test.go | 56 ++++++++++++++----------- graph/builder.go | 40 ++++++------------ graph/interfaces.go | 2 +- routing/mock_test.go | 4 +- routing/payment_lifecycle.go | 5 ++- routing/payment_session.go | 15 ++++--- routing/router.go | 2 +- 8 files changed, 93 insertions(+), 64 deletions(-) diff --git a/channeldb/models/channel_edge_policy.go b/channeldb/models/channel_edge_policy.go index eece025ffe..ac7bf651ee 100644 --- a/channeldb/models/channel_edge_policy.go +++ b/channeldb/models/channel_edge_policy.go @@ -256,3 +256,36 @@ func (c *ChannelEdgePolicy2) GetToNode() [33]byte { // A compile-time check to ensure that ChannelEdgePolicy2 implements the // ChannelEdgePolicy interface. var _ ChannelEdgePolicy = (*ChannelEdgePolicy2)(nil) + +// EdgePolicyFromUpdate converts the given lnwire.ChannelUpdate into the +// corresponding ChannelEdgePolicy type. +func EdgePolicyFromUpdate(update lnwire.ChannelUpdate) ( + ChannelEdgePolicy, error) { + + switch upd := update.(type) { + case *lnwire.ChannelUpdate1: + //nolint:lll + return &ChannelEdgePolicy1{ + SigBytes: upd.Signature.ToSignatureBytes(), + ChannelID: upd.ShortChannelID.ToUint64(), + LastUpdate: time.Unix(int64(upd.Timestamp), 0), + MessageFlags: upd.MessageFlags, + ChannelFlags: upd.ChannelFlags, + TimeLockDelta: upd.TimeLockDelta, + MinHTLC: upd.HtlcMinimumMsat, + MaxHTLC: upd.HtlcMaximumMsat, + FeeBaseMSat: lnwire.MilliSatoshi(upd.BaseFee), + FeeProportionalMillionths: lnwire.MilliSatoshi(upd.FeeRate), + ExtraOpaqueData: upd.ExtraOpaqueData, + }, nil + + case *lnwire.ChannelUpdate2: + return &ChannelEdgePolicy2{ + ChannelUpdate2: *upd, + }, nil + + default: + return nil, fmt.Errorf("unhandled implementation of "+ + "lnwire.ChannelUpdate: %T", update) + } +} diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index 935b77db26..5f0497eb6e 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -93,7 +93,7 @@ type mockGraphSource struct { mu sync.Mutex nodes []channeldb.LightningNode infos map[uint64]models.ChannelEdgeInfo - edges map[uint64][]models.ChannelEdgePolicy1 + edges map[uint64][]models.ChannelEdgePolicy zombies map[uint64][][33]byte chansToReject map[uint64]struct{} addEdgeErrCode fn.Option[graph.ErrorCode] @@ -103,7 +103,7 @@ func newMockRouter(height uint32) *mockGraphSource { return &mockGraphSource{ bestHeight: height, infos: make(map[uint64]models.ChannelEdgeInfo), - edges: make(map[uint64][]models.ChannelEdgePolicy1), + edges: make(map[uint64][]models.ChannelEdgePolicy), zombies: make(map[uint64][][33]byte), chansToReject: make(map[uint64]struct{}), } @@ -161,20 +161,22 @@ func (r *mockGraphSource) queueValidationFail(chanID uint64) { r.chansToReject[chanID] = struct{}{} } -func (r *mockGraphSource) UpdateEdge(edge *models.ChannelEdgePolicy1, +func (r *mockGraphSource) UpdateEdge(edge models.ChannelEdgePolicy, _ ...batch.SchedulerOption) error { r.mu.Lock() defer r.mu.Unlock() - if len(r.edges[edge.ChannelID]) == 0 { - r.edges[edge.ChannelID] = make([]models.ChannelEdgePolicy1, 2) + chanID := edge.SCID().ToUint64() + + if len(r.edges[chanID]) == 0 { + r.edges[chanID] = make([]models.ChannelEdgePolicy, 2) } - if edge.ChannelFlags&lnwire.ChanUpdateDirection == 0 { - r.edges[edge.ChannelID][0] = *edge + if edge.IsNode1() { + r.edges[chanID][0] = edge } else { - r.edges[edge.ChannelID][1] = *edge + r.edges[chanID][1] = edge } return nil @@ -218,7 +220,6 @@ func (r *mockGraphSource) ForAllOutgoingChannels(cb func(tx kvdb.RTx, r.mu.Lock() defer r.mu.Unlock() - chans := make(map[uint64]channeldb.ChannelEdge) for _, info := range r.infos { info := info @@ -230,9 +231,9 @@ func (r *mockGraphSource) ForAllOutgoingChannels(cb func(tx kvdb.RTx, for _, edges := range r.edges { edges := edges - edge := chans[edges[0].ChannelID] - edge.Policy1 = &edges[0] - chans[edges[0].ChannelID] = edge + edge := chans[edges[0].SCID().ToUint64()] + edge.Policy1 = edges[0] + chans[edges[0].SCID().ToUint64()] = edge } for _, channel := range chans { @@ -240,7 +241,6 @@ func (r *mockGraphSource) ForAllOutgoingChannels(cb func(tx kvdb.RTx, return err } } - return nil } @@ -271,14 +271,14 @@ func (r *mockGraphSource) GetChannelByID(chanID lnwire.ShortChannelID) ( return chanInfo, nil, nil, nil } - var edge1 *models.ChannelEdgePolicy1 + var edge1 models.ChannelEdgePolicy if !reflect.DeepEqual(edges[0], models.ChannelEdgePolicy1{}) { - edge1 = &edges[0] + edge1 = edges[0] } - var edge2 *models.ChannelEdgePolicy1 + var edge2 models.ChannelEdgePolicy if !reflect.DeepEqual(edges[1], models.ChannelEdgePolicy1{}) { - edge2 = &edges[1] + edge2 = edges[1] } return chanInfo, edge1, edge2, nil @@ -379,15 +379,21 @@ func (r *mockGraphSource) IsStaleEdgePolicy(chanID lnwire.ShortChannelID, } switch { - case flags&lnwire.ChanUpdateDirection == 0 && - !reflect.DeepEqual(edges[0], models.ChannelEdgePolicy1{}): - - return !timestamp.After(edges[0].LastUpdate) - - case flags&lnwire.ChanUpdateDirection == 1 && - !reflect.DeepEqual(edges[1], models.ChannelEdgePolicy1{}): + case flags&lnwire.ChanUpdateDirection == 0 && edges[0] != nil: + switch edge := edges[0].(type) { + case *models.ChannelEdgePolicy1: + return !timestamp.After(edge.LastUpdate) + default: + panic(fmt.Sprintf("unhandled: %T", edges[0])) + } - return !timestamp.After(edges[1].LastUpdate) + case flags&lnwire.ChanUpdateDirection == 1 && edges[1] != nil: + switch edge := edges[1].(type) { + case *models.ChannelEdgePolicy1: + return !timestamp.After(edge.LastUpdate) + default: + panic(fmt.Sprintf("unhandled: %T", edges[1])) + } default: return false diff --git a/graph/builder.go b/graph/builder.go index 8357d2a145..4f52d6b235 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -1513,49 +1513,35 @@ type routingMsg struct { // ApplyChannelUpdate validates a channel update and if valid, applies it to the // database. It returns a bool indicating whether the updates were successful. -func (b *Builder) ApplyChannelUpdate(msg *lnwire.ChannelUpdate1) bool { - ch, _, _, err := b.GetChannelByID(msg.ShortChannelID) +func (b *Builder) ApplyChannelUpdate(msg lnwire.ChannelUpdate) bool { + ch, _, _, err := b.GetChannelByID(msg.SCID()) if err != nil { log.Errorf("Unable to retrieve channel by id: %v", err) return false } var pubKey *btcec.PublicKey - - switch msg.ChannelFlags & lnwire.ChanUpdateDirection { - case 0: + if msg.IsNode1() { pubKey, _ = ch.NodeKey1() - - case 1: + } else { pubKey, _ = ch.NodeKey2() } - // Exit early if the pubkey cannot be decided. - if pubKey == nil { - log.Errorf("Unable to decide pubkey with ChannelFlags=%v", - msg.ChannelFlags) + err = netann.ValidateChannelUpdateAnn(pubKey, ch.GetCapacity(), msg) + if err != nil { + log.Errorf("Unable to validate channel update: %v", err) return false } - err = netann.ValidateChannelUpdateAnn(pubKey, ch.GetCapacity(), msg) + edgePolicy, err := models.EdgePolicyFromUpdate(msg) if err != nil { - log.Errorf("Unable to validate channel update: %v", err) + log.Errorf("Unable to convert update message to edge "+ + "policy: %v", err) + return false } - err = b.UpdateEdge(&models.ChannelEdgePolicy1{ - SigBytes: msg.Signature.ToSignatureBytes(), - ChannelID: msg.ShortChannelID.ToUint64(), - LastUpdate: time.Unix(int64(msg.Timestamp), 0), - MessageFlags: msg.MessageFlags, - ChannelFlags: msg.ChannelFlags, - TimeLockDelta: msg.TimeLockDelta, - MinHTLC: msg.HtlcMinimumMsat, - MaxHTLC: msg.HtlcMaximumMsat, - FeeBaseMSat: lnwire.MilliSatoshi(msg.BaseFee), - FeeProportionalMillionths: lnwire.MilliSatoshi(msg.FeeRate), - ExtraOpaqueData: msg.ExtraOpaqueData, - }) + err = b.UpdateEdge(edgePolicy) if err != nil && !IsError(err, ErrIgnored, ErrOutdated) { log.Errorf("Unable to apply channel update: %v", err) return false @@ -1622,7 +1608,7 @@ func (b *Builder) AddEdge(edge models.ChannelEdgeInfo, // considered as not fully constructed. // // NOTE: This method is part of the ChannelGraphSource interface. -func (b *Builder) UpdateEdge(update *models.ChannelEdgePolicy1, +func (b *Builder) UpdateEdge(update models.ChannelEdgePolicy, op ...batch.SchedulerOption) error { rMsg := &routingMsg{ diff --git a/graph/interfaces.go b/graph/interfaces.go index df8d16932b..60c2cb4d76 100644 --- a/graph/interfaces.go +++ b/graph/interfaces.go @@ -39,7 +39,7 @@ type ChannelGraphSource interface { // UpdateEdge is used to update edge information, without this message // edge considered as not fully constructed. - UpdateEdge(policy *models.ChannelEdgePolicy1, + UpdateEdge(policy models.ChannelEdgePolicy, op ...batch.SchedulerOption) error // IsStaleNode returns true if the graph source has a node announcement diff --git a/routing/mock_test.go b/routing/mock_test.go index 35ac3ecd99..1664e72c92 100644 --- a/routing/mock_test.go +++ b/routing/mock_test.go @@ -186,7 +186,7 @@ func (m *mockPaymentSessionOld) RequestRoute(_, _ lnwire.MilliSatoshi, return r, nil } -func (m *mockPaymentSessionOld) UpdateAdditionalEdge(_ *lnwire.ChannelUpdate1, +func (m *mockPaymentSessionOld) UpdateAdditionalEdge(_ lnwire.ChannelUpdate, _ *btcec.PublicKey, _ *models.CachedEdgePolicy) bool { return false @@ -710,7 +710,7 @@ func (m *mockPaymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi, return args.Get(0).(*route.Route), args.Error(1) } -func (m *mockPaymentSession) UpdateAdditionalEdge(msg *lnwire.ChannelUpdate1, +func (m *mockPaymentSession) UpdateAdditionalEdge(msg lnwire.ChannelUpdate, pubKey *btcec.PublicKey, policy *models.CachedEdgePolicy) bool { args := m.Called(msg, pubKey, policy) diff --git a/routing/payment_lifecycle.go b/routing/payment_lifecycle.go index 93b214bdea..5e8473d1f5 100644 --- a/routing/payment_lifecycle.go +++ b/routing/payment_lifecycle.go @@ -981,7 +981,7 @@ func (p *paymentLifecycle) handleFailureMessage(rt *route.Route, // SendToRoute where there's no payment lifecycle. if p.paySession != nil { policy = p.paySession.GetAdditionalEdgePolicy( - errSource, update.ShortChannelID.ToUint64(), + errSource, update.SCID().ToUint64(), ) if policy != nil { isAdditionalEdge = true @@ -991,7 +991,8 @@ func (p *paymentLifecycle) handleFailureMessage(rt *route.Route, // Apply channel update to additional edge policy. if isAdditionalEdge { if !p.paySession.UpdateAdditionalEdge( - update, errSource, policy) { + update, errSource, policy, + ) { log.Debugf("Invalid channel update received: node=%v", errVertex) diff --git a/routing/payment_session.go b/routing/payment_session.go index 89fb2fd137..dfef220fd6 100644 --- a/routing/payment_session.go +++ b/routing/payment_session.go @@ -147,8 +147,9 @@ type PaymentSession interface { // (private channels) and applies the update from the message. Returns // a boolean to indicate whether the update has been applied without // error. - UpdateAdditionalEdge(msg *lnwire.ChannelUpdate1, - pubKey *btcec.PublicKey, policy *models.CachedEdgePolicy) bool + UpdateAdditionalEdge(msg lnwire.ChannelUpdate, + pubKey *btcec.PublicKey, + policy *models.CachedEdgePolicy) bool // GetAdditionalEdgePolicy uses the public key and channel ID to query // the ephemeral channel edge policy for additional edges. Returns a nil @@ -437,7 +438,7 @@ func (p *paymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi, // validates the message signature and checks it's up to date, then applies the // updates to the supplied policy. It returns a boolean to indicate whether // there's an error when applying the updates. -func (p *paymentSession) UpdateAdditionalEdge(msg *lnwire.ChannelUpdate1, +func (p *paymentSession) UpdateAdditionalEdge(msg lnwire.ChannelUpdate, pubKey *btcec.PublicKey, policy *models.CachedEdgePolicy) bool { // Validate the message signature. @@ -448,10 +449,12 @@ func (p *paymentSession) UpdateAdditionalEdge(msg *lnwire.ChannelUpdate1, return false } + fwdingPolicy := msg.ForwardingPolicy() + // Update channel policy for the additional edge. - policy.TimeLockDelta = msg.TimeLockDelta - policy.FeeBaseMSat = lnwire.MilliSatoshi(msg.BaseFee) - policy.FeeProportionalMillionths = lnwire.MilliSatoshi(msg.FeeRate) + policy.TimeLockDelta = fwdingPolicy.TimeLockDelta + policy.FeeBaseMSat = fwdingPolicy.BaseFee + policy.FeeProportionalMillionths = fwdingPolicy.FeeRate log.Debugf("New private channel update applied: %v", lnutils.SpewLogClosure(msg)) diff --git a/routing/router.go b/routing/router.go index 1fea60ddbe..cbb0ae4969 100644 --- a/routing/router.go +++ b/routing/router.go @@ -288,7 +288,7 @@ type Config struct { // ApplyChannelUpdate can be called to apply a new channel update to the // graph that we received from a payment failure. - ApplyChannelUpdate func(msg *lnwire.ChannelUpdate1) bool + ApplyChannelUpdate func(msg lnwire.ChannelUpdate) bool // ClosedSCIDs is used by the router to fetch closed channels. // From 5aee5fb1f0bef92dd1d7c7bf776eeecd5bce4eb5 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 11:42:42 +0200 Subject: [PATCH 36/60] multi: let some netann funcs use lnwire.ChannelUpdate ...interface instead of ChannelUpdate1. --- discovery/chan_series.go | 6 +- discovery/gossiper.go | 50 +++++++++---- discovery/gossiper_test.go | 6 +- discovery/syncer.go | 19 +++-- discovery/syncer_test.go | 10 +-- netann/chan_status_manager.go | 6 +- netann/chan_status_manager_test.go | 43 +++++------ netann/channel_update.go | 75 ++++++++++++++++--- peer/test_utils.go | 2 +- routing/router_test.go | 115 +++++++++++++++++++---------- server.go | 2 +- 11 files changed, 227 insertions(+), 107 deletions(-) diff --git a/discovery/chan_series.go b/discovery/chan_series.go index c8abedb2c0..2fbaf6df7b 100644 --- a/discovery/chan_series.go +++ b/discovery/chan_series.go @@ -61,7 +61,7 @@ type ChannelGraphTimeSeries interface { // specified short channel ID. If no channel updates are known for the // channel, then an empty slice will be returned. FetchChanUpdates(chain chainhash.Hash, - shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate1, + shortChanID lnwire.ShortChannelID) ([]lnwire.ChannelUpdate, error) } @@ -336,7 +336,7 @@ func (c *ChanSeries) FetchChanAnns(chain chainhash.Hash, // // NOTE: This is part of the ChannelGraphTimeSeries interface. func (c *ChanSeries) FetchChanUpdates(chain chainhash.Hash, - shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate1, error) { + shortChanID lnwire.ShortChannelID) ([]lnwire.ChannelUpdate, error) { chanInfo, e1, e2, err := c.graph.FetchChannelEdgesByID( shortChanID.ToUint64(), @@ -345,7 +345,7 @@ func (c *ChanSeries) FetchChanUpdates(chain chainhash.Hash, return nil, err } - chanUpdates := make([]*lnwire.ChannelUpdate1, 0, 2) + chanUpdates := make([]lnwire.ChannelUpdate, 0, 2) if e1 != nil { chanUpdate, err := netann.ChannelUpdateFromEdge(chanInfo, e1) if err != nil { diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 9020e918f7..ea667dbef1 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -1836,7 +1836,7 @@ func (d *AuthenticatedGossiper) processChanPolicyUpdate( var defaultAlias lnwire.ShortChannelID foundAlias, _ := d.cfg.GetAlias(chanID) if foundAlias != defaultAlias { - chanUpdate.ShortChannelID = foundAlias + chanUpdate.SetSCID(foundAlias) err := d.cfg.SignAliasUpdate(chanUpdate) if err != nil { @@ -1856,7 +1856,7 @@ func (d *AuthenticatedGossiper) processChanPolicyUpdate( log.Errorf("Unable to reliably send %v for "+ "channel=%v to peer=%x: %v", chanUpdate.MsgType(), - chanUpdate.ShortChannelID, + chanUpdate.SCID(), remotePubKey, err) } continue @@ -2254,23 +2254,17 @@ func (d *AuthenticatedGossiper) isMsgStale(msg lnwire.Message) bool { // updateChannel creates a new fully signed update for the channel, and updates // the underlying graph with the new state. func (d *AuthenticatedGossiper) updateChannel(edgeInfo models.ChannelEdgeInfo, - edgePolicy models.ChannelEdgePolicy) (lnwire.ChannelAnnouncement, - *lnwire.ChannelUpdate1, error) { + edge models.ChannelEdgePolicy) (lnwire.ChannelAnnouncement, + lnwire.ChannelUpdate, error) { // Parse the unsigned edge into a channel update. chanUpdate, err := netann.UnsignedChannelUpdateFromEdge( - edgeInfo.GetChainHash(), edgePolicy, + edgeInfo.GetChainHash(), edge, ) if err != nil { return nil, nil, err } - edge, ok := edgePolicy.(*models.ChannelEdgePolicy1) - if !ok { - return nil, nil, fmt.Errorf("expected "+ - "*models.ChannelEdgePolicy1, got: %T", edgePolicy) - } - // We'll generate a new signature over a digest of the channel // announcement itself and update the timestamp to ensure it propagate. err = netann.SignChannelUpdate( @@ -2283,8 +2277,25 @@ func (d *AuthenticatedGossiper) updateChannel(edgeInfo models.ChannelEdgeInfo, // Next, we'll set the new signature in place, and update the reference // in the backing slice. - edge.LastUpdate = time.Unix(int64(chanUpdate.Timestamp), 0) - edge.SigBytes = chanUpdate.Signature.ToSignatureBytes() + switch e := edge.(type) { + case *models.ChannelEdgePolicy1: + chanUpd, ok := chanUpdate.(*lnwire.ChannelUpdate1) + if !ok { + return nil, nil, fmt.Errorf("wanted chan update 1") + } + + e.LastUpdate = time.Unix(int64(chanUpd.Timestamp), 0) + e.SigBytes = chanUpd.Signature.ToSignatureBytes() + + case *models.ChannelEdgePolicy2: + chanUpd, ok := chanUpdate.(*lnwire.ChannelUpdate2) + if !ok { + return nil, nil, fmt.Errorf("wanted chan update 2") + } + + e.BlockHeight = chanUpd.BlockHeight + e.Signature = chanUpd.Signature + } // To ensure that our signature is valid, we'll verify it ourself // before committing it to the slice returned. @@ -2312,6 +2323,10 @@ func (d *AuthenticatedGossiper) updateChannel(edgeInfo models.ChannelEdgeInfo, if err != nil { return nil, nil, err } + + case *models.ChannelEdgeInfo2: + chanAnn = chanAnn2FromEdgeInfo2(info) + default: return nil, nil, fmt.Errorf("unhandled "+ "implementation of models.ChannelEdgeInfo: "+ @@ -2366,6 +2381,15 @@ func chanAnn1FromEdgeInfo1(info *models.ChannelEdgeInfo1) ( return chanAnn, nil } +func chanAnn2FromEdgeInfo2( + info *models.ChannelEdgeInfo2) *lnwire.ChannelAnnouncement2 { + + chanAnn := info.ChannelAnnouncement2 + chanAnn.Signature = info.Signature + + return &chanAnn +} + // SyncManager returns the gossiper's SyncManager instance. func (d *AuthenticatedGossiper) SyncManager() *SyncManager { return d.syncMgr diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index 5f0497eb6e..84a77263d0 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -266,9 +266,11 @@ func (r *mockGraphSource) GetChannelByID(chanID lnwire.ShortChannelID) ( }, nil, nil, channeldb.ErrZombieEdge } + chanInfoCP := chanInfo.Copy() + edges := r.edges[chanID.ToUint64()] if len(edges) == 0 { - return chanInfo, nil, nil, nil + return chanInfoCP, nil, nil, nil } var edge1 models.ChannelEdgePolicy @@ -281,7 +283,7 @@ func (r *mockGraphSource) GetChannelByID(chanID lnwire.ShortChannelID) ( edge2 = edges[1] } - return chanInfo, edge1, edge2, nil + return chanInfoCP, edge1, edge2, nil } func (r *mockGraphSource) FetchLightningNode( diff --git a/discovery/syncer.go b/discovery/syncer.go index 4da82cfdb5..e78558ccd0 100644 --- a/discovery/syncer.go +++ b/discovery/syncer.go @@ -1407,16 +1407,16 @@ func (g *GossipSyncer) FilterGossipMsgs(msgs ...msgWithSenders) { // to quickly check if we should forward a chan ann, based on the known // channel updates for a channel. chanUpdateIndex := make( - map[lnwire.ShortChannelID][]*lnwire.ChannelUpdate1, + map[lnwire.ShortChannelID][]lnwire.ChannelUpdate, ) for _, msg := range msgs { - chanUpdate, ok := msg.msg.(*lnwire.ChannelUpdate1) + chanUpdate, ok := msg.msg.(lnwire.ChannelUpdate) if !ok { continue } - chanUpdateIndex[chanUpdate.ShortChannelID] = append( - chanUpdateIndex[chanUpdate.ShortChannelID], chanUpdate, + chanUpdateIndex[chanUpdate.SCID()] = append( + chanUpdateIndex[chanUpdate.SCID()], chanUpdate, ) } @@ -1469,7 +1469,16 @@ func (g *GossipSyncer) FilterGossipMsgs(msgs ...msgWithSenders) { } for _, chanUpdate := range chanUpdates { - if passesFilter(chanUpdate.Timestamp) { + update, ok := chanUpdate.(*lnwire.ChannelUpdate1) + if !ok { + log.Errorf("expected "+ + "*lnwire.ChannelUpdate1, "+ + "got: %T", update) + + continue + } + + if passesFilter(update.Timestamp) { msgsToSend = append(msgsToSend, msg) break } diff --git a/discovery/syncer_test.go b/discovery/syncer_test.go index 0ee635a0f2..f176580578 100644 --- a/discovery/syncer_test.go +++ b/discovery/syncer_test.go @@ -52,7 +52,7 @@ type mockChannelGraphTimeSeries struct { annResp chan []lnwire.Message updateReq chan lnwire.ShortChannelID - updateResp chan []*lnwire.ChannelUpdate1 + updateResp chan []lnwire.ChannelUpdate } func newMockChannelGraphTimeSeries( @@ -74,7 +74,7 @@ func newMockChannelGraphTimeSeries( annResp: make(chan []lnwire.Message, 1), updateReq: make(chan lnwire.ShortChannelID, 1), - updateResp: make(chan []*lnwire.ChannelUpdate1, 1), + updateResp: make(chan []lnwire.ChannelUpdate, 1), } } @@ -149,7 +149,7 @@ func (m *mockChannelGraphTimeSeries) FetchChanAnns(chain chainhash.Hash, return <-m.annResp, nil } func (m *mockChannelGraphTimeSeries) FetchChanUpdates(chain chainhash.Hash, - shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate1, error) { + shortChanID lnwire.ShortChannelID) ([]lnwire.ChannelUpdate, error) { m.updateReq <- shortChanID @@ -369,8 +369,8 @@ func TestGossipSyncerFilterGossipMsgsAllInMemory(t *testing.T) { } // If so, then we'll send back the missing update. - chanSeries.updateResp <- []*lnwire.ChannelUpdate1{ - { + chanSeries.updateResp <- []lnwire.ChannelUpdate{ + &lnwire.ChannelUpdate1{ ShortChannelID: lnwire.NewShortChanIDFromInt(25), Timestamp: unixStamp(5), }, diff --git a/netann/chan_status_manager.go b/netann/chan_status_manager.go index 9a7b30e3a0..a75db58dda 100644 --- a/netann/chan_status_manager.go +++ b/netann/chan_status_manager.go @@ -63,7 +63,7 @@ type ChanStatusConfig struct { // ApplyChannelUpdate processes new ChannelUpdates signed by our node by // updating our local routing table and broadcasting the update to our // peers. - ApplyChannelUpdate func(*lnwire.ChannelUpdate1, *wire.OutPoint, + ApplyChannelUpdate func(lnwire.ChannelUpdate, *wire.OutPoint, bool) error // DB stores the set of channels that are to be monitored. @@ -658,7 +658,7 @@ func (m *ChanStatusManager) signAndSendNextUpdate(outpoint wire.OutPoint, // in case our ChannelEdgePolicy is not found in the database. Also returns if // the channel is private by checking AuthProof for nil. func (m *ChanStatusManager) fetchLastChanUpdateByOutPoint(op wire.OutPoint) ( - *lnwire.ChannelUpdate1, bool, error) { + lnwire.ChannelUpdate, bool, error) { // Get the edge info and policies for this channel from the graph. info, edge1, edge2, err := m.cfg.Graph.FetchChannelEdgesByOutpoint(&op) @@ -689,7 +689,7 @@ func (m *ChanStatusManager) loadInitialChanState( // Determine the channel's starting status by inspecting the disable bit // on last announcement we sent out. var initialStatus ChanStatus - if lastUpdate.ChannelFlags&lnwire.ChanUpdateDisabled == 0 { + if !lastUpdate.IsDisabled() { initialStatus = ChanStatusEnabled } else { initialStatus = ChanStatusDisabled diff --git a/netann/chan_status_manager_test.go b/netann/chan_status_manager_test.go index f0025d7eb9..e5e0e48b9f 100644 --- a/netann/chan_status_manager_test.go +++ b/netann/chan_status_manager_test.go @@ -136,7 +136,7 @@ type mockGraph struct { chanPols2 map[wire.OutPoint]*models.ChannelEdgePolicy1 sidToCid map[lnwire.ShortChannelID]wire.OutPoint - updates chan *lnwire.ChannelUpdate1 + updates chan lnwire.ChannelUpdate } func newMockGraph(t *testing.T, numChannels int, @@ -148,7 +148,7 @@ func newMockGraph(t *testing.T, numChannels int, chanPols1: make(map[wire.OutPoint]*models.ChannelEdgePolicy1), chanPols2: make(map[wire.OutPoint]*models.ChannelEdgePolicy1), sidToCid: make(map[lnwire.ShortChannelID]wire.OutPoint), - updates: make(chan *lnwire.ChannelUpdate1, 2*numChannels), + updates: make(chan lnwire.ChannelUpdate, 2*numChannels), } for i := 0; i < numChannels; i++ { @@ -187,46 +187,47 @@ func (g *mockGraph) FetchChannelEdgesByOutpoint( return info, pol1, pol2, nil } -func (g *mockGraph) ApplyChannelUpdate(update *lnwire.ChannelUpdate1, +func (g *mockGraph) ApplyChannelUpdate(update lnwire.ChannelUpdate, op *wire.OutPoint, private bool) error { g.mu.Lock() defer g.mu.Unlock() - outpoint, ok := g.sidToCid[update.ShortChannelID] + outpoint, ok := g.sidToCid[update.SCID()] if !ok { return fmt.Errorf("unknown short channel id: %v", - update.ShortChannelID) + update.SCID()) } pol1 := g.chanPols1[outpoint] pol2 := g.chanPols2[outpoint] - // Determine which policy we should update by making the flags on the // policies and updates, and seeing which match up. var update1 bool + switch { - case update.ChannelFlags&lnwire.ChanUpdateDirection == - pol1.ChannelFlags&lnwire.ChanUpdateDirection: + case update.IsNode1() == pol1.IsNode1(): update1 = true - case update.ChannelFlags&lnwire.ChanUpdateDirection == - pol2.ChannelFlags&lnwire.ChanUpdateDirection: + case update.IsNode1() == pol2.IsNode1(): update1 = false default: return fmt.Errorf("unable to find policy to update") } - timestamp := time.Unix(int64(update.Timestamp), 0) + upd, ok := update.(*lnwire.ChannelUpdate1) + if !ok { + return fmt.Errorf("expected channel update 1") + } + timestamp := time.Unix(int64(upd.Timestamp), 0) policy := &models.ChannelEdgePolicy1{ - ChannelID: update.ShortChannelID.ToUint64(), - ChannelFlags: update.ChannelFlags, + ChannelID: upd.ShortChannelID.ToUint64(), + ChannelFlags: upd.ChannelFlags, LastUpdate: timestamp, SigBytes: testSigBytes, } - if update1 { g.chanPols1[outpoint] = policy } else { @@ -517,23 +518,23 @@ func (h *testHarness) assertUpdates(channels []*channeldb.OpenChannel, for { select { case upd := <-h.graph.updates: + scid := upd.SCID() + // Assert that the received short channel id is one that // we expect. If no updates were expected, this will // always fail on the first update received. - if _, ok := expSids[upd.ShortChannelID]; !ok { + if _, ok := expSids[scid]; !ok { h.t.Fatalf("received update for unexpected "+ - "short chan id: %v", upd.ShortChannelID) + "short chan id: %v", scid) } // Assert that the disabled bit is set properly. - enabled := upd.ChannelFlags&lnwire.ChanUpdateDisabled != - lnwire.ChanUpdateDisabled - if expEnabled != enabled { + if expEnabled != !upd.IsDisabled() { h.t.Fatalf("expected enabled: %v, actual: %v", - expEnabled, enabled) + expEnabled, !upd.IsDisabled()) } - recvdSids[upd.ShortChannelID] = struct{}{} + recvdSids[scid] = struct{}{} case <-timeout: // Time is up, assert that the correct number of unique diff --git a/netann/channel_update.go b/netann/channel_update.go index e476762324..1062f5d422 100644 --- a/netann/channel_update.go +++ b/netann/channel_update.go @@ -145,9 +145,9 @@ func ExtractChannelUpdate(ownerPubKey []byte, *lnwire.ChannelUpdate1, error) { // Helper function to extract the owner of the given policy. - owner := func(edge *models.ChannelEdgePolicy1) []byte { + owner := func(edge models.ChannelEdgePolicy) []byte { var pubKey *btcec.PublicKey - if edge.ChannelFlags&lnwire.ChanUpdateDirection == 0 { + if edge.IsNode1() { pubKey, _ = info.NodeKey1() } else { pubKey, _ = info.NodeKey2() @@ -163,14 +163,20 @@ func ExtractChannelUpdate(ownerPubKey []byte, // Extract the channel update from the policy we own, if any. for _, edge := range policies { - e, ok := edge.(*models.ChannelEdgePolicy1) - if !ok { - return nil, fmt.Errorf("expected "+ - "*models.ChannelEdgePolicy1, got: %T", edge) - } + if edge != nil && bytes.Equal(ownerPubKey, owner(edge)) { + update, err := ChannelUpdateFromEdge(info, edge) + if err != nil { + return nil, err + } + + chanUpd1, ok := update.(*lnwire.ChannelUpdate1) + if !ok { + return nil, fmt.Errorf("expected "+ + "*lnwire.ChannelUpdate1, got: %T", + chanUpd1) + } - if edge != nil && bytes.Equal(ownerPubKey, owner(e)) { - return ChannelUpdateFromEdge(info, edge) + return chanUpd1, nil } } @@ -180,12 +186,15 @@ func ExtractChannelUpdate(ownerPubKey []byte, // UnsignedChannelUpdateFromEdge reconstructs an unsigned ChannelUpdate from the // given edge info and policy. func UnsignedChannelUpdateFromEdge(chainHash chainhash.Hash, - policy models.ChannelEdgePolicy) (*lnwire.ChannelUpdate1, error) { + policy models.ChannelEdgePolicy) (lnwire.ChannelUpdate, error) { switch p := policy.(type) { case *models.ChannelEdgePolicy1: return unsignedChanPolicy1ToUpdate(chainHash, p), nil + case *models.ChannelEdgePolicy2: + return unsignedChanPolicy2ToUpdate(chainHash, p), nil + default: return nil, fmt.Errorf("unhandled implementation of the "+ "models.ChanelEdgePolicy interface: %T", policy) @@ -210,10 +219,36 @@ func unsignedChanPolicy1ToUpdate(chainHash chainhash.Hash, } } +func unsignedChanPolicy2ToUpdate(chainHash chainhash.Hash, + policy *models.ChannelEdgePolicy2) *lnwire.ChannelUpdate2 { + + update := &lnwire.ChannelUpdate2{ + ShortChannelID: policy.ShortChannelID, + BlockHeight: policy.BlockHeight, + DisabledFlags: policy.DisabledFlags, + SecondPeer: policy.SecondPeer, + CLTVExpiryDelta: policy.CLTVExpiryDelta, + HTLCMinimumMsat: policy.HTLCMinimumMsat, + HTLCMaximumMsat: policy.HTLCMaximumMsat, + FeeBaseMsat: policy.FeeBaseMsat, + FeeProportionalMillionths: policy.FeeProportionalMillionths, + ExtraOpaqueData: policy.ExtraOpaqueData, + } + update.ChainHash.Val = chainHash + + return update +} + // ChannelUpdateFromEdge reconstructs a signed ChannelUpdate from the given // edge info and policy. func ChannelUpdateFromEdge(info models.ChannelEdgeInfo, - policy models.ChannelEdgePolicy) (*lnwire.ChannelUpdate1, error) { + policy models.ChannelEdgePolicy) (lnwire.ChannelUpdate, error) { + + return signedChannelUpdateFromEdge(info.GetChainHash(), policy) +} + +func signedChannelUpdateFromEdge(chainHash chainhash.Hash, + policy models.ChannelEdgePolicy) (lnwire.ChannelUpdate, error) { switch p := policy.(type) { case *models.ChannelEdgePolicy1: @@ -227,7 +262,23 @@ func ChannelUpdateFromEdge(info models.ChannelEdgeInfo, return nil, err } - update := unsignedChanPolicy1ToUpdate(info.GetChainHash(), p) + update := unsignedChanPolicy1ToUpdate(chainHash, p) + update.Signature = s + + return update, nil + + case *models.ChannelEdgePolicy2: + sig, err := p.Signature.ToSignature() + if err != nil { + return nil, err + } + + s, err := lnwire.NewSigFromSignature(sig) + if err != nil { + return nil, err + } + + update := unsignedChanPolicy2ToUpdate(chainHash, p) update.Signature = s return update, nil diff --git a/peer/test_utils.go b/peer/test_utils.go index 231a476ce1..0db1186ed0 100644 --- a/peer/test_utils.go +++ b/peer/test_utils.go @@ -615,7 +615,7 @@ func createTestPeer(t *testing.T) *peerTestCtx { IsChannelActive: func(lnwire.ChannelID) bool { return true }, - ApplyChannelUpdate: func(*lnwire.ChannelUpdate1, + ApplyChannelUpdate: func(lnwire.ChannelUpdate, *wire.OutPoint, bool) error { return nil diff --git a/routing/router_test.go b/routing/router_test.go index 21ddf57a8e..1a173b2c9c 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -15,8 +15,10 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2/ecdsa" + "github.com/btcsuite/btcd/btcec/v2/schnorr" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" "github.com/go-errors/errors" @@ -28,6 +30,7 @@ import ( "github.com/lightningnetwork/lnd/graph" "github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" @@ -151,7 +154,7 @@ func createTestCtxFromGraphInstanceAssumeValid(t *testing.T, MissionControl: mc, } - graphBuilder := newMockGraphBuilder(graphInstance.graph) + graphBuilder := newMockGraphBuilder(t, graphInstance.graph) router, err := New(Config{ SelfNode: sourceNode.PubKeyBytes, @@ -229,16 +232,50 @@ func createTestCtxFromFile(t *testing.T, // Add valid signature to channel update simulated as error received from the // network. func signErrChanUpdate(t *testing.T, key *btcec.PrivateKey, - errChanUpdate *lnwire.ChannelUpdate1) { + errChanUpdate lnwire.ChannelUpdate) { - chanUpdateMsg, err := errChanUpdate.DataToSign() - require.NoError(t, err, "failed to retrieve data to sign") + signer := &mockSigner{key: key} + err := netann.SignChannelUpdate( + signer, keychain.KeyLocator{}, errChanUpdate, + ) + require.NoError(t, err) +} + +type mockSigner struct { + key *btcec.PrivateKey + keychain.MessageSignerRing +} + +func (s *mockSigner) SignMessage(keyLoc keychain.KeyLocator, msg []byte, + doubleHash bool) (*ecdsa.Signature, error) { + + digest := chainhash.DoubleHashB(msg) + sig := ecdsa.Sign(s.key, digest) + + return sig, nil +} - digest := chainhash.DoubleHashB(chanUpdateMsg) - sig := ecdsa.Sign(key, digest) +func (s *mockSigner) SignMessageSchnorr(keyLoc keychain.KeyLocator, msg []byte, + doubleHash bool, taprootTweak, tag []byte) (*schnorr.Signature, + error) { - errChanUpdate.Signature, err = lnwire.NewSigFromSignature(sig) - require.NoError(t, err, "failed to create new signature") + var digest []byte + switch { + case len(tag) > 0: + taggedHash := chainhash.TaggedHash(tag, msg) + digest = taggedHash[:] + case doubleHash: + digest = chainhash.DoubleHashB(msg) + default: + digest = chainhash.HashB(msg) + } + + privKey := s.key + if len(taprootTweak) > 0 { + privKey = txscript.TweakTaprootPrivKey(*privKey, taprootTweak) + } + + return schnorr.Sign(privKey, digest) } // TestFindRoutesWithFeeLimit asserts that routes found by the FindRoutes method @@ -621,16 +658,16 @@ func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) { ) require.NoError(t, err, "unable to fetch chan id") - edgeUpdToFail, ok := edgeUpdateToFail.(*models.ChannelEdgePolicy1) - require.True(t, ok) - errChanUpdate, err := netann.UnsignedChannelUpdateFromEdge( - chainhash.Hash{}, edgeUpdToFail, + chainhash.Hash{}, edgeUpdateToFail, ) require.NoError(t, err) signErrChanUpdate(t, ctx.privKeys["songoku"], errChanUpdate) + chanUpd, ok := errChanUpdate.(*lnwire.ChannelUpdate1) + require.True(t, ok) + // We'll now modify the SendToSwitch method to return an error for the // outgoing channel to Son goku. This will be a fee related error, so // it should only cause the edge to be pruned after the second attempt. @@ -644,15 +681,17 @@ func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) { roasbeefSongokuChanID, ) if firstHop == roasbeefSongoku { - return [32]byte{}, htlcswitch.NewForwardingError( - // Within our error, we'll add a - // channel update which is meant to - // reflect the new fee schedule for the - // node/channel. - &lnwire.FailFeeInsufficient{ - Update: *errChanUpdate, - }, 1, - ) + if firstHop == roasbeefSongoku { + return [32]byte{}, htlcswitch.NewForwardingError( + // Within our error, we'll add a + // channel update which is meant to + // reflect the new fee schedule for the + // node/channel. + &lnwire.FailFeeInsufficient{ + Update: *chanUpd, + }, 1, + ) + } } return preImage, nil @@ -969,6 +1008,9 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) { ) require.NoError(t, err) + chanUpd, ok := errChanUpdate.(*lnwire.ChannelUpdate1) + require.True(t, ok) + // We'll now modify the SendToSwitch method to return an error for the // outgoing channel to son goku. Since this is a time lock related // error, we should fail the payment flow all together, as Goku is the @@ -978,7 +1020,7 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) { if firstHop == roasbeefSongoku { return [32]byte{}, htlcswitch.NewForwardingError( &lnwire.FailExpiryTooSoon{ - Update: *errChanUpdate, + Update: *chanUpd, }, 1, ) } @@ -1026,7 +1068,7 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) { if firstHop == roasbeefSongoku { return [32]byte{}, htlcswitch.NewForwardingError( &lnwire.FailIncorrectCltvExpiry{ - Update: *errChanUpdate, + Update: *chanUpd, }, 1, ) } @@ -2977,13 +3019,15 @@ func createDummyLightningPayment(t *testing.T, } type mockGraphBuilder struct { + t *testing.T rejectUpdate bool - updateEdge func(update *models.ChannelEdgePolicy1) error + updateEdge func(update models.ChannelEdgePolicy) error } -func newMockGraphBuilder(graph graph.DB) *mockGraphBuilder { +func newMockGraphBuilder(t *testing.T, graph graph.DB) *mockGraphBuilder { return &mockGraphBuilder{ - updateEdge: func(update *models.ChannelEdgePolicy1) error { + t: t, + updateEdge: func(update models.ChannelEdgePolicy) error { return graph.UpdateEdgePolicy(update) }, } @@ -2993,26 +3037,15 @@ func (m *mockGraphBuilder) setNextReject(reject bool) { m.rejectUpdate = reject } -func (m *mockGraphBuilder) ApplyChannelUpdate(msg *lnwire.ChannelUpdate1) bool { +func (m *mockGraphBuilder) ApplyChannelUpdate(msg lnwire.ChannelUpdate) bool { if m.rejectUpdate { return false } - err := m.updateEdge(&models.ChannelEdgePolicy1{ - SigBytes: msg.Signature.ToSignatureBytes(), - ChannelID: msg.ShortChannelID.ToUint64(), - LastUpdate: time.Unix(int64(msg.Timestamp), 0), - MessageFlags: msg.MessageFlags, - ChannelFlags: msg.ChannelFlags, - TimeLockDelta: msg.TimeLockDelta, - MinHTLC: msg.HtlcMinimumMsat, - MaxHTLC: msg.HtlcMaximumMsat, - FeeBaseMSat: lnwire.MilliSatoshi(msg.BaseFee), - FeeProportionalMillionths: lnwire.MilliSatoshi(msg.FeeRate), - ExtraOpaqueData: msg.ExtraOpaqueData, - }) + policy, err := models.EdgePolicyFromUpdate(msg) + require.NoError(m.t, err) - return err == nil + return m.updateEdge(policy) == nil } type mockChain struct { diff --git a/server.go b/server.go index e9e328b279..ffe5a83e1b 100644 --- a/server.go +++ b/server.go @@ -4917,7 +4917,7 @@ func (s *server) fetchLastChanUpdate() func(lnwire.ShortChannelID) ( // applyChannelUpdate applies the channel update to the different sub-systems of // the server. The useAlias boolean denotes whether or not to send an alias in // place of the real SCID. -func (s *server) applyChannelUpdate(update *lnwire.ChannelUpdate1, +func (s *server) applyChannelUpdate(update lnwire.ChannelUpdate, op *wire.OutPoint, useAlias bool) error { var ( From 92b6d11049773c97a1a5e9e32b23153480624049 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 11:53:27 +0200 Subject: [PATCH 37/60] multi: use ChannelUpdate interface for failure messages --- htlcswitch/interceptable_switch.go | 2 +- htlcswitch/link.go | 8 +- htlcswitch/switch.go | 4 +- htlcswitch/switch_test.go | 13 ++- lnrpc/routerrpc/router_backend.go | 107 +++++++++++++++---- lnwire/onion_error.go | 145 +++++++++++++++++--------- lnwire/onion_error_test.go | 18 ++-- routing/missioncontrol_test.go | 6 +- routing/result_interpretation_test.go | 7 +- routing/router.go | 14 +-- routing/router_test.go | 20 ++-- 11 files changed, 223 insertions(+), 121 deletions(-) diff --git a/htlcswitch/interceptable_switch.go b/htlcswitch/interceptable_switch.go index e06163d486..7fe9e403fc 100644 --- a/htlcswitch/interceptable_switch.go +++ b/htlcswitch/interceptable_switch.go @@ -793,7 +793,7 @@ func (f *interceptedForward) FailWithCode(code lnwire.FailCode) error { return err } - failureMsg = lnwire.NewExpiryTooSoon(*update) + failureMsg = lnwire.NewExpiryTooSoon(update) default: return ErrUnsupportedFailureCode diff --git a/htlcswitch/link.go b/htlcswitch/link.go index e7766bc815..db5f22072e 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -3059,7 +3059,7 @@ func (l *channelLink) CheckHtlcForward(payHash [32]byte, // As part of the returned error, we'll send our latest routing // policy so the sending node obtains the most up to date data. cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage { - return lnwire.NewFeeInsufficient(amtToForward, *upd) + return lnwire.NewFeeInsufficient(amtToForward, upd) } failure := l.createFailureWithUpdate(false, originalScid, cb) return NewLinkError(failure) @@ -3088,7 +3088,7 @@ func (l *channelLink) CheckHtlcForward(payHash [32]byte, // date with our current policy. cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage { return lnwire.NewIncorrectCltvExpiry( - incomingTimeout, *upd, + incomingTimeout, upd, ) } failure := l.createFailureWithUpdate(false, originalScid, cb) @@ -3136,7 +3136,7 @@ func (l *channelLink) canSendHtlc(policy models.ForwardingPolicy, // As part of the returned error, we'll send our latest routing // policy so the sending node obtains the most up to date data. cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage { - return lnwire.NewAmountBelowMinimum(amt, *upd) + return lnwire.NewAmountBelowMinimum(amt, upd) } failure := l.createFailureWithUpdate(false, originalScid, cb) return NewLinkError(failure) @@ -3166,7 +3166,7 @@ func (l *channelLink) canSendHtlc(policy models.ForwardingPolicy, timeout, heightNow) cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage { - return lnwire.NewExpiryTooSoon(*upd) + return lnwire.NewExpiryTooSoon(upd) } failure := l.createFailureWithUpdate(false, originalScid, cb) return NewLinkError(failure) diff --git a/htlcswitch/switch.go b/htlcswitch/switch.go index b2fd0d1213..79f664b1f7 100644 --- a/htlcswitch/switch.go +++ b/htlcswitch/switch.go @@ -2802,7 +2802,9 @@ func (s *Switch) handlePacketAdd(packet *htlcPacket, // sure that HTLC is not from the source node. if s.cfg.RejectHTLC { failure := NewDetailedLinkError( - &lnwire.FailChannelDisabled{}, + &lnwire.FailChannelDisabled{ + Update: &lnwire.ChannelUpdate1{}, + }, OutgoingFailureForwardsDisabled, ) diff --git a/htlcswitch/switch_test.go b/htlcswitch/switch_test.go index 825ee6c652..d9e68f3554 100644 --- a/htlcswitch/switch_test.go +++ b/htlcswitch/switch_test.go @@ -3382,7 +3382,10 @@ func TestHtlcNotifier(t *testing.T) { return getThreeHopEvents( channels, htlcID, ts, htlc, hops, &LinkError{ - msg: &lnwire.FailChannelDisabled{}, + //nolint:lll + msg: &lnwire.FailChannelDisabled{ + Update: &lnwire.ChannelUpdate1{}, + }, FailureDetail: OutgoingFailureForwardsDisabled, }, preimage, @@ -5045,7 +5048,7 @@ func testSwitchForwardFailAlias(t *testing.T, zeroConf bool) { msg := failPacket.linkFailure.msg failMsg, ok := msg.(*lnwire.FailTemporaryChannelFailure) require.True(t, ok) - require.Equal(t, aliceAlias, failMsg.Update.ShortChannelID) + require.Equal(t, aliceAlias, failMsg.Update.SCID()) case <-s2.quit: t.Fatal("switch shutting down, failed to forward packet") } @@ -5228,7 +5231,7 @@ func testSwitchAliasFailAdd(t *testing.T, zeroConf, private, useAlias bool) { msg := failPacket.linkFailure.msg failMsg, ok := msg.(*lnwire.FailTemporaryChannelFailure) require.True(t, ok) - require.Equal(t, outgoingChanID, failMsg.Update.ShortChannelID) + require.Equal(t, outgoingChanID, failMsg.Update.SCID()) case <-s.quit: t.Fatal("switch shutting down, failed to receive fail packet") } @@ -5428,7 +5431,7 @@ func testSwitchHandlePacketForward(t *testing.T, zeroConf, private, msg := failPacket.linkFailure.msg failMsg, ok := msg.(*lnwire.FailAmountBelowMinimum) require.True(t, ok) - require.Equal(t, outgoingChanID, failMsg.Update.ShortChannelID) + require.Equal(t, outgoingChanID, failMsg.Update.SCID()) case <-s.quit: t.Fatal("switch shutting down, failed to receive failure") } @@ -5583,7 +5586,7 @@ func testSwitchAliasInterceptFail(t *testing.T, zeroConf bool) { failureMsg, ok := failure.(*lnwire.FailTemporaryChannelFailure) require.True(t, ok) - failScid := failureMsg.Update.ShortChannelID + failScid := failureMsg.Update.SCID() isAlias := failScid == aliceAlias || failScid == aliceAlias2 require.True(t, isAlias) diff --git a/lnrpc/routerrpc/router_backend.go b/lnrpc/routerrpc/router_backend.go index f2d21750ae..c1e54473c5 100644 --- a/lnrpc/routerrpc/router_backend.go +++ b/lnrpc/routerrpc/router_backend.go @@ -1556,8 +1556,14 @@ func marshallWireError(msg lnwire.FailureMessage, response.Code = lnrpc.Failure_INVALID_REALM case *lnwire.FailExpiryTooSoon: + update1, update2, err := marshallChannelUpdate(onionErr.Update) + if err != nil { + return err + } + response.Code = lnrpc.Failure_EXPIRY_TOO_SOON - response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update) + response.ChannelUpdate = update1 + response.ChannelUpdate_2 = update2 case *lnwire.FailExpiryTooFar: response.Code = lnrpc.Failure_EXPIRY_TOO_FAR @@ -1575,28 +1581,58 @@ func marshallWireError(msg lnwire.FailureMessage, response.OnionSha_256 = onionErr.OnionSHA256[:] case *lnwire.FailAmountBelowMinimum: + update1, update2, err := marshallChannelUpdate(onionErr.Update) + if err != nil { + return err + } + response.Code = lnrpc.Failure_AMOUNT_BELOW_MINIMUM - response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update) + response.ChannelUpdate = update1 + response.ChannelUpdate_2 = update2 response.HtlcMsat = uint64(onionErr.HtlcMsat) case *lnwire.FailFeeInsufficient: + update1, update2, err := marshallChannelUpdate(onionErr.Update) + if err != nil { + return err + } + response.Code = lnrpc.Failure_FEE_INSUFFICIENT - response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update) + response.ChannelUpdate = update1 + response.ChannelUpdate_2 = update2 response.HtlcMsat = uint64(onionErr.HtlcMsat) case *lnwire.FailIncorrectCltvExpiry: + update1, update2, err := marshallChannelUpdate(onionErr.Update) + if err != nil { + return err + } + response.Code = lnrpc.Failure_INCORRECT_CLTV_EXPIRY - response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update) + response.ChannelUpdate = update1 + response.ChannelUpdate_2 = update2 response.CltvExpiry = onionErr.CltvExpiry case *lnwire.FailChannelDisabled: + update1, update2, err := marshallChannelUpdate(onionErr.Update) + if err != nil { + return err + } + response.Code = lnrpc.Failure_CHANNEL_DISABLED - response.ChannelUpdate = marshallChannelUpdate(&onionErr.Update) + response.ChannelUpdate = update1 + response.ChannelUpdate_2 = update2 response.Flags = uint32(onionErr.Flags) case *lnwire.FailTemporaryChannelFailure: + update1, update2, err := marshallChannelUpdate(onionErr.Update) + if err != nil { + return err + } + response.Code = lnrpc.Failure_TEMPORARY_CHANNEL_FAILURE - response.ChannelUpdate = marshallChannelUpdate(onionErr.Update) + response.ChannelUpdate = update1 + response.ChannelUpdate_2 = update2 case *lnwire.FailRequiredNodeFeatureMissing: response.Code = lnrpc.Failure_REQUIRED_NODE_FEATURE_MISSING @@ -1638,24 +1674,49 @@ func marshallWireError(msg lnwire.FailureMessage, // marshallChannelUpdate marshalls a channel update as received over the wire to // the router rpc format. -func marshallChannelUpdate(update *lnwire.ChannelUpdate1) *lnrpc.ChannelUpdate { +func marshallChannelUpdate(update lnwire.ChannelUpdate) (*lnrpc.ChannelUpdate, + *lnrpc.ChannelUpdate2, error) { + if update == nil { - return nil - } - - return &lnrpc.ChannelUpdate{ - Signature: update.Signature.RawBytes(), - ChainHash: update.ChainHash[:], - ChanId: update.ShortChannelID.ToUint64(), - Timestamp: update.Timestamp, - MessageFlags: uint32(update.MessageFlags), - ChannelFlags: uint32(update.ChannelFlags), - TimeLockDelta: uint32(update.TimeLockDelta), - HtlcMinimumMsat: uint64(update.HtlcMinimumMsat), - BaseFee: update.BaseFee, - FeeRate: update.FeeRate, - HtlcMaximumMsat: uint64(update.HtlcMaximumMsat), - ExtraOpaqueData: update.ExtraOpaqueData, + return nil, nil, nil + } + + switch upd := update.(type) { + case *lnwire.ChannelUpdate1: + return &lnrpc.ChannelUpdate{ + Signature: upd.Signature.RawBytes(), + ChainHash: upd.ChainHash[:], + ChanId: upd.ShortChannelID.ToUint64(), + Timestamp: upd.Timestamp, + MessageFlags: uint32(upd.MessageFlags), + ChannelFlags: uint32(upd.ChannelFlags), + TimeLockDelta: uint32(upd.TimeLockDelta), + HtlcMinimumMsat: uint64(upd.HtlcMinimumMsat), + BaseFee: upd.BaseFee, + FeeRate: upd.FeeRate, + HtlcMaximumMsat: uint64(upd.HtlcMaximumMsat), + ExtraOpaqueData: upd.ExtraOpaqueData, + }, nil, nil + + case *lnwire.ChannelUpdate2: + return nil, &lnrpc.ChannelUpdate2{ + Signature: upd.Signature.RawBytes(), + ChainHash: upd.ChainHash.Val[:], + ChanId: upd.ShortChannelID.Val.ToUint64(), + BlockHeight: upd.BlockHeight.Val, + DisabledFlags: uint32(upd.DisabledFlags.Val), + Direction: upd.SecondPeer.IsSome(), + TimeLockDelta: uint32(upd.CLTVExpiryDelta.Val), + BaseFee: upd.FeeBaseMsat.Val, + FeeRate: upd.FeeProportionalMillionths.Val, + HtlcMinimumMsat: uint64(upd.HTLCMinimumMsat.Val), + HtlcMaximumMsat: uint64(upd.HTLCMaximumMsat.Val), + ExtraOpaqueData: upd.ExtraOpaqueData, + }, nil + + default: + return nil, nil, fmt.Errorf("unhandled implementation of "+ + "lnwire.ChannelUpdate: %T", update) } } diff --git a/lnwire/onion_error.go b/lnwire/onion_error.go index 8d54a98951..8def77837d 100644 --- a/lnwire/onion_error.go +++ b/lnwire/onion_error.go @@ -601,7 +601,7 @@ func (f *FailInvalidOnionKey) Error() string { // unable to pull out a fully valid version, then we'll fall back to the // regular parsing mechanism which includes the length prefix an NO type byte. func parseChannelUpdateCompatibilityMode(reader io.Reader, length uint16, - chanUpdate *ChannelUpdate1, pver uint32) error { + pver uint32) (ChannelUpdate, error) { // Instantiate a LimitReader because there may be additional data // present after the channel update. Without limiting the stream, the @@ -614,28 +614,50 @@ func parseChannelUpdateCompatibilityMode(reader io.Reader, length uint16, // buffer so we can decide how to parse the remainder of it. maybeTypeBytes, err := r.Peek(2) if err != nil { - return err + return nil, err + } + + var ( + typeInt = binary.BigEndian.Uint16(maybeTypeBytes) + chanUpdate ChannelUpdate + hasTypeBytes bool + ) + switch typeInt { + case MsgChannelUpdate: + chanUpdate = &ChannelUpdate1{} + hasTypeBytes = true + + case MsgChannelUpdate2: + chanUpdate = &ChannelUpdate2{} + hasTypeBytes = true + + default: + // Some older nodes will not have the type prefix in front of + // their channel updates as there was initially some ambiguity + // in the spec. This should ony be the case for the + // ChannelUpdate2 message. + chanUpdate = &ChannelUpdate1{} } - // Some nodes well prefix an additional set of bytes in front of their - // channel updates. These bytes will _almost_ always be 258 or the type - // of the ChannelUpdate message. - typeInt := binary.BigEndian.Uint16(maybeTypeBytes) - if typeInt == MsgChannelUpdate { + if hasTypeBytes { // At this point it's likely the case that this is a channel // update message with its type prefixed, so we'll snip off the // first two bytes and parse it as normal. var throwAwayTypeBytes [2]byte _, err := r.Read(throwAwayTypeBytes[:]) if err != nil { - return err + return nil, err } } // At this pint, we've either decided to keep the entire thing, or snip // off the first two bytes. In either case, we can just read it as // normal. - return chanUpdate.Decode(r, pver) + if err = chanUpdate.Decode(r, pver); err != nil { + return nil, err + } + + return chanUpdate, nil } // FailTemporaryChannelFailure is if an otherwise unspecified transient error @@ -648,12 +670,12 @@ type FailTemporaryChannelFailure struct { // which caused the failure. // // NOTE: This field is optional. - Update *ChannelUpdate1 + Update ChannelUpdate } // NewTemporaryChannelFailure creates new instance of the FailTemporaryChannelFailure. func NewTemporaryChannelFailure( - update *ChannelUpdate1) *FailTemporaryChannelFailure { + update ChannelUpdate) *FailTemporaryChannelFailure { return &FailTemporaryChannelFailure{Update: update} } @@ -688,11 +710,14 @@ func (f *FailTemporaryChannelFailure) Decode(r io.Reader, pver uint32) error { } if length != 0 { - f.Update = &ChannelUpdate1{} - - return parseChannelUpdateCompatibilityMode( - r, length, f.Update, pver, + update, err := parseChannelUpdateCompatibilityMode( + r, length, pver, ) + if err != nil { + return err + } + + f.Update = update } return nil @@ -723,12 +748,12 @@ type FailAmountBelowMinimum struct { // Update is used to update information about state of the channel // which caused the failure. - Update ChannelUpdate1 + Update ChannelUpdate } // NewAmountBelowMinimum creates new instance of the FailAmountBelowMinimum. func NewAmountBelowMinimum(htlcMsat MilliSatoshi, - update ChannelUpdate1) *FailAmountBelowMinimum { + update ChannelUpdate) *FailAmountBelowMinimum { return &FailAmountBelowMinimum{ HtlcMsat: htlcMsat, @@ -764,11 +789,16 @@ func (f *FailAmountBelowMinimum) Decode(r io.Reader, pver uint32) error { return err } - f.Update = ChannelUpdate1{} - - return parseChannelUpdateCompatibilityMode( - r, length, &f.Update, pver, + update, err := parseChannelUpdateCompatibilityMode( + r, length, pver, ) + if err != nil { + return err + } + + f.Update = update + + return nil } // Encode writes the failure in bytes stream. @@ -779,7 +809,7 @@ func (f *FailAmountBelowMinimum) Encode(w *bytes.Buffer, pver uint32) error { return err } - return writeOnionErrorChanUpdate(w, &f.Update, pver) + return writeOnionErrorChanUpdate(w, f.Update, pver) } // FailFeeInsufficient is returned if the HTLC does not pay sufficient fee, we @@ -793,12 +823,13 @@ type FailFeeInsufficient struct { // Update is used to update information about state of the channel // which caused the failure. - Update ChannelUpdate1 + Update ChannelUpdate } // NewFeeInsufficient creates new instance of the FailFeeInsufficient. func NewFeeInsufficient(htlcMsat MilliSatoshi, - update ChannelUpdate1) *FailFeeInsufficient { + update ChannelUpdate) *FailFeeInsufficient { + return &FailFeeInsufficient{ HtlcMsat: htlcMsat, Update: update, @@ -833,11 +864,14 @@ func (f *FailFeeInsufficient) Decode(r io.Reader, pver uint32) error { return err } - f.Update = ChannelUpdate1{} + update, err := parseChannelUpdateCompatibilityMode(r, length, pver) + if err != nil { + return err + } - return parseChannelUpdateCompatibilityMode( - r, length, &f.Update, pver, - ) + f.Update = update + + return nil } // Encode writes the failure in bytes stream. @@ -848,7 +882,7 @@ func (f *FailFeeInsufficient) Encode(w *bytes.Buffer, pver uint32) error { return err } - return writeOnionErrorChanUpdate(w, &f.Update, pver) + return writeOnionErrorChanUpdate(w, f.Update, pver) } // FailIncorrectCltvExpiry is returned if outgoing cltv value does not match @@ -864,12 +898,12 @@ type FailIncorrectCltvExpiry struct { // Update is used to update information about state of the channel // which caused the failure. - Update ChannelUpdate1 + Update ChannelUpdate } // NewIncorrectCltvExpiry creates new instance of the FailIncorrectCltvExpiry. func NewIncorrectCltvExpiry(cltvExpiry uint32, - update ChannelUpdate1) *FailIncorrectCltvExpiry { + update ChannelUpdate) *FailIncorrectCltvExpiry { return &FailIncorrectCltvExpiry{ CltvExpiry: cltvExpiry, @@ -902,11 +936,14 @@ func (f *FailIncorrectCltvExpiry) Decode(r io.Reader, pver uint32) error { return err } - f.Update = ChannelUpdate1{} + update, err := parseChannelUpdateCompatibilityMode(r, length, pver) + if err != nil { + return err + } + + f.Update = update - return parseChannelUpdateCompatibilityMode( - r, length, &f.Update, pver, - ) + return nil } // Encode writes the failure in bytes stream. @@ -917,7 +954,7 @@ func (f *FailIncorrectCltvExpiry) Encode(w *bytes.Buffer, pver uint32) error { return err } - return writeOnionErrorChanUpdate(w, &f.Update, pver) + return writeOnionErrorChanUpdate(w, f.Update, pver) } // FailExpiryTooSoon is returned if the ctlv-expiry is too near, we tell them @@ -927,11 +964,11 @@ func (f *FailIncorrectCltvExpiry) Encode(w *bytes.Buffer, pver uint32) error { type FailExpiryTooSoon struct { // Update is used to update information about state of the channel // which caused the failure. - Update ChannelUpdate1 + Update ChannelUpdate } // NewExpiryTooSoon creates new instance of the FailExpiryTooSoon. -func NewExpiryTooSoon(update ChannelUpdate1) *FailExpiryTooSoon { +func NewExpiryTooSoon(update ChannelUpdate) *FailExpiryTooSoon { return &FailExpiryTooSoon{ Update: update, } @@ -960,18 +997,21 @@ func (f *FailExpiryTooSoon) Decode(r io.Reader, pver uint32) error { return err } - f.Update = ChannelUpdate1{} + update, err := parseChannelUpdateCompatibilityMode(r, length, pver) + if err != nil { + return err + } - return parseChannelUpdateCompatibilityMode( - r, length, &f.Update, pver, - ) + f.Update = update + + return nil } // Encode writes the failure in bytes stream. // // NOTE: Part of the Serializable interface. func (f *FailExpiryTooSoon) Encode(w *bytes.Buffer, pver uint32) error { - return writeOnionErrorChanUpdate(w, &f.Update, pver) + return writeOnionErrorChanUpdate(w, f.Update, pver) } // FailChannelDisabled is returned if the channel is disabled, we tell them the @@ -986,12 +1026,12 @@ type FailChannelDisabled struct { // Update is used to update information about state of the channel // which caused the failure. - Update ChannelUpdate1 + Update ChannelUpdate } // NewChannelDisabled creates new instance of the FailChannelDisabled. func NewChannelDisabled(flags uint16, - update ChannelUpdate1) *FailChannelDisabled { + update ChannelUpdate) *FailChannelDisabled { return &FailChannelDisabled{ Flags: flags, @@ -1027,11 +1067,14 @@ func (f *FailChannelDisabled) Decode(r io.Reader, pver uint32) error { return err } - f.Update = ChannelUpdate1{} + update, err := parseChannelUpdateCompatibilityMode(r, length, pver) + if err != nil { + return err + } - return parseChannelUpdateCompatibilityMode( - r, length, &f.Update, pver, - ) + f.Update = update + + return nil } // Encode writes the failure in bytes stream. @@ -1042,7 +1085,7 @@ func (f *FailChannelDisabled) Encode(w *bytes.Buffer, pver uint32) error { return err } - return writeOnionErrorChanUpdate(w, &f.Update, pver) + return writeOnionErrorChanUpdate(w, f.Update, pver) } // FailFinalIncorrectCltvExpiry is returned if the outgoing_cltv_value does not @@ -1520,7 +1563,7 @@ func makeEmptyOnionError(code FailCode) (FailureMessage, error) { // writeOnionErrorChanUpdate writes out a ChannelUpdate using the onion error // format. The format is that we first write out the true serialized length of // the channel update, followed by the serialized channel update itself. -func writeOnionErrorChanUpdate(w *bytes.Buffer, chanUpdate *ChannelUpdate1, +func writeOnionErrorChanUpdate(w *bytes.Buffer, chanUpdate ChannelUpdate, pver uint32) error { // First, we encode the channel update in a temporary buffer in order diff --git a/lnwire/onion_error_test.go b/lnwire/onion_error_test.go index 9c39be6d5c..829f8a6cb1 100644 --- a/lnwire/onion_error_test.go +++ b/lnwire/onion_error_test.go @@ -21,7 +21,7 @@ var ( testType = uint64(3) testOffset = uint16(24) sig, _ = NewSigFromSignature(testSig) - testChannelUpdate = ChannelUpdate1{ + testChannelUpdate = &ChannelUpdate1{ Signature: sig, ShortChannelID: NewShortChanIDFromInt(1), Timestamp: 1, @@ -47,7 +47,7 @@ var onionFailures = []FailureMessage{ NewInvalidOnionVersion(testOnionHash[:]), NewInvalidOnionHmac(testOnionHash[:]), NewInvalidOnionKey(testOnionHash[:]), - NewTemporaryChannelFailure(&testChannelUpdate), + NewTemporaryChannelFailure(testChannelUpdate), NewTemporaryChannelFailure(nil), NewAmountBelowMinimum(testAmount, testChannelUpdate), NewFeeInsufficient(testAmount, testChannelUpdate), @@ -138,9 +138,8 @@ func TestChannelUpdateCompatibilityParsing(t *testing.T) { // Now that we have the set of bytes encoded, we'll ensure that we're // able to decode it using our compatibility method, as it's a regular // encoded channel update message. - var newChanUpdate ChannelUpdate1 - err := parseChannelUpdateCompatibilityMode( - &b, uint16(b.Len()), &newChanUpdate, 0, + newChanUpdate, err := parseChannelUpdateCompatibilityMode( + &b, uint16(b.Len()), 0, ) require.NoError(t, err, "unable to parse channel update") @@ -165,9 +164,8 @@ func TestChannelUpdateCompatibilityParsing(t *testing.T) { // We should be able to properly parse the encoded channel update // message even with the extra two bytes. - var newChanUpdate2 ChannelUpdate1 - err = parseChannelUpdateCompatibilityMode( - &b, uint16(b.Len()), &newChanUpdate2, 0, + newChanUpdate2, err := parseChannelUpdateCompatibilityMode( + &b, uint16(b.Len()), 0, ) require.NoError(t, err, "unable to parse channel update") @@ -186,7 +184,7 @@ func TestWriteOnionErrorChanUpdate(t *testing.T) { // raw serialized length. var b bytes.Buffer update := testChannelUpdate - trueUpdateLength, err := WriteMessage(&b, &update, 0) + trueUpdateLength, err := WriteMessage(&b, update, 0) if err != nil { t.Fatalf("unable to write update: %v", err) } @@ -194,7 +192,7 @@ func TestWriteOnionErrorChanUpdate(t *testing.T) { // Next, we'll use the function to encode the update as we would in a // onion error message. var errorBuf bytes.Buffer - err = writeOnionErrorChanUpdate(&errorBuf, &update, 0) + err = writeOnionErrorChanUpdate(&errorBuf, update, 0) require.NoError(t, err, "unable to encode onion error") // Finally, read the length encoded and ensure that it matches the raw diff --git a/routing/missioncontrol_test.go b/routing/missioncontrol_test.go index dad033ac44..bf212e1821 100644 --- a/routing/missioncontrol_test.go +++ b/routing/missioncontrol_test.go @@ -212,7 +212,7 @@ func TestMissionControl(t *testing.T) { // A node level failure should bring probability of all known channels // back to zero. - ctx.reportFailure(0, lnwire.NewExpiryTooSoon(lnwire.ChannelUpdate1{})) + ctx.reportFailure(0, lnwire.NewExpiryTooSoon(&lnwire.ChannelUpdate1{})) ctx.expectP(1000, 0) // Check whether history snapshot looks sane. @@ -234,14 +234,14 @@ func TestMissionControlChannelUpdate(t *testing.T) { // Report a policy related failure. Because it is the first, we don't // expect a penalty. ctx.reportFailure( - 0, lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate1{}), + 0, lnwire.NewFeeInsufficient(0, &lnwire.ChannelUpdate1{}), ) ctx.expectP(100, testAprioriHopProbability) // Report another failure for the same channel. We expect it to be // pruned. ctx.reportFailure( - 0, lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate1{}), + 0, lnwire.NewFeeInsufficient(0, &lnwire.ChannelUpdate1{}), ) ctx.expectP(100, 0) } diff --git a/routing/result_interpretation_test.go b/routing/result_interpretation_test.go index 14506e3a14..9f95f1a3b3 100644 --- a/routing/result_interpretation_test.go +++ b/routing/result_interpretation_test.go @@ -159,8 +159,9 @@ var resultTestCases = []resultTestCase{ name: "fail expiry too soon", route: &routeFourHop, failureSrcIdx: 3, - failure: lnwire.NewExpiryTooSoon(lnwire.ChannelUpdate1{}), - + failure: lnwire.NewExpiryTooSoon( + &lnwire.ChannelUpdate1{}, + ), expectedResult: &interpretedResult{ pairResults: map[DirectedNodePair]pairResult{ getTestPair(0, 1): failPairResult(0), @@ -262,7 +263,7 @@ var resultTestCases = []resultTestCase{ route: &routeFourHop, failureSrcIdx: 2, failure: lnwire.NewFeeInsufficient( - 0, lnwire.ChannelUpdate1{}, + 0, &lnwire.ChannelUpdate1{}, ), expectedResult: &interpretedResult{ pairResults: map[DirectedNodePair]pairResult{ diff --git a/routing/router.go b/routing/router.go index cbb0ae4969..107baa14c1 100644 --- a/routing/router.go +++ b/routing/router.go @@ -1330,20 +1330,20 @@ func (r *ChannelRouter) sendPayment(ctx context.Context, // extractChannelUpdate examines the error and extracts the channel update. func (r *ChannelRouter) extractChannelUpdate( - failure lnwire.FailureMessage) *lnwire.ChannelUpdate1 { + failure lnwire.FailureMessage) lnwire.ChannelUpdate { - var update *lnwire.ChannelUpdate1 + var update lnwire.ChannelUpdate switch onionErr := failure.(type) { case *lnwire.FailExpiryTooSoon: - update = &onionErr.Update + update = onionErr.Update case *lnwire.FailAmountBelowMinimum: - update = &onionErr.Update + update = onionErr.Update case *lnwire.FailFeeInsufficient: - update = &onionErr.Update + update = onionErr.Update case *lnwire.FailIncorrectCltvExpiry: - update = &onionErr.Update + update = onionErr.Update case *lnwire.FailChannelDisabled: - update = &onionErr.Update + update = onionErr.Update case *lnwire.FailTemporaryChannelFailure: update = onionErr.Update } diff --git a/routing/router_test.go b/routing/router_test.go index 1a173b2c9c..e374438763 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -558,7 +558,7 @@ func TestChannelUpdateValidation(t *testing.T) { func(firstHop lnwire.ShortChannelID) ([32]byte, error) { return [32]byte{}, htlcswitch.NewForwardingError( &lnwire.FailFeeInsufficient{ - Update: errChanUpdate, + Update: &errChanUpdate, }, 1, ) @@ -665,9 +665,6 @@ func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) { signErrChanUpdate(t, ctx.privKeys["songoku"], errChanUpdate) - chanUpd, ok := errChanUpdate.(*lnwire.ChannelUpdate1) - require.True(t, ok) - // We'll now modify the SendToSwitch method to return an error for the // outgoing channel to Son goku. This will be a fee related error, so // it should only cause the edge to be pruned after the second attempt. @@ -688,7 +685,7 @@ func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) { // reflect the new fee schedule for the // node/channel. &lnwire.FailFeeInsufficient{ - Update: *chanUpd, + Update: errChanUpdate, }, 1, ) } @@ -798,7 +795,7 @@ func TestSendPaymentErrorFeeInsufficientPrivateEdge(t *testing.T) { // reflect the new fee schedule for the // node/channel. &lnwire.FailFeeInsufficient{ - Update: errChanUpdate, + Update: &errChanUpdate, }, 1, ) }, @@ -924,7 +921,7 @@ func TestSendPaymentPrivateEdgeUpdateFeeExceedsLimit(t *testing.T) { // reflect the new fee schedule for the // node/channel. &lnwire.FailFeeInsufficient{ - Update: errChanUpdate, + Update: &errChanUpdate, }, 1, ) }, @@ -1008,9 +1005,6 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) { ) require.NoError(t, err) - chanUpd, ok := errChanUpdate.(*lnwire.ChannelUpdate1) - require.True(t, ok) - // We'll now modify the SendToSwitch method to return an error for the // outgoing channel to son goku. Since this is a time lock related // error, we should fail the payment flow all together, as Goku is the @@ -1020,7 +1014,7 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) { if firstHop == roasbeefSongoku { return [32]byte{}, htlcswitch.NewForwardingError( &lnwire.FailExpiryTooSoon{ - Update: *chanUpd, + Update: errChanUpdate, }, 1, ) } @@ -1068,7 +1062,7 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) { if firstHop == roasbeefSongoku { return [32]byte{}, htlcswitch.NewForwardingError( &lnwire.FailIncorrectCltvExpiry{ - Update: *chanUpd, + Update: errChanUpdate, }, 1, ) } @@ -1468,7 +1462,7 @@ func TestSendToRouteStructuredError(t *testing.T) { testCases := map[int]lnwire.FailureMessage{ finalHopIndex: lnwire.NewFailIncorrectDetails(payAmt, 100), 1: &lnwire.FailFeeInsufficient{ - Update: lnwire.ChannelUpdate1{}, + Update: &lnwire.ChannelUpdate1{}, }, } From b3602d6c86eb1523304bc91552e3c2780c1a34e8 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 12:00:28 +0200 Subject: [PATCH 38/60] htlcswitch: let failAliasUpdate return lnwire.ChannelUpdate --- htlcswitch/interfaces.go | 2 +- htlcswitch/link.go | 21 +++++++++++---------- htlcswitch/link_test.go | 2 +- htlcswitch/mock.go | 4 ++-- htlcswitch/switch.go | 2 +- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/htlcswitch/interfaces.go b/htlcswitch/interfaces.go index 3dd70247d2..c8cd350e5b 100644 --- a/htlcswitch/interfaces.go +++ b/htlcswitch/interfaces.go @@ -87,7 +87,7 @@ type scidAliasHandler interface { // HTLCs on option_scid_alias channels. attachFailAliasUpdate(failClosure func( sid lnwire.ShortChannelID, - incoming bool) *lnwire.ChannelUpdate1) + incoming bool) lnwire.ChannelUpdate) // getAliases fetches the link's underlying aliases. This is used by // the Switch to determine whether to forward an HTLC and where to diff --git a/htlcswitch/link.go b/htlcswitch/link.go index db5f22072e..b1a469a929 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -263,7 +263,7 @@ type ChannelLinkConfig struct { // FailAliasUpdate is a function used to fail an HTLC for an // option_scid_alias channel. FailAliasUpdate func(sid lnwire.ShortChannelID, - incoming bool) *lnwire.ChannelUpdate1 + incoming bool) lnwire.ChannelUpdate // GetAliases is used by the link and switch to fetch the set of // aliases for a given link. @@ -766,7 +766,7 @@ func shouldAdjustCommitFee(netFee, chanFee, } // failCb is used to cut down on the argument verbosity. -type failCb func(update *lnwire.ChannelUpdate1) lnwire.FailureMessage +type failCb func(update lnwire.ChannelUpdate) lnwire.FailureMessage // createFailureWithUpdate creates a ChannelUpdate when failing an incoming or // outgoing HTLC. It may return a FailureMessage that references a channel's @@ -2966,7 +2966,7 @@ func (l *channelLink) getAliases() []lnwire.ShortChannelID { // // Part of the scidAliasHandler interface. func (l *channelLink) attachFailAliasUpdate(closure func( - sid lnwire.ShortChannelID, incoming bool) *lnwire.ChannelUpdate1) { + sid lnwire.ShortChannelID, incoming bool) lnwire.ChannelUpdate) { l.Lock() l.cfg.FailAliasUpdate = closure @@ -3058,7 +3058,7 @@ func (l *channelLink) CheckHtlcForward(payHash [32]byte, // As part of the returned error, we'll send our latest routing // policy so the sending node obtains the most up to date data. - cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage { + cb := func(upd lnwire.ChannelUpdate) lnwire.FailureMessage { return lnwire.NewFeeInsufficient(amtToForward, upd) } failure := l.createFailureWithUpdate(false, originalScid, cb) @@ -3086,7 +3086,7 @@ func (l *channelLink) CheckHtlcForward(payHash [32]byte, // Grab the latest routing policy so the sending node is up to // date with our current policy. - cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage { + cb := func(upd lnwire.ChannelUpdate) lnwire.FailureMessage { return lnwire.NewIncorrectCltvExpiry( incomingTimeout, upd, ) @@ -3135,7 +3135,7 @@ func (l *channelLink) canSendHtlc(policy models.ForwardingPolicy, // As part of the returned error, we'll send our latest routing // policy so the sending node obtains the most up to date data. - cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage { + cb := func(upd lnwire.ChannelUpdate) lnwire.FailureMessage { return lnwire.NewAmountBelowMinimum(amt, upd) } failure := l.createFailureWithUpdate(false, originalScid, cb) @@ -3150,7 +3150,7 @@ func (l *channelLink) canSendHtlc(policy models.ForwardingPolicy, // As part of the returned error, we'll send our latest routing // policy so the sending node obtains the most up-to-date data. - cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage { + cb := func(upd lnwire.ChannelUpdate) lnwire.FailureMessage { return lnwire.NewTemporaryChannelFailure(upd) } failure := l.createFailureWithUpdate(false, originalScid, cb) @@ -3165,7 +3165,7 @@ func (l *channelLink) canSendHtlc(policy models.ForwardingPolicy, "outgoing_expiry=%v, best_height=%v", payHash[:], timeout, heightNow) - cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage { + cb := func(upd lnwire.ChannelUpdate) lnwire.FailureMessage { return lnwire.NewExpiryTooSoon(upd) } failure := l.createFailureWithUpdate(false, originalScid, cb) @@ -3185,7 +3185,7 @@ func (l *channelLink) canSendHtlc(policy models.ForwardingPolicy, if amt > l.Bandwidth() { l.log.Warnf("insufficient bandwidth to route htlc: %v is "+ "larger than %v", amt, l.Bandwidth()) - cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage { + cb := func(upd lnwire.ChannelUpdate) lnwire.FailureMessage { return lnwire.NewTemporaryChannelFailure(upd) } failure := l.createFailureWithUpdate(false, originalScid, cb) @@ -3697,7 +3697,8 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg) { l.log.Errorf("unable to encode the "+ "remaining route %v", err) - cb := func(upd *lnwire.ChannelUpdate1) lnwire.FailureMessage { //nolint:lll + //nolint:lll + cb := func(upd lnwire.ChannelUpdate) lnwire.FailureMessage { return lnwire.NewTemporaryChannelFailure(upd) } diff --git a/htlcswitch/link_test.go b/htlcswitch/link_test.go index 018601a045..ca2b2c46d2 100644 --- a/htlcswitch/link_test.go +++ b/htlcswitch/link_test.go @@ -6178,7 +6178,7 @@ func TestCheckHtlcForward(t *testing.T) { } failAliasUpdate := func(sid lnwire.ShortChannelID, - incoming bool) *lnwire.ChannelUpdate1 { + incoming bool) lnwire.ChannelUpdate { return nil } diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go index 50165be29d..bc560f19bf 100644 --- a/htlcswitch/mock.go +++ b/htlcswitch/mock.go @@ -744,7 +744,7 @@ type mockChannelLink struct { checkHtlcForwardResult *LinkError failAliasUpdate func(sid lnwire.ShortChannelID, - incoming bool) *lnwire.ChannelUpdate1 + incoming bool) lnwire.ChannelUpdate confirmedZC bool } @@ -879,7 +879,7 @@ func (f *mockChannelLink) AttachMailBox(mailBox MailBox) { } func (f *mockChannelLink) attachFailAliasUpdate(closure func( - sid lnwire.ShortChannelID, incoming bool) *lnwire.ChannelUpdate1) { + sid lnwire.ShortChannelID, incoming bool) lnwire.ChannelUpdate) { f.failAliasUpdate = closure } diff --git a/htlcswitch/switch.go b/htlcswitch/switch.go index 79f664b1f7..cf7aba5872 100644 --- a/htlcswitch/switch.go +++ b/htlcswitch/switch.go @@ -2639,7 +2639,7 @@ func (s *Switch) failMailboxUpdate(outgoingScid, // and the caller is expected to handle this properly. In this case, a return // to the original non-alias behavior is expected. func (s *Switch) failAliasUpdate(scid lnwire.ShortChannelID, - incoming bool) *lnwire.ChannelUpdate1 { + incoming bool) lnwire.ChannelUpdate { // This function does not defer the unlocking because of the database // lookups for ChannelUpdate. From c42cdd449c5f25cd083179122b5cf3fd0f95eea6 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 12:06:42 +0200 Subject: [PATCH 39/60] htlcswitch: use ChannelUpdate interface in FetchLastChannelUpdate --- htlcswitch/link.go | 2 +- htlcswitch/link_test.go | 2 +- htlcswitch/mock.go | 2 +- htlcswitch/switch.go | 8 ++++---- htlcswitch/switch_test.go | 2 +- htlcswitch/test_utils.go | 4 ++-- peer/brontide.go | 2 +- peer/test_utils.go | 5 +++-- server.go | 4 ++-- 9 files changed, 16 insertions(+), 15 deletions(-) diff --git a/htlcswitch/link.go b/htlcswitch/link.go index b1a469a929..d98be65bbc 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -121,7 +121,7 @@ type ChannelLinkConfig struct { // provide payment senders our latest policy when sending encrypted // error messages. FetchLastChannelUpdate func(lnwire.ShortChannelID) ( - *lnwire.ChannelUpdate1, error) + lnwire.ChannelUpdate, error) // Peer is a lightning network node with which we have the channel link // opened. diff --git a/htlcswitch/link_test.go b/htlcswitch/link_test.go index ca2b2c46d2..3fcc0ffa8e 100644 --- a/htlcswitch/link_test.go +++ b/htlcswitch/link_test.go @@ -6172,7 +6172,7 @@ func TestForwardingAsymmetricTimeLockPolicies(t *testing.T) { // forwarding policy. func TestCheckHtlcForward(t *testing.T) { fetchLastChannelUpdate := func(lnwire.ShortChannelID) ( - *lnwire.ChannelUpdate1, error) { + lnwire.ChannelUpdate, error) { return &lnwire.ChannelUpdate1{}, nil } diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go index bc560f19bf..eb05b39679 100644 --- a/htlcswitch/mock.go +++ b/htlcswitch/mock.go @@ -192,7 +192,7 @@ func initSwitchWithDB(startingHeight uint32, db *channeldb.DB) (*Switch, error) events: make(map[time.Time]channeldb.ForwardingEvent), }, FetchLastChannelUpdate: func(scid lnwire.ShortChannelID) ( - *lnwire.ChannelUpdate1, error) { + lnwire.ChannelUpdate, error) { return &lnwire.ChannelUpdate1{ ShortChannelID: scid, diff --git a/htlcswitch/switch.go b/htlcswitch/switch.go index cf7aba5872..1422b7c88f 100644 --- a/htlcswitch/switch.go +++ b/htlcswitch/switch.go @@ -173,7 +173,7 @@ type Config struct { // provide payment senders our latest policy when sending encrypted // error messages. FetchLastChannelUpdate func(lnwire.ShortChannelID) ( - *lnwire.ChannelUpdate1, error) + lnwire.ChannelUpdate, error) // Notifier is an instance of a chain notifier that we'll use to signal // the switch when a new block has arrived. @@ -2668,7 +2668,7 @@ func (s *Switch) failAliasUpdate(scid lnwire.ShortChannelID, } // Replace the baseScid with the passed-in alias. - update.ShortChannelID = scid + update.SetSCID(scid) err = s.cfg.SignAliasUpdate(update) if err != nil { return nil @@ -2689,7 +2689,7 @@ func (s *Switch) failAliasUpdate(scid lnwire.ShortChannelID, // In the incoming case, we want to ensure that we don't leak // the UTXO in case the channel is private. In the outgoing // case, since the alias was used, we do the same thing. - update.ShortChannelID = scid + update.SetSCID(scid) err = s.cfg.SignAliasUpdate(update) if err != nil { return nil @@ -2739,7 +2739,7 @@ func (s *Switch) failAliasUpdate(scid lnwire.ShortChannelID, // We will replace and sign the update with the first alias. // Since this happens on the incoming side, it's not actually // possible to know what the sender used in the onion. - update.ShortChannelID = aliases[0] + update.SetSCID(aliases[0]) err := s.cfg.SignAliasUpdate(update) if err != nil { return nil diff --git a/htlcswitch/switch_test.go b/htlcswitch/switch_test.go index d9e68f3554..6220b71c99 100644 --- a/htlcswitch/switch_test.go +++ b/htlcswitch/switch_test.go @@ -3954,7 +3954,7 @@ func TestSwitchHoldForward(t *testing.T) { // Simulate an error during the composition of the failure message. currentCallback := c.s.cfg.FetchLastChannelUpdate c.s.cfg.FetchLastChannelUpdate = func( - lnwire.ShortChannelID) (*lnwire.ChannelUpdate1, error) { + lnwire.ShortChannelID) (lnwire.ChannelUpdate, error) { return nil, errors.New("cannot fetch update") } diff --git a/htlcswitch/test_utils.go b/htlcswitch/test_utils.go index 450d5a19d8..ae7b7ec7aa 100644 --- a/htlcswitch/test_utils.go +++ b/htlcswitch/test_utils.go @@ -91,8 +91,8 @@ func genIDs() (lnwire.ChannelID, lnwire.ChannelID, lnwire.ShortChannelID, // mockGetChanUpdateMessage helper function which returns topology update of // the channel -func mockGetChanUpdateMessage(_ lnwire.ShortChannelID) (*lnwire.ChannelUpdate1, - error) { +func mockGetChanUpdateMessage(_ lnwire.ShortChannelID) ( + lnwire.ChannelUpdate, error) { return &lnwire.ChannelUpdate1{ Signature: wireSig, diff --git a/peer/brontide.go b/peer/brontide.go index 56f713a4df..8cfae3c697 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -317,7 +317,7 @@ type Config struct { // FetchLastChanUpdate fetches our latest channel update for a target // channel. - FetchLastChanUpdate func(lnwire.ShortChannelID) (*lnwire.ChannelUpdate1, + FetchLastChanUpdate func(lnwire.ShortChannelID) (lnwire.ChannelUpdate, error) // FundingManager is an implementation of the funding.Controller interface. diff --git a/peer/test_utils.go b/peer/test_utils.go index 0db1186ed0..5b98b6c555 100644 --- a/peer/test_utils.go +++ b/peer/test_utils.go @@ -722,8 +722,9 @@ func createTestPeer(t *testing.T) *peerTestCtx { return nil }, PongBuf: make([]byte, lnwire.MaxPongBytes), - FetchLastChanUpdate: func(chanID lnwire.ShortChannelID, - ) (*lnwire.ChannelUpdate1, error) { + FetchLastChanUpdate: func( + chanID lnwire.ShortChannelID) (lnwire.ChannelUpdate, + error) { return &lnwire.ChannelUpdate1{}, nil }, diff --git a/server.go b/server.go index ffe5a83e1b..4b3b6cba3b 100644 --- a/server.go +++ b/server.go @@ -4899,10 +4899,10 @@ func (s *server) fetchNodeAdvertisedAddrs(pub *btcec.PublicKey) ([]net.Addr, err // fetchLastChanUpdate returns a function which is able to retrieve our latest // channel update for a target channel. func (s *server) fetchLastChanUpdate() func(lnwire.ShortChannelID) ( - *lnwire.ChannelUpdate1, error) { + lnwire.ChannelUpdate, error) { ourPubKey := s.identityECDH.PubKey().SerializeCompressed() - return func(cid lnwire.ShortChannelID) (*lnwire.ChannelUpdate1, error) { + return func(cid lnwire.ShortChannelID) (lnwire.ChannelUpdate, error) { info, edge1, edge2, err := s.graphBuilder.GetChannelByID(cid) if err != nil { return nil, err From 39f0eee549a86d7d8e47960cdee8859cf414569c Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 12:13:19 +0200 Subject: [PATCH 40/60] netann: use ChannelUpdate interface in ExtractChannelUpdate --- netann/channel_update.go | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/netann/channel_update.go b/netann/channel_update.go index 1062f5d422..eb1d5ff2eb 100644 --- a/netann/channel_update.go +++ b/netann/channel_update.go @@ -142,7 +142,7 @@ func SignChannelUpdate(signer keychain.MessageSignerRing, // NOTE: The passed policies can be nil. func ExtractChannelUpdate(ownerPubKey []byte, info models.ChannelEdgeInfo, policies ...models.ChannelEdgePolicy) ( - *lnwire.ChannelUpdate1, error) { + lnwire.ChannelUpdate, error) { // Helper function to extract the owner of the given policy. owner := func(edge models.ChannelEdgePolicy) []byte { @@ -164,19 +164,7 @@ func ExtractChannelUpdate(ownerPubKey []byte, // Extract the channel update from the policy we own, if any. for _, edge := range policies { if edge != nil && bytes.Equal(ownerPubKey, owner(edge)) { - update, err := ChannelUpdateFromEdge(info, edge) - if err != nil { - return nil, err - } - - chanUpd1, ok := update.(*lnwire.ChannelUpdate1) - if !ok { - return nil, fmt.Errorf("expected "+ - "*lnwire.ChannelUpdate1, got: %T", - chanUpd1) - } - - return chanUpd1, nil + return ChannelUpdateFromEdge(info, edge) } } From d5ecbebfc12487b2d21cd1f877cfefc7f4e7d12f Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 12:24:18 +0200 Subject: [PATCH 41/60] multi: use ChannelUpdate interface in various places --- discovery/gossiper.go | 59 +++++++++++++++++++++------------ discovery/gossiper_test.go | 7 ++-- discovery/message_store.go | 19 +++++++---- discovery/message_store_test.go | 8 ++--- funding/manager.go | 2 +- funding/manager_test.go | 14 ++++---- graph/validation_barrier.go | 12 +++---- peer/brontide.go | 7 ++++ 8 files changed, 79 insertions(+), 49 deletions(-) diff --git a/discovery/gossiper.go b/discovery/gossiper.go index ea667dbef1..d99a3b3eb8 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -949,10 +949,9 @@ type channelUpdateID struct { // retrieve all necessary data to validate the channel existence. channelID lnwire.ShortChannelID - // Flags least-significant bit must be set to 0 if the creating node - // corresponds to the first node in the previously sent channel - // announcement and 1 otherwise. - flags lnwire.ChanUpdateChanFlags + disabled bool + + direction bool } // msgWithSenders is a wrapper struct around a message, and the set of peers @@ -1061,32 +1060,49 @@ func (d *deDupedAnnouncements) addMsg(message networkMsg) { // Channel updates are identified by the (short channel id, // channelflags) tuple. - case *lnwire.ChannelUpdate1: + case lnwire.ChannelUpdate: sender := route.NewVertex(message.source) deDupKey := channelUpdateID{ - msg.ShortChannelID, - msg.ChannelFlags, + msg.SCID(), + msg.IsDisabled(), + msg.IsNode1(), } - oldTimestamp := uint32(0) + var ( + older = false + newer = true + ) mws, ok := d.channelUpdates[deDupKey] if ok { // If we already have seen this message, record its // timestamp. - update, ok := mws.msg.(*lnwire.ChannelUpdate1) + oldMsg, ok := mws.msg.(lnwire.ChannelUpdate) if !ok { - log.Errorf("Expected *lnwire.ChannelUpdate1, "+ - "got: %T", mws.msg) + log.Errorf("expected type "+ + "lnwire.ChannelUpdate, got: %T", + mws.msg) + + return + } + cmp, err := msg.CmpAge(oldMsg) + if err != nil { return } - oldTimestamp = update.Timestamp + newer = false + switch cmp { + case lnwire.LessThan: + older = true + case lnwire.GreaterThan: + newer = true + default: + } } // If we already had this message with a strictly newer // timestamp, then we'll just discard the message we got. - if oldTimestamp > msg.Timestamp { + if older { log.Debugf("Ignored outdated network message: "+ "peer=%v, msg=%s", message.peer, msg.MsgType()) return @@ -1095,7 +1111,7 @@ func (d *deDupedAnnouncements) addMsg(message networkMsg) { // If the message we just got is newer than what we previously // have seen, or this is the first time we see it, then we'll // add it to our map of announcements. - if oldTimestamp < msg.Timestamp { + if newer { mws = msgWithSenders{ msg: msg, isLocal: !message.isRemote, @@ -1616,8 +1632,8 @@ func (d *AuthenticatedGossiper) isRecentlyRejectedMsg(msg lnwire.Message, var scid uint64 switch m := msg.(type) { - case *lnwire.ChannelUpdate1: - scid = m.ShortChannelID.ToUint64() + case lnwire.ChannelUpdate: + scid = m.SCID().ToUint64() case lnwire.ChannelAnnouncement: scid = m.SCID().ToUint64() @@ -2115,7 +2131,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement( // ChannelEdgeInfo1 should be inspected. func (d *AuthenticatedGossiper) processZombieUpdate( chanInfo models.ChannelEdgeInfo, scid lnwire.ShortChannelID, - msg *lnwire.ChannelUpdate1) error { + msg lnwire.ChannelUpdate) error { // Since we've deemed the update as not stale above, before marking it // live, we'll make sure it has been signed by the correct party. If we @@ -2131,7 +2147,7 @@ func (d *AuthenticatedGossiper) processZombieUpdate( } if pubKey == nil { return fmt.Errorf("incorrect pubkey to resurrect zombie "+ - "with chan_id=%v", msg.ShortChannelID) + "with chan_id=%v", msg.SCID()) } err := netann.VerifyChannelUpdateSignature(msg, pubKey) @@ -2139,7 +2155,6 @@ func (d *AuthenticatedGossiper) processZombieUpdate( return fmt.Errorf("unable to verify channel "+ "update signature: %v", err) } - // With the signature valid, we'll proceed to mark the // edge as live and wait for the channel announcement to // come through again. @@ -2154,13 +2169,13 @@ func (d *AuthenticatedGossiper) processZombieUpdate( case err != nil: return fmt.Errorf("unable to remove edge with "+ "chan_id=%v from zombie index: %v", - msg.ShortChannelID, err) + msg.SCID(), err) default: } log.Debugf("Removed edge with chan_id=%v from zombie "+ - "index", msg.ShortChannelID) + "index", msg.SCID()) return nil } @@ -2858,7 +2873,7 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg, // Reprocess the message, making sure we return an // error to the original caller in case the gossiper // shuts down. - case *lnwire.ChannelUpdate1: + case lnwire.ChannelUpdate: log.Debugf("Reprocessing ChannelUpdate for "+ "shortChanID=%v", scid.ToUint64()) diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index 84a77263d0..7b29dc509f 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -1884,7 +1884,8 @@ func TestDeDuplicatedAnnouncements(t *testing.T) { assertChannelUpdate := func(channelUpdate *lnwire.ChannelUpdate1) { channelKey := channelUpdateID{ ua3.ShortChannelID, - ua3.ChannelFlags, + ua3.IsDisabled(), + ua3.IsNode1(), } mws, ok := announcements.channelUpdates[channelKey] @@ -2827,7 +2828,7 @@ func TestRetransmit(t *testing.T) { switch msg.(type) { case lnwire.ChannelAnnouncement: chanAnn++ - case *lnwire.ChannelUpdate1: + case lnwire.ChannelUpdate: chanUpd++ case *lnwire.NodeAnnouncement: nodeAnn++ @@ -3314,7 +3315,7 @@ func TestSendChannelUpdateReliably(t *testing.T) { } switch msg := msg.(type) { - case *lnwire.ChannelUpdate1: + case lnwire.ChannelUpdate: assertMessage(t, staleChannelUpdate, msg) case *lnwire.AnnounceSignatures1: assertMessage(t, batch.localProofAnn, msg) diff --git a/discovery/message_store.go b/discovery/message_store.go index e336c1281b..156d56caa3 100644 --- a/discovery/message_store.go +++ b/discovery/message_store.go @@ -85,8 +85,8 @@ func msgShortChanID(msg lnwire.Message) (lnwire.ShortChannelID, error) { switch msg := msg.(type) { case lnwire.AnnounceSignatures: shortChanID = msg.SCID() - case *lnwire.ChannelUpdate1: - shortChanID = msg.ShortChannelID + case lnwire.ChannelUpdate: + shortChanID = msg.SCID() default: return shortChanID, ErrUnsupportedMessage } @@ -160,7 +160,7 @@ func (s *MessageStore) DeleteMessage(msg lnwire.Message, // In the event that we're attempting to delete a ChannelUpdate // from the store, we'll make sure that we're actually deleting // the correct one as it can be overwritten. - if msg, ok := msg.(*lnwire.ChannelUpdate1); ok { + if msg, ok := msg.(lnwire.ChannelUpdate); ok { // Deleting a value from a bucket that doesn't exist // acts as a NOP, so we'll return if a message doesn't // exist under this key. @@ -176,13 +176,18 @@ func (s *MessageStore) DeleteMessage(msg lnwire.Message, // If the timestamps don't match, then the update stored // should be the latest one, so we'll avoid deleting it. - m, ok := dbMsg.(*lnwire.ChannelUpdate1) + m, ok := dbMsg.(lnwire.ChannelUpdate) if !ok { return fmt.Errorf("expected "+ - "*lnwire.ChannelUpdate1, got: %T", - dbMsg) + "lnwire.ChannelUpdate, got: %T", dbMsg) + } + + diff, err := msg.CmpAge(m) + if err != nil { + return err } - if msg.Timestamp != m.Timestamp { + + if diff != lnwire.EqualTo { return nil } } diff --git a/discovery/message_store_test.go b/discovery/message_store_test.go index 36c082e36f..10189b9022 100644 --- a/discovery/message_store_test.go +++ b/discovery/message_store_test.go @@ -116,10 +116,10 @@ func TestMessageStoreMessages(t *testing.T) { for _, msg := range peerMsgs { var shortChanID uint64 switch msg := msg.(type) { - case *lnwire.AnnounceSignatures1: - shortChanID = msg.ShortChannelID.ToUint64() - case *lnwire.ChannelUpdate1: - shortChanID = msg.ShortChannelID.ToUint64() + case lnwire.AnnounceSignatures: + shortChanID = msg.SCID().ToUint64() + case lnwire.ChannelUpdate: + shortChanID = msg.SCID().ToUint64() default: t.Fatalf("found unexpected message type %T", msg) } diff --git a/funding/manager.go b/funding/manager.go index dcc9e94c9c..40f18121bc 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -4292,7 +4292,7 @@ func (f *Manager) ensureInitialForwardingPolicy(chanID lnwire.ChannelID, // send out to the network after a new channel has been created locally. type chanAnnouncement struct { chanAnn lnwire.ChannelAnnouncement - chanUpdateAnn *lnwire.ChannelUpdate1 + chanUpdateAnn lnwire.ChannelUpdate chanProof lnwire.AnnounceSignatures } diff --git a/funding/manager_test.go b/funding/manager_test.go index a162e06cc2..57a3ffad19 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -1214,7 +1214,7 @@ func assertChannelAnnouncements(t *testing.T, alice, bob *testNode, switch m := msg.(type) { case lnwire.ChannelAnnouncement: gotChannelAnnouncement = true - case *lnwire.ChannelUpdate1: + case lnwire.ChannelUpdate: // The channel update sent by the node should // advertise the MinHTLC value required by the @@ -1229,31 +1229,33 @@ func assertChannelAnnouncements(t *testing.T, alice, bob *testNode, baseFee := aliceCfg.DefaultRoutingPolicy.BaseFee feeRate := aliceCfg.DefaultRoutingPolicy.FeeRate - require.EqualValues(t, 1, m.MessageFlags) + pol := m.ForwardingPolicy() + + require.True(t, pol.HasMaxHTLC) // We might expect a custom MinHTLC value. if len(customMinHtlc) > 0 { minHtlc = customMinHtlc[j] } - require.Equal(t, minHtlc, m.HtlcMinimumMsat) + require.Equal(t, minHtlc, pol.MinHTLC) // We might expect a custom MaxHltc value. if len(customMaxHtlc) > 0 { maxHtlc = customMaxHtlc[j] } - require.Equal(t, maxHtlc, m.HtlcMaximumMsat) + require.Equal(t, maxHtlc, pol.MaxHTLC) // We might expect a custom baseFee value. if len(baseFees) > 0 { baseFee = baseFees[j] } - require.EqualValues(t, baseFee, m.BaseFee) + require.EqualValues(t, baseFee, pol.BaseFee) // We might expect a custom feeRate value. if len(feeRates) > 0 { feeRate = feeRates[j] } - require.EqualValues(t, feeRate, m.FeeRate) + require.EqualValues(t, feeRate, pol.FeeRate) gotChannelUpdate = true } diff --git a/graph/validation_barrier.go b/graph/validation_barrier.go index c1de127bad..74ca896204 100644 --- a/graph/validation_barrier.go +++ b/graph/validation_barrier.go @@ -146,7 +146,7 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) { // initialization needs to be done beyond just occupying a job slot. case models.ChannelEdgePolicy: return - case *lnwire.ChannelUpdate1: + case lnwire.ChannelUpdate: return case *lnwire.NodeAnnouncement: // TODO(roasbeef): node ann needs to wait on existing channel updates @@ -201,11 +201,11 @@ func (v *ValidationBarrier) WaitForDependants(job interface{}) error { jobDesc = fmt.Sprintf("job=channeldb.LightningNode, pub=%s", vertex) - case *lnwire.ChannelUpdate1: - signals, ok = v.chanEdgeDependencies[msg.ShortChannelID] + case lnwire.ChannelUpdate: + signals, ok = v.chanEdgeDependencies[msg.SCID()] jobDesc = fmt.Sprintf("job=lnwire.ChannelUpdate, scid=%v", - msg.ShortChannelID.ToUint64()) + msg.SCID().ToUint64()) case *lnwire.NodeAnnouncement: vertex := route.Vertex(msg.NodeID) @@ -296,8 +296,8 @@ func (v *ValidationBarrier) SignalDependants(job interface{}, allow bool) { delete(v.nodeAnnDependencies, route.Vertex(msg.PubKeyBytes)) case *lnwire.NodeAnnouncement: delete(v.nodeAnnDependencies, route.Vertex(msg.NodeID)) - case *lnwire.ChannelUpdate1: - delete(v.chanEdgeDependencies, msg.ShortChannelID) + case lnwire.ChannelUpdate: + delete(v.chanEdgeDependencies, msg.SCID()) case models.ChannelEdgePolicy: delete(v.chanEdgeDependencies, msg.SCID()) diff --git a/peer/brontide.go b/peer/brontide.go index 8cfae3c697..fa98aab352 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -2040,6 +2040,7 @@ out: } case *lnwire.ChannelUpdate1, + *lnwire.ChannelUpdate2, *lnwire.ChannelAnnouncement1, *lnwire.ChannelAnnouncement2, *lnwire.NodeAnnouncement, @@ -2317,6 +2318,12 @@ func messageSummary(msg lnwire.Message) string { msg.ShortChannelID.ToUint64(), msg.MessageFlags, msg.ChannelFlags, time.Unix(int64(msg.Timestamp), 0)) + case *lnwire.ChannelUpdate2: + return fmt.Sprintf("chain_hash=%v, short_chan_id=%v, "+ + "is_disabled=%v, is_node_1=%v, block_height=%v", + msg.ChainHash, msg.ShortChannelID.Val.ToUint64(), + msg.IsDisabled(), msg.IsNode1(), msg.BlockHeight) + case *lnwire.NodeAnnouncement: return fmt.Sprintf("node=%x, update_time=%v", msg.NodeID, time.Unix(int64(msg.Timestamp), 0)) From 58bad38b67d8118ae1878ed70e8b8bc42543360d Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 12:41:58 +0200 Subject: [PATCH 42/60] discovery+routing: update to use ChanUpdate interface In the IsKeepAlive and IsStaleEdgePolicy functions --- discovery/gossiper.go | 157 +++++++++++++++++++++++++++---------- discovery/gossiper_test.go | 14 +++- graph/builder.go | 135 +++++++++++++++++++++---------- graph/builder_test.go | 26 +++--- graph/interfaces.go | 4 +- 5 files changed, 238 insertions(+), 98 deletions(-) diff --git a/discovery/gossiper.go b/discovery/gossiper.go index d99a3b3eb8..38bddc3b4e 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -2413,48 +2413,114 @@ func (d *AuthenticatedGossiper) SyncManager() *SyncManager { // IsKeepAliveUpdate determines whether this channel update is considered a // keep-alive update based on the previous channel update processed for the same // direction. -func IsKeepAliveUpdate(update *lnwire.ChannelUpdate1, - prev *models.ChannelEdgePolicy1) bool { +func IsKeepAliveUpdate(update lnwire.ChannelUpdate, + prevPolicy models.ChannelEdgePolicy) (bool, error) { - // Both updates should be from the same direction. - if update.ChannelFlags&lnwire.ChanUpdateDirection != - prev.ChannelFlags&lnwire.ChanUpdateDirection { + switch upd := update.(type) { + case *lnwire.ChannelUpdate1: + prev, ok := prevPolicy.(*models.ChannelEdgePolicy1) + if !ok { + return false, fmt.Errorf("expected chan edge policy 1") + } - return false - } + // Both updates should be from the same direction. + if upd.ChannelFlags&lnwire.ChanUpdateDirection != + prev.ChannelFlags&lnwire.ChanUpdateDirection { - // The timestamp should always increase for a keep-alive update. - timestamp := time.Unix(int64(update.Timestamp), 0) - if !timestamp.After(prev.LastUpdate) { - return false - } + return false, nil + } - // None of the remaining fields should change for a keep-alive update. - if update.ChannelFlags.IsDisabled() != prev.ChannelFlags.IsDisabled() { - return false - } - if lnwire.MilliSatoshi(update.BaseFee) != prev.FeeBaseMSat { - return false - } - if lnwire.MilliSatoshi(update.FeeRate) != prev.FeeProportionalMillionths { - return false - } - if update.TimeLockDelta != prev.TimeLockDelta { - return false - } - if update.HtlcMinimumMsat != prev.MinHTLC { - return false - } - if update.MessageFlags.HasMaxHtlc() && !prev.MessageFlags.HasMaxHtlc() { - return false - } - if update.HtlcMaximumMsat != prev.MaxHTLC { - return false - } - if !bytes.Equal(update.ExtraOpaqueData, prev.ExtraOpaqueData) { - return false + // The timestamp should always increase for a keep-alive update. + timestamp := time.Unix(int64(upd.Timestamp), 0) + if !timestamp.After(prev.LastUpdate) { + return false, nil + } + + // None of the remaining fields should change for a keep-alive + // update. + if upd.ChannelFlags.IsDisabled() != + prev.ChannelFlags.IsDisabled() { + + return false, nil + } + if lnwire.MilliSatoshi(upd.BaseFee) != prev.FeeBaseMSat { + return false, nil + } + if lnwire.MilliSatoshi(upd.FeeRate) != + prev.FeeProportionalMillionths { + + return false, nil + } + if upd.TimeLockDelta != prev.TimeLockDelta { + return false, nil + } + if upd.HtlcMinimumMsat != prev.MinHTLC { + return false, nil + } + if upd.MessageFlags.HasMaxHtlc() && + !prev.MessageFlags.HasMaxHtlc() { + + return false, nil + } + if upd.HtlcMaximumMsat != prev.MaxHTLC { + return false, nil + } + if !bytes.Equal(upd.ExtraOpaqueData, prev.ExtraOpaqueData) { + return false, nil + } + + return true, nil + + case *lnwire.ChannelUpdate2: + prev, ok := prevPolicy.(*models.ChannelEdgePolicy2) + if !ok { + return false, fmt.Errorf("expected chan edge policy 2") + } + + // Both updates should be from the same direction. + if upd.IsNode1() != prev.IsNode1() { + return false, nil + } + + // The block-height should always increase for a keep-alive + // update. + if upd.BlockHeight.Val <= prev.BlockHeight.Val { + return false, nil + } + + // None of the remaining fields should change for a keep-alive + // update. + if upd.IsDisabled() != prev.IsDisabled() { + return false, nil + } + fwd := upd.ForwardingPolicy() + prevFwd := upd.ForwardingPolicy() + + if fwd.BaseFee != prevFwd.BaseFee { + return false, nil + } + if fwd.FeeRate != prevFwd.FeeRate { + return false, nil + } + if fwd.TimeLockDelta != prevFwd.TimeLockDelta { + return false, nil + } + if fwd.MinHTLC != prevFwd.MinHTLC { + return false, nil + } + if fwd.MaxHTLC != prevFwd.MinHTLC { + return false, nil + } + if !bytes.Equal(upd.ExtraOpaqueData, prev.ExtraOpaqueData) { + return false, nil + } + + return true, nil + + default: + return false, fmt.Errorf("unhandled implementation of "+ + "ChannelUpdate: %T", update) } - return true } // latestHeight returns the gossiper's latest height known of the chain. @@ -2977,16 +3043,14 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, graphScid = upd.ShortChannelID } - if d.cfg.Graph.IsStaleEdgePolicy( - graphScid, timestamp, upd.ChannelFlags, - ) { - + if d.cfg.Graph.IsStaleEdgePolicy(graphScid, upd) { log.Debugf("Ignored stale edge policy for short_chan_id(%v): "+ "peer=%v, msg=%s, is_remote=%v", shortChanID, nMsg.peer, nMsg.msg.MsgType(), nMsg.isRemote, ) nMsg.err <- nil + return nil, true } @@ -3168,7 +3232,16 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // heuristic of sending keep-alive updates after the same // duration (see retransmitStaleAnns). timeSinceLastUpdate := timestamp.Sub(edge.LastUpdate) - if IsKeepAliveUpdate(upd, edge) { + isKeepAlive, err := IsKeepAliveUpdate(upd, edge) + if err != nil { + log.Errorf("Could not determine if update is "+ + "keepalive: %v", err) + nMsg.err <- err + + return nil, false + } + + if isKeepAlive { if timeSinceLastUpdate < d.cfg.RebroadcastInterval { log.Debugf("Ignoring keep alive update not "+ "within %v period for channel %v", diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index 7b29dc509f..908dc6cee5 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -359,11 +359,18 @@ func (r *mockGraphSource) IsKnownEdge(chanID lnwire.ShortChannelID) bool { // IsStaleEdgePolicy returns true if the graph source has a channel edge for // the passed channel ID (and flags) that have a more recent timestamp. func (r *mockGraphSource) IsStaleEdgePolicy(chanID lnwire.ShortChannelID, - timestamp time.Time, flags lnwire.ChanUpdateChanFlags) bool { + policy lnwire.ChannelUpdate) bool { r.mu.Lock() defer r.mu.Unlock() + pol, ok := policy.(*lnwire.ChannelUpdate1) + if !ok { + panic("expected chan update 1") + } + + timestamp := time.Unix(int64(pol.Timestamp), 0) + chanIDInt := chanID.ToUint64() edges, ok := r.edges[chanIDInt] if !ok { @@ -373,7 +380,6 @@ func (r *mockGraphSource) IsStaleEdgePolicy(chanID lnwire.ShortChannelID, if !isZombie { return false } - // Since it exists within our zombie index, we'll check that it // respects the router's live edge horizon to determine whether // it is stale or not. @@ -381,7 +387,7 @@ func (r *mockGraphSource) IsStaleEdgePolicy(chanID lnwire.ShortChannelID, } switch { - case flags&lnwire.ChanUpdateDirection == 0 && edges[0] != nil: + case policy.IsNode1() && edges[0] != nil: switch edge := edges[0].(type) { case *models.ChannelEdgePolicy1: return !timestamp.After(edge.LastUpdate) @@ -389,7 +395,7 @@ func (r *mockGraphSource) IsStaleEdgePolicy(chanID lnwire.ShortChannelID, panic(fmt.Sprintf("unhandled: %T", edges[0])) } - case flags&lnwire.ChanUpdateDirection == 1 && edges[1] != nil: + case !policy.IsNode1() && edges[1] != nil: switch edge := edges[1].(type) { case *models.ChannelEdgePolicy1: return !timestamp.After(edge.LastUpdate) diff --git a/graph/builder.go b/graph/builder.go index 4f52d6b235..db4df5a06c 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -1762,53 +1762,108 @@ func (b *Builder) IsKnownEdge(chanID lnwire.ShortChannelID) bool { // // NOTE: This method is part of the ChannelGraphSource interface. func (b *Builder) IsStaleEdgePolicy(chanID lnwire.ShortChannelID, - timestamp time.Time, flags lnwire.ChanUpdateChanFlags) bool { + update lnwire.ChannelUpdate) bool { - edge1Timestamp, edge2Timestamp, exists, isZombie, err := - b.cfg.Graph.HasChannelEdge1(chanID.ToUint64()) - if err != nil { - log.Debugf("Check stale edge policy got error: %v", err) - return false - } + var ( + disabled = update.IsDisabled() + isNode1 = update.IsNode1() + ) + + switch upd := update.(type) { + case *lnwire.ChannelUpdate1: + timestamp := time.Unix(int64(upd.Timestamp), 0) + + edge1Timestamp, edge2Timestamp, exists, isZombie, err := + b.cfg.Graph.HasChannelEdge1(chanID.ToUint64()) + if err != nil { + log.Debugf("Check stale edge policy got error: %v", err) + + return false + } - // If we know of the edge as a zombie, then we'll make some additional - // checks to determine if the new policy is fresh. - if isZombie { - // When running with AssumeChannelValid, we also prune channels - // if both of their edges are disabled. We'll mark the new - // policy as stale if it remains disabled. - if b.cfg.AssumeChannelValid { - isDisabled := flags&lnwire.ChanUpdateDisabled == - lnwire.ChanUpdateDisabled - if isDisabled { - return true + // If we know of the edge as a zombie, then we'll make some + // additional checks to determine if the new policy is fresh. + if isZombie { + // When running with AssumeChannelValid, we also prune + // channels if both of their edges are disabled. We'll + // mark the new policy as stale if it remains disabled. + if b.cfg.AssumeChannelValid { + if disabled { + return true + } } + + // Otherwise, we'll fall back to our usual + // ChannelPruneExpiry. + return time.Since(timestamp) > b.cfg.ChannelPruneExpiry } - // Otherwise, we'll fall back to our usual ChannelPruneExpiry. - return time.Since(timestamp) > b.cfg.ChannelPruneExpiry - } + // If we don't know of the edge, then it means it's fresh (thus + // not stale). + if !exists { + return false + } - // If we don't know of the edge, then it means it's fresh (thus not - // stale). - if !exists { - return false - } + // As edges are directional edge node has a unique policy for + // the direction of the edge they control. Therefore we first + // check if we already have the most up to date information for + // that edge. If so, then we can exit early. + switch { + case isNode1: + return !edge1Timestamp.Before(timestamp) - // As edges are directional edge node has a unique policy for the - // direction of the edge they control. Therefore, we first check if we - // already have the most up-to-date information for that edge. If so, - // then we can exit early. - switch { - // A flag set of 0 indicates this is an announcement for the "first" - // node in the channel. - case flags&lnwire.ChanUpdateDirection == 0: - return !edge1Timestamp.Before(timestamp) - - // Similarly, a flag set of 1 indicates this is an announcement for the - // "second" node in the channel. - case flags&lnwire.ChanUpdateDirection == 1: - return !edge2Timestamp.Before(timestamp) + case !isNode1: + return !edge2Timestamp.Before(timestamp) + } + + case *lnwire.ChannelUpdate2: + height := upd.BlockHeight + + edge1Height, edge2Height, exists, isZombie, err := + b.cfg.Graph.HasChannelEdge2(chanID.ToUint64()) + if err != nil { + log.Debugf("Check stale edge policy got error: %v", err) + + return false + } + + // If we know of the edge as a zombie, then we'll make some + // additional checks to determine if the new policy is fresh. + if isZombie { + // When running with AssumeChannelValid, we also prune + // channels if both of their edges are disabled. We'll + // mark the new policy as stale if it remains disabled. + if b.cfg.AssumeChannelValid { + if disabled { + return true + } + } + + // Otherwise, we'll fall back to our usual + // ChannelPruneExpiry. + blocksSince := b.SyncedHeight() - height.Val + + return blocksSince > + uint32(b.cfg.ChannelPruneExpiry.Hours()*6) + } + + // If we don't know of the edge, then it means it's fresh (thus + // not stale). + if !exists { + return false + } + + // As edges are directional edge node has a unique policy for + // the direction of the edge they control. Therefore we first + // check if we already have the most up to date information for + // that edge. If so, then we can exit early. + switch { + case isNode1: + return edge1Height >= height.Val + + case !isNode1: + return edge2Height >= height.Val + } } return false diff --git a/graph/builder_test.go b/graph/builder_test.go index de3afaaabf..b883b2cc6f 100644 --- a/graph/builder_test.go +++ b/graph/builder_test.go @@ -1142,13 +1142,17 @@ func TestIsStaleEdgePolicy(t *testing.T) { // If we query for staleness before adding the edge, we should get // false. - updateTimeStamp := time.Unix(123, 0) - if ctx.builder.IsStaleEdgePolicy(*chanID, updateTimeStamp, 0) { - t.Fatalf("router failed to detect fresh edge policy") + time1 := 123 + updateTimeStamp := time.Unix(int64(time1), 0) + update1 := &lnwire.ChannelUpdate1{ + Timestamp: uint32(time1), } - if ctx.builder.IsStaleEdgePolicy(*chanID, updateTimeStamp, 1) { - t.Fatalf("router failed to detect fresh edge policy") + update2 := &lnwire.ChannelUpdate1{ + Timestamp: uint32(time1), + ChannelFlags: lnwire.ChanUpdateDirection, } + require.False(t, ctx.builder.IsStaleEdgePolicy(*chanID, update1)) + require.False(t, ctx.builder.IsStaleEdgePolicy(*chanID, update2)) edge := &models.ChannelEdgeInfo1{ ChannelID: chanID.ToUint64(), @@ -1193,20 +1197,22 @@ func TestIsStaleEdgePolicy(t *testing.T) { // Now that the edges have been added, an identical (chanID, flag, // timestamp) tuple for each edge should be detected as a stale edge. - if !ctx.builder.IsStaleEdgePolicy(*chanID, updateTimeStamp, 0) { + if !ctx.builder.IsStaleEdgePolicy(*chanID, update1) { t.Fatalf("router failed to detect stale edge policy") } - if !ctx.builder.IsStaleEdgePolicy(*chanID, updateTimeStamp, 1) { + if !ctx.builder.IsStaleEdgePolicy(*chanID, update2) { t.Fatalf("router failed to detect stale edge policy") } // If we now update the timestamp for both edges, the router should // detect that this tuple represents a fresh edge. - updateTimeStamp = time.Unix(9999, 0) - if ctx.builder.IsStaleEdgePolicy(*chanID, updateTimeStamp, 0) { + time2 := 9999 + update1.Timestamp = uint32(time2) + update2.Timestamp = uint32(time2) + if ctx.builder.IsStaleEdgePolicy(*chanID, update1) { t.Fatalf("router failed to detect fresh edge policy") } - if ctx.builder.IsStaleEdgePolicy(*chanID, updateTimeStamp, 1) { + if ctx.builder.IsStaleEdgePolicy(*chanID, update2) { t.Fatalf("router failed to detect fresh edge policy") } } diff --git a/graph/interfaces.go b/graph/interfaces.go index 60c2cb4d76..1eede0a70d 100644 --- a/graph/interfaces.go +++ b/graph/interfaces.go @@ -59,8 +59,8 @@ type ChannelGraphSource interface { // IsStaleEdgePolicy returns true if the graph source has a channel // edge for the passed channel ID (and flags) that have a more recent // timestamp. - IsStaleEdgePolicy(chanID lnwire.ShortChannelID, timestamp time.Time, - flags lnwire.ChanUpdateChanFlags) bool + IsStaleEdgePolicy(chanID lnwire.ShortChannelID, + policy lnwire.ChannelUpdate) bool // MarkEdgeLive clears an edge from our zombie index, deeming it as // live. From a0f99e9c3c307a21ff40ba6edf5d126801cdfe97 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 14:10:38 +0200 Subject: [PATCH 43/60] discovery: use ChannelUpdate interface in handleChanUpdate --- discovery/gossiper.go | 249 ++++++++++++++++++++++++++---------------- 1 file changed, 155 insertions(+), 94 deletions(-) diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 38bddc3b4e..1de237eeb0 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -2108,7 +2108,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement( // A new authenticated channel edge update has arrived. This indicates // that the directional information for an already known channel has // been updated. - case *lnwire.ChannelUpdate1: + case lnwire.ChannelUpdate: return d.handleChanUpdate(nMsg, msg, schedulerOp) // A new signature announcement has been received. This indicates @@ -2982,22 +2982,28 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg, // handleChanUpdate processes a new channel update. func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, - upd *lnwire.ChannelUpdate1, - ops []batch.SchedulerOption) ([]networkMsg, bool) { + upd lnwire.ChannelUpdate, ops []batch.SchedulerOption) ([]networkMsg, + bool) { + + var ( + scid = upd.SCID() + chainHash = upd.GetChainHash() + ) log.Debugf("Processing ChannelUpdate: peer=%v, short_chan_id=%v, ", - nMsg.peer, upd.ShortChannelID.ToUint64()) + nMsg.peer, scid) // We'll ignore any channel updates that target any chain other than // the set of chains we know of. - if !bytes.Equal(upd.ChainHash[:], d.cfg.ChainHash[:]) { - err := fmt.Errorf("ignoring ChannelUpdate from chain=%v, "+ - "gossiper on chain=%v", upd.ChainHash, d.cfg.ChainHash) + if !bytes.Equal(chainHash[:], d.cfg.ChainHash[:]) { + err := fmt.Errorf("ignoring %s from chain=%v, "+ + "gossiper on chain=%v", upd.MsgType(), chainHash, + d.cfg.ChainHash) + log.Errorf(err.Error()) key := newRejectCacheKey( - upd.ShortChannelID.ToUint64(), - sourceToPub(nMsg.source), + scid.ToUint64(), sourceToPub(nMsg.source), ) _, _ = d.recentRejects.Put(key, &cachedReject{}) @@ -3005,8 +3011,8 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, return nil, false } - blockHeight := upd.ShortChannelID.BlockHeight - shortChanID := upd.ShortChannelID.ToUint64() + blockHeight := upd.SCID().BlockHeight + shortChanID := upd.SCID().ToUint64() // If the advertised inclusionary block is beyond our knowledge of the // chain tip, then we'll put the announcement in limbo to be fully @@ -3014,8 +3020,8 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // alias SCID, we'll skip the isPremature check. This is necessary // since aliases start at block height 16_000_000. d.Lock() - if nMsg.isRemote && !d.cfg.IsAlias(upd.ShortChannelID) && - d.isPremature(upd.ShortChannelID, 0, nMsg) { + if nMsg.isRemote && !d.cfg.IsAlias(scid) && + d.isPremature(scid, 0, nMsg) { log.Warnf("Update announcement for short_chan_id(%v), is "+ "premature: advertises height %v, only height %v is "+ @@ -3026,23 +3032,21 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, } d.Unlock() - // Before we perform any of the expensive checks below, we'll check - // whether this update is stale or is for a zombie channel in order to - // quickly reject it. - timestamp := time.Unix(int64(upd.Timestamp), 0) - // Fetch the SCID we should be using to lock the channelMtx and make // graph queries with. - graphScid, err := d.cfg.FindBaseByAlias(upd.ShortChannelID) + graphScid, err := d.cfg.FindBaseByAlias(scid) if err != nil { // Fallback and set the graphScid to the peer-provided SCID. // This will occur for non-option-scid-alias channels and for // public option-scid-alias channels after 6 confirmations. // Once public option-scid-alias channels have 6 confs, we'll // ignore ChannelUpdates with one of their aliases. - graphScid = upd.ShortChannelID + graphScid = scid } + // Before we perform any of the expensive checks below, we'll check + // whether this update is stale or is for a zombie channel in order to + // quickly reject it. if d.cfg.Graph.IsStaleEdgePolicy(graphScid, upd) { log.Debugf("Ignored stale edge policy for short_chan_id(%v): "+ "peer=%v, msg=%s, is_remote=%v", shortChanID, @@ -3050,24 +3054,46 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, ) nMsg.err <- nil - return nil, true } // Check that the ChanUpdate is not too far into the future, this could // reveal some faulty implementation therefore we log an error. - if time.Until(timestamp) > graph.DefaultChannelPruneExpiry { - log.Errorf("Skewed timestamp (%v) for edge policy of "+ - "short_chan_id(%v), timestamp too far in the future: "+ - "peer=%v, msg=%s, is_remote=%v", timestamp.Unix(), - shortChanID, nMsg.peer, nMsg.msg.MsgType(), - nMsg.isRemote, - ) + // TODO(elle): abstract this check + switch u := upd.(type) { + case *lnwire.ChannelUpdate1: + timestamp := time.Unix(int64(u.Timestamp), 0) + + if time.Until(timestamp) > graph.DefaultChannelPruneExpiry { + log.Errorf("Skewed timestamp (%v) for edge policy of "+ + "short_chan_id(%v), timestamp too far in the future: "+ + "peer=%v, msg=%s, is_remote=%v", timestamp.Unix(), + shortChanID, nMsg.peer, nMsg.msg.MsgType(), + nMsg.isRemote, + ) - nMsg.err <- fmt.Errorf("skewed timestamp of edge policy, "+ - "timestamp too far in the future: %v", timestamp.Unix()) + nMsg.err <- fmt.Errorf("skewed timestamp of edge policy, "+ + "timestamp too far in the future: %v", timestamp.Unix()) - return nil, false + return nil, false + } + + case *lnwire.ChannelUpdate2: + if int64(u.BlockHeight.Val)-int64(d.latestHeight()) > + int64(graph.DefaultChannelPruneExpiry.Hours()*6) { + + log.Errorf("Skewed blockheight (%v) for edge policy "+ + "of short_chan_id(%v), blockheight too far "+ + "in the future: peer=%v, msg=%s, is_remote=%v", + u.BlockHeight.Val, shortChanID, nMsg.peer, + nMsg.msg.MsgType(), nMsg.isRemote, + ) + + nMsg.err <- fmt.Errorf("skewed blockheight of edge policy, "+ + "timestamp too far in the future: %v", u.BlockHeight) + + return nil, false + } } // Get the node pub key as far since we don't have it in the channel @@ -3108,7 +3134,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // If the edge corresponding to this ChannelUpdate was not // found in the graph, this might be a channel in the process // of being opened, and we haven't processed our own - // ChannelAnnouncement yet, hence it is not not found in the + // ChannelAnnouncement yet, hence it is not found in the // graph. This usually gets resolved after the channel proofs // are exchanged and the channel is broadcasted to the rest of // the network, but in case this is a private channel this @@ -3161,7 +3187,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, nMsg.err <- err key := newRejectCacheKey( - upd.ShortChannelID.ToUint64(), + scid.ToUint64(), sourceToPub(nMsg.source), ) _, _ = d.recentRejects.Put(key, &cachedReject{}) @@ -3175,15 +3201,16 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, var ( pubKey *btcec.PublicKey edgeToUpdate models.ChannelEdgePolicy + direction int ) - direction := upd.ChannelFlags & lnwire.ChanUpdateDirection - switch direction { - case 0: + if upd.IsNode1() { pubKey, _ = chanInfo.NodeKey1() edgeToUpdate = e1 - case 1: + direction = 0 + } else { pubKey, _ = chanInfo.NodeKey2() edgeToUpdate = e2 + direction = 1 } var chanID = chanInfo.GetChanID() @@ -3201,38 +3228,21 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, if err != nil { rErr := fmt.Errorf("unable to validate channel update "+ "announcement for short_chan_id=%v: %v", - spew.Sdump(upd.ShortChannelID), err) + spew.Sdump(scid), err) log.Error(rErr) nMsg.err <- rErr return nil, false } - var edge *models.ChannelEdgePolicy1 - if edgeToUpdate != nil { - var ok bool - edge, ok = edgeToUpdate.(*models.ChannelEdgePolicy1) - if !ok { - rErr := fmt.Errorf("expected "+ - "*models.ChannelEdgePolicy1, got: %T", - edgeToUpdate) - - log.Error(rErr) - nMsg.err <- rErr - - return nil, false - } - } - // If we have a previous version of the edge being updated, we'll want // to rate limit its updates to prevent spam throughout the network. - if nMsg.isRemote && edge != nil { + if nMsg.isRemote && edgeToUpdate != nil { // If it's a keep-alive update, we'll only propagate one if // it's been a day since the previous. This follows our own // heuristic of sending keep-alive updates after the same // duration (see retransmitStaleAnns). - timeSinceLastUpdate := timestamp.Sub(edge.LastUpdate) - isKeepAlive, err := IsKeepAliveUpdate(upd, edge) + isKeepAlive, err := IsKeepAliveUpdate(upd, edgeToUpdate) if err != nil { log.Errorf("Could not determine if update is "+ "keepalive: %v", err) @@ -3242,7 +3252,18 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, } if isKeepAlive { - if timeSinceLastUpdate < d.cfg.RebroadcastInterval { + within, err := d.updateWithinRebroadcastInterval( + upd, edgeToUpdate, + ) + if err != nil { + log.Errorf("Could not determine if update is "+ + "within rebroadcast interval: %v", err) + nMsg.err <- err + + return nil, false + } + + if !within { log.Debugf("Ignoring keep alive update not "+ "within %v period for channel %v", d.cfg.RebroadcastInterval, shortChanID) @@ -3261,7 +3282,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // multiple aliases for a channel and we may otherwise // rate-limit only a single alias of the channel, // instead of the whole channel. - baseScid := chanID + baseScid := chanInfo.GetChanID() d.Lock() rls, ok := d.chanUpdateRateLimiter[baseScid] if !ok { @@ -3292,18 +3313,23 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // different alias. This might mean that SigBytes is incorrect as it // signs a different SCID than the database SCID, but since there will // only be a difference if AuthProof == nil, this is fine. - update := &models.ChannelEdgePolicy1{ - SigBytes: upd.Signature.ToSignatureBytes(), - ChannelID: chanID, - LastUpdate: timestamp, - MessageFlags: upd.MessageFlags, - ChannelFlags: upd.ChannelFlags, - TimeLockDelta: upd.TimeLockDelta, - MinHTLC: upd.HtlcMinimumMsat, - MaxHTLC: upd.HtlcMaximumMsat, - FeeBaseMSat: lnwire.MilliSatoshi(upd.BaseFee), - FeeProportionalMillionths: lnwire.MilliSatoshi(upd.FeeRate), - ExtraOpaqueData: upd.ExtraOpaqueData, + update, err := models.EdgePolicyFromUpdate(upd) + if err != nil { + rErr := fmt.Errorf("unable to convert update to policy for "+ + "short_chan_id=%v: %v", spew.Sdump(scid), err) + + log.Error(rErr) + nMsg.err <- rErr + + return nil, false + } + switch upd := update.(type) { + case *models.ChannelEdgePolicy1: + upd.ChannelID = chanInfo.GetChanID() + case *models.ChannelEdgePolicy2: + upd.ShortChannelID.Val = lnwire.NewShortChanIDFromInt( + chanInfo.GetChanID(), + ) } if err := d.cfg.Graph.UpdateEdge(update, ops...); err != nil { @@ -3319,7 +3345,8 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // Since we know the stored SCID in the graph, we'll // cache that SCID. key := newRejectCacheKey( - chanID, sourceToPub(nMsg.source), + chanInfo.GetChanID(), + sourceToPub(nMsg.source), ) _, _ = d.recentRejects.Put(key, &cachedReject{}) @@ -3328,32 +3355,33 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, } nMsg.err <- err + return nil, false } // If this is a local ChannelUpdate without an AuthProof, it means it // is an update to a channel that is not (yet) supposed to be announced - // to the greater network. However, our channel counter party will need + // to the greater network. However, our channel counterparty will need // to be given the update, so we'll try sending the update directly to // the remote peer. if !nMsg.isRemote && chanInfo.GetAuthProof() == nil { - if nMsg.optionalMsgFields != nil { + if nMsg.optionalMsgFields != nil && + nMsg.optionalMsgFields.remoteAlias != nil { + + // The remoteAlias field was specified, meaning + // that we should replace the SCID in the + // update with the remote's alias. We'll also + // need to re-sign the channel update. This is + // required for option-scid-alias feature-bit + // negotiated channels. remoteAlias := nMsg.optionalMsgFields.remoteAlias - if remoteAlias != nil { - // The remoteAlias field was specified, meaning - // that we should replace the SCID in the - // update with the remote's alias. We'll also - // need to re-sign the channel update. This is - // required for option-scid-alias feature-bit - // negotiated channels. - upd.ShortChannelID = *remoteAlias - - err := d.cfg.SignAliasUpdate(upd) - if err != nil { - log.Error(err) - nMsg.err <- err - return nil, false - } + upd.SetSCID(*remoteAlias) + + err := d.cfg.SignAliasUpdate(upd) + if err != nil { + log.Error(err) + nMsg.err <- err + return nil, false } } @@ -3370,7 +3398,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, if err != nil { err := fmt.Errorf("unable to reliably send %v for "+ "channel=%v to peer=%x: %v", upd.MsgType(), - upd.ShortChannelID, remotePubKey, err) + scid, remotePubKey, err) nMsg.err <- err return nil, false } @@ -3383,7 +3411,7 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, // contains an alias because the network would reject this. var announcements []networkMsg if chanInfo.GetAuthProof() != nil && - !d.cfg.IsAlias(upd.ShortChannelID) { + !d.cfg.IsAlias(scid) { announcements = append(announcements, networkMsg{ peer: nMsg.peer, @@ -3395,9 +3423,9 @@ func (d *AuthenticatedGossiper) handleChanUpdate(nMsg *networkMsg, nMsg.err <- nil - log.Debugf("Processed ChannelUpdate: peer=%v, short_chan_id=%v, "+ - "timestamp=%v", nMsg.peer, upd.ShortChannelID.ToUint64(), - timestamp) + log.Debugf("Processed %s: peer=%v, short_chan_id=%v, ", upd.MsgType(), + nMsg.peer, scid.ToUint64()) + return announcements, true } @@ -3858,6 +3886,39 @@ func (d *AuthenticatedGossiper) ShouldDisconnect(pubkey *btcec.PublicKey) ( return false, nil } +func (d *AuthenticatedGossiper) updateWithinRebroadcastInterval( + upd lnwire.ChannelUpdate, policy models.ChannelEdgePolicy) (bool, + error) { + + switch update := upd.(type) { + case *lnwire.ChannelUpdate1: + pol, ok := policy.(*models.ChannelEdgePolicy1) + if !ok { + return false, fmt.Errorf("expected chan edge policy 1") + } + + timestamp := time.Unix(int64(update.Timestamp), 0) + timeSinceLastUpdate := timestamp.Sub(pol.LastUpdate) + + return timeSinceLastUpdate >= d.cfg.RebroadcastInterval, nil + + case *lnwire.ChannelUpdate2: + pol, ok := policy.(*models.ChannelEdgePolicy2) + if !ok { + return false, fmt.Errorf("expected chan edge policy 2") + } + + blocksSinceLastUpdate := update.BlockHeight.Val - + pol.BlockHeight.Val + + return blocksSinceLastUpdate >= + uint32(d.cfg.RebroadcastInterval.Hours()*6), nil + + default: + return false, fmt.Errorf("unhandled impl of Chan Update") + } +} + func buildChanProof(ann lnwire.ChannelAnnouncement) ( models.ChannelAuthProof, error) { From df145e78ffc36e36ef479ae36fde410aaef1b855 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 23 Aug 2024 14:44:48 +0200 Subject: [PATCH 44/60] docs: add release notes --- docs/release-notes/release-notes-0.19.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/release-notes-0.19.0.md b/docs/release-notes/release-notes-0.19.0.md index 146de82ca9..f1da2228ea 100644 --- a/docs/release-notes/release-notes-0.19.0.md +++ b/docs/release-notes/release-notes-0.19.0.md @@ -74,6 +74,7 @@ * Use the new interfaces added for Gossip 1.75 throughout the codebase [1](https://github.com/lightningnetwork/lnd/pull/8252/). [2](https://github.com/lightningnetwork/lnd/pull/8253). + [3](https://github.com/lightningnetwork/lnd/pull/8254). ## Testing ## Database From f5fb2a40888ab271ae0676bfdb2b95ebc70ff7e9 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 16:18:31 +0200 Subject: [PATCH 45/60] discovery: Filter ChanUpdate2 messages --- discovery/syncer.go | 58 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/discovery/syncer.go b/discovery/syncer.go index e78558ccd0..a3b845c5e0 100644 --- a/discovery/syncer.go +++ b/discovery/syncer.go @@ -15,6 +15,7 @@ import ( "github.com/lightningnetwork/lnd/graph" "github.com/lightningnetwork/lnd/lnpeer" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/tlv" "golang.org/x/time/rate" ) @@ -1427,14 +1428,25 @@ func (g *GossipSyncer) FilterGossipMsgs(msgs ...msgWithSenders) { endTime := startTime.Add( time.Duration(g.remoteUpdateHorizon.TimestampRange) * time.Second, ) + + var ( + startBlock tlv.RecordT[tlv.TlvType2, uint32] + endBlock tlv.RecordT[tlv.TlvType4, uint32] + ) + startBlock = g.remoteUpdateHorizon.FirstBlockHeight.UnwrapOr(startBlock) + endBlock = g.remoteUpdateHorizon.BlockRange.UnwrapOr(endBlock) g.Unlock() - passesFilter := func(timeStamp uint32) bool { + passesTimestampFilter := func(timeStamp uint32) bool { t := time.Unix(int64(timeStamp), 0) return t.Equal(startTime) || (t.After(startTime) && t.Before(endTime)) } + passesBlockHeightFilter := func(height uint32) bool { + return height >= startBlock.Val && height < endBlock.Val + } + msgsToSend := make([]lnwire.Message, 0, len(msgs)) for _, msg := range msgs { // If the target peer is the peer that sent us this message, @@ -1469,18 +1481,29 @@ func (g *GossipSyncer) FilterGossipMsgs(msgs ...msgWithSenders) { } for _, chanUpdate := range chanUpdates { - update, ok := chanUpdate.(*lnwire.ChannelUpdate1) - if !ok { - log.Errorf("expected "+ - "*lnwire.ChannelUpdate1, "+ - "got: %T", update) + switch update := chanUpdate.(type) { + case *lnwire.ChannelUpdate1: + if passesTimestampFilter( + update.Timestamp, + ) { - continue - } + msgsToSend = append( + msgsToSend, msg, + ) - if passesFilter(update.Timestamp) { - msgsToSend = append(msgsToSend, msg) - break + break + } + case *lnwire.ChannelUpdate2: + if passesBlockHeightFilter( + update.BlockHeight.Val, + ) { + + msgsToSend = append( + msgsToSend, msg, + ) + + break + } } } @@ -1488,17 +1511,24 @@ func (g *GossipSyncer) FilterGossipMsgs(msgs ...msgWithSenders) { msgsToSend = append(msgsToSend, msg) } - // For each channel update, we'll only send if it the timestamp + // For each channel update 1, we'll only send if the timestamp // is between our time range. case *lnwire.ChannelUpdate1: - if passesFilter(msg.Timestamp) { + if passesTimestampFilter(msg.Timestamp) { + msgsToSend = append(msgsToSend, msg) + } + + // For each channel update 2, we'll only send if the block + // height is between our block range. + case *lnwire.ChannelUpdate2: + if passesBlockHeightFilter(msg.BlockHeight.Val) { msgsToSend = append(msgsToSend, msg) } // Similarly, we only send node announcements if the update // timestamp ifs between our set gossip filter time range. case *lnwire.NodeAnnouncement: - if passesFilter(msg.Timestamp) { + if passesTimestampFilter(msg.Timestamp) { msgsToSend = append(msgsToSend, msg) } } From 18423e8a8f18b46dc5b310f744483cf80d694135 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 16:21:47 +0200 Subject: [PATCH 46/60] channeldb: Update ChanUpdatesInHorizon So that a start block and end block can also be passed in. --- channeldb/graph.go | 111 +++++++++++++++++++++++++++------------ channeldb/graph_test.go | 5 +- discovery/chan_series.go | 2 +- graph/builder.go | 12 ++++- graph/interfaces.go | 4 +- 5 files changed, 93 insertions(+), 41 deletions(-) diff --git a/channeldb/graph.go b/channeldb/graph.go index cfe5484b1e..c8f5524e68 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -2129,7 +2129,7 @@ type ChannelEdge struct { // ChanUpdatesInHorizon returns all the known channel edges which have at least // one edge that has an update timestamp within the specified horizon. func (c *ChannelGraph) ChanUpdatesInHorizon(startTime, - endTime time.Time) ([]ChannelEdge, error) { + endTime time.Time, startBlock, endBlock uint32) ([]ChannelEdge, error) { // To ensure we don't return duplicate ChannelEdges, we'll use an // additional map to keep track of the edges already seen to prevent @@ -2138,50 +2138,30 @@ func (c *ChannelGraph) ChanUpdatesInHorizon(startTime, var edgesToCache map[uint64]ChannelEdge var edgesInHorizon []ChannelEdge - c.cacheMu.Lock() - defer c.cacheMu.Unlock() - var hits int - err := kvdb.View(c.db, func(tx kvdb.RTx) error { - edges := tx.ReadBucket(edgeBucket) - if edges == nil { - return ErrGraphNoEdgesFound - } - edgeIndex := edges.NestedReadBucket(edgeIndexBucket) - if edgeIndex == nil { - return ErrGraphNoEdgesFound - } - edgeUpdateIndex := edges.NestedReadBucket(edgeUpdateIndexBucket) + fetchUpdates := func(tx kvdb.RTx, edges, edgeIndex, nodes kvdb.RBucket, + updateIndexBkt []byte, startBytes, endBytes []byte, + chanIDFromKey func([]byte) []byte) error { + + edgeUpdateIndex := edges.NestedReadBucket(updateIndexBkt) if edgeUpdateIndex == nil { return ErrGraphNoEdgesFound } - nodes := tx.ReadBucket(nodeBucket) - if nodes == nil { - return ErrGraphNodesNotFound - } - // We'll now obtain a cursor to perform a range query within // the index to find all channels within the horizon. updateCursor := edgeUpdateIndex.ReadCursor() - var startTimeBytes, endTimeBytes [8 + 8]byte - byteOrder.PutUint64( - startTimeBytes[:8], uint64(startTime.Unix()), - ) - byteOrder.PutUint64( - endTimeBytes[:8], uint64(endTime.Unix()), - ) - // With our start and end times constructed, we'll step through // the index collecting the info and policy of each update of // each channel that has a last update within the time range. - for indexKey, _ := updateCursor.Seek(startTimeBytes[:]); indexKey != nil && - bytes.Compare(indexKey, endTimeBytes[:]) <= 0; indexKey, _ = updateCursor.Next() { + //nolint:lll + for indexKey, _ := updateCursor.Seek(startBytes); indexKey != nil && + bytes.Compare(indexKey, endBytes) <= 0; indexKey, _ = updateCursor.Next() { //nolint:whitespace // We have a new eligible entry, so we'll slice of the // chan ID so we can query it in the DB. - chanID := indexKey[8:] + chanID := chanIDFromKey(indexKey) // If we've already retrieved the info and policies for // this edge, then we can skip it as we don't need to do @@ -2218,16 +2198,15 @@ func (c *ChannelGraph) ChanUpdatesInHorizon(startTime, err) } - var ( - node1Bytes = edgeInfo.Node1Bytes() - node2Bytes = edgeInfo.Node2Bytes() - ) + node1Bytes := edgeInfo.Node1Bytes() node1, err := fetchLightningNode(nodes, node1Bytes[:]) if err != nil { return err } + node2Bytes := edgeInfo.Node2Bytes() + node2, err := fetchLightningNode(nodes, node2Bytes[:]) if err != nil { return err @@ -2247,6 +2226,66 @@ func (c *ChannelGraph) ChanUpdatesInHorizon(startTime, edgesToCache[chanIDInt] = channel } + return nil + } + + c.cacheMu.Lock() + defer c.cacheMu.Unlock() + + err := kvdb.View(c.db, func(tx kvdb.RTx) error { + edges := tx.ReadBucket(edgeBucket) + if edges == nil { + return ErrGraphNoEdgesFound + } + edgeIndex := edges.NestedReadBucket(edgeIndexBucket) + if edgeIndex == nil { + return ErrGraphNoEdgesFound + } + + nodes := tx.ReadBucket(nodeBucket) + if nodes == nil { + return ErrGraphNodesNotFound + } + + var startTimeBytes, endTimeBytes [8 + 8]byte + byteOrder.PutUint64( + startTimeBytes[:8], uint64(startTime.Unix()), + ) + byteOrder.PutUint64( + endTimeBytes[:8], uint64(endTime.Unix()), + ) + + var noEdgesFound bool + err := fetchUpdates( + tx, edges, edgeIndex, nodes, edgeUpdateIndexBucket, + startTimeBytes[:], endTimeBytes[:], + func(key []byte) []byte { + return key[8:] + }, + ) + if errors.Is(err, ErrGraphNoEdgesFound) { + noEdgesFound = true + } else if err != nil { + return err + } + + var startBlockBytes, endBlockBytes [4 + 8]byte + byteOrder.PutUint32(startTimeBytes[:4], startBlock) + byteOrder.PutUint32(endTimeBytes[:4], endBlock) + + err = fetchUpdates( + tx, edges, edgeIndex, nodes, edgeUpdate2IndexBucket, + startBlockBytes[:], endBlockBytes[:], + func(key []byte) []byte { + return key[4:] + }, + ) + if errors.Is(err, ErrGraphNoEdgesFound) && noEdgesFound { + return err + } else if err != nil { + return err + } + return nil }, func() { edgesSeen = make(map[uint64]struct{}) @@ -3664,7 +3703,9 @@ func (c *ChannelGraph) FetchOtherNode(tx kvdb.RTx, // otherwise we can use the existing db transaction. var err error if tx == nil { - err = kvdb.View(c.db, fetchNodeFunc, func() { targetNode = nil }) + err = kvdb.View(c.db, fetchNodeFunc, func() { + targetNode = nil + }) } else { err = fetchNodeFunc(tx) } diff --git a/channeldb/graph_test.go b/channeldb/graph_test.go index e5f411c88a..94848449c6 100644 --- a/channeldb/graph_test.go +++ b/channeldb/graph_test.go @@ -1671,7 +1671,7 @@ func TestChanUpdatesInHorizon(t *testing.T) { // If we issue an arbitrary query before any channel updates are // inserted in the database, we should get zero results. chanUpdates, err := graph.ChanUpdatesInHorizon( - time.Unix(999, 0), time.Unix(9999, 0), + time.Unix(999, 0), time.Unix(9999, 0), 0, 0, ) require.NoError(t, err, "unable to updates for updates") if len(chanUpdates) != 0 { @@ -1789,7 +1789,7 @@ func TestChanUpdatesInHorizon(t *testing.T) { } for _, queryCase := range queryCases { resp, err := graph.ChanUpdatesInHorizon( - queryCase.start, queryCase.end, + queryCase.start, queryCase.end, 0, 0, ) if err != nil { t.Fatalf("unable to query for updates: %v", err) @@ -2317,6 +2317,7 @@ func TestStressTestChannelGraphAPI(t *testing.T) { fn: func() error { _, err := graph.ChanUpdatesInHorizon( time.Now().Add(-time.Hour), time.Now(), + 0, 0, ) return err diff --git a/discovery/chan_series.go b/discovery/chan_series.go index 2fbaf6df7b..e89e6c288c 100644 --- a/discovery/chan_series.go +++ b/discovery/chan_series.go @@ -112,7 +112,7 @@ func (c *ChanSeries) UpdatesInHorizon(chain chainhash.Hash, // First, we'll query for all the set of channels that have an update // that falls within the specified horizon. chansInHorizon, err := c.graph.ChanUpdatesInHorizon( - startTime, endTime, + startTime, endTime, 0, 0, ) if err != nil { return nil, err diff --git a/graph/builder.go b/graph/builder.go index db4df5a06c..74cda63acc 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -608,7 +608,17 @@ func (b *Builder) pruneZombieChans() error { startTime := time.Unix(0, 0) endTime := time.Now().Add(-1 * chanExpiry) - oldEdges, err := b.cfg.Graph.ChanUpdatesInHorizon(startTime, endTime) + + startBlock := 0 + _, bestBlock, err := b.cfg.Chain.GetBestBlock() + if err != nil { + return err + } + endBlock := uint32(bestBlock) - uint32(chanExpiry.Hours()*6) + + oldEdges, err := b.cfg.Graph.ChanUpdatesInHorizon( + startTime, endTime, uint32(startBlock), endBlock, + ) if err != nil { return fmt.Errorf("unable to fetch expired channel updates "+ "chans: %v", err) diff --git a/graph/interfaces.go b/graph/interfaces.go index 1eede0a70d..7d6f4e0962 100644 --- a/graph/interfaces.go +++ b/graph/interfaces.go @@ -147,8 +147,8 @@ type DB interface { // ChanUpdatesInHorizon returns all the known channel edges which have // at least one edge that has an update timestamp within the specified // horizon. - ChanUpdatesInHorizon(startTime, endTime time.Time) ( - []channeldb.ChannelEdge, error) + ChanUpdatesInHorizon(startTime, endTime time.Time, startBlock, + endBlock uint32) ([]channeldb.ChannelEdge, error) // DeleteChannelEdges removes edges with the given channel IDs from the // database and marks them as zombies. This ensures that we're unable to From 40fff0457b45b3f0ac08565a413e0b67e6928f44 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 16:29:56 +0200 Subject: [PATCH 47/60] discovery: update UpdatesInHorizon --- discovery/chan_series.go | 10 +++++----- discovery/syncer.go | 9 ++++++++- discovery/syncer_test.go | 15 +++++++++------ 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/discovery/chan_series.go b/discovery/chan_series.go index e89e6c288c..39bec23d3f 100644 --- a/discovery/chan_series.go +++ b/discovery/chan_series.go @@ -29,8 +29,8 @@ type ChannelGraphTimeSeries interface { // update timestamp between the start time and end time. We'll use this // to catch up a remote node to the set of channel updates that they // may have missed out on within the target chain. - UpdatesInHorizon(chain chainhash.Hash, - startTime time.Time, endTime time.Time) ([]lnwire.Message, error) + UpdatesInHorizon(startTime time.Time, endTime time.Time, startBlock, + endBlock uint32) ([]lnwire.Message, error) // FilterKnownChanIDs takes a target chain, and a set of channel ID's, // and returns a filtered set of chan ID's. This filtered set of chan @@ -104,15 +104,15 @@ func (c *ChanSeries) HighestChanID(chain chainhash.Hash) (*lnwire.ShortChannelID // within the target chain. // // NOTE: This is part of the ChannelGraphTimeSeries interface. -func (c *ChanSeries) UpdatesInHorizon(chain chainhash.Hash, - startTime time.Time, endTime time.Time) ([]lnwire.Message, error) { +func (c *ChanSeries) UpdatesInHorizon(startTime, endTime time.Time, startBlock, + endBlock uint32) ([]lnwire.Message, error) { var updates []lnwire.Message // First, we'll query for all the set of channels that have an update // that falls within the specified horizon. chansInHorizon, err := c.graph.ChanUpdatesInHorizon( - startTime, endTime, 0, 0, + startTime, endTime, startBlock, endBlock, ) if err != nil { return nil, err diff --git a/discovery/syncer.go b/discovery/syncer.go index a3b845c5e0..f9590df428 100644 --- a/discovery/syncer.go +++ b/discovery/syncer.go @@ -1313,6 +1313,13 @@ func (g *GossipSyncer) ApplyGossipFilter(filter *lnwire.GossipTimestampRange) er time.Duration(g.remoteUpdateHorizon.TimestampRange) * time.Second, ) + var ( + startBlock = tlv.ZeroRecordT[tlv.TlvType2, uint32]() + endBlock = tlv.ZeroRecordT[tlv.TlvType4, uint32]() + ) + startBlock = g.remoteUpdateHorizon.FirstBlockHeight.UnwrapOr(startBlock) + endBlock = g.remoteUpdateHorizon.BlockRange.UnwrapOr(endBlock) + g.Unlock() // If requested, don't reply with historical gossip data when the remote @@ -1336,7 +1343,7 @@ func (g *GossipSyncer) ApplyGossipFilter(filter *lnwire.GossipTimestampRange) er // Now that the remote peer has applied their filter, we'll query the // database for all the messages that are beyond this filter. newUpdatestoSend, err := g.cfg.channelSeries.UpdatesInHorizon( - g.cfg.chainHash, startTime, endTime, + startTime, endTime, startBlock.Val, endBlock.Val, ) if err != nil { returnSema() diff --git a/discovery/syncer_test.go b/discovery/syncer_test.go index f176580578..1281dfbe82 100644 --- a/discovery/syncer_test.go +++ b/discovery/syncer_test.go @@ -28,10 +28,12 @@ var ( ) type horizonQuery struct { - chain chainhash.Hash - start time.Time - end time.Time + start time.Time + end time.Time + startBlock uint32 + endBlock uint32 } + type filterRangeReq struct { startHeight, endHeight uint32 } @@ -81,11 +83,12 @@ func newMockChannelGraphTimeSeries( func (m *mockChannelGraphTimeSeries) HighestChanID(chain chainhash.Hash) (*lnwire.ShortChannelID, error) { return &m.highestID, nil } -func (m *mockChannelGraphTimeSeries) UpdatesInHorizon(chain chainhash.Hash, - startTime time.Time, endTime time.Time) ([]lnwire.Message, error) { +func (m *mockChannelGraphTimeSeries) UpdatesInHorizon(startTime time.Time, + endTime time.Time, startBlock, endBlock uint32) ([]lnwire.Message, + error) { m.horizonReq <- horizonQuery{ - chain, startTime, endTime, + startTime, endTime, startBlock, endBlock, } return <-m.horizonResp, nil From b1d21fc4f5bce4cc7f645716e898d51e265f6848 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 17:12:31 +0200 Subject: [PATCH 48/60] discovery: start sending block heights in range query --- discovery/syncer.go | 46 +++++++++++++++++++++++++++++++++++++--- discovery/syncer_test.go | 43 +++++++++++++++++++++++++++++++------ 2 files changed, 80 insertions(+), 9 deletions(-) diff --git a/discovery/syncer.go b/discovery/syncer.go index f9590df428..f00e663ec0 100644 --- a/discovery/syncer.go +++ b/discovery/syncer.go @@ -622,8 +622,12 @@ func (g *GossipSyncer) channelGraphSyncer() { if g.localUpdateHorizon == nil && syncType.IsActiveSync() { + startBlock := g.cfg.bestHeight() + blockRange := uint32(math.MaxUint32) + err := g.sendGossipTimestampRange( time.Now(), math.MaxUint32, + &startBlock, &blockRange, ) if err != nil { log.Errorf("Unable to send update "+ @@ -690,12 +694,23 @@ func (g *GossipSyncer) replyHandler() { // sendGossipTimestampRange constructs and sets a GossipTimestampRange for the // syncer and sends it to the remote peer. func (g *GossipSyncer) sendGossipTimestampRange(firstTimestamp time.Time, - timestampRange uint32) error { + timestampRange uint32, firstBlock, blockRange *uint32) error { endTimestamp := firstTimestamp.Add( time.Duration(timestampRange) * time.Second, ) + if firstBlock != nil && blockRange != nil { + log.Infof("GossipSyncer(%x): applying "+ + "gossipFilter(start-time=%v, end-time=%v, "+ + "start-block=%v, block-range=%v)", g.cfg.peerPub[:], + firstTimestamp, endTimestamp, *firstBlock, *blockRange) + } else { + log.Infof("GossipSyncer(%x): applying "+ + "gossipFilter(start-time=%v, end-time=%v", + g.cfg.peerPub[:], firstTimestamp, endTimestamp) + } + log.Infof("GossipSyncer(%x): applying gossipFilter(start=%v, end=%v)", g.cfg.peerPub[:], firstTimestamp, endTimestamp) @@ -705,11 +720,28 @@ func (g *GossipSyncer) sendGossipTimestampRange(firstTimestamp time.Time, TimestampRange: timestampRange, } + if firstBlock != nil { + first := tlv.ZeroRecordT[tlv.TlvType2, uint32]() + first.Val = *firstBlock + + localUpdateHorizon.FirstBlockHeight = tlv.SomeRecordT(first) + } + + if blockRange != nil { + bRange := tlv.ZeroRecordT[tlv.TlvType4, uint32]() + bRange.Val = *blockRange + + localUpdateHorizon.BlockRange = tlv.SomeRecordT(bRange) + } + if err := g.cfg.sendToPeer(localUpdateHorizon); err != nil { return err } - if firstTimestamp == zeroTimestamp && timestampRange == 0 { + noTimeStamps := firstTimestamp == zeroTimestamp && timestampRange == 0 + noBlockHeights := firstBlock == nil && blockRange == nil + + if noTimeStamps && noBlockHeights { g.localUpdateHorizon = nil } else { g.localUpdateHorizon = localUpdateHorizon @@ -1655,6 +1687,8 @@ func (g *GossipSyncer) handleSyncTransition(req *syncTransitionReq) error { var ( firstTimestamp time.Time timestampRange uint32 + firstBlock *uint32 + blockRange *uint32 ) switch req.newSyncType { @@ -1663,6 +1697,10 @@ func (g *GossipSyncer) handleSyncTransition(req *syncTransitionReq) error { case ActiveSync, PinnedSync: firstTimestamp = time.Now() timestampRange = math.MaxUint32 + bestHeight := g.cfg.bestHeight() + firstBlock = &bestHeight + heightRange := uint32(math.MaxUint32) + blockRange = &heightRange // If a PassiveSync transition has been requested, then we should no // longer receive any new updates from the remote peer. We can do this @@ -1677,7 +1715,9 @@ func (g *GossipSyncer) handleSyncTransition(req *syncTransitionReq) error { req.newSyncType) } - err := g.sendGossipTimestampRange(firstTimestamp, timestampRange) + err := g.sendGossipTimestampRange( + firstTimestamp, timestampRange, firstBlock, blockRange, + ) if err != nil { return fmt.Errorf("unable to send local update horizon: %w", err) diff --git a/discovery/syncer_test.go b/discovery/syncer_test.go index 1281dfbe82..8d056aa0f0 100644 --- a/discovery/syncer_test.go +++ b/discovery/syncer_test.go @@ -15,6 +15,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/tlv" "github.com/stretchr/testify/require" ) @@ -2258,12 +2259,26 @@ func TestGossipSyncerSyncTransitions(t *testing.T) { // send out a message that indicates we want // all the updates from here on. firstTimestamp := uint32(time.Now().Unix()) - assertMsgSent( - t, mChan, &lnwire.GossipTimestampRange{ - FirstTimestamp: firstTimestamp, - TimestampRange: math.MaxUint32, - }, - ) + firstBlock := tlv.ZeroRecordT[ + tlv.TlvType2, uint32, + ]() + firstBlock.Val = uint32(latestKnownHeight) + + blockRange := tlv.ZeroRecordT[ + tlv.TlvType4, uint32, + ]() + blockRange.Val = uint32(math.MaxUint32) + + assertMsgSent(t, mChan, &lnwire.GossipTimestampRange{ //nolint:lll + FirstTimestamp: firstTimestamp, + TimestampRange: math.MaxUint32, + FirstBlockHeight: tlv.SomeRecordT( + firstBlock, + ), + BlockRange: tlv.SomeRecordT( + blockRange, + ), + }) // When transitioning from active to passive, we // should expect to see a new local update @@ -2298,10 +2313,26 @@ func TestGossipSyncerSyncTransitions(t *testing.T) { // horizon sent to the remote peer indicating // that it would like to receive any future // updates. + firstBlock := tlv.ZeroRecordT[ + tlv.TlvType2, uint32, + ]() + firstBlock.Val = uint32(latestKnownHeight) + + blockRange := tlv.ZeroRecordT[ + tlv.TlvType4, uint32, + ]() + blockRange.Val = uint32(math.MaxUint32) + firstTimestamp := uint32(time.Now().Unix()) assertMsgSent(t, msgChan, &lnwire.GossipTimestampRange{ FirstTimestamp: firstTimestamp, TimestampRange: math.MaxUint32, + FirstBlockHeight: tlv.SomeRecordT( + firstBlock, + ), + BlockRange: tlv.SomeRecordT( + blockRange, + ), }) syncState := g.syncState() From 97e807eeb1f3e12c786e8df685370b38fb07d968 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 23 Aug 2024 14:49:34 +0200 Subject: [PATCH 49/60] docs: update release notes --- docs/release-notes/release-notes-0.19.0.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/release-notes/release-notes-0.19.0.md b/docs/release-notes/release-notes-0.19.0.md index f1da2228ea..195b0eb3e0 100644 --- a/docs/release-notes/release-notes-0.19.0.md +++ b/docs/release-notes/release-notes-0.19.0.md @@ -76,6 +76,10 @@ [2](https://github.com/lightningnetwork/lnd/pull/8253). [3](https://github.com/lightningnetwork/lnd/pull/8254). +* Update the [gossip + protocol](https://github.com/lightningnetwork/lnd/pull/8255) to be able to + gossip new Gossip 1.75 messages. + ## Testing ## Database From 49519e5e3a2e94fb104b0981192423b3408bb7a6 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 9 Oct 2023 15:08:26 +0200 Subject: [PATCH 50/60] channeldb: Nonce persistance In preparation for the signing flow for the ChannelAnnouncement2 message, we add functionality here to store the bitcoin and node nonces sent to us by our peer. --- channeldb/announcement_nonces.go | 148 ++++++++++++++++++++++++++ channeldb/announcement_nonces_test.go | 109 +++++++++++++++++++ 2 files changed, 257 insertions(+) create mode 100644 channeldb/announcement_nonces.go create mode 100644 channeldb/announcement_nonces_test.go diff --git a/channeldb/announcement_nonces.go b/channeldb/announcement_nonces.go new file mode 100644 index 0000000000..157dc04a0a --- /dev/null +++ b/channeldb/announcement_nonces.go @@ -0,0 +1,148 @@ +package channeldb + +import ( + "fmt" + + "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" + "github.com/lightningnetwork/lnd/kvdb" + "github.com/lightningnetwork/lnd/lnwire" +) + +var ( + // announcementNoncesBucket is a top level bucket with the following + // structure: channel_id => node_nonce || bitcoin_nonce + announcementNoncesBucket = []byte("announcement-nonces") +) + +// AnnouncementNonces holds the nonces used during the creating of a +// ChannelAnnouncement2. +type AnnouncementNonces struct { + Btc [musig2.PubNonceSize]byte + Node [musig2.PubNonceSize]byte +} + +// SaveAnnouncementNonces persist the given announcement nonces. +func (c *ChannelStateDB) SaveAnnouncementNonces(chanID lnwire.ChannelID, + nonces *AnnouncementNonces) error { + + chanIDCopy := make([]byte, 32) + copy(chanIDCopy, chanID[:]) + + scratch := make([]byte, musig2.PubNonceSize*2) + copy(scratch[:musig2.PubNonceSize], nonces.Node[:]) + copy(scratch[musig2.PubNonceSize:], nonces.Btc[:]) + + return kvdb.Update(c.backend, func(tx kvdb.RwTx) error { + bucket, err := tx.CreateTopLevelBucket( + announcementNoncesBucket, + ) + if err != nil { + return err + } + + return bucket.Put(chanIDCopy, scratch) + }, func() {}) +} + +// GetAllAnnouncementNonces returns all the announcement nonce pairs currently +// stored in the DB. +func (c *ChannelStateDB) GetAllAnnouncementNonces() ( + map[lnwire.ChannelID]AnnouncementNonces, error) { + + m := make(map[lnwire.ChannelID]AnnouncementNonces) + err := kvdb.View(c.backend, func(tx kvdb.RTx) error { + bucket := tx.ReadBucket(announcementNoncesBucket) + if bucket == nil { + return nil + } + + return bucket.ForEach(func(k, v []byte) error { + if len(k) != 32 { + return fmt.Errorf("invalid chan ID key") + } + if len(v) != musig2.PubNonceSize*2 { + return fmt.Errorf("wrong number of bytes") + } + + var chanID lnwire.ChannelID + copy(chanID[:], k) + + var btc, node [musig2.PubNonceSize]byte + + copy(node[:], v[:musig2.PubNonceSize]) + copy(btc[:], v[musig2.PubNonceSize:]) + + m[chanID] = AnnouncementNonces{ + Btc: btc, + Node: node, + } + + return nil + }) + }, func() { + m = make(map[lnwire.ChannelID]AnnouncementNonces) + }) + if err != nil { + return nil, err + } + + return m, nil +} + +// GetAnnouncementNonces fetches the announcement nonces for the given channel +// ID. +func (c *ChannelStateDB) GetAnnouncementNonces(chanID lnwire.ChannelID) ( + *AnnouncementNonces, error) { + + chanIDCopy := make([]byte, 32) + copy(chanIDCopy, chanID[:]) + + var nonces AnnouncementNonces + err := kvdb.View(c.backend, func(tx kvdb.RTx) error { + bucket := tx.ReadBucket(announcementNoncesBucket) + if bucket == nil { + return ErrChannelNotFound + } + + noncesBytes := bucket.Get(chanIDCopy) + if noncesBytes == nil { + return ErrChannelNotFound + } + + if len(noncesBytes) != musig2.PubNonceSize*2 { + return fmt.Errorf("wrong number of bytes") + } + + copy(nonces.Node[:], noncesBytes[:musig2.PubNonceSize]) + copy(nonces.Btc[:], noncesBytes[musig2.PubNonceSize:]) + + return nil + }, func() { + nonces = AnnouncementNonces{} + }) + if err != nil { + return nil, err + } + + return &nonces, nil +} + +// DeleteAnnouncementNonces deletes the announcement nonce pair stored under +// the given channel ID key if an entry exists. +func (c *ChannelStateDB) DeleteAnnouncementNonces( + chanID lnwire.ChannelID) error { + + chanIDCopy := make([]byte, 32) + copy(chanIDCopy, chanID[:]) + + return kvdb.Update(c.backend, func(tx kvdb.RwTx) error { + bucket := tx.ReadWriteBucket( + announcementNoncesBucket, + ) + if bucket == nil { + return nil + } + + return bucket.Delete(chanIDCopy) + }, func() {}) +} diff --git a/channeldb/announcement_nonces_test.go b/channeldb/announcement_nonces_test.go new file mode 100644 index 0000000000..d85d76982e --- /dev/null +++ b/channeldb/announcement_nonces_test.go @@ -0,0 +1,109 @@ +package channeldb + +import ( + "math/rand" + "testing" + + "github.com/lightningnetwork/lnd/lnwire" + "github.com/stretchr/testify/require" +) + +// TestAnnouncementNonces tests the various announcement nonce pair CRUD +// operations. +func TestAnnouncementNonces(t *testing.T) { + cdb, err := MakeTestDB(t) + require.NoError(t, err) + + db := cdb.ChannelStateDB() + + // Show that the set of nonces is currently empty. + nonceSet, err := db.GetAllAnnouncementNonces() + require.NoError(t, err) + require.Empty(t, nonceSet) + + // Generate a random channel ID. + chanID1 := randChannelID(t) + + // Assert that there is no entry for this channel yet. + _, err = db.GetAnnouncementNonces(chanID1) + require.ErrorIs(t, err, ErrChannelNotFound) + + // Insert an entry. + nonces1 := AnnouncementNonces{ + Btc: randNonce(t), + Node: randNonce(t), + } + + err = db.SaveAnnouncementNonces(chanID1, &nonces1) + require.NoError(t, err) + + // Assert that the entry is now returned. + n, err := db.GetAnnouncementNonces(chanID1) + require.NoError(t, err) + require.Equal(t, &nonces1, n) + + nonceSet, err = db.GetAllAnnouncementNonces() + require.NoError(t, err) + require.EqualValues(t, map[lnwire.ChannelID]AnnouncementNonces{ + chanID1: nonces1, + }, nonceSet) + + // Add another entry. + chanID2 := randChannelID(t) + nonces2 := AnnouncementNonces{ + Btc: randNonce(t), + Node: randNonce(t), + } + + err = db.SaveAnnouncementNonces(chanID2, &nonces2) + require.NoError(t, err) + + n, err = db.GetAnnouncementNonces(chanID2) + require.NoError(t, err) + require.Equal(t, &nonces2, n) + + nonceSet, err = db.GetAllAnnouncementNonces() + require.NoError(t, err) + require.EqualValues(t, map[lnwire.ChannelID]AnnouncementNonces{ + chanID1: nonces1, + chanID2: nonces2, + }, nonceSet) + + // Now, assert that deletion works. + err = db.DeleteAnnouncementNonces(chanID1) + require.NoError(t, err) + + _, err = db.GetAnnouncementNonces(chanID1) + require.ErrorIs(t, err, ErrChannelNotFound) + + nonceSet, err = db.GetAllAnnouncementNonces() + require.NoError(t, err) + require.EqualValues(t, map[lnwire.ChannelID]AnnouncementNonces{ + chanID2: nonces2, + }, nonceSet) + + err = db.DeleteAnnouncementNonces(chanID2) + require.NoError(t, err) + + nonceSet, err = db.GetAllAnnouncementNonces() + require.NoError(t, err) + require.Empty(t, nonceSet) +} + +func randChannelID(t *testing.T) lnwire.ChannelID { + var chanID lnwire.ChannelID + + _, err := rand.Read(chanID[:]) + require.NoError(t, err) + + return chanID +} + +func randNonce(t *testing.T) [66]byte { + var b [66]byte + + _, err := rand.Read(b[:]) + require.NoError(t, err) + + return b +} From c4a77a1e11edc59b723404704acb610e851894d2 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 10 Oct 2023 15:26:15 +0200 Subject: [PATCH 51/60] funding: add channel_ready nonce exchange --- channeldb/announcement_nonces.go | 13 ++ funding/manager.go | 142 +++++++++++++++++++- funding/nonces.go | 214 +++++++++++++++++++++++++++++++ 3 files changed, 364 insertions(+), 5 deletions(-) create mode 100644 funding/nonces.go diff --git a/channeldb/announcement_nonces.go b/channeldb/announcement_nonces.go index 157dc04a0a..7e6bdb2dc5 100644 --- a/channeldb/announcement_nonces.go +++ b/channeldb/announcement_nonces.go @@ -14,6 +14,19 @@ var ( announcementNoncesBucket = []byte("announcement-nonces") ) +type AnnouncementNonceStore interface { + SaveAnnouncementNonces(chanID lnwire.ChannelID, + nonces *AnnouncementNonces) error + + GetAllAnnouncementNonces() (map[lnwire.ChannelID]AnnouncementNonces, + error) + + DeleteAnnouncementNonces(chanID lnwire.ChannelID) error + + GetAnnouncementNonces(chanID lnwire.ChannelID) (*AnnouncementNonces, + error) +} + // AnnouncementNonces holds the nonces used during the creating of a // ChannelAnnouncement2. type AnnouncementNonces struct { diff --git a/funding/manager.go b/funding/manager.go index 40f18121bc..394ae4dc36 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -36,6 +36,7 @@ import ( "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chanfunding" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/tlv" "golang.org/x/crypto/salsa20" ) @@ -603,6 +604,8 @@ type Manager struct { // TODO(roasbeef): replace w/ generic concurrent map pendingMusigNonces map[lnwire.ChannelID]*musig2.Nonces + nonceMgr *nonceManager + // activeReservations is a map which houses the state of all pending // funding workflows. activeReservations map[serializedPubKey]pendingChannels @@ -697,7 +700,8 @@ func NewFundingManager(cfg Config) (*Manager, error) { pendingMusigNonces: make( map[lnwire.ChannelID]*musig2.Nonces, ), - quit: make(chan struct{}), + nonceMgr: newNonceManager(cfg.ChannelDB, cfg.IDKey), + quit: make(chan struct{}), }, nil } @@ -713,6 +717,10 @@ func (f *Manager) Start() error { } func (f *Manager) start() error { + if err := f.nonceMgr.start(); err != nil { + return err + } + // Upon restart, the Funding Manager will check the database to load any // channels that were waiting for their funding transactions to be // confirmed on the blockchain at the time when the daemon last went @@ -1243,6 +1251,12 @@ func (f *Manager) stateStep(channel *channeldb.OpenChannel, "announcement: %v", err) } + err = f.nonceMgr.completed(chanID) + if err != nil { + log.Errorf("could not delete announcement sigs for "+ + "chanID: %x", chanID) + } + // We delete the channel opening state from our internal // database as the opening process has succeeded. We can do // this because we assume the AuthenticatedGossiper queues the @@ -3331,11 +3345,12 @@ func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel, } channelReadyMsg := lnwire.NewChannelReady(chanID, nextRevocation) + public := completeChan.ChannelFlags&lnwire.FFAnnounceChannel != 0 + // If this is a taproot channel, then we also need to send along our // set of musig2 nonces as well. if completeChan.ChanType.IsTaproot() { - log.Infof("ChanID(%v): generating musig2 nonces...", - chanID) + log.Infof("ChanID(%v): generating musig2 nonces...", chanID) f.nonceMtx.Lock() localNonce, ok := f.pendingMusigNonces[chanID] @@ -3361,6 +3376,32 @@ func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel, channelReadyMsg.NextLocalNonce = lnwire.SomeMusig2Nonce( localNonce.PubNonce, ) + + if public { + btcNonce, nodeNonce, err := f.nonceMgr.getNoncesToSend( + chanID, completeChan.RevocationProducer, + completeChan.LocalChanCfg.MultiSigKey.PubKey, + ) + if err != nil { + return err + } + + annNodeNonce := tlv.ZeroRecordT[ + tlv.TlvType0, lnwire.Musig2Nonce, + ]() + annNodeNonce.Val = nodeNonce.PubNonce + channelReadyMsg.AnnouncementNodeNonce = tlv.SomeRecordT( + annNodeNonce, + ) + + annBtcNonce := tlv.ZeroRecordT[ + tlv.TlvType2, lnwire.Musig2Nonce, + ]() + annBtcNonce.Val = btcNonce.PubNonce + channelReadyMsg.AnnouncementBitcoinNonce = tlv.SomeRecordT( //nolint:lll + annBtcNonce, + ) + } } // If the channel negotiated the option-scid-alias feature bit, we'll @@ -3492,6 +3533,14 @@ func (f *Manager) receivedChannelReady(node *btcec.PublicKey, return false, nil } + isPublic := channel.ChannelFlags&lnwire.FFAnnounceChannel != 0 + if channel.ChanType.IsTaproot() && isPublic { + _, _, haveNonces := f.nonceMgr.getReceivedNonces(chanID) + if !haveNonces { + return false, nil + } + } + // Finally, the barrier signal is removed once we finish // `handleChannelReady`. If we can still find the signal, we haven't // finished processing it yet. @@ -3746,6 +3795,7 @@ func (f *Manager) annAfterSixConfs(completeChan *channeldb.OpenChannel, &completeChan.LocalChanCfg.MultiSigKey, completeChan.RemoteChanCfg.MultiSigKey.PubKey, *shortChanID, chanID, completeChan.ChanType, + completeChan, ) if err != nil { return fmt.Errorf("channel announcement failed: %w", @@ -3953,15 +4003,33 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, //nolint:funlen return } + public := channel.ChannelFlags&lnwire.FFAnnounceChannel != 0 + // If this is a taproot channel, then we can generate the set of nonces // the remote party needs to send the next remote commitment here. - var firstVerNonce *musig2.Nonces + var ( + firstVerNonce *musig2.Nonces + btcNonce *musig2.Nonces + nodeNonce *musig2.Nonces + ) if channel.ChanType.IsTaproot() { firstVerNonce, err = genFirstStateMusigNonce(channel) if err != nil { log.Error(err) return } + + if public { + btcNonce, nodeNonce, err = f.nonceMgr.getNoncesToSend( + chanID, channel.RevocationProducer, + channel.LocalChanCfg.MultiSigKey.PubKey, + ) + if err != nil { + log.Error(err) + + return + } + } } // We'll need to store the received TLV alias if the option_scid_alias @@ -4033,6 +4101,24 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, //nolint:funlen ) } + if public && btcNonce != nil && nodeNonce != nil { + annNodeNonce := tlv.ZeroRecordT[ + tlv.TlvType0, lnwire.Musig2Nonce, + ]() + annNodeNonce.Val = nodeNonce.PubNonce + channelReadyMsg.AnnouncementNodeNonce = tlv.SomeRecordT( //nolint:lll + annNodeNonce, + ) + + annBtcNonce := tlv.ZeroRecordT[ + tlv.TlvType2, lnwire.Musig2Nonce, + ]() + annBtcNonce.Val = btcNonce.PubNonce + channelReadyMsg.AnnouncementBitcoinNonce = tlv.SomeRecordT( //nolint:lll + annBtcNonce, + ) + } + err = peer.SendMessage(true, channelReadyMsg) if err != nil { log.Errorf("unable to send channel_ready: %v", @@ -4093,6 +4179,48 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, //nolint:funlen }), ) + if public { + if msg.AnnouncementBitcoinNonce.IsNone() || + msg.AnnouncementNodeNonce.IsNone() { + + log.Errorf("remote announcement nonces are nil") + + return + } + + var ( + btcNonce lnwire.Musig2Nonce + nodeNonce lnwire.Musig2Nonce + ) + + msg.AnnouncementNodeNonce.WhenSome( + func(nonce tlv.RecordT[tlv.TlvType0, + lnwire.Musig2Nonce]) { + + nodeNonce = nonce.Val + }, + ) + + msg.AnnouncementBitcoinNonce.WhenSome( + func(nonce tlv.RecordT[tlv.TlvType2, + lnwire.Musig2Nonce]) { + + btcNonce = nonce.Val + }, + ) + + err = f.nonceMgr.receivedNonces( + chanID, nodeNonce, btcNonce, + channel.RevocationProducer, + channel.LocalChanCfg.MultiSigKey.PubKey, + ) + if err != nil { + log.Errorf("%v", err) + + return + } + } + // Inform the aux funding controller that the liquidity in the // custom channel is now ready to be advertised. We potentially // haven't sent our own channel ready message yet, but other @@ -4187,6 +4315,9 @@ func (f *Manager) handleChannelReadyReceived(channel *channeldb.OpenChannel, // channel is moved to the next state of the state machine. It will be // moved to the last state (actually deleted from the database) after // the channel is finally announced. + // TODO: need to either persist peer's announcement nonces (for tap + // chans) here, or we need to require that chan_ready be resent on + // restart. Persistence might be easier/simpler. err = f.saveChannelOpeningState( &channel.FundingOutpoint, addedToGraph, scid, ) @@ -4525,7 +4656,8 @@ func (f *Manager) newChanAnnouncement(localPubKey, func (f *Manager) announceChannel(localIDKey, remoteIDKey *btcec.PublicKey, localFundingKey *keychain.KeyDescriptor, remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID, - chanID lnwire.ChannelID, chanType channeldb.ChannelType) error { + chanID lnwire.ChannelID, chanType channeldb.ChannelType, + channel *channeldb.OpenChannel) error { // First, we'll create the batch of announcements to be sent upon // initial channel creation. This includes the channel announcement diff --git a/funding/nonces.go b/funding/nonces.go new file mode 100644 index 0000000000..9eed44b280 --- /dev/null +++ b/funding/nonces.go @@ -0,0 +1,214 @@ +package funding + +import ( + "fmt" + "sync" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" + "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/shachain" +) + +type annSigNonces struct { + sent *sentNonces + received *receivedNonces +} + +type sentNonces struct { + btc *musig2.Nonces + node *musig2.Nonces +} + +type receivedNonces struct { + btc [musig2.PubNonceSize]byte + node [musig2.PubNonceSize]byte +} + +type nonceManager struct { + started sync.Once + + idKey *btcec.PublicKey + + store channeldb.AnnouncementNonceStore + + annSigNonces map[lnwire.ChannelID]annSigNonces + + mu sync.Mutex +} + +func newNonceManager(store channeldb.AnnouncementNonceStore, + idKey *btcec.PublicKey) *nonceManager { + + return &nonceManager{ + idKey: idKey, + store: store, + annSigNonces: make(map[lnwire.ChannelID]annSigNonces), + } +} + +func (m *nonceManager) start() error { + var returnErr error + m.started.Do(func() { + nonces, err := m.store.GetAllAnnouncementNonces() + if err != nil { + returnErr = err + + return + } + + for chanID, n := range nonces { + m.annSigNonces[chanID] = annSigNonces{ + received: &receivedNonces{ + btc: n.Btc, + node: n.Node, + }, + } + } + }) + + return returnErr +} + +func (m *nonceManager) completed(chanID lnwire.ChannelID) error { + m.mu.Lock() + defer m.mu.Unlock() + + delete(m.annSigNonces, chanID) + + return m.store.DeleteAnnouncementNonces(chanID) +} + +func (m *nonceManager) getReceivedNonces(chanID lnwire.ChannelID) ( + [musig2.PubNonceSize]byte, [musig2.PubNonceSize]byte, bool) { + + m.mu.Lock() + defer m.mu.Unlock() + + aggNonces, ok := m.annSigNonces[chanID] + if !ok || aggNonces.received == nil { + return [musig2.PubNonceSize]byte{}, [musig2.PubNonceSize]byte{}, + false + } + + return aggNonces.received.btc, aggNonces.received.node, true +} + +func (m *nonceManager) receivedNonces(chanID lnwire.ChannelID, node, + btc [musig2.PubNonceSize]byte, revProducer shachain.Producer, + multiSigBTCKey *btcec.PublicKey) error { + + m.mu.Lock() + defer m.mu.Unlock() + + sendNonces, err := m.getNoncesToSendUnsafe( + chanID, revProducer, multiSigBTCKey, + ) + if err != nil { + return err + } + + announcementSendNonces, ok := m.annSigNonces[chanID] + if !ok { + m.annSigNonces[chanID] = annSigNonces{ + sent: sendNonces, + } + announcementSendNonces = m.annSigNonces[chanID] + } + + announcementSendNonces.received = &receivedNonces{ + btc: btc, + node: node, + } + + m.annSigNonces[chanID] = announcementSendNonces + + return m.store.SaveAnnouncementNonces( + chanID, &channeldb.AnnouncementNonces{ + Node: node, + Btc: btc, + }, + ) +} + +func (m *nonceManager) getNoncesToSend(chanID lnwire.ChannelID, + revProducer shachain.Producer, multiSigBTCKey *btcec.PublicKey) ( + *musig2.Nonces, *musig2.Nonces, error) { + + m.mu.Lock() + defer m.mu.Unlock() + + nonces, err := m.getNoncesToSendUnsafe( + chanID, revProducer, multiSigBTCKey, + ) + if err != nil { + return nil, nil, err + } + + return nonces.btc, nonces.node, nil +} + +func (m *nonceManager) getNoncesToSendUnsafe(chanID lnwire.ChannelID, + revProducer shachain.Producer, multiSigBTCKey *btcec.PublicKey) ( + *sentNonces, error) { + + announceNonces, ok := m.annSigNonces[chanID] + if ok && announceNonces.sent != nil { + return announceNonces.sent, nil + } + + sent, err := m.genAnnouncementNonces(revProducer, multiSigBTCKey) + if err != nil { + return nil, err + } + + if !ok { + m.annSigNonces[chanID] = annSigNonces{sent: sent} + } else { + announceNonces.sent = sent + } + + announceNonces = m.annSigNonces[chanID] + + return sent, nil +} + +func (m *nonceManager) genAnnouncementNonces(revProducer shachain.Producer, + multiSigBTCKey *btcec.PublicKey) (*sentNonces, error) { + + musig2ShaChain, err := channeldb.DeriveMusig2Shachain( + revProducer, + ) + if err != nil { + return nil, fmt.Errorf("unable to generate musig "+ + "announcement nonces: %v", err) + } + + // TODO: replace with unique derivation. + btcNonce, err := channeldb.NewMusigVerificationNonce( + multiSigBTCKey, + 0, + musig2ShaChain, + ) + if err != nil { + return nil, fmt.Errorf("unable to generate musig "+ + "announcement nonces: %v", err) + } + + // TODO: replace with unique derivation. + nodeNonce, err := channeldb.NewMusigVerificationNonce( + m.idKey, + 1, + musig2ShaChain, + ) + if err != nil { + return nil, fmt.Errorf("unable to generate musig "+ + "announcement nonces: %v", err) + } + + return &sentNonces{ + btc: btcNonce, + node: nodeNonce, + }, nil +} From 770a64390f275d13345cbde9acea06cbf20ff2bc Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Thu, 16 Nov 2023 14:51:20 +0200 Subject: [PATCH 52/60] funding: prep with signers needed for g175 messages --- funding/manager.go | 25 +++++------ funding/manager_test.go | 98 +++++++++++++++++++++++++++++------------ server.go | 9 ++-- 3 files changed, 86 insertions(+), 46 deletions(-) diff --git a/funding/manager.go b/funding/manager.go index 394ae4dc36..194437e101 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -11,7 +11,6 @@ import ( "github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/btcec/v2" - "github.com/btcsuite/btcd/btcec/v2/ecdsa" "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -386,15 +385,11 @@ type Config struct { // ChannelDB is the database that keeps track of all channel state. ChannelDB *channeldb.ChannelStateDB - // SignMessage signs an arbitrary message with a given public key. The - // actual digest signed is the double sha-256 of the message. In the - // case that the private key corresponding to the passed public key - // cannot be located, then an error is returned. - // - // TODO(roasbeef): should instead pass on this responsibility to a - // distinct sub-system? - SignMessage func(keyLoc keychain.KeyLocator, - msg []byte, doubleHash bool) (*ecdsa.Signature, error) + // MessageSigner can be used to sign various wire messages. + MessageSigner keychain.MessageSignerRing + + // MuSig2Signer is a musig2 capable signer. + MuSig2Signer input.MuSig2Signer // CurrentNodeAnnouncement should return the latest, fully signed node // announcement from the backing Lightning Network node with a fresh @@ -4588,7 +4583,9 @@ func (f *Manager) newChanAnnouncement(localPubKey, if err != nil { return nil, err } - sig, err := f.cfg.SignMessage(f.cfg.IDKeyLoc, chanUpdateMsg, true) + sig, err := f.cfg.MessageSigner.SignMessage( + f.cfg.IDKeyLoc, chanUpdateMsg, true, + ) if err != nil { return nil, errors.Errorf("unable to generate channel "+ "update announcement signature: %v", err) @@ -4610,12 +4607,14 @@ func (f *Manager) newChanAnnouncement(localPubKey, if err != nil { return nil, err } - nodeSig, err := f.cfg.SignMessage(f.cfg.IDKeyLoc, chanAnnMsg, true) + nodeSig, err := f.cfg.MessageSigner.SignMessage( + f.cfg.IDKeyLoc, chanAnnMsg, true, + ) if err != nil { return nil, errors.Errorf("unable to generate node "+ "signature for channel announcement: %v", err) } - bitcoinSig, err := f.cfg.SignMessage( + bitcoinSig, err := f.cfg.MessageSigner.SignMessage( localFundingKey.KeyLocator, chanAnnMsg, true, ) if err != nil { diff --git a/funding/manager_test.go b/funding/manager_test.go index 57a3ffad19..cccc0f39ad 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -16,6 +16,7 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2/ecdsa" + "github.com/btcsuite/btcd/btcec/v2/schnorr" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -106,13 +107,21 @@ var ( Address: bobTCPAddr, } - testRBytes, _ = hex.DecodeString("8ce2bc69281ce27da07e6683571319d18e949ddfa2965fb6caa1bf0314f882d7") - testSBytes, _ = hex.DecodeString("299105481d63e0f4bc2a88121167221b6700d72a0ead154c03be696a292d24ae") - testRScalar = new(btcec.ModNScalar) - testSScalar = new(btcec.ModNScalar) - _ = testRScalar.SetByteSlice(testRBytes) - _ = testSScalar.SetByteSlice(testSBytes) - testSig = ecdsa.NewSignature(testRScalar, testSScalar) + testRBytes, _ = hex.DecodeString( + "8ce2bc69281ce27da07e6683571319d18e" + + "949ddfa2965fb6caa1bf0314f882d7", + ) + testSBytes, _ = hex.DecodeString( + "299105481d63e0f4bc2a88121167221b6" + + "700d72a0ead154c03be696a292d24ae", + ) + testRScalar = new(btcec.ModNScalar) + testSScalar = new(btcec.ModNScalar) + _ = testRScalar.SetByteSlice(testRBytes) + _ = testSScalar.SetByteSlice(testSBytes) + testSig = ecdsa.NewSignature(testRScalar, testSScalar) + zeroVal btcec.FieldVal + testSchnorrSig = schnorr.NewSignature(&zeroVal, testSScalar) testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey} @@ -448,18 +457,25 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey, chainedAcceptor := acpt.NewChainedAcceptor() + keyFetcher := func(desc *keychain.KeyDescriptor) (*btcec.PrivateKey, + error) { + + if desc.KeyLocator == testKeyLoc { + return privKey, nil + } + + return keyRing.DerivePrivKey(*desc) + } + fundingCfg := Config{ - IDKey: privKey.PubKey(), - IDKeyLoc: testKeyLoc, - Wallet: lnw, - Notifier: chainNotifier, - ChannelDB: cdb, - FeeEstimator: estimator, - SignMessage: func(_ keychain.KeyLocator, - _ []byte, _ bool) (*ecdsa.Signature, error) { - - return testSig, nil - }, + IDKey: privKey.PubKey(), + IDKeyLoc: testKeyLoc, + Wallet: lnw, + Notifier: chainNotifier, + ChannelDB: cdb, + FeeEstimator: estimator, + MessageSigner: &mockSigner{}, + MuSig2Signer: input.NewMusigSessionManager(keyFetcher), SendAnnouncement: func(msg lnwire.Message, _ ...discovery.OptionalMsgField) chan error { @@ -622,18 +638,25 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) { chainedAcceptor := acpt.NewChainedAcceptor() + keyFetcher := func(desc *keychain.KeyDescriptor) (*btcec.PrivateKey, + error) { + + if desc.KeyLocator == oldCfg.IDKeyLoc { + return alice.privKey, nil + } + + return alice.fundingMgr.cfg.Wallet.DerivePrivKey(*desc) + } + f, err := NewFundingManager(Config{ - IDKey: oldCfg.IDKey, - IDKeyLoc: oldCfg.IDKeyLoc, - Wallet: oldCfg.Wallet, - Notifier: oldCfg.Notifier, - ChannelDB: oldCfg.ChannelDB, - FeeEstimator: oldCfg.FeeEstimator, - SignMessage: func(_ keychain.KeyLocator, - _ []byte, _ bool) (*ecdsa.Signature, error) { - - return testSig, nil - }, + IDKey: oldCfg.IDKey, + IDKeyLoc: oldCfg.IDKeyLoc, + Wallet: oldCfg.Wallet, + Notifier: oldCfg.Notifier, + ChannelDB: oldCfg.ChannelDB, + FeeEstimator: oldCfg.FeeEstimator, + MessageSigner: &mockSigner{}, + MuSig2Signer: input.NewMusigSessionManager(keyFetcher), SendAnnouncement: func(msg lnwire.Message, _ ...discovery.OptionalMsgField) chan error { @@ -4975,3 +4998,20 @@ func TestFundingManagerCoinbase(t *testing.T) { // channel. assertHandleChannelReady(t, alice, bob) } + +type mockSigner struct { + keychain.MessageSignerRing +} + +func (s *mockSigner) SignMessage(_ keychain.KeyLocator, _ []byte, + _ bool) (*ecdsa.Signature, error) { + + return testSig, nil +} + +func (m *mockSigner) SignMessageSchnorr(keyLoc keychain.KeyLocator, msg []byte, + doubleHash bool, taprootTweak, tag []byte) (*schnorr.Signature, + error) { + + return testSchnorrSig, nil +} diff --git a/server.go b/server.go index 4b3b6cba3b..e06ad9d016 100644 --- a/server.go +++ b/server.go @@ -1420,10 +1420,11 @@ func newServer(cfg *Config, listenAddrs []net.Addr, UpdateLabel: func(hash chainhash.Hash, label string) error { return cc.Wallet.LabelTransaction(hash, label, true) }, - Notifier: cc.ChainNotifier, - ChannelDB: s.chanStateDB, - FeeEstimator: cc.FeeEstimator, - SignMessage: cc.MsgSigner.SignMessage, + Notifier: cc.ChainNotifier, + ChannelDB: s.chanStateDB, + FeeEstimator: cc.FeeEstimator, + MessageSigner: cc.KeyRing, + MuSig2Signer: cc.Signer, CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement, error) { From cd8eec509a921ff01b641718b5bce2887b07afba Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 7 Nov 2023 17:23:29 +0200 Subject: [PATCH 53/60] funding: start creating channel_announcement_2 --- channeldb/models/channel_edge_info.go | 60 +----- funding/manager.go | 290 ++++++++++++++++++++++++-- funding/manager_test.go | 10 + server.go | 1 + 4 files changed, 288 insertions(+), 73 deletions(-) diff --git a/channeldb/models/channel_edge_info.go b/channeldb/models/channel_edge_info.go index 82f722a292..a3e8f28c02 100644 --- a/channeldb/models/channel_edge_info.go +++ b/channeldb/models/channel_edge_info.go @@ -298,64 +298,14 @@ func (c *ChannelEdgeInfo1) GetChanPoint() wire.OutPoint { // // NOTE: this is part of the ChannelEdgeInfo interface. func (c *ChannelEdgeInfo1) FundingScript() ([]byte, error) { - legacyFundingScript := func() ([]byte, error) { - witnessScript, err := input.GenMultiSigScript( - c.BitcoinKey1Bytes[:], c.BitcoinKey2Bytes[:], - ) - if err != nil { - return nil, err - } - pkScript, err := input.WitnessScriptHash(witnessScript) - if err != nil { - return nil, err - } - - return pkScript, nil - } - - if len(c.Features) == 0 { - return legacyFundingScript() - } - - // TODO(elle): remove this taproot funding script logic once - // ChannelEdgeInfo2 is being used. - - // In order to make the correct funding script, we'll need to parse the - // chanFeatures bytes into a feature vector we can interact with. - rawFeatures := lnwire.NewRawFeatureVector() - err := rawFeatures.Decode(bytes.NewReader(c.Features)) - if err != nil { - return nil, fmt.Errorf("unable to parse chan feature "+ - "bits: %w", err) - } - - chanFeatureBits := lnwire.NewFeatureVector( - rawFeatures, lnwire.Features, + witnessScript, err := input.GenMultiSigScript( + c.BitcoinKey1Bytes[:], c.BitcoinKey2Bytes[:], ) - if chanFeatureBits.HasFeature( - lnwire.SimpleTaprootChannelsOptionalStaging, - ) { - - pubKey1, err := btcec.ParsePubKey(c.BitcoinKey1Bytes[:]) - if err != nil { - return nil, err - } - pubKey2, err := btcec.ParsePubKey(c.BitcoinKey2Bytes[:]) - if err != nil { - return nil, err - } - - fundingScript, _, err := input.GenTaprootFundingScript( - pubKey1, pubKey2, 0, c.TapscriptRoot, - ) - if err != nil { - return nil, err - } - - return fundingScript, nil + if err != nil { + return nil, err } - return legacyFundingScript() + return input.WitnessScriptHash(witnessScript) } // A compile-time check to ensure that ChannelEdgeInfo1 implements the diff --git a/funding/manager.go b/funding/manager.go index 194437e101..f770581c6f 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -35,6 +35,7 @@ import ( "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chanfunding" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/netann" "github.com/lightningnetwork/lnd/tlv" "golang.org/x/crypto/salsa20" ) @@ -558,6 +559,9 @@ type Config struct { // AuxResolver is an optional interface that can be used to modify the // way contracts are resolved. AuxResolver fn.Option[lnwallet.AuxContractResolver] + + // BestBlockView gives access to the current best block. + BestBlockView chainntnfs.BestBlockView } // Manager acts as an orchestrator/bridge between the wallet's @@ -3596,7 +3600,7 @@ func (f *Manager) addToGraph(completeChan *channeldb.OpenChannel, &completeChan.LocalChanCfg.MultiSigKey, completeChan.RemoteChanCfg.MultiSigKey.PubKey, *shortChanID, chanID, fwdMinHTLC, fwdMaxHTLC, ourPolicy, - completeChan.ChanType, + completeChan.ChanType, completeChan, false, ) if err != nil { return fmt.Errorf("error generating channel "+ @@ -4420,6 +4424,8 @@ type chanAnnouncement struct { chanAnn lnwire.ChannelAnnouncement chanUpdateAnn lnwire.ChannelUpdate chanProof lnwire.AnnounceSignatures + + opts []discovery.OptionalMsgField } // newChanAnnouncement creates the authenticated channel announcement messages @@ -4435,7 +4441,16 @@ func (f *Manager) newChanAnnouncement(localPubKey, remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID, chanID lnwire.ChannelID, fwdMinHTLC, fwdMaxHTLC lnwire.MilliSatoshi, ourEdgePolicy models.ChannelEdgePolicy, - chanType channeldb.ChannelType) (*chanAnnouncement, error) { + chanType channeldb.ChannelType, channel *channeldb.OpenChannel, + withProof bool) (*chanAnnouncement, error) { + + if chanType.IsTaproot() { + return f.newTaprootChanAnnouncement( + localPubKey, remotePubKey, localFundingKey, + remoteFundingKey, shortChanID, chanID, fwdMinHTLC, + fwdMaxHTLC, ourEdgePolicy, channel, withProof, + ) + } var ourPolicy *models.ChannelEdgePolicy1 if ourEdgePolicy != nil { @@ -4458,20 +4473,6 @@ func (f *Manager) newChanAnnouncement(localPubKey, ChainHash: chainHash, } - // If this is a taproot channel, then we'll set a special bit in the - // feature vector to indicate to the routing layer that this needs a - // slightly different type of validation. - // - // TODO(roasbeef): temp, remove after gossip 1.5 - if chanType.IsTaproot() { - log.Debugf("Applying taproot feature bit to "+ - "ChannelAnnouncement for %v", chanID) - - chanAnn.Features.Set( - lnwire.SimpleTaprootChannelsRequiredStaging, - ) - } - // The chanFlags field indicates which directed edge of the channel is // being updated within the ChannelUpdateAnnouncement announcement // below. A value of zero means it's the edge of the "first" node and 1 @@ -4645,6 +4646,259 @@ func (f *Manager) newChanAnnouncement(localPubKey, }, nil } +func (f *Manager) newTaprootChanAnnouncement(localPubKey, + remotePubKey *btcec.PublicKey, localFundingKey *keychain.KeyDescriptor, + remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID, + chanID lnwire.ChannelID, fwdMinHTLC, fwdMaxHTLC lnwire.MilliSatoshi, + ourEdgePolicy models.ChannelEdgePolicy, channel *channeldb.OpenChannel, + withProof bool) (*chanAnnouncement, error) { + + var ourPolicy *models.ChannelEdgePolicy2 + if ourEdgePolicy != nil { + var ok bool + ourPolicy, ok = ourEdgePolicy.(*models.ChannelEdgePolicy2) + if !ok { + return nil, fmt.Errorf("expected "+ + "ChannelEdgePolicy2, got: %T", ourEdgePolicy) + } + } + + chainHash := *f.cfg.Wallet.Cfg.NetParams.GenesisHash + + var chanAnn lnwire.ChannelAnnouncement2 + chanAnn.ShortChannelID.Val = shortChanID + chanAnn.Features.Val = *lnwire.NewRawFeatureVector() + chanAnn.ChainHash.Val = chainHash + chanAnn.Capacity.Val = uint64(channel.Capacity) + + channel.TapscriptRoot.WhenSome(func(root chainhash.Hash) { + r := tlv.NewPrimitiveRecord[tlv.TlvType16, [32]byte](root) + chanAnn.MerkleRootHash = tlv.SomeRecordT(r) + }) + + var direction int + + // The lexicographical ordering of the two identity public keys of the + // nodes indicates which of the nodes is "first". If our serialized + // identity key is lower than theirs then we're the "first" node and + // second otherwise. + selfBytes := localPubKey.SerializeCompressed() + remoteBytes := remotePubKey.SerializeCompressed() + if bytes.Compare(selfBytes, remoteBytes) == -1 { + copy(chanAnn.NodeID1.Val[:], localPubKey.SerializeCompressed()) + copy(chanAnn.NodeID2.Val[:], remotePubKey.SerializeCompressed()) + + btc1 := tlv.ZeroRecordT[tlv.TlvType12, [33]byte]() + copy(btc1.Val[:], localFundingKey.PubKey.SerializeCompressed()) + chanAnn.BitcoinKey1 = tlv.SomeRecordT(btc1) + + btc2 := tlv.ZeroRecordT[tlv.TlvType14, [33]byte]() + copy(btc2.Val[:], remoteFundingKey.SerializeCompressed()) + chanAnn.BitcoinKey2 = tlv.SomeRecordT(btc2) + + // If we're the first node then update the chanFlags to + // indicate the "direction" of the update. + direction = 0 + } else { + copy(chanAnn.NodeID1.Val[:], remotePubKey.SerializeCompressed()) + copy(chanAnn.NodeID2.Val[:], localPubKey.SerializeCompressed()) + + btc1 := tlv.ZeroRecordT[tlv.TlvType12, [33]byte]() + copy(btc1.Val[:], remoteFundingKey.SerializeCompressed()) + chanAnn.BitcoinKey1 = tlv.SomeRecordT(btc1) + + btc2 := tlv.ZeroRecordT[tlv.TlvType14, [33]byte]() + copy(btc2.Val[:], localFundingKey.PubKey.SerializeCompressed()) + chanAnn.BitcoinKey2 = tlv.SomeRecordT(btc2) + + // If we're the second node then update the chanFlags to + // indicate the "direction" of the update. + direction = 1 + } + + // We cannot glean the block timestamp from the short channel ID since + // that may be a zero conf alias at this point. + currentHeight, err := f.cfg.BestBlockView.BestHeight() + if err != nil { + return nil, err + } + + // We announce the channel with the default values. Some of + // these values can later be changed by crafting a new ChannelUpdate. + var chanUpdateAnn lnwire.ChannelUpdate2 + chanUpdateAnn.ChainHash.Val = chainHash + chanUpdateAnn.ShortChannelID.Val = shortChanID + chanUpdateAnn.BlockHeight.Val = currentHeight + chanUpdateAnn.CLTVExpiryDelta.Val = uint16( + f.cfg.DefaultRoutingPolicy.TimeLockDelta, + ) + chanUpdateAnn.HTLCMinimumMsat.Val = fwdMinHTLC + chanUpdateAnn.HTLCMaximumMsat.Val = fwdMaxHTLC + + if direction == 1 { + chanUpdateAnn.SecondPeer = tlv.SomeRecordT( + tlv.ZeroRecordT[tlv.TlvType8, lnwire.TrueBoolean](), + ) + } + + // The caller of newChanAnnouncement is expected to provide the initial + // forwarding policy to be announced. If no persisted initial policy + // values are found, then we will use the default policy values in the + // channel announcement. + storedFwdingPolicy, err := f.getInitialForwardingPolicy(chanID) + if err != nil && !errors.Is(err, channeldb.ErrChannelNotFound) { + return nil, errors.Errorf("unable to generate channel "+ + "update announcement: %v", err) + } + + switch { + case ourPolicy != nil: + // If ourPolicy is non-nil, modify the default parameters of the + // ChannelUpdate. + chanUpdateAnn.SecondPeer = ourPolicy.SecondPeer + chanUpdateAnn.CLTVExpiryDelta = ourPolicy.CLTVExpiryDelta + chanUpdateAnn.HTLCMinimumMsat = ourPolicy.HTLCMinimumMsat + chanUpdateAnn.HTLCMaximumMsat = ourPolicy.HTLCMaximumMsat + chanUpdateAnn.FeeBaseMsat = ourPolicy.FeeBaseMsat + chanUpdateAnn.FeeProportionalMillionths = + ourPolicy.FeeProportionalMillionths + + case storedFwdingPolicy != nil: + chanUpdateAnn.FeeBaseMsat.Val = uint32( + storedFwdingPolicy.BaseFee, + ) + chanUpdateAnn.FeeProportionalMillionths.Val = uint32( + storedFwdingPolicy.FeeRate, + ) + + default: + log.Infof("No channel forwarding policy specified for channel "+ + "announcement of ChannelID(%v). "+ + "Assuming default fee parameters.", chanID) + chanUpdateAnn.FeeBaseMsat.Val = uint32( + f.cfg.DefaultRoutingPolicy.BaseFee, + ) + chanUpdateAnn.FeeProportionalMillionths.Val = uint32( + f.cfg.DefaultRoutingPolicy.FeeRate, + ) + } + + // With the channel update announcement constructed, we'll generate a + // signature that signs a double-sha digest of the announcement. + // This'll serve to authenticate this announcement and any other future + // updates we may send. + chanUpdateMsg, err := chanUpdateAnn.DataToSign() + if err != nil { + return nil, err + } + sig, err := f.cfg.MessageSigner.SignMessageSchnorr( + f.cfg.IDKeyLoc, chanUpdateMsg, false, nil, + netann.ChanUpdate2DigestTag(), + ) + if err != nil { + return nil, errors.Errorf("unable to generate channel "+ + "update announcement signature: %v", err) + } + chanUpdateAnn.Signature, err = lnwire.NewSigFromSignature(sig) + if err != nil { + return nil, errors.Errorf("unable to generate channel "+ + "update announcement signature: %v", err) + } + + if !withProof { + return &chanAnnouncement{ + chanAnn: &chanAnn, + chanUpdateAnn: &chanUpdateAnn, + }, nil + } + + chanAnnMsg, err := netann.ChanAnn2DigestToSign(&chanAnn) + if err != nil { + return nil, err + } + + pubKeys := []*btcec.PublicKey{ + localPubKey, + remotePubKey, + localFundingKey.PubKey, + remoteFundingKey, + } + + rBtc, rNode, haveReceivedNonces := f.nonceMgr.getReceivedNonces(chanID) + if err != nil { + return nil, err + } + + if !haveReceivedNonces { + return nil, fmt.Errorf("havent received all the necessary " + + "nonces yet") + } + + sBtc, sNode, err := f.nonceMgr.getNoncesToSend( + chanID, channel.RevocationProducer, + channel.LocalChanCfg.MultiSigKey.PubKey, + ) + if err != nil { + return nil, err + } + + musigBtcSess, err := f.cfg.MuSig2Signer.MuSig2CreateSession( + input.MuSig2Version100RC2, localFundingKey.KeyLocator, + pubKeys, &input.MuSig2Tweaks{}, + [][66]byte{sNode.PubNonce, rBtc, rNode}, sBtc, + ) + if err != nil { + return nil, err + } + + bitcoinPartialSig, err := f.cfg.MuSig2Signer.MuSig2Sign( + musigBtcSess.SessionID, *chanAnnMsg, true, + ) + if err != nil { + return nil, err + } + + musigNodeSess, err := f.cfg.MuSig2Signer.MuSig2CreateSession( + input.MuSig2Version100RC2, f.cfg.IDKeyLoc, pubKeys, + &input.MuSig2Tweaks{}, + [][66]byte{sBtc.PubNonce, rBtc, rNode}, sNode, + ) + if err != nil { + return nil, err + } + + nodePartialSig, err := f.cfg.MuSig2Signer.MuSig2Sign( + musigNodeSess.SessionID, *chanAnnMsg, true, + ) + if err != nil { + return nil, errors.Errorf("unable to generate node "+ + "partial signature for channel announcement: %v", err) + } + + // Combine the two partial signatures. + ps := musig2.NewPartialSignature( + bitcoinPartialSig.S.Add(nodePartialSig.S), bitcoinPartialSig.R, + ) + + // Finally, we'll generate the announcement proof which we'll use to + // provide the other side with the necessary signatures required to + // allow them to reconstruct the full channel announcement. + proof := &lnwire.AnnounceSignatures2{ + ChannelID: chanID, + ShortChannelID: shortChanID, + PartialSignature: lnwire.NewPartialSig(*ps.S), + } + + return &chanAnnouncement{ + chanAnn: &chanAnn, + chanUpdateAnn: &chanUpdateAnn, + chanProof: proof, + opts: []discovery.OptionalMsgField{ + discovery.AggregateNonce(ps.R), + }, + }, nil +} + // announceChannel announces a newly created channel to the rest of the network // by crafting the two authenticated announcements required for the peers on // the network to recognize the legitimacy of the channel. The crafted @@ -4667,7 +4921,7 @@ func (f *Manager) announceChannel(localIDKey, remoteIDKey *btcec.PublicKey, // only use the channel announcement message from the returned struct. ann, err := f.newChanAnnouncement( localIDKey, remoteIDKey, localFundingKey, remoteFundingKey, - shortChanID, chanID, 0, 0, nil, chanType, + shortChanID, chanID, 0, 0, nil, chanType, channel, true, ) if err != nil { log.Errorf("can't generate channel announcement: %v", err) @@ -4678,7 +4932,7 @@ func (f *Manager) announceChannel(localIDKey, remoteIDKey *btcec.PublicKey, // because addToGraph previously sent the ChannelAnnouncement and // the ChannelUpdate announcement messages. The channel proof and node // announcements are broadcast to the greater network. - errChan := f.cfg.SendAnnouncement(ann.chanProof) + errChan := f.cfg.SendAnnouncement(ann.chanProof, ann.opts...) select { case err := <-errChan: if err != nil { diff --git a/funding/manager_test.go b/funding/manager_test.go index cccc0f39ad..fad5c18e0b 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -586,6 +586,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey, AuxSigner: fn.Some[lnwallet.AuxSigner]( &lnwallet.MockAuxSigner{}, ), + BestBlockView: &mockBlockView{}, } for _, op := range options { @@ -704,6 +705,7 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) { AliasManager: oldCfg.AliasManager, AuxLeafStore: oldCfg.AuxLeafStore, AuxSigner: oldCfg.AuxSigner, + BestBlockView: &mockBlockView{}, }) require.NoError(t, err, "failed recreating aliceFundingManager") @@ -5015,3 +5017,11 @@ func (m *mockSigner) SignMessageSchnorr(keyLoc keychain.KeyLocator, msg []byte, return testSchnorrSig, nil } + +type mockBlockView struct { + chainntnfs.BestBlockView +} + +func (m *mockBlockView) BestHeight() (uint32, error) { + return 0, nil +} diff --git a/server.go b/server.go index e06ad9d016..6c127c31e2 100644 --- a/server.go +++ b/server.go @@ -1586,6 +1586,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, AuxFundingController: implCfg.AuxFundingController, AuxSigner: implCfg.AuxSigner, AuxResolver: implCfg.AuxContractResolver, + BestBlockView: s.cc.BestBlockTracker, }) if err != nil { return nil, err From 0f0483d437de8b290eb7659623addbb1033f71c8 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 10 Oct 2023 15:46:24 +0200 Subject: [PATCH 54/60] feature+lnwire: add taproot gossip feature bit --- feature/default_sets.go | 4 ++++ lnwire/features.go | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/feature/default_sets.go b/feature/default_sets.go index 4a9b2bf64d..ad1de70e29 100644 --- a/feature/default_sets.go +++ b/feature/default_sets.go @@ -96,4 +96,8 @@ var defaultSetDesc = setDesc{ SetInit: {}, // I SetNodeAnn: {}, // N }, + lnwire.TaprootGossipOptionalStaging: { + SetInit: {}, // I + SetNodeAnn: {}, // N + }, } diff --git a/lnwire/features.go b/lnwire/features.go index c597b03988..50c4f3e178 100644 --- a/lnwire/features.go +++ b/lnwire/features.go @@ -273,7 +273,7 @@ const ( // a BOLT 11 invoice. Bolt11BlindedPathsOptional = 263 - // SimpleTaprootOverlayChansRequired is a required bit that indicates + // SimpleTaprootOverlayChansOptional is a optional bit that indicates // support for the special custom taproot overlay channel. SimpleTaprootOverlayChansOptional = 2025 @@ -281,6 +281,12 @@ const ( // support for the special custom taproot overlay channel. SimpleTaprootOverlayChansRequired = 2026 + TaprootGossipRequiredFinal = 32 + TaprootGossipOptionalFinal = 33 + + TaprootGossipRequiredStaging = 132 + TaprootGossipOptionalStaging = 133 + // MaxBolt11Feature is the maximum feature bit value allowed in bolt 11 // invoices. // @@ -351,6 +357,10 @@ var Features = map[FeatureBit]string{ SimpleTaprootOverlayChansRequired: "taproot-overlay-chans", Bolt11BlindedPathsOptional: "bolt-11-blinded-paths", Bolt11BlindedPathsRequired: "bolt-11-blinded-paths", + TaprootGossipRequiredFinal: "taproot-gossip", + TaprootGossipOptionalFinal: "taproot-gossip", + TaprootGossipRequiredStaging: "taproot-gossip-x", + TaprootGossipOptionalStaging: "taproot-gossip-x", } // RawFeatureVector represents a set of feature bits as defined in BOLT-09. A From 6e5d114c14b17d3ff356e5f1ed99c09971cbda58 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 10 Oct 2023 15:47:39 +0200 Subject: [PATCH 55/60] funding: allow public taproot channels --- funding/manager.go | 31 ++++++++++-------- funding/manager_test.go | 72 ++++++----------------------------------- 2 files changed, 26 insertions(+), 77 deletions(-) diff --git a/funding/manager.go b/funding/manager.go index f770581c6f..f53d2fd93b 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -1635,26 +1635,13 @@ func (f *Manager) fundeeProcessOpenChannel(peer lnpeer.Peer, } public := msg.ChannelFlags&lnwire.FFAnnounceChannel != 0 - switch { - // Sending the option-scid-alias channel type for a public channel is - // disallowed. - case public && scid: + if public && scid { err = fmt.Errorf("option-scid-alias chantype for public " + "channel") log.Errorf("Cancelling funding flow for public channel %v "+ "with scid-alias: %v", cid, err) f.failFundingFlow(peer, cid, err) - return - - // The current variant of taproot channels can only be used with - // unadvertised channels for now. - case commitType.IsTaproot() && public: - err = fmt.Errorf("taproot channel type for public channel") - log.Errorf("Cancelling funding flow for public taproot "+ - "channel %v: %v", cid, err) - f.failFundingFlow(peer, cid, err) - return } @@ -5125,6 +5112,22 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) { return } + // Announced taproot channels are only allowed if our peer also supports + // taproot gossip. + if !msg.Private && commitType.IsTaproot() { + if !msg.Peer.RemoteFeatures().HasFeature( + lnwire.TaprootGossipOptionalStaging, + ) { + + err := fmt.Errorf("peer does not support taproot " + + "gossip") + log.Errorf("%v", err) + msg.Err <- err + + return + } + } + var ( zeroConf bool scid bool diff --git a/funding/manager_test.go b/funding/manager_test.go index fad5c18e0b..f46af367af 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -37,7 +37,6 @@ import ( "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lntest/mock" "github.com/lightningnetwork/lnd/lntest/wait" - "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chanfunding" @@ -834,12 +833,6 @@ func fundChannel(t *testing.T, alice, bob *testNode, localFundingAmt, Err: errChan, } - // If this is a taproot channel, then we want to force it to be a - // private channel, as that's the only channel type supported for now. - if isTaprootChanType(chanType) { - initReq.Private = true - } - alice.fundingMgr.InitFundingWorkflow(initReq) // Alice should have sent the OpenChannel message to Bob. @@ -1328,7 +1321,7 @@ func assertAnnouncementSignatures(t *testing.T, alice, bob *testNode) { gotNodeAnnouncement := false for _, msg := range announcements { switch msg.(type) { - case *lnwire.AnnounceSignatures1: + case lnwire.AnnounceSignatures: gotAnnounceSignatures = true case *lnwire.NodeAnnouncement: gotNodeAnnouncement = true @@ -1345,25 +1338,6 @@ func assertAnnouncementSignatures(t *testing.T, alice, bob *testNode) { } } -func assertType[T any](t *testing.T, typ any) T { - value, ok := typ.(T) - require.True(t, ok) - - return value -} - -func assertNodeAnnSent(t *testing.T, alice, bob *testNode) { - t.Helper() - - for _, node := range []*testNode{alice, bob} { - nodeAnn, err := lnutils.RecvOrTimeout( - node.msgChan, time.Second*5, - ) - require.NoError(t, err) - assertType[*lnwire.NodeAnnouncement](t, *nodeAnn) - } -} - func waitForOpenUpdate(t *testing.T, updateChan chan *lnrpc.OpenStatusUpdate) { var openUpdate *lnrpc.OpenStatusUpdate select { @@ -1482,11 +1456,11 @@ func testNormalWorkflow(t *testing.T, chanType *lnwire.ChannelType) { // test. featureBits := []lnwire.FeatureBit{ lnwire.ZeroConfOptional, - lnwire.ScidAliasOptional, lnwire.ExplicitChannelTypeOptional, lnwire.StaticRemoteKeyOptional, lnwire.AnchorsZeroFeeHtlcTxOptional, lnwire.SimpleTaprootChannelsOptionalStaging, + lnwire.TaprootGossipOptionalStaging, } alice.localFeatures = featureBits alice.remoteFeatures = featureBits @@ -1576,20 +1550,7 @@ func testNormalWorkflow(t *testing.T, chanType *lnwire.ChannelType) { Tx: fundingTx, } - switch { - // For taproot channels, we expect them to only send a node - // announcement message at this point. These channels aren't advertised - // so we don't expect the other messages. - case isTaprootChanType(chanType): - assertNodeAnnSent(t, alice, bob) - - // For regular channels, we'll make sure the fundingManagers exchange - // announcement signatures. - case chanType == nil: - fallthrough - default: - assertAnnouncementSignatures(t, alice, bob) - } + assertAnnouncementSignatures(t, alice, bob) // The internal state-machine should now have deleted the channelStates // from the database, as the channel is announced. @@ -4525,6 +4486,7 @@ func testZeroConf(t *testing.T, chanType *lnwire.ChannelType) { lnwire.StaticRemoteKeyOptional, lnwire.AnchorsZeroFeeHtlcTxOptional, lnwire.SimpleTaprootChannelsOptionalStaging, + lnwire.TaprootGossipOptionalStaging, } alice.localFeatures = featureBits alice.remoteFeatures = featureBits @@ -4622,12 +4584,9 @@ func testZeroConf(t *testing.T, chanType *lnwire.ChannelType) { Tx: fundingTx, } - // For taproot channels, we don't expect them to be announced atm. - if !isTaprootChanType(chanType) { - assertChannelAnnouncements( - t, alice, bob, fundingAmt, nil, nil, nil, nil, - ) - } + assertChannelAnnouncements( + t, alice, bob, fundingAmt, nil, nil, nil, nil, + ) // Both Alice and Bob should send on reportScidChan. select { @@ -4651,20 +4610,7 @@ func testZeroConf(t *testing.T, chanType *lnwire.ChannelType) { Tx: fundingTx, } - switch { - // For taproot channels, we expect them to only send a node - // announcement message at this point. These channels aren't advertised - // so we don't expect the other messages. - case isTaprootChanType(chanType): - assertNodeAnnSent(t, alice, bob) - - // For regular channels, we'll make sure the fundingManagers exchange - // announcement signatures. - case chanType == nil: - fallthrough - default: - assertAnnouncementSignatures(t, alice, bob) - } + assertAnnouncementSignatures(t, alice, bob) // Assert that the channel state is deleted from the fundingmanager's // datastore. @@ -5005,7 +4951,7 @@ type mockSigner struct { keychain.MessageSignerRing } -func (s *mockSigner) SignMessage(_ keychain.KeyLocator, _ []byte, +func (m *mockSigner) SignMessage(_ keychain.KeyLocator, _ []byte, _ bool) (*ecdsa.Signature, error) { return testSig, nil From d7d85e565f4c157dd707a6adb7b14977e3afe8fa Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 10 Oct 2023 15:49:42 +0200 Subject: [PATCH 56/60] server+rpcserver: allow public tap chans --- rpcserver.go | 7 ------- server.go | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/rpcserver.go b/rpcserver.go index b75d39840f..21d8521dac 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -2284,13 +2284,6 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest, *channelType = lnwire.ChannelType(*fv) case lnrpc.CommitmentType_SIMPLE_TAPROOT: - // If the taproot channel type is being set, then the channel - // MUST be private (unadvertised) for now. - if !in.Private { - return nil, fmt.Errorf("taproot channels must be " + - "private") - } - channelType = new(lnwire.ChannelType) fv := lnwire.NewRawFeatureVector( lnwire.SimpleTaprootChannelsRequiredStaging, diff --git a/server.go b/server.go index 6c127c31e2..ef09280dc7 100644 --- a/server.go +++ b/server.go @@ -4800,6 +4800,28 @@ func (s *server) OpenChannel( req.Peer = peer s.mu.RUnlock() + // If the desired channel is for an advertised taproot channel, then + // it the peer must support taproot gossip. + if req.ChannelType != nil { + rfv := lnwire.RawFeatureVector(*req.ChannelType) + fv := lnwire.NewFeatureVector(&rfv, lnwire.Features) + + if fv.HasFeature(lnwire.SimpleTaprootChannelsOptionalStaging) && + !req.Private { + + if !peer.RemoteFeatures().HasFeature( + lnwire.TaprootGossipOptionalStaging, + ) { + + req.Err <- fmt.Errorf("peer %x does not "+ + "support announced taproot channels", + pubKeyBytes) + + return req.Updates, req.Err + } + } + } + // We'll wait until the peer is active before beginning the channel // opening process. select { From 8eaa970917f5e3247f03200f0af56f9a312ed5a8 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 10 Oct 2023 16:03:22 +0200 Subject: [PATCH 57/60] itest: allow public taproot chan tests --- itest/lnd_channel_backup_test.go | 15 --- itest/lnd_channel_force_close_test.go | 10 -- itest/lnd_funding_test.go | 13 +-- itest/lnd_multi-hop_test.go | 156 +------------------------- itest/lnd_payment_test.go | 5 - itest/lnd_psbt_test.go | 12 +- itest/lnd_revocation_test.go | 6 - 7 files changed, 7 insertions(+), 210 deletions(-) diff --git a/itest/lnd_channel_backup_test.go b/itest/lnd_channel_backup_test.go index 474cd663a0..a9d695dfdf 100644 --- a/itest/lnd_channel_backup_test.go +++ b/itest/lnd_channel_backup_test.go @@ -106,13 +106,6 @@ func newChanRestoreScenario(ht *lntest.HarnessTest, ct lnrpc.CommitmentType, // with a portion pushed. ht.ConnectNodes(dave, carol) - // If the commitment type is taproot, then the channel must also be - // private. - var privateChan bool - if ct == lnrpc.CommitmentType_SIMPLE_TAPROOT { - privateChan = true - } - return &chanRestoreScenario{ carol: carol, dave: dave, @@ -123,7 +116,6 @@ func newChanRestoreScenario(ht *lntest.HarnessTest, ct lnrpc.CommitmentType, PushAmt: pushAmt, ZeroConf: zeroConf, CommitmentType: ct, - Private: privateChan, }, } } @@ -648,13 +640,6 @@ func runChanRestoreScenarioCommitTypes(ht *lntest.HarnessTest, multi, err := os.ReadFile(backupFilePath) require.NoError(ht, err) - // If this was a zero conf taproot channel, then since it's private, - // we'll need to mine an extra block (framework won't mine extra blocks - // otherwise). - if ct == lnrpc.CommitmentType_SIMPLE_TAPROOT && zeroConf { - ht.MineBlocksAndAssertNumTxes(1, 1) - } - // Now that we have Dave's backup file, we'll create a new nodeRestorer // that we'll restore using the on-disk channels.backup. restoredNodeFunc := chanRestoreViaRPC( diff --git a/itest/lnd_channel_force_close_test.go b/itest/lnd_channel_force_close_test.go index 34df5ab591..fb30bf8cde 100644 --- a/itest/lnd_channel_force_close_test.go +++ b/itest/lnd_channel_force_close_test.go @@ -119,18 +119,8 @@ func channelForceClosureTest(ht *lntest.HarnessTest, carolBalResp := carol.RPC.WalletBalance() carolStartingBalance := carolBalResp.ConfirmedBalance - // If the channel is a taproot channel, then we'll need to create a - // private channel. - // - // TODO(roasbeef): lift after G175 - var privateChan bool - if channelType == lnrpc.CommitmentType_SIMPLE_TAPROOT { - privateChan = true - } - chanPoint := ht.OpenChannel( alice, carol, lntest.OpenChannelParams{ - Private: privateChan, Amt: chanAmt, PushAmt: pushAmt, CommitmentType: channelType, diff --git a/itest/lnd_funding_test.go b/itest/lnd_funding_test.go index a1c2e292d3..eaca155217 100644 --- a/itest/lnd_funding_test.go +++ b/itest/lnd_funding_test.go @@ -61,16 +61,6 @@ func testBasicChannelFunding(ht *lntest.HarnessTest) { // connected to the funding flow can properly be executed. ht.EnsureConnected(carol, dave) - var privateChan bool - - // If this is to be a taproot channel type, then it needs to be - // private, otherwise it'll be rejected by Dave. - // - // TODO(roasbeef): lift after gossip 1.75 - if carolCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT { - privateChan = true - } - // If carol wants taproot, but dave wants something // else, then we'll assert that the channel negotiation // attempt fails. @@ -82,7 +72,6 @@ func testBasicChannelFunding(ht *lntest.HarnessTest) { amt := funding.MaxBtcFundingAmount ht.OpenChannelAssertErr( carol, dave, lntest.OpenChannelParams{ - Private: privateChan, Amt: amt, CommitmentType: carolCommitType, }, expectedErr, @@ -92,7 +81,7 @@ func testBasicChannelFunding(ht *lntest.HarnessTest) { } carolChan, daveChan, closeChan := basicChannelFundingTest( - ht, carol, dave, nil, privateChan, &carolCommitType, + ht, carol, dave, nil, false, &carolCommitType, ) // Both nodes should report the same commitment diff --git a/itest/lnd_multi-hop_test.go b/itest/lnd_multi-hop_test.go index c28910f580..b495374741 100644 --- a/itest/lnd_multi-hop_test.go +++ b/itest/lnd_multi-hop_test.go @@ -8,7 +8,6 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" - "github.com/lightningnetwork/lnd/chainreg" "github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" @@ -58,59 +57,6 @@ var commitWithZeroConf = []struct { }, } -// makeRouteHints creates a route hints that will allow Carol to be reached -// using an unadvertised channel created by Bob (Bob -> Carol). If the zeroConf -// bool is set, then the scid alias of Bob will be used in place. -func makeRouteHints(bob, carol *node.HarnessNode, - zeroConf bool) []*lnrpc.RouteHint { - - carolChans := carol.RPC.ListChannels( - &lnrpc.ListChannelsRequest{}, - ) - - carolChan := carolChans.Channels[0] - - hopHint := &lnrpc.HopHint{ - NodeId: carolChan.RemotePubkey, - ChanId: carolChan.ChanId, - FeeBaseMsat: uint32( - chainreg.DefaultBitcoinBaseFeeMSat, - ), - FeeProportionalMillionths: uint32( - chainreg.DefaultBitcoinFeeRate, - ), - CltvExpiryDelta: chainreg.DefaultBitcoinTimeLockDelta, - } - - if zeroConf { - bobChans := bob.RPC.ListChannels( - &lnrpc.ListChannelsRequest{}, - ) - - // Now that we have Bob's channels, scan for the channel he has - // open to Carol so we can use the proper scid. - var found bool - for _, bobChan := range bobChans.Channels { - if bobChan.RemotePubkey == carol.PubKeyStr { - hopHint.ChanId = bobChan.AliasScids[0] - - found = true - - break - } - } - if !found { - bob.Fatalf("unable to create route hint") - } - } - - return []*lnrpc.RouteHint{ - { - HopHints: []*lnrpc.HopHint{hopHint}, - }, - } -} - // caseRunner defines a single test case runner. type caseRunner func(ht *lntest.HarnessTest, alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) @@ -199,13 +145,6 @@ func runMultiHopHtlcLocalTimeout(ht *lntest.HarnessTest, dustPayHash := ht.Random32Bytes() payHash := ht.Random32Bytes() - // If this is a taproot channel, then we'll need to make some manual - // route hints so Alice can actually find a route. - var routeHints []*lnrpc.RouteHint - if c == lnrpc.CommitmentType_SIMPLE_TAPROOT { - routeHints = makeRouteHints(bob, carol, zeroConf) - } - alice.RPC.SendPayment(&routerrpc.SendPaymentRequest{ Dest: carolPubKey, Amt: int64(dustHtlcAmt), @@ -213,7 +152,6 @@ func runMultiHopHtlcLocalTimeout(ht *lntest.HarnessTest, FinalCltvDelta: finalCltvDelta, TimeoutSeconds: 60, FeeLimitMsat: noFeeLimitMsat, - RouteHints: routeHints, }) alice.RPC.SendPayment(&routerrpc.SendPaymentRequest{ @@ -223,7 +161,6 @@ func runMultiHopHtlcLocalTimeout(ht *lntest.HarnessTest, FinalCltvDelta: finalCltvDelta, TimeoutSeconds: 60, FeeLimitMsat: noFeeLimitMsat, - RouteHints: routeHints, }) // Verify that all nodes in the path now have two HTLC's with the @@ -429,13 +366,6 @@ func runMultiHopReceiverChainClaim(ht *lntest.HarnessTest, ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) } - // If this is a taproot channel, then we'll need to make some manual - // route hints so Alice can actually find a route. - var routeHints []*lnrpc.RouteHint - if c == lnrpc.CommitmentType_SIMPLE_TAPROOT { - routeHints = makeRouteHints(bob, carol, zeroConf) - } - // With the network active, we'll now add a new hodl invoice at Carol's // end. Make sure the cltv expiry delta is large enough, otherwise Bob // won't send out the outgoing htlc. @@ -447,7 +377,6 @@ func runMultiHopReceiverChainClaim(ht *lntest.HarnessTest, Value: invoiceAmt, CltvExpiry: finalCltvDelta, Hash: payHash[:], - RouteHints: routeHints, } carolInvoice := carol.RPC.AddHoldInvoice(invoiceReq) @@ -681,13 +610,6 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest, // opens up the base for out tests. const htlcAmt = btcutil.Amount(300_000) - // If this is a taproot channel, then we'll need to make some manual - // route hints so Alice can actually find a route. - var routeHints []*lnrpc.RouteHint - if c == lnrpc.CommitmentType_SIMPLE_TAPROOT { - routeHints = makeRouteHints(bob, carol, zeroConf) - } - // We'll now send a single HTLC across our multi-hop network. carolPubKey := carol.PubKey[:] payHash := ht.Random32Bytes() @@ -698,7 +620,6 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest, FinalCltvDelta: finalCltvDelta, TimeoutSeconds: 60, FeeLimitMsat: noFeeLimitMsat, - RouteHints: routeHints, } alice.RPC.SendPayment(req) @@ -876,13 +797,6 @@ func runMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest, // opens up the base for out tests. const htlcAmt = btcutil.Amount(30000) - // If this is a taproot channel, then we'll need to make some manual - // route hints so Alice can actually find a route. - var routeHints []*lnrpc.RouteHint - if c == lnrpc.CommitmentType_SIMPLE_TAPROOT { - routeHints = makeRouteHints(bob, carol, zeroConf) - } - // We'll now send a single HTLC across our multi-hop network. var preimage lntypes.Preimage copy(preimage[:], ht.Random32Bytes()) @@ -891,7 +805,6 @@ func runMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest, Value: int64(htlcAmt), CltvExpiry: finalCltvDelta, Hash: payHash[:], - RouteHints: routeHints, } carolInvoice := carol.RPC.AddHoldInvoice(invoiceReq) @@ -1085,13 +998,6 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest, ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) } - // If this is a taproot channel, then we'll need to make some manual - // route hints so Alice can actually find a route. - var routeHints []*lnrpc.RouteHint - if c == lnrpc.CommitmentType_SIMPLE_TAPROOT { - routeHints = makeRouteHints(bob, carol, zeroConf) - } - // With the network active, we'll now add a new hodl invoice at Carol's // end. Make sure the cltv expiry delta is large enough, otherwise Bob // won't send out the outgoing htlc. @@ -1103,7 +1009,6 @@ func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest, Value: invoiceAmt, CltvExpiry: finalCltvDelta, Hash: payHash[:], - RouteHints: routeHints, } carolInvoice := carol.RPC.AddHoldInvoice(invoiceReq) @@ -1441,13 +1346,6 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest, ht, alice, bob, false, c, zeroConf, ) - // If this is a taproot channel, then we'll need to make some manual - // route hints so Alice can actually find a route. - var routeHints []*lnrpc.RouteHint - if c == lnrpc.CommitmentType_SIMPLE_TAPROOT { - routeHints = makeRouteHints(bob, carol, zeroConf) - } - // With the network active, we'll now add a new hodl invoice at Carol's // end. Make sure the cltv expiry delta is large enough, otherwise Bob // won't send out the outgoing htlc. @@ -1459,7 +1357,6 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest, Value: invoiceAmt, CltvExpiry: finalCltvDelta, Hash: payHash[:], - RouteHints: routeHints, } carolInvoice := carol.RPC.AddHoldInvoice(invoiceReq) @@ -1737,23 +1634,11 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest, ht, alice, bob, false, c, zeroConf, ) - // If this is a taproot channel, then we'll need to make some manual - // route hints so Alice+Carol can actually find a route. - var ( - carolRouteHints []*lnrpc.RouteHint - aliceRouteHints []*lnrpc.RouteHint - ) - if c == lnrpc.CommitmentType_SIMPLE_TAPROOT { - carolRouteHints = makeRouteHints(bob, carol, zeroConf) - aliceRouteHints = makeRouteHints(bob, alice, zeroConf) - } - // To ensure we have capacity in both directions of the route, we'll // make a fairly large payment Alice->Carol and settle it. const reBalanceAmt = 500_000 invoice := &lnrpc.Invoice{ - Value: reBalanceAmt, - RouteHints: carolRouteHints, + Value: reBalanceAmt, } resp := carol.RPC.AddInvoice(invoice) ht.CompletePaymentRequests(alice, []string{resp.PaymentRequest}) @@ -1785,7 +1670,6 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest, Value: invoiceAmt, CltvExpiry: finalCltvDelta, Hash: payHash[:], - RouteHints: carolRouteHints, } carolInvoice := carol.RPC.AddHoldInvoice(invoiceReq) @@ -1807,7 +1691,6 @@ func runMultiHopHtlcAggregation(ht *lntest.HarnessTest, Value: invoiceAmt, CltvExpiry: thawHeightDelta - 4, Hash: payHash[:], - RouteHints: aliceRouteHints, } aliceInvoice := alice.RPC.AddHoldInvoice(invoiceReq) @@ -2222,13 +2105,7 @@ func createThreeHopNetwork(ht *lntest.HarnessTest, ) } - var privateChan bool - if c == lnrpc.CommitmentType_SIMPLE_TAPROOT { - privateChan = true - } - aliceParams := lntest.OpenChannelParams{ - Private: privateChan, Amt: chanAmt, CommitmentType: c, FundingShim: aliceFundingShim, @@ -2253,7 +2130,6 @@ func createThreeHopNetwork(ht *lntest.HarnessTest, // Prepare params for Bob. bobParams := lntest.OpenChannelParams{ Amt: chanAmt, - Private: privateChan, CommitmentType: c, FundingShim: bobFundingShim, ZeroConf: zeroConf, @@ -2292,18 +2168,8 @@ func createThreeHopNetwork(ht *lntest.HarnessTest, bobChanPoint := resp[1] // Make sure alice and carol know each other's channels. - // - // We'll only do this though if it wasn't a private channel we opened - // earlier. - if !privateChan { - ht.AssertTopologyChannelOpen(alice, bobChanPoint) - ht.AssertTopologyChannelOpen(carol, aliceChanPoint) - } else { - // Otherwise, we want to wait for all the channels to be shown - // as active before we proceed. - ht.AssertChannelExists(alice, aliceChanPoint) - ht.AssertChannelExists(carol, bobChanPoint) - } + ht.AssertTopologyChannelOpen(alice, bobChanPoint) + ht.AssertTopologyChannelOpen(carol, aliceChanPoint) // Remove the ChannelAcceptor for Bob and Carol. if zeroConf { @@ -2341,13 +2207,6 @@ func runExtraPreimageFromRemoteCommit(ht *lntest.HarnessTest, ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) } - // If this is a taproot channel, then we'll need to make some manual - // route hints so Alice can actually find a route. - var routeHints []*lnrpc.RouteHint - if c == lnrpc.CommitmentType_SIMPLE_TAPROOT { - routeHints = makeRouteHints(bob, carol, zeroConf) - } - // With the network active, we'll now add a new hodl invoice at Carol's // end. Make sure the cltv expiry delta is large enough, otherwise Bob // won't send out the outgoing htlc. @@ -2357,7 +2216,6 @@ func runExtraPreimageFromRemoteCommit(ht *lntest.HarnessTest, Value: 100_000, CltvExpiry: finalCltvDelta, Hash: payHash[:], - RouteHints: routeHints, } eveInvoice := carol.RPC.AddHoldInvoice(invoiceReq) @@ -2511,13 +2369,6 @@ func runExtraPreimageFromLocalCommit(ht *lntest.HarnessTest, ht, alice, bob, false, c, zeroConf, ) - // If this is a taproot channel, then we'll need to make some manual - // route hints so Alice can actually find a route. - var routeHints []*lnrpc.RouteHint - if c == lnrpc.CommitmentType_SIMPLE_TAPROOT { - routeHints = makeRouteHints(bob, carol, zeroConf) - } - // With the network active, we'll now add a new hodl invoice at Carol's // end. Make sure the cltv expiry delta is large enough, otherwise Bob // won't send out the outgoing htlc. @@ -2527,7 +2378,6 @@ func runExtraPreimageFromLocalCommit(ht *lntest.HarnessTest, Value: 100_000, CltvExpiry: finalCltvDelta, Hash: payHash[:], - RouteHints: routeHints, } carolInvoice := carol.RPC.AddHoldInvoice(invoiceReq) diff --git a/itest/lnd_payment_test.go b/itest/lnd_payment_test.go index 317ca02eda..9635bbcbf0 100644 --- a/itest/lnd_payment_test.go +++ b/itest/lnd_payment_test.go @@ -446,11 +446,6 @@ func testSendDirectPayment(ht *lntest.HarnessTest) { CommitmentType: ct, } - // Open private channel for taproot channels. - if ct == lnrpc.CommitmentType_SIMPLE_TAPROOT { - params.Private = true - } - testSendPayment(st, params) }) } diff --git a/itest/lnd_psbt_test.go b/itest/lnd_psbt_test.go index bedc61722b..13af92e51a 100644 --- a/itest/lnd_psbt_test.go +++ b/itest/lnd_psbt_test.go @@ -38,20 +38,14 @@ func testPsbtChanFunding(ht *lntest.HarnessTest) { testCases := []struct { name string commitmentType lnrpc.CommitmentType - private bool }{ { name: "anchors", commitmentType: lnrpc.CommitmentType_ANCHORS, - private: false, }, { name: "simple taproot", commitmentType: lnrpc.CommitmentType_SIMPLE_TAPROOT, - - // Set this to true once simple taproot channels can be - // announced to the network. - private: true, }, } @@ -79,7 +73,7 @@ func testPsbtChanFunding(ht *lntest.HarnessTest) { Name: tc.name, TestFunc: func(sst *lntest.HarnessTest) { runPsbtChanFunding( - sst, carol, dave, tc.private, + sst, carol, dave, false, tc.commitmentType, ) }, @@ -100,7 +94,7 @@ func testPsbtChanFunding(ht *lntest.HarnessTest) { Name: tc.name, TestFunc: func(sst *lntest.HarnessTest) { runPsbtChanFundingExternal( - sst, carol, dave, tc.private, + sst, carol, dave, false, tc.commitmentType, ) }, @@ -117,7 +111,7 @@ func testPsbtChanFunding(ht *lntest.HarnessTest) { Name: tc.name, TestFunc: func(sst *lntest.HarnessTest) { runPsbtChanFundingSingleStep( - sst, carol, dave, tc.private, + sst, carol, dave, false, tc.commitmentType, ) }, diff --git a/itest/lnd_revocation_test.go b/itest/lnd_revocation_test.go index 82415e0396..f4a78f3b8e 100644 --- a/itest/lnd_revocation_test.go +++ b/itest/lnd_revocation_test.go @@ -52,12 +52,10 @@ func breachRetributionTestCase(ht *lntest.HarnessTest, // In order to test Carol's response to an uncooperative channel // closure by Bob, we'll first open up a channel between them with a // 0.5 BTC value. - privateChan := commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT chanPoint := ht.OpenChannel( carol, bob, lntest.OpenChannelParams{ CommitmentType: commitType, Amt: chanAmt, - Private: privateChan, }, ) @@ -244,12 +242,10 @@ func revokedCloseRetributionZeroValueRemoteOutputCase(ht *lntest.HarnessTest, // In order to test Dave's response to an uncooperative channel // closure by Carol, we'll first open up a channel between them with a // 0.5 BTC value. - privateChan := commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT chanPoint := ht.OpenChannel( dave, carol, lntest.OpenChannelParams{ CommitmentType: commitType, Amt: chanAmt, - Private: privateChan, }, ) @@ -429,12 +425,10 @@ func revokedCloseRetributionRemoteHodlCase(ht *lntest.HarnessTest, // In order to test Dave's response to an uncooperative channel closure // by Carol, we'll first open up a channel between them with a // funding.MaxBtcFundingAmount (2^24) satoshis value. - privateChan := commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT chanPoint := ht.OpenChannel( dave, carol, lntest.OpenChannelParams{ Amt: chanAmt, PushAmt: pushAmt, - Private: privateChan, CommitmentType: commitType, }, ) From f60b58e4b1a8cc2cef9b6752190c89846317d087 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 23 Aug 2024 14:59:07 +0200 Subject: [PATCH 58/60] docs: update release notes --- docs/release-notes/release-notes-0.19.0.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/release-notes/release-notes-0.19.0.md b/docs/release-notes/release-notes-0.19.0.md index 195b0eb3e0..9594e0ef40 100644 --- a/docs/release-notes/release-notes-0.19.0.md +++ b/docs/release-notes/release-notes-0.19.0.md @@ -80,6 +80,9 @@ protocol](https://github.com/lightningnetwork/lnd/pull/8255) to be able to gossip new Gossip 1.75 messages. +* Add the new [feature bit](https://github.com/lightningnetwork/lnd/pull/8256) + for Gossip 1.75 and allow creation of public channels from lncli. + ## Testing ## Database From 72831aa7ccf31d682e2d6a62ddf7b98b1c9b9bfa Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Thu, 10 Oct 2024 11:30:40 +0200 Subject: [PATCH 59/60] comments --- funding/manager.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/funding/manager.go b/funding/manager.go index f53d2fd93b..9af75dbc0c 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -4799,11 +4799,14 @@ func (f *Manager) newTaprootChanAnnouncement(localPubKey, }, nil } + // Get the message that we will sign. chanAnnMsg, err := netann.ChanAnn2DigestToSign(&chanAnn) if err != nil { return nil, err } + // Collect the 4 keys that will make up the aggregate public key that + // a signature will be created for. pubKeys := []*btcec.PublicKey{ localPubKey, remotePubKey, @@ -4811,6 +4814,8 @@ func (f *Manager) newTaprootChanAnnouncement(localPubKey, remoteFundingKey, } + // Get the received public nonces that the peer has sent us via + // channel_ready. rBtc, rNode, haveReceivedNonces := f.nonceMgr.getReceivedNonces(chanID) if err != nil { return nil, err @@ -4821,6 +4826,7 @@ func (f *Manager) newTaprootChanAnnouncement(localPubKey, "nonces yet") } + // Get the nonces that we have previously sent to the peer. sBtc, sNode, err := f.nonceMgr.getNoncesToSend( chanID, channel.RevocationProducer, channel.LocalChanCfg.MultiSigKey.PubKey, @@ -4829,6 +4835,15 @@ func (f *Manager) newTaprootChanAnnouncement(localPubKey, return nil, err } + // Construct the musig2 session that will be used to represent our + // public BTC key. The parameters are: + // - the key locator for deriving our btc key. + // - all the public keys that make up the aggregate key we are signing. + // - no tweaks. + // - The "otherSignerNonces". In other words, all the nonces other than + // our btc key's nonce. So: Our node nonce along with our peer's + // btc nonce and node nonce. + // - Our btc nonce. musigBtcSess, err := f.cfg.MuSig2Signer.MuSig2CreateSession( input.MuSig2Version100RC2, localFundingKey.KeyLocator, pubKeys, &input.MuSig2Tweaks{}, @@ -4845,6 +4860,15 @@ func (f *Manager) newTaprootChanAnnouncement(localPubKey, return nil, err } + // Construct the musig2 session that will be used to represent our + // public node key. The parameters are: + // - the key locator for deriving our node key. + // - all the public keys that make up the aggregate key we are signing. + // - no tweaks. + // - The "otherSignerNonces". In other words, all the nonces other than + // our node key's nonce. So: Our btc nonce along with our peer's + // btc nonce and node nonce. + // - Our node nonce. musigNodeSess, err := f.cfg.MuSig2Signer.MuSig2CreateSession( input.MuSig2Version100RC2, f.cfg.IDKeyLoc, pubKeys, &input.MuSig2Tweaks{}, From 29285c84d5cde19f992084e1c5549de83028d120 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 11 Oct 2024 15:45:31 +0200 Subject: [PATCH 60/60] errything --- channeldb/edge_info.go | 18 +- channeldb/edge_info_test.go | 45 +- channeldb/edge_policy.go | 6 +- channeldb/edge_policy_test.go | 2 +- channeldb/models/channel_edge_info.go | 20 +- channeldb/models/channel_edge_policy.go | 6 +- channeldb/models/interfaces.go | 2 +- channeldb/waitingproof.go | 2 +- channeldb/waitingproof_test.go | 28 +- discovery/gossiper.go | 18 +- funding/manager.go | 12 +- go.mod | 2 + go.sum | 2 - graph/notifications.go | 7 +- htlcswitch/mock.go | 2 +- lnrpc/routerrpc/router_backend.go | 4 +- lnwire/announcement_signatures_2.go | 93 +- lnwire/channel_announcement_2.go | 201 +- lnwire/channel_id.go | 34 + lnwire/channel_update_2.go | 89 +- lnwire/lnwire_test.go | 87 +- lnwire/pure_tlv.go | 89 + lnwire/pure_tlv_test.go | 361 ++ netann/channel_announcement.go | 24 +- netann/channel_announcement_test.go | 4 +- netann/channel_update.go | 14 +- routing/localchans/manager.go | 22 +- rpcserver.go | 4 +- tlv/internal/gen/gen_tlv_types.go | 20 +- tlv/tlv_types_generated.go | 5028 ++++++++++++++++++++--- 30 files changed, 5429 insertions(+), 817 deletions(-) create mode 100644 lnwire/pure_tlv.go create mode 100644 lnwire/pure_tlv_test.go diff --git a/channeldb/edge_info.go b/channeldb/edge_info.go index fbf5525770..469564f64b 100644 --- a/channeldb/edge_info.go +++ b/channeldb/edge_info.go @@ -28,7 +28,8 @@ const ( const ( // EdgeInfo2MsgType is the tlv type used within the serialisation of // ChannelEdgeInfo2 for storing the serialisation of the associated - // lnwire.ChannelAnnouncement2 message. + // lnwire.ChannelAnnouncement2 message. This will exclude the signature + // TLV record. EdgeInfo2MsgType = tlv.Type(0) // EdgeInfo2Sig is the tlv type used within the serialisation of @@ -182,17 +183,18 @@ func serializeChanEdgeInfo1(w io.Writer, } func serializeChanEdgeInfo2(w io.Writer, edge *models.ChannelEdgeInfo2) error { - if len(edge.ExtraOpaqueData) > MaxAllowedExtraOpaqueBytes { - return ErrTooManyExtraOpaqueBytes(len(edge.ExtraOpaqueData)) - } + //if len(edge.ExtraOpaqueData) > MaxAllowedExtraOpaqueBytes { + // return ErrTooManyExtraOpaqueBytes(len(edge.ExtraOpaqueData)) + //} - serializedMsg, err := edge.DataToSign() - if err != nil { + var msgBuff bytes.Buffer + if err := edge.EncodeAllNonSigFields(&msgBuff); err != nil { return err } + msgBytes := msgBuff.Bytes() records := []tlv.Record{ - tlv.MakePrimitiveRecord(EdgeInfo2MsgType, &serializedMsg), + tlv.MakePrimitiveRecord(EdgeInfo2MsgType, &msgBytes), } if edge.AuthProof != nil { @@ -380,7 +382,7 @@ func deserializeChanEdgeInfo2(r io.Reader) (*models.ChannelEdgeInfo2, error) { } reader := bytes.NewReader(msgBytes) - err = edgeInfo.ChannelAnnouncement2.DecodeTLVRecords(reader) + err = edgeInfo.ChannelAnnouncement2.DecodeNonSigTLVRecords(reader) if err != nil { return nil, err } diff --git a/channeldb/edge_info_test.go b/channeldb/edge_info_test.go index 9a0ecf732c..b04d91bed9 100644 --- a/channeldb/edge_info_test.go +++ b/channeldb/edge_info_test.go @@ -133,9 +133,11 @@ func TestEdgeInfoSerialisation(t *testing.T) { return mainScenario(&m) }, genValue: func(v []reflect.Value, r *rand.Rand) { - ann := lnwire.ChannelAnnouncement2{ - ExtraOpaqueData: make([]byte, 0), - } + var ann lnwire.ChannelAnnouncement2 + + ann.ExtraFieldsInSignedRange = randTLVMap( + t, r, 1000000000, + ) features := randRawFeatureVector(r) ann.Features.Val = *features @@ -186,15 +188,6 @@ func TestEdgeInfoSerialisation(t *testing.T) { ) } - numExtraBytes := r.Int31n(1000) - if numExtraBytes > 0 { - ann.ExtraOpaqueData = make( - []byte, numExtraBytes, - ) - _, err := r.Read(ann.ExtraOpaqueData[:]) - require.NoError(t, err) - } - info := &models.ChannelEdgeInfo2{ ChannelAnnouncement2: ann, ChannelPoint: wire.OutPoint{ @@ -262,3 +255,31 @@ func randRawFeatureVector(r *rand.Rand) *lnwire.RawFeatureVector { return featureVec } + +func randTLVMap(t *testing.T, r *rand.Rand, + rangeStart uint64) map[uint64][]byte { + + var ( + m = make(map[uint64][]byte) + + // We'll generate a random number of records, between 1 and 10. + numRecords = r.Intn(9) + 1 + ) + + // For each record, we'll generate a random key and value. + for i := 0; i < numRecords; i++ { + // Keys must be equal to or greater than + // MinCustomRecordsTlvType. + keyOffset := uint64(r.Intn(100)) + key := rangeStart + keyOffset + + // Values are byte slices of any length. + value := make([]byte, r.Intn(10)) + _, err := r.Read(value) + require.NoError(t, err) + + m[key] = value + } + + return m +} diff --git a/channeldb/edge_policy.go b/channeldb/edge_policy.go index 57dbb0e77a..fc6a26d0f1 100644 --- a/channeldb/edge_policy.go +++ b/channeldb/edge_policy.go @@ -394,9 +394,9 @@ func serializeChanEdgePolicy1(w io.Writer, func serializeChanEdgePolicy2(w io.Writer, edge *models.ChannelEdgePolicy2) error { - if len(edge.ExtraOpaqueData) > MaxAllowedExtraOpaqueBytes { - return ErrTooManyExtraOpaqueBytes(len(edge.ExtraOpaqueData)) - } + //if len(edge.ExtraOpaqueData) > MaxAllowedExtraOpaqueBytes { + // return ErrTooManyExtraOpaqueBytes(len(edge.ExtraOpaqueData)) + //} var b bytes.Buffer if err := edge.Encode(&b, 0); err != nil { diff --git a/channeldb/edge_policy_test.go b/channeldb/edge_policy_test.go index 7b0b81f8ce..386afbe433 100644 --- a/channeldb/edge_policy_test.go +++ b/channeldb/edge_policy_test.go @@ -104,12 +104,12 @@ func TestEdgePolicySerialisation(t *testing.T) { policy := &models.ChannelEdgePolicy2{ //nolint:lll ChannelUpdate2: lnwire.ChannelUpdate2{ - Signature: testSchnorrSig, ExtraOpaqueData: make([]byte, 0), }, ToNode: [33]byte{}, } + policy.Signature.Val = testSchnorrSig policy.ShortChannelID.Val = lnwire.NewShortChanIDFromInt( //nolint:lll uint64(r.Int63()), ) diff --git a/channeldb/models/channel_edge_info.go b/channeldb/models/channel_edge_info.go index a3e8f28c02..1109a58f74 100644 --- a/channeldb/models/channel_edge_info.go +++ b/channeldb/models/channel_edge_info.go @@ -341,16 +341,16 @@ type ChannelEdgeInfo2 struct { func (c *ChannelEdgeInfo2) Copy() ChannelEdgeInfo { return &ChannelEdgeInfo2{ ChannelAnnouncement2: lnwire.ChannelAnnouncement2{ - ChainHash: c.ChainHash, - Features: c.Features, - ShortChannelID: c.ShortChannelID, - Capacity: c.Capacity, - NodeID1: c.NodeID1, - NodeID2: c.NodeID2, - BitcoinKey1: c.BitcoinKey1, - BitcoinKey2: c.BitcoinKey2, - MerkleRootHash: c.MerkleRootHash, - ExtraOpaqueData: c.ExtraOpaqueData, + ChainHash: c.ChainHash, + Features: c.Features, + ShortChannelID: c.ShortChannelID, + Capacity: c.Capacity, + NodeID1: c.NodeID1, + NodeID2: c.NodeID2, + BitcoinKey1: c.BitcoinKey1, + BitcoinKey2: c.BitcoinKey2, + MerkleRootHash: c.MerkleRootHash, + ExtraFieldsInSignedRange: c.ExtraFieldsInSignedRange, }, ChannelPoint: c.ChannelPoint, AuthProof: c.AuthProof, diff --git a/channeldb/models/channel_edge_policy.go b/channeldb/models/channel_edge_policy.go index ac7bf651ee..d00d3503ba 100644 --- a/channeldb/models/channel_edge_policy.go +++ b/channeldb/models/channel_edge_policy.go @@ -188,8 +188,8 @@ func (c *ChannelEdgePolicy1) AfterUpdateMsg(msg lnwire.ChannelUpdate) (bool, return c.LastUpdate.After(timestamp), nil } -func (c *ChannelEdgePolicy1) ExtraData() lnwire.ExtraOpaqueData { - return c.ExtraOpaqueData +func (c *ChannelEdgePolicy1) ExtraData() (lnwire.ExtraOpaqueData, error) { + return c.ExtraOpaqueData, nil } // Sig returns the signature of the update message. @@ -213,7 +213,7 @@ type ChannelEdgePolicy2 struct { // // NOTE: This is part of the ChannelEdgePolicy interface. func (c *ChannelEdgePolicy2) Sig() (input.Signature, error) { - return c.Signature.ToSignature() + return c.Signature.Val.ToSignature() } // AfterUpdateMsg compares this update against the passed lnwire.ChannelUpdate diff --git a/channeldb/models/interfaces.go b/channeldb/models/interfaces.go index bfca995fad..50d21ff2fb 100644 --- a/channeldb/models/interfaces.go +++ b/channeldb/models/interfaces.go @@ -95,5 +95,5 @@ type ChannelEdgePolicy interface { // Sig returns the signature of the update message. Sig() (input.Signature, error) - ExtraData() lnwire.ExtraOpaqueData + ExtraData() (lnwire.ExtraOpaqueData, error) } diff --git a/channeldb/waitingproof.go b/channeldb/waitingproof.go index 419addec36..697a6fe643 100644 --- a/channeldb/waitingproof.go +++ b/channeldb/waitingproof.go @@ -265,7 +265,7 @@ type TaprootWaitingProof struct { // // NOTE: this is part of the WaitingProofInterface. func (t *TaprootWaitingProof) SCID() lnwire.ShortChannelID { - return t.ShortChannelID + return t.ShortChannelID.Val } // Decode parses the bytes from the given reader to reconstruct the diff --git a/channeldb/waitingproof_test.go b/channeldb/waitingproof_test.go index 21568d169e..c819c20f2c 100644 --- a/channeldb/waitingproof_test.go +++ b/channeldb/waitingproof_test.go @@ -25,25 +25,25 @@ func TestWaitingProofStore(t *testing.T) { }) // No agg nonce. - proof2 := NewTaprootWaitingProof(true, &lnwire.AnnounceSignatures2{ - ShortChannelID: lnwire.ShortChannelID{ - BlockHeight: 2000, - }, - PartialSignature: *randPartialSig(t), - ExtraOpaqueData: make([]byte, 0), - }, nil) + proof2 := NewTaprootWaitingProof( + true, lnwire.NewAnnSigs2( + lnwire.ChannelID{}, + lnwire.ShortChannelID{BlockHeight: 2000}, + *randPartialSig(t), + ), nil, + ) // With agg nonce. priv, err := btcec.NewPrivateKey() require.NoError(t, err) - proof3 := NewTaprootWaitingProof(true, &lnwire.AnnounceSignatures2{ - ShortChannelID: lnwire.ShortChannelID{ - BlockHeight: 2000, - }, - PartialSignature: *randPartialSig(t), - ExtraOpaqueData: make([]byte, 0), - }, priv.PubKey()) + proof3 := NewTaprootWaitingProof( + true, lnwire.NewAnnSigs2( + lnwire.ChannelID{}, + lnwire.ShortChannelID{BlockHeight: 2000}, + *randPartialSig(t), + ), priv.PubKey(), + ) proofs := []*WaitingProof{ proof1, diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 1de237eeb0..45ee581815 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -2511,9 +2511,19 @@ func IsKeepAliveUpdate(update lnwire.ChannelUpdate, if fwd.MaxHTLC != prevFwd.MinHTLC { return false, nil } - if !bytes.Equal(upd.ExtraOpaqueData, prev.ExtraOpaqueData) { + if len(upd.ExtraFieldsInSignedRange) != len(prev.ExtraFieldsInSignedRange) { return false, nil } + for t, b := range upd.ExtraFieldsInSignedRange { + bb, ok := prev.ExtraFieldsInSignedRange[t] + if !ok { + return false, nil + } + + if !bytes.Equal(bb, b) { + return false, nil + } + } return true, nil @@ -3723,11 +3733,11 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg, } ps1 := musig2.NewPartialSignature( - &a.PartialSignature.Sig, aggNonce, + &a.PartialSignature.Val.Sig, aggNonce, ) ps2 := musig2.NewPartialSignature( - &oppProof.PartialSignature.Sig, aggNonce, + &oppProof.PartialSignature.Val.Sig, aggNonce, ) // Now aggregate the partial sigs. @@ -3933,7 +3943,7 @@ func buildChanProof(ann lnwire.ChannelAnnouncement) ( case *lnwire.ChannelAnnouncement2: return &models.ChannelAuthProof2{ - SchnorrSigBytes: a.Signature.ToSignatureBytes(), + SchnorrSigBytes: a.Signature.Val.ToSignatureBytes(), }, nil default: diff --git a/funding/manager.go b/funding/manager.go index 9af75dbc0c..110a104f4d 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -4774,7 +4774,7 @@ func (f *Manager) newTaprootChanAnnouncement(localPubKey, // signature that signs a double-sha digest of the announcement. // This'll serve to authenticate this announcement and any other future // updates we may send. - chanUpdateMsg, err := chanUpdateAnn.DataToSign() + chanUpdateMsg, err := lnwire.SerialiseFieldsToSign(&chanUpdateAnn) if err != nil { return nil, err } @@ -4786,7 +4786,7 @@ func (f *Manager) newTaprootChanAnnouncement(localPubKey, return nil, errors.Errorf("unable to generate channel "+ "update announcement signature: %v", err) } - chanUpdateAnn.Signature, err = lnwire.NewSigFromSignature(sig) + chanUpdateAnn.Signature.Val, err = lnwire.NewSigFromSignature(sig) if err != nil { return nil, errors.Errorf("unable to generate channel "+ "update announcement signature: %v", err) @@ -4894,11 +4894,9 @@ func (f *Manager) newTaprootChanAnnouncement(localPubKey, // Finally, we'll generate the announcement proof which we'll use to // provide the other side with the necessary signatures required to // allow them to reconstruct the full channel announcement. - proof := &lnwire.AnnounceSignatures2{ - ChannelID: chanID, - ShortChannelID: shortChanID, - PartialSignature: lnwire.NewPartialSig(*ps.S), - } + proof := lnwire.NewAnnSigs2( + chanID, shortChanID, lnwire.NewPartialSig(*ps.S), + ) return &chanAnnouncement{ chanAnn: &chanAnn, diff --git a/go.mod b/go.mod index 60af5fb3de..7ec10d74e2 100644 --- a/go.mod +++ b/go.mod @@ -210,3 +210,5 @@ replace google.golang.org/protobuf => github.com/lightninglabs/protobuf-go-hex-d go 1.22.6 retract v0.0.2 + +replace github.com/lightningnetwork/lnd/tlv => ./tlv diff --git a/go.sum b/go.sum index 312b225780..2e1a9ff143 100644 --- a/go.sum +++ b/go.sum @@ -465,8 +465,6 @@ github.com/lightningnetwork/lnd/sqldb v1.0.4 h1:9cMwPxcrLQG8UmyZO4q8SpR7NmxSwBMb github.com/lightningnetwork/lnd/sqldb v1.0.4/go.mod h1:4cQOkdymlZ1znnjuRNvMoatQGJkRneTj2CoPSPaQhWo= github.com/lightningnetwork/lnd/ticker v1.1.1 h1:J/b6N2hibFtC7JLV77ULQp++QLtCwT6ijJlbdiZFbSM= github.com/lightningnetwork/lnd/ticker v1.1.1/go.mod h1:waPTRAAcwtu7Ji3+3k+u/xH5GHovTsCoSVpho0KDvdA= -github.com/lightningnetwork/lnd/tlv v1.2.6 h1:icvQG2yDr6k3ZuZzfRdG3EJp6pHurcuh3R6dg0gv/Mw= -github.com/lightningnetwork/lnd/tlv v1.2.6/go.mod h1:/CmY4VbItpOldksocmGT4lxiJqRP9oLxwSZOda2kzNQ= github.com/lightningnetwork/lnd/tor v1.1.2 h1:3zv9z/EivNFaMF89v3ciBjCS7kvCj4ZFG7XvD2Qq0/k= github.com/lightningnetwork/lnd/tor v1.1.2/go.mod h1:j7T9uJ2NLMaHwE7GiBGnpYLn4f7NRoTM6qj+ul6/ycA= github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw= diff --git a/graph/notifications.go b/graph/notifications.go index 040f266dca..11c6186bf8 100644 --- a/graph/notifications.go +++ b/graph/notifications.go @@ -372,6 +372,11 @@ func addToTopologyChange(graph DB, update *TopologyChange, return err } + extra, err := m.ExtraData() + if err != nil { + return err + } + policy := m.ForwardingPolicy() edgeUpdate := &ChannelEdgeUpdate{ ChanID: m.SCID().ToUint64(), @@ -385,7 +390,7 @@ func addToTopologyChange(graph DB, update *TopologyChange, AdvertisingNode: aNode, ConnectingNode: cNode, Disabled: m.IsDisabled(), - ExtraOpaqueData: m.ExtraData(), + ExtraOpaqueData: extra, } // TODO(roasbeef): add bit to toggle diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go index eb05b39679..401cc99254 100644 --- a/htlcswitch/mock.go +++ b/htlcswitch/mock.go @@ -176,7 +176,7 @@ func initSwitchWithDB(startingHeight uint32, db *channeldb.DB) (*Switch, error) case *lnwire.ChannelUpdate1: u.Signature = s case *lnwire.ChannelUpdate2: - u.Signature = s + u.Signature.Val = s } return nil diff --git a/lnrpc/routerrpc/router_backend.go b/lnrpc/routerrpc/router_backend.go index c1e54473c5..1ef8ce2e4c 100644 --- a/lnrpc/routerrpc/router_backend.go +++ b/lnrpc/routerrpc/router_backend.go @@ -1700,7 +1700,7 @@ func marshallChannelUpdate(update lnwire.ChannelUpdate) (*lnrpc.ChannelUpdate, case *lnwire.ChannelUpdate2: return nil, &lnrpc.ChannelUpdate2{ - Signature: upd.Signature.RawBytes(), + Signature: upd.Signature.Val.RawBytes(), ChainHash: upd.ChainHash.Val[:], ChanId: upd.ShortChannelID.Val.ToUint64(), BlockHeight: upd.BlockHeight.Val, @@ -1711,7 +1711,7 @@ func marshallChannelUpdate(update lnwire.ChannelUpdate) (*lnrpc.ChannelUpdate, FeeRate: upd.FeeProportionalMillionths.Val, HtlcMinimumMsat: uint64(upd.HTLCMinimumMsat.Val), HtlcMaximumMsat: uint64(upd.HTLCMaximumMsat.Val), - ExtraOpaqueData: upd.ExtraOpaqueData, + //ExtraOpaqueData: upd.ExtraOpaqueData, }, nil default: diff --git a/lnwire/announcement_signatures_2.go b/lnwire/announcement_signatures_2.go index a104470321..dd44290ed5 100644 --- a/lnwire/announcement_signatures_2.go +++ b/lnwire/announcement_signatures_2.go @@ -3,6 +3,8 @@ package lnwire import ( "bytes" "io" + + "github.com/lightningnetwork/lnd/tlv" ) // AnnounceSignatures2 is a direct message between two endpoints of a @@ -14,27 +16,39 @@ type AnnounceSignatures2 struct { // Channel id is better for users and debugging and short channel id is // used for quick test on existence of the particular utxo inside the // blockchain, because it contains information about block. - ChannelID ChannelID + ChannelID tlv.RecordT[tlv.TlvType0, ChannelID] // ShortChannelID is the unique description of the funding transaction. // It is constructed with the most significant 3 bytes as the block // height, the next 3 bytes indicating the transaction index within the // block, and the least significant two bytes indicating the output // index which pays to the channel. - ShortChannelID ShortChannelID + ShortChannelID tlv.RecordT[tlv.TlvType2, ShortChannelID] // PartialSignature is the combination of the partial Schnorr signature // created for the node's bitcoin key with the partial signature created // for the node's node ID key. - PartialSignature PartialSig - - // ExtraOpaqueData is the set of data that was appended to this - // message, some of which we may not actually know how to iterate or - // parse. By holding onto this data, we ensure that we're able to - // properly validate the set of signatures that cover these new fields, - // and ensure we're able to make upgrades to the network in a forwards - // compatible manner. - ExtraOpaqueData ExtraOpaqueData + PartialSignature tlv.RecordT[tlv.TlvType4, PartialSig] + + // Any extra fields in the signed range that we do not yet know about, + // but we need to keep them for signature validation and to produce a + // valid message. + ExtraFieldsInSignedRange map[uint64][]byte +} + +func NewAnnSigs2(chanID ChannelID, scid ShortChannelID, + partialSig PartialSig) *AnnounceSignatures2 { + + return &AnnounceSignatures2{ + ChannelID: tlv.NewRecordT[tlv.TlvType0, ChannelID](chanID), + ShortChannelID: tlv.NewRecordT[tlv.TlvType2, ShortChannelID]( + scid, + ), + PartialSignature: tlv.NewRecordT[tlv.TlvType4, PartialSig]( + partialSig, + ), + ExtraFieldsInSignedRange: make(map[uint64][]byte, 0), + } } // A compile time check to ensure AnnounceSignatures2 implements the @@ -46,32 +60,29 @@ var _ Message = (*AnnounceSignatures2)(nil) // // This is part of the lnwire.Message interface. func (a *AnnounceSignatures2) Decode(r io.Reader, _ uint32) error { - return ReadElements(r, - &a.ChannelID, - &a.ShortChannelID, - &a.PartialSignature, - &a.ExtraOpaqueData, - ) -} - -// Encode serializes the target AnnounceSignatures2 into the passed io.Writer -// observing the protocol version specified. -// -// This is part of the lnwire.Message interface. -func (a *AnnounceSignatures2) Encode(w *bytes.Buffer, _ uint32) error { - if err := WriteChannelID(w, a.ChannelID); err != nil { + stream, err := tlv.NewStream(ProduceRecordsSorted( + &a.ChannelID, &a.ShortChannelID, &a.PartialSignature, + )...) + if err != nil { return err } - if err := WriteShortChannelID(w, a.ShortChannelID); err != nil { + typeMap, err := stream.DecodeWithParsedTypesP2P(r) + if err != nil { return err } - if err := WriteElement(w, a.PartialSignature); err != nil { - return err - } + a.ExtraFieldsInSignedRange = ExtraSignedFieldsFromTypeMap(typeMap) + + return nil +} - return WriteBytes(w, a.ExtraOpaqueData) +// Encode serializes the target AnnounceSignatures2 into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (a *AnnounceSignatures2) Encode(w *bytes.Buffer, _ uint32) error { + return EncodePureTLVMessage(a, w) } // MsgType returns the integer uniquely identifying this message type on the @@ -82,16 +93,34 @@ func (a *AnnounceSignatures2) MsgType() MessageType { return MsgAnnounceSignatures2 } +// AllRecords returns all the TLV records for the message. This will include all +// the records we know about along with any that we don't know about but that +// fall in the signed TLV range. +// +// NOTE: this is part of the PureTLVMessage interface. +func (a *AnnounceSignatures2) AllRecords() []tlv.Record { + recordProducers := []tlv.RecordProducer{ + &a.ChannelID, &a.ShortChannelID, + &a.PartialSignature, + } + + recordProducers = append(recordProducers, RecordsAsProducers( + tlv.MapToRecords(a.ExtraFieldsInSignedRange), + )...) + + return ProduceRecordsSorted(recordProducers...) +} + // SCID returns the ShortChannelID of the channel. // // NOTE: this is part of the AnnounceSignatures interface. func (a *AnnounceSignatures2) SCID() ShortChannelID { - return a.ShortChannelID + return a.ShortChannelID.Val } // ChanID returns the ChannelID identifying the channel. // // NOTE: this is part of the AnnounceSignatures interface. func (a *AnnounceSignatures2) ChanID() ChannelID { - return a.ChannelID + return a.ChannelID.Val } diff --git a/lnwire/channel_announcement_2.go b/lnwire/channel_announcement_2.go index 074e7d0842..a236966689 100644 --- a/lnwire/channel_announcement_2.go +++ b/lnwire/channel_announcement_2.go @@ -12,9 +12,6 @@ import ( // ChannelAnnouncement2 message is used to announce the existence of a taproot // channel between two peers in the network. type ChannelAnnouncement2 struct { - // Signature is a Schnorr signature over the TLV stream of the message. - Signature Sig - // ChainHash denotes the target chain that this channel was opened // within. This value should be the genesis hash of the target chain. ChainHash tlv.RecordT[tlv.TlvType0, chainhash.Hash] @@ -59,47 +56,103 @@ type ChannelAnnouncement2 struct { // the funding output is a pure 2-of-2 MuSig aggregate public key. MerkleRootHash tlv.OptionalRecordT[tlv.TlvType16, [32]byte] - // ExtraOpaqueData is the set of data that was appended to this - // message, some of which we may not actually know how to iterate or - // parse. By holding onto this data, we ensure that we're able to - // properly validate the set of signatures that cover these new fields, - // and ensure we're able to make upgrades to the network in a forwards - // compatible manner. - ExtraOpaqueData ExtraOpaqueData + // Signature is a Schnorr signature over serialised signed-range TLV + // stream of the message. + Signature tlv.RecordT[tlv.TlvType160, Sig] + + // Any extra fields in the signed range that we do not yet know about, + // but we need to keep them for signature validation and to produce a + // valid message. + ExtraFieldsInSignedRange map[uint64][]byte } -// Decode deserializes a serialized AnnounceSignatures1 stored in the passed -// io.Reader observing the specified protocol version. +// Encode serializes the target AnnounceSignatures1 into the passed io.Writer +// observing the protocol version specified. // // This is part of the lnwire.Message interface. -func (c *ChannelAnnouncement2) Decode(r io.Reader, _ uint32) error { - err := ReadElement(r, &c.Signature) - if err != nil { - return err - } - c.Signature.ForceSchnorr() +func (c *ChannelAnnouncement2) Encode(w *bytes.Buffer, _ uint32) error { + return EncodePureTLVMessage(c, w) +} + +// AllRecords returns all the TLV records for the message. This will include all +// the records we know about along with any that we don't know about but that +// fall in the signed TLV range. +// +// NOTE: this is part of the PureTLVMessage interface. +func (c *ChannelAnnouncement2) AllRecords() []tlv.Record { + recordProducers := append( + c.allNonSignatureRecordProducers(), &c.Signature, + ) - return c.DecodeTLVRecords(r) + return ProduceRecordsSorted(recordProducers...) } -// DecodeTLVRecords decodes only the TLV section of the message. -func (c *ChannelAnnouncement2) DecodeTLVRecords(r io.Reader) error { - // First extract into extra opaque data. - var tlvRecords ExtraOpaqueData - if err := ReadElements(r, &tlvRecords); err != nil { - return err +func (c *ChannelAnnouncement2) allNonSignatureRecordProducers() []tlv.RecordProducer { + // The chain-hash record is only included if it is _not_ equal to the + // bitcoin mainnet genisis block hash. + var recordProducers []tlv.RecordProducer + if !c.ChainHash.Val.IsEqual(chaincfg.MainNetParams.GenesisHash) { + hash := tlv.ZeroRecordT[tlv.TlvType0, [32]byte]() + hash.Val = c.ChainHash.Val + + recordProducers = append(recordProducers, &hash) } + recordProducers = append(recordProducers, + &c.Features, &c.ShortChannelID, &c.Capacity, &c.NodeID1, + &c.NodeID2, + ) + + c.BitcoinKey1.WhenSome(func(key tlv.RecordT[tlv.TlvType12, [33]byte]) { + recordProducers = append(recordProducers, &key) + }) + + c.BitcoinKey2.WhenSome(func(key tlv.RecordT[tlv.TlvType14, [33]byte]) { + recordProducers = append(recordProducers, &key) + }) + + c.MerkleRootHash.WhenSome( + func(hash tlv.RecordT[tlv.TlvType16, [32]byte]) { + recordProducers = append(recordProducers, &hash) + }, + ) + + recordProducers = append(recordProducers, RecordsAsProducers( + tlv.MapToRecords(c.ExtraFieldsInSignedRange), + )...) + + return recordProducers +} + +// Decode deserializes a serialized AnnounceSignatures1 stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *ChannelAnnouncement2) Decode(r io.Reader, _ uint32) error { var ( chainHash = tlv.ZeroRecordT[tlv.TlvType0, [32]byte]() btcKey1 = tlv.ZeroRecordT[tlv.TlvType12, [33]byte]() btcKey2 = tlv.ZeroRecordT[tlv.TlvType14, [33]byte]() merkleRootHash = tlv.ZeroRecordT[tlv.TlvType16, [32]byte]() ) - typeMap, err := tlvRecords.ExtractRecords( - &chainHash, &c.Features, &c.ShortChannelID, &c.Capacity, - &c.NodeID1, &c.NodeID2, &btcKey1, &btcKey2, &merkleRootHash, - ) + stream, err := tlv.NewStream(ProduceRecordsSorted( + &chainHash, + &c.Features, + &c.ShortChannelID, + &c.Capacity, + &c.NodeID1, + &c.NodeID2, + &btcKey1, + &btcKey2, + &merkleRootHash, + &c.Signature, + )...) + if err != nil { + return err + } + c.Signature.Val.ForceSchnorr() + + typeMap, err := stream.DecodeWithParsedTypesP2P(r) if err != nil { return err } @@ -122,68 +175,68 @@ func (c *ChannelAnnouncement2) DecodeTLVRecords(r io.Reader) error { c.MerkleRootHash = tlv.SomeRecordT(merkleRootHash) } - if len(tlvRecords) != 0 { - c.ExtraOpaqueData = tlvRecords - } + c.ExtraFieldsInSignedRange = ExtraSignedFieldsFromTypeMap(typeMap) return nil } -// Encode serializes the target AnnounceSignatures1 into the passed io.Writer -// observing the protocol version specified. -// -// This is part of the lnwire.Message interface. -func (c *ChannelAnnouncement2) Encode(w *bytes.Buffer, _ uint32) error { - _, err := w.Write(c.Signature.RawBytes()) +// DecodeNonSigTLVRecords decodes only the TLV section of the message. +func (c *ChannelAnnouncement2) DecodeNonSigTLVRecords(r io.Reader) error { + var ( + chainHash = tlv.ZeroRecordT[tlv.TlvType0, [32]byte]() + btcKey1 = tlv.ZeroRecordT[tlv.TlvType12, [33]byte]() + btcKey2 = tlv.ZeroRecordT[tlv.TlvType14, [33]byte]() + merkleRootHash = tlv.ZeroRecordT[tlv.TlvType16, [32]byte]() + ) + stream, err := tlv.NewStream(ProduceRecordsSorted( + &chainHash, + &c.Features, + &c.ShortChannelID, + &c.Capacity, + &c.NodeID1, + &c.NodeID2, + &btcKey1, + &btcKey2, + &merkleRootHash, + )...) if err != nil { return err } - _, err = c.DataToSign() + + typeMap, err := stream.DecodeWithParsedTypesP2P(r) if err != nil { return err } - return WriteBytes(w, c.ExtraOpaqueData) -} + // By default, the chain-hash is the bitcoin mainnet genesis block hash. + c.ChainHash.Val = *chaincfg.MainNetParams.GenesisHash + if _, ok := typeMap[c.ChainHash.TlvType()]; ok { + c.ChainHash.Val = chainHash.Val + } -// DataToSign encodes the data to be signed into the ExtraOpaqueData member and -// returns it. -func (c *ChannelAnnouncement2) DataToSign() ([]byte, error) { - // The chain-hash record is only included if it is _not_ equal to the - // bitcoin mainnet genisis block hash. - var recordProducers []tlv.RecordProducer - if !c.ChainHash.Val.IsEqual(chaincfg.MainNetParams.GenesisHash) { - hash := tlv.ZeroRecordT[tlv.TlvType0, [32]byte]() - hash.Val = c.ChainHash.Val + if _, ok := typeMap[c.BitcoinKey1.TlvType()]; ok { + c.BitcoinKey1 = tlv.SomeRecordT(btcKey1) + } - recordProducers = append(recordProducers, &hash) + if _, ok := typeMap[c.BitcoinKey2.TlvType()]; ok { + c.BitcoinKey2 = tlv.SomeRecordT(btcKey2) } - recordProducers = append(recordProducers, - &c.Features, &c.ShortChannelID, &c.Capacity, &c.NodeID1, - &c.NodeID2, - ) + if _, ok := typeMap[c.MerkleRootHash.TlvType()]; ok { + c.MerkleRootHash = tlv.SomeRecordT(merkleRootHash) + } - c.BitcoinKey1.WhenSome(func(key tlv.RecordT[tlv.TlvType12, [33]byte]) { - recordProducers = append(recordProducers, &key) - }) + c.ExtraFieldsInSignedRange = ExtraSignedFieldsFromTypeMap(typeMap) - c.BitcoinKey2.WhenSome(func(key tlv.RecordT[tlv.TlvType14, [33]byte]) { - recordProducers = append(recordProducers, &key) - }) + return nil +} - c.MerkleRootHash.WhenSome( - func(hash tlv.RecordT[tlv.TlvType16, [32]byte]) { - recordProducers = append(recordProducers, &hash) - }, +// EncodeAllNonSigFields encodes the entire message to the given writer but +// excludes the signature field. +func (c *ChannelAnnouncement2) EncodeAllNonSigFields(w io.Writer) error { + return EncodeRecordsTo( + w, ProduceRecordsSorted(c.allNonSignatureRecordProducers()...), ) - - err := EncodeMessageExtraData(&c.ExtraOpaqueData, recordProducers...) - if err != nil { - return nil, err - } - - return c.ExtraOpaqueData, nil } // MsgType returns the integer uniquely identifying this message type on the @@ -198,6 +251,10 @@ func (c *ChannelAnnouncement2) MsgType() MessageType { // lnwire.Message interface. var _ Message = (*ChannelAnnouncement2)(nil) +// A compile time check to ensure ChannelAnnouncement2 implements the +// lnwire.PureTLVMessage interface. +var _ PureTLVMessage = (*ChannelAnnouncement2)(nil) + // Node1KeyBytes returns the bytes representing the public key of node 1 in the // channel. // diff --git a/lnwire/channel_id.go b/lnwire/channel_id.go index 1615eb7471..d6ef3569fc 100644 --- a/lnwire/channel_id.go +++ b/lnwire/channel_id.go @@ -3,10 +3,12 @@ package lnwire import ( "encoding/binary" "encoding/hex" + "io" "math" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" + "github.com/lightningnetwork/lnd/tlv" ) const ( @@ -36,6 +38,38 @@ func (c ChannelID) String() string { return hex.EncodeToString(c[:]) } +func (c *ChannelID) Record() tlv.Record { + return tlv.MakeStaticRecord(0, c, 32, encodeChannelID, decodeChannelID) +} + +func encodeChannelID(w io.Writer, val interface{}, buf *[8]byte) error { + if v, ok := val.(*ChannelID); ok { + bigSize := [32]byte(*v) + + return tlv.EBytes32(w, &bigSize, buf) + } + + return tlv.NewTypeForEncodingErr(val, "lnwire.ChannelID") +} + +func decodeChannelID(r io.Reader, val interface{}, buf *[8]byte, + l uint64) error { + + if v, ok := val.(*ChannelID); ok { + var id [32]byte + err := tlv.DBytes32(r, &id, buf, l) + if err != nil { + return err + } + + *v = ChannelID(id) + + return nil + } + + return tlv.NewTypeForDecodingErr(val, "lnwire.ChannelID", l, l) +} + // NewChanIDFromOutPoint converts a target OutPoint into a ChannelID that is // usable within the network. In order to convert the OutPoint into a ChannelID, // we XOR the lower 2-bytes of the txid within the OutPoint with the big-endian diff --git a/lnwire/channel_update_2.go b/lnwire/channel_update_2.go index 79a76aad61..08be40a7c5 100644 --- a/lnwire/channel_update_2.go +++ b/lnwire/channel_update_2.go @@ -22,10 +22,6 @@ const ( // HTLCs and other parameters. This message is also used to redeclare initially // set channel parameters. type ChannelUpdate2 struct { - // Signature is used to validate the announced data and prove the - // ownership of node id. - Signature Sig - // ChainHash denotes the target chain that this channel was opened // within. This value should be the genesis hash of the target chain. // Along with the short channel ID, this uniquely identifies the @@ -74,10 +70,22 @@ type ChannelUpdate2 struct { // millionth of a satoshi. FeeProportionalMillionths tlv.RecordT[tlv.TlvType18, uint32] - // ExtraOpaqueData is the set of data that was appended to this message - // to fill out the full maximum transport message size. These fields can - // be used to specify optional data such as custom TLV fields. - ExtraOpaqueData ExtraOpaqueData + // Signature is used to validate the announced data and prove the + // ownership of node id. + Signature tlv.RecordT[tlv.TlvType160, Sig] + + // Any extra fields in the signed range that we do not yet know about, + // but we need to keep them for signature validation and to produce a + // valid message. + ExtraFieldsInSignedRange map[uint64][]byte +} + +// Encode serializes the target ChannelUpdate2 into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (c *ChannelUpdate2) Encode(w *bytes.Buffer, _ uint32) error { + return EncodePureTLVMessage(c, w) } // Decode deserializes a serialized ChannelUpdate2 stored in the passed @@ -85,17 +93,6 @@ type ChannelUpdate2 struct { // // This is part of the lnwire.Message interface. func (c *ChannelUpdate2) Decode(r io.Reader, _ uint32) error { - err := ReadElement(r, &c.Signature) - if err != nil { - return err - } - c.Signature.ForceSchnorr() - - return c.DecodeTLVRecords(r) -} - -// DecodeTLVRecords decodes only the TLV section of the message. -func (c *ChannelUpdate2) DecodeTLVRecords(r io.Reader) error { // First extract into extra opaque data. var tlvRecords ExtraOpaqueData if err := ReadElements(r, &tlvRecords); err != nil { @@ -111,10 +108,12 @@ func (c *ChannelUpdate2) DecodeTLVRecords(r io.Reader) error { &secondPeer, &c.CLTVExpiryDelta, &c.HTLCMinimumMsat, &c.HTLCMaximumMsat, &c.FeeBaseMsat, &c.FeeProportionalMillionths, + &c.Signature, ) if err != nil { return err } + c.Signature.Val.ForceSchnorr() // By default, the chain-hash is the bitcoin mainnet genesis block hash. c.ChainHash.Val = *chaincfg.MainNetParams.GenesisHash @@ -150,38 +149,21 @@ func (c *ChannelUpdate2) DecodeTLVRecords(r io.Reader) error { c.FeeProportionalMillionths.Val = defaultFeeProportionalMillionths //nolint:lll } - if len(tlvRecords) != 0 { - c.ExtraOpaqueData = tlvRecords - } + c.ExtraFieldsInSignedRange = ExtraSignedFieldsFromTypeMap(typeMap) return nil } -// Encode serializes the target ChannelUpdate2 into the passed io.Writer -// observing the protocol version specified. +// AllRecords returns all the TLV records for the message. This will include all +// the records we know about along with any that we don't know about but that +// fall in the signed TLV range. // -// This is part of the lnwire.Message interface. -func (c *ChannelUpdate2) Encode(w *bytes.Buffer, _ uint32) error { - _, err := w.Write(c.Signature.RawBytes()) - if err != nil { - return err - } - - _, err = c.DataToSign() - if err != nil { - return err - } - - return WriteBytes(w, c.ExtraOpaqueData) -} +// NOTE: this is part of the PureTLVMessage interface. +func (c *ChannelUpdate2) AllRecords() []tlv.Record { + var recordProducers []tlv.RecordProducer -// DataToSign is used to retrieve part of the announcement message which should -// be signed. For the ChannelUpdate2 message, this includes the serialised TLV -// records. -func (c *ChannelUpdate2) DataToSign() ([]byte, error) { // The chain-hash record is only included if it is _not_ equal to the // bitcoin mainnet genisis block hash. - var recordProducers []tlv.RecordProducer if !c.ChainHash.Val.IsEqual(chaincfg.MainNetParams.GenesisHash) { hash := tlv.ZeroRecordT[tlv.TlvType0, [32]byte]() hash.Val = c.ChainHash.Val @@ -190,7 +172,7 @@ func (c *ChannelUpdate2) DataToSign() ([]byte, error) { } recordProducers = append(recordProducers, - &c.ShortChannelID, &c.BlockHeight, + &c.ShortChannelID, &c.BlockHeight, &c.Signature, ) // Only include the disable flags if any bit is set. @@ -225,12 +207,11 @@ func (c *ChannelUpdate2) DataToSign() ([]byte, error) { ) } - err := EncodeMessageExtraData(&c.ExtraOpaqueData, recordProducers...) - if err != nil { - return nil, err - } + recordProducers = append(recordProducers, RecordsAsProducers( + tlv.MapToRecords(c.ExtraFieldsInSignedRange), + )...) - return c.ExtraOpaqueData, nil + return ProduceRecordsSorted(recordProducers...) } // MsgType returns the integer uniquely identifying this message type on the @@ -241,8 +222,14 @@ func (c *ChannelUpdate2) MsgType() MessageType { return MsgChannelUpdate2 } -func (c *ChannelUpdate2) ExtraData() ExtraOpaqueData { - return c.ExtraOpaqueData +func (c *ChannelUpdate2) ExtraData() (ExtraOpaqueData, error) { + var buf *bytes.Buffer + err := EncodeRecordsTo(buf, tlv.MapToRecords(c.ExtraFieldsInSignedRange)) + if err != nil { + return nil, err + } + + return buf.Bytes(), nil } // A compile time check to ensure ChannelUpdate2 implements the diff --git a/lnwire/lnwire_test.go b/lnwire/lnwire_test.go index 6b9630f58a..2610b24ec8 100644 --- a/lnwire/lnwire_test.go +++ b/lnwire/lnwire_test.go @@ -187,7 +187,7 @@ func randDeliveryAddress(r *rand.Rand) (DeliveryAddress, error) { func randRawFeatureVector(r *rand.Rand) *RawFeatureVector { featureVec := NewRawFeatureVector() - for i := 0; i < 10000; i++ { + for i := 0; i < 10; i++ { if r.Int31n(2) == 0 { featureVec.Set(FeatureBit(i)) } @@ -420,8 +420,20 @@ func TestEmptyMessageUnknownType(t *testing.T) { // randCustomRecords generates a random set of custom records for testing. func randCustomRecords(t *testing.T, r *rand.Rand) CustomRecords { + customRecords := randTLVMap(t, r, MinCustomRecordsTlvType) + + // Validate the custom records as a sanity check. + err := CustomRecords(customRecords).Validate() + require.NoError(t, err) + + return customRecords +} + +func randTLVMap(t *testing.T, r *rand.Rand, + rangeStart uint64) map[uint64][]byte { + var ( - customRecords = CustomRecords{} + m = make(map[uint64][]byte) // We'll generate a random number of records, between 1 and 10. numRecords = r.Intn(9) + 1 @@ -432,21 +444,17 @@ func randCustomRecords(t *testing.T, r *rand.Rand) CustomRecords { // Keys must be equal to or greater than // MinCustomRecordsTlvType. keyOffset := uint64(r.Intn(100)) - key := MinCustomRecordsTlvType + keyOffset + key := rangeStart + keyOffset // Values are byte slices of any length. value := make([]byte, r.Intn(10)) _, err := r.Read(value) require.NoError(t, err) - customRecords[key] = value + m[key] = value } - // Validate the custom records as a sanity check. - err := customRecords.Validate() - require.NoError(t, err) - - return customRecords + return m } // TestLightningWireProtocol uses the testing/quick package to create a series @@ -1505,37 +1513,26 @@ func TestLightningWireProtocol(t *testing.T) { MsgAnnounceSignatures2: func(v []reflect.Value, r *rand.Rand) { - req := AnnounceSignatures2{ - ShortChannelID: NewShortChanIDFromInt( - uint64(r.Int63()), - ), - ExtraOpaqueData: make([]byte, 0), - } + var req AnnounceSignatures2 + + req.ExtraFieldsInSignedRange = randTLVMap( + t, r, 1000000000, + ) - _, err := r.Read(req.ChannelID[:]) + _, err := r.Read(req.ChannelID.Val[:]) require.NoError(t, err) partialSig, err := randPartialSig(r) require.NoError(t, err) - req.PartialSignature = *partialSig - - numExtraBytes := r.Int31n(1000) - if numExtraBytes > 0 { - req.ExtraOpaqueData = make( - []byte, numExtraBytes, - ) - _, err := r.Read(req.ExtraOpaqueData[:]) - require.NoError(t, err) - } + req.PartialSignature.Val = *partialSig v[0] = reflect.ValueOf(req) }, MsgChannelAnnouncement2: func(v []reflect.Value, r *rand.Rand) { - req := ChannelAnnouncement2{ - Signature: testSchnorrSig, - ExtraOpaqueData: make([]byte, 0), - } + req := ChannelAnnouncement2{} + + req.Signature.Val = testSchnorrSig req.ShortChannelID.Val = NewShortChanIDFromInt( uint64(r.Int63()), @@ -1584,23 +1581,20 @@ func TestLightningWireProtocol(t *testing.T) { } } - numExtraBytes := r.Int31n(1000) - if numExtraBytes > 0 { - req.ExtraOpaqueData = make( - []byte, numExtraBytes, - ) - _, err := r.Read(req.ExtraOpaqueData[:]) - require.NoError(t, err) - } + req.ExtraFieldsInSignedRange = randTLVMap( + t, r, 1000000000, + ) v[0] = reflect.ValueOf(req) }, MsgChannelUpdate2: func(v []reflect.Value, r *rand.Rand) { - req := ChannelUpdate2{ - Signature: testSchnorrSig, - ExtraOpaqueData: make([]byte, 0), - } + var req ChannelUpdate2 + + req.ExtraFieldsInSignedRange = randTLVMap( + t, r, 1000000000, + ) + req.Signature.Val = testSchnorrSig req.ShortChannelID.Val = NewShortChanIDFromInt( uint64(r.Int63()), ) @@ -1661,15 +1655,6 @@ func TestLightningWireProtocol(t *testing.T) { ChanUpdateDisableOutgoing } - numExtraBytes := r.Int31n(1000) - if numExtraBytes > 0 { - req.ExtraOpaqueData = make( - []byte, numExtraBytes, - ) - _, err := r.Read(req.ExtraOpaqueData[:]) - require.NoError(t, err) - } - v[0] = reflect.ValueOf(req) }, } diff --git a/lnwire/pure_tlv.go b/lnwire/pure_tlv.go new file mode 100644 index 0000000000..7c5ea77ffa --- /dev/null +++ b/lnwire/pure_tlv.go @@ -0,0 +1,89 @@ +package lnwire + +import ( + "bytes" + + "github.com/lightningnetwork/lnd/tlv" +) + +var ( + unsignedRangeOneStart tlv.TlvType160 + signedSecondRangeStart tlv.TlvType1000000000 + unsignedRangeTwoStart tlv.TlvType3000000000 +) + +// PureTLVMessage describes an LN message that is a pure TLV stream. If the +// message includes a signature, it will sign all the TLV records in the +// inclusive ranges: 0 to 159 and 1000000000 to 2999999999. +type PureTLVMessage interface { + // AllRecords returns all the TLV records for the message. This will + // include all the records we know about along with any that we don't + // know about but that fall in the signed TLV range. + AllRecords() []tlv.Record +} + +// EncodePureTLVMessage encodes the given PureTLVMessage to the given buffer. +func EncodePureTLVMessage(msg PureTLVMessage, buf *bytes.Buffer) error { + return EncodeRecordsTo(buf, msg.AllRecords()) +} + +// SerialiseFieldsToSign serialises all the records from the given +// PureTLVMessage that fall within the signed TLV range. +func SerialiseFieldsToSign(msg PureTLVMessage) ([]byte, error) { + // Filter out all the fields not in the signed ranges. + var signedRecords []tlv.Record + for _, record := range msg.AllRecords() { + if InUnsignedRange(record.Type()) { + continue + } + + signedRecords = append(signedRecords, record) + } + + var buf bytes.Buffer + if err := EncodeRecordsTo(&buf, signedRecords); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +// InUnsignedRange returns true if the given TLV type falls outside the TLV +// ranges that the signature of a pure TLV message will cover. +func InUnsignedRange(t tlv.Type) bool { + return (t >= unsignedRangeOneStart.TypeVal() && + t < signedSecondRangeStart.TypeVal()) || + t >= unsignedRangeTwoStart.TypeVal() +} + +// ExtraSignedFieldsFromTypeMap is a helper that can be used alongside calls to +// the tlv.Stream DecodeWithParsedTypesP2P or DecodeWithParsedTypes methods to +// extract the tlv type and value pairs in the defined PureTLVMessage signed +// range which we have not handled with any of our defined Records. These +// methods will return a tlv.TypeMap containing the records that were extracted +// from an io.Reader. If the record was know and handled by a defined record, +// then the value accompanying the record's type in the map will be nil. +// Otherwise, if the record was unhandled, it will be non-nil. +func ExtraSignedFieldsFromTypeMap(m tlv.TypeMap) map[uint64][]byte { + extraFields := make(map[uint64][]byte) + for t, v := range m { + // If the value in the type map is nil, then it indicates that + // we know this type, and it was handled by one of the records + // we passed to the decode function vai the TLV stream. + if v == nil { + continue + } + + // No need to keep this field if it is unknown to us and is not + // in the sign range. + if InUnsignedRange(t) { + continue + } + + // Otherwise, this is an un-handled type, so we keep track of + // it for signature validation and re-encoding later on. + extraFields[uint64(t)] = v + } + + return extraFields +} diff --git a/lnwire/pure_tlv_test.go b/lnwire/pure_tlv_test.go new file mode 100644 index 0000000000..30996f2ee1 --- /dev/null +++ b/lnwire/pure_tlv_test.go @@ -0,0 +1,361 @@ +package lnwire + +import ( + "bytes" + "io" + "testing" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/lightningnetwork/lnd/tlv" + "github.com/stretchr/testify/require" +) + +func TestPureTLVMessage(t *testing.T) { + t.Parallel() + + var ( + _, pkA = btcec.PrivKeyFromBytes([]byte{1}) + _, pkB = btcec.PrivKeyFromBytes([]byte{2}) + capacity = MilliSatoshi(100) + ) + + t.Run("Encode and Decode of GossipMsg1", func(t *testing.T) { + t.Parallel() + + // Test Encode and Decode of GossipMsg1. + msgOld := newMsgV1(pkA, &capacity) + + buf := bytes.NewBuffer(nil) + require.NoError(t, msgOld.Encode(buf, 0)) + + var msgOld2 MsgV1 + require.NoError(t, msgOld2.Decode(buf, 0)) + + require.Equal(t, msgOld, &msgOld2) + }) + + t.Run("Encode and Decode of GossipMsg2", func(t *testing.T) { + t.Parallel() + + // Test Encode and Decode of GossipMsg2. + msgNew := newMsgV2( + pkA, &capacity, pkB, []byte{1, 2, 3, 4}, 90, true, + ) + + buf := bytes.NewBuffer(nil) + require.NoError(t, msgNew.Encode(buf, 0)) + + var msgNew2 MsgV2 + require.NoError(t, msgNew2.Decode(buf, 0)) + + require.Equal(t, msgNew, &msgNew2) + }) + + t.Run("Encode Msg2 and decode via Msg1", func(t *testing.T) { + t.Parallel() + + // Ok cool, now try see if we can parse the new message with the + // old decoder. + var ( + buf = bytes.NewBuffer(nil) + msgNew = newMsgV2( + pkA, &capacity, pkB, []byte{1, 2, 3, 4}, 90, + true, + ) + ) + require.NoError(t, msgNew.Encode(buf, 0)) + + // Get the serialised bytes that would be signed for msgNew. + signData1, err := SerialiseFieldsToSign(msgNew) + require.NoError(t, err) + + // Decoding via the old message should store some of the extra + // fields. + var msgOld MsgV1 + require.NoError(t, msgOld.Decode(buf, 0)) + require.NotEmpty(t, msgOld.ExtraFieldsInSignedRange) + + // The serialised bytes to verify the signature against should + // be the same though. + signData2, err := SerialiseFieldsToSign(&msgOld) + require.NoError(t, err) + + require.Equal(t, signData1, signData2) + + // Re-encoding via the old message should keep the extra fields. + buf = bytes.NewBuffer(nil) + require.NoError(t, msgOld.Encode(buf, 0)) + + var msgOld2 MsgV1 + require.NoError(t, msgOld2.Decode(buf, 0)) + + require.Equal(t, &msgOld, &msgOld2) + }) +} + +// MsgV1 represents a more minimal, first version of a Lightning Network +// message. +type MsgV1 struct { + // Two known fields in the signed range. + NodeKey tlv.RecordT[tlv.TlvType0, *btcec.PublicKey] + Capacity tlv.OptionalRecordT[tlv.TlvType1, MilliSatoshi] + + // Signature in the unsigned range. + Signature tlv.RecordT[tlv.TlvType160, Sig] + + // Any extra fields in the signed range that we do not yet know about, + // but we need to keep them for signature validation and to produce a + // valid message. + ExtraFieldsInSignedRange map[uint64][]byte +} + +var _ Message = (*MsgV1)(nil) +var _ PureTLVMessage = (*MsgV1)(nil) + +// newMsgV1 is a constructor for MsgV1. +func newMsgV1(nodeKey *btcec.PublicKey, cap *MilliSatoshi) *MsgV1 { + newMsg := &MsgV1{ + NodeKey: tlv.NewPrimitiveRecord[tlv.TlvType0]( + nodeKey, + ), + Signature: tlv.NewRecordT[tlv.TlvType160]( + testSchnorrSig, + ), + ExtraFieldsInSignedRange: make(map[uint64][]byte), + } + + if cap != nil { + newMsg.Capacity = tlv.SomeRecordT( + tlv.NewPrimitiveRecord[tlv.TlvType1](*cap), + ) + } + + return newMsg +} + +// Decode deserializes a serialized MsgV1 in the passed io.Reader. +// +// This is part of the lnwire.Message interface. +func (g *MsgV1) Decode(r io.Reader, _ uint32) error { + var capacity = tlv.ZeroRecordT[tlv.TlvType1, MilliSatoshi]() + stream, err := tlv.NewStream( + ProduceRecordsSorted( + &g.NodeKey, + &capacity, + &g.Signature, + )..., + ) + if err != nil { + return err + } + g.Signature.Val.ForceSchnorr() + + typeMap, err := stream.DecodeWithParsedTypesP2P(r) + if err != nil { + return err + } + + if _, ok := typeMap[g.Capacity.TlvType()]; ok { + g.Capacity = tlv.SomeRecordT(capacity) + } + + g.ExtraFieldsInSignedRange = ExtraSignedFieldsFromTypeMap(typeMap) + + return nil +} + +// Encode serializes the target MsgV1 into the passed buffer. +// +// This is part of the lnwire.Message interface. +func (g *MsgV1) Encode(buf *bytes.Buffer, _ uint32) error { + return EncodePureTLVMessage(g, buf) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (g *MsgV1) MsgType() MessageType { + return 7777 +} + +// AllRecords returns all the TLV records for the message. This will +// include all the records we know about along with any that we don't +// know about but that fall in the signed TLV range. +// +// This is part of the PureTLVMessage interface. +func (g *MsgV1) AllRecords() []tlv.Record { + recordProducers := []tlv.RecordProducer{ + &g.NodeKey, + &g.Signature, + } + recordProducers = append( + recordProducers, + RecordsAsProducers( + tlv.MapToRecords(g.ExtraFieldsInSignedRange), + )..., + ) + + g.Capacity.WhenSome(func(cap tlv.RecordT[tlv.TlvType1, MilliSatoshi]) { + recordProducers = append(recordProducers, &cap) + }) + + return ProduceRecordsSorted(recordProducers...) +} + +// MsgV2 represents a newer version of MsgV1 which contains more fields both in +// the unsigned and signed TLV ranges. +type MsgV2 struct { + NodeKey tlv.RecordT[tlv.TlvType0, *btcec.PublicKey] + Capacity tlv.OptionalRecordT[tlv.TlvType1, MilliSatoshi] + + // An additional fields (optional) in the signed range. + BitcoinKey tlv.OptionalRecordT[tlv.TlvType3, *btcec.PublicKey] + + // A zero length TLV in the signed range. + SecondPeer tlv.OptionalRecordT[tlv.TlvType5, TrueBoolean] + + // Signature in the unsigned range. + Signature tlv.RecordT[tlv.TlvType160, Sig] + + // Another field in the unsigned range. An older node can throw this + // away. + SPVProof tlv.RecordT[tlv.TlvType161, []byte] + + // A new field in the second signed range. An older node should keep + // this since it is part of the serialised message that is signed. + Num tlv.RecordT[tlv.TlvType1000000000, uint8] + + // Any extra fields in the signed range that we do not yet know about, + // but we need to keep them for signature validation and to produce a + // valid message. + ExtraFieldsInSignedRange map[uint64][]byte +} + +// newMsgV2 is a constructor for MsgV2. +func newMsgV2(nodeKey *btcec.PublicKey, cap *MilliSatoshi, + btcKey *btcec.PublicKey, spvProof []byte, num uint8, + secondPeer bool) *MsgV2 { + + newMsg := &MsgV2{ + NodeKey: tlv.NewPrimitiveRecord[tlv.TlvType0](nodeKey), + SPVProof: tlv.NewPrimitiveRecord[tlv.TlvType161](spvProof), + Num: tlv.NewPrimitiveRecord[tlv.TlvType1000000000](num), + Signature: tlv.NewRecordT[tlv.TlvType160]( + testSchnorrSig, + ), + ExtraFieldsInSignedRange: make(map[uint64][]byte), + } + + if secondPeer { + newMsg.SecondPeer = tlv.SomeRecordT( + tlv.NewRecordT[tlv.TlvType5](TrueBoolean{}), + ) + } + + if cap != nil { + newMsg.Capacity = tlv.SomeRecordT( + tlv.NewPrimitiveRecord[tlv.TlvType1](*cap), + ) + } + + if btcKey != nil { + newMsg.BitcoinKey = tlv.SomeRecordT( + tlv.NewPrimitiveRecord[tlv.TlvType3](btcKey), + ) + } + + return newMsg +} + +// Decode deserializes a serialized MsgV2 in the passed io.Reader. +// +// This is part of the lnwire.Message interface. +func (g *MsgV2) Decode(r io.Reader, _ uint32) error { + var ( + capacity = tlv.ZeroRecordT[tlv.TlvType1, MilliSatoshi]() + btcKey = tlv.ZeroRecordT[tlv.TlvType3, *btcec.PublicKey]() + secondPeer = tlv.ZeroRecordT[tlv.TlvType5, TrueBoolean]() + ) + + stream, err := tlv.NewStream( + ProduceRecordsSorted( + &g.NodeKey, + &capacity, + &btcKey, + &secondPeer, + &g.Signature, + &g.SPVProof, + &g.Num, + )..., + ) + if err != nil { + return err + } + g.Signature.Val.ForceSchnorr() + + typeMap, err := stream.DecodeWithParsedTypesP2P(r) + if err != nil { + return err + } + + if _, ok := typeMap[g.Capacity.TlvType()]; ok { + g.Capacity = tlv.SomeRecordT(capacity) + } + + if _, ok := typeMap[g.SecondPeer.TlvType()]; ok { + g.SecondPeer = tlv.SomeRecordT(secondPeer) + } + + if _, ok := typeMap[g.BitcoinKey.TlvType()]; ok { + g.BitcoinKey = tlv.SomeRecordT(btcKey) + } + + g.ExtraFieldsInSignedRange = ExtraSignedFieldsFromTypeMap(typeMap) + + return nil +} + +// Encode serializes the target MsgV2 into the passed buffer. +// +// This is part of the lnwire.Message interface. +func (g *MsgV2) Encode(buf *bytes.Buffer, _ uint32) error { + return EncodePureTLVMessage(g, buf) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (g *MsgV2) MsgType() MessageType { + return 7779 +} + +// AllRecords returns all the TLV records for the message. This will +// include all the records we know about along with any that we don't +// know about but that fall in the signed TLV range. +// +// This is part of the PureTLVMessage interface. +func (g *MsgV2) AllRecords() []tlv.Record { + recordProducers := []tlv.RecordProducer{ + &g.NodeKey, + &g.Signature, + &g.SPVProof, + &g.Num, + } + recordProducers = append(recordProducers, RecordsAsProducers( + tlv.MapToRecords(g.ExtraFieldsInSignedRange), + )...) + + g.Capacity.WhenSome(func(cap tlv.RecordT[tlv.TlvType1, MilliSatoshi]) { + recordProducers = append(recordProducers, &cap) + }) + g.BitcoinKey.WhenSome(func(key tlv.RecordT[tlv.TlvType3, *btcec.PublicKey]) { + recordProducers = append(recordProducers, &key) + }) + g.SecondPeer.WhenSome(func(second tlv.RecordT[tlv.TlvType5, TrueBoolean]) { + recordProducers = append(recordProducers, &second) + }) + + return ProduceRecordsSorted(recordProducers...) +} diff --git a/netann/channel_announcement.go b/netann/channel_announcement.go index 345770d058..295fc19074 100644 --- a/netann/channel_announcement.go +++ b/netann/channel_announcement.go @@ -189,19 +189,19 @@ func createChanAnnouncement2(chanProof *models.ChannelAuthProof2, // authentication chanProof, we'll create re-create the original // authenticated channel announcement. chanAnn := &lnwire.ChannelAnnouncement2{ - ShortChannelID: chanInfo.ShortChannelID, - NodeID1: chanInfo.NodeID1, - NodeID2: chanInfo.NodeID2, - ChainHash: chanInfo.ChainHash, - BitcoinKey1: chanInfo.BitcoinKey1, - BitcoinKey2: chanInfo.BitcoinKey2, - Features: chanInfo.Features, - Capacity: chanInfo.Capacity, - ExtraOpaqueData: chanInfo.ExtraOpaqueData, + ShortChannelID: chanInfo.ShortChannelID, + NodeID1: chanInfo.NodeID1, + NodeID2: chanInfo.NodeID2, + ChainHash: chanInfo.ChainHash, + BitcoinKey1: chanInfo.BitcoinKey1, + BitcoinKey2: chanInfo.BitcoinKey2, + Features: chanInfo.Features, + Capacity: chanInfo.Capacity, + ExtraFieldsInSignedRange: chanInfo.ExtraFieldsInSignedRange, } var err error - chanAnn.Signature, err = lnwire.NewSigFromSchnorrRawSignature( + chanAnn.Signature.Val, err = lnwire.NewSigFromSchnorrRawSignature( chanProof.SchnorrSigBytes, ) if err != nil { @@ -333,7 +333,7 @@ func validateChannelAnn2(a *lnwire.ChannelAnnouncement2, return err } - sig, err := a.Signature.ToSignature() + sig, err := a.Signature.Val.ToSignature() if err != nil { return err } @@ -408,7 +408,7 @@ func validateChannelAnn2(a *lnwire.ChannelAnnouncement2, func ChanAnn2DigestToSign(a *lnwire.ChannelAnnouncement2) (*chainhash.Hash, error) { - data, err := a.DataToSign() + data, err := lnwire.SerialiseFieldsToSign(a) if err != nil { return nil, err } diff --git a/netann/channel_announcement_test.go b/netann/channel_announcement_test.go index 0190c7cf85..64aa308ef9 100644 --- a/netann/channel_announcement_test.go +++ b/netann/channel_announcement_test.go @@ -162,7 +162,7 @@ func test4of4MuSig2ChanAnnouncement(t *testing.T) { sig, err := lnwire.NewSigFromSignature(s) require.NoError(t, err) - ann.Signature = sig + ann.Signature.Val = sig // Validate the announcement. require.NoError(t, ValidateChannelAnn(ann, nil)) @@ -262,7 +262,7 @@ func test3of3MuSig2ChanAnnouncement(t *testing.T) { sig, err := lnwire.NewSigFromSignature(s) require.NoError(t, err) - ann.Signature = sig + ann.Signature.Val = sig // Validate the announcement. require.NoError(t, ValidateChannelAnn(ann, fetchTx)) diff --git a/netann/channel_update.go b/netann/channel_update.go index eb1d5ff2eb..1119e871ca 100644 --- a/netann/channel_update.go +++ b/netann/channel_update.go @@ -112,7 +112,7 @@ func SignChannelUpdate(signer keychain.MessageSignerRing, } case *lnwire.ChannelUpdate2: - data, err := upd.DataToSign() + data, err := lnwire.SerialiseFieldsToSign(upd) if err != nil { return err } @@ -124,7 +124,7 @@ func SignChannelUpdate(signer keychain.MessageSignerRing, return err } - upd.Signature, err = lnwire.NewSigFromSignature(sig) + upd.Signature.Val, err = lnwire.NewSigFromSignature(sig) if err != nil { return err } @@ -220,7 +220,7 @@ func unsignedChanPolicy2ToUpdate(chainHash chainhash.Hash, HTLCMaximumMsat: policy.HTLCMaximumMsat, FeeBaseMsat: policy.FeeBaseMsat, FeeProportionalMillionths: policy.FeeProportionalMillionths, - ExtraOpaqueData: policy.ExtraOpaqueData, + ExtraFieldsInSignedRange: policy.ExtraFieldsInSignedRange, } update.ChainHash.Val = chainHash @@ -256,7 +256,7 @@ func signedChannelUpdateFromEdge(chainHash chainhash.Hash, return update, nil case *models.ChannelEdgePolicy2: - sig, err := p.Signature.ToSignature() + sig, err := p.Signature.Val.ToSignature() if err != nil { return nil, err } @@ -267,7 +267,7 @@ func signedChannelUpdateFromEdge(chainHash chainhash.Hash, } update := unsignedChanPolicy2ToUpdate(chainHash, p) - update.Signature = s + update.Signature.Val = s return update, nil @@ -341,7 +341,7 @@ func verifyChannelUpdate2Signature(c *lnwire.ChannelUpdate2, return fmt.Errorf("unable to reconstruct message data: %w", err) } - nodeSig, err := c.Signature.ToSignature() + nodeSig, err := c.Signature.Val.ToSignature() if err != nil { return err } @@ -429,7 +429,7 @@ func ChanUpdate2DigestTag() []byte { // chanUpdate2DigestToSign computes the digest of the ChannelUpdate2 message to // be signed. func chanUpdate2DigestToSign(c *lnwire.ChannelUpdate2) ([]byte, error) { - data, err := c.DataToSign() + data, err := lnwire.SerialiseFieldsToSign(c) if err != nil { return nil, err } diff --git a/routing/localchans/manager.go b/routing/localchans/manager.go index 8ae46f8bd8..c829ea46a0 100644 --- a/routing/localchans/manager.go +++ b/routing/localchans/manager.go @@ -273,16 +273,16 @@ func (r *Manager) updateEdge(tx kvdb.RTx, chanPoint wire.OutPoint, edge.CLTVExpiryDelta.Val = uint16(newSchema.TimeLockDelta) // If inbound fees are set, we update the edge with them. - err := fn.MapOptionZ(newSchema.InboundFee, - func(f models.InboundFee) error { - inboundWireFee := f.ToWire() - return edge.ExtraOpaqueData.PackRecords( - &inboundWireFee, - ) - }) - if err != nil { - return err - } + //err := fn.MapOptionZ(newSchema.InboundFee, + // func(f models.InboundFee) error { + // inboundWireFee := f.ToWire() + // return edge.ExtraOpaqueData.PackRecords( + // &inboundWireFee, + // ) + // }) + //if err != nil { + // return err + //} // Retrieve negotiated channel htlc amt limits. amtMin, amtMax, err := r.getHtlcAmtLimits(tx, chanPoint) @@ -335,7 +335,7 @@ func (r *Manager) updateEdge(tx kvdb.RTx, chanPoint wire.OutPoint, // Clear signature to help prevent usage of the previous // signature. - edge.Signature = lnwire.Sig{} + edge.Signature.Val = lnwire.Sig{} default: return fmt.Errorf("unhandled implementation of "+ diff --git a/rpcserver.go b/rpcserver.go index 21d8521dac..84d3a5d678 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -6628,7 +6628,7 @@ func marshalDBEdge(edgeInfo models.ChannelEdgeInfo, customRecords := marshalExtraOpaqueData(info.ExtraOpaqueData) edge.CustomRecords = customRecords case *models.ChannelEdgeInfo2: - customRecords := marshalExtraOpaqueData(info.ExtraOpaqueData) + customRecords := info.ExtraFieldsInSignedRange edge.CustomRecords = customRecords default: return nil, fmt.Errorf("unhandled implementation of "+ @@ -6663,7 +6663,7 @@ func marshalDBRoutingPolicy(policy models.ChannelEdgePolicy) ( routingPolicy.InboundFeeRateMilliMsat = inboundFee.FeeRate case *models.ChannelEdgePolicy2: - customRecords := marshalExtraOpaqueData(p.ExtraOpaqueData) + customRecords := p.ExtraFieldsInSignedRange routingPolicy.CustomRecords = customRecords routingPolicy.BlockHeight = p.BlockHeight.Val diff --git a/tlv/internal/gen/gen_tlv_types.go b/tlv/internal/gen/gen_tlv_types.go index 331d10b646..50671d7346 100644 --- a/tlv/internal/gen/gen_tlv_types.go +++ b/tlv/internal/gen/gen_tlv_types.go @@ -8,14 +8,23 @@ import ( ) const ( - numberOfTypes uint32 = 100 + numberOfTypes uint32 = 300 // customTypeStart defines the beginning of the custom TLV type range as // defined in BOLT-01. - customTypeStart uint32 = 65536 - defaultOutputFile = "tlv_types_generated.go" + customTypeStart uint32 = 65536 + + pureTLVSecondSignedTypeRangeStart uint32 = 1000000000 + pureTLVSecondUnsignedTypeRangeStart uint32 = 3000000000 + + defaultOutputFile = "tlv_types_generated.go" ) +var typeMarkers = map[uint32]struct{}{ + pureTLVSecondSignedTypeRangeStart: {}, + pureTLVSecondUnsignedTypeRangeStart: {}, +} + const typeCodeTemplate = `// Code generated by tlv/internal/gen; DO NOT EDIT. package tlv @@ -50,6 +59,11 @@ func main() { items[i] = struct{}{} } + // We'll also generate any marker types. + for t := range typeMarkers { + items[t] = struct{}{} + } + tpl, err := template.New("tlv").Parse(typeCodeTemplate) if err != nil { panic(err) diff --git a/tlv/tlv_types_generated.go b/tlv/tlv_types_generated.go index c75a86232b..9a80f9364e 100644 --- a/tlv/tlv_types_generated.go +++ b/tlv/tlv_types_generated.go @@ -1012,1012 +1012,5032 @@ func (t *tlvType100) tlv() {} type TlvType100 = *tlvType100 +type tlvType101 struct{} + +func (t *tlvType101) TypeVal() Type { + return 101 +} + +func (t *tlvType101) tlv() {} + +type TlvType101 = *tlvType101 + +type tlvType102 struct{} + +func (t *tlvType102) TypeVal() Type { + return 102 +} + +func (t *tlvType102) tlv() {} + +type TlvType102 = *tlvType102 + +type tlvType103 struct{} + +func (t *tlvType103) TypeVal() Type { + return 103 +} + +func (t *tlvType103) tlv() {} + +type TlvType103 = *tlvType103 + +type tlvType104 struct{} + +func (t *tlvType104) TypeVal() Type { + return 104 +} + +func (t *tlvType104) tlv() {} + +type TlvType104 = *tlvType104 + +type tlvType105 struct{} + +func (t *tlvType105) TypeVal() Type { + return 105 +} + +func (t *tlvType105) tlv() {} + +type TlvType105 = *tlvType105 + +type tlvType106 struct{} + +func (t *tlvType106) TypeVal() Type { + return 106 +} + +func (t *tlvType106) tlv() {} + +type TlvType106 = *tlvType106 + +type tlvType107 struct{} + +func (t *tlvType107) TypeVal() Type { + return 107 +} + +func (t *tlvType107) tlv() {} + +type TlvType107 = *tlvType107 + +type tlvType108 struct{} + +func (t *tlvType108) TypeVal() Type { + return 108 +} + +func (t *tlvType108) tlv() {} + +type TlvType108 = *tlvType108 + +type tlvType109 struct{} + +func (t *tlvType109) TypeVal() Type { + return 109 +} + +func (t *tlvType109) tlv() {} + +type TlvType109 = *tlvType109 + +type tlvType110 struct{} + +func (t *tlvType110) TypeVal() Type { + return 110 +} + +func (t *tlvType110) tlv() {} + +type TlvType110 = *tlvType110 + +type tlvType111 struct{} + +func (t *tlvType111) TypeVal() Type { + return 111 +} + +func (t *tlvType111) tlv() {} + +type TlvType111 = *tlvType111 + +type tlvType112 struct{} + +func (t *tlvType112) TypeVal() Type { + return 112 +} + +func (t *tlvType112) tlv() {} + +type TlvType112 = *tlvType112 + +type tlvType113 struct{} + +func (t *tlvType113) TypeVal() Type { + return 113 +} + +func (t *tlvType113) tlv() {} + +type TlvType113 = *tlvType113 + +type tlvType114 struct{} + +func (t *tlvType114) TypeVal() Type { + return 114 +} + +func (t *tlvType114) tlv() {} + +type TlvType114 = *tlvType114 + +type tlvType115 struct{} + +func (t *tlvType115) TypeVal() Type { + return 115 +} + +func (t *tlvType115) tlv() {} + +type TlvType115 = *tlvType115 + +type tlvType116 struct{} + +func (t *tlvType116) TypeVal() Type { + return 116 +} + +func (t *tlvType116) tlv() {} + +type TlvType116 = *tlvType116 + +type tlvType117 struct{} + +func (t *tlvType117) TypeVal() Type { + return 117 +} + +func (t *tlvType117) tlv() {} + +type TlvType117 = *tlvType117 + +type tlvType118 struct{} + +func (t *tlvType118) TypeVal() Type { + return 118 +} + +func (t *tlvType118) tlv() {} + +type TlvType118 = *tlvType118 + +type tlvType119 struct{} + +func (t *tlvType119) TypeVal() Type { + return 119 +} + +func (t *tlvType119) tlv() {} + +type TlvType119 = *tlvType119 + +type tlvType120 struct{} + +func (t *tlvType120) TypeVal() Type { + return 120 +} + +func (t *tlvType120) tlv() {} + +type TlvType120 = *tlvType120 + +type tlvType121 struct{} + +func (t *tlvType121) TypeVal() Type { + return 121 +} + +func (t *tlvType121) tlv() {} + +type TlvType121 = *tlvType121 + +type tlvType122 struct{} + +func (t *tlvType122) TypeVal() Type { + return 122 +} + +func (t *tlvType122) tlv() {} + +type TlvType122 = *tlvType122 + +type tlvType123 struct{} + +func (t *tlvType123) TypeVal() Type { + return 123 +} + +func (t *tlvType123) tlv() {} + +type TlvType123 = *tlvType123 + +type tlvType124 struct{} + +func (t *tlvType124) TypeVal() Type { + return 124 +} + +func (t *tlvType124) tlv() {} + +type TlvType124 = *tlvType124 + +type tlvType125 struct{} + +func (t *tlvType125) TypeVal() Type { + return 125 +} + +func (t *tlvType125) tlv() {} + +type TlvType125 = *tlvType125 + +type tlvType126 struct{} + +func (t *tlvType126) TypeVal() Type { + return 126 +} + +func (t *tlvType126) tlv() {} + +type TlvType126 = *tlvType126 + +type tlvType127 struct{} + +func (t *tlvType127) TypeVal() Type { + return 127 +} + +func (t *tlvType127) tlv() {} + +type TlvType127 = *tlvType127 + +type tlvType128 struct{} + +func (t *tlvType128) TypeVal() Type { + return 128 +} + +func (t *tlvType128) tlv() {} + +type TlvType128 = *tlvType128 + +type tlvType129 struct{} + +func (t *tlvType129) TypeVal() Type { + return 129 +} + +func (t *tlvType129) tlv() {} + +type TlvType129 = *tlvType129 + +type tlvType130 struct{} + +func (t *tlvType130) TypeVal() Type { + return 130 +} + +func (t *tlvType130) tlv() {} + +type TlvType130 = *tlvType130 + +type tlvType131 struct{} + +func (t *tlvType131) TypeVal() Type { + return 131 +} + +func (t *tlvType131) tlv() {} + +type TlvType131 = *tlvType131 + +type tlvType132 struct{} + +func (t *tlvType132) TypeVal() Type { + return 132 +} + +func (t *tlvType132) tlv() {} + +type TlvType132 = *tlvType132 + +type tlvType133 struct{} + +func (t *tlvType133) TypeVal() Type { + return 133 +} + +func (t *tlvType133) tlv() {} + +type TlvType133 = *tlvType133 + +type tlvType134 struct{} + +func (t *tlvType134) TypeVal() Type { + return 134 +} + +func (t *tlvType134) tlv() {} + +type TlvType134 = *tlvType134 + +type tlvType135 struct{} + +func (t *tlvType135) TypeVal() Type { + return 135 +} + +func (t *tlvType135) tlv() {} + +type TlvType135 = *tlvType135 + +type tlvType136 struct{} + +func (t *tlvType136) TypeVal() Type { + return 136 +} + +func (t *tlvType136) tlv() {} + +type TlvType136 = *tlvType136 + +type tlvType137 struct{} + +func (t *tlvType137) TypeVal() Type { + return 137 +} + +func (t *tlvType137) tlv() {} + +type TlvType137 = *tlvType137 + +type tlvType138 struct{} + +func (t *tlvType138) TypeVal() Type { + return 138 +} + +func (t *tlvType138) tlv() {} + +type TlvType138 = *tlvType138 + +type tlvType139 struct{} + +func (t *tlvType139) TypeVal() Type { + return 139 +} + +func (t *tlvType139) tlv() {} + +type TlvType139 = *tlvType139 + +type tlvType140 struct{} + +func (t *tlvType140) TypeVal() Type { + return 140 +} + +func (t *tlvType140) tlv() {} + +type TlvType140 = *tlvType140 + +type tlvType141 struct{} + +func (t *tlvType141) TypeVal() Type { + return 141 +} + +func (t *tlvType141) tlv() {} + +type TlvType141 = *tlvType141 + +type tlvType142 struct{} + +func (t *tlvType142) TypeVal() Type { + return 142 +} + +func (t *tlvType142) tlv() {} + +type TlvType142 = *tlvType142 + +type tlvType143 struct{} + +func (t *tlvType143) TypeVal() Type { + return 143 +} + +func (t *tlvType143) tlv() {} + +type TlvType143 = *tlvType143 + +type tlvType144 struct{} + +func (t *tlvType144) TypeVal() Type { + return 144 +} + +func (t *tlvType144) tlv() {} + +type TlvType144 = *tlvType144 + +type tlvType145 struct{} + +func (t *tlvType145) TypeVal() Type { + return 145 +} + +func (t *tlvType145) tlv() {} + +type TlvType145 = *tlvType145 + +type tlvType146 struct{} + +func (t *tlvType146) TypeVal() Type { + return 146 +} + +func (t *tlvType146) tlv() {} + +type TlvType146 = *tlvType146 + +type tlvType147 struct{} + +func (t *tlvType147) TypeVal() Type { + return 147 +} + +func (t *tlvType147) tlv() {} + +type TlvType147 = *tlvType147 + +type tlvType148 struct{} + +func (t *tlvType148) TypeVal() Type { + return 148 +} + +func (t *tlvType148) tlv() {} + +type TlvType148 = *tlvType148 + +type tlvType149 struct{} + +func (t *tlvType149) TypeVal() Type { + return 149 +} + +func (t *tlvType149) tlv() {} + +type TlvType149 = *tlvType149 + +type tlvType150 struct{} + +func (t *tlvType150) TypeVal() Type { + return 150 +} + +func (t *tlvType150) tlv() {} + +type TlvType150 = *tlvType150 + +type tlvType151 struct{} + +func (t *tlvType151) TypeVal() Type { + return 151 +} + +func (t *tlvType151) tlv() {} + +type TlvType151 = *tlvType151 + +type tlvType152 struct{} + +func (t *tlvType152) TypeVal() Type { + return 152 +} + +func (t *tlvType152) tlv() {} + +type TlvType152 = *tlvType152 + +type tlvType153 struct{} + +func (t *tlvType153) TypeVal() Type { + return 153 +} + +func (t *tlvType153) tlv() {} + +type TlvType153 = *tlvType153 + +type tlvType154 struct{} + +func (t *tlvType154) TypeVal() Type { + return 154 +} + +func (t *tlvType154) tlv() {} + +type TlvType154 = *tlvType154 + +type tlvType155 struct{} + +func (t *tlvType155) TypeVal() Type { + return 155 +} + +func (t *tlvType155) tlv() {} + +type TlvType155 = *tlvType155 + +type tlvType156 struct{} + +func (t *tlvType156) TypeVal() Type { + return 156 +} + +func (t *tlvType156) tlv() {} + +type TlvType156 = *tlvType156 + +type tlvType157 struct{} + +func (t *tlvType157) TypeVal() Type { + return 157 +} + +func (t *tlvType157) tlv() {} + +type TlvType157 = *tlvType157 + +type tlvType158 struct{} + +func (t *tlvType158) TypeVal() Type { + return 158 +} + +func (t *tlvType158) tlv() {} + +type TlvType158 = *tlvType158 + +type tlvType159 struct{} + +func (t *tlvType159) TypeVal() Type { + return 159 +} + +func (t *tlvType159) tlv() {} + +type TlvType159 = *tlvType159 + +type tlvType160 struct{} + +func (t *tlvType160) TypeVal() Type { + return 160 +} + +func (t *tlvType160) tlv() {} + +type TlvType160 = *tlvType160 + +type tlvType161 struct{} + +func (t *tlvType161) TypeVal() Type { + return 161 +} + +func (t *tlvType161) tlv() {} + +type TlvType161 = *tlvType161 + +type tlvType162 struct{} + +func (t *tlvType162) TypeVal() Type { + return 162 +} + +func (t *tlvType162) tlv() {} + +type TlvType162 = *tlvType162 + +type tlvType163 struct{} + +func (t *tlvType163) TypeVal() Type { + return 163 +} + +func (t *tlvType163) tlv() {} + +type TlvType163 = *tlvType163 + +type tlvType164 struct{} + +func (t *tlvType164) TypeVal() Type { + return 164 +} + +func (t *tlvType164) tlv() {} + +type TlvType164 = *tlvType164 + +type tlvType165 struct{} + +func (t *tlvType165) TypeVal() Type { + return 165 +} + +func (t *tlvType165) tlv() {} + +type TlvType165 = *tlvType165 + +type tlvType166 struct{} + +func (t *tlvType166) TypeVal() Type { + return 166 +} + +func (t *tlvType166) tlv() {} + +type TlvType166 = *tlvType166 + +type tlvType167 struct{} + +func (t *tlvType167) TypeVal() Type { + return 167 +} + +func (t *tlvType167) tlv() {} + +type TlvType167 = *tlvType167 + +type tlvType168 struct{} + +func (t *tlvType168) TypeVal() Type { + return 168 +} + +func (t *tlvType168) tlv() {} + +type TlvType168 = *tlvType168 + +type tlvType169 struct{} + +func (t *tlvType169) TypeVal() Type { + return 169 +} + +func (t *tlvType169) tlv() {} + +type TlvType169 = *tlvType169 + +type tlvType170 struct{} + +func (t *tlvType170) TypeVal() Type { + return 170 +} + +func (t *tlvType170) tlv() {} + +type TlvType170 = *tlvType170 + +type tlvType171 struct{} + +func (t *tlvType171) TypeVal() Type { + return 171 +} + +func (t *tlvType171) tlv() {} + +type TlvType171 = *tlvType171 + +type tlvType172 struct{} + +func (t *tlvType172) TypeVal() Type { + return 172 +} + +func (t *tlvType172) tlv() {} + +type TlvType172 = *tlvType172 + +type tlvType173 struct{} + +func (t *tlvType173) TypeVal() Type { + return 173 +} + +func (t *tlvType173) tlv() {} + +type TlvType173 = *tlvType173 + +type tlvType174 struct{} + +func (t *tlvType174) TypeVal() Type { + return 174 +} + +func (t *tlvType174) tlv() {} + +type TlvType174 = *tlvType174 + +type tlvType175 struct{} + +func (t *tlvType175) TypeVal() Type { + return 175 +} + +func (t *tlvType175) tlv() {} + +type TlvType175 = *tlvType175 + +type tlvType176 struct{} + +func (t *tlvType176) TypeVal() Type { + return 176 +} + +func (t *tlvType176) tlv() {} + +type TlvType176 = *tlvType176 + +type tlvType177 struct{} + +func (t *tlvType177) TypeVal() Type { + return 177 +} + +func (t *tlvType177) tlv() {} + +type TlvType177 = *tlvType177 + +type tlvType178 struct{} + +func (t *tlvType178) TypeVal() Type { + return 178 +} + +func (t *tlvType178) tlv() {} + +type TlvType178 = *tlvType178 + +type tlvType179 struct{} + +func (t *tlvType179) TypeVal() Type { + return 179 +} + +func (t *tlvType179) tlv() {} + +type TlvType179 = *tlvType179 + +type tlvType180 struct{} + +func (t *tlvType180) TypeVal() Type { + return 180 +} + +func (t *tlvType180) tlv() {} + +type TlvType180 = *tlvType180 + +type tlvType181 struct{} + +func (t *tlvType181) TypeVal() Type { + return 181 +} + +func (t *tlvType181) tlv() {} + +type TlvType181 = *tlvType181 + +type tlvType182 struct{} + +func (t *tlvType182) TypeVal() Type { + return 182 +} + +func (t *tlvType182) tlv() {} + +type TlvType182 = *tlvType182 + +type tlvType183 struct{} + +func (t *tlvType183) TypeVal() Type { + return 183 +} + +func (t *tlvType183) tlv() {} + +type TlvType183 = *tlvType183 + +type tlvType184 struct{} + +func (t *tlvType184) TypeVal() Type { + return 184 +} + +func (t *tlvType184) tlv() {} + +type TlvType184 = *tlvType184 + +type tlvType185 struct{} + +func (t *tlvType185) TypeVal() Type { + return 185 +} + +func (t *tlvType185) tlv() {} + +type TlvType185 = *tlvType185 + +type tlvType186 struct{} + +func (t *tlvType186) TypeVal() Type { + return 186 +} + +func (t *tlvType186) tlv() {} + +type TlvType186 = *tlvType186 + +type tlvType187 struct{} + +func (t *tlvType187) TypeVal() Type { + return 187 +} + +func (t *tlvType187) tlv() {} + +type TlvType187 = *tlvType187 + +type tlvType188 struct{} + +func (t *tlvType188) TypeVal() Type { + return 188 +} + +func (t *tlvType188) tlv() {} + +type TlvType188 = *tlvType188 + +type tlvType189 struct{} + +func (t *tlvType189) TypeVal() Type { + return 189 +} + +func (t *tlvType189) tlv() {} + +type TlvType189 = *tlvType189 + +type tlvType190 struct{} + +func (t *tlvType190) TypeVal() Type { + return 190 +} + +func (t *tlvType190) tlv() {} + +type TlvType190 = *tlvType190 + +type tlvType191 struct{} + +func (t *tlvType191) TypeVal() Type { + return 191 +} + +func (t *tlvType191) tlv() {} + +type TlvType191 = *tlvType191 + +type tlvType192 struct{} + +func (t *tlvType192) TypeVal() Type { + return 192 +} + +func (t *tlvType192) tlv() {} + +type TlvType192 = *tlvType192 + +type tlvType193 struct{} + +func (t *tlvType193) TypeVal() Type { + return 193 +} + +func (t *tlvType193) tlv() {} + +type TlvType193 = *tlvType193 + +type tlvType194 struct{} + +func (t *tlvType194) TypeVal() Type { + return 194 +} + +func (t *tlvType194) tlv() {} + +type TlvType194 = *tlvType194 + +type tlvType195 struct{} + +func (t *tlvType195) TypeVal() Type { + return 195 +} + +func (t *tlvType195) tlv() {} + +type TlvType195 = *tlvType195 + +type tlvType196 struct{} + +func (t *tlvType196) TypeVal() Type { + return 196 +} + +func (t *tlvType196) tlv() {} + +type TlvType196 = *tlvType196 + +type tlvType197 struct{} + +func (t *tlvType197) TypeVal() Type { + return 197 +} + +func (t *tlvType197) tlv() {} + +type TlvType197 = *tlvType197 + +type tlvType198 struct{} + +func (t *tlvType198) TypeVal() Type { + return 198 +} + +func (t *tlvType198) tlv() {} + +type TlvType198 = *tlvType198 + +type tlvType199 struct{} + +func (t *tlvType199) TypeVal() Type { + return 199 +} + +func (t *tlvType199) tlv() {} + +type TlvType199 = *tlvType199 + +type tlvType200 struct{} + +func (t *tlvType200) TypeVal() Type { + return 200 +} + +func (t *tlvType200) tlv() {} + +type TlvType200 = *tlvType200 + +type tlvType201 struct{} + +func (t *tlvType201) TypeVal() Type { + return 201 +} + +func (t *tlvType201) tlv() {} + +type TlvType201 = *tlvType201 + +type tlvType202 struct{} + +func (t *tlvType202) TypeVal() Type { + return 202 +} + +func (t *tlvType202) tlv() {} + +type TlvType202 = *tlvType202 + +type tlvType203 struct{} + +func (t *tlvType203) TypeVal() Type { + return 203 +} + +func (t *tlvType203) tlv() {} + +type TlvType203 = *tlvType203 + +type tlvType204 struct{} + +func (t *tlvType204) TypeVal() Type { + return 204 +} + +func (t *tlvType204) tlv() {} + +type TlvType204 = *tlvType204 + +type tlvType205 struct{} + +func (t *tlvType205) TypeVal() Type { + return 205 +} + +func (t *tlvType205) tlv() {} + +type TlvType205 = *tlvType205 + +type tlvType206 struct{} + +func (t *tlvType206) TypeVal() Type { + return 206 +} + +func (t *tlvType206) tlv() {} + +type TlvType206 = *tlvType206 + +type tlvType207 struct{} + +func (t *tlvType207) TypeVal() Type { + return 207 +} + +func (t *tlvType207) tlv() {} + +type TlvType207 = *tlvType207 + +type tlvType208 struct{} + +func (t *tlvType208) TypeVal() Type { + return 208 +} + +func (t *tlvType208) tlv() {} + +type TlvType208 = *tlvType208 + +type tlvType209 struct{} + +func (t *tlvType209) TypeVal() Type { + return 209 +} + +func (t *tlvType209) tlv() {} + +type TlvType209 = *tlvType209 + +type tlvType210 struct{} + +func (t *tlvType210) TypeVal() Type { + return 210 +} + +func (t *tlvType210) tlv() {} + +type TlvType210 = *tlvType210 + +type tlvType211 struct{} + +func (t *tlvType211) TypeVal() Type { + return 211 +} + +func (t *tlvType211) tlv() {} + +type TlvType211 = *tlvType211 + +type tlvType212 struct{} + +func (t *tlvType212) TypeVal() Type { + return 212 +} + +func (t *tlvType212) tlv() {} + +type TlvType212 = *tlvType212 + +type tlvType213 struct{} + +func (t *tlvType213) TypeVal() Type { + return 213 +} + +func (t *tlvType213) tlv() {} + +type TlvType213 = *tlvType213 + +type tlvType214 struct{} + +func (t *tlvType214) TypeVal() Type { + return 214 +} + +func (t *tlvType214) tlv() {} + +type TlvType214 = *tlvType214 + +type tlvType215 struct{} + +func (t *tlvType215) TypeVal() Type { + return 215 +} + +func (t *tlvType215) tlv() {} + +type TlvType215 = *tlvType215 + +type tlvType216 struct{} + +func (t *tlvType216) TypeVal() Type { + return 216 +} + +func (t *tlvType216) tlv() {} + +type TlvType216 = *tlvType216 + +type tlvType217 struct{} + +func (t *tlvType217) TypeVal() Type { + return 217 +} + +func (t *tlvType217) tlv() {} + +type TlvType217 = *tlvType217 + +type tlvType218 struct{} + +func (t *tlvType218) TypeVal() Type { + return 218 +} + +func (t *tlvType218) tlv() {} + +type TlvType218 = *tlvType218 + +type tlvType219 struct{} + +func (t *tlvType219) TypeVal() Type { + return 219 +} + +func (t *tlvType219) tlv() {} + +type TlvType219 = *tlvType219 + +type tlvType220 struct{} + +func (t *tlvType220) TypeVal() Type { + return 220 +} + +func (t *tlvType220) tlv() {} + +type TlvType220 = *tlvType220 + +type tlvType221 struct{} + +func (t *tlvType221) TypeVal() Type { + return 221 +} + +func (t *tlvType221) tlv() {} + +type TlvType221 = *tlvType221 + +type tlvType222 struct{} + +func (t *tlvType222) TypeVal() Type { + return 222 +} + +func (t *tlvType222) tlv() {} + +type TlvType222 = *tlvType222 + +type tlvType223 struct{} + +func (t *tlvType223) TypeVal() Type { + return 223 +} + +func (t *tlvType223) tlv() {} + +type TlvType223 = *tlvType223 + +type tlvType224 struct{} + +func (t *tlvType224) TypeVal() Type { + return 224 +} + +func (t *tlvType224) tlv() {} + +type TlvType224 = *tlvType224 + +type tlvType225 struct{} + +func (t *tlvType225) TypeVal() Type { + return 225 +} + +func (t *tlvType225) tlv() {} + +type TlvType225 = *tlvType225 + +type tlvType226 struct{} + +func (t *tlvType226) TypeVal() Type { + return 226 +} + +func (t *tlvType226) tlv() {} + +type TlvType226 = *tlvType226 + +type tlvType227 struct{} + +func (t *tlvType227) TypeVal() Type { + return 227 +} + +func (t *tlvType227) tlv() {} + +type TlvType227 = *tlvType227 + +type tlvType228 struct{} + +func (t *tlvType228) TypeVal() Type { + return 228 +} + +func (t *tlvType228) tlv() {} + +type TlvType228 = *tlvType228 + +type tlvType229 struct{} + +func (t *tlvType229) TypeVal() Type { + return 229 +} + +func (t *tlvType229) tlv() {} + +type TlvType229 = *tlvType229 + +type tlvType230 struct{} + +func (t *tlvType230) TypeVal() Type { + return 230 +} + +func (t *tlvType230) tlv() {} + +type TlvType230 = *tlvType230 + +type tlvType231 struct{} + +func (t *tlvType231) TypeVal() Type { + return 231 +} + +func (t *tlvType231) tlv() {} + +type TlvType231 = *tlvType231 + +type tlvType232 struct{} + +func (t *tlvType232) TypeVal() Type { + return 232 +} + +func (t *tlvType232) tlv() {} + +type TlvType232 = *tlvType232 + +type tlvType233 struct{} + +func (t *tlvType233) TypeVal() Type { + return 233 +} + +func (t *tlvType233) tlv() {} + +type TlvType233 = *tlvType233 + +type tlvType234 struct{} + +func (t *tlvType234) TypeVal() Type { + return 234 +} + +func (t *tlvType234) tlv() {} + +type TlvType234 = *tlvType234 + +type tlvType235 struct{} + +func (t *tlvType235) TypeVal() Type { + return 235 +} + +func (t *tlvType235) tlv() {} + +type TlvType235 = *tlvType235 + +type tlvType236 struct{} + +func (t *tlvType236) TypeVal() Type { + return 236 +} + +func (t *tlvType236) tlv() {} + +type TlvType236 = *tlvType236 + +type tlvType237 struct{} + +func (t *tlvType237) TypeVal() Type { + return 237 +} + +func (t *tlvType237) tlv() {} + +type TlvType237 = *tlvType237 + +type tlvType238 struct{} + +func (t *tlvType238) TypeVal() Type { + return 238 +} + +func (t *tlvType238) tlv() {} + +type TlvType238 = *tlvType238 + +type tlvType239 struct{} + +func (t *tlvType239) TypeVal() Type { + return 239 +} + +func (t *tlvType239) tlv() {} + +type TlvType239 = *tlvType239 + +type tlvType240 struct{} + +func (t *tlvType240) TypeVal() Type { + return 240 +} + +func (t *tlvType240) tlv() {} + +type TlvType240 = *tlvType240 + +type tlvType241 struct{} + +func (t *tlvType241) TypeVal() Type { + return 241 +} + +func (t *tlvType241) tlv() {} + +type TlvType241 = *tlvType241 + +type tlvType242 struct{} + +func (t *tlvType242) TypeVal() Type { + return 242 +} + +func (t *tlvType242) tlv() {} + +type TlvType242 = *tlvType242 + +type tlvType243 struct{} + +func (t *tlvType243) TypeVal() Type { + return 243 +} + +func (t *tlvType243) tlv() {} + +type TlvType243 = *tlvType243 + +type tlvType244 struct{} + +func (t *tlvType244) TypeVal() Type { + return 244 +} + +func (t *tlvType244) tlv() {} + +type TlvType244 = *tlvType244 + +type tlvType245 struct{} + +func (t *tlvType245) TypeVal() Type { + return 245 +} + +func (t *tlvType245) tlv() {} + +type TlvType245 = *tlvType245 + +type tlvType246 struct{} + +func (t *tlvType246) TypeVal() Type { + return 246 +} + +func (t *tlvType246) tlv() {} + +type TlvType246 = *tlvType246 + +type tlvType247 struct{} + +func (t *tlvType247) TypeVal() Type { + return 247 +} + +func (t *tlvType247) tlv() {} + +type TlvType247 = *tlvType247 + +type tlvType248 struct{} + +func (t *tlvType248) TypeVal() Type { + return 248 +} + +func (t *tlvType248) tlv() {} + +type TlvType248 = *tlvType248 + +type tlvType249 struct{} + +func (t *tlvType249) TypeVal() Type { + return 249 +} + +func (t *tlvType249) tlv() {} + +type TlvType249 = *tlvType249 + +type tlvType250 struct{} + +func (t *tlvType250) TypeVal() Type { + return 250 +} + +func (t *tlvType250) tlv() {} + +type TlvType250 = *tlvType250 + +type tlvType251 struct{} + +func (t *tlvType251) TypeVal() Type { + return 251 +} + +func (t *tlvType251) tlv() {} + +type TlvType251 = *tlvType251 + +type tlvType252 struct{} + +func (t *tlvType252) TypeVal() Type { + return 252 +} + +func (t *tlvType252) tlv() {} + +type TlvType252 = *tlvType252 + +type tlvType253 struct{} + +func (t *tlvType253) TypeVal() Type { + return 253 +} + +func (t *tlvType253) tlv() {} + +type TlvType253 = *tlvType253 + +type tlvType254 struct{} + +func (t *tlvType254) TypeVal() Type { + return 254 +} + +func (t *tlvType254) tlv() {} + +type TlvType254 = *tlvType254 + +type tlvType255 struct{} + +func (t *tlvType255) TypeVal() Type { + return 255 +} + +func (t *tlvType255) tlv() {} + +type TlvType255 = *tlvType255 + +type tlvType256 struct{} + +func (t *tlvType256) TypeVal() Type { + return 256 +} + +func (t *tlvType256) tlv() {} + +type TlvType256 = *tlvType256 + +type tlvType257 struct{} + +func (t *tlvType257) TypeVal() Type { + return 257 +} + +func (t *tlvType257) tlv() {} + +type TlvType257 = *tlvType257 + +type tlvType258 struct{} + +func (t *tlvType258) TypeVal() Type { + return 258 +} + +func (t *tlvType258) tlv() {} + +type TlvType258 = *tlvType258 + +type tlvType259 struct{} + +func (t *tlvType259) TypeVal() Type { + return 259 +} + +func (t *tlvType259) tlv() {} + +type TlvType259 = *tlvType259 + +type tlvType260 struct{} + +func (t *tlvType260) TypeVal() Type { + return 260 +} + +func (t *tlvType260) tlv() {} + +type TlvType260 = *tlvType260 + +type tlvType261 struct{} + +func (t *tlvType261) TypeVal() Type { + return 261 +} + +func (t *tlvType261) tlv() {} + +type TlvType261 = *tlvType261 + +type tlvType262 struct{} + +func (t *tlvType262) TypeVal() Type { + return 262 +} + +func (t *tlvType262) tlv() {} + +type TlvType262 = *tlvType262 + +type tlvType263 struct{} + +func (t *tlvType263) TypeVal() Type { + return 263 +} + +func (t *tlvType263) tlv() {} + +type TlvType263 = *tlvType263 + +type tlvType264 struct{} + +func (t *tlvType264) TypeVal() Type { + return 264 +} + +func (t *tlvType264) tlv() {} + +type TlvType264 = *tlvType264 + +type tlvType265 struct{} + +func (t *tlvType265) TypeVal() Type { + return 265 +} + +func (t *tlvType265) tlv() {} + +type TlvType265 = *tlvType265 + +type tlvType266 struct{} + +func (t *tlvType266) TypeVal() Type { + return 266 +} + +func (t *tlvType266) tlv() {} + +type TlvType266 = *tlvType266 + +type tlvType267 struct{} + +func (t *tlvType267) TypeVal() Type { + return 267 +} + +func (t *tlvType267) tlv() {} + +type TlvType267 = *tlvType267 + +type tlvType268 struct{} + +func (t *tlvType268) TypeVal() Type { + return 268 +} + +func (t *tlvType268) tlv() {} + +type TlvType268 = *tlvType268 + +type tlvType269 struct{} + +func (t *tlvType269) TypeVal() Type { + return 269 +} + +func (t *tlvType269) tlv() {} + +type TlvType269 = *tlvType269 + +type tlvType270 struct{} + +func (t *tlvType270) TypeVal() Type { + return 270 +} + +func (t *tlvType270) tlv() {} + +type TlvType270 = *tlvType270 + +type tlvType271 struct{} + +func (t *tlvType271) TypeVal() Type { + return 271 +} + +func (t *tlvType271) tlv() {} + +type TlvType271 = *tlvType271 + +type tlvType272 struct{} + +func (t *tlvType272) TypeVal() Type { + return 272 +} + +func (t *tlvType272) tlv() {} + +type TlvType272 = *tlvType272 + +type tlvType273 struct{} + +func (t *tlvType273) TypeVal() Type { + return 273 +} + +func (t *tlvType273) tlv() {} + +type TlvType273 = *tlvType273 + +type tlvType274 struct{} + +func (t *tlvType274) TypeVal() Type { + return 274 +} + +func (t *tlvType274) tlv() {} + +type TlvType274 = *tlvType274 + +type tlvType275 struct{} + +func (t *tlvType275) TypeVal() Type { + return 275 +} + +func (t *tlvType275) tlv() {} + +type TlvType275 = *tlvType275 + +type tlvType276 struct{} + +func (t *tlvType276) TypeVal() Type { + return 276 +} + +func (t *tlvType276) tlv() {} + +type TlvType276 = *tlvType276 + +type tlvType277 struct{} + +func (t *tlvType277) TypeVal() Type { + return 277 +} + +func (t *tlvType277) tlv() {} + +type TlvType277 = *tlvType277 + +type tlvType278 struct{} + +func (t *tlvType278) TypeVal() Type { + return 278 +} + +func (t *tlvType278) tlv() {} + +type TlvType278 = *tlvType278 + +type tlvType279 struct{} + +func (t *tlvType279) TypeVal() Type { + return 279 +} + +func (t *tlvType279) tlv() {} + +type TlvType279 = *tlvType279 + +type tlvType280 struct{} + +func (t *tlvType280) TypeVal() Type { + return 280 +} + +func (t *tlvType280) tlv() {} + +type TlvType280 = *tlvType280 + +type tlvType281 struct{} + +func (t *tlvType281) TypeVal() Type { + return 281 +} + +func (t *tlvType281) tlv() {} + +type TlvType281 = *tlvType281 + +type tlvType282 struct{} + +func (t *tlvType282) TypeVal() Type { + return 282 +} + +func (t *tlvType282) tlv() {} + +type TlvType282 = *tlvType282 + +type tlvType283 struct{} + +func (t *tlvType283) TypeVal() Type { + return 283 +} + +func (t *tlvType283) tlv() {} + +type TlvType283 = *tlvType283 + +type tlvType284 struct{} + +func (t *tlvType284) TypeVal() Type { + return 284 +} + +func (t *tlvType284) tlv() {} + +type TlvType284 = *tlvType284 + +type tlvType285 struct{} + +func (t *tlvType285) TypeVal() Type { + return 285 +} + +func (t *tlvType285) tlv() {} + +type TlvType285 = *tlvType285 + +type tlvType286 struct{} + +func (t *tlvType286) TypeVal() Type { + return 286 +} + +func (t *tlvType286) tlv() {} + +type TlvType286 = *tlvType286 + +type tlvType287 struct{} + +func (t *tlvType287) TypeVal() Type { + return 287 +} + +func (t *tlvType287) tlv() {} + +type TlvType287 = *tlvType287 + +type tlvType288 struct{} + +func (t *tlvType288) TypeVal() Type { + return 288 +} + +func (t *tlvType288) tlv() {} + +type TlvType288 = *tlvType288 + +type tlvType289 struct{} + +func (t *tlvType289) TypeVal() Type { + return 289 +} + +func (t *tlvType289) tlv() {} + +type TlvType289 = *tlvType289 + +type tlvType290 struct{} + +func (t *tlvType290) TypeVal() Type { + return 290 +} + +func (t *tlvType290) tlv() {} + +type TlvType290 = *tlvType290 + +type tlvType291 struct{} + +func (t *tlvType291) TypeVal() Type { + return 291 +} + +func (t *tlvType291) tlv() {} + +type TlvType291 = *tlvType291 + +type tlvType292 struct{} + +func (t *tlvType292) TypeVal() Type { + return 292 +} + +func (t *tlvType292) tlv() {} + +type TlvType292 = *tlvType292 + +type tlvType293 struct{} + +func (t *tlvType293) TypeVal() Type { + return 293 +} + +func (t *tlvType293) tlv() {} + +type TlvType293 = *tlvType293 + +type tlvType294 struct{} + +func (t *tlvType294) TypeVal() Type { + return 294 +} + +func (t *tlvType294) tlv() {} + +type TlvType294 = *tlvType294 + +type tlvType295 struct{} + +func (t *tlvType295) TypeVal() Type { + return 295 +} + +func (t *tlvType295) tlv() {} + +type TlvType295 = *tlvType295 + +type tlvType296 struct{} + +func (t *tlvType296) TypeVal() Type { + return 296 +} + +func (t *tlvType296) tlv() {} + +type TlvType296 = *tlvType296 + +type tlvType297 struct{} + +func (t *tlvType297) TypeVal() Type { + return 297 +} + +func (t *tlvType297) tlv() {} + +type TlvType297 = *tlvType297 + +type tlvType298 struct{} + +func (t *tlvType298) TypeVal() Type { + return 298 +} + +func (t *tlvType298) tlv() {} + +type TlvType298 = *tlvType298 + +type tlvType299 struct{} + +func (t *tlvType299) TypeVal() Type { + return 299 +} + +func (t *tlvType299) tlv() {} + +type TlvType299 = *tlvType299 + +type tlvType300 struct{} + +func (t *tlvType300) TypeVal() Type { + return 300 +} + +func (t *tlvType300) tlv() {} + +type TlvType300 = *tlvType300 + type tlvType65536 struct{} -func (t *tlvType65536) TypeVal() Type { - return 65536 +func (t *tlvType65536) TypeVal() Type { + return 65536 +} + +func (t *tlvType65536) tlv() {} + +type TlvType65536 = *tlvType65536 + +type tlvType65537 struct{} + +func (t *tlvType65537) TypeVal() Type { + return 65537 +} + +func (t *tlvType65537) tlv() {} + +type TlvType65537 = *tlvType65537 + +type tlvType65538 struct{} + +func (t *tlvType65538) TypeVal() Type { + return 65538 +} + +func (t *tlvType65538) tlv() {} + +type TlvType65538 = *tlvType65538 + +type tlvType65539 struct{} + +func (t *tlvType65539) TypeVal() Type { + return 65539 +} + +func (t *tlvType65539) tlv() {} + +type TlvType65539 = *tlvType65539 + +type tlvType65540 struct{} + +func (t *tlvType65540) TypeVal() Type { + return 65540 +} + +func (t *tlvType65540) tlv() {} + +type TlvType65540 = *tlvType65540 + +type tlvType65541 struct{} + +func (t *tlvType65541) TypeVal() Type { + return 65541 +} + +func (t *tlvType65541) tlv() {} + +type TlvType65541 = *tlvType65541 + +type tlvType65542 struct{} + +func (t *tlvType65542) TypeVal() Type { + return 65542 +} + +func (t *tlvType65542) tlv() {} + +type TlvType65542 = *tlvType65542 + +type tlvType65543 struct{} + +func (t *tlvType65543) TypeVal() Type { + return 65543 +} + +func (t *tlvType65543) tlv() {} + +type TlvType65543 = *tlvType65543 + +type tlvType65544 struct{} + +func (t *tlvType65544) TypeVal() Type { + return 65544 +} + +func (t *tlvType65544) tlv() {} + +type TlvType65544 = *tlvType65544 + +type tlvType65545 struct{} + +func (t *tlvType65545) TypeVal() Type { + return 65545 +} + +func (t *tlvType65545) tlv() {} + +type TlvType65545 = *tlvType65545 + +type tlvType65546 struct{} + +func (t *tlvType65546) TypeVal() Type { + return 65546 +} + +func (t *tlvType65546) tlv() {} + +type TlvType65546 = *tlvType65546 + +type tlvType65547 struct{} + +func (t *tlvType65547) TypeVal() Type { + return 65547 +} + +func (t *tlvType65547) tlv() {} + +type TlvType65547 = *tlvType65547 + +type tlvType65548 struct{} + +func (t *tlvType65548) TypeVal() Type { + return 65548 +} + +func (t *tlvType65548) tlv() {} + +type TlvType65548 = *tlvType65548 + +type tlvType65549 struct{} + +func (t *tlvType65549) TypeVal() Type { + return 65549 +} + +func (t *tlvType65549) tlv() {} + +type TlvType65549 = *tlvType65549 + +type tlvType65550 struct{} + +func (t *tlvType65550) TypeVal() Type { + return 65550 +} + +func (t *tlvType65550) tlv() {} + +type TlvType65550 = *tlvType65550 + +type tlvType65551 struct{} + +func (t *tlvType65551) TypeVal() Type { + return 65551 +} + +func (t *tlvType65551) tlv() {} + +type TlvType65551 = *tlvType65551 + +type tlvType65552 struct{} + +func (t *tlvType65552) TypeVal() Type { + return 65552 +} + +func (t *tlvType65552) tlv() {} + +type TlvType65552 = *tlvType65552 + +type tlvType65553 struct{} + +func (t *tlvType65553) TypeVal() Type { + return 65553 +} + +func (t *tlvType65553) tlv() {} + +type TlvType65553 = *tlvType65553 + +type tlvType65554 struct{} + +func (t *tlvType65554) TypeVal() Type { + return 65554 +} + +func (t *tlvType65554) tlv() {} + +type TlvType65554 = *tlvType65554 + +type tlvType65555 struct{} + +func (t *tlvType65555) TypeVal() Type { + return 65555 +} + +func (t *tlvType65555) tlv() {} + +type TlvType65555 = *tlvType65555 + +type tlvType65556 struct{} + +func (t *tlvType65556) TypeVal() Type { + return 65556 +} + +func (t *tlvType65556) tlv() {} + +type TlvType65556 = *tlvType65556 + +type tlvType65557 struct{} + +func (t *tlvType65557) TypeVal() Type { + return 65557 +} + +func (t *tlvType65557) tlv() {} + +type TlvType65557 = *tlvType65557 + +type tlvType65558 struct{} + +func (t *tlvType65558) TypeVal() Type { + return 65558 +} + +func (t *tlvType65558) tlv() {} + +type TlvType65558 = *tlvType65558 + +type tlvType65559 struct{} + +func (t *tlvType65559) TypeVal() Type { + return 65559 +} + +func (t *tlvType65559) tlv() {} + +type TlvType65559 = *tlvType65559 + +type tlvType65560 struct{} + +func (t *tlvType65560) TypeVal() Type { + return 65560 +} + +func (t *tlvType65560) tlv() {} + +type TlvType65560 = *tlvType65560 + +type tlvType65561 struct{} + +func (t *tlvType65561) TypeVal() Type { + return 65561 +} + +func (t *tlvType65561) tlv() {} + +type TlvType65561 = *tlvType65561 + +type tlvType65562 struct{} + +func (t *tlvType65562) TypeVal() Type { + return 65562 +} + +func (t *tlvType65562) tlv() {} + +type TlvType65562 = *tlvType65562 + +type tlvType65563 struct{} + +func (t *tlvType65563) TypeVal() Type { + return 65563 +} + +func (t *tlvType65563) tlv() {} + +type TlvType65563 = *tlvType65563 + +type tlvType65564 struct{} + +func (t *tlvType65564) TypeVal() Type { + return 65564 +} + +func (t *tlvType65564) tlv() {} + +type TlvType65564 = *tlvType65564 + +type tlvType65565 struct{} + +func (t *tlvType65565) TypeVal() Type { + return 65565 +} + +func (t *tlvType65565) tlv() {} + +type TlvType65565 = *tlvType65565 + +type tlvType65566 struct{} + +func (t *tlvType65566) TypeVal() Type { + return 65566 +} + +func (t *tlvType65566) tlv() {} + +type TlvType65566 = *tlvType65566 + +type tlvType65567 struct{} + +func (t *tlvType65567) TypeVal() Type { + return 65567 +} + +func (t *tlvType65567) tlv() {} + +type TlvType65567 = *tlvType65567 + +type tlvType65568 struct{} + +func (t *tlvType65568) TypeVal() Type { + return 65568 +} + +func (t *tlvType65568) tlv() {} + +type TlvType65568 = *tlvType65568 + +type tlvType65569 struct{} + +func (t *tlvType65569) TypeVal() Type { + return 65569 +} + +func (t *tlvType65569) tlv() {} + +type TlvType65569 = *tlvType65569 + +type tlvType65570 struct{} + +func (t *tlvType65570) TypeVal() Type { + return 65570 +} + +func (t *tlvType65570) tlv() {} + +type TlvType65570 = *tlvType65570 + +type tlvType65571 struct{} + +func (t *tlvType65571) TypeVal() Type { + return 65571 +} + +func (t *tlvType65571) tlv() {} + +type TlvType65571 = *tlvType65571 + +type tlvType65572 struct{} + +func (t *tlvType65572) TypeVal() Type { + return 65572 +} + +func (t *tlvType65572) tlv() {} + +type TlvType65572 = *tlvType65572 + +type tlvType65573 struct{} + +func (t *tlvType65573) TypeVal() Type { + return 65573 +} + +func (t *tlvType65573) tlv() {} + +type TlvType65573 = *tlvType65573 + +type tlvType65574 struct{} + +func (t *tlvType65574) TypeVal() Type { + return 65574 +} + +func (t *tlvType65574) tlv() {} + +type TlvType65574 = *tlvType65574 + +type tlvType65575 struct{} + +func (t *tlvType65575) TypeVal() Type { + return 65575 +} + +func (t *tlvType65575) tlv() {} + +type TlvType65575 = *tlvType65575 + +type tlvType65576 struct{} + +func (t *tlvType65576) TypeVal() Type { + return 65576 +} + +func (t *tlvType65576) tlv() {} + +type TlvType65576 = *tlvType65576 + +type tlvType65577 struct{} + +func (t *tlvType65577) TypeVal() Type { + return 65577 +} + +func (t *tlvType65577) tlv() {} + +type TlvType65577 = *tlvType65577 + +type tlvType65578 struct{} + +func (t *tlvType65578) TypeVal() Type { + return 65578 +} + +func (t *tlvType65578) tlv() {} + +type TlvType65578 = *tlvType65578 + +type tlvType65579 struct{} + +func (t *tlvType65579) TypeVal() Type { + return 65579 +} + +func (t *tlvType65579) tlv() {} + +type TlvType65579 = *tlvType65579 + +type tlvType65580 struct{} + +func (t *tlvType65580) TypeVal() Type { + return 65580 +} + +func (t *tlvType65580) tlv() {} + +type TlvType65580 = *tlvType65580 + +type tlvType65581 struct{} + +func (t *tlvType65581) TypeVal() Type { + return 65581 +} + +func (t *tlvType65581) tlv() {} + +type TlvType65581 = *tlvType65581 + +type tlvType65582 struct{} + +func (t *tlvType65582) TypeVal() Type { + return 65582 +} + +func (t *tlvType65582) tlv() {} + +type TlvType65582 = *tlvType65582 + +type tlvType65583 struct{} + +func (t *tlvType65583) TypeVal() Type { + return 65583 +} + +func (t *tlvType65583) tlv() {} + +type TlvType65583 = *tlvType65583 + +type tlvType65584 struct{} + +func (t *tlvType65584) TypeVal() Type { + return 65584 +} + +func (t *tlvType65584) tlv() {} + +type TlvType65584 = *tlvType65584 + +type tlvType65585 struct{} + +func (t *tlvType65585) TypeVal() Type { + return 65585 +} + +func (t *tlvType65585) tlv() {} + +type TlvType65585 = *tlvType65585 + +type tlvType65586 struct{} + +func (t *tlvType65586) TypeVal() Type { + return 65586 +} + +func (t *tlvType65586) tlv() {} + +type TlvType65586 = *tlvType65586 + +type tlvType65587 struct{} + +func (t *tlvType65587) TypeVal() Type { + return 65587 +} + +func (t *tlvType65587) tlv() {} + +type TlvType65587 = *tlvType65587 + +type tlvType65588 struct{} + +func (t *tlvType65588) TypeVal() Type { + return 65588 +} + +func (t *tlvType65588) tlv() {} + +type TlvType65588 = *tlvType65588 + +type tlvType65589 struct{} + +func (t *tlvType65589) TypeVal() Type { + return 65589 +} + +func (t *tlvType65589) tlv() {} + +type TlvType65589 = *tlvType65589 + +type tlvType65590 struct{} + +func (t *tlvType65590) TypeVal() Type { + return 65590 +} + +func (t *tlvType65590) tlv() {} + +type TlvType65590 = *tlvType65590 + +type tlvType65591 struct{} + +func (t *tlvType65591) TypeVal() Type { + return 65591 +} + +func (t *tlvType65591) tlv() {} + +type TlvType65591 = *tlvType65591 + +type tlvType65592 struct{} + +func (t *tlvType65592) TypeVal() Type { + return 65592 +} + +func (t *tlvType65592) tlv() {} + +type TlvType65592 = *tlvType65592 + +type tlvType65593 struct{} + +func (t *tlvType65593) TypeVal() Type { + return 65593 +} + +func (t *tlvType65593) tlv() {} + +type TlvType65593 = *tlvType65593 + +type tlvType65594 struct{} + +func (t *tlvType65594) TypeVal() Type { + return 65594 +} + +func (t *tlvType65594) tlv() {} + +type TlvType65594 = *tlvType65594 + +type tlvType65595 struct{} + +func (t *tlvType65595) TypeVal() Type { + return 65595 +} + +func (t *tlvType65595) tlv() {} + +type TlvType65595 = *tlvType65595 + +type tlvType65596 struct{} + +func (t *tlvType65596) TypeVal() Type { + return 65596 +} + +func (t *tlvType65596) tlv() {} + +type TlvType65596 = *tlvType65596 + +type tlvType65597 struct{} + +func (t *tlvType65597) TypeVal() Type { + return 65597 +} + +func (t *tlvType65597) tlv() {} + +type TlvType65597 = *tlvType65597 + +type tlvType65598 struct{} + +func (t *tlvType65598) TypeVal() Type { + return 65598 +} + +func (t *tlvType65598) tlv() {} + +type TlvType65598 = *tlvType65598 + +type tlvType65599 struct{} + +func (t *tlvType65599) TypeVal() Type { + return 65599 +} + +func (t *tlvType65599) tlv() {} + +type TlvType65599 = *tlvType65599 + +type tlvType65600 struct{} + +func (t *tlvType65600) TypeVal() Type { + return 65600 +} + +func (t *tlvType65600) tlv() {} + +type TlvType65600 = *tlvType65600 + +type tlvType65601 struct{} + +func (t *tlvType65601) TypeVal() Type { + return 65601 +} + +func (t *tlvType65601) tlv() {} + +type TlvType65601 = *tlvType65601 + +type tlvType65602 struct{} + +func (t *tlvType65602) TypeVal() Type { + return 65602 +} + +func (t *tlvType65602) tlv() {} + +type TlvType65602 = *tlvType65602 + +type tlvType65603 struct{} + +func (t *tlvType65603) TypeVal() Type { + return 65603 +} + +func (t *tlvType65603) tlv() {} + +type TlvType65603 = *tlvType65603 + +type tlvType65604 struct{} + +func (t *tlvType65604) TypeVal() Type { + return 65604 +} + +func (t *tlvType65604) tlv() {} + +type TlvType65604 = *tlvType65604 + +type tlvType65605 struct{} + +func (t *tlvType65605) TypeVal() Type { + return 65605 +} + +func (t *tlvType65605) tlv() {} + +type TlvType65605 = *tlvType65605 + +type tlvType65606 struct{} + +func (t *tlvType65606) TypeVal() Type { + return 65606 +} + +func (t *tlvType65606) tlv() {} + +type TlvType65606 = *tlvType65606 + +type tlvType65607 struct{} + +func (t *tlvType65607) TypeVal() Type { + return 65607 +} + +func (t *tlvType65607) tlv() {} + +type TlvType65607 = *tlvType65607 + +type tlvType65608 struct{} + +func (t *tlvType65608) TypeVal() Type { + return 65608 +} + +func (t *tlvType65608) tlv() {} + +type TlvType65608 = *tlvType65608 + +type tlvType65609 struct{} + +func (t *tlvType65609) TypeVal() Type { + return 65609 +} + +func (t *tlvType65609) tlv() {} + +type TlvType65609 = *tlvType65609 + +type tlvType65610 struct{} + +func (t *tlvType65610) TypeVal() Type { + return 65610 +} + +func (t *tlvType65610) tlv() {} + +type TlvType65610 = *tlvType65610 + +type tlvType65611 struct{} + +func (t *tlvType65611) TypeVal() Type { + return 65611 +} + +func (t *tlvType65611) tlv() {} + +type TlvType65611 = *tlvType65611 + +type tlvType65612 struct{} + +func (t *tlvType65612) TypeVal() Type { + return 65612 +} + +func (t *tlvType65612) tlv() {} + +type TlvType65612 = *tlvType65612 + +type tlvType65613 struct{} + +func (t *tlvType65613) TypeVal() Type { + return 65613 +} + +func (t *tlvType65613) tlv() {} + +type TlvType65613 = *tlvType65613 + +type tlvType65614 struct{} + +func (t *tlvType65614) TypeVal() Type { + return 65614 +} + +func (t *tlvType65614) tlv() {} + +type TlvType65614 = *tlvType65614 + +type tlvType65615 struct{} + +func (t *tlvType65615) TypeVal() Type { + return 65615 +} + +func (t *tlvType65615) tlv() {} + +type TlvType65615 = *tlvType65615 + +type tlvType65616 struct{} + +func (t *tlvType65616) TypeVal() Type { + return 65616 +} + +func (t *tlvType65616) tlv() {} + +type TlvType65616 = *tlvType65616 + +type tlvType65617 struct{} + +func (t *tlvType65617) TypeVal() Type { + return 65617 +} + +func (t *tlvType65617) tlv() {} + +type TlvType65617 = *tlvType65617 + +type tlvType65618 struct{} + +func (t *tlvType65618) TypeVal() Type { + return 65618 +} + +func (t *tlvType65618) tlv() {} + +type TlvType65618 = *tlvType65618 + +type tlvType65619 struct{} + +func (t *tlvType65619) TypeVal() Type { + return 65619 +} + +func (t *tlvType65619) tlv() {} + +type TlvType65619 = *tlvType65619 + +type tlvType65620 struct{} + +func (t *tlvType65620) TypeVal() Type { + return 65620 +} + +func (t *tlvType65620) tlv() {} + +type TlvType65620 = *tlvType65620 + +type tlvType65621 struct{} + +func (t *tlvType65621) TypeVal() Type { + return 65621 +} + +func (t *tlvType65621) tlv() {} + +type TlvType65621 = *tlvType65621 + +type tlvType65622 struct{} + +func (t *tlvType65622) TypeVal() Type { + return 65622 +} + +func (t *tlvType65622) tlv() {} + +type TlvType65622 = *tlvType65622 + +type tlvType65623 struct{} + +func (t *tlvType65623) TypeVal() Type { + return 65623 +} + +func (t *tlvType65623) tlv() {} + +type TlvType65623 = *tlvType65623 + +type tlvType65624 struct{} + +func (t *tlvType65624) TypeVal() Type { + return 65624 +} + +func (t *tlvType65624) tlv() {} + +type TlvType65624 = *tlvType65624 + +type tlvType65625 struct{} + +func (t *tlvType65625) TypeVal() Type { + return 65625 +} + +func (t *tlvType65625) tlv() {} + +type TlvType65625 = *tlvType65625 + +type tlvType65626 struct{} + +func (t *tlvType65626) TypeVal() Type { + return 65626 +} + +func (t *tlvType65626) tlv() {} + +type TlvType65626 = *tlvType65626 + +type tlvType65627 struct{} + +func (t *tlvType65627) TypeVal() Type { + return 65627 +} + +func (t *tlvType65627) tlv() {} + +type TlvType65627 = *tlvType65627 + +type tlvType65628 struct{} + +func (t *tlvType65628) TypeVal() Type { + return 65628 +} + +func (t *tlvType65628) tlv() {} + +type TlvType65628 = *tlvType65628 + +type tlvType65629 struct{} + +func (t *tlvType65629) TypeVal() Type { + return 65629 +} + +func (t *tlvType65629) tlv() {} + +type TlvType65629 = *tlvType65629 + +type tlvType65630 struct{} + +func (t *tlvType65630) TypeVal() Type { + return 65630 +} + +func (t *tlvType65630) tlv() {} + +type TlvType65630 = *tlvType65630 + +type tlvType65631 struct{} + +func (t *tlvType65631) TypeVal() Type { + return 65631 +} + +func (t *tlvType65631) tlv() {} + +type TlvType65631 = *tlvType65631 + +type tlvType65632 struct{} + +func (t *tlvType65632) TypeVal() Type { + return 65632 +} + +func (t *tlvType65632) tlv() {} + +type TlvType65632 = *tlvType65632 + +type tlvType65633 struct{} + +func (t *tlvType65633) TypeVal() Type { + return 65633 +} + +func (t *tlvType65633) tlv() {} + +type TlvType65633 = *tlvType65633 + +type tlvType65634 struct{} + +func (t *tlvType65634) TypeVal() Type { + return 65634 +} + +func (t *tlvType65634) tlv() {} + +type TlvType65634 = *tlvType65634 + +type tlvType65635 struct{} + +func (t *tlvType65635) TypeVal() Type { + return 65635 +} + +func (t *tlvType65635) tlv() {} + +type TlvType65635 = *tlvType65635 + +type tlvType65636 struct{} + +func (t *tlvType65636) TypeVal() Type { + return 65636 +} + +func (t *tlvType65636) tlv() {} + +type TlvType65636 = *tlvType65636 + +type tlvType65637 struct{} + +func (t *tlvType65637) TypeVal() Type { + return 65637 +} + +func (t *tlvType65637) tlv() {} + +type TlvType65637 = *tlvType65637 + +type tlvType65638 struct{} + +func (t *tlvType65638) TypeVal() Type { + return 65638 +} + +func (t *tlvType65638) tlv() {} + +type TlvType65638 = *tlvType65638 + +type tlvType65639 struct{} + +func (t *tlvType65639) TypeVal() Type { + return 65639 +} + +func (t *tlvType65639) tlv() {} + +type TlvType65639 = *tlvType65639 + +type tlvType65640 struct{} + +func (t *tlvType65640) TypeVal() Type { + return 65640 +} + +func (t *tlvType65640) tlv() {} + +type TlvType65640 = *tlvType65640 + +type tlvType65641 struct{} + +func (t *tlvType65641) TypeVal() Type { + return 65641 +} + +func (t *tlvType65641) tlv() {} + +type TlvType65641 = *tlvType65641 + +type tlvType65642 struct{} + +func (t *tlvType65642) TypeVal() Type { + return 65642 +} + +func (t *tlvType65642) tlv() {} + +type TlvType65642 = *tlvType65642 + +type tlvType65643 struct{} + +func (t *tlvType65643) TypeVal() Type { + return 65643 +} + +func (t *tlvType65643) tlv() {} + +type TlvType65643 = *tlvType65643 + +type tlvType65644 struct{} + +func (t *tlvType65644) TypeVal() Type { + return 65644 +} + +func (t *tlvType65644) tlv() {} + +type TlvType65644 = *tlvType65644 + +type tlvType65645 struct{} + +func (t *tlvType65645) TypeVal() Type { + return 65645 +} + +func (t *tlvType65645) tlv() {} + +type TlvType65645 = *tlvType65645 + +type tlvType65646 struct{} + +func (t *tlvType65646) TypeVal() Type { + return 65646 +} + +func (t *tlvType65646) tlv() {} + +type TlvType65646 = *tlvType65646 + +type tlvType65647 struct{} + +func (t *tlvType65647) TypeVal() Type { + return 65647 +} + +func (t *tlvType65647) tlv() {} + +type TlvType65647 = *tlvType65647 + +type tlvType65648 struct{} + +func (t *tlvType65648) TypeVal() Type { + return 65648 +} + +func (t *tlvType65648) tlv() {} + +type TlvType65648 = *tlvType65648 + +type tlvType65649 struct{} + +func (t *tlvType65649) TypeVal() Type { + return 65649 +} + +func (t *tlvType65649) tlv() {} + +type TlvType65649 = *tlvType65649 + +type tlvType65650 struct{} + +func (t *tlvType65650) TypeVal() Type { + return 65650 +} + +func (t *tlvType65650) tlv() {} + +type TlvType65650 = *tlvType65650 + +type tlvType65651 struct{} + +func (t *tlvType65651) TypeVal() Type { + return 65651 +} + +func (t *tlvType65651) tlv() {} + +type TlvType65651 = *tlvType65651 + +type tlvType65652 struct{} + +func (t *tlvType65652) TypeVal() Type { + return 65652 +} + +func (t *tlvType65652) tlv() {} + +type TlvType65652 = *tlvType65652 + +type tlvType65653 struct{} + +func (t *tlvType65653) TypeVal() Type { + return 65653 +} + +func (t *tlvType65653) tlv() {} + +type TlvType65653 = *tlvType65653 + +type tlvType65654 struct{} + +func (t *tlvType65654) TypeVal() Type { + return 65654 +} + +func (t *tlvType65654) tlv() {} + +type TlvType65654 = *tlvType65654 + +type tlvType65655 struct{} + +func (t *tlvType65655) TypeVal() Type { + return 65655 +} + +func (t *tlvType65655) tlv() {} + +type TlvType65655 = *tlvType65655 + +type tlvType65656 struct{} + +func (t *tlvType65656) TypeVal() Type { + return 65656 +} + +func (t *tlvType65656) tlv() {} + +type TlvType65656 = *tlvType65656 + +type tlvType65657 struct{} + +func (t *tlvType65657) TypeVal() Type { + return 65657 +} + +func (t *tlvType65657) tlv() {} + +type TlvType65657 = *tlvType65657 + +type tlvType65658 struct{} + +func (t *tlvType65658) TypeVal() Type { + return 65658 +} + +func (t *tlvType65658) tlv() {} + +type TlvType65658 = *tlvType65658 + +type tlvType65659 struct{} + +func (t *tlvType65659) TypeVal() Type { + return 65659 +} + +func (t *tlvType65659) tlv() {} + +type TlvType65659 = *tlvType65659 + +type tlvType65660 struct{} + +func (t *tlvType65660) TypeVal() Type { + return 65660 +} + +func (t *tlvType65660) tlv() {} + +type TlvType65660 = *tlvType65660 + +type tlvType65661 struct{} + +func (t *tlvType65661) TypeVal() Type { + return 65661 +} + +func (t *tlvType65661) tlv() {} + +type TlvType65661 = *tlvType65661 + +type tlvType65662 struct{} + +func (t *tlvType65662) TypeVal() Type { + return 65662 +} + +func (t *tlvType65662) tlv() {} + +type TlvType65662 = *tlvType65662 + +type tlvType65663 struct{} + +func (t *tlvType65663) TypeVal() Type { + return 65663 +} + +func (t *tlvType65663) tlv() {} + +type TlvType65663 = *tlvType65663 + +type tlvType65664 struct{} + +func (t *tlvType65664) TypeVal() Type { + return 65664 +} + +func (t *tlvType65664) tlv() {} + +type TlvType65664 = *tlvType65664 + +type tlvType65665 struct{} + +func (t *tlvType65665) TypeVal() Type { + return 65665 +} + +func (t *tlvType65665) tlv() {} + +type TlvType65665 = *tlvType65665 + +type tlvType65666 struct{} + +func (t *tlvType65666) TypeVal() Type { + return 65666 +} + +func (t *tlvType65666) tlv() {} + +type TlvType65666 = *tlvType65666 + +type tlvType65667 struct{} + +func (t *tlvType65667) TypeVal() Type { + return 65667 +} + +func (t *tlvType65667) tlv() {} + +type TlvType65667 = *tlvType65667 + +type tlvType65668 struct{} + +func (t *tlvType65668) TypeVal() Type { + return 65668 +} + +func (t *tlvType65668) tlv() {} + +type TlvType65668 = *tlvType65668 + +type tlvType65669 struct{} + +func (t *tlvType65669) TypeVal() Type { + return 65669 +} + +func (t *tlvType65669) tlv() {} + +type TlvType65669 = *tlvType65669 + +type tlvType65670 struct{} + +func (t *tlvType65670) TypeVal() Type { + return 65670 +} + +func (t *tlvType65670) tlv() {} + +type TlvType65670 = *tlvType65670 + +type tlvType65671 struct{} + +func (t *tlvType65671) TypeVal() Type { + return 65671 +} + +func (t *tlvType65671) tlv() {} + +type TlvType65671 = *tlvType65671 + +type tlvType65672 struct{} + +func (t *tlvType65672) TypeVal() Type { + return 65672 +} + +func (t *tlvType65672) tlv() {} + +type TlvType65672 = *tlvType65672 + +type tlvType65673 struct{} + +func (t *tlvType65673) TypeVal() Type { + return 65673 +} + +func (t *tlvType65673) tlv() {} + +type TlvType65673 = *tlvType65673 + +type tlvType65674 struct{} + +func (t *tlvType65674) TypeVal() Type { + return 65674 +} + +func (t *tlvType65674) tlv() {} + +type TlvType65674 = *tlvType65674 + +type tlvType65675 struct{} + +func (t *tlvType65675) TypeVal() Type { + return 65675 +} + +func (t *tlvType65675) tlv() {} + +type TlvType65675 = *tlvType65675 + +type tlvType65676 struct{} + +func (t *tlvType65676) TypeVal() Type { + return 65676 +} + +func (t *tlvType65676) tlv() {} + +type TlvType65676 = *tlvType65676 + +type tlvType65677 struct{} + +func (t *tlvType65677) TypeVal() Type { + return 65677 +} + +func (t *tlvType65677) tlv() {} + +type TlvType65677 = *tlvType65677 + +type tlvType65678 struct{} + +func (t *tlvType65678) TypeVal() Type { + return 65678 +} + +func (t *tlvType65678) tlv() {} + +type TlvType65678 = *tlvType65678 + +type tlvType65679 struct{} + +func (t *tlvType65679) TypeVal() Type { + return 65679 +} + +func (t *tlvType65679) tlv() {} + +type TlvType65679 = *tlvType65679 + +type tlvType65680 struct{} + +func (t *tlvType65680) TypeVal() Type { + return 65680 +} + +func (t *tlvType65680) tlv() {} + +type TlvType65680 = *tlvType65680 + +type tlvType65681 struct{} + +func (t *tlvType65681) TypeVal() Type { + return 65681 +} + +func (t *tlvType65681) tlv() {} + +type TlvType65681 = *tlvType65681 + +type tlvType65682 struct{} + +func (t *tlvType65682) TypeVal() Type { + return 65682 +} + +func (t *tlvType65682) tlv() {} + +type TlvType65682 = *tlvType65682 + +type tlvType65683 struct{} + +func (t *tlvType65683) TypeVal() Type { + return 65683 +} + +func (t *tlvType65683) tlv() {} + +type TlvType65683 = *tlvType65683 + +type tlvType65684 struct{} + +func (t *tlvType65684) TypeVal() Type { + return 65684 +} + +func (t *tlvType65684) tlv() {} + +type TlvType65684 = *tlvType65684 + +type tlvType65685 struct{} + +func (t *tlvType65685) TypeVal() Type { + return 65685 +} + +func (t *tlvType65685) tlv() {} + +type TlvType65685 = *tlvType65685 + +type tlvType65686 struct{} + +func (t *tlvType65686) TypeVal() Type { + return 65686 +} + +func (t *tlvType65686) tlv() {} + +type TlvType65686 = *tlvType65686 + +type tlvType65687 struct{} + +func (t *tlvType65687) TypeVal() Type { + return 65687 +} + +func (t *tlvType65687) tlv() {} + +type TlvType65687 = *tlvType65687 + +type tlvType65688 struct{} + +func (t *tlvType65688) TypeVal() Type { + return 65688 +} + +func (t *tlvType65688) tlv() {} + +type TlvType65688 = *tlvType65688 + +type tlvType65689 struct{} + +func (t *tlvType65689) TypeVal() Type { + return 65689 +} + +func (t *tlvType65689) tlv() {} + +type TlvType65689 = *tlvType65689 + +type tlvType65690 struct{} + +func (t *tlvType65690) TypeVal() Type { + return 65690 +} + +func (t *tlvType65690) tlv() {} + +type TlvType65690 = *tlvType65690 + +type tlvType65691 struct{} + +func (t *tlvType65691) TypeVal() Type { + return 65691 +} + +func (t *tlvType65691) tlv() {} + +type TlvType65691 = *tlvType65691 + +type tlvType65692 struct{} + +func (t *tlvType65692) TypeVal() Type { + return 65692 +} + +func (t *tlvType65692) tlv() {} + +type TlvType65692 = *tlvType65692 + +type tlvType65693 struct{} + +func (t *tlvType65693) TypeVal() Type { + return 65693 +} + +func (t *tlvType65693) tlv() {} + +type TlvType65693 = *tlvType65693 + +type tlvType65694 struct{} + +func (t *tlvType65694) TypeVal() Type { + return 65694 +} + +func (t *tlvType65694) tlv() {} + +type TlvType65694 = *tlvType65694 + +type tlvType65695 struct{} + +func (t *tlvType65695) TypeVal() Type { + return 65695 +} + +func (t *tlvType65695) tlv() {} + +type TlvType65695 = *tlvType65695 + +type tlvType65696 struct{} + +func (t *tlvType65696) TypeVal() Type { + return 65696 +} + +func (t *tlvType65696) tlv() {} + +type TlvType65696 = *tlvType65696 + +type tlvType65697 struct{} + +func (t *tlvType65697) TypeVal() Type { + return 65697 +} + +func (t *tlvType65697) tlv() {} + +type TlvType65697 = *tlvType65697 + +type tlvType65698 struct{} + +func (t *tlvType65698) TypeVal() Type { + return 65698 +} + +func (t *tlvType65698) tlv() {} + +type TlvType65698 = *tlvType65698 + +type tlvType65699 struct{} + +func (t *tlvType65699) TypeVal() Type { + return 65699 +} + +func (t *tlvType65699) tlv() {} + +type TlvType65699 = *tlvType65699 + +type tlvType65700 struct{} + +func (t *tlvType65700) TypeVal() Type { + return 65700 +} + +func (t *tlvType65700) tlv() {} + +type TlvType65700 = *tlvType65700 + +type tlvType65701 struct{} + +func (t *tlvType65701) TypeVal() Type { + return 65701 +} + +func (t *tlvType65701) tlv() {} + +type TlvType65701 = *tlvType65701 + +type tlvType65702 struct{} + +func (t *tlvType65702) TypeVal() Type { + return 65702 +} + +func (t *tlvType65702) tlv() {} + +type TlvType65702 = *tlvType65702 + +type tlvType65703 struct{} + +func (t *tlvType65703) TypeVal() Type { + return 65703 +} + +func (t *tlvType65703) tlv() {} + +type TlvType65703 = *tlvType65703 + +type tlvType65704 struct{} + +func (t *tlvType65704) TypeVal() Type { + return 65704 +} + +func (t *tlvType65704) tlv() {} + +type TlvType65704 = *tlvType65704 + +type tlvType65705 struct{} + +func (t *tlvType65705) TypeVal() Type { + return 65705 +} + +func (t *tlvType65705) tlv() {} + +type TlvType65705 = *tlvType65705 + +type tlvType65706 struct{} + +func (t *tlvType65706) TypeVal() Type { + return 65706 +} + +func (t *tlvType65706) tlv() {} + +type TlvType65706 = *tlvType65706 + +type tlvType65707 struct{} + +func (t *tlvType65707) TypeVal() Type { + return 65707 +} + +func (t *tlvType65707) tlv() {} + +type TlvType65707 = *tlvType65707 + +type tlvType65708 struct{} + +func (t *tlvType65708) TypeVal() Type { + return 65708 +} + +func (t *tlvType65708) tlv() {} + +type TlvType65708 = *tlvType65708 + +type tlvType65709 struct{} + +func (t *tlvType65709) TypeVal() Type { + return 65709 +} + +func (t *tlvType65709) tlv() {} + +type TlvType65709 = *tlvType65709 + +type tlvType65710 struct{} + +func (t *tlvType65710) TypeVal() Type { + return 65710 +} + +func (t *tlvType65710) tlv() {} + +type TlvType65710 = *tlvType65710 + +type tlvType65711 struct{} + +func (t *tlvType65711) TypeVal() Type { + return 65711 +} + +func (t *tlvType65711) tlv() {} + +type TlvType65711 = *tlvType65711 + +type tlvType65712 struct{} + +func (t *tlvType65712) TypeVal() Type { + return 65712 +} + +func (t *tlvType65712) tlv() {} + +type TlvType65712 = *tlvType65712 + +type tlvType65713 struct{} + +func (t *tlvType65713) TypeVal() Type { + return 65713 +} + +func (t *tlvType65713) tlv() {} + +type TlvType65713 = *tlvType65713 + +type tlvType65714 struct{} + +func (t *tlvType65714) TypeVal() Type { + return 65714 +} + +func (t *tlvType65714) tlv() {} + +type TlvType65714 = *tlvType65714 + +type tlvType65715 struct{} + +func (t *tlvType65715) TypeVal() Type { + return 65715 +} + +func (t *tlvType65715) tlv() {} + +type TlvType65715 = *tlvType65715 + +type tlvType65716 struct{} + +func (t *tlvType65716) TypeVal() Type { + return 65716 +} + +func (t *tlvType65716) tlv() {} + +type TlvType65716 = *tlvType65716 + +type tlvType65717 struct{} + +func (t *tlvType65717) TypeVal() Type { + return 65717 +} + +func (t *tlvType65717) tlv() {} + +type TlvType65717 = *tlvType65717 + +type tlvType65718 struct{} + +func (t *tlvType65718) TypeVal() Type { + return 65718 +} + +func (t *tlvType65718) tlv() {} + +type TlvType65718 = *tlvType65718 + +type tlvType65719 struct{} + +func (t *tlvType65719) TypeVal() Type { + return 65719 +} + +func (t *tlvType65719) tlv() {} + +type TlvType65719 = *tlvType65719 + +type tlvType65720 struct{} + +func (t *tlvType65720) TypeVal() Type { + return 65720 +} + +func (t *tlvType65720) tlv() {} + +type TlvType65720 = *tlvType65720 + +type tlvType65721 struct{} + +func (t *tlvType65721) TypeVal() Type { + return 65721 +} + +func (t *tlvType65721) tlv() {} + +type TlvType65721 = *tlvType65721 + +type tlvType65722 struct{} + +func (t *tlvType65722) TypeVal() Type { + return 65722 +} + +func (t *tlvType65722) tlv() {} + +type TlvType65722 = *tlvType65722 + +type tlvType65723 struct{} + +func (t *tlvType65723) TypeVal() Type { + return 65723 +} + +func (t *tlvType65723) tlv() {} + +type TlvType65723 = *tlvType65723 + +type tlvType65724 struct{} + +func (t *tlvType65724) TypeVal() Type { + return 65724 +} + +func (t *tlvType65724) tlv() {} + +type TlvType65724 = *tlvType65724 + +type tlvType65725 struct{} + +func (t *tlvType65725) TypeVal() Type { + return 65725 +} + +func (t *tlvType65725) tlv() {} + +type TlvType65725 = *tlvType65725 + +type tlvType65726 struct{} + +func (t *tlvType65726) TypeVal() Type { + return 65726 +} + +func (t *tlvType65726) tlv() {} + +type TlvType65726 = *tlvType65726 + +type tlvType65727 struct{} + +func (t *tlvType65727) TypeVal() Type { + return 65727 +} + +func (t *tlvType65727) tlv() {} + +type TlvType65727 = *tlvType65727 + +type tlvType65728 struct{} + +func (t *tlvType65728) TypeVal() Type { + return 65728 +} + +func (t *tlvType65728) tlv() {} + +type TlvType65728 = *tlvType65728 + +type tlvType65729 struct{} + +func (t *tlvType65729) TypeVal() Type { + return 65729 +} + +func (t *tlvType65729) tlv() {} + +type TlvType65729 = *tlvType65729 + +type tlvType65730 struct{} + +func (t *tlvType65730) TypeVal() Type { + return 65730 +} + +func (t *tlvType65730) tlv() {} + +type TlvType65730 = *tlvType65730 + +type tlvType65731 struct{} + +func (t *tlvType65731) TypeVal() Type { + return 65731 +} + +func (t *tlvType65731) tlv() {} + +type TlvType65731 = *tlvType65731 + +type tlvType65732 struct{} + +func (t *tlvType65732) TypeVal() Type { + return 65732 +} + +func (t *tlvType65732) tlv() {} + +type TlvType65732 = *tlvType65732 + +type tlvType65733 struct{} + +func (t *tlvType65733) TypeVal() Type { + return 65733 +} + +func (t *tlvType65733) tlv() {} + +type TlvType65733 = *tlvType65733 + +type tlvType65734 struct{} + +func (t *tlvType65734) TypeVal() Type { + return 65734 +} + +func (t *tlvType65734) tlv() {} + +type TlvType65734 = *tlvType65734 + +type tlvType65735 struct{} + +func (t *tlvType65735) TypeVal() Type { + return 65735 +} + +func (t *tlvType65735) tlv() {} + +type TlvType65735 = *tlvType65735 + +type tlvType65736 struct{} + +func (t *tlvType65736) TypeVal() Type { + return 65736 +} + +func (t *tlvType65736) tlv() {} + +type TlvType65736 = *tlvType65736 + +type tlvType65737 struct{} + +func (t *tlvType65737) TypeVal() Type { + return 65737 } -func (t *tlvType65536) tlv() {} +func (t *tlvType65737) tlv() {} -type TlvType65536 = *tlvType65536 +type TlvType65737 = *tlvType65737 -type tlvType65537 struct{} +type tlvType65738 struct{} -func (t *tlvType65537) TypeVal() Type { - return 65537 +func (t *tlvType65738) TypeVal() Type { + return 65738 } -func (t *tlvType65537) tlv() {} +func (t *tlvType65738) tlv() {} -type TlvType65537 = *tlvType65537 +type TlvType65738 = *tlvType65738 -type tlvType65538 struct{} +type tlvType65739 struct{} -func (t *tlvType65538) TypeVal() Type { - return 65538 +func (t *tlvType65739) TypeVal() Type { + return 65739 } -func (t *tlvType65538) tlv() {} +func (t *tlvType65739) tlv() {} -type TlvType65538 = *tlvType65538 +type TlvType65739 = *tlvType65739 -type tlvType65539 struct{} +type tlvType65740 struct{} -func (t *tlvType65539) TypeVal() Type { - return 65539 +func (t *tlvType65740) TypeVal() Type { + return 65740 } -func (t *tlvType65539) tlv() {} +func (t *tlvType65740) tlv() {} -type TlvType65539 = *tlvType65539 +type TlvType65740 = *tlvType65740 -type tlvType65540 struct{} +type tlvType65741 struct{} -func (t *tlvType65540) TypeVal() Type { - return 65540 +func (t *tlvType65741) TypeVal() Type { + return 65741 } -func (t *tlvType65540) tlv() {} +func (t *tlvType65741) tlv() {} -type TlvType65540 = *tlvType65540 +type TlvType65741 = *tlvType65741 -type tlvType65541 struct{} +type tlvType65742 struct{} -func (t *tlvType65541) TypeVal() Type { - return 65541 +func (t *tlvType65742) TypeVal() Type { + return 65742 } -func (t *tlvType65541) tlv() {} +func (t *tlvType65742) tlv() {} -type TlvType65541 = *tlvType65541 +type TlvType65742 = *tlvType65742 -type tlvType65542 struct{} +type tlvType65743 struct{} -func (t *tlvType65542) TypeVal() Type { - return 65542 +func (t *tlvType65743) TypeVal() Type { + return 65743 } -func (t *tlvType65542) tlv() {} +func (t *tlvType65743) tlv() {} -type TlvType65542 = *tlvType65542 +type TlvType65743 = *tlvType65743 -type tlvType65543 struct{} +type tlvType65744 struct{} -func (t *tlvType65543) TypeVal() Type { - return 65543 +func (t *tlvType65744) TypeVal() Type { + return 65744 } -func (t *tlvType65543) tlv() {} +func (t *tlvType65744) tlv() {} -type TlvType65543 = *tlvType65543 +type TlvType65744 = *tlvType65744 -type tlvType65544 struct{} +type tlvType65745 struct{} -func (t *tlvType65544) TypeVal() Type { - return 65544 +func (t *tlvType65745) TypeVal() Type { + return 65745 } -func (t *tlvType65544) tlv() {} +func (t *tlvType65745) tlv() {} -type TlvType65544 = *tlvType65544 +type TlvType65745 = *tlvType65745 -type tlvType65545 struct{} +type tlvType65746 struct{} -func (t *tlvType65545) TypeVal() Type { - return 65545 +func (t *tlvType65746) TypeVal() Type { + return 65746 } -func (t *tlvType65545) tlv() {} +func (t *tlvType65746) tlv() {} -type TlvType65545 = *tlvType65545 +type TlvType65746 = *tlvType65746 -type tlvType65546 struct{} +type tlvType65747 struct{} -func (t *tlvType65546) TypeVal() Type { - return 65546 +func (t *tlvType65747) TypeVal() Type { + return 65747 } -func (t *tlvType65546) tlv() {} +func (t *tlvType65747) tlv() {} -type TlvType65546 = *tlvType65546 +type TlvType65747 = *tlvType65747 -type tlvType65547 struct{} +type tlvType65748 struct{} -func (t *tlvType65547) TypeVal() Type { - return 65547 +func (t *tlvType65748) TypeVal() Type { + return 65748 } -func (t *tlvType65547) tlv() {} +func (t *tlvType65748) tlv() {} -type TlvType65547 = *tlvType65547 +type TlvType65748 = *tlvType65748 -type tlvType65548 struct{} +type tlvType65749 struct{} -func (t *tlvType65548) TypeVal() Type { - return 65548 +func (t *tlvType65749) TypeVal() Type { + return 65749 } -func (t *tlvType65548) tlv() {} +func (t *tlvType65749) tlv() {} -type TlvType65548 = *tlvType65548 +type TlvType65749 = *tlvType65749 -type tlvType65549 struct{} +type tlvType65750 struct{} -func (t *tlvType65549) TypeVal() Type { - return 65549 +func (t *tlvType65750) TypeVal() Type { + return 65750 } -func (t *tlvType65549) tlv() {} +func (t *tlvType65750) tlv() {} -type TlvType65549 = *tlvType65549 +type TlvType65750 = *tlvType65750 -type tlvType65550 struct{} +type tlvType65751 struct{} -func (t *tlvType65550) TypeVal() Type { - return 65550 +func (t *tlvType65751) TypeVal() Type { + return 65751 } -func (t *tlvType65550) tlv() {} +func (t *tlvType65751) tlv() {} -type TlvType65550 = *tlvType65550 +type TlvType65751 = *tlvType65751 -type tlvType65551 struct{} +type tlvType65752 struct{} -func (t *tlvType65551) TypeVal() Type { - return 65551 +func (t *tlvType65752) TypeVal() Type { + return 65752 } -func (t *tlvType65551) tlv() {} +func (t *tlvType65752) tlv() {} -type TlvType65551 = *tlvType65551 +type TlvType65752 = *tlvType65752 -type tlvType65552 struct{} +type tlvType65753 struct{} -func (t *tlvType65552) TypeVal() Type { - return 65552 +func (t *tlvType65753) TypeVal() Type { + return 65753 } -func (t *tlvType65552) tlv() {} +func (t *tlvType65753) tlv() {} -type TlvType65552 = *tlvType65552 +type TlvType65753 = *tlvType65753 -type tlvType65553 struct{} +type tlvType65754 struct{} -func (t *tlvType65553) TypeVal() Type { - return 65553 +func (t *tlvType65754) TypeVal() Type { + return 65754 } -func (t *tlvType65553) tlv() {} +func (t *tlvType65754) tlv() {} -type TlvType65553 = *tlvType65553 +type TlvType65754 = *tlvType65754 -type tlvType65554 struct{} +type tlvType65755 struct{} -func (t *tlvType65554) TypeVal() Type { - return 65554 +func (t *tlvType65755) TypeVal() Type { + return 65755 } -func (t *tlvType65554) tlv() {} +func (t *tlvType65755) tlv() {} -type TlvType65554 = *tlvType65554 +type TlvType65755 = *tlvType65755 -type tlvType65555 struct{} +type tlvType65756 struct{} -func (t *tlvType65555) TypeVal() Type { - return 65555 +func (t *tlvType65756) TypeVal() Type { + return 65756 } -func (t *tlvType65555) tlv() {} +func (t *tlvType65756) tlv() {} -type TlvType65555 = *tlvType65555 +type TlvType65756 = *tlvType65756 -type tlvType65556 struct{} +type tlvType65757 struct{} -func (t *tlvType65556) TypeVal() Type { - return 65556 +func (t *tlvType65757) TypeVal() Type { + return 65757 } -func (t *tlvType65556) tlv() {} +func (t *tlvType65757) tlv() {} -type TlvType65556 = *tlvType65556 +type TlvType65757 = *tlvType65757 -type tlvType65557 struct{} +type tlvType65758 struct{} -func (t *tlvType65557) TypeVal() Type { - return 65557 +func (t *tlvType65758) TypeVal() Type { + return 65758 } -func (t *tlvType65557) tlv() {} +func (t *tlvType65758) tlv() {} -type TlvType65557 = *tlvType65557 +type TlvType65758 = *tlvType65758 -type tlvType65558 struct{} +type tlvType65759 struct{} -func (t *tlvType65558) TypeVal() Type { - return 65558 +func (t *tlvType65759) TypeVal() Type { + return 65759 } -func (t *tlvType65558) tlv() {} +func (t *tlvType65759) tlv() {} -type TlvType65558 = *tlvType65558 +type TlvType65759 = *tlvType65759 -type tlvType65559 struct{} +type tlvType65760 struct{} -func (t *tlvType65559) TypeVal() Type { - return 65559 +func (t *tlvType65760) TypeVal() Type { + return 65760 } -func (t *tlvType65559) tlv() {} +func (t *tlvType65760) tlv() {} -type TlvType65559 = *tlvType65559 +type TlvType65760 = *tlvType65760 -type tlvType65560 struct{} +type tlvType65761 struct{} -func (t *tlvType65560) TypeVal() Type { - return 65560 +func (t *tlvType65761) TypeVal() Type { + return 65761 } -func (t *tlvType65560) tlv() {} +func (t *tlvType65761) tlv() {} -type TlvType65560 = *tlvType65560 +type TlvType65761 = *tlvType65761 -type tlvType65561 struct{} +type tlvType65762 struct{} -func (t *tlvType65561) TypeVal() Type { - return 65561 +func (t *tlvType65762) TypeVal() Type { + return 65762 } -func (t *tlvType65561) tlv() {} +func (t *tlvType65762) tlv() {} -type TlvType65561 = *tlvType65561 +type TlvType65762 = *tlvType65762 -type tlvType65562 struct{} +type tlvType65763 struct{} -func (t *tlvType65562) TypeVal() Type { - return 65562 +func (t *tlvType65763) TypeVal() Type { + return 65763 } -func (t *tlvType65562) tlv() {} +func (t *tlvType65763) tlv() {} -type TlvType65562 = *tlvType65562 +type TlvType65763 = *tlvType65763 -type tlvType65563 struct{} +type tlvType65764 struct{} -func (t *tlvType65563) TypeVal() Type { - return 65563 +func (t *tlvType65764) TypeVal() Type { + return 65764 } -func (t *tlvType65563) tlv() {} +func (t *tlvType65764) tlv() {} -type TlvType65563 = *tlvType65563 +type TlvType65764 = *tlvType65764 -type tlvType65564 struct{} +type tlvType65765 struct{} -func (t *tlvType65564) TypeVal() Type { - return 65564 +func (t *tlvType65765) TypeVal() Type { + return 65765 } -func (t *tlvType65564) tlv() {} +func (t *tlvType65765) tlv() {} -type TlvType65564 = *tlvType65564 +type TlvType65765 = *tlvType65765 -type tlvType65565 struct{} +type tlvType65766 struct{} -func (t *tlvType65565) TypeVal() Type { - return 65565 +func (t *tlvType65766) TypeVal() Type { + return 65766 } -func (t *tlvType65565) tlv() {} +func (t *tlvType65766) tlv() {} -type TlvType65565 = *tlvType65565 +type TlvType65766 = *tlvType65766 -type tlvType65566 struct{} +type tlvType65767 struct{} -func (t *tlvType65566) TypeVal() Type { - return 65566 +func (t *tlvType65767) TypeVal() Type { + return 65767 } -func (t *tlvType65566) tlv() {} +func (t *tlvType65767) tlv() {} -type TlvType65566 = *tlvType65566 +type TlvType65767 = *tlvType65767 -type tlvType65567 struct{} +type tlvType65768 struct{} -func (t *tlvType65567) TypeVal() Type { - return 65567 +func (t *tlvType65768) TypeVal() Type { + return 65768 } -func (t *tlvType65567) tlv() {} +func (t *tlvType65768) tlv() {} -type TlvType65567 = *tlvType65567 +type TlvType65768 = *tlvType65768 -type tlvType65568 struct{} +type tlvType65769 struct{} -func (t *tlvType65568) TypeVal() Type { - return 65568 +func (t *tlvType65769) TypeVal() Type { + return 65769 } -func (t *tlvType65568) tlv() {} +func (t *tlvType65769) tlv() {} -type TlvType65568 = *tlvType65568 +type TlvType65769 = *tlvType65769 -type tlvType65569 struct{} +type tlvType65770 struct{} -func (t *tlvType65569) TypeVal() Type { - return 65569 +func (t *tlvType65770) TypeVal() Type { + return 65770 } -func (t *tlvType65569) tlv() {} +func (t *tlvType65770) tlv() {} -type TlvType65569 = *tlvType65569 +type TlvType65770 = *tlvType65770 -type tlvType65570 struct{} +type tlvType65771 struct{} -func (t *tlvType65570) TypeVal() Type { - return 65570 +func (t *tlvType65771) TypeVal() Type { + return 65771 } -func (t *tlvType65570) tlv() {} +func (t *tlvType65771) tlv() {} -type TlvType65570 = *tlvType65570 +type TlvType65771 = *tlvType65771 -type tlvType65571 struct{} +type tlvType65772 struct{} -func (t *tlvType65571) TypeVal() Type { - return 65571 +func (t *tlvType65772) TypeVal() Type { + return 65772 } -func (t *tlvType65571) tlv() {} +func (t *tlvType65772) tlv() {} -type TlvType65571 = *tlvType65571 +type TlvType65772 = *tlvType65772 -type tlvType65572 struct{} +type tlvType65773 struct{} -func (t *tlvType65572) TypeVal() Type { - return 65572 +func (t *tlvType65773) TypeVal() Type { + return 65773 } -func (t *tlvType65572) tlv() {} +func (t *tlvType65773) tlv() {} -type TlvType65572 = *tlvType65572 +type TlvType65773 = *tlvType65773 -type tlvType65573 struct{} +type tlvType65774 struct{} -func (t *tlvType65573) TypeVal() Type { - return 65573 +func (t *tlvType65774) TypeVal() Type { + return 65774 } -func (t *tlvType65573) tlv() {} +func (t *tlvType65774) tlv() {} -type TlvType65573 = *tlvType65573 +type TlvType65774 = *tlvType65774 -type tlvType65574 struct{} +type tlvType65775 struct{} -func (t *tlvType65574) TypeVal() Type { - return 65574 +func (t *tlvType65775) TypeVal() Type { + return 65775 } -func (t *tlvType65574) tlv() {} +func (t *tlvType65775) tlv() {} -type TlvType65574 = *tlvType65574 +type TlvType65775 = *tlvType65775 -type tlvType65575 struct{} +type tlvType65776 struct{} -func (t *tlvType65575) TypeVal() Type { - return 65575 +func (t *tlvType65776) TypeVal() Type { + return 65776 } -func (t *tlvType65575) tlv() {} +func (t *tlvType65776) tlv() {} -type TlvType65575 = *tlvType65575 +type TlvType65776 = *tlvType65776 -type tlvType65576 struct{} +type tlvType65777 struct{} -func (t *tlvType65576) TypeVal() Type { - return 65576 +func (t *tlvType65777) TypeVal() Type { + return 65777 } -func (t *tlvType65576) tlv() {} +func (t *tlvType65777) tlv() {} -type TlvType65576 = *tlvType65576 +type TlvType65777 = *tlvType65777 -type tlvType65577 struct{} +type tlvType65778 struct{} -func (t *tlvType65577) TypeVal() Type { - return 65577 +func (t *tlvType65778) TypeVal() Type { + return 65778 } -func (t *tlvType65577) tlv() {} +func (t *tlvType65778) tlv() {} -type TlvType65577 = *tlvType65577 +type TlvType65778 = *tlvType65778 -type tlvType65578 struct{} +type tlvType65779 struct{} -func (t *tlvType65578) TypeVal() Type { - return 65578 +func (t *tlvType65779) TypeVal() Type { + return 65779 } -func (t *tlvType65578) tlv() {} +func (t *tlvType65779) tlv() {} -type TlvType65578 = *tlvType65578 +type TlvType65779 = *tlvType65779 -type tlvType65579 struct{} +type tlvType65780 struct{} -func (t *tlvType65579) TypeVal() Type { - return 65579 +func (t *tlvType65780) TypeVal() Type { + return 65780 } -func (t *tlvType65579) tlv() {} +func (t *tlvType65780) tlv() {} -type TlvType65579 = *tlvType65579 +type TlvType65780 = *tlvType65780 -type tlvType65580 struct{} +type tlvType65781 struct{} -func (t *tlvType65580) TypeVal() Type { - return 65580 +func (t *tlvType65781) TypeVal() Type { + return 65781 } -func (t *tlvType65580) tlv() {} +func (t *tlvType65781) tlv() {} -type TlvType65580 = *tlvType65580 +type TlvType65781 = *tlvType65781 -type tlvType65581 struct{} +type tlvType65782 struct{} -func (t *tlvType65581) TypeVal() Type { - return 65581 +func (t *tlvType65782) TypeVal() Type { + return 65782 } -func (t *tlvType65581) tlv() {} +func (t *tlvType65782) tlv() {} -type TlvType65581 = *tlvType65581 +type TlvType65782 = *tlvType65782 -type tlvType65582 struct{} +type tlvType65783 struct{} -func (t *tlvType65582) TypeVal() Type { - return 65582 +func (t *tlvType65783) TypeVal() Type { + return 65783 } -func (t *tlvType65582) tlv() {} +func (t *tlvType65783) tlv() {} -type TlvType65582 = *tlvType65582 +type TlvType65783 = *tlvType65783 -type tlvType65583 struct{} +type tlvType65784 struct{} -func (t *tlvType65583) TypeVal() Type { - return 65583 +func (t *tlvType65784) TypeVal() Type { + return 65784 } -func (t *tlvType65583) tlv() {} +func (t *tlvType65784) tlv() {} -type TlvType65583 = *tlvType65583 +type TlvType65784 = *tlvType65784 -type tlvType65584 struct{} +type tlvType65785 struct{} -func (t *tlvType65584) TypeVal() Type { - return 65584 +func (t *tlvType65785) TypeVal() Type { + return 65785 } -func (t *tlvType65584) tlv() {} +func (t *tlvType65785) tlv() {} -type TlvType65584 = *tlvType65584 +type TlvType65785 = *tlvType65785 -type tlvType65585 struct{} +type tlvType65786 struct{} -func (t *tlvType65585) TypeVal() Type { - return 65585 +func (t *tlvType65786) TypeVal() Type { + return 65786 } -func (t *tlvType65585) tlv() {} +func (t *tlvType65786) tlv() {} + +type TlvType65786 = *tlvType65786 + +type tlvType65787 struct{} + +func (t *tlvType65787) TypeVal() Type { + return 65787 +} + +func (t *tlvType65787) tlv() {} -type TlvType65585 = *tlvType65585 +type TlvType65787 = *tlvType65787 -type tlvType65586 struct{} +type tlvType65788 struct{} -func (t *tlvType65586) TypeVal() Type { - return 65586 +func (t *tlvType65788) TypeVal() Type { + return 65788 } -func (t *tlvType65586) tlv() {} +func (t *tlvType65788) tlv() {} -type TlvType65586 = *tlvType65586 +type TlvType65788 = *tlvType65788 -type tlvType65587 struct{} +type tlvType65789 struct{} -func (t *tlvType65587) TypeVal() Type { - return 65587 +func (t *tlvType65789) TypeVal() Type { + return 65789 } -func (t *tlvType65587) tlv() {} +func (t *tlvType65789) tlv() {} -type TlvType65587 = *tlvType65587 +type TlvType65789 = *tlvType65789 -type tlvType65588 struct{} +type tlvType65790 struct{} -func (t *tlvType65588) TypeVal() Type { - return 65588 +func (t *tlvType65790) TypeVal() Type { + return 65790 } -func (t *tlvType65588) tlv() {} +func (t *tlvType65790) tlv() {} -type TlvType65588 = *tlvType65588 +type TlvType65790 = *tlvType65790 -type tlvType65589 struct{} +type tlvType65791 struct{} -func (t *tlvType65589) TypeVal() Type { - return 65589 +func (t *tlvType65791) TypeVal() Type { + return 65791 } -func (t *tlvType65589) tlv() {} +func (t *tlvType65791) tlv() {} -type TlvType65589 = *tlvType65589 +type TlvType65791 = *tlvType65791 -type tlvType65590 struct{} +type tlvType65792 struct{} -func (t *tlvType65590) TypeVal() Type { - return 65590 +func (t *tlvType65792) TypeVal() Type { + return 65792 } -func (t *tlvType65590) tlv() {} +func (t *tlvType65792) tlv() {} -type TlvType65590 = *tlvType65590 +type TlvType65792 = *tlvType65792 -type tlvType65591 struct{} +type tlvType65793 struct{} -func (t *tlvType65591) TypeVal() Type { - return 65591 +func (t *tlvType65793) TypeVal() Type { + return 65793 } -func (t *tlvType65591) tlv() {} +func (t *tlvType65793) tlv() {} -type TlvType65591 = *tlvType65591 +type TlvType65793 = *tlvType65793 -type tlvType65592 struct{} +type tlvType65794 struct{} -func (t *tlvType65592) TypeVal() Type { - return 65592 +func (t *tlvType65794) TypeVal() Type { + return 65794 } -func (t *tlvType65592) tlv() {} +func (t *tlvType65794) tlv() {} -type TlvType65592 = *tlvType65592 +type TlvType65794 = *tlvType65794 -type tlvType65593 struct{} +type tlvType65795 struct{} -func (t *tlvType65593) TypeVal() Type { - return 65593 +func (t *tlvType65795) TypeVal() Type { + return 65795 } -func (t *tlvType65593) tlv() {} +func (t *tlvType65795) tlv() {} -type TlvType65593 = *tlvType65593 +type TlvType65795 = *tlvType65795 -type tlvType65594 struct{} +type tlvType65796 struct{} -func (t *tlvType65594) TypeVal() Type { - return 65594 +func (t *tlvType65796) TypeVal() Type { + return 65796 } -func (t *tlvType65594) tlv() {} +func (t *tlvType65796) tlv() {} -type TlvType65594 = *tlvType65594 +type TlvType65796 = *tlvType65796 -type tlvType65595 struct{} +type tlvType65797 struct{} -func (t *tlvType65595) TypeVal() Type { - return 65595 +func (t *tlvType65797) TypeVal() Type { + return 65797 } -func (t *tlvType65595) tlv() {} +func (t *tlvType65797) tlv() {} -type TlvType65595 = *tlvType65595 +type TlvType65797 = *tlvType65797 -type tlvType65596 struct{} +type tlvType65798 struct{} -func (t *tlvType65596) TypeVal() Type { - return 65596 +func (t *tlvType65798) TypeVal() Type { + return 65798 } -func (t *tlvType65596) tlv() {} +func (t *tlvType65798) tlv() {} -type TlvType65596 = *tlvType65596 +type TlvType65798 = *tlvType65798 -type tlvType65597 struct{} +type tlvType65799 struct{} -func (t *tlvType65597) TypeVal() Type { - return 65597 +func (t *tlvType65799) TypeVal() Type { + return 65799 } -func (t *tlvType65597) tlv() {} +func (t *tlvType65799) tlv() {} -type TlvType65597 = *tlvType65597 +type TlvType65799 = *tlvType65799 -type tlvType65598 struct{} +type tlvType65800 struct{} -func (t *tlvType65598) TypeVal() Type { - return 65598 +func (t *tlvType65800) TypeVal() Type { + return 65800 } -func (t *tlvType65598) tlv() {} +func (t *tlvType65800) tlv() {} -type TlvType65598 = *tlvType65598 +type TlvType65800 = *tlvType65800 -type tlvType65599 struct{} +type tlvType65801 struct{} -func (t *tlvType65599) TypeVal() Type { - return 65599 +func (t *tlvType65801) TypeVal() Type { + return 65801 } -func (t *tlvType65599) tlv() {} +func (t *tlvType65801) tlv() {} -type TlvType65599 = *tlvType65599 +type TlvType65801 = *tlvType65801 -type tlvType65600 struct{} +type tlvType65802 struct{} -func (t *tlvType65600) TypeVal() Type { - return 65600 +func (t *tlvType65802) TypeVal() Type { + return 65802 } -func (t *tlvType65600) tlv() {} +func (t *tlvType65802) tlv() {} -type TlvType65600 = *tlvType65600 +type TlvType65802 = *tlvType65802 -type tlvType65601 struct{} +type tlvType65803 struct{} -func (t *tlvType65601) TypeVal() Type { - return 65601 +func (t *tlvType65803) TypeVal() Type { + return 65803 } -func (t *tlvType65601) tlv() {} +func (t *tlvType65803) tlv() {} -type TlvType65601 = *tlvType65601 +type TlvType65803 = *tlvType65803 -type tlvType65602 struct{} +type tlvType65804 struct{} -func (t *tlvType65602) TypeVal() Type { - return 65602 +func (t *tlvType65804) TypeVal() Type { + return 65804 } -func (t *tlvType65602) tlv() {} +func (t *tlvType65804) tlv() {} -type TlvType65602 = *tlvType65602 +type TlvType65804 = *tlvType65804 -type tlvType65603 struct{} +type tlvType65805 struct{} -func (t *tlvType65603) TypeVal() Type { - return 65603 +func (t *tlvType65805) TypeVal() Type { + return 65805 } -func (t *tlvType65603) tlv() {} +func (t *tlvType65805) tlv() {} -type TlvType65603 = *tlvType65603 +type TlvType65805 = *tlvType65805 -type tlvType65604 struct{} +type tlvType65806 struct{} -func (t *tlvType65604) TypeVal() Type { - return 65604 +func (t *tlvType65806) TypeVal() Type { + return 65806 } -func (t *tlvType65604) tlv() {} +func (t *tlvType65806) tlv() {} -type TlvType65604 = *tlvType65604 +type TlvType65806 = *tlvType65806 -type tlvType65605 struct{} +type tlvType65807 struct{} -func (t *tlvType65605) TypeVal() Type { - return 65605 +func (t *tlvType65807) TypeVal() Type { + return 65807 } -func (t *tlvType65605) tlv() {} +func (t *tlvType65807) tlv() {} -type TlvType65605 = *tlvType65605 +type TlvType65807 = *tlvType65807 -type tlvType65606 struct{} +type tlvType65808 struct{} -func (t *tlvType65606) TypeVal() Type { - return 65606 +func (t *tlvType65808) TypeVal() Type { + return 65808 } -func (t *tlvType65606) tlv() {} +func (t *tlvType65808) tlv() {} -type TlvType65606 = *tlvType65606 +type TlvType65808 = *tlvType65808 -type tlvType65607 struct{} +type tlvType65809 struct{} -func (t *tlvType65607) TypeVal() Type { - return 65607 +func (t *tlvType65809) TypeVal() Type { + return 65809 } -func (t *tlvType65607) tlv() {} +func (t *tlvType65809) tlv() {} -type TlvType65607 = *tlvType65607 +type TlvType65809 = *tlvType65809 -type tlvType65608 struct{} +type tlvType65810 struct{} -func (t *tlvType65608) TypeVal() Type { - return 65608 +func (t *tlvType65810) TypeVal() Type { + return 65810 } -func (t *tlvType65608) tlv() {} +func (t *tlvType65810) tlv() {} -type TlvType65608 = *tlvType65608 +type TlvType65810 = *tlvType65810 -type tlvType65609 struct{} +type tlvType65811 struct{} -func (t *tlvType65609) TypeVal() Type { - return 65609 +func (t *tlvType65811) TypeVal() Type { + return 65811 } -func (t *tlvType65609) tlv() {} +func (t *tlvType65811) tlv() {} -type TlvType65609 = *tlvType65609 +type TlvType65811 = *tlvType65811 -type tlvType65610 struct{} +type tlvType65812 struct{} -func (t *tlvType65610) TypeVal() Type { - return 65610 +func (t *tlvType65812) TypeVal() Type { + return 65812 } -func (t *tlvType65610) tlv() {} +func (t *tlvType65812) tlv() {} -type TlvType65610 = *tlvType65610 +type TlvType65812 = *tlvType65812 -type tlvType65611 struct{} +type tlvType65813 struct{} -func (t *tlvType65611) TypeVal() Type { - return 65611 +func (t *tlvType65813) TypeVal() Type { + return 65813 } -func (t *tlvType65611) tlv() {} +func (t *tlvType65813) tlv() {} -type TlvType65611 = *tlvType65611 +type TlvType65813 = *tlvType65813 -type tlvType65612 struct{} +type tlvType65814 struct{} -func (t *tlvType65612) TypeVal() Type { - return 65612 +func (t *tlvType65814) TypeVal() Type { + return 65814 } -func (t *tlvType65612) tlv() {} +func (t *tlvType65814) tlv() {} -type TlvType65612 = *tlvType65612 +type TlvType65814 = *tlvType65814 -type tlvType65613 struct{} +type tlvType65815 struct{} -func (t *tlvType65613) TypeVal() Type { - return 65613 +func (t *tlvType65815) TypeVal() Type { + return 65815 } -func (t *tlvType65613) tlv() {} +func (t *tlvType65815) tlv() {} -type TlvType65613 = *tlvType65613 +type TlvType65815 = *tlvType65815 -type tlvType65614 struct{} +type tlvType65816 struct{} -func (t *tlvType65614) TypeVal() Type { - return 65614 +func (t *tlvType65816) TypeVal() Type { + return 65816 } -func (t *tlvType65614) tlv() {} +func (t *tlvType65816) tlv() {} -type TlvType65614 = *tlvType65614 +type TlvType65816 = *tlvType65816 -type tlvType65615 struct{} +type tlvType65817 struct{} -func (t *tlvType65615) TypeVal() Type { - return 65615 +func (t *tlvType65817) TypeVal() Type { + return 65817 } -func (t *tlvType65615) tlv() {} +func (t *tlvType65817) tlv() {} -type TlvType65615 = *tlvType65615 +type TlvType65817 = *tlvType65817 -type tlvType65616 struct{} +type tlvType65818 struct{} -func (t *tlvType65616) TypeVal() Type { - return 65616 +func (t *tlvType65818) TypeVal() Type { + return 65818 } -func (t *tlvType65616) tlv() {} +func (t *tlvType65818) tlv() {} -type TlvType65616 = *tlvType65616 +type TlvType65818 = *tlvType65818 -type tlvType65617 struct{} +type tlvType65819 struct{} -func (t *tlvType65617) TypeVal() Type { - return 65617 +func (t *tlvType65819) TypeVal() Type { + return 65819 } -func (t *tlvType65617) tlv() {} +func (t *tlvType65819) tlv() {} -type TlvType65617 = *tlvType65617 +type TlvType65819 = *tlvType65819 -type tlvType65618 struct{} +type tlvType65820 struct{} -func (t *tlvType65618) TypeVal() Type { - return 65618 +func (t *tlvType65820) TypeVal() Type { + return 65820 } -func (t *tlvType65618) tlv() {} +func (t *tlvType65820) tlv() {} -type TlvType65618 = *tlvType65618 +type TlvType65820 = *tlvType65820 -type tlvType65619 struct{} +type tlvType65821 struct{} -func (t *tlvType65619) TypeVal() Type { - return 65619 +func (t *tlvType65821) TypeVal() Type { + return 65821 } -func (t *tlvType65619) tlv() {} +func (t *tlvType65821) tlv() {} -type TlvType65619 = *tlvType65619 +type TlvType65821 = *tlvType65821 -type tlvType65620 struct{} +type tlvType65822 struct{} -func (t *tlvType65620) TypeVal() Type { - return 65620 +func (t *tlvType65822) TypeVal() Type { + return 65822 } -func (t *tlvType65620) tlv() {} +func (t *tlvType65822) tlv() {} -type TlvType65620 = *tlvType65620 +type TlvType65822 = *tlvType65822 -type tlvType65621 struct{} +type tlvType65823 struct{} -func (t *tlvType65621) TypeVal() Type { - return 65621 +func (t *tlvType65823) TypeVal() Type { + return 65823 } -func (t *tlvType65621) tlv() {} +func (t *tlvType65823) tlv() {} -type TlvType65621 = *tlvType65621 +type TlvType65823 = *tlvType65823 -type tlvType65622 struct{} +type tlvType65824 struct{} -func (t *tlvType65622) TypeVal() Type { - return 65622 +func (t *tlvType65824) TypeVal() Type { + return 65824 } -func (t *tlvType65622) tlv() {} +func (t *tlvType65824) tlv() {} -type TlvType65622 = *tlvType65622 +type TlvType65824 = *tlvType65824 -type tlvType65623 struct{} +type tlvType65825 struct{} -func (t *tlvType65623) TypeVal() Type { - return 65623 +func (t *tlvType65825) TypeVal() Type { + return 65825 } -func (t *tlvType65623) tlv() {} +func (t *tlvType65825) tlv() {} -type TlvType65623 = *tlvType65623 +type TlvType65825 = *tlvType65825 -type tlvType65624 struct{} +type tlvType65826 struct{} -func (t *tlvType65624) TypeVal() Type { - return 65624 +func (t *tlvType65826) TypeVal() Type { + return 65826 } -func (t *tlvType65624) tlv() {} +func (t *tlvType65826) tlv() {} -type TlvType65624 = *tlvType65624 +type TlvType65826 = *tlvType65826 -type tlvType65625 struct{} +type tlvType65827 struct{} -func (t *tlvType65625) TypeVal() Type { - return 65625 +func (t *tlvType65827) TypeVal() Type { + return 65827 } -func (t *tlvType65625) tlv() {} +func (t *tlvType65827) tlv() {} -type TlvType65625 = *tlvType65625 +type TlvType65827 = *tlvType65827 -type tlvType65626 struct{} +type tlvType65828 struct{} -func (t *tlvType65626) TypeVal() Type { - return 65626 +func (t *tlvType65828) TypeVal() Type { + return 65828 } -func (t *tlvType65626) tlv() {} +func (t *tlvType65828) tlv() {} -type TlvType65626 = *tlvType65626 +type TlvType65828 = *tlvType65828 -type tlvType65627 struct{} +type tlvType65829 struct{} -func (t *tlvType65627) TypeVal() Type { - return 65627 +func (t *tlvType65829) TypeVal() Type { + return 65829 } -func (t *tlvType65627) tlv() {} +func (t *tlvType65829) tlv() {} -type TlvType65627 = *tlvType65627 +type TlvType65829 = *tlvType65829 -type tlvType65628 struct{} +type tlvType65830 struct{} -func (t *tlvType65628) TypeVal() Type { - return 65628 +func (t *tlvType65830) TypeVal() Type { + return 65830 } -func (t *tlvType65628) tlv() {} +func (t *tlvType65830) tlv() {} -type TlvType65628 = *tlvType65628 +type TlvType65830 = *tlvType65830 -type tlvType65629 struct{} +type tlvType65831 struct{} -func (t *tlvType65629) TypeVal() Type { - return 65629 +func (t *tlvType65831) TypeVal() Type { + return 65831 } -func (t *tlvType65629) tlv() {} +func (t *tlvType65831) tlv() {} -type TlvType65629 = *tlvType65629 +type TlvType65831 = *tlvType65831 -type tlvType65630 struct{} +type tlvType65832 struct{} -func (t *tlvType65630) TypeVal() Type { - return 65630 +func (t *tlvType65832) TypeVal() Type { + return 65832 } -func (t *tlvType65630) tlv() {} +func (t *tlvType65832) tlv() {} -type TlvType65630 = *tlvType65630 +type TlvType65832 = *tlvType65832 -type tlvType65631 struct{} +type tlvType65833 struct{} -func (t *tlvType65631) TypeVal() Type { - return 65631 +func (t *tlvType65833) TypeVal() Type { + return 65833 } -func (t *tlvType65631) tlv() {} +func (t *tlvType65833) tlv() {} -type TlvType65631 = *tlvType65631 +type TlvType65833 = *tlvType65833 -type tlvType65632 struct{} +type tlvType65834 struct{} -func (t *tlvType65632) TypeVal() Type { - return 65632 +func (t *tlvType65834) TypeVal() Type { + return 65834 } -func (t *tlvType65632) tlv() {} +func (t *tlvType65834) tlv() {} -type TlvType65632 = *tlvType65632 +type TlvType65834 = *tlvType65834 -type tlvType65633 struct{} +type tlvType65835 struct{} -func (t *tlvType65633) TypeVal() Type { - return 65633 +func (t *tlvType65835) TypeVal() Type { + return 65835 } -func (t *tlvType65633) tlv() {} +func (t *tlvType65835) tlv() {} -type TlvType65633 = *tlvType65633 +type TlvType65835 = *tlvType65835 -type tlvType65634 struct{} +type tlvType65836 struct{} -func (t *tlvType65634) TypeVal() Type { - return 65634 +func (t *tlvType65836) TypeVal() Type { + return 65836 } -func (t *tlvType65634) tlv() {} +func (t *tlvType65836) tlv() {} -type TlvType65634 = *tlvType65634 +type TlvType65836 = *tlvType65836 -type tlvType65635 struct{} +type tlvType1000000000 struct{} -func (t *tlvType65635) TypeVal() Type { - return 65635 +func (t *tlvType1000000000) TypeVal() Type { + return 1000000000 } -func (t *tlvType65635) tlv() {} +func (t *tlvType1000000000) tlv() {} -type TlvType65635 = *tlvType65635 +type TlvType1000000000 = *tlvType1000000000 -type tlvType65636 struct{} +type tlvType3000000000 struct{} -func (t *tlvType65636) TypeVal() Type { - return 65636 +func (t *tlvType3000000000) TypeVal() Type { + return 3000000000 } -func (t *tlvType65636) tlv() {} +func (t *tlvType3000000000) tlv() {} -type TlvType65636 = *tlvType65636 +type TlvType3000000000 = *tlvType3000000000