From 1a3be78471ef2394f67b62402417b35b6813274b Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 13 Mar 2023 12:45:58 +0100 Subject: [PATCH 01/87] cmd/lncli: add --num_confs to wallet psbt fund command --- cmd/lncli/walletrpc_active.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cmd/lncli/walletrpc_active.go b/cmd/lncli/walletrpc_active.go index abccb2b2c..7bae32fbf 100644 --- a/cmd/lncli/walletrpc_active.go +++ b/cmd/lncli/walletrpc_active.go @@ -660,6 +660,13 @@ var fundPsbtCommand = cli.Command{ "always use the coin selection key scope to " + "generate the change address", }, + cli.Uint64Flag{ + Name: "min_confs", + Usage: "(optional) the minimum number of " + + "confirmations each input used for the PSBT " + + "transaction must satisfy", + Value: defaultUtxoMinConf, + }, }, Action: actionDecorator(fundPsbt), } @@ -673,8 +680,11 @@ func fundPsbt(ctx *cli.Context) error { return cli.ShowCommandHelp(ctx, "fund") } + minConfs := int32(ctx.Uint64("min_confs")) req := &walletrpc.FundPsbtRequest{ - Account: ctx.String("account"), + Account: ctx.String("account"), + MinConfs: minConfs, + SpendUnconfirmed: minConfs == 0, } // Parse template flags. From 1ed63a85b39148f3e262e889edc8571bb4e45773 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 13 Mar 2023 12:46:05 +0100 Subject: [PATCH 02/87] docs: add release notes --- docs/release-notes/release-notes-0.16.1.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 docs/release-notes/release-notes-0.16.1.md diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md new file mode 100644 index 000000000..eb882a777 --- /dev/null +++ b/docs/release-notes/release-notes-0.16.1.md @@ -0,0 +1,7 @@ +# Release Notes + +## `lncli` + +- The `lncli wallet psbt fund` command now allows users to specify the + [`--min_confs` flag](https://github.com/lightningnetwork/lnd/pull/7510). + From 20e53e85b40fb24f61a8944274974b0b160251dd Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 14 Mar 2023 21:24:50 +0800 Subject: [PATCH 03/87] itest+lntest: make sure states are cleaned when tests end This commit changes how the node's state is updated to make sure the test cleans up the node's state. Also `testLookupHtlcResolution` is fixed with a cleanup. --- itest/lnd_htlc_test.go | 1 + lntest/harness.go | 61 +++++++++++++++++++++++++++--------------- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/itest/lnd_htlc_test.go b/itest/lnd_htlc_test.go index 4e73a385b..fc04fe8d0 100644 --- a/itest/lnd_htlc_test.go +++ b/itest/lnd_htlc_test.go @@ -24,6 +24,7 @@ func testLookupHtlcResolution(ht *lntest.HarnessTest) { cp := ht.OpenChannel( alice, carol, lntest.OpenChannelParams{Amt: chanAmt}, ) + defer ht.CloseChannel(alice, cp) // Channel should be ready for payments. const payAmt = 100 diff --git a/lntest/harness.go b/lntest/harness.go index 95cc1afbb..819a0a8d3 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -299,9 +299,6 @@ func (h *HarnessTest) resetStandbyNodes(t *testing.T) { // config for the coming test. This will also inherit the // test's running context. h.RestartNodeWithExtraArgs(hn, hn.Cfg.OriginalExtraArgs) - - // Update the node's internal state. - hn.UpdateState() } } @@ -433,8 +430,19 @@ func (h *HarnessTest) cleanupStandbyNode(hn *node.HarnessNode) { // Delete all payments made from this test. hn.RPC.DeleteAllPayments() - // Finally, check the node is in a clean state for the following tests. - h.validateNodeState(hn) + // Check the node's current state with timeout. + // + // NOTE: we need to do this in a `wait` because it takes some time for + // the node to update its internal state. Once the RPCs are synced we + // can then remove this wait. + err := wait.NoError(func() error { + // Update the node's internal state. + hn.UpdateState() + + // Check the node is in a clean state for the following tests. + return h.validateNodeState(hn) + }, wait.DefaultTimeout) + require.NoError(h, err, "timeout checking node's state") } // removeConnectionns will remove all connections made on the standby nodes @@ -752,32 +760,43 @@ func (h *HarnessTest) SetFeeEstimateWithConf( // validateNodeState checks that the node doesn't have any uncleaned states // which will affect its following tests. -func (h *HarnessTest) validateNodeState(hn *node.HarnessNode) { - errStr := func(subject string) string { - return fmt.Sprintf("%s: found %s channels, please close "+ +func (h *HarnessTest) validateNodeState(hn *node.HarnessNode) error { + errStr := func(subject string) error { + return fmt.Errorf("%s: found %s channels, please close "+ "them properly", hn.Name(), subject) } // If the node still has open channels, it's most likely that the // current test didn't close it properly. - require.Zerof(h, hn.State.OpenChannel.Active, errStr("active")) - require.Zerof(h, hn.State.OpenChannel.Public, errStr("public")) - require.Zerof(h, hn.State.OpenChannel.Private, errStr("private")) - require.Zerof(h, hn.State.OpenChannel.Pending, errStr("pending open")) + if hn.State.OpenChannel.Active != 0 { + return errStr("active") + } + if hn.State.OpenChannel.Public != 0 { + return errStr("public") + } + if hn.State.OpenChannel.Private != 0 { + return errStr("private") + } + if hn.State.OpenChannel.Pending != 0 { + return errStr("pending open") + } // The number of pending force close channels should be zero. - require.Zerof(h, hn.State.CloseChannel.PendingForceClose, - errStr("pending force")) + if hn.State.CloseChannel.PendingForceClose != 0 { + return errStr("pending force") + } // The number of waiting close channels should be zero. - require.Zerof(h, hn.State.CloseChannel.WaitingClose, - errStr("waiting close")) + if hn.State.CloseChannel.WaitingClose != 0 { + return errStr("waiting close") + } // Ths number of payments should be zero. - // TODO(yy): no need to check since it's deleted in the cleanup? Or - // check it in a wait? - require.Zerof(h, hn.State.Payment.Total, "%s: found "+ - "uncleaned payments, please delete all of them properly", - hn.Name()) + if hn.State.Payment.Total != 0 { + return fmt.Errorf("%s: found uncleaned payments, please "+ + "delete all of them properly", hn.Name()) + } + + return nil } // GetChanPointFundingTxid takes a channel point and converts it into a chain From 941a33af3188eebe5b3f715abb48e6863a432f67 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 9 Mar 2023 02:40:15 +0800 Subject: [PATCH 04/87] Makefile: add testing_flags to coverage test --- Makefile | 2 +- make/testing_flags.mk | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a45e86817..1c1e074b2 100644 --- a/Makefile +++ b/Makefile @@ -190,7 +190,7 @@ unit-debug: $(BTCD_BIN) unit-cover: $(GOACC_BIN) @$(call print, "Running unit coverage tests.") - $(GOACC_BIN) $(COVER_PKG) -- -tags="$(DEV_TAGS) $(LOG_TAGS)" + $(GOACC) unit-race: @$(call print, "Running unit race tests.") diff --git a/make/testing_flags.mk b/make/testing_flags.mk index f35a779a7..b4109bb5c 100644 --- a/make/testing_flags.mk +++ b/make/testing_flags.mk @@ -116,3 +116,6 @@ endif # Construct the integration test command with the added build flags. ITEST_TAGS := $(DEV_TAGS) $(RPC_TAGS) integration $(backend) + +# Construct the coverage test command with the added build flags. +GOACC := $(GOACC_BIN) $(COVER_PKG) -- -tags="$(DEV_TAGS) $(LOG_TAGS)" $(TEST_FLAGS) From 4054ace4e1655370d2ffc8ed01ce52302cd8eeae Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 8 Mar 2023 14:27:45 +0800 Subject: [PATCH 05/87] htlcswitch: return `FEE_INSUFFICIENT` before checking balance --- htlcswitch/link.go | 25 +++++++++++++------------ htlcswitch/link_test.go | 13 +++++++++++++ htlcswitch/switch_test.go | 1 + 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/htlcswitch/link.go b/htlcswitch/link.go index bb800f5e4..b1836c7c7 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -2551,17 +2551,8 @@ func (l *channelLink) CheckHtlcForward(payHash [32]byte, policy := l.cfg.FwrdingPolicy l.RUnlock() - // First check whether the outgoing htlc satisfies the channel policy. - err := l.canSendHtlc( - policy, payHash, amtToForward, outgoingTimeout, heightNow, - originalScid, - ) - if err != nil { - return err - } - - // Next, using the amount of the incoming HTLC, we'll calculate the - // expected fee this incoming HTLC must carry in order to satisfy the + // Using the amount of the incoming HTLC, we'll calculate the expected + // fee this incoming HTLC must carry in order to satisfy the // constraints of the outgoing link. expectedFee := ExpectedFee(policy, amtToForward) @@ -2569,7 +2560,8 @@ func (l *channelLink) CheckHtlcForward(payHash [32]byte, // this HTLC as it didn't provide a sufficient amount of fees, or the // values have been tampered with, or the send used incorrect/dated // information to construct the forwarding information for this hop. In - // any case, we'll cancel this HTLC. + // any case, we'll cancel this HTLC. We're checking for this case first + // to leak as little information as possible. actualFee := incomingHtlcAmt - amtToForward if incomingHtlcAmt < amtToForward || actualFee < expectedFee { l.log.Warnf("outgoing htlc(%x) has insufficient fee: "+ @@ -2585,6 +2577,15 @@ func (l *channelLink) CheckHtlcForward(payHash [32]byte, return NewLinkError(failure) } + // Check whether the outgoing htlc satisfies the channel policy. + err := l.canSendHtlc( + policy, payHash, amtToForward, outgoingTimeout, heightNow, + originalScid, + ) + if err != nil { + return err + } + // Finally, we'll ensure that the time-lock on the outgoing HTLC meets // the following constraint: the incoming time-lock minus our time-lock // delta should equal the outgoing time lock. Otherwise, whether the diff --git a/htlcswitch/link_test.go b/htlcswitch/link_test.go index 55d77d13d..b58c8a63b 100644 --- a/htlcswitch/link_test.go +++ b/htlcswitch/link_test.go @@ -5643,6 +5643,19 @@ func TestCheckHtlcForward(t *testing.T) { } }) + // Test that insufficient fee error takes preference over insufficient + // channel balance. + t.Run("insufficient fee error preference", func(t *testing.T) { + t.Parallel() + + result := link.CheckHtlcForward( + hash, 100005, 100000, 200, + 150, 0, lnwire.ShortChannelID{}, + ) + _, ok := result.WireMessage().(*lnwire.FailFeeInsufficient) + require.True(t, ok, "expected FailFeeInsufficient failure code") + }) + t.Run("expiry too soon", func(t *testing.T) { result := link.CheckHtlcForward(hash, 1500, 1000, 200, 150, 190, lnwire.ShortChannelID{}) diff --git a/htlcswitch/switch_test.go b/htlcswitch/switch_test.go index 2e0400340..b1e134954 100644 --- a/htlcswitch/switch_test.go +++ b/htlcswitch/switch_test.go @@ -5339,6 +5339,7 @@ func testSwitchHandlePacketForward(t *testing.T, zeroConf, private, ogPacket := &htlcPacket{ incomingChanID: bobLink.ShortChanID(), incomingHTLCID: 0, + incomingAmount: 1000, obfuscator: NewMockObfuscator(), htlc: &lnwire.UpdateAddHTLC{ PaymentHash: rhash, From 7853cf0a43f3f69d8fe0b7077a7b5232d9038340 Mon Sep 17 00:00:00 2001 From: Tommy Volk Date: Thu, 26 May 2022 19:43:39 +0000 Subject: [PATCH 06/87] docs: update release notes --- docs/release-notes/release-notes-0.16.1.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index eb882a777..0edf7c3c8 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -5,3 +5,13 @@ - The `lncli wallet psbt fund` command now allows users to specify the [`--min_confs` flag](https://github.com/lightningnetwork/lnd/pull/7510). +## Misc + +* [Return `FEE_INSUFFICIENT` before checking balance for incoming low-fee + HTLCs.](https://github.com/lightningnetwork/lnd/pull/7490). + +# Contributors (Alphabetical Order) + +* Oliver Gugger +* Tommy Volk +* Yong Yu From 40ac82e439f2676dd4d7035c9fe38c1141908d6d Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 18 Oct 2022 12:08:46 +0200 Subject: [PATCH 07/87] watchtower: add ClientSessionFilterFn to session requests In this commit, a new ClientSessionFilterFn parameter is added to the DB's ListClientSession method which can be used to allow the caller to specify a filter function for filtering sessions read from the DB. Currently all filtering of sessions are done after the sessions have been read from the DB, so adding this option should provide some efficiency. --- watchtower/wtclient/client.go | 12 ++++---- watchtower/wtclient/interface.go | 3 +- watchtower/wtdb/client_db.go | 49 +++++++++++++++++++++++-------- watchtower/wtdb/client_db_test.go | 13 ++++---- watchtower/wtmock/client_db.go | 13 ++++++-- 5 files changed, 62 insertions(+), 28 deletions(-) diff --git a/watchtower/wtclient/client.go b/watchtower/wtclient/client.go index 685170eab..8cd2b7e7d 100644 --- a/watchtower/wtclient/client.go +++ b/watchtower/wtclient/client.go @@ -418,7 +418,7 @@ func getTowerAndSessionCandidates(db DB, keyRing ECDHKeyRing, return nil, err } - sessions, err := db.ListClientSessions(&tower.ID, opts...) + sessions, err := db.ListClientSessions(&tower.ID, nil, opts...) if err != nil { return nil, err } @@ -470,7 +470,7 @@ func getClientSessions(db DB, keyRing ECDHKeyRing, forTower *wtdb.TowerID, opts ...wtdb.ClientSessionListOption) ( map[wtdb.SessionID]*ClientSession, error) { - dbSessions, err := db.ListClientSessions(forTower, opts...) + dbSessions, err := db.ListClientSessions(forTower, nil, opts...) if err != nil { return nil, err } @@ -1289,7 +1289,7 @@ func (c *TowerClient) handleStaleTower(msg *staleTowerMsg) error { // Otherwise, the tower should no longer be used for future session // negotiations and backups. pubKey := msg.pubKey.SerializeCompressed() - sessions, err := c.cfg.DB.ListClientSessions(&dbTower.ID) + sessions, err := c.cfg.DB.ListClientSessions(&dbTower.ID, nil) if err != nil { return fmt.Errorf("unable to retrieve sessions for tower %x: "+ "%v", pubKey, err) @@ -1320,7 +1320,7 @@ func (c *TowerClient) RegisteredTowers(opts ...wtdb.ClientSessionListOption) ( if err != nil { return nil, err } - clientSessions, err := c.cfg.DB.ListClientSessions(nil, opts...) + clientSessions, err := c.cfg.DB.ListClientSessions(nil, nil, opts...) if err != nil { return nil, err } @@ -1361,7 +1361,9 @@ func (c *TowerClient) LookupTower(pubKey *btcec.PublicKey, return nil, err } - towerSessions, err := c.cfg.DB.ListClientSessions(&tower.ID, opts...) + towerSessions, err := c.cfg.DB.ListClientSessions( + &tower.ID, nil, opts..., + ) if err != nil { return nil, err } diff --git a/watchtower/wtclient/interface.go b/watchtower/wtclient/interface.go index 63d718b60..9751988ba 100644 --- a/watchtower/wtclient/interface.go +++ b/watchtower/wtclient/interface.go @@ -60,7 +60,8 @@ type DB interface { // ListClientSessions returns the set of all client sessions known to // the db. An optional tower ID can be used to filter out any client // sessions in the response that do not correspond to this tower. - ListClientSessions(*wtdb.TowerID, ...wtdb.ClientSessionListOption) ( + ListClientSessions(*wtdb.TowerID, wtdb.ClientSessionFilterFn, + ...wtdb.ClientSessionListOption) ( map[wtdb.SessionID]*wtdb.ClientSession, error) // FetchSessionCommittedUpdates retrieves the current set of un-acked diff --git a/watchtower/wtdb/client_db.go b/watchtower/wtdb/client_db.go index f8eda37bf..3cbe0c6f1 100644 --- a/watchtower/wtdb/client_db.go +++ b/watchtower/wtdb/client_db.go @@ -138,6 +138,10 @@ var ( // range-index found for the given session ID to channel ID pair. ErrNoRangeIndexFound = errors.New("no range index found for the " + "given session-channel pair") + + // ErrSessionFailedFilterFn indicates that a particular session did + // not pass the filter func provided by the caller. + ErrSessionFailedFilterFn = errors.New("session failed filter func") ) // NewBoltBackendCreator returns a function that creates a new bbolt backend for @@ -469,7 +473,7 @@ func (c *ClientDB) RemoveTower(pubKey *btcec.PublicKey, addr net.Addr) error { towerSessions, err := c.listTowerSessions( towerID, sessions, chanIDIndexBkt, - towersToSessionsIndex, + towersToSessionsIndex, nil, WithPerCommittedUpdate(perCommittedUpdate), ) if err != nil { @@ -960,7 +964,8 @@ func getSessionKeyIndex(keyIndexes kvdb.RwBucket, towerID TowerID, // optional tower ID can be used to filter out any client sessions in the // response that do not correspond to this tower. func (c *ClientDB) ListClientSessions(id *TowerID, - opts ...ClientSessionListOption) (map[SessionID]*ClientSession, error) { + filterFn ClientSessionFilterFn, opts ...ClientSessionListOption) ( + map[SessionID]*ClientSession, error) { var clientSessions map[SessionID]*ClientSession err := kvdb.View(c.db, func(tx kvdb.RTx) error { @@ -985,7 +990,7 @@ func (c *ClientDB) ListClientSessions(id *TowerID, // known to the db. if id == nil { clientSessions, err = c.listClientAllSessions( - sessions, chanIDIndexBkt, opts..., + sessions, chanIDIndexBkt, filterFn, opts..., ) return err } @@ -998,7 +1003,7 @@ func (c *ClientDB) ListClientSessions(id *TowerID, clientSessions, err = c.listTowerSessions( *id, sessions, chanIDIndexBkt, towerToSessionIndex, - opts..., + filterFn, opts..., ) return err }, func() { @@ -1013,7 +1018,8 @@ func (c *ClientDB) ListClientSessions(id *TowerID, // listClientAllSessions returns the set of all client sessions known to the db. func (c *ClientDB) listClientAllSessions(sessions, chanIDIndexBkt kvdb.RBucket, - opts ...ClientSessionListOption) (map[SessionID]*ClientSession, error) { + filterFn ClientSessionFilterFn, opts ...ClientSessionListOption) ( + map[SessionID]*ClientSession, error) { clientSessions := make(map[SessionID]*ClientSession) err := sessions.ForEach(func(k, _ []byte) error { @@ -1022,9 +1028,11 @@ func (c *ClientDB) listClientAllSessions(sessions, chanIDIndexBkt kvdb.RBucket, // committed updates and compute the highest known commit height // for each channel. session, err := c.getClientSession( - sessions, chanIDIndexBkt, k, opts..., + sessions, chanIDIndexBkt, k, filterFn, opts..., ) - if err != nil { + if errors.Is(err, ErrSessionFailedFilterFn) { + return nil + } else if err != nil { return err } @@ -1042,8 +1050,8 @@ func (c *ClientDB) listClientAllSessions(sessions, chanIDIndexBkt kvdb.RBucket, // listTowerSessions returns the set of all client sessions known to the db // that are associated with the given tower id. func (c *ClientDB) listTowerSessions(id TowerID, sessionsBkt, chanIDIndexBkt, - towerToSessionIndex kvdb.RBucket, opts ...ClientSessionListOption) ( - map[SessionID]*ClientSession, error) { + towerToSessionIndex kvdb.RBucket, filterFn ClientSessionFilterFn, + opts ...ClientSessionListOption) (map[SessionID]*ClientSession, error) { towerIndexBkt := towerToSessionIndex.NestedReadBucket(id.Bytes()) if towerIndexBkt == nil { @@ -1057,9 +1065,11 @@ func (c *ClientDB) listTowerSessions(id TowerID, sessionsBkt, chanIDIndexBkt, // committed updates and compute the highest known commit height // for each channel. session, err := c.getClientSession( - sessionsBkt, chanIDIndexBkt, k, opts..., + sessionsBkt, chanIDIndexBkt, k, filterFn, opts..., ) - if err != nil { + if errors.Is(err, ErrSessionFailedFilterFn) { + return nil + } else if err != nil { return err } @@ -1523,6 +1533,11 @@ func getClientSessionBody(sessions kvdb.RBucket, return &session, nil } +// ClientSessionFilterFn describes the signature of a callback function that can +// be used to filter the sessions that are returned in any of the DB methods +// that read sessions from the DB. +type ClientSessionFilterFn func(*ClientSession) bool + // PerMaxHeightCB describes the signature of a callback function that can be // called for each channel that a session has updates for to communicate the // maximum commitment height that the session has backed up for the channel. @@ -1533,6 +1548,10 @@ type PerMaxHeightCB func(*ClientSession, lnwire.ChannelID, uint64) // number of updates that the session has for the channel. type PerNumAckedUpdatesCB func(*ClientSession, lnwire.ChannelID, uint16) +// PerAckedUpdateCB describes the signature of a callback function that can be +// called for each of a session's acked updates. +type PerAckedUpdateCB func(*ClientSession, uint16, BackupID) + // PerCommittedUpdateCB describes the signature of a callback function that can // be called for each of a session's committed updates (updates that the client // has not yet received an ACK for). @@ -1597,8 +1616,8 @@ func WithPerCommittedUpdate(cb PerCommittedUpdateCB) ClientSessionListOption { // session id. This method populates the CommittedUpdates, AckUpdates and Tower // in addition to the ClientSession's body. func (c *ClientDB) getClientSession(sessionsBkt, chanIDIndexBkt kvdb.RBucket, - idBytes []byte, opts ...ClientSessionListOption) (*ClientSession, - error) { + idBytes []byte, filterFn ClientSessionFilterFn, + opts ...ClientSessionListOption) (*ClientSession, error) { cfg := NewClientSessionCfg() for _, o := range opts { @@ -1610,6 +1629,10 @@ func (c *ClientDB) getClientSession(sessionsBkt, chanIDIndexBkt kvdb.RBucket, return nil, err } + if filterFn != nil && !filterFn(session) { + return nil, ErrSessionFailedFilterFn + } + // Can't fail because client session body has already been read. sessionBkt := sessionsBkt.NestedReadBucket(idBytes) diff --git a/watchtower/wtdb/client_db_test.go b/watchtower/wtdb/client_db_test.go index 2cafc160b..cd77ec77e 100644 --- a/watchtower/wtdb/client_db_test.go +++ b/watchtower/wtdb/client_db_test.go @@ -49,11 +49,12 @@ func (h *clientDBHarness) insertSession(session *wtdb.ClientSession, } func (h *clientDBHarness) listSessions(id *wtdb.TowerID, + filterFn wtdb.ClientSessionFilterFn, opts ...wtdb.ClientSessionListOption) map[wtdb.SessionID]*wtdb.ClientSession { h.t.Helper() - sessions, err := h.db.ListClientSessions(id, opts...) + sessions, err := h.db.ListClientSessions(id, filterFn, opts...) require.NoError(h.t, err, "unable to list client sessions") return sessions @@ -80,7 +81,7 @@ func (h *clientDBHarness) createTower(lnAddr *lnwire.NetAddress, require.ErrorIs(h.t, err, expErr) require.NotZero(h.t, tower.ID, "tower id should never be 0") - for _, session := range h.listSessions(&tower.ID) { + for _, session := range h.listSessions(&tower.ID, nil) { require.Equal(h.t, wtdb.CSessionActive, session.Status) } @@ -123,7 +124,7 @@ func (h *clientDBHarness) removeTower(pubKey *btcec.PublicKey, addr net.Addr, return } - for _, session := range h.listSessions(&tower.ID) { + for _, session := range h.listSessions(&tower.ID, nil) { require.Equal(h.t, wtdb.CSessionInactive, session.Status, "expected status for session "+ "%v to be %v, got %v", session.ID, @@ -268,7 +269,7 @@ func testCreateClientSession(h *clientDBHarness) { // First, assert that this session is not already present in the // database. - _, ok := h.listSessions(nil)[session.ID] + _, ok := h.listSessions(nil, nil)[session.ID] require.Falsef(h.t, ok, "session for id %x should not exist yet", session.ID) @@ -296,7 +297,7 @@ func testCreateClientSession(h *clientDBHarness) { h.insertSession(session, nil) // Verify that the session now exists in the database. - _, ok = h.listSessions(nil)[session.ID] + _, ok = h.listSessions(nil, nil)[session.ID] require.Truef(h.t, ok, "session for id %x should exist now", session.ID) // Attempt to insert the session again, which should fail due to the @@ -344,7 +345,7 @@ func testFilterClientSessions(h *clientDBHarness) { // We should see the expected sessions for each tower when filtering // them. for towerID, expectedSessions := range towerSessions { - sessions := h.listSessions(&towerID) + sessions := h.listSessions(&towerID, nil) require.Len(h.t, sessions, len(expectedSessions)) for _, expectedSession := range expectedSessions { diff --git a/watchtower/wtmock/client_db.go b/watchtower/wtmock/client_db.go index 095e8cbac..071ee7782 100644 --- a/watchtower/wtmock/client_db.go +++ b/watchtower/wtmock/client_db.go @@ -83,7 +83,7 @@ func (m *ClientDB) CreateTower(lnAddr *lnwire.NetAddress) (*wtdb.Tower, error) { tower = m.towers[towerID] tower.AddAddress(lnAddr.Address) - towerSessions, err := m.listClientSessions(&towerID) + towerSessions, err := m.listClientSessions(&towerID, nil) if err != nil { return nil, err } @@ -135,7 +135,7 @@ func (m *ClientDB) RemoveTower(pubKey *btcec.PublicKey, addr net.Addr) error { return nil } - towerSessions, err := m.listClientSessions(&tower.ID) + towerSessions, err := m.listClientSessions(&tower.ID, nil) if err != nil { return err } @@ -220,18 +220,20 @@ func (m *ClientDB) MarkBackupIneligible(_ lnwire.ChannelID, _ uint64) error { // optional tower ID can be used to filter out any client sessions in the // response that do not correspond to this tower. func (m *ClientDB) ListClientSessions(tower *wtdb.TowerID, + filterFn wtdb.ClientSessionFilterFn, opts ...wtdb.ClientSessionListOption) ( map[wtdb.SessionID]*wtdb.ClientSession, error) { m.mu.Lock() defer m.mu.Unlock() - return m.listClientSessions(tower, opts...) + return m.listClientSessions(tower, filterFn, opts...) } // listClientSessions returns the set of all client sessions known to the db. An // optional tower ID can be used to filter out any client sessions in the // response that do not correspond to this tower. func (m *ClientDB) listClientSessions(tower *wtdb.TowerID, + filterFn wtdb.ClientSessionFilterFn, opts ...wtdb.ClientSessionListOption) ( map[wtdb.SessionID]*wtdb.ClientSession, error) { @@ -246,6 +248,11 @@ func (m *ClientDB) listClientSessions(tower *wtdb.TowerID, if tower != nil && *tower != session.TowerID { continue } + + if filterFn != nil && !filterFn(&session) { + continue + } + sessions[session.ID] = &session if cfg.PerMaxHeight != nil { From c1be4206968fdcb2d9272e468dea9a723f84238f Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 18 Oct 2022 12:21:42 +0200 Subject: [PATCH 08/87] watchtower: make use of the new ClientSessionFilterFn option In this commit, the wtclient starts making use of the new ClientSessionFilterFn to do any session filtering instead of doing it in memory. --- watchtower/wtclient/client.go | 82 ++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/watchtower/wtclient/client.go b/watchtower/wtclient/client.go index 8cd2b7e7d..32622b7da 100644 --- a/watchtower/wtclient/client.go +++ b/watchtower/wtclient/client.go @@ -42,12 +42,24 @@ const ( DefaultForceQuitDelay = 10 * time.Second ) -// genActiveSessionFilter generates a filter that selects active sessions that -// also match the desired channel type, either legacy or anchor. -func genActiveSessionFilter(anchor bool) func(*ClientSession) bool { - return func(s *ClientSession) bool { - return s.Status == wtdb.CSessionActive && - anchor == s.Policy.IsAnchorChannel() +// genSessionFilter constructs a filter that can be used to select sessions only +// if they match the policy of the client (namely anchor vs legacy). If +// activeOnly is set, then only active sessions will be returned. +func (c *TowerClient) genSessionFilter( + activeOnly bool) wtdb.ClientSessionFilterFn { + + return func(session *wtdb.ClientSession) bool { + if c.cfg.Policy.IsAnchorChannel() != + session.Policy.IsAnchorChannel() { + + return false + } + + if !activeOnly { + return true + } + + return session.Status == wtdb.CSessionActive } } @@ -344,13 +356,6 @@ func New(config *Config) (*TowerClient, error) { perUpdate(s.Policy, u.BackupID.ChanID, u.BackupID.CommitHeight) } - // Load all candidate sessions and towers from the database into the - // client. We will use any of these sessions if their policies match the - // current policy of the client, otherwise they will be ignored and new - // sessions will be requested. - isAnchorClient := cfg.Policy.IsAnchorChannel() - activeSessionFilter := genActiveSessionFilter(isAnchorClient) - candidateTowers := newTowerListIterator() perActiveTower := func(tower *Tower) { // If the tower has already been marked as active, then there is @@ -366,9 +371,13 @@ func New(config *Config) (*TowerClient, error) { candidateTowers.AddCandidate(tower) } + // Load all candidate sessions and towers from the database into the + // client. We will use any of these sessions if their policies match the + // current policy of the client, otherwise they will be ignored and new + // sessions will be requested. candidateSessions, err := getTowerAndSessionCandidates( - cfg.DB, cfg.SecretKeyRing, activeSessionFilter, perActiveTower, - wtdb.WithPerMaxHeight(perMaxHeight), + cfg.DB, cfg.SecretKeyRing, c.genSessionFilter(true), + perActiveTower, wtdb.WithPerMaxHeight(perMaxHeight), wtdb.WithPerCommittedUpdate(perCommittedUpdate), ) if err != nil { @@ -401,7 +410,7 @@ func New(config *Config) (*TowerClient, error) { // sessionFilter check then the perActiveTower call-back will be called on that // tower. func getTowerAndSessionCandidates(db DB, keyRing ECDHKeyRing, - sessionFilter func(*ClientSession) bool, + sessionFilter wtdb.ClientSessionFilterFn, perActiveTower func(tower *Tower), opts ...wtdb.ClientSessionListOption) ( map[wtdb.SessionID]*ClientSession, error) { @@ -418,7 +427,9 @@ func getTowerAndSessionCandidates(db DB, keyRing ECDHKeyRing, return nil, err } - sessions, err := db.ListClientSessions(&tower.ID, nil, opts...) + sessions, err := db.ListClientSessions( + &tower.ID, sessionFilter, opts..., + ) if err != nil { return nil, err } @@ -438,19 +449,14 @@ func getTowerAndSessionCandidates(db DB, keyRing ECDHKeyRing, towerKeyDesc, keyRing, ) - cs := &ClientSession{ + // Add the session to the set of candidate sessions. + candidateSessions[s.ID] = &ClientSession{ ID: s.ID, ClientSessionBody: s.ClientSessionBody, Tower: tower, SessionKeyECDH: sessionKeyECDH, } - if !sessionFilter(cs) { - continue - } - - // Add the session to the set of candidate sessions. - candidateSessions[s.ID] = cs perActiveTower(tower) } } @@ -466,11 +472,13 @@ func getTowerAndSessionCandidates(db DB, keyRing ECDHKeyRing, // ClientSession's SessionPrivKey field is desired, otherwise, the existing // ListClientSessions method should be used. func getClientSessions(db DB, keyRing ECDHKeyRing, forTower *wtdb.TowerID, - passesFilter func(*ClientSession) bool, + sessionFilter wtdb.ClientSessionFilterFn, opts ...wtdb.ClientSessionListOption) ( map[wtdb.SessionID]*ClientSession, error) { - dbSessions, err := db.ListClientSessions(forTower, nil, opts...) + dbSessions, err := db.ListClientSessions( + forTower, sessionFilter, opts..., + ) if err != nil { return nil, err } @@ -494,6 +502,7 @@ func getClientSessions(db DB, keyRing ECDHKeyRing, forTower *wtdb.TowerID, if err != nil { return nil, err } + sessionKeyECDH := keychain.NewPubKeyECDH(towerKeyDesc, keyRing) tower, err := NewTowerFromDBTower(dbTower) @@ -501,20 +510,12 @@ func getClientSessions(db DB, keyRing ECDHKeyRing, forTower *wtdb.TowerID, return nil, err } - cs := &ClientSession{ + sessions[s.ID] = &ClientSession{ ID: s.ID, ClientSessionBody: s.ClientSessionBody, Tower: tower, SessionKeyECDH: sessionKeyECDH, } - - // If an optional filter was provided, use it to filter out any - // undesired sessions. - if passesFilter != nil && !passesFilter(cs) { - continue - } - - sessions[s.ID] = cs } return sessions, nil @@ -1200,10 +1201,9 @@ func (c *TowerClient) handleNewTower(msg *newTowerMsg) error { c.candidateTowers.AddCandidate(tower) // Include all of its corresponding sessions to our set of candidates. - isAnchorClient := c.cfg.Policy.IsAnchorChannel() - activeSessionFilter := genActiveSessionFilter(isAnchorClient) sessions, err := getClientSessions( - c.cfg.DB, c.cfg.SecretKeyRing, &tower.ID, activeSessionFilter, + c.cfg.DB, c.cfg.SecretKeyRing, &tower.ID, + c.genSessionFilter(true), ) if err != nil { return fmt.Errorf("unable to determine sessions for tower %x: "+ @@ -1320,7 +1320,9 @@ func (c *TowerClient) RegisteredTowers(opts ...wtdb.ClientSessionListOption) ( if err != nil { return nil, err } - clientSessions, err := c.cfg.DB.ListClientSessions(nil, nil, opts...) + clientSessions, err := c.cfg.DB.ListClientSessions( + nil, c.genSessionFilter(false), opts..., + ) if err != nil { return nil, err } @@ -1362,7 +1364,7 @@ func (c *TowerClient) LookupTower(pubKey *btcec.PublicKey, } towerSessions, err := c.cfg.DB.ListClientSessions( - &tower.ID, nil, opts..., + &tower.ID, c.genSessionFilter(false), opts..., ) if err != nil { return nil, err From b635629e3c4bc5cdc55477a15ffa80e803f30138 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 18 Oct 2022 12:25:22 +0200 Subject: [PATCH 09/87] lnrpc/wtclientrpc: correctly merge tower client info Prior to this commit, the wtclient would request tower info from both the legacy client and the anchors client and would then merge the results returned. This is incorrect since the two clients will have different session info and different "active" statuses for the same tower. This commit thus ensures that we dont lose this info. --- lnrpc/wtclientrpc/wtclient.go | 119 +++++-- lnrpc/wtclientrpc/wtclient.pb.go | 402 ++++++++++++++++-------- lnrpc/wtclientrpc/wtclient.proto | 29 +- lnrpc/wtclientrpc/wtclient.swagger.json | 38 ++- 4 files changed, 421 insertions(+), 167 deletions(-) diff --git a/lnrpc/wtclientrpc/wtclient.go b/lnrpc/wtclientrpc/wtclient.go index 6672c0c75..415ae1702 100644 --- a/lnrpc/wtclientrpc/wtclient.go +++ b/lnrpc/wtclientrpc/wtclient.go @@ -1,10 +1,13 @@ package wtclientrpc import ( + "bytes" "context" + "encoding/binary" "errors" "fmt" "net" + "sort" "strconv" "github.com/btcsuite/btcd/btcec/v2" @@ -274,30 +277,46 @@ func (c *WatchtowerClient) ListTowers(ctx context.Context, return nil, err } + // Collect all the anchor client towers. + rpcTowers := make(map[wtdb.TowerID]*Tower) + for _, tower := range anchorTowers { + rpcTower := marshallTower( + tower, PolicyType_ANCHOR, req.IncludeSessions, + ackCounts, committedUpdateCounts, + ) + + rpcTowers[tower.ID] = rpcTower + } + legacyTowers, err := c.cfg.Client.RegisteredTowers(opts...) if err != nil { return nil, err } - // Filter duplicates. - towers := make(map[wtdb.TowerID]*wtclient.RegisteredTower) - for _, tower := range anchorTowers { - towers[tower.Tower.ID] = tower - } + // Collect all the legacy client towers. If it has any of the same + // towers that the anchors client has, then just add the session info + // for the legacy client to the existing tower. for _, tower := range legacyTowers { - towers[tower.Tower.ID] = tower - } - - rpcTowers := make([]*Tower, 0, len(towers)) - for _, tower := range towers { rpcTower := marshallTower( - tower, req.IncludeSessions, ackCounts, - committedUpdateCounts, + tower, PolicyType_LEGACY, req.IncludeSessions, + ackCounts, committedUpdateCounts, ) - rpcTowers = append(rpcTowers, rpcTower) + + t, ok := rpcTowers[tower.ID] + if !ok { + rpcTowers[tower.ID] = rpcTower + continue + } + + t.SessionInfo = append(t.SessionInfo, rpcTower.SessionInfo...) } - return &ListTowersResponse{Towers: rpcTowers}, nil + towers := make([]*Tower, 0, len(rpcTowers)) + for _, tower := range rpcTowers { + towers = append(towers, tower) + } + + return &ListTowersResponse{Towers: towers}, nil } // GetTowerInfo retrieves information for a registered watchtower. @@ -317,18 +336,37 @@ func (c *WatchtowerClient) GetTowerInfo(ctx context.Context, req.IncludeSessions, ) - var tower *wtclient.RegisteredTower - tower, err = c.cfg.Client.LookupTower(pubKey, opts...) - if err == wtdb.ErrTowerNotFound { - tower, err = c.cfg.AnchorClient.LookupTower(pubKey, opts...) + // Get the tower and its sessions from anchors client. + tower, err := c.cfg.AnchorClient.LookupTower(pubKey, opts...) + if err != nil { + return nil, err } + rpcTower := marshallTower( + tower, PolicyType_ANCHOR, req.IncludeSessions, ackCounts, + committedUpdateCounts, + ) + + // Get the tower and its sessions from legacy client. + tower, err = c.cfg.Client.LookupTower(pubKey, opts...) if err != nil { return nil, err } - return marshallTower( - tower, req.IncludeSessions, ackCounts, committedUpdateCounts, - ), nil + rpcLegacyTower := marshallTower( + tower, PolicyType_LEGACY, req.IncludeSessions, ackCounts, + committedUpdateCounts, + ) + + if !bytes.Equal(rpcTower.Pubkey, rpcLegacyTower.Pubkey) { + return nil, fmt.Errorf("legacy and anchor clients returned " + + "inconsistent results for the given tower") + } + + rpcTower.SessionInfo = append( + rpcTower.SessionInfo, rpcLegacyTower.SessionInfo..., + ) + + return rpcTower, nil } // constructFunctionalOptions is a helper function that constructs a list of @@ -437,8 +475,8 @@ func (c *WatchtowerClient) Policy(ctx context.Context, // marshallTower converts a client registered watchtower into its corresponding // RPC type. -func marshallTower(tower *wtclient.RegisteredTower, includeSessions bool, - ackCounts map[wtdb.SessionID]uint16, +func marshallTower(tower *wtclient.RegisteredTower, policyType PolicyType, + includeSessions bool, ackCounts map[wtdb.SessionID]uint16, pendingCounts map[wtdb.SessionID]uint16) *Tower { rpcAddrs := make([]string, 0, len(tower.Addresses)) @@ -448,8 +486,24 @@ func marshallTower(tower *wtclient.RegisteredTower, includeSessions bool, var rpcSessions []*TowerSession if includeSessions { - rpcSessions = make([]*TowerSession, 0, len(tower.Sessions)) + // To ensure that the output order is deterministic for a given + // set of sessions, we put the sessions into a slice and order + // them based on session ID. + sessions := make([]*wtdb.ClientSession, 0, len(tower.Sessions)) for _, session := range tower.Sessions { + sessions = append(sessions, session) + } + + sort.Slice(sessions, func(i, j int) bool { + id1 := sessions[i].ID + id2 := sessions[j].ID + + return binary.BigEndian.Uint64(id1[:]) < + binary.BigEndian.Uint64(id2[:]) + }) + + rpcSessions = make([]*TowerSession, 0, len(tower.Sessions)) + for _, session := range sessions { satPerVByte := session.Policy.SweepFeeRate.FeePerKVByte() / 1000 rpcSessions = append(rpcSessions, &TowerSession{ NumBackups: uint32(ackCounts[session.ID]), @@ -463,11 +517,22 @@ func marshallTower(tower *wtclient.RegisteredTower, includeSessions bool, } } - return &Tower{ - Pubkey: tower.IdentityKey.SerializeCompressed(), - Addresses: rpcAddrs, + rpcTower := &Tower{ + Pubkey: tower.IdentityKey.SerializeCompressed(), + Addresses: rpcAddrs, + SessionInfo: []*TowerSessionInfo{{ + PolicyType: policyType, + ActiveSessionCandidate: tower.ActiveSessionCandidate, + NumSessions: uint32(len(tower.Sessions)), + Sessions: rpcSessions, + }}, + // The below fields are populated for backwards compatibility + // but will be removed in a future commit when the proto fields + // are removed. ActiveSessionCandidate: tower.ActiveSessionCandidate, NumSessions: uint32(len(tower.Sessions)), Sessions: rpcSessions, } + + return rpcTower } diff --git a/lnrpc/wtclientrpc/wtclient.pb.go b/lnrpc/wtclientrpc/wtclient.pb.go index d614a9f39..10f4559ee 100644 --- a/lnrpc/wtclientrpc/wtclient.pb.go +++ b/lnrpc/wtclientrpc/wtclient.pb.go @@ -418,12 +418,26 @@ type Tower struct { Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"` // The list of addresses the watchtower is reachable over. Addresses []string `protobuf:"bytes,2,rep,name=addresses,proto3" json:"addresses,omitempty"` + // Deprecated, use the active_session_candidate field under the + // correct identifier in the client_type map. // Whether the watchtower is currently a candidate for new sessions. + // + // Deprecated: Do not use. ActiveSessionCandidate bool `protobuf:"varint,3,opt,name=active_session_candidate,json=activeSessionCandidate,proto3" json:"active_session_candidate,omitempty"` + // Deprecated, use the num_sessions field under the correct identifier + // in the client_type map. // The number of sessions that have been negotiated with the watchtower. + // + // Deprecated: Do not use. NumSessions uint32 `protobuf:"varint,4,opt,name=num_sessions,json=numSessions,proto3" json:"num_sessions,omitempty"` + // Deprecated, use the sessions field under the correct identifier in the + // client_type map. // The list of sessions that have been negotiated with the watchtower. + // + // Deprecated: Do not use. Sessions []*TowerSession `protobuf:"bytes,5,rep,name=sessions,proto3" json:"sessions,omitempty"` + // A list sessions held with the tower. + SessionInfo []*TowerSessionInfo `protobuf:"bytes,6,rep,name=session_info,json=sessionInfo,proto3" json:"session_info,omitempty"` } func (x *Tower) Reset() { @@ -472,6 +486,7 @@ func (x *Tower) GetAddresses() []string { return nil } +// Deprecated: Do not use. func (x *Tower) GetActiveSessionCandidate() bool { if x != nil { return x.ActiveSessionCandidate @@ -479,6 +494,7 @@ func (x *Tower) GetActiveSessionCandidate() bool { return false } +// Deprecated: Do not use. func (x *Tower) GetNumSessions() uint32 { if x != nil { return x.NumSessions @@ -486,6 +502,7 @@ func (x *Tower) GetNumSessions() uint32 { return 0 } +// Deprecated: Do not use. func (x *Tower) GetSessions() []*TowerSession { if x != nil { return x.Sessions @@ -493,6 +510,88 @@ func (x *Tower) GetSessions() []*TowerSession { return nil } +func (x *Tower) GetSessionInfo() []*TowerSessionInfo { + if x != nil { + return x.SessionInfo + } + return nil +} + +type TowerSessionInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Whether the watchtower is currently a candidate for new sessions. + ActiveSessionCandidate bool `protobuf:"varint,1,opt,name=active_session_candidate,json=activeSessionCandidate,proto3" json:"active_session_candidate,omitempty"` + // The number of sessions that have been negotiated with the watchtower. + NumSessions uint32 `protobuf:"varint,2,opt,name=num_sessions,json=numSessions,proto3" json:"num_sessions,omitempty"` + // The list of sessions that have been negotiated with the watchtower. + Sessions []*TowerSession `protobuf:"bytes,3,rep,name=sessions,proto3" json:"sessions,omitempty"` + // The session's policy type. + PolicyType PolicyType `protobuf:"varint,4,opt,name=policy_type,json=policyType,proto3,enum=wtclientrpc.PolicyType" json:"policy_type,omitempty"` +} + +func (x *TowerSessionInfo) Reset() { + *x = TowerSessionInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_wtclientrpc_wtclient_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TowerSessionInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TowerSessionInfo) ProtoMessage() {} + +func (x *TowerSessionInfo) ProtoReflect() protoreflect.Message { + mi := &file_wtclientrpc_wtclient_proto_msgTypes[7] + 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 TowerSessionInfo.ProtoReflect.Descriptor instead. +func (*TowerSessionInfo) Descriptor() ([]byte, []int) { + return file_wtclientrpc_wtclient_proto_rawDescGZIP(), []int{7} +} + +func (x *TowerSessionInfo) GetActiveSessionCandidate() bool { + if x != nil { + return x.ActiveSessionCandidate + } + return false +} + +func (x *TowerSessionInfo) GetNumSessions() uint32 { + if x != nil { + return x.NumSessions + } + return 0 +} + +func (x *TowerSessionInfo) GetSessions() []*TowerSession { + if x != nil { + return x.Sessions + } + return nil +} + +func (x *TowerSessionInfo) GetPolicyType() PolicyType { + if x != nil { + return x.PolicyType + } + return PolicyType_LEGACY +} + type ListTowersRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -505,7 +604,7 @@ type ListTowersRequest struct { func (x *ListTowersRequest) Reset() { *x = ListTowersRequest{} if protoimpl.UnsafeEnabled { - mi := &file_wtclientrpc_wtclient_proto_msgTypes[7] + mi := &file_wtclientrpc_wtclient_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -518,7 +617,7 @@ func (x *ListTowersRequest) String() string { func (*ListTowersRequest) ProtoMessage() {} func (x *ListTowersRequest) ProtoReflect() protoreflect.Message { - mi := &file_wtclientrpc_wtclient_proto_msgTypes[7] + mi := &file_wtclientrpc_wtclient_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -531,7 +630,7 @@ func (x *ListTowersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTowersRequest.ProtoReflect.Descriptor instead. func (*ListTowersRequest) Descriptor() ([]byte, []int) { - return file_wtclientrpc_wtclient_proto_rawDescGZIP(), []int{7} + return file_wtclientrpc_wtclient_proto_rawDescGZIP(), []int{8} } func (x *ListTowersRequest) GetIncludeSessions() bool { @@ -553,7 +652,7 @@ type ListTowersResponse struct { func (x *ListTowersResponse) Reset() { *x = ListTowersResponse{} if protoimpl.UnsafeEnabled { - mi := &file_wtclientrpc_wtclient_proto_msgTypes[8] + mi := &file_wtclientrpc_wtclient_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -566,7 +665,7 @@ func (x *ListTowersResponse) String() string { func (*ListTowersResponse) ProtoMessage() {} func (x *ListTowersResponse) ProtoReflect() protoreflect.Message { - mi := &file_wtclientrpc_wtclient_proto_msgTypes[8] + mi := &file_wtclientrpc_wtclient_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -579,7 +678,7 @@ func (x *ListTowersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTowersResponse.ProtoReflect.Descriptor instead. func (*ListTowersResponse) Descriptor() ([]byte, []int) { - return file_wtclientrpc_wtclient_proto_rawDescGZIP(), []int{8} + return file_wtclientrpc_wtclient_proto_rawDescGZIP(), []int{9} } func (x *ListTowersResponse) GetTowers() []*Tower { @@ -598,7 +697,7 @@ type StatsRequest struct { func (x *StatsRequest) Reset() { *x = StatsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_wtclientrpc_wtclient_proto_msgTypes[9] + mi := &file_wtclientrpc_wtclient_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -611,7 +710,7 @@ func (x *StatsRequest) String() string { func (*StatsRequest) ProtoMessage() {} func (x *StatsRequest) ProtoReflect() protoreflect.Message { - mi := &file_wtclientrpc_wtclient_proto_msgTypes[9] + mi := &file_wtclientrpc_wtclient_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -624,7 +723,7 @@ func (x *StatsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StatsRequest.ProtoReflect.Descriptor instead. func (*StatsRequest) Descriptor() ([]byte, []int) { - return file_wtclientrpc_wtclient_proto_rawDescGZIP(), []int{9} + return file_wtclientrpc_wtclient_proto_rawDescGZIP(), []int{10} } type StatsResponse struct { @@ -650,7 +749,7 @@ type StatsResponse struct { func (x *StatsResponse) Reset() { *x = StatsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_wtclientrpc_wtclient_proto_msgTypes[10] + mi := &file_wtclientrpc_wtclient_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -663,7 +762,7 @@ func (x *StatsResponse) String() string { func (*StatsResponse) ProtoMessage() {} func (x *StatsResponse) ProtoReflect() protoreflect.Message { - mi := &file_wtclientrpc_wtclient_proto_msgTypes[10] + mi := &file_wtclientrpc_wtclient_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -676,7 +775,7 @@ func (x *StatsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StatsResponse.ProtoReflect.Descriptor instead. func (*StatsResponse) Descriptor() ([]byte, []int) { - return file_wtclientrpc_wtclient_proto_rawDescGZIP(), []int{10} + return file_wtclientrpc_wtclient_proto_rawDescGZIP(), []int{11} } func (x *StatsResponse) GetNumBackups() uint32 { @@ -726,7 +825,7 @@ type PolicyRequest struct { func (x *PolicyRequest) Reset() { *x = PolicyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_wtclientrpc_wtclient_proto_msgTypes[11] + mi := &file_wtclientrpc_wtclient_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -739,7 +838,7 @@ func (x *PolicyRequest) String() string { func (*PolicyRequest) ProtoMessage() {} func (x *PolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_wtclientrpc_wtclient_proto_msgTypes[11] + mi := &file_wtclientrpc_wtclient_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -752,7 +851,7 @@ func (x *PolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyRequest.ProtoReflect.Descriptor instead. func (*PolicyRequest) Descriptor() ([]byte, []int) { - return file_wtclientrpc_wtclient_proto_rawDescGZIP(), []int{11} + return file_wtclientrpc_wtclient_proto_rawDescGZIP(), []int{12} } func (x *PolicyRequest) GetPolicyType() PolicyType { @@ -784,7 +883,7 @@ type PolicyResponse struct { func (x *PolicyResponse) Reset() { *x = PolicyResponse{} if protoimpl.UnsafeEnabled { - mi := &file_wtclientrpc_wtclient_proto_msgTypes[12] + mi := &file_wtclientrpc_wtclient_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -797,7 +896,7 @@ func (x *PolicyResponse) String() string { func (*PolicyResponse) ProtoMessage() {} func (x *PolicyResponse) ProtoReflect() protoreflect.Message { - mi := &file_wtclientrpc_wtclient_proto_msgTypes[12] + mi := &file_wtclientrpc_wtclient_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -810,7 +909,7 @@ func (x *PolicyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyResponse.ProtoReflect.Descriptor instead. func (*PolicyResponse) Descriptor() ([]byte, []int) { - return file_wtclientrpc_wtclient_proto_rawDescGZIP(), []int{12} + return file_wtclientrpc_wtclient_proto_rawDescGZIP(), []int{13} } func (x *PolicyResponse) GetMaxUpdates() uint32 { @@ -871,94 +970,113 @@ var file_wtclientrpc_wtclient_proto_rawDesc = []byte{ 0x73, 0x77, 0x65, 0x65, 0x70, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x12, 0x2d, 0x0a, 0x13, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x73, 0x77, - 0x65, 0x65, 0x70, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, 0x22, 0xd1, - 0x01, 0x0a, 0x05, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, + 0x65, 0x65, 0x70, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, 0x22, 0x9f, + 0x02, 0x0a, 0x05, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x38, + 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x3c, 0x0a, 0x18, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x16, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, - 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x5f, - 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, - 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x73, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, - 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, - 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x22, 0x3e, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, - 0x64, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x22, 0x40, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x74, 0x6f, 0x77, 0x65, - 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x06, 0x74, 0x6f, - 0x77, 0x65, 0x72, 0x73, 0x22, 0x0e, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x22, 0xf8, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x75, 0x6d, 0x5f, 0x62, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6e, 0x75, 0x6d, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x6e, 0x75, 0x6d, 0x5f, 0x70, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x6e, 0x75, 0x6d, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6e, 0x75, 0x6d, 0x5f, 0x66, - 0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x10, 0x6e, 0x75, 0x6d, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x42, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x61, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x34, 0x0a, 0x16, 0x6e, 0x75, 0x6d, - 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x65, 0x78, 0x68, 0x61, 0x75, 0x73, - 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x6e, 0x75, 0x6d, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x78, 0x68, 0x61, 0x75, 0x73, 0x74, 0x65, 0x64, 0x22, - 0x49, 0x0a, 0x0d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x38, 0x0a, 0x0b, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x22, 0x91, 0x01, 0x0a, 0x0e, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, - 0x0b, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x2f, - 0x0a, 0x12, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, - 0x62, 0x79, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0f, - 0x73, 0x77, 0x65, 0x65, 0x70, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x12, - 0x2d, 0x0a, 0x13, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, - 0x5f, 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x73, 0x77, - 0x65, 0x65, 0x70, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, 0x2a, 0x24, - 0x0a, 0x0a, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, - 0x4c, 0x45, 0x47, 0x41, 0x43, 0x59, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4e, 0x43, 0x48, - 0x4f, 0x52, 0x10, 0x01, 0x32, 0xc5, 0x03, 0x0a, 0x10, 0x57, 0x61, 0x74, 0x63, 0x68, 0x74, 0x6f, - 0x77, 0x65, 0x72, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x08, 0x41, 0x64, 0x64, - 0x54, 0x6f, 0x77, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x77, 0x65, - 0x72, 0x12, 0x1f, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, - 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x05, 0x53, 0x74, 0x61, - 0x74, 0x73, 0x12, 0x19, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, - 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x06, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x12, 0x1a, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1b, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, 0x31, - 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, 0x2f, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, - 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x42, 0x02, 0x18, 0x01, 0x52, 0x16, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x25, 0x0a, 0x0c, + 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x39, 0x0a, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x42, 0x02, 0x18, 0x01, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x40, + 0x0a, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, + 0x22, 0xe0, 0x01, 0x0a, 0x10, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x38, 0x0a, 0x18, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, + 0x21, 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x38, 0x0a, 0x0b, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, + 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, + 0x79, 0x70, 0x65, 0x22, 0x3e, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x22, 0x40, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x74, 0x6f, 0x77, + 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x77, 0x74, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x06, 0x74, + 0x6f, 0x77, 0x65, 0x72, 0x73, 0x22, 0x0e, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xf8, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x75, 0x6d, 0x5f, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6e, 0x75, + 0x6d, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x6e, 0x75, 0x6d, 0x5f, + 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x6e, 0x75, 0x6d, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6e, 0x75, 0x6d, 0x5f, + 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x6e, 0x75, 0x6d, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x42, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x61, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x34, 0x0a, 0x16, 0x6e, 0x75, + 0x6d, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x65, 0x78, 0x68, 0x61, 0x75, + 0x73, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x6e, 0x75, 0x6d, 0x53, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x78, 0x68, 0x61, 0x75, 0x73, 0x74, 0x65, 0x64, + 0x22, 0x49, 0x0a, 0x0d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x38, 0x0a, 0x0b, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x0a, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x22, 0x91, 0x01, 0x0a, 0x0e, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, + 0x2f, 0x0a, 0x12, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, + 0x5f, 0x62, 0x79, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, + 0x0f, 0x73, 0x77, 0x65, 0x65, 0x70, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, + 0x12, 0x2d, 0x0a, 0x13, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, + 0x72, 0x5f, 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x73, + 0x77, 0x65, 0x65, 0x70, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, 0x2a, + 0x24, 0x0a, 0x0a, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, + 0x06, 0x4c, 0x45, 0x47, 0x41, 0x43, 0x59, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4e, 0x43, + 0x48, 0x4f, 0x52, 0x10, 0x01, 0x32, 0xc5, 0x03, 0x0a, 0x10, 0x57, 0x61, 0x74, 0x63, 0x68, 0x74, + 0x6f, 0x77, 0x65, 0x72, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x08, 0x41, 0x64, + 0x64, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x77, + 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, + 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, + 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x05, 0x53, 0x74, + 0x61, 0x74, 0x73, 0x12, 0x19, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, + 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x06, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1a, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1b, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, + 0x31, 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, 0x2f, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, + 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -974,7 +1092,7 @@ func file_wtclientrpc_wtclient_proto_rawDescGZIP() []byte { } var file_wtclientrpc_wtclient_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_wtclientrpc_wtclient_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_wtclientrpc_wtclient_proto_msgTypes = make([]protoimpl.MessageInfo, 14) var file_wtclientrpc_wtclient_proto_goTypes = []interface{}{ (PolicyType)(0), // 0: wtclientrpc.PolicyType (*AddTowerRequest)(nil), // 1: wtclientrpc.AddTowerRequest @@ -984,34 +1102,38 @@ var file_wtclientrpc_wtclient_proto_goTypes = []interface{}{ (*GetTowerInfoRequest)(nil), // 5: wtclientrpc.GetTowerInfoRequest (*TowerSession)(nil), // 6: wtclientrpc.TowerSession (*Tower)(nil), // 7: wtclientrpc.Tower - (*ListTowersRequest)(nil), // 8: wtclientrpc.ListTowersRequest - (*ListTowersResponse)(nil), // 9: wtclientrpc.ListTowersResponse - (*StatsRequest)(nil), // 10: wtclientrpc.StatsRequest - (*StatsResponse)(nil), // 11: wtclientrpc.StatsResponse - (*PolicyRequest)(nil), // 12: wtclientrpc.PolicyRequest - (*PolicyResponse)(nil), // 13: wtclientrpc.PolicyResponse + (*TowerSessionInfo)(nil), // 8: wtclientrpc.TowerSessionInfo + (*ListTowersRequest)(nil), // 9: wtclientrpc.ListTowersRequest + (*ListTowersResponse)(nil), // 10: wtclientrpc.ListTowersResponse + (*StatsRequest)(nil), // 11: wtclientrpc.StatsRequest + (*StatsResponse)(nil), // 12: wtclientrpc.StatsResponse + (*PolicyRequest)(nil), // 13: wtclientrpc.PolicyRequest + (*PolicyResponse)(nil), // 14: wtclientrpc.PolicyResponse } var file_wtclientrpc_wtclient_proto_depIdxs = []int32{ 6, // 0: wtclientrpc.Tower.sessions:type_name -> wtclientrpc.TowerSession - 7, // 1: wtclientrpc.ListTowersResponse.towers:type_name -> wtclientrpc.Tower - 0, // 2: wtclientrpc.PolicyRequest.policy_type:type_name -> wtclientrpc.PolicyType - 1, // 3: wtclientrpc.WatchtowerClient.AddTower:input_type -> wtclientrpc.AddTowerRequest - 3, // 4: wtclientrpc.WatchtowerClient.RemoveTower:input_type -> wtclientrpc.RemoveTowerRequest - 8, // 5: wtclientrpc.WatchtowerClient.ListTowers:input_type -> wtclientrpc.ListTowersRequest - 5, // 6: wtclientrpc.WatchtowerClient.GetTowerInfo:input_type -> wtclientrpc.GetTowerInfoRequest - 10, // 7: wtclientrpc.WatchtowerClient.Stats:input_type -> wtclientrpc.StatsRequest - 12, // 8: wtclientrpc.WatchtowerClient.Policy:input_type -> wtclientrpc.PolicyRequest - 2, // 9: wtclientrpc.WatchtowerClient.AddTower:output_type -> wtclientrpc.AddTowerResponse - 4, // 10: wtclientrpc.WatchtowerClient.RemoveTower:output_type -> wtclientrpc.RemoveTowerResponse - 9, // 11: wtclientrpc.WatchtowerClient.ListTowers:output_type -> wtclientrpc.ListTowersResponse - 7, // 12: wtclientrpc.WatchtowerClient.GetTowerInfo:output_type -> wtclientrpc.Tower - 11, // 13: wtclientrpc.WatchtowerClient.Stats:output_type -> wtclientrpc.StatsResponse - 13, // 14: wtclientrpc.WatchtowerClient.Policy:output_type -> wtclientrpc.PolicyResponse - 9, // [9:15] is the sub-list for method output_type - 3, // [3:9] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 8, // 1: wtclientrpc.Tower.session_info:type_name -> wtclientrpc.TowerSessionInfo + 6, // 2: wtclientrpc.TowerSessionInfo.sessions:type_name -> wtclientrpc.TowerSession + 0, // 3: wtclientrpc.TowerSessionInfo.policy_type:type_name -> wtclientrpc.PolicyType + 7, // 4: wtclientrpc.ListTowersResponse.towers:type_name -> wtclientrpc.Tower + 0, // 5: wtclientrpc.PolicyRequest.policy_type:type_name -> wtclientrpc.PolicyType + 1, // 6: wtclientrpc.WatchtowerClient.AddTower:input_type -> wtclientrpc.AddTowerRequest + 3, // 7: wtclientrpc.WatchtowerClient.RemoveTower:input_type -> wtclientrpc.RemoveTowerRequest + 9, // 8: wtclientrpc.WatchtowerClient.ListTowers:input_type -> wtclientrpc.ListTowersRequest + 5, // 9: wtclientrpc.WatchtowerClient.GetTowerInfo:input_type -> wtclientrpc.GetTowerInfoRequest + 11, // 10: wtclientrpc.WatchtowerClient.Stats:input_type -> wtclientrpc.StatsRequest + 13, // 11: wtclientrpc.WatchtowerClient.Policy:input_type -> wtclientrpc.PolicyRequest + 2, // 12: wtclientrpc.WatchtowerClient.AddTower:output_type -> wtclientrpc.AddTowerResponse + 4, // 13: wtclientrpc.WatchtowerClient.RemoveTower:output_type -> wtclientrpc.RemoveTowerResponse + 10, // 14: wtclientrpc.WatchtowerClient.ListTowers:output_type -> wtclientrpc.ListTowersResponse + 7, // 15: wtclientrpc.WatchtowerClient.GetTowerInfo:output_type -> wtclientrpc.Tower + 12, // 16: wtclientrpc.WatchtowerClient.Stats:output_type -> wtclientrpc.StatsResponse + 14, // 17: wtclientrpc.WatchtowerClient.Policy:output_type -> wtclientrpc.PolicyResponse + 12, // [12:18] is the sub-list for method output_type + 6, // [6:12] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_wtclientrpc_wtclient_proto_init() } @@ -1105,7 +1227,7 @@ func file_wtclientrpc_wtclient_proto_init() { } } file_wtclientrpc_wtclient_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListTowersRequest); i { + switch v := v.(*TowerSessionInfo); i { case 0: return &v.state case 1: @@ -1117,7 +1239,7 @@ func file_wtclientrpc_wtclient_proto_init() { } } file_wtclientrpc_wtclient_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListTowersResponse); i { + switch v := v.(*ListTowersRequest); i { case 0: return &v.state case 1: @@ -1129,7 +1251,7 @@ func file_wtclientrpc_wtclient_proto_init() { } } file_wtclientrpc_wtclient_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StatsRequest); i { + switch v := v.(*ListTowersResponse); i { case 0: return &v.state case 1: @@ -1141,7 +1263,7 @@ func file_wtclientrpc_wtclient_proto_init() { } } file_wtclientrpc_wtclient_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StatsResponse); i { + switch v := v.(*StatsRequest); i { case 0: return &v.state case 1: @@ -1153,7 +1275,7 @@ func file_wtclientrpc_wtclient_proto_init() { } } file_wtclientrpc_wtclient_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PolicyRequest); i { + switch v := v.(*StatsResponse); i { case 0: return &v.state case 1: @@ -1165,6 +1287,18 @@ func file_wtclientrpc_wtclient_proto_init() { } } file_wtclientrpc_wtclient_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PolicyRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_wtclientrpc_wtclient_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PolicyResponse); i { case 0: return &v.state @@ -1183,7 +1317,7 @@ func file_wtclientrpc_wtclient_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_wtclientrpc_wtclient_proto_rawDesc, NumEnums: 1, - NumMessages: 13, + NumMessages: 14, NumExtensions: 0, NumServices: 1, }, diff --git a/lnrpc/wtclientrpc/wtclient.proto b/lnrpc/wtclientrpc/wtclient.proto index 736a4bdde..45bdd24ef 100644 --- a/lnrpc/wtclientrpc/wtclient.proto +++ b/lnrpc/wtclientrpc/wtclient.proto @@ -107,14 +107,37 @@ message Tower { // The list of addresses the watchtower is reachable over. repeated string addresses = 2; + // Deprecated, use the active_session_candidate field under the + // correct identifier in the client_type map. // Whether the watchtower is currently a candidate for new sessions. - bool active_session_candidate = 3; + bool active_session_candidate = 3 [deprecated = true]; + + // Deprecated, use the num_sessions field under the correct identifier + // in the client_type map. + // The number of sessions that have been negotiated with the watchtower. + uint32 num_sessions = 4 [deprecated = true]; + + // Deprecated, use the sessions field under the correct identifier in the + // client_type map. + // The list of sessions that have been negotiated with the watchtower. + repeated TowerSession sessions = 5 [deprecated = true]; + + // A list sessions held with the tower. + repeated TowerSessionInfo session_info = 6; +} + +message TowerSessionInfo { + // Whether the watchtower is currently a candidate for new sessions. + bool active_session_candidate = 1; // The number of sessions that have been negotiated with the watchtower. - uint32 num_sessions = 4; + uint32 num_sessions = 2; // The list of sessions that have been negotiated with the watchtower. - repeated TowerSession sessions = 5; + repeated TowerSession sessions = 3; + + // The session's policy type. + PolicyType policy_type = 4; } message ListTowersRequest { diff --git a/lnrpc/wtclientrpc/wtclient.swagger.json b/lnrpc/wtclientrpc/wtclient.swagger.json index 9ba618316..830dd10fe 100644 --- a/lnrpc/wtclientrpc/wtclient.swagger.json +++ b/lnrpc/wtclientrpc/wtclient.swagger.json @@ -359,19 +359,26 @@ }, "active_session_candidate": { "type": "boolean", - "description": "Whether the watchtower is currently a candidate for new sessions." + "description": "Deprecated, use the active_session_candidate field under the\ncorrect identifier in the client_type map.\nWhether the watchtower is currently a candidate for new sessions." }, "num_sessions": { "type": "integer", "format": "int64", - "description": "The number of sessions that have been negotiated with the watchtower." + "description": "Deprecated, use the num_sessions field under the correct identifier\nin the client_type map.\nThe number of sessions that have been negotiated with the watchtower." }, "sessions": { "type": "array", "items": { "$ref": "#/definitions/wtclientrpcTowerSession" }, - "description": "The list of sessions that have been negotiated with the watchtower." + "description": "Deprecated, use the sessions field under the correct identifier in the\nclient_type map.\nThe list of sessions that have been negotiated with the watchtower." + }, + "session_info": { + "type": "array", + "items": { + "$ref": "#/definitions/wtclientrpcTowerSessionInfo" + }, + "description": "A list sessions held with the tower." } } }, @@ -404,6 +411,31 @@ "description": "The fee rate, in satoshis per vbyte, that will be used by the watchtower for\nthe justice transaction in the event of a channel breach." } } + }, + "wtclientrpcTowerSessionInfo": { + "type": "object", + "properties": { + "active_session_candidate": { + "type": "boolean", + "description": "Whether the watchtower is currently a candidate for new sessions." + }, + "num_sessions": { + "type": "integer", + "format": "int64", + "description": "The number of sessions that have been negotiated with the watchtower." + }, + "sessions": { + "type": "array", + "items": { + "$ref": "#/definitions/wtclientrpcTowerSession" + }, + "description": "The list of sessions that have been negotiated with the watchtower." + }, + "policy_type": { + "$ref": "#/definitions/wtclientrpcPolicyType", + "description": "The session's policy type." + } + } } } } From bc868fe270c3a2432f3fe504646a004d1f8d39be Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Thu, 16 Mar 2023 15:00:26 +0200 Subject: [PATCH 10/87] docs: update release notes with 7059 --- docs/release-notes/release-notes-0.16.1.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index 0edf7c3c8..c53d672ef 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -2,9 +2,14 @@ ## `lncli` -- The `lncli wallet psbt fund` command now allows users to specify the +* The `lncli wallet psbt fund` command now allows users to specify the [`--min_confs` flag](https://github.com/lightningnetwork/lnd/pull/7510). +## Watchtowers + +* [Allow caller to filter sessions at the time of reading them from + disk](https://github.com/lightningnetwork/lnd/pull/7059) + ## Misc * [Return `FEE_INSUFFICIENT` before checking balance for incoming low-fee @@ -12,6 +17,7 @@ # Contributors (Alphabetical Order) +* Elle Mouton * Oliver Gugger * Tommy Volk * Yong Yu From b5d281dca8087b7264810b5da67d314209000b78 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 22 Feb 2023 09:26:47 +0200 Subject: [PATCH 11/87] lnwallet: run commitment tx tests in parallel --- lnwallet/transactions_test.go | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/lnwallet/transactions_test.go b/lnwallet/transactions_test.go index b51a3f903..6ce0f527e 100644 --- a/lnwallet/transactions_test.go +++ b/lnwallet/transactions_test.go @@ -169,8 +169,9 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) { jsonFile: "test_vectors_legacy.json", }, { - name: "anchors", - chanType: channeldb.SingleFunderTweaklessBit | channeldb.AnchorOutputsBit, + name: "anchors", + chanType: channeldb.SingleFunderTweaklessBit | + channeldb.AnchorOutputsBit, jsonFile: "test_vectors_anchors.json", }, } @@ -186,15 +187,18 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) { err = json.Unmarshal(jsonText, &testCases) require.NoError(t, err) - t.Run(set.name, func(t *testing.T) { - for _, test := range testCases { - test := test + for _, test := range testCases { + test := test + name := fmt.Sprintf("%s-%s", set.name, test.Name) + + t.Run(name, func(t *testing.T) { + t.Parallel() t.Run(test.Name, func(t *testing.T) { testVectors(t, set.chanType, test) }) - } - }) + }) + } } } From 15da50df104119ff06c89dc2be63129de9d24530 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 22 Feb 2023 09:32:24 +0200 Subject: [PATCH 12/87] lnwallet: remove dead code --- lnwallet/transactions_test.go | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/lnwallet/transactions_test.go b/lnwallet/transactions_test.go index 6ce0f527e..b77d9cf8c 100644 --- a/lnwallet/transactions_test.go +++ b/lnwallet/transactions_test.go @@ -378,27 +378,6 @@ func testVectors(t *testing.T, chanType channeldb.ChannelType, test testCase) { } } -// htlcViewFromHTLCs constructs an htlcView of PaymentDescriptors from a slice -// of channeldb.HTLC structs. -func htlcViewFromHTLCs(htlcs []channeldb.HTLC) *htlcView { - var theHTLCView htlcView - for _, htlc := range htlcs { - paymentDesc := &PaymentDescriptor{ - RHash: htlc.RHash, - Timeout: htlc.RefundTimeout, - Amount: htlc.Amt, - } - if htlc.Incoming { - theHTLCView.theirUpdates = - append(theHTLCView.theirUpdates, paymentDesc) - } else { - theHTLCView.ourUpdates = - append(theHTLCView.ourUpdates, paymentDesc) - } - } - return &theHTLCView -} - func TestCommitTxStateHint(t *testing.T) { t.Parallel() From 09ff853b9cdd3944ba93d1c11b8bbdb566a67b7e Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 22 Feb 2023 09:47:37 +0200 Subject: [PATCH 13/87] lnwallet: lint bolt 3 test vectors func --- lnwallet/transactions_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lnwallet/transactions_test.go b/lnwallet/transactions_test.go index b77d9cf8c..aaef59e30 100644 --- a/lnwallet/transactions_test.go +++ b/lnwallet/transactions_test.go @@ -304,10 +304,12 @@ func testVectors(t *testing.T, chanType channeldb.ChannelType, test testCase) { remoteSig, remoteHtlcSigs, _, err := remoteChannel.SignNextCommitment() require.NoError(t, err) - require.Equal(t, test.RemoteSigHex, hex.EncodeToString(remoteSig.ToSignatureBytes())) + require.Equal(t, test.RemoteSigHex, + hex.EncodeToString(remoteSig.ToSignatureBytes())) for i, sig := range remoteHtlcSigs { - require.Equal(t, test.HtlcDescs[i].RemoteSigHex, hex.EncodeToString(sig.ToSignatureBytes())) + require.Equal(t, test.HtlcDescs[i].RemoteSigHex, + hex.EncodeToString(sig.ToSignatureBytes())) } err = localChannel.ReceiveNewCommitment(remoteSig, remoteHtlcSigs) @@ -325,7 +327,8 @@ func testVectors(t *testing.T, chanType channeldb.ChannelType, test testCase) { var txBytes bytes.Buffer require.NoError(t, forceCloseSum.CloseTx.Serialize(&txBytes)) - require.Equal(t, test.ExpectedCommitmentTxHex, hex.EncodeToString(txBytes.Bytes())) + require.Equal(t, test.ExpectedCommitmentTxHex, + hex.EncodeToString(txBytes.Bytes())) // Obtain the second level transactions that the local node's channel // state machine has produced. Store them in a map indexed by commit tx From dbc19b24e5b4df093aacf17552e4e8dfd80a5d49 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 22 Feb 2023 09:49:37 +0200 Subject: [PATCH 14/87] lnwallet: add funding amount assertion to tests In this commit, an assertion is added to the bolt 3 commitment tx tests that ensures that the local and remote balances add up to the expected funding amount. Adding this assertion uncovered a borked test vector which is also fixed in this commit. --- lnwallet/test_vectors_anchors.json | 6 +++--- lnwallet/transactions_test.go | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lnwallet/test_vectors_anchors.json b/lnwallet/test_vectors_anchors.json index 59b8eaa18..2559e6822 100644 --- a/lnwallet/test_vectors_anchors.json +++ b/lnwallet/test_vectors_anchors.json @@ -11,13 +11,13 @@ }, { "Name": "simple commitment tx with no HTLCs and single anchor", - "LocalBalance": 7000000000, + "LocalBalance": 10000000000, "RemoteBalance": 0, "FeePerKw": 15000, "UseTestHtlcs": false, "HtlcDescs": [], - "ExpectedCommitmentTxHex": "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80024a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f508b6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100da5310620e72bc23dc57af25d18102cc75479aea0258ab89fe1a66ca176033ec0220339efb450c12872e134c8bda986bb92f3e4eebcaa2d0fee5d9a2b1257d12f12a0147304402200dc30542c9b8b2ff4b8d98f46798b3218a088a07e97b9e786177287dc6a5347b02203d23b1c2bf17262362fdb4cdcc36dbb449a9efcdb10051ad52cfa09fc76842b001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", - "RemoteSigHex": "304402200dc30542c9b8b2ff4b8d98f46798b3218a088a07e97b9e786177287dc6a5347b02203d23b1c2bf17262362fdb4cdcc36dbb449a9efcdb10051ad52cfa09fc76842b0" + "ExpectedCommitmentTxHex": "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80024a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f10529800000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022007cf6b405e9c9b4f527b0ecad9d8bb661fabb8b12abf7d1c0b3ad1855db3ed490220616d5c1eeadccc63bd775a131149455d62d95a42c2a1b01cc7821fc42dce7778014730440220655bf909fb6fa81d086f1336ac72c97906dce29d1b166e305c99152d810e26e1022051f577faa46412c46707aaac46b65d50053550a66334e00a44af2706f27a865801475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + "RemoteSigHex": "30440220655bf909fb6fa81d086f1336ac72c97906dce29d1b166e305c99152d810e26e1022051f577faa46412c46707aaac46b65d50053550a66334e00a44af2706f27a8658" }, { "Name": "commitment tx with seven outputs untrimmed (maximum feerate)", diff --git a/lnwallet/transactions_test.go b/lnwallet/transactions_test.go index aaef59e30..28c547935 100644 --- a/lnwallet/transactions_test.go +++ b/lnwallet/transactions_test.go @@ -270,6 +270,11 @@ func testVectors(t *testing.T, chanType channeldb.ChannelType, test testCase) { } } + // Assert that the remote and local balances add up to the channel + // capacity. + require.EqualValues(t, lnwire.NewMSatFromSatoshis(tc.fundingAmount), + remoteBalance+localBalance) + // Set up a test channel on which the test commitment transaction is // going to be produced. remoteChannel, localChannel := createTestChannelsForVectors( From 4f14193ca9ec72e93e543770f2f2e697a63ecd4b Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 22 Feb 2023 10:19:53 +0200 Subject: [PATCH 15/87] lnwallet: add new htlc set for test vectors Add a new test htlc set comprised of htlc 1 from the original set and two new htlcs, 5 and 6, that use the same preimage and have the same output value (in sats). This htlc set is used in tests that assert the ordering of htlcs that have the same preimage and output value. --- lnwallet/transactions_test.go | 70 +++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/lnwallet/transactions_test.go b/lnwallet/transactions_test.go index 28c547935..86c40f657 100644 --- a/lnwallet/transactions_test.go +++ b/lnwallet/transactions_test.go @@ -11,6 +11,7 @@ import ( "io/ioutil" "net" "sort" + "strings" "testing" "time" @@ -93,41 +94,80 @@ func newTestContext(t *testing.T) *testContext { return tc } -var testHtlcs = []struct { +type htlc struct { incoming bool amount lnwire.MilliSatoshi expiry uint32 preimage string -}{ +} + +var testHtlcsSet1 = []htlc{ + // htlc 0. { incoming: true, amount: 1000000, expiry: 500, - preimage: "0000000000000000000000000000000000000000000000000000000000000000", + preimage: "0000000000000000000000000000000000000000000000000" + + "000000000000000", }, + // htlc 1. { incoming: true, amount: 2000000, expiry: 501, - preimage: "0101010101010101010101010101010101010101010101010101010101010101", + preimage: "0101010101010101010101010101010101010101010101010" + + "101010101010101", }, + // htlc 2. { incoming: false, amount: 2000000, expiry: 502, - preimage: "0202020202020202020202020202020202020202020202020202020202020202", + preimage: "0202020202020202020202020202020202020202020202020" + + "202020202020202", }, + // htlc 3. { incoming: false, amount: 3000000, expiry: 503, - preimage: "0303030303030303030303030303030303030303030303030303030303030303", + preimage: "03030303030303030303030303030303030303030303030303" + + "03030303030303", }, + // htlc 4. { incoming: true, amount: 4000000, expiry: 504, - preimage: "0404040404040404040404040404040404040404040404040404040404040404", + preimage: "0404040404040404040404040404040404040404040404040" + + "404040404040404", + }, +} + +var testHtlcsSet2 = []htlc{ + // htlc 1. + { + incoming: true, + amount: 2000000, + expiry: 501, + preimage: "01010101010101010101010101010101010101010101010101" + + "01010101010101", + }, + // htlc 5. + { + incoming: false, + amount: 5000000, + expiry: 506, + preimage: "05050505050505050505050505050505050505050505050505" + + "05050505050505", + }, + // htlc 6. + { + incoming: false, + amount: 5000001, + expiry: 505, + preimage: "05050505050505050505050505050505050505050505050505" + + "05050505050505", }, } @@ -204,11 +244,11 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) { // addTestHtlcs adds the test vector htlcs to the update logs of the local and // remote node. -func addTestHtlcs(t *testing.T, remote, - local *LightningChannel) map[[20]byte]lntypes.Preimage { +func addTestHtlcs(t *testing.T, remote, local *LightningChannel, + htlcSet []htlc) map[[20]byte]lntypes.Preimage { hash160map := make(map[[20]byte]lntypes.Preimage) - for _, htlc := range testHtlcs { + for _, htlc := range htlcSet { preimage, err := lntypes.MakePreimageFromStr(htlc.preimage) require.NoError(t, err) @@ -255,6 +295,12 @@ func addTestHtlcs(t *testing.T, remote, func testVectors(t *testing.T, chanType channeldb.ChannelType, test testCase) { tc := newTestContext(t) + // Determine which htlc set to use. + testHtlcs := testHtlcsSet1 + if strings.Contains(test.Name, "same amount and preimage") { + testHtlcs = testHtlcsSet2 + } + // Balances in the test vectors are before subtraction of in-flight // htlcs. Convert to spendable balances. remoteBalance := test.RemoteBalance @@ -289,7 +335,9 @@ func testVectors(t *testing.T, chanType channeldb.ChannelType, test testCase) { // retrieve the corresponding preimage. var hash160map map[[20]byte]lntypes.Preimage if test.UseTestHtlcs { - hash160map = addTestHtlcs(t, remoteChannel, localChannel) + hash160map = addTestHtlcs( + t, remoteChannel, localChannel, testHtlcs, + ) } // Execute commit dance to arrive at the point where the local node has From a41f6d5a73863e33022c729b04afa0f437e69911 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 22 Feb 2023 10:39:13 +0200 Subject: [PATCH 16/87] lnwallet: add same amount and preimage legacy test vector --- lnwallet/test_vectors_legacy.json | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lnwallet/test_vectors_legacy.json b/lnwallet/test_vectors_legacy.json index 0db6e4381..9bdc78807 100644 --- a/lnwallet/test_vectors_legacy.json +++ b/lnwallet/test_vectors_legacy.json @@ -237,5 +237,28 @@ "HtlcDescs": [], "ExpectedCommitmentTxHex": "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8001c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de8431100400473044022031a82b51bd014915fe68928d1abf4b9885353fb896cac10c3fdd88d7f9c7f2e00220716bda819641d2c63e65d3549b6120112e1aeaf1742eed94a471488e79e206b101473044022064901950be922e62cbe3f2ab93de2b99f37cff9fc473e73e394b27f88ef0731d02206d1dfa227527b4df44a07599289e207d6fd9cca60c0365682dcd3deaf739567e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", "RemoteSigHex": "3044022064901950be922e62cbe3f2ab93de2b99f37cff9fc473e73e394b27f88ef0731d02206d1dfa227527b4df44a07599289e207d6fd9cca60c0365682dcd3deaf739567e" + }, + { + "Name": "commitment tx with 3 htlc outputs, 2 offered having the same amount and preimage", + "LocalBalance": 6987999999, + "RemoteBalance": 3000000000, + "FeePerKw": 253, + "UseTestHtlcs": true, + "HtlcDescs": [ + { + "RemoteSigHex": "30450221008117770f1d750a8af7a23f27c51a22f66386ea8f074115d0feeac7fe0f077f6102203d4d8dab53ef695b634786224ae5138c81d223b0493fd4637a448e31f734bb30", + "ResolutionTxHex": "0200000000010129253160416b9b2a2ecc303421b7fd1dee52d2e0b08d1a697f3979608334dbb9000000000000000000011f070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004830450221008117770f1d750a8af7a23f27c51a22f66386ea8f074115d0feeac7fe0f077f6102203d4d8dab53ef695b634786224ae5138c81d223b0493fd4637a448e31f734bb3001483045022100f2868e4380ac389960b96a8d01bd0d7ae845d24ad67993f1680e207864d5d3ae0220779ad0a943f73951d628a4f931c3044c51d393de1ab6f8283df41b68485f2b1b012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000" + }, + { + "RemoteSigHex": "30440220620b37379e587447e7ee9c8eed9e71b2d2ec29cadc89a4b5411ee6f9b013ca1b02201aaf26d1a03d901425fc44562bff77d5645cb54498e4d9a56c39456825974a3d", + "ResolutionTxHex": "0200000000010129253160416b9b2a2ecc303421b7fd1dee52d2e0b08d1a697f3979608334dbb901000000000000000001e1120000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220620b37379e587447e7ee9c8eed9e71b2d2ec29cadc89a4b5411ee6f9b013ca1b02201aaf26d1a03d901425fc44562bff77d5645cb54498e4d9a56c39456825974a3d0147304402204db4a1266aa8f0df66d35cd8b4269feef47f1cccebf7fdbb2b64cef35d72d79f022021b6d270a6d623cfec4cd0186096596d8deb17505d8c1c9785c719e0dbfa7e8401008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6868f9010000" + }, + { + "RemoteSigHex": "30450221009353b1d7e6313dc57a3781671b7ed9dde668b30e6f438ff08b13580937264de202200654599d2b9839fe9c88553f7c164a517fc8f0892e942b615460325fee7e0747", + "ResolutionTxHex": "0200000000010129253160416b9b2a2ecc303421b7fd1dee52d2e0b08d1a697f3979608334dbb902000000000000000001e1120000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004830450221009353b1d7e6313dc57a3781671b7ed9dde668b30e6f438ff08b13580937264de202200654599d2b9839fe9c88553f7c164a517fc8f0892e942b615460325fee7e074701483045022100c11a3f26356524b556bdfaeeae80f3cdef2cdb1c42c49047014a56af6916e2cb0220230d0667dc5b86015056a2ae5158ff29cbaf9cde419677e058d23c59a0a07d3101008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6868fa010000" + } + ], + "ExpectedCommitmentTxHex": "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8005d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2d8813000000000000220020305c12e1a0bc21e283c131cea1c66d68857d28b7b2fce0a6fbc40c164852121b8813000000000000220020305c12e1a0bc21e283c131cea1c66d68857d28b7b2fce0a6fbc40c164852121bc0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110a69f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100d25455151be075bae8b3400d0825341a3c25a1a5258b84ad2546c09539a83bc602203c1a4ac19c3ac415af7f6a98348f8d7e94fc0ab82dbed54c3c40134f465d027f0147304402206cda85b2811a211aa70fb74abf23303d87c4355ccf2c2c7954d4137c4fb26a830220719402ab3fef1cbaf42ba42fe437e9bed1e45f84547d603bf7af3fb88f50193301475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + "RemoteSigHex": "304402206cda85b2811a211aa70fb74abf23303d87c4355ccf2c2c7954d4137c4fb26a830220719402ab3fef1cbaf42ba42fe437e9bed1e45f84547d603bf7af3fb88f501933" } ] \ No newline at end of file From 6774b729139a47378e690ddc35cb324fed0cea62 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 22 Feb 2023 13:34:58 +0200 Subject: [PATCH 17/87] lnwallet: add same amount and preimage anchors test vector --- lnwallet/test_vectors_anchors.json | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lnwallet/test_vectors_anchors.json b/lnwallet/test_vectors_anchors.json index 2559e6822..14e6da9ac 100644 --- a/lnwallet/test_vectors_anchors.json +++ b/lnwallet/test_vectors_anchors.json @@ -237,5 +237,28 @@ "HtlcDescs": [], "ExpectedCommitmentTxHex": "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80024a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994c0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994a04004830450221009ad80792e3038fe6968d12ff23e6888a565c3ddd065037f357445f01675d63f3022018384915e5f1f4ae157e15debf4f49b61c8d9d2b073c7d6f97c4a68caa3ed4c1014830450221008fd5dbff02e4b59020d4cd23a3c30d3e287065fda75a0a09b402980adf68ccda022001e0b8b620cd915ddff11f1de32addf23d81d51b90e6841b2cb8dcaf3faa5ecf01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", "RemoteSigHex": "30450221008fd5dbff02e4b59020d4cd23a3c30d3e287065fda75a0a09b402980adf68ccda022001e0b8b620cd915ddff11f1de32addf23d81d51b90e6841b2cb8dcaf3faa5ecf" + }, + { + "Name": "commitment tx with 3 htlc outputs, 2 offered having the same amount and preimage", + "LocalBalance": 6987999999, + "RemoteBalance": 3000000000, + "FeePerKw": 253, + "UseTestHtlcs": true, + "HtlcDescs": [ + { + "RemoteSigHex": "30450221008c3060a17cb4799bc2290d692c8ae3d4a4ecbc7ed938d91709f7d3f4879987ea02201f32d763f52bee8b3362b2150d66a45c58fbe215160a4c271b4de17658e59d6e", + "ResolutionTxHex": "020000000001013d060d0305c9616eaabc21d41fae85bcb5477b5d7f1c92aa429cf15339bbe1c4020000000001000000011e070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004830450221008c3060a17cb4799bc2290d692c8ae3d4a4ecbc7ed938d91709f7d3f4879987ea02201f32d763f52bee8b3362b2150d66a45c58fbe215160a4c271b4de17658e59d6e83473044022045658d7072665bd8721859ea877d91587af138f9d3d6bc29339b972173521bb702205ccba02e9a2abd737af16abcfca3d9fd3fe6e0544e0efafddb634f3e30369c9e012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000" + }, + { + "RemoteSigHex": "3044022030fa4ca0a8dfd47112aa04dfa76f5b30d1ec593b5d76d7c0f986603fb61c3a6d02203ae477dfbb5fba5959302faeb04b4e66cef2030e1ac8826e7034865059962b00", + "ResolutionTxHex": "020000000001013d060d0305c9616eaabc21d41fae85bcb5477b5d7f1c92aa429cf15339bbe1c403000000000100000001e0120000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022030fa4ca0a8dfd47112aa04dfa76f5b30d1ec593b5d76d7c0f986603fb61c3a6d02203ae477dfbb5fba5959302faeb04b4e66cef2030e1ac8826e7034865059962b0083483045022100a6408b8db488d9f0a3bfd54087e447d19be77e54c849ac388c99b0d68fe90921022023052d488d814ee1c94a27df75aaa9b97a4fd789a5eb1ee989ee2a30663f447f01008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6851b27568f9010000" + }, + { + "RemoteSigHex": "304402203ba5761a9a145470c62beef6984b7c3d76e9f1ec9f2b69fa8ccc5f47781e25b202205913220be6eb80a436f78d9e1c8c048f41b7490e9f91e862f4a473c9a8cac022", + "ResolutionTxHex": "020000000001013d060d0305c9616eaabc21d41fae85bcb5477b5d7f1c92aa429cf15339bbe1c404000000000100000001e0120000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402203ba5761a9a145470c62beef6984b7c3d76e9f1ec9f2b69fa8ccc5f47781e25b202205913220be6eb80a436f78d9e1c8c048f41b7490e9f91e862f4a473c9a8cac0228348304502210091f2bb95774acb4d51986d11c917fa7f51a39fe38b8aa880b430c9e629389ee202201e6bc67849075ec0fc8b5205380069b91097a4ad7a5bc1183384519ba05b3a2401008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6851b27568fa010000" + } + ], + "ExpectedCommitmentTxHex": "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80074a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994d007000000000000220020fe0598d74fee2205cc3672e6e6647706b4f3099713b4661b62482c3addd04a5e881300000000000022002018e40f9072c44350f134bdc887bab4d9bdfc8aa468a25616c80e21757ba5dac7881300000000000022002018e40f9072c44350f134bdc887bab4d9bdfc8aa468a25616c80e21757ba5dac7c0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994aad9c6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100b4014970d9d7962853f3f85196144671d7d5d87426250f0a5fdaf9a55292e92502205360910c9abb397467e19dbd63d081deb4a3240903114c98cec0a23591b79b7601473044022027b38dfb654c34032ffb70bb43022981652fce923cbbe3cbe7394e2ade8b34230220584195b78da6e25c2e8da6b4308d9db25b65b64975db9266163ef592abb7c72501475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + "RemoteSigHex": "3044022027b38dfb654c34032ffb70bb43022981652fce923cbbe3cbe7394e2ade8b34230220584195b78da6e25c2e8da6b4308d9db25b65b64975db9266163ef592abb7c725" } ] \ No newline at end of file From b607db30f9d46502d32b9500da4deb9211974201 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 22 Feb 2023 13:14:49 +0200 Subject: [PATCH 18/87] lnwallet: add zero-fee-htlc-tx test vectors --- lnwallet/test_vectors_zero_fee_htlc_tx.json | 166 ++++++++++++++++++++ lnwallet/transactions_test.go | 22 ++- 2 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 lnwallet/test_vectors_zero_fee_htlc_tx.json diff --git a/lnwallet/test_vectors_zero_fee_htlc_tx.json b/lnwallet/test_vectors_zero_fee_htlc_tx.json new file mode 100644 index 000000000..0bb266e8b --- /dev/null +++ b/lnwallet/test_vectors_zero_fee_htlc_tx.json @@ -0,0 +1,166 @@ +[ + { + "Name": "simple commitment tx with no HTLCs", + "LocalBalance": 7000000000, + "RemoteBalance": 3000000000, + "DustLimitSatoshis": 546, + "FeePerKw": 15000, + "UseTestHtlcs": false, + "HtlcDescs": [], + "ExpectedCommitmentTxHex": "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80044a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994c0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994a508b6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004830450221008266ac6db5ea71aac3c95d97b0e172ff596844851a3216eb88382a8dddfd33d2022050e240974cfd5d708708b4365574517c18e7ae535ef732a3484d43d0d82be9f701483045022100f89034eba16b2be0e5581f750a0a6309192b75cce0f202f0ee2b4ec0cc394850022076c65dc507fe42276152b7a3d90e961e678adbe966e916ecfe85e64d430e75f301475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + "RemoteSigHex": "3045022100f89034eba16b2be0e5581f750a0a6309192b75cce0f202f0ee2b4ec0cc394850022076c65dc507fe42276152b7a3d90e961e678adbe966e916ecfe85e64d430e75f3" + }, + { + "Name": "simple commitment tx with no HTLCs and single anchor", + "LocalBalance": 10000000000, + "RemoteBalance": 0, + "DustLimitSatoshis": 546, + "FeePerKw": 15000, + "UseTestHtlcs": false, + "HtlcDescs": [], + "ExpectedCommitmentTxHex": "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80024a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f10529800000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022007cf6b405e9c9b4f527b0ecad9d8bb661fabb8b12abf7d1c0b3ad1855db3ed490220616d5c1eeadccc63bd775a131149455d62d95a42c2a1b01cc7821fc42dce7778014730440220655bf909fb6fa81d086f1336ac72c97906dce29d1b166e305c99152d810e26e1022051f577faa46412c46707aaac46b65d50053550a66334e00a44af2706f27a865801475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + "RemoteSigHex": "30440220655bf909fb6fa81d086f1336ac72c97906dce29d1b166e305c99152d810e26e1022051f577faa46412c46707aaac46b65d50053550a66334e00a44af2706f27a8658" + }, + { + "Name": "commitment tx with seven outputs untrimmed", + "LocalBalance": 6988000000, + "RemoteBalance": 3000000000, + "DustLimitSatoshis": 546, + "FeePerKw": 644, + "UseTestHtlcs": true, + "HtlcDescs": [ + { + "RemoteSigHex": "30440220746dc89a593e1b50915db63359b50c3c404f8324f78075c87708c866ccefda2502202a11062012dc8607b17e8c46ea4eefdfcc6b89a35440de99432ba12788d7bb17", + "ResolutionTxHex": "02000000000101b8cefef62ea66f5178b9361b2371be0759cbc8c689bcfa7a8e6746d497ec221a02000000000100000001e8030000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220746dc89a593e1b50915db63359b50c3c404f8324f78075c87708c866ccefda2502202a11062012dc8607b17e8c46ea4eefdfcc6b89a35440de99432ba12788d7bb1783473044022036f77f88b49bd03dc16d3a015efcc7acffc2a93b213324035d77a716f79013ff02203c218eb882a40402a8bb05dbb751a442345a4e56307be76b214b6d4db9ed3c92012000000000000000000000000000000000000000000000000000000000000000008d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac6851b2756800000000" + }, + { + "RemoteSigHex": "3045022100a847bc3b8cf2441013725ae32dc589c419835d069afd6d7f3d9834d8be7cea6e02204ce9d35ec7f0788da80e4d62e810c4ccd13617e58fa10832e38fb7ae87bdf338", + "ResolutionTxHex": "02000000000101b8cefef62ea66f5178b9361b2371be0759cbc8c689bcfa7a8e6746d497ec221a03000000000100000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100a847bc3b8cf2441013725ae32dc589c419835d069afd6d7f3d9834d8be7cea6e02204ce9d35ec7f0788da80e4d62e810c4ccd13617e58fa10832e38fb7ae87bdf33883473044022026739b1adbfa34c485bf0e5a19e0cf7532f64545bcc5c95b95643ccc2d351e1902201743bb1b34f00e031cc15f6eff0f8ab764508d2681ff965ba62e76e540bca1e801008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6851b27568f6010000" + }, + { + "RemoteSigHex": "3044022035977f2aa6d6ae12f1dae3366440faa17558e9c88c3188bfc8df7e276c6c65410220659f1f9070c725d9d46e43b99a36fc6d711d36069704add2d57fc1fa2818cf12", + "ResolutionTxHex": "02000000000101b8cefef62ea66f5178b9361b2371be0759cbc8c689bcfa7a8e6746d497ec221a04000000000100000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022035977f2aa6d6ae12f1dae3366440faa17558e9c88c3188bfc8df7e276c6c65410220659f1f9070c725d9d46e43b99a36fc6d711d36069704add2d57fc1fa2818cf12834730440220191ba44e57b1601a59d99f85971d4801b286d428de275487c87ceeb8df1a4811022002215875d92833df0c9615c9096cf97152f87139ed9f82718bbb5b8b3d312524012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000" + }, + { + "RemoteSigHex": "3044022002f3ff9a31270092c214d3d5b8b4f826599404bba64b87f7536ef6324d41551b022079dc4cb25f7ecd84b49f5cce03eae7e2655b59f39d543765daef0d4f11c93fa2", + "ResolutionTxHex": "02000000000101b8cefef62ea66f5178b9361b2371be0759cbc8c689bcfa7a8e6746d497ec221a05000000000100000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022002f3ff9a31270092c214d3d5b8b4f826599404bba64b87f7536ef6324d41551b022079dc4cb25f7ecd84b49f5cce03eae7e2655b59f39d543765daef0d4f11c93fa283483045022100f03047e38bc0aae2d80d53424b8c1d1b8139120e2bf09ad31a2803978745e6e102205b74c0eef0b472710b98c77e619ee9d0cc47a9dd786f4f214a564f44d79f9b9a01008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" + }, + { + "RemoteSigHex": "30440220547937564288f64fb3e3c945a1348b912471f0c1c4cc7dc8ceca15a4cbd299b6022053c4f8e30832b13dfbe31e4091e313428625e0b5ac61eecba93f8f11c1e26225", + "ResolutionTxHex": "02000000000101b8cefef62ea66f5178b9361b2371be0759cbc8c689bcfa7a8e6746d497ec221a06000000000100000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220547937564288f64fb3e3c945a1348b912471f0c1c4cc7dc8ceca15a4cbd299b6022053c4f8e30832b13dfbe31e4091e313428625e0b5ac61eecba93f8f11c1e2622583473044022022604660234aef9bd21284598ec50f070ac82a3a0152e0af5e98a02cd6e8976f022042b0b9112ee00806b856dff6de52a82c98b036a4fe14bb5fd2926725e2fc8191012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" + } + ], + "ExpectedCommitmentTxHex": "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80094a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994e80300000000000022002010f88bf09e56f14fb4543fd26e47b0db50ea5de9cf3fc46434792471082621aed0070000000000002200203e68115ae0b15b8de75b6c6bc9af5ac9f01391544e0870dae443a1e8fe7837ead007000000000000220020fe0598d74fee2205cc3672e6e6647706b4f3099713b4661b62482c3addd04a5eb80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994a4f996a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100ef82a405364bfc4007e63a7cc82925a513d79065bdbc216d60b6a4223a323f8a02200716730b8561f3c6d362eaf47f202e99fb30d0557b61b92b5f9134f8e2de368101483045022100e0106830467a558c07544a3de7715610c1147062e7d091deeebe8b5c661cda9402202ad049c1a6d04834317a78483f723c205c9f638d17222aafc620800cc1b6ae3501475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + "RemoteSigHex": "3045022100e0106830467a558c07544a3de7715610c1147062e7d091deeebe8b5c661cda9402202ad049c1a6d04834317a78483f723c205c9f638d17222aafc620800cc1b6ae35" + }, + { + "Name": "commitment tx with six outputs untrimmed (minimum dust limit)", + "LocalBalance": 6988000000, + "RemoteBalance": 3000000000, + "DustLimitSatoshis": 1001, + "FeePerKw": 645, + "UseTestHtlcs": true, + "HtlcDescs": [ + { + "RemoteSigHex": "3045022100e04d160a326432659fe9fb127304c1d348dfeaba840081bdc57d8efd902a48d8022008a824e7cf5492b97e4d9e03c06a09f822775a44f6b5b2533a2088904abfc282", + "ResolutionTxHex": "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320002000000000100000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100e04d160a326432659fe9fb127304c1d348dfeaba840081bdc57d8efd902a48d8022008a824e7cf5492b97e4d9e03c06a09f822775a44f6b5b2533a2088904abfc28283483045022100b7c49846466b13b190ff739bbe3005c105482fc55539e55b1c561f76b6982b6c02200e5c35808619cf543c8405cff9fedd25f333a4a2f6f6d5e8af8150090c40ef0901008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6851b27568f6010000" + }, + { + "RemoteSigHex": "3045022100fbdc3c367ce3bf30796025cc590ee1f2ce0e72ae1ac19f5986d6d0a4fc76211f02207e45ae9267e8e820d188569604f71d1abd11bd385d58853dd7dc034cdb3e9a6e", + "ResolutionTxHex": "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320003000000000100000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100fbdc3c367ce3bf30796025cc590ee1f2ce0e72ae1ac19f5986d6d0a4fc76211f02207e45ae9267e8e820d188569604f71d1abd11bd385d58853dd7dc034cdb3e9a6e83483045022100d29330f24db213b262068706099b39c15fa7e070c3fcdf8836c09723fc4d365602203ce57d01e9f28601e461a0b5c4a50119b270bde8b70148d133a6849c70b115ac012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000" + }, + { + "RemoteSigHex": "3044022066c5ef625cee3ddd2bc7b6bfb354b5834cf1cc6d52dd972fb41b7b225437ae4a022066cb85647df65c6b87a54e416dcdcca778a776c36a9643d2b5dc793c9b29f4c1", + "ResolutionTxHex": "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320004000000000100000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022066c5ef625cee3ddd2bc7b6bfb354b5834cf1cc6d52dd972fb41b7b225437ae4a022066cb85647df65c6b87a54e416dcdcca778a776c36a9643d2b5dc793c9b29f4c18347304402202d4ce515cd9000ec37575972d70b8d24f73909fb7012e8ebd8c2066ef6fe187902202830b53e64ea565fecd0f398100691da6bb2a5cf9bb0d1926f1d71d05828a11e01008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" + }, + { + "RemoteSigHex": "3044022022c7e11595c53ee89a57ca76baf0aed730da035952d6ab3fe6459f5eff3b337a022075e10cc5f5fd724a35ce4087a5d03cd616698626c69814032132b50bb97dc615", + "ResolutionTxHex": "02000000000101104f394af4c4fad78337f95e3e9f802f4c0d86ab231853af09b285348561320005000000000100000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022022c7e11595c53ee89a57ca76baf0aed730da035952d6ab3fe6459f5eff3b337a022075e10cc5f5fd724a35ce4087a5d03cd616698626c69814032132b50bb97dc61583483045022100b20cd63e0587d1711beaebda4730775c4ac8b8b2ec78fe18a0c44c3f168c25230220079abb7fc4924e2fca5950842e5b9e416735585026914570078c4ef62f286226012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" + } + ], + "ExpectedCommitmentTxHex": "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80084a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994d0070000000000002200203e68115ae0b15b8de75b6c6bc9af5ac9f01391544e0870dae443a1e8fe7837ead007000000000000220020fe0598d74fee2205cc3672e6e6647706b4f3099713b4661b62482c3addd04a5eb80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994abc996a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100d57697c707b6f6d053febf24b98e8989f186eea42e37e9e91663ec2c70bb8f70022079b0715a472118f262f43016a674f59c015d9cafccec885968e76d9d9c5d005101473044022025d97466c8049e955a5afce28e322f4b34d2561118e52332fb400f9b908cc0a402205dc6fba3a0d67ee142c428c535580cd1f2ff42e2f89b47e0c8a01847caffc31201475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + "RemoteSigHex": "3044022025d97466c8049e955a5afce28e322f4b34d2561118e52332fb400f9b908cc0a402205dc6fba3a0d67ee142c428c535580cd1f2ff42e2f89b47e0c8a01847caffc312" + }, + { + "Name": "commitment tx with four outputs untrimmed (minimum dust limit)", + "LocalBalance": 6988000000, + "RemoteBalance": 3000000000, + "DustLimitSatoshis": 2001, + "FeePerKw": 2185, + "UseTestHtlcs": true, + "HtlcDescs": [ + { + "RemoteSigHex": "304402206870514a72ad6e723ff7f1e0370d7a33c1cd2a0b9272674143ebaf6a1d02dee102205bd953c34faf5e7322e9a1c0103581cb090280fda4f1039ee8552668afa90ebb", + "ResolutionTxHex": "02000000000101ac13a7715f80b8e52dda43c6929cade5521bdced3a405da02b443f1ffb1e33cc02000000000100000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402206870514a72ad6e723ff7f1e0370d7a33c1cd2a0b9272674143ebaf6a1d02dee102205bd953c34faf5e7322e9a1c0103581cb090280fda4f1039ee8552668afa90ebb834730440220669de9ca7910eff65a7773ebd14a9fc371fe88cde5b8e2a81609d85c87ac939b02201ac29472fa4067322e92d75b624942d60be5050139b20bb363db75be79eb946f01008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6851b27568f7010000" + }, + { + "RemoteSigHex": "3045022100949e8dd938da56445b1cdfdebe1b7efea086edd05d89910d205a1e2e033ce47102202cbd68b5262ab144d9ec12653f87dfb0bb6bd05d1f58ae1e523f028eaefd7271", + "ResolutionTxHex": "02000000000101ac13a7715f80b8e52dda43c6929cade5521bdced3a405da02b443f1ffb1e33cc03000000000100000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100949e8dd938da56445b1cdfdebe1b7efea086edd05d89910d205a1e2e033ce47102202cbd68b5262ab144d9ec12653f87dfb0bb6bd05d1f58ae1e523f028eaefd727183483045022100e3104ed8b239f8019e5f0a1a73d7782a94a8c36e7984f476c3a0b3cb0e62e27902207e3d52884600985f8a2098e53a5c30dd6a5e857733acfaa07ab2162421ed2688012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" + } + ], + "ExpectedCommitmentTxHex": "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80064a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994b80b000000000000220020f96d0334feb64a4f40eb272031d07afcb038db56aa57446d60308c9f8ccadef9a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994ac5916a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100cd8479cfe1edb1e5a1d487391e0451a469c7171e51e680183f19eb4321f20e9b02204eab7d5a6384b1b08e03baa6e4d9748dfd2b5ab2bae7e39604a0d0055bbffdd501473044022040f63a16148cf35c8d3d41827f5ae7f7c3746885bb64d4d1b895892a83812b3e02202fcf95c2bf02c466163b3fa3ced6a24926fbb4035095a96842ef516e86ba54c001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + "RemoteSigHex": "3044022040f63a16148cf35c8d3d41827f5ae7f7c3746885bb64d4d1b895892a83812b3e02202fcf95c2bf02c466163b3fa3ced6a24926fbb4035095a96842ef516e86ba54c0" + }, + { + "Name": "commitment tx with three outputs untrimmed (minimum dust limit)", + "LocalBalance": 6988000000, + "RemoteBalance": 3000000000, + "DustLimitSatoshis": 3001, + "FeePerKw": 3687, + "UseTestHtlcs": true, + "HtlcDescs": [ + { + "RemoteSigHex": "3044022017b558a3cf5f0cb94269e2e927b29ed22bd2416abb8a7ce6de4d1256f359b93602202e9ca2b1a23ea3e69f433c704e327739e219804b8c188b1d52f74fd5a9de954c", + "ResolutionTxHex": "02000000000101542562b326c08e3a076d9cfca2be175041366591da334d8d513ff1686fd95a6002000000000100000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022017b558a3cf5f0cb94269e2e927b29ed22bd2416abb8a7ce6de4d1256f359b93602202e9ca2b1a23ea3e69f433c704e327739e219804b8c188b1d52f74fd5a9de954c83483045022100af7a8b7c7ff2080c68995254cb66d64d9954edcc5baac3bb4f27ed2d29aaa6120220421c27da7a60574a9263f271e0f3bd34594ec6011095190022b3b54596ea03de012004040404040404040404040404040404040404040404040404040404040404048d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac6851b2756800000000" + } + ], + "ExpectedCommitmentTxHex": "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80054a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994a00f000000000000220020ce6e751274836ff59622a0d1e07f8831d80bd6730bd48581398bfadd2bb8da9ac0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994aa28b6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100c970799bcb33f43179eb43b3378a0a61991cf2923f69b36ef12548c3df0e6d500220413dc27d2e39ee583093adfcb7799be680141738babb31cc7b0669a777a31f5d01483045022100ad6c71569856b2d7ff42e838b4abe74a713426b37f22fa667a195a4c88908c6902202b37272b02a42dc6d9f4f82cab3eaf84ac882d9ed762859e1e75455c2c22837701475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + "RemoteSigHex": "3045022100ad6c71569856b2d7ff42e838b4abe74a713426b37f22fa667a195a4c88908c6902202b37272b02a42dc6d9f4f82cab3eaf84ac882d9ed762859e1e75455c2c228377" + }, + { + "Name": "commitment tx with two outputs untrimmed (minimum dust limit)", + "LocalBalance": 6988000000, + "RemoteBalance": 3000000000, + "DustLimitSatoshis": 4001, + "FeePerKw": 4894, + "UseTestHtlcs": true, + "HtlcDescs": [], + "ExpectedCommitmentTxHex": "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80044a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994c0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994ad0886a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004830450221009f16ac85d232e4eddb3fcd750a68ebf0b58e3356eaada45d3513ede7e817bf4c02207c2b043b4e5f971261975406cb955219fa56bffe5d834a833694b5abc1ce4cfd01483045022100e784a66b1588575801e237d35e510fd92a81ae3a4a2a1b90c031ad803d07b3f3022021bc5f16501f167607d63b681442da193eb0a76b4b7fd25c2ed4f8b28fd35b9501475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + "RemoteSigHex": "3045022100e784a66b1588575801e237d35e510fd92a81ae3a4a2a1b90c031ad803d07b3f3022021bc5f16501f167607d63b681442da193eb0a76b4b7fd25c2ed4f8b28fd35b95" + }, + { + "Name": "commitment tx with one output untrimmed (minimum dust limit)", + "LocalBalance": 6988000000, + "RemoteBalance": 3000000000, + "DustLimitSatoshis": 4001, + "FeePerKw": 6216010, + "UseTestHtlcs": true, + "HtlcDescs": [], + "ExpectedCommitmentTxHex": "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80024a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994c0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994a04004830450221009ad80792e3038fe6968d12ff23e6888a565c3ddd065037f357445f01675d63f3022018384915e5f1f4ae157e15debf4f49b61c8d9d2b073c7d6f97c4a68caa3ed4c1014830450221008fd5dbff02e4b59020d4cd23a3c30d3e287065fda75a0a09b402980adf68ccda022001e0b8b620cd915ddff11f1de32addf23d81d51b90e6841b2cb8dcaf3faa5ecf01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + "RemoteSigHex": "30450221008fd5dbff02e4b59020d4cd23a3c30d3e287065fda75a0a09b402980adf68ccda022001e0b8b620cd915ddff11f1de32addf23d81d51b90e6841b2cb8dcaf3faa5ecf" + }, + { + "Name": "commitment tx with 3 htlc outputs, 2 offered having the same amount and preimage", + "LocalBalance": 6987999999, + "RemoteBalance": 3000000000, + "DustLimitSatoshis": 546, + "FeePerKw": 253, + "UseTestHtlcs": true, + "HtlcDescs": [ + { + "RemoteSigHex": "30440220078fe5343dab88c348a3a8a9c1a9293259dbf35507ae971702cc39dd623ea9af022011ed0c0f35243cd0bb4d9ca3c772379b2b5f4af93140e9fdc5600dfec1cdb0c2", + "ResolutionTxHex": "020000000001013d060d0305c9616eaabc21d41fae85bcb5477b5d7f1c92aa429cf15339bbe1c402000000000100000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220078fe5343dab88c348a3a8a9c1a9293259dbf35507ae971702cc39dd623ea9af022011ed0c0f35243cd0bb4d9ca3c772379b2b5f4af93140e9fdc5600dfec1cdb0c28347304402205df665e2908c7690d2d33eb70e6e119958c28febe141a94ed0dd9a55ce7c8cfc0220364d02663a5d019af35c5cd5fda9465d985d85bbd12db207738d61163449a424012001010101010101010101010101010101010101010101010101010101010101018d76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac6851b2756800000000" + }, + { + "RemoteSigHex": "304402202df6bf0f98a42cfd0172a16bded7d1b16c14f5f42ba23f5c54648c14b647531302200fe1508626817f23925bb56951d5e4b2654c751743ab6db48a6cce7dda17c01c", + "ResolutionTxHex": "020000000001013d060d0305c9616eaabc21d41fae85bcb5477b5d7f1c92aa429cf15339bbe1c40300000000010000000188130000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402202df6bf0f98a42cfd0172a16bded7d1b16c14f5f42ba23f5c54648c14b647531302200fe1508626817f23925bb56951d5e4b2654c751743ab6db48a6cce7dda17c01c8347304402203f99ec05cdd89558a23683b471c1dcce8f6a92295f1fff3b0b5d21be4d4f97ea022019d29070690fc2c126fe27cc4ab2f503f289d362721b2efa7418e7fddb939a5b01008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6851b27568f9010000" + }, + { + "RemoteSigHex": "3045022100bd206b420c495f3aa714d3ea4766cbe95441deacb5d2f737f1913349aee7c2ae02200249d2c950dd3b15326bf378ae5d2b871d33d6737f5d70735f3de8383140f2a1", + "ResolutionTxHex": "020000000001013d060d0305c9616eaabc21d41fae85bcb5477b5d7f1c92aa429cf15339bbe1c40400000000010000000188130000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100bd206b420c495f3aa714d3ea4766cbe95441deacb5d2f737f1913349aee7c2ae02200249d2c950dd3b15326bf378ae5d2b871d33d6737f5d70735f3de8383140f2a183483045022100f2cd35e385b9b7e15b92a5d78d120b6b2c5af4e974bc01e884c5facb3bb5966c0220706e0506477ce809a40022d6de8e041e9ef13136c45abee9c36f58a01fdb188b01008876a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9142002cc93ebefbb1b73f0af055dcc27a0b504ad7688ac6851b27568fa010000" + } + ], + "ExpectedCommitmentTxHex": "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80074a010000000000002200202b1b5854183c12d3316565972c4668929d314d81c5dcdbb21cb45fe8a9a8114f4a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994d007000000000000220020fe0598d74fee2205cc3672e6e6647706b4f3099713b4661b62482c3addd04a5e881300000000000022002018e40f9072c44350f134bdc887bab4d9bdfc8aa468a25616c80e21757ba5dac7881300000000000022002018e40f9072c44350f134bdc887bab4d9bdfc8aa468a25616c80e21757ba5dac7c0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994aad9c6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100b4014970d9d7962853f3f85196144671d7d5d87426250f0a5fdaf9a55292e92502205360910c9abb397467e19dbd63d081deb4a3240903114c98cec0a23591b79b7601473044022027b38dfb654c34032ffb70bb43022981652fce923cbbe3cbe7394e2ade8b34230220584195b78da6e25c2e8da6b4308d9db25b65b64975db9266163ef592abb7c72501475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + "RemoteSigHex": "3044022027b38dfb654c34032ffb70bb43022981652fce923cbbe3cbe7394e2ade8b34230220584195b78da6e25c2e8da6b4308d9db25b65b64975db9266163ef592abb7c725" + } +] \ No newline at end of file diff --git a/lnwallet/transactions_test.go b/lnwallet/transactions_test.go index 86c40f657..92b22d5e0 100644 --- a/lnwallet/transactions_test.go +++ b/lnwallet/transactions_test.go @@ -178,10 +178,11 @@ type htlcDesc struct { } type testCase struct { - Name string - LocalBalance lnwire.MilliSatoshi - RemoteBalance lnwire.MilliSatoshi - FeePerKw btcutil.Amount + Name string + LocalBalance lnwire.MilliSatoshi + RemoteBalance lnwire.MilliSatoshi + FeePerKw btcutil.Amount + DustLimitSatoshis btcutil.Amount // UseTestHtlcs defined whether the fixed set of test htlc should be // added to the channel before checking the commitment assertions. @@ -214,6 +215,13 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) { channeldb.AnchorOutputsBit, jsonFile: "test_vectors_anchors.json", }, + { + name: "zero fee htlc tx", + chanType: channeldb.SingleFunderTweaklessBit | + channeldb.AnchorOutputsBit | + channeldb.ZeroHtlcTxFeeBit, + jsonFile: "test_vectors_zero_fee_htlc_tx.json", + }, } for _, set := range vectorSets { @@ -301,6 +309,12 @@ func testVectors(t *testing.T, chanType channeldb.ChannelType, test testCase) { testHtlcs = testHtlcsSet2 } + // If the test specifies a dust limit, then use it instead of the + // default. + if test.DustLimitSatoshis != 0 { + tc.dustLimit = test.DustLimitSatoshis + } + // Balances in the test vectors are before subtraction of in-flight // htlcs. Convert to spendable balances. remoteBalance := test.RemoteBalance From 05793e55912efc8c2cdd1c8719a5074eaebdc3d0 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 22 Feb 2023 13:16:33 +0200 Subject: [PATCH 19/87] docs: add release note --- docs/release-notes/release-notes-0.16.1.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index 0edf7c3c8..89f0a7eaa 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -9,9 +9,15 @@ * [Return `FEE_INSUFFICIENT` before checking balance for incoming low-fee HTLCs.](https://github.com/lightningnetwork/lnd/pull/7490). + +## Spec + +* [Add test vectors for + option_zero_fee_htlc_tx](https://github.com/lightningnetwork/lnd/pull/7439) # Contributors (Alphabetical Order) +* Elle Mouton * Oliver Gugger * Tommy Volk * Yong Yu From c87da1ff0129d7ab242086f1787c81a9e39f6289 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 16 Mar 2023 01:45:50 +0800 Subject: [PATCH 20/87] itest: fix flake in `testAnchorThirdPartySpend` --- itest/lnd_onchain_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/itest/lnd_onchain_test.go b/itest/lnd_onchain_test.go index b9d50d5c6..8d57907d5 100644 --- a/itest/lnd_onchain_test.go +++ b/itest/lnd_onchain_test.go @@ -430,6 +430,15 @@ func testAnchorThirdPartySpend(ht *lntest.HarnessTest) { commitTxn := ht.Miner.GetRawTransaction(forceCloseTxID) ht.Miner.MineBlockWithTxes([]*btcutil.Tx{commitTxn}) + // Assert that the channel is now in PendingForceClose. + // + // NOTE: We must do this check to make sure `lnd` node has updated its + // internal state regarding the closing transaction, otherwise the + // `SendCoins` below might fail since it involves a reserved value + // check, which requires a certain amount of coins to be reserved based + // on the number of anchor channels. + ht.AssertChannelPendingForceClose(alice, aliceChanPoint1) + // With the anchor output located, and the main commitment mined we'll // instruct the wallet to send all coins in the wallet to a new address // (to the miner), including unconfirmed change. From 9bd0dcd12103e592657db496c3371c25149995df Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Fri, 17 Mar 2023 10:00:54 +0800 Subject: [PATCH 21/87] rpcserver: add debug log for rpc calls --- rpcperms/interceptor.go | 4 ++++ rpcserver.go | 20 -------------------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/rpcperms/interceptor.go b/rpcperms/interceptor.go index b96bc7f84..cea9670c4 100644 --- a/rpcperms/interceptor.go +++ b/rpcperms/interceptor.go @@ -772,6 +772,8 @@ func (r *InterceptorChain) rpcStateUnaryServerInterceptor() grpc.UnaryServerInte return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + r.rpcsLog.Debugf("[%v] requested", info.FullMethod) + if err := r.checkRPCState(info.Server); err != nil { return nil, err } @@ -786,6 +788,8 @@ func (r *InterceptorChain) rpcStateStreamServerInterceptor() grpc.StreamServerIn return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + r.rpcsLog.Debugf("[%v] requested", info.FullMethod) + if err := r.checkRPCState(srv); err != nil { return err } diff --git a/rpcserver.go b/rpcserver.go index cc8b95e06..f531e8a5b 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -2941,8 +2941,6 @@ func (r *rpcServer) GetRecoveryInfo(ctx context.Context, func (r *rpcServer) ListPeers(ctx context.Context, in *lnrpc.ListPeersRequest) (*lnrpc.ListPeersResponse, error) { - rpcsLog.Tracef("[listpeers] request") - serverPeers := r.server.Peers() resp := &lnrpc.ListPeersResponse{ Peers: make([]*lnrpc.Peer, 0, len(serverPeers)), @@ -3701,8 +3699,6 @@ func (r *rpcServer) PendingChannels(ctx context.Context, in *lnrpc.PendingChannelsRequest) ( *lnrpc.PendingChannelsResponse, error) { - rpcsLog.Debugf("[pendingchannels]") - resp := &lnrpc.PendingChannelsResponse{} // First, we find all the channels that will soon be opened. @@ -6409,8 +6405,6 @@ func marshallTopologyChange(topChange *routing.TopologyChange) *lnrpc.GraphTopol func (r *rpcServer) ListPayments(ctx context.Context, req *lnrpc.ListPaymentsRequest) (*lnrpc.ListPaymentsResponse, error) { - rpcsLog.Debugf("[ListPayments]") - // If both dates are set, we check that the start date is less than the // end date, otherwise we'll get an empty result. if req.CreationDateStart != 0 && req.CreationDateEnd != 0 { @@ -6627,10 +6621,6 @@ const feeBase float64 = 1000000 func (r *rpcServer) FeeReport(ctx context.Context, _ *lnrpc.FeeReportRequest) (*lnrpc.FeeReportResponse, error) { - // TODO(roasbeef): use UnaryInterceptor to add automated logging - - rpcsLog.Debugf("[feereport]") - channelGraph := r.server.graphDB selfNode, err := channelGraph.SourceNode() if err != nil { @@ -6894,8 +6884,6 @@ func (r *rpcServer) ForwardingHistory(ctx context.Context, req *lnrpc.ForwardingHistoryRequest) (*lnrpc.ForwardingHistoryResponse, error) { - rpcsLog.Debugf("[forwardinghistory]") - // Before we perform the queries below, we'll instruct the switch to // flush any pending events to disk. This ensure we get a complete // snapshot at this particular time. @@ -7426,8 +7414,6 @@ func (r *rpcServer) ChannelAcceptor(stream lnrpc.Lightning_ChannelAcceptorServer func (r *rpcServer) BakeMacaroon(ctx context.Context, req *lnrpc.BakeMacaroonRequest) (*lnrpc.BakeMacaroonResponse, error) { - rpcsLog.Debugf("[bakemacaroon]") - // If the --no-macaroons flag is used to start lnd, the macaroon service // is not initialized. Therefore we can't bake new macaroons. if r.macService == nil { @@ -7514,8 +7500,6 @@ func (r *rpcServer) ListMacaroonIDs(ctx context.Context, req *lnrpc.ListMacaroonIDsRequest) ( *lnrpc.ListMacaroonIDsResponse, error) { - rpcsLog.Debugf("[listmacaroonids]") - // If the --no-macaroons flag is used to start lnd, the macaroon service // is not initialized. Therefore we can't show any IDs. if r.macService == nil { @@ -7546,8 +7530,6 @@ func (r *rpcServer) DeleteMacaroonID(ctx context.Context, req *lnrpc.DeleteMacaroonIDRequest) ( *lnrpc.DeleteMacaroonIDResponse, error) { - rpcsLog.Debugf("[deletemacaroonid]") - // If the --no-macaroons flag is used to start lnd, the macaroon service // is not initialized. Therefore we can't delete any IDs. if r.macService == nil { @@ -7577,8 +7559,6 @@ func (r *rpcServer) ListPermissions(_ context.Context, _ *lnrpc.ListPermissionsRequest) (*lnrpc.ListPermissionsResponse, error) { - rpcsLog.Debugf("[listpermissions]") - permissionMap := make(map[string]*lnrpc.MacaroonPermissionList) for uri, perms := range r.interceptorChain.Permissions() { rpcPerms := make([]*lnrpc.MacaroonPermission, len(perms)) From ef4b5dba852f0cfc3cc913adce26da17000223d5 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 16 Mar 2023 02:08:20 +0800 Subject: [PATCH 22/87] docs: update release note --- docs/release-notes/release-notes-0.16.1.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index 0edf7c3c8..a65aa8c3f 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -10,6 +10,12 @@ * [Return `FEE_INSUFFICIENT` before checking balance for incoming low-fee HTLCs.](https://github.com/lightningnetwork/lnd/pull/7490). +## RPC + +- A [debug log](https://github.com/lightningnetwork/lnd/pull/7514) has been + added to `lnrpc` so the node operator can know whether a certain request has + happened or not. + # Contributors (Alphabetical Order) * Oliver Gugger From 1b7c56b2ed1fea1a136762ee68bc6f4c82657ddc Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 16 Mar 2023 04:42:21 +0800 Subject: [PATCH 23/87] multi: rename `FundingLocked` to `ChannelReady` This commit is created by running, ```shell gofmt -d -w -r 'FundingLocked -> ChannelReady' . gco master channeldb/migration ``` --- funding/manager.go | 4 ++-- funding/manager_test.go | 46 ++++++++++++++++++++-------------------- htlcswitch/link_test.go | 24 ++++++++++----------- htlcswitch/mock.go | 2 +- htlcswitch/test_utils.go | 2 +- lnwire/funding_locked.go | 14 ++++++------ lnwire/lnwire_test.go | 2 +- lnwire/message.go | 2 +- lnwire/message_test.go | 2 +- peer/brontide.go | 4 ++-- 10 files changed, 51 insertions(+), 51 deletions(-) diff --git a/funding/manager.go b/funding/manager.go index 2d702ba48..113a30343 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -889,7 +889,7 @@ func (f *Manager) reservationCoordinator() { case *lnwire.FundingSigned: f.handleFundingSigned(fmsg.peer, msg) - case *lnwire.FundingLocked: + case *lnwire.ChannelReady: f.wg.Add(1) go f.handleFundingLocked(fmsg.peer, msg) @@ -3394,7 +3394,7 @@ func (f *Manager) waitForZeroConfChannel(c *channeldb.OpenChannel, // handleFundingLocked finalizes the channel funding process and enables the // channel to enter normal operating mode. func (f *Manager) handleFundingLocked(peer lnpeer.Peer, - msg *lnwire.FundingLocked) { + msg *lnwire.ChannelReady) { defer f.wg.Done() log.Debugf("Received FundingLocked for ChannelID(%v) from "+ diff --git a/funding/manager_test.go b/funding/manager_test.go index f386e3de5..0d33e60bb 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -901,7 +901,7 @@ func assertFundingMsgSent(t *testing.T, msgChan chan lnwire.Message, case "FundingSigned": sentMsg, ok = msg.(*lnwire.FundingSigned) case "FundingLocked": - sentMsg, ok = msg.(*lnwire.FundingLocked) + sentMsg, ok = msg.(*lnwire.ChannelReady) case "Error": sentMsg, ok = msg.(*lnwire.Error) default: @@ -1408,12 +1408,12 @@ func TestFundingManagerNormalWorkflow(t *testing.T) { // fundingLocked to Bob. fundingLockedAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. fundingLockedBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly assertFundingLockedSent(t, alice, bob, fundingOutPoint) @@ -1679,7 +1679,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) { // Bob will send funding locked to Alice. fundingLockedBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // Alice should still be markedOpen assertDatabaseState(t, alice, fundingOutPoint, markedOpen) @@ -1708,7 +1708,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) { fundingLockedAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // The state should now be fundingLockedSent assertDatabaseState(t, alice, fundingOutPoint, fundingLockedSent) @@ -1836,7 +1836,7 @@ func TestFundingManagerOfflinePeer(t *testing.T) { // Bob will send funding locked to Alice fundingLockedBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // Alice should still be markedOpen assertDatabaseState(t, alice, fundingOutPoint, markedOpen) @@ -1884,7 +1884,7 @@ func TestFundingManagerOfflinePeer(t *testing.T) { // This should make Alice send the fundingLocked. fundingLockedAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // The state should now be fundingLockedSent assertDatabaseState(t, alice, fundingOutPoint, fundingLockedSent) @@ -2313,12 +2313,12 @@ func TestFundingManagerReceiveFundingLockedTwice(t *testing.T) { // fundingLocked to Bob. fundingLockedAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. fundingLockedBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly assertFundingLockedSent(t, alice, bob, fundingOutPoint) @@ -2424,12 +2424,12 @@ func TestFundingManagerRestartAfterChanAnn(t *testing.T) { // fundingLocked to Bob. fundingLockedAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. fundingLockedBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly assertFundingLockedSent(t, alice, bob, fundingOutPoint) @@ -2521,12 +2521,12 @@ func TestFundingManagerRestartAfterReceivingFundingLocked(t *testing.T) { // fundingLocked to Bob. fundingLockedAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. fundingLockedBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly assertFundingLockedSent(t, alice, bob, fundingOutPoint) @@ -2614,12 +2614,12 @@ func TestFundingManagerPrivateChannel(t *testing.T) { // fundingLocked to Bob. fundingLockedAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. fundingLockedBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly assertFundingLockedSent(t, alice, bob, fundingOutPoint) @@ -2737,12 +2737,12 @@ func TestFundingManagerPrivateRestart(t *testing.T) { // fundingLocked to Bob. fundingLockedAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. fundingLockedBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly assertFundingLockedSent(t, alice, bob, fundingOutPoint) @@ -3172,12 +3172,12 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) { // fundingLocked to Bob. fundingLockedAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. fundingLockedBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) // Exchange the fundingLocked messages. alice.fundingMgr.ProcessFundingMsg(fundingLockedBob, bob) @@ -3489,11 +3489,11 @@ func TestFundingManagerMaxPendingChannels(t *testing.T) { // Expect both to be sending FundingLocked. _ = assertFundingMsgSent( t, alice.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) _ = assertFundingMsgSent( t, bob.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) } @@ -4205,14 +4205,14 @@ func TestFundingManagerZeroConf(t *testing.T) { // Assert that Bob's funding_locked message has an AliasScid. bobFundingLocked := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) require.NotNil(t, bobFundingLocked.AliasScid) require.Equal(t, *bobFundingLocked.AliasScid, alias) // Do the same for Alice as well. aliceFundingLocked := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", - ).(*lnwire.FundingLocked) + ).(*lnwire.ChannelReady) require.NotNil(t, aliceFundingLocked.AliasScid) require.Equal(t, *aliceFundingLocked.AliasScid, alias) diff --git a/htlcswitch/link_test.go b/htlcswitch/link_test.go index b58c8a63b..72afa2ebb 100644 --- a/htlcswitch/link_test.go +++ b/htlcswitch/link_test.go @@ -1684,8 +1684,8 @@ func TestChannelLinkSingleHopMessageOrdering(t *testing.T) { {"alice", "bob", &lnwire.ChannelReestablish{}, false}, {"bob", "alice", &lnwire.ChannelReestablish{}, false}, - {"alice", "bob", &lnwire.FundingLocked{}, false}, - {"bob", "alice", &lnwire.FundingLocked{}, false}, + {"alice", "bob", &lnwire.ChannelReady{}, false}, + {"bob", "alice", &lnwire.ChannelReady{}, false}, {"alice", "bob", &lnwire.UpdateAddHTLC{}, false}, {"alice", "bob", &lnwire.CommitSig{}, false}, @@ -3303,8 +3303,8 @@ func TestChannelRetransmission(t *testing.T) { {"alice", "bob", &lnwire.ChannelReestablish{}, false}, {"bob", "alice", &lnwire.ChannelReestablish{}, false}, - {"alice", "bob", &lnwire.FundingLocked{}, false}, - {"bob", "alice", &lnwire.FundingLocked{}, false}, + {"alice", "bob", &lnwire.ChannelReady{}, false}, + {"bob", "alice", &lnwire.ChannelReady{}, false}, // Send payment from Alice to Bob and intercept // the last revocation message, in this case @@ -3343,8 +3343,8 @@ func TestChannelRetransmission(t *testing.T) { {"alice", "bob", &lnwire.ChannelReestablish{}, false}, {"bob", "alice", &lnwire.ChannelReestablish{}, false}, - {"alice", "bob", &lnwire.FundingLocked{}, false}, - {"bob", "alice", &lnwire.FundingLocked{}, false}, + {"alice", "bob", &lnwire.ChannelReady{}, false}, + {"bob", "alice", &lnwire.ChannelReady{}, false}, // Send payment from Alice to Bob and intercept // the last revocation message, in this case @@ -3385,8 +3385,8 @@ func TestChannelRetransmission(t *testing.T) { {"alice", "bob", &lnwire.ChannelReestablish{}, false}, {"bob", "alice", &lnwire.ChannelReestablish{}, false}, - {"alice", "bob", &lnwire.FundingLocked{}, false}, - {"bob", "alice", &lnwire.FundingLocked{}, false}, + {"alice", "bob", &lnwire.ChannelReady{}, false}, + {"bob", "alice", &lnwire.ChannelReady{}, false}, // Attempt make a payment from Alice to Bob, // which is intercepted, emulating the Bob @@ -3399,8 +3399,8 @@ func TestChannelRetransmission(t *testing.T) { {"alice", "bob", &lnwire.ChannelReestablish{}, false}, {"bob", "alice", &lnwire.ChannelReestablish{}, false}, - {"alice", "bob", &lnwire.FundingLocked{}, false}, - {"bob", "alice", &lnwire.FundingLocked{}, false}, + {"alice", "bob", &lnwire.ChannelReady{}, false}, + {"bob", "alice", &lnwire.ChannelReady{}, false}, // After Bob has notified Alice that he didn't // receive updates Alice should re-send them. @@ -3816,8 +3816,8 @@ func TestChannelLinkUpdateCommitFee(t *testing.T) { {"alice", "bob", &lnwire.ChannelReestablish{}, false}, {"bob", "alice", &lnwire.ChannelReestablish{}, false}, - {"alice", "bob", &lnwire.FundingLocked{}, false}, - {"bob", "alice", &lnwire.FundingLocked{}, false}, + {"alice", "bob", &lnwire.ChannelReady{}, false}, + {"bob", "alice", &lnwire.ChannelReady{}, false}, // First fee update. {"alice", "bob", &lnwire.UpdateFee{}, false}, diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go index 866e7d36f..cec170a35 100644 --- a/htlcswitch/mock.go +++ b/htlcswitch/mock.go @@ -627,7 +627,7 @@ func (s *mockServer) readHandler(message lnwire.Message) error { targetChan = msg.ChanID case *lnwire.CommitSig: targetChan = msg.ChanID - case *lnwire.FundingLocked: + case *lnwire.ChannelReady: // Ignore return nil case *lnwire.ChannelReestablish: diff --git a/htlcswitch/test_utils.go b/htlcswitch/test_utils.go index e1bd6783a..c1bfb1f55 100644 --- a/htlcswitch/test_utils.go +++ b/htlcswitch/test_utils.go @@ -495,7 +495,7 @@ func getChanID(msg lnwire.Message) (lnwire.ChannelID, error) { chanID = msg.ChanID case *lnwire.ChannelReestablish: chanID = msg.ChanID - case *lnwire.FundingLocked: + case *lnwire.ChannelReady: chanID = msg.ChanID case *lnwire.UpdateFee: chanID = msg.ChanID diff --git a/lnwire/funding_locked.go b/lnwire/funding_locked.go index fb47356ba..ab741433d 100644 --- a/lnwire/funding_locked.go +++ b/lnwire/funding_locked.go @@ -13,7 +13,7 @@ import ( // blockchain. FundingLocked contains the signatures necessary for the channel // participants to advertise the existence of the channel to the rest of the // network. -type FundingLocked struct { +type ChannelReady struct { // ChanID is the outpoint of the channel's funding transaction. This // can be used to query for the channel in the database. ChanID ChannelID @@ -35,8 +35,8 @@ type FundingLocked struct { // NewFundingLocked creates a new FundingLocked message, populating it with the // necessary IDs and revocation secret. -func NewFundingLocked(cid ChannelID, npcp *btcec.PublicKey) *FundingLocked { - return &FundingLocked{ +func NewFundingLocked(cid ChannelID, npcp *btcec.PublicKey) *ChannelReady { + return &ChannelReady{ ChanID: cid, NextPerCommitmentPoint: npcp, ExtraData: make([]byte, 0), @@ -45,14 +45,14 @@ func NewFundingLocked(cid ChannelID, npcp *btcec.PublicKey) *FundingLocked { // A compile time check to ensure FundingLocked implements the lnwire.Message // interface. -var _ Message = (*FundingLocked)(nil) +var _ Message = (*ChannelReady)(nil) // Decode deserializes the serialized FundingLocked message stored in the // passed io.Reader into the target FundingLocked using the deserialization // rules defined by the passed protocol version. // // This is part of the lnwire.Message interface. -func (c *FundingLocked) Decode(r io.Reader, pver uint32) error { +func (c *ChannelReady) Decode(r io.Reader, pver uint32) error { // Read all the mandatory fields in the message. err := ReadElements(r, &c.ChanID, @@ -85,7 +85,7 @@ func (c *FundingLocked) Decode(r io.Reader, pver uint32) error { // protocol version. // // This is part of the lnwire.Message interface. -func (c *FundingLocked) Encode(w *bytes.Buffer, pver uint32) error { +func (c *ChannelReady) Encode(w *bytes.Buffer, pver uint32) error { if err := WriteChannelID(w, c.ChanID); err != nil { return err } @@ -110,6 +110,6 @@ func (c *FundingLocked) Encode(w *bytes.Buffer, pver uint32) error { // FundingLocked message on the wire. // // This is part of the lnwire.Message interface. -func (c *FundingLocked) MsgType() MessageType { +func (c *ChannelReady) MsgType() MessageType { return MsgFundingLocked } diff --git a/lnwire/lnwire_test.go b/lnwire/lnwire_test.go index 96d0c8ae5..d4b4e7dab 100644 --- a/lnwire/lnwire_test.go +++ b/lnwire/lnwire_test.go @@ -1014,7 +1014,7 @@ func TestLightningWireProtocol(t *testing.T) { }, { msgType: MsgFundingLocked, - scenario: func(m FundingLocked) bool { + scenario: func(m ChannelReady) bool { return mainScenario(&m) }, }, diff --git a/lnwire/message.go b/lnwire/message.go index 2e71173e5..7ededf595 100644 --- a/lnwire/message.go +++ b/lnwire/message.go @@ -191,7 +191,7 @@ func makeEmptyMessage(msgType MessageType) (Message, error) { case MsgFundingSigned: msg = &FundingSigned{} case MsgFundingLocked: - msg = &FundingLocked{} + msg = &ChannelReady{} case MsgShutdown: msg = &Shutdown{} case MsgClosingSigned: diff --git a/lnwire/message_test.go b/lnwire/message_test.go index 090978a74..b016fc35c 100644 --- a/lnwire/message_test.go +++ b/lnwire/message_test.go @@ -442,7 +442,7 @@ func newMsgFundingSigned(t testing.TB, r io.Reader) *lnwire.FundingSigned { return msg } -func newMsgFundingLocked(t testing.TB, r io.Reader) *lnwire.FundingLocked { +func newMsgFundingLocked(t testing.TB, r io.Reader) *lnwire.ChannelReady { t.Helper() var c [32]byte diff --git a/peer/brontide.go b/peer/brontide.go index 9ea85edd1..fda3f01e1 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -1545,7 +1545,7 @@ out: *lnwire.AcceptChannel, *lnwire.FundingCreated, *lnwire.FundingSigned, - *lnwire.FundingLocked: + *lnwire.ChannelReady: p.cfg.FundingManager.ProcessFundingMsg(msg, p) @@ -1794,7 +1794,7 @@ func messageSummary(msg lnwire.Message) string { case *lnwire.FundingSigned: return fmt.Sprintf("chan_id=%v", msg.ChanID) - case *lnwire.FundingLocked: + case *lnwire.ChannelReady: return fmt.Sprintf("chan_id=%v, next_point=%x", msg.ChanID, msg.NextPerCommitmentPoint.SerializeCompressed()) From c8e835891811eb219a1fa5b071f886f551a1b79d Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 16 Mar 2023 04:44:15 +0800 Subject: [PATCH 24/87] channeldb+lnwire: rename `MsgFundingLocked` to `MsgChannelReady` This commit is created by running, ```shell gofmt -d -w -r 'MsgFundingLocked -> MsgChannelReady' . gco master channeldb/migration ``` --- lnwire/funding_locked.go | 2 +- lnwire/fuzz_test.go | 2 +- lnwire/lnwire_test.go | 4 ++-- lnwire/message.go | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lnwire/funding_locked.go b/lnwire/funding_locked.go index ab741433d..e2625f48b 100644 --- a/lnwire/funding_locked.go +++ b/lnwire/funding_locked.go @@ -111,5 +111,5 @@ func (c *ChannelReady) Encode(w *bytes.Buffer, pver uint32) error { // // This is part of the lnwire.Message interface. func (c *ChannelReady) MsgType() MessageType { - return MsgFundingLocked + return MsgChannelReady } diff --git a/lnwire/fuzz_test.go b/lnwire/fuzz_test.go index 34d144c84..bd1995eab 100644 --- a/lnwire/fuzz_test.go +++ b/lnwire/fuzz_test.go @@ -289,7 +289,7 @@ func FuzzFundingCreated(f *testing.F) { func FuzzFundingLocked(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { // Prefix with MsgFundingLocked. - data = prefixWithMsgType(data, MsgFundingLocked) + data = prefixWithMsgType(data, MsgChannelReady) // Pass the message into our general fuzz harness for wire // messages! diff --git a/lnwire/lnwire_test.go b/lnwire/lnwire_test.go index d4b4e7dab..d55b4efda 100644 --- a/lnwire/lnwire_test.go +++ b/lnwire/lnwire_test.go @@ -566,7 +566,7 @@ func TestLightningWireProtocol(t *testing.T) { v[0] = reflect.ValueOf(req) }, - MsgFundingLocked: func(v []reflect.Value, r *rand.Rand) { + MsgChannelReady: func(v []reflect.Value, r *rand.Rand) { var c [32]byte if _, err := r.Read(c[:]); err != nil { @@ -1013,7 +1013,7 @@ func TestLightningWireProtocol(t *testing.T) { }, }, { - msgType: MsgFundingLocked, + msgType: MsgChannelReady, scenario: func(m ChannelReady) bool { return mainScenario(&m) }, diff --git a/lnwire/message.go b/lnwire/message.go index 7ededf595..ad065bb46 100644 --- a/lnwire/message.go +++ b/lnwire/message.go @@ -31,7 +31,7 @@ const ( MsgAcceptChannel = 33 MsgFundingCreated = 34 MsgFundingSigned = 35 - MsgFundingLocked = 36 + MsgChannelReady = 36 MsgShutdown = 38 MsgClosingSigned = 39 MsgUpdateAddHTLC = 128 @@ -88,7 +88,7 @@ func (t MessageType) String() string { return "MsgFundingCreated" case MsgFundingSigned: return "MsgFundingSigned" - case MsgFundingLocked: + case MsgChannelReady: return "FundingLocked" case MsgShutdown: return "Shutdown" @@ -190,7 +190,7 @@ func makeEmptyMessage(msgType MessageType) (Message, error) { msg = &FundingCreated{} case MsgFundingSigned: msg = &FundingSigned{} - case MsgFundingLocked: + case MsgChannelReady: msg = &ChannelReady{} case MsgShutdown: msg = &Shutdown{} From 2dc08a2a7629cd301da387771b3ec101b06f339c Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 16 Mar 2023 04:46:30 +0800 Subject: [PATCH 25/87] multi: rename `NewFundingLocked` to `NewChannelReady` This commit is created by the following command, ```shell gofmt -d -w -r 'NewFundingLocked -> NewChannelReady' . ``` --- funding/manager.go | 4 ++-- htlcswitch/link.go | 2 +- lnwire/funding_locked.go | 2 +- lnwire/lnwire_test.go | 2 +- lnwire/message_test.go | 2 +- peer/brontide.go | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/funding/manager.go b/funding/manager.go index 113a30343..edd56b712 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -2909,7 +2909,7 @@ func (f *Manager) sendFundingLocked(completeChan *channeldb.OpenChannel, if err != nil { return fmt.Errorf("unable to create next revocation: %v", err) } - fundingLockedMsg := lnwire.NewFundingLocked(chanID, nextRevocation) + fundingLockedMsg := lnwire.NewChannelReady(chanID, nextRevocation) // If the channel negotiated the option-scid-alias feature bit, we'll // send a TLV segment that includes an alias the peer can use in their @@ -3517,7 +3517,7 @@ func (f *Manager) handleFundingLocked(peer lnpeer.Peer, return } - fundingLockedMsg := lnwire.NewFundingLocked( + fundingLockedMsg := lnwire.NewChannelReady( chanID, secondPoint, ) fundingLockedMsg.AliasScid = &alias diff --git a/htlcswitch/link.go b/htlcswitch/link.go index b1836c7c7..2ef8d1f93 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -734,7 +734,7 @@ func (l *channelLink) syncChanStates() error { "revocation: %v", err) } - fundingLockedMsg := lnwire.NewFundingLocked( + fundingLockedMsg := lnwire.NewChannelReady( l.ChanID(), nextRevocation, ) diff --git a/lnwire/funding_locked.go b/lnwire/funding_locked.go index e2625f48b..0995f91d3 100644 --- a/lnwire/funding_locked.go +++ b/lnwire/funding_locked.go @@ -35,7 +35,7 @@ type ChannelReady struct { // NewFundingLocked creates a new FundingLocked message, populating it with the // necessary IDs and revocation secret. -func NewFundingLocked(cid ChannelID, npcp *btcec.PublicKey) *ChannelReady { +func NewChannelReady(cid ChannelID, npcp *btcec.PublicKey) *ChannelReady { return &ChannelReady{ ChanID: cid, NextPerCommitmentPoint: npcp, diff --git a/lnwire/lnwire_test.go b/lnwire/lnwire_test.go index d55b4efda..baefa4a6a 100644 --- a/lnwire/lnwire_test.go +++ b/lnwire/lnwire_test.go @@ -580,7 +580,7 @@ func TestLightningWireProtocol(t *testing.T) { return } - req := NewFundingLocked(ChannelID(c), pubKey) + req := NewChannelReady(ChannelID(c), pubKey) v[0] = reflect.ValueOf(*req) }, diff --git a/lnwire/message_test.go b/lnwire/message_test.go index b016fc35c..1d540455f 100644 --- a/lnwire/message_test.go +++ b/lnwire/message_test.go @@ -452,7 +452,7 @@ func newMsgFundingLocked(t testing.TB, r io.Reader) *lnwire.ChannelReady { pubKey := randPubKey(t) - msg := lnwire.NewFundingLocked(lnwire.ChannelID(c), pubKey) + msg := lnwire.NewChannelReady(lnwire.ChannelID(c), pubKey) msg.ExtraData = createExtraData(t, r) return msg diff --git a/peer/brontide.go b/peer/brontide.go index fda3f01e1..7064805f7 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -746,7 +746,7 @@ func (p *Brontide) loadActiveChannels(chans []*channeldb.OpenChannel) ( return nil, err } - fundingLockedMsg := lnwire.NewFundingLocked( + fundingLockedMsg := lnwire.NewChannelReady( chanID, second, ) fundingLockedMsg.AliasScid = &aliasScid From 112dc1faca3a7e4a517684712524177e0d6eab6d Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 16 Mar 2023 04:58:04 +0800 Subject: [PATCH 26/87] funding: rename `FundingLocked` related functions and variables This commit is created by running the following commands, ```shell gofmt -d -w -r 'sendFundingLocked -> sendChannelReady' . gofmt -d -w -r 'handleFundingLockedMtx -> handleChannelReadyMtx' . gofmt -d -w -r 'handleFundingLockedBarriers -> handleChannelReadyBarriers' . gofmt -d -w -r 'receivedFundingLocked -> receivedChannelReady' . gofmt -d -w -r 'handleFundingLocked -> handleChannelReady' . gofmt -d -w -r 'fundingLockedSent -> channelReadySent' . gofmt -d -w -r 'checkPeerFundingLockInterval -> checkPeerChannelReadyInterval' . ``` --- funding/config_integration.go | 2 +- funding/manager.go | 64 +++++++++++++++++------------------ funding/manager_test.go | 12 +++---- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/funding/config_integration.go b/funding/config_integration.go index 06bb6e173..f032a3338 100644 --- a/funding/config_integration.go +++ b/funding/config_integration.go @@ -7,5 +7,5 @@ import "time" func init() { // For itest, we will use a much shorter checking interval here as // local communications are very fast. - checkPeerFundingLockInterval = 10 * time.Millisecond + checkPeerChannelReadyInterval = 10 * time.Millisecond } diff --git a/funding/manager.go b/funding/manager.go index edd56b712..ba43c3ad0 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -45,7 +45,7 @@ var ( // if the message is received. // // NOTE: for itest, this value is changed to 10ms. - checkPeerFundingLockInterval = 1 * time.Second + checkPeerChannelReadyInterval = 1 * time.Second ) // WriteOutpoint writes an outpoint to an io.Writer. This is not the same as @@ -570,8 +570,8 @@ type Manager struct { localDiscoveryMtx sync.Mutex localDiscoverySignals map[lnwire.ChannelID]chan struct{} - handleFundingLockedMtx sync.RWMutex - handleFundingLockedBarriers map[lnwire.ChannelID]struct{} + handleChannelReadyMtx sync.RWMutex + handleChannelReadyBarriers map[lnwire.ChannelID]struct{} quit chan struct{} wg sync.WaitGroup @@ -591,7 +591,7 @@ const ( // fundingLockedSent is the opening state of a channel if the // fundingLocked message has successfully been sent to the other peer, // but we still haven't announced the channel to the network. - fundingLockedSent + channelReadySent // addedToRouterGraph is the opening state of a channel if the // channel has been successfully added to the router graph @@ -604,7 +604,7 @@ func (c channelOpeningState) String() string { switch c { case markedOpen: return "markedOpen" - case fundingLockedSent: + case channelReadySent: return "fundingLocked" case addedToRouterGraph: return "addedToRouterGraph" @@ -617,16 +617,16 @@ func (c channelOpeningState) String() string { // fundingManager. func NewFundingManager(cfg Config) (*Manager, error) { return &Manager{ - cfg: &cfg, - chanIDKey: cfg.TempChanIDSeed, - activeReservations: make(map[serializedPubKey]pendingChannels), - signedReservations: make(map[lnwire.ChannelID][32]byte), - newChanBarriers: make(map[lnwire.ChannelID]chan struct{}), - fundingMsgs: make(chan *fundingMsg, msgBufferSize), - fundingRequests: make(chan *InitFundingMsg, msgBufferSize), - localDiscoverySignals: make(map[lnwire.ChannelID]chan struct{}), - handleFundingLockedBarriers: make(map[lnwire.ChannelID]struct{}), - quit: make(chan struct{}), + cfg: &cfg, + chanIDKey: cfg.TempChanIDSeed, + activeReservations: make(map[serializedPubKey]pendingChannels), + signedReservations: make(map[lnwire.ChannelID][32]byte), + newChanBarriers: make(map[lnwire.ChannelID]chan struct{}), + fundingMsgs: make(chan *fundingMsg, msgBufferSize), + fundingRequests: make(chan *InitFundingMsg, msgBufferSize), + localDiscoverySignals: make(map[lnwire.ChannelID]chan struct{}), + handleChannelReadyBarriers: make(map[lnwire.ChannelID]struct{}), + quit: make(chan struct{}), }, nil } @@ -891,7 +891,7 @@ func (f *Manager) reservationCoordinator() { case *lnwire.ChannelReady: f.wg.Add(1) - go f.handleFundingLocked(fmsg.peer, msg) + go f.handleChannelReady(fmsg.peer, msg) case *lnwire.Warning: f.handleWarningMsg(fmsg.peer, msg) @@ -1002,7 +1002,7 @@ func (f *Manager) stateStep(channel *channeldb.OpenChannel, // The funding transaction was confirmed, but we did not successfully // send the fundingLocked message to the peer, so let's do that now. case markedOpen: - err := f.sendFundingLocked(channel, lnChannel) + err := f.sendChannelReady(channel, lnChannel) if err != nil { return fmt.Errorf("failed sending fundingLocked: %v", err) @@ -1013,7 +1013,7 @@ func (f *Manager) stateStep(channel *channeldb.OpenChannel, // will be moved to the last state (actually deleted from the // database) after the channel is finally announced. err = f.saveChannelOpeningState( - &channel.FundingOutpoint, fundingLockedSent, + &channel.FundingOutpoint, channelReadySent, shortChanID, ) if err != nil { @@ -1028,10 +1028,10 @@ func (f *Manager) stateStep(channel *channeldb.OpenChannel, // fundingLocked was sent to peer, but the channel was not added to the // router graph and the channel announcement was not sent. - case fundingLockedSent: + case channelReadySent: // We must wait until we've received the peer's funding locked // before sending a channel_update according to BOLT#07. - received, err := f.receivedFundingLocked( + received, err := f.receivedChannelReady( channel.IdentityPub, chanID, ) if err != nil { @@ -1044,7 +1044,7 @@ func (f *Manager) stateStep(channel *channeldb.OpenChannel, // to the next iteration of the loop after sleeping for // checkPeerFundingLockInterval. select { - case <-time.After(checkPeerFundingLockInterval): + case <-time.After(checkPeerChannelReadyInterval): case <-f.quit: return ErrFundingManagerShuttingDown } @@ -2893,7 +2893,7 @@ func (f *Manager) handleFundingConfirmation( // sendFundingLocked creates and sends the fundingLocked message. // This should be called after the funding transaction has been confirmed, // and the channelState is 'markedOpen'. -func (f *Manager) sendFundingLocked(completeChan *channeldb.OpenChannel, +func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel, channel *lnwallet.LightningChannel) error { chanID := lnwire.NewChanIDFromOutPoint(&completeChan.FundingOutpoint) @@ -3007,7 +3007,7 @@ func (f *Manager) sendFundingLocked(completeChan *channeldb.OpenChannel, // receivedFundingLocked checks whether or not we've received a FundingLocked // from the remote peer. If we have, RemoteNextRevocation will be set. -func (f *Manager) receivedFundingLocked(node *btcec.PublicKey, +func (f *Manager) receivedChannelReady(node *btcec.PublicKey, chanID lnwire.ChannelID) (bool, error) { // If the funding manager has exited, return an error to stop looping. @@ -3393,7 +3393,7 @@ func (f *Manager) waitForZeroConfChannel(c *channeldb.OpenChannel, // handleFundingLocked finalizes the channel funding process and enables the // channel to enter normal operating mode. -func (f *Manager) handleFundingLocked(peer lnpeer.Peer, +func (f *Manager) handleChannelReady(peer lnpeer.Peer, msg *lnwire.ChannelReady) { defer f.wg.Done() @@ -3403,24 +3403,24 @@ func (f *Manager) handleFundingLocked(peer lnpeer.Peer, // If we are currently in the process of handling a funding locked // message for this channel, ignore. - f.handleFundingLockedMtx.Lock() - _, ok := f.handleFundingLockedBarriers[msg.ChanID] + f.handleChannelReadyMtx.Lock() + _, ok := f.handleChannelReadyBarriers[msg.ChanID] if ok { log.Infof("Already handling fundingLocked for "+ "ChannelID(%v), ignoring.", msg.ChanID) - f.handleFundingLockedMtx.Unlock() + f.handleChannelReadyMtx.Unlock() return } // If not already handling fundingLocked for this channel, set up // barrier, and move on. - f.handleFundingLockedBarriers[msg.ChanID] = struct{}{} - f.handleFundingLockedMtx.Unlock() + f.handleChannelReadyBarriers[msg.ChanID] = struct{}{} + f.handleChannelReadyMtx.Unlock() defer func() { - f.handleFundingLockedMtx.Lock() - delete(f.handleFundingLockedBarriers, msg.ChanID) - f.handleFundingLockedMtx.Unlock() + f.handleChannelReadyMtx.Lock() + delete(f.handleChannelReadyBarriers, msg.ChanID) + f.handleChannelReadyMtx.Unlock() }() f.localDiscoveryMtx.Lock() diff --git a/funding/manager_test.go b/funding/manager_test.go index 0d33e60bb..b7a17171b 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -1055,8 +1055,8 @@ func assertFundingLockedSent(t *testing.T, alice, bob *testNode, t.Helper() - assertDatabaseState(t, alice, fundingOutPoint, fundingLockedSent) - assertDatabaseState(t, bob, fundingOutPoint, fundingLockedSent) + assertDatabaseState(t, alice, fundingOutPoint, channelReadySent) + assertDatabaseState(t, bob, fundingOutPoint, channelReadySent) } func assertAddedToRouterGraph(t *testing.T, alice, bob *testNode, @@ -1685,7 +1685,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) { assertDatabaseState(t, alice, fundingOutPoint, markedOpen) // While Bob successfully sent fundingLocked. - assertDatabaseState(t, bob, fundingOutPoint, fundingLockedSent) + assertDatabaseState(t, bob, fundingOutPoint, channelReadySent) // We now recreate Alice's fundingManager with the correct sendMessage // implementation, and expect it to retry sending the fundingLocked @@ -1711,7 +1711,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) { ).(*lnwire.ChannelReady) // The state should now be fundingLockedSent - assertDatabaseState(t, alice, fundingOutPoint, fundingLockedSent) + assertDatabaseState(t, alice, fundingOutPoint, channelReadySent) // Check that the channel announcements were never sent select { @@ -1842,7 +1842,7 @@ func TestFundingManagerOfflinePeer(t *testing.T) { assertDatabaseState(t, alice, fundingOutPoint, markedOpen) // While Bob successfully sent fundingLocked. - assertDatabaseState(t, bob, fundingOutPoint, fundingLockedSent) + assertDatabaseState(t, bob, fundingOutPoint, channelReadySent) // Alice should be waiting for the server to notify when Bob comes back // online. @@ -1887,7 +1887,7 @@ func TestFundingManagerOfflinePeer(t *testing.T) { ).(*lnwire.ChannelReady) // The state should now be fundingLockedSent - assertDatabaseState(t, alice, fundingOutPoint, fundingLockedSent) + assertDatabaseState(t, alice, fundingOutPoint, channelReadySent) // Exchange the fundingLocked messages. alice.fundingMgr.ProcessFundingMsg(fundingLockedBob, bob) From 539cae19999f8ea639c6ecee0175d340f88e5024 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 16 Mar 2023 05:00:17 +0800 Subject: [PATCH 27/87] multi: rename `fundingLockedMsg` to `channelReadyMsg` This commit is created by running, ```shell gofmt -d -w -r 'fundingLockedMsg -> channelReadyMsg' . ``` --- funding/manager.go | 18 +++++++++--------- htlcswitch/link.go | 6 +++--- peer/brontide.go | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/funding/manager.go b/funding/manager.go index ba43c3ad0..9190a2778 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -2909,7 +2909,7 @@ func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel, if err != nil { return fmt.Errorf("unable to create next revocation: %v", err) } - fundingLockedMsg := lnwire.NewChannelReady(chanID, nextRevocation) + channelReadyMsg := lnwire.NewChannelReady(chanID, nextRevocation) // If the channel negotiated the option-scid-alias feature bit, we'll // send a TLV segment that includes an alias the peer can use in their @@ -2926,7 +2926,7 @@ func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel, // We can use a pointer to aliases since GetAliases returns a // copy of the alias slice. - fundingLockedMsg.AliasScid = &aliases[0] + channelReadyMsg.AliasScid = &aliases[0] } // If the peer has disconnected before we reach this point, we will need @@ -2956,7 +2956,7 @@ func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel, // We could also refresh the channel state instead of checking // whether the feature was negotiated, but this saves us a // database read. - if fundingLockedMsg.AliasScid == nil && localAlias && + if channelReadyMsg.AliasScid == nil && localAlias && remoteAlias { // If an alias was not assigned above and the scid @@ -2983,16 +2983,16 @@ func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel, return err } - fundingLockedMsg.AliasScid = &alias + channelReadyMsg.AliasScid = &alias } else { - fundingLockedMsg.AliasScid = &aliases[0] + channelReadyMsg.AliasScid = &aliases[0] } } log.Infof("Peer(%x) is online, sending FundingLocked "+ "for ChannelID(%v)", peerKey, chanID) - if err := peer.SendMessage(true, fundingLockedMsg); err == nil { + if err := peer.SendMessage(true, channelReadyMsg); err == nil { // Sending succeeded, we can break out and continue the // funding flow. break @@ -3517,12 +3517,12 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, return } - fundingLockedMsg := lnwire.NewChannelReady( + channelReadyMsg := lnwire.NewChannelReady( chanID, secondPoint, ) - fundingLockedMsg.AliasScid = &alias + channelReadyMsg.AliasScid = &alias - err = peer.SendMessage(true, fundingLockedMsg) + err = peer.SendMessage(true, channelReadyMsg) if err != nil { log.Errorf("unable to send funding locked: %v", err) diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 2ef8d1f93..1151286ee 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -734,7 +734,7 @@ func (l *channelLink) syncChanStates() error { "revocation: %v", err) } - fundingLockedMsg := lnwire.NewChannelReady( + channelReadyMsg := lnwire.NewChannelReady( l.ChanID(), nextRevocation, ) @@ -756,10 +756,10 @@ func (l *channelLink) syncChanStates() error { // getAliases returns a copy of the alias slice // so it is ok to use a pointer to the first // entry. - fundingLockedMsg.AliasScid = &aliases[0] + channelReadyMsg.AliasScid = &aliases[0] } - err = l.cfg.Peer.SendMessage(false, fundingLockedMsg) + err = l.cfg.Peer.SendMessage(false, channelReadyMsg) if err != nil { return fmt.Errorf("unable to re-send "+ "FundingLocked: %v", err) diff --git a/peer/brontide.go b/peer/brontide.go index 7064805f7..7e838a62c 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -746,12 +746,12 @@ func (p *Brontide) loadActiveChannels(chans []*channeldb.OpenChannel) ( return nil, err } - fundingLockedMsg := lnwire.NewChannelReady( + channelReadyMsg := lnwire.NewChannelReady( chanID, second, ) - fundingLockedMsg.AliasScid = &aliasScid + channelReadyMsg.AliasScid = &aliasScid - msgs = append(msgs, fundingLockedMsg) + msgs = append(msgs, channelReadyMsg) } // If we've negotiated the option-scid-alias feature From 015446559bf7fbdc9db5c0feb1294049467f1c90 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 16 Mar 2023 05:04:26 +0800 Subject: [PATCH 28/87] funding+lnwire: rename `FundingLocked` related tests This commit is created by running the following commands, ```shell gofmt -d -w -r 'fundingLockedAlice -> channelReadyAlice' . gofmt -d -w -r 'fundingLockedBob -> channelReadyBob' . gofmt -d -w -r 'assertHandleFundingLocked -> assertHandleChannelReady' . gofmt -d -w -r 'assertFundingLockedSent -> assertChannelReadySent' . gofmt -d -w -r 'aliceFundingLocked -> aliceChannelReady' . gofmt -d -w -r 'bobFundingLocked -> bobChannelReady' . gofmt -d -w -r 'FuzzFundingLocked -> FuzzChannelReady' . gofmt -d -w -r 'newMsgFundingLocked -> newMsgChannelReady' . gofmt -d -w -r 'TestFundingManagerReceiveFundingLockedTwice -> TestFundingManagerReceiveChannelReadyTwice' . gofmt -d -w -r 'TestFundingManagerRestartAfterReceivingFundingLocked -> TestFundingManagerRestartAfterReceivingChannelReady' . ``` --- funding/manager_test.go | 132 ++++++++++++++++++++-------------------- lnwire/fuzz_test.go | 2 +- lnwire/message_test.go | 4 +- 3 files changed, 69 insertions(+), 69 deletions(-) diff --git a/funding/manager_test.go b/funding/manager_test.go index b7a17171b..967669a22 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -1050,7 +1050,7 @@ func assertMarkedOpen(t *testing.T, alice, bob *testNode, assertDatabaseState(t, bob, fundingOutPoint, markedOpen) } -func assertFundingLockedSent(t *testing.T, alice, bob *testNode, +func assertChannelReadySent(t *testing.T, alice, bob *testNode, fundingOutPoint *wire.OutPoint) { t.Helper() @@ -1347,7 +1347,7 @@ func assertInitialFwdingPolicyNotFound(t *testing.T, node *testNode, fwdingPolicy) } -func assertHandleFundingLocked(t *testing.T, alice, bob *testNode) { +func assertHandleChannelReady(t *testing.T, alice, bob *testNode) { t.Helper() // They should both send the new channel state to their peer. @@ -1406,25 +1406,25 @@ func TestFundingManagerNormalWorkflow(t *testing.T) { // After the funding transaction is mined, Alice will send // fundingLocked to Bob. - fundingLockedAlice := assertFundingMsgSent( + channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. - fundingLockedBob := assertFundingMsgSent( + channelReadyBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly - assertFundingLockedSent(t, alice, bob, fundingOutPoint) + assertChannelReadySent(t, alice, bob, fundingOutPoint) // Exchange the fundingLocked messages. - alice.fundingMgr.ProcessFundingMsg(fundingLockedBob, bob) - bob.fundingMgr.ProcessFundingMsg(fundingLockedAlice, alice) + alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) + bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) // Check that they notify the breach arbiter and peer about the new // channel. - assertHandleFundingLocked(t, alice, bob) + assertHandleChannelReady(t, alice, bob) // Make sure both fundingManagers send the expected channel // announcements. @@ -1677,7 +1677,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) { } // Bob will send funding locked to Alice. - fundingLockedBob := assertFundingMsgSent( + channelReadyBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) @@ -1706,7 +1706,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) { return errChan } - fundingLockedAlice := assertFundingMsgSent( + channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) @@ -1723,12 +1723,12 @@ func TestFundingManagerRestartBehavior(t *testing.T) { } // Exchange the fundingLocked messages. - alice.fundingMgr.ProcessFundingMsg(fundingLockedBob, bob) - bob.fundingMgr.ProcessFundingMsg(fundingLockedAlice, alice) + alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) + bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) // Check that they notify the breach arbiter and peer about the new // channel. - assertHandleFundingLocked(t, alice, bob) + assertHandleChannelReady(t, alice, bob) // Next up, we check that Alice rebroadcasts the announcement // messages on restart. Bob should as expected send announcements. @@ -1834,7 +1834,7 @@ func TestFundingManagerOfflinePeer(t *testing.T) { } // Bob will send funding locked to Alice - fundingLockedBob := assertFundingMsgSent( + channelReadyBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) @@ -1882,7 +1882,7 @@ func TestFundingManagerOfflinePeer(t *testing.T) { con <- bob // This should make Alice send the fundingLocked. - fundingLockedAlice := assertFundingMsgSent( + channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) @@ -1890,12 +1890,12 @@ func TestFundingManagerOfflinePeer(t *testing.T) { assertDatabaseState(t, alice, fundingOutPoint, channelReadySent) // Exchange the fundingLocked messages. - alice.fundingMgr.ProcessFundingMsg(fundingLockedBob, bob) - bob.fundingMgr.ProcessFundingMsg(fundingLockedAlice, alice) + alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) + bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) // Check that they notify the breach arbiter and peer about the new // channel. - assertHandleFundingLocked(t, alice, bob) + assertHandleChannelReady(t, alice, bob) // Make sure both fundingManagers send the expected channel // announcements. @@ -2275,7 +2275,7 @@ func TestFundingManagerFundingNotTimeoutInitiator(t *testing.T) { // TestFundingManagerReceiveFundingLockedTwice checks that the fundingManager // continues to operate as expected in case we receive a duplicate fundingLocked // message. -func TestFundingManagerReceiveFundingLockedTwice(t *testing.T) { +func TestFundingManagerReceiveChannelReadyTwice(t *testing.T) { t.Parallel() alice, bob := setupFundingManagers(t) @@ -2311,26 +2311,26 @@ func TestFundingManagerReceiveFundingLockedTwice(t *testing.T) { // After the funding transaction is mined, Alice will send // fundingLocked to Bob. - fundingLockedAlice := assertFundingMsgSent( + channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. - fundingLockedBob := assertFundingMsgSent( + channelReadyBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly - assertFundingLockedSent(t, alice, bob, fundingOutPoint) + assertChannelReadySent(t, alice, bob, fundingOutPoint) // Send the fundingLocked message twice to Alice, and once to Bob. - alice.fundingMgr.ProcessFundingMsg(fundingLockedBob, bob) - alice.fundingMgr.ProcessFundingMsg(fundingLockedBob, bob) - bob.fundingMgr.ProcessFundingMsg(fundingLockedAlice, alice) + alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) + alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) + bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) // Check that they notify the breach arbiter and peer about the new // channel. - assertHandleFundingLocked(t, alice, bob) + assertHandleChannelReady(t, alice, bob) // Alice should not send the channel state the second time, as the // second funding locked should just be ignored. @@ -2343,7 +2343,7 @@ func TestFundingManagerReceiveFundingLockedTwice(t *testing.T) { // Another fundingLocked should also be ignored, since Alice should // have updated her database at this point. - alice.fundingMgr.ProcessFundingMsg(fundingLockedBob, bob) + alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) select { case <-alice.newChannels: t.Fatalf("alice sent new channel to peer a second time") @@ -2422,25 +2422,25 @@ func TestFundingManagerRestartAfterChanAnn(t *testing.T) { // After the funding transaction is mined, Alice will send // fundingLocked to Bob. - fundingLockedAlice := assertFundingMsgSent( + channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. - fundingLockedBob := assertFundingMsgSent( + channelReadyBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly - assertFundingLockedSent(t, alice, bob, fundingOutPoint) + assertChannelReadySent(t, alice, bob, fundingOutPoint) // Exchange the fundingLocked messages. - alice.fundingMgr.ProcessFundingMsg(fundingLockedBob, bob) - bob.fundingMgr.ProcessFundingMsg(fundingLockedAlice, alice) + alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) + bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) // Check that they notify the breach arbiter and peer about the new // channel. - assertHandleFundingLocked(t, alice, bob) + assertHandleChannelReady(t, alice, bob) // Make sure both fundingManagers send the expected channel // announcements. @@ -2483,7 +2483,7 @@ func TestFundingManagerRestartAfterChanAnn(t *testing.T) { // TestFundingManagerRestartAfterReceivingFundingLocked checks that the // fundingManager continues to operate as expected after it has received // fundingLocked and then gets restarted. -func TestFundingManagerRestartAfterReceivingFundingLocked(t *testing.T) { +func TestFundingManagerRestartAfterReceivingChannelReady(t *testing.T) { t.Parallel() alice, bob := setupFundingManagers(t) @@ -2519,27 +2519,27 @@ func TestFundingManagerRestartAfterReceivingFundingLocked(t *testing.T) { // After the funding transaction is mined, Alice will send // fundingLocked to Bob. - fundingLockedAlice := assertFundingMsgSent( + channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. - fundingLockedBob := assertFundingMsgSent( + channelReadyBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly - assertFundingLockedSent(t, alice, bob, fundingOutPoint) + assertChannelReadySent(t, alice, bob, fundingOutPoint) // Let Alice immediately get the fundingLocked message. - alice.fundingMgr.ProcessFundingMsg(fundingLockedBob, bob) + alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) // Also let Bob get the fundingLocked message. - bob.fundingMgr.ProcessFundingMsg(fundingLockedAlice, alice) + bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) // Check that they notify the breach arbiter and peer about the new // channel. - assertHandleFundingLocked(t, alice, bob) + assertHandleChannelReady(t, alice, bob) // At this point we restart Alice's fundingManager. recreateAliceFundingManager(t, alice) @@ -2612,25 +2612,25 @@ func TestFundingManagerPrivateChannel(t *testing.T) { // After the funding transaction is mined, Alice will send // fundingLocked to Bob. - fundingLockedAlice := assertFundingMsgSent( + channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. - fundingLockedBob := assertFundingMsgSent( + channelReadyBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly - assertFundingLockedSent(t, alice, bob, fundingOutPoint) + assertChannelReadySent(t, alice, bob, fundingOutPoint) // Exchange the fundingLocked messages. - alice.fundingMgr.ProcessFundingMsg(fundingLockedBob, bob) - bob.fundingMgr.ProcessFundingMsg(fundingLockedAlice, alice) + alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) + bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) // Check that they notify the breach arbiter and peer about the new // channel. - assertHandleFundingLocked(t, alice, bob) + assertHandleChannelReady(t, alice, bob) // Make sure both fundingManagers send the expected channel // announcements. @@ -2735,25 +2735,25 @@ func TestFundingManagerPrivateRestart(t *testing.T) { // After the funding transaction is mined, Alice will send // fundingLocked to Bob. - fundingLockedAlice := assertFundingMsgSent( + channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. - fundingLockedBob := assertFundingMsgSent( + channelReadyBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly - assertFundingLockedSent(t, alice, bob, fundingOutPoint) + assertChannelReadySent(t, alice, bob, fundingOutPoint) // Exchange the fundingLocked messages. - alice.fundingMgr.ProcessFundingMsg(fundingLockedBob, bob) - bob.fundingMgr.ProcessFundingMsg(fundingLockedAlice, alice) + alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) + bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) // Check that they notify the breach arbiter and peer about the new // channel. - assertHandleFundingLocked(t, alice, bob) + assertHandleChannelReady(t, alice, bob) // Make sure both fundingManagers send the expected channel // announcements. @@ -3170,22 +3170,22 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) { // After the funding transaction is mined, Alice will send // fundingLocked to Bob. - fundingLockedAlice := assertFundingMsgSent( + channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. - fundingLockedBob := assertFundingMsgSent( + channelReadyBob := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) // Exchange the fundingLocked messages. - alice.fundingMgr.ProcessFundingMsg(fundingLockedBob, bob) - bob.fundingMgr.ProcessFundingMsg(fundingLockedAlice, alice) + alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) + bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) // Check that they notify the breach arbiter and peer about the new // channel. - assertHandleFundingLocked(t, alice, bob) + assertHandleChannelReady(t, alice, bob) // Make sure both fundingManagers send the expected channel // announcements. @@ -4203,25 +4203,25 @@ func TestFundingManagerZeroConf(t *testing.T) { } // Assert that Bob's funding_locked message has an AliasScid. - bobFundingLocked := assertFundingMsgSent( + bobChannelReady := assertFundingMsgSent( t, bob.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) - require.NotNil(t, bobFundingLocked.AliasScid) - require.Equal(t, *bobFundingLocked.AliasScid, alias) + require.NotNil(t, bobChannelReady.AliasScid) + require.Equal(t, *bobChannelReady.AliasScid, alias) // Do the same for Alice as well. - aliceFundingLocked := assertFundingMsgSent( + aliceChannelReady := assertFundingMsgSent( t, alice.msgChan, "FundingLocked", ).(*lnwire.ChannelReady) - require.NotNil(t, aliceFundingLocked.AliasScid) - require.Equal(t, *aliceFundingLocked.AliasScid, alias) + require.NotNil(t, aliceChannelReady.AliasScid) + require.Equal(t, *aliceChannelReady.AliasScid, alias) // Exchange the funding_locked messages. - alice.fundingMgr.ProcessFundingMsg(bobFundingLocked, bob) - bob.fundingMgr.ProcessFundingMsg(aliceFundingLocked, alice) + alice.fundingMgr.ProcessFundingMsg(bobChannelReady, bob) + bob.fundingMgr.ProcessFundingMsg(aliceChannelReady, alice) // We'll assert that they both create new links. - assertHandleFundingLocked(t, alice, bob) + assertHandleChannelReady(t, alice, bob) // We'll now assert that both sides send ChannelAnnouncement and // ChannelUpdate messages. diff --git a/lnwire/fuzz_test.go b/lnwire/fuzz_test.go index bd1995eab..7e3823773 100644 --- a/lnwire/fuzz_test.go +++ b/lnwire/fuzz_test.go @@ -286,7 +286,7 @@ func FuzzFundingCreated(f *testing.F) { }) } -func FuzzFundingLocked(f *testing.F) { +func FuzzChannelReady(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { // Prefix with MsgFundingLocked. data = prefixWithMsgType(data, MsgChannelReady) diff --git a/lnwire/message_test.go b/lnwire/message_test.go index 1d540455f..f39a88995 100644 --- a/lnwire/message_test.go +++ b/lnwire/message_test.go @@ -268,7 +268,7 @@ func makeAllMessages(t testing.TB, r *rand.Rand) []lnwire.Message { msgAll = append(msgAll, newMsgAcceptChannel(t, r)) msgAll = append(msgAll, newMsgFundingCreated(t, r)) msgAll = append(msgAll, newMsgFundingSigned(t, r)) - msgAll = append(msgAll, newMsgFundingLocked(t, r)) + msgAll = append(msgAll, newMsgChannelReady(t, r)) msgAll = append(msgAll, newMsgShutdown(t, r)) msgAll = append(msgAll, newMsgClosingSigned(t, r)) msgAll = append(msgAll, newMsgUpdateAddHTLC(t, r)) @@ -442,7 +442,7 @@ func newMsgFundingSigned(t testing.TB, r io.Reader) *lnwire.FundingSigned { return msg } -func newMsgFundingLocked(t testing.TB, r io.Reader) *lnwire.ChannelReady { +func newMsgChannelReady(t testing.TB, r io.Reader) *lnwire.ChannelReady { t.Helper() var c [32]byte From f8a8326141cf234b02e345185b1f266f25094a48 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 16 Mar 2023 05:36:58 +0800 Subject: [PATCH 29/87] multi: replace `FundingLocked` and `funding_locked` strings This commit is created by running the following commands, ```shell find . -name "*.go" -exec sed -i '' 's/\"FundingLocked/\"ChannelReady/g' {} \; find . -name "*.go" -exec sed -i '' 's/FundingLocked\"/ChannelReady\"/g' {} \; find . -name "*.go" -exec sed -i '' 's/\ funding_locked/\ channel_ready/g' {} \; ``` --- aliasmgr/aliasmgr.go | 6 ++--- channeldb/channel.go | 2 +- funding/interfaces.go | 6 ++--- funding/manager.go | 18 +++++++-------- funding/manager_test.go | 50 ++++++++++++++++++++--------------------- htlcswitch/link.go | 6 ++--- lnwire/features.go | 4 ++-- lnwire/message.go | 2 +- peer/brontide.go | 8 +++---- 9 files changed, 51 insertions(+), 51 deletions(-) diff --git a/aliasmgr/aliasmgr.go b/aliasmgr/aliasmgr.go index 381476a73..f33eb391e 100644 --- a/aliasmgr/aliasmgr.go +++ b/aliasmgr/aliasmgr.go @@ -38,7 +38,7 @@ var ( lastAliasKey = []byte("last-alias-key") // invoiceAliasBucket is a root-level bucket that stores the alias - // SCIDs that our peers send us in the funding_locked TLV. The keys are + // SCIDs that our peers send us in the channel_ready TLV. The keys are // the ChannelID generated from the FundingOutpoint and the values are // the remote peer's alias SCID. invoiceAliasBucket = []byte("invoice-alias-bucket") @@ -88,7 +88,7 @@ type Manager struct { aliasToBase map[lnwire.ShortChannelID]lnwire.ShortChannelID // peerAlias is a cache for the alias SCIDs that our peers send us in - // the funding_locked TLV. The keys are the ChannelID generated from + // the channel_ready TLV. The keys are the ChannelID generated from // the FundingOutpoint and the values are the remote peer's alias SCID. // The values should match the ones stored in the "invoice-alias-bucket" // bucket. @@ -341,7 +341,7 @@ func (m *Manager) DeleteSixConfs(baseScid lnwire.ShortChannelID) error { } // PutPeerAlias stores the peer's alias SCID once we learn of it in the -// funding_locked message. +// channel_ready message. func (m *Manager) PutPeerAlias(chanID lnwire.ChannelID, alias lnwire.ShortChannelID) error { diff --git a/channeldb/channel.go b/channeldb/channel.go index d71f17047..ed09605ef 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -1345,7 +1345,7 @@ func (c *OpenChannel) MarkBorked() error { } // SecondCommitmentPoint returns the second per-commitment-point for use in the -// funding_locked message. +// channel_ready message. func (c *OpenChannel) SecondCommitmentPoint() (*btcec.PublicKey, error) { c.RLock() defer c.RUnlock() diff --git a/funding/interfaces.go b/funding/interfaces.go index 09270d149..b87705424 100644 --- a/funding/interfaces.go +++ b/funding/interfaces.go @@ -23,15 +23,15 @@ type Controller interface { // aliasHandler is an interface that abstracts the managing of aliases. type aliasHandler interface { // RequestAlias lets the funding manager request a unique SCID alias to - // use in the funding_locked message. + // use in the channel_ready message. RequestAlias() (lnwire.ShortChannelID, error) // PutPeerAlias lets the funding manager store the received alias SCID - // in the funding_locked message. + // in the channel_ready message. PutPeerAlias(lnwire.ChannelID, lnwire.ShortChannelID) error // GetPeerAlias lets the funding manager lookup the received alias SCID - // from the funding_locked message. This is not the same as GetAliases + // from the channel_ready message. This is not the same as GetAliases // which retrieves OUR aliases for a given channel. GetPeerAlias(lnwire.ChannelID) (lnwire.ShortChannelID, error) diff --git a/funding/manager.go b/funding/manager.go index 9190a2778..7faeb098c 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -1022,7 +1022,7 @@ func (f *Manager) stateStep(channel *channeldb.OpenChannel, } log.Debugf("Channel(%v) with ShortChanID %v: successfully "+ - "sent FundingLocked", chanID, shortChanID) + "sent ChannelReady", chanID, shortChanID) return nil @@ -1054,7 +1054,7 @@ func (f *Manager) stateStep(channel *channeldb.OpenChannel, var peerAlias *lnwire.ShortChannelID if channel.IsZeroConf() { - // We'll need to wait until funding_locked has been + // We'll need to wait until channel_ready has been // received and the peer lets us know the alias they // want to use for the channel. With this information, // we can then construct a ChannelUpdate for them. @@ -2963,7 +2963,7 @@ func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel, // alias feature was negotiated, check if we already // have an alias stored in case handleFundingLocked was // called before this. If an alias exists, use that in - // funding_locked. Otherwise, request and store an + // channel_ready. Otherwise, request and store an // alias and use that. aliases := f.cfg.AliasManager.GetAliases( completeChan.ShortChannelID, @@ -2989,7 +2989,7 @@ func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel, } } - log.Infof("Peer(%x) is online, sending FundingLocked "+ + log.Infof("Peer(%x) is online, sending ChannelReady "+ "for ChannelID(%v)", peerKey, chanID) if err := peer.SendMessage(true, channelReadyMsg); err == nil { @@ -3028,7 +3028,7 @@ func (f *Manager) receivedChannelReady(node *btcec.PublicKey, channel, err := f.cfg.FindChannel(node, chanID) if err != nil { log.Errorf("Unable to locate ChannelID(%v) to determine if "+ - "FundingLocked was received", chanID) + "ChannelReady was received", chanID) return false, err } @@ -3397,7 +3397,7 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, msg *lnwire.ChannelReady) { defer f.wg.Done() - log.Debugf("Received FundingLocked for ChannelID(%v) from "+ + log.Debugf("Received ChannelReady for ChannelID(%v) from "+ "peer %x", msg.ChanID, peer.IdentityKey().SerializeCompressed()) @@ -3487,14 +3487,14 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, // If we do not have an alias stored, we'll create one now. // This is only used in the upgrade case where a user toggles // the option-scid-alias feature-bit to on. We'll also send the - // funding_locked message here in case the link is created + // channel_ready message here in case the link is created // before sendFundingLocked is called. aliases := f.cfg.AliasManager.GetAliases( channel.ShortChannelID, ) if len(aliases) == 0 { // No aliases were found so we'll request and store an - // alias and use it in the funding_locked message. + // alias and use it in the channel_ready message. alias, err := f.cfg.AliasManager.RequestAlias() if err != nil { log.Errorf("unable to request alias: %v", err) @@ -3535,7 +3535,7 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, // already processed fundingLocked for this channel, so ignore. This // check is after the alias logic so we store the peer's most recent // alias. The spec requires us to validate that subsequent - // funding_locked messages use the same per commitment point (the + // channel_ready messages use the same per commitment point (the // second), but it is not actually necessary since we'll just end up // ignoring it. We are, however, required to *send* the same per // commitment point, since another pedantic implementation might diff --git a/funding/manager_test.go b/funding/manager_test.go index 967669a22..fe358e673 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -900,7 +900,7 @@ func assertFundingMsgSent(t *testing.T, msgChan chan lnwire.Message, sentMsg, ok = msg.(*lnwire.FundingCreated) case "FundingSigned": sentMsg, ok = msg.(*lnwire.FundingSigned) - case "FundingLocked": + case "ChannelReady": sentMsg, ok = msg.(*lnwire.ChannelReady) case "Error": sentMsg, ok = msg.(*lnwire.Error) @@ -1407,12 +1407,12 @@ func TestFundingManagerNormalWorkflow(t *testing.T) { // After the funding transaction is mined, Alice will send // fundingLocked to Bob. channelReadyAlice := assertFundingMsgSent( - t, alice.msgChan, "FundingLocked", + t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. channelReadyBob := assertFundingMsgSent( - t, bob.msgChan, "FundingLocked", + t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly @@ -1678,7 +1678,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) { // Bob will send funding locked to Alice. channelReadyBob := assertFundingMsgSent( - t, bob.msgChan, "FundingLocked", + t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // Alice should still be markedOpen @@ -1707,7 +1707,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) { } channelReadyAlice := assertFundingMsgSent( - t, alice.msgChan, "FundingLocked", + t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // The state should now be fundingLockedSent @@ -1835,7 +1835,7 @@ func TestFundingManagerOfflinePeer(t *testing.T) { // Bob will send funding locked to Alice channelReadyBob := assertFundingMsgSent( - t, bob.msgChan, "FundingLocked", + t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // Alice should still be markedOpen @@ -1883,7 +1883,7 @@ func TestFundingManagerOfflinePeer(t *testing.T) { // This should make Alice send the fundingLocked. channelReadyAlice := assertFundingMsgSent( - t, alice.msgChan, "FundingLocked", + t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // The state should now be fundingLockedSent @@ -2312,12 +2312,12 @@ func TestFundingManagerReceiveChannelReadyTwice(t *testing.T) { // After the funding transaction is mined, Alice will send // fundingLocked to Bob. channelReadyAlice := assertFundingMsgSent( - t, alice.msgChan, "FundingLocked", + t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. channelReadyBob := assertFundingMsgSent( - t, bob.msgChan, "FundingLocked", + t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly @@ -2423,12 +2423,12 @@ func TestFundingManagerRestartAfterChanAnn(t *testing.T) { // After the funding transaction is mined, Alice will send // fundingLocked to Bob. channelReadyAlice := assertFundingMsgSent( - t, alice.msgChan, "FundingLocked", + t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. channelReadyBob := assertFundingMsgSent( - t, bob.msgChan, "FundingLocked", + t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly @@ -2520,12 +2520,12 @@ func TestFundingManagerRestartAfterReceivingChannelReady(t *testing.T) { // After the funding transaction is mined, Alice will send // fundingLocked to Bob. channelReadyAlice := assertFundingMsgSent( - t, alice.msgChan, "FundingLocked", + t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. channelReadyBob := assertFundingMsgSent( - t, bob.msgChan, "FundingLocked", + t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly @@ -2613,12 +2613,12 @@ func TestFundingManagerPrivateChannel(t *testing.T) { // After the funding transaction is mined, Alice will send // fundingLocked to Bob. channelReadyAlice := assertFundingMsgSent( - t, alice.msgChan, "FundingLocked", + t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. channelReadyBob := assertFundingMsgSent( - t, bob.msgChan, "FundingLocked", + t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly @@ -2736,12 +2736,12 @@ func TestFundingManagerPrivateRestart(t *testing.T) { // After the funding transaction is mined, Alice will send // fundingLocked to Bob. channelReadyAlice := assertFundingMsgSent( - t, alice.msgChan, "FundingLocked", + t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. channelReadyBob := assertFundingMsgSent( - t, bob.msgChan, "FundingLocked", + t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // Check that the state machine is updated accordingly @@ -3171,12 +3171,12 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) { // After the funding transaction is mined, Alice will send // fundingLocked to Bob. channelReadyAlice := assertFundingMsgSent( - t, alice.msgChan, "FundingLocked", + t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // And similarly Bob will send funding locked to Alice. channelReadyBob := assertFundingMsgSent( - t, bob.msgChan, "FundingLocked", + t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) // Exchange the fundingLocked messages. @@ -3488,11 +3488,11 @@ func TestFundingManagerMaxPendingChannels(t *testing.T) { // Expect both to be sending FundingLocked. _ = assertFundingMsgSent( - t, alice.msgChan, "FundingLocked", + t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) _ = assertFundingMsgSent( - t, bob.msgChan, "FundingLocked", + t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) } @@ -4202,21 +4202,21 @@ func TestFundingManagerZeroConf(t *testing.T) { Index: 0, } - // Assert that Bob's funding_locked message has an AliasScid. + // Assert that Bob's channel_ready message has an AliasScid. bobChannelReady := assertFundingMsgSent( - t, bob.msgChan, "FundingLocked", + t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) require.NotNil(t, bobChannelReady.AliasScid) require.Equal(t, *bobChannelReady.AliasScid, alias) // Do the same for Alice as well. aliceChannelReady := assertFundingMsgSent( - t, alice.msgChan, "FundingLocked", + t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) require.NotNil(t, aliceChannelReady.AliasScid) require.Equal(t, *aliceChannelReady.AliasScid, alias) - // Exchange the funding_locked messages. + // Exchange the channel_ready messages. alice.fundingMgr.ProcessFundingMsg(bobChannelReady, bob) bob.fundingMgr.ProcessFundingMsg(aliceChannelReady, alice) diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 1151286ee..20aa90bb7 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -726,7 +726,7 @@ func (l *channelLink) syncChanStates() error { localChanSyncMsg.NextLocalCommitHeight == 1 && !l.channel.IsPending() { - l.log.Infof("resending FundingLocked message to peer") + l.log.Infof("resending ChannelReady message to peer") nextRevocation, err := l.channel.NextRevocationKey() if err != nil { @@ -740,7 +740,7 @@ func (l *channelLink) syncChanStates() error { // For channels that negotiated the option-scid-alias // feature bit, ensure that we send over the alias in - // the funding_locked message. We'll send the first + // the channel_ready message. We'll send the first // alias we find for the channel since it does not // matter which alias we send. We'll error out if no // aliases are found. @@ -762,7 +762,7 @@ func (l *channelLink) syncChanStates() error { err = l.cfg.Peer.SendMessage(false, channelReadyMsg) if err != nil { return fmt.Errorf("unable to re-send "+ - "FundingLocked: %v", err) + "ChannelReady: %v", err) } } diff --git a/lnwire/features.go b/lnwire/features.go index c386fd37b..76dab3b05 100644 --- a/lnwire/features.go +++ b/lnwire/features.go @@ -169,12 +169,12 @@ const ( // ScidAliasRequired is a required feature bit that signals that the // node requires understanding of ShortChannelID aliases in the TLV - // segment of the funding_locked message. + // segment of the channel_ready message. ScidAliasRequired FeatureBit = 46 // ScidAliasOptional is an optional feature bit that signals that the // node understands ShortChannelID aliases in the TLV segment of the - // funding_locked message. + // channel_ready message. ScidAliasOptional FeatureBit = 47 // PaymentMetadataRequired is a required bit that denotes that if an diff --git a/lnwire/message.go b/lnwire/message.go index ad065bb46..02447b806 100644 --- a/lnwire/message.go +++ b/lnwire/message.go @@ -89,7 +89,7 @@ func (t MessageType) String() string { case MsgFundingSigned: return "MsgFundingSigned" case MsgChannelReady: - return "FundingLocked" + return "ChannelReady" case MsgShutdown: return "Shutdown" case MsgClosingSigned: diff --git a/peer/brontide.go b/peer/brontide.go index 7e838a62c..063e82c56 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -717,11 +717,11 @@ func (p *Brontide) loadActiveChannels(chans []*channeldb.OpenChannel) ( // manager are not aware of each other's states and if // we did not do this, we would accept alias channel // updates after 6 confirmations, which would be buggy. - // We'll queue a funding_locked message with the new + // We'll queue a channel_ready message with the new // alias. This should technically be done *after* the // reestablish, but this behavior is pre-existing since // the funding manager may already queue a - // funding_locked before the channel_reestablish. + // channel_ready before the channel_reestablish. if !dbChan.IsPending { aliasScid, err := p.cfg.RequestAlias() if err != nil { @@ -740,7 +740,7 @@ func (p *Brontide) loadActiveChannels(chans []*channeldb.OpenChannel) ( ) // Fetch the second commitment point to send in - // the funding_locked message. + // the channel_ready message. second, err := dbChan.SecondCommitmentPoint() if err != nil { return nil, err @@ -2372,7 +2372,7 @@ out: } p.log.Infof("Processing retransmitted "+ - "FundingLocked for ChannelPoint(%v)", + "ChannelReady for ChannelPoint(%v)", chanPoint) nextRevoke := newChan.RemoteNextRevocation From 6b9217acfcb4aa69c4492c81a14ae4162b9ef5ef Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 16 Mar 2023 05:45:14 +0800 Subject: [PATCH 30/87] multi: replace `FundingLocked` related docs This commit replaces `FundingLocked` found in docs using the following command, ```shell find . -name "*.go" -exec sed -i '' 's/FundingLocked/ChannelReady/g' {} \; find . -name "*.go" -exec sed -i '' 's/FundingLock/ChannelReady/g' {} \; ``` --- channeldb/channel.go | 2 +- funding/manager.go | 22 +++++++++++----------- funding/manager_test.go | 12 ++++++------ htlcswitch/link.go | 2 +- htlcswitch/switch_test.go | 2 +- lntest/README.md | 4 ++-- lnwallet/channel.go | 4 ++-- lnwire/funding_locked.go | 16 ++++++++-------- lnwire/fuzz_test.go | 2 +- netann/chan_status_manager.go | 2 +- 10 files changed, 34 insertions(+), 34 deletions(-) diff --git a/channeldb/channel.go b/channeldb/channel.go index ed09605ef..b731028ee 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -3770,7 +3770,7 @@ func putChanRevocationState(chanBucket kvdb.RwBucket, channel *OpenChannel) erro // TODO(roasbeef): don't keep producer on disk // If the next revocation is present, which is only the case after the - // FundingLocked message has been sent, then we'll write it to disk. + // ChannelReady message has been sent, then we'll write it to disk. if channel.RemoteNextRevocation != nil { err = WriteElements(&b, channel.RemoteNextRevocation) if err != nil { diff --git a/funding/manager.go b/funding/manager.go index 7faeb098c..c43b99830 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -40,8 +40,8 @@ var ( // buffers. byteOrder = binary.BigEndian - // checkPeerFundingLockInterval is used when we are waiting for the - // peer to send us FundingLocked. We will check every 1 second to see + // checkPeerChannelReadyInterval is used when we are waiting for the + // peer to send us ChannelReady. We will check every 1 second to see // if the message is received. // // NOTE: for itest, this value is changed to 10ms. @@ -1040,9 +1040,9 @@ func (f *Manager) stateStep(channel *channeldb.OpenChannel, } if !received { - // We haven't received FundingLocked, so we'll continue + // We haven't received ChannelReady, so we'll continue // to the next iteration of the loop after sleeping for - // checkPeerFundingLockInterval. + // checkPeerChannelReadyInterval. select { case <-time.After(checkPeerChannelReadyInterval): case <-f.quit: @@ -1213,7 +1213,7 @@ func (f *Manager) advancePendingChannelState( f.cfg.NotifyOpenChannelEvent(channel.FundingOutpoint) // Find and close the discoverySignal for this channel such - // that FundingLocked messages will be processed. + // that ChannelReady messages will be processed. chanID := lnwire.NewChanIDFromOutPoint( &channel.FundingOutpoint, ) @@ -2890,7 +2890,7 @@ func (f *Manager) handleFundingConfirmation( return nil } -// sendFundingLocked creates and sends the fundingLocked message. +// sendChannelReady creates and sends the fundingLocked message. // This should be called after the funding transaction has been confirmed, // and the channelState is 'markedOpen'. func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel, @@ -2961,7 +2961,7 @@ func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel, // If an alias was not assigned above and the scid // alias feature was negotiated, check if we already - // have an alias stored in case handleFundingLocked was + // have an alias stored in case handleChannelReady was // called before this. If an alias exists, use that in // channel_ready. Otherwise, request and store an // alias and use that. @@ -3005,7 +3005,7 @@ func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel, return nil } -// receivedFundingLocked checks whether or not we've received a FundingLocked +// receivedChannelReady checks whether or not we've received a ChannelReady // from the remote peer. If we have, RemoteNextRevocation will be set. func (f *Manager) receivedChannelReady(node *btcec.PublicKey, chanID lnwire.ChannelID) (bool, error) { @@ -3391,7 +3391,7 @@ func (f *Manager) waitForZeroConfChannel(c *channeldb.OpenChannel, return nil } -// handleFundingLocked finalizes the channel funding process and enables the +// handleChannelReady finalizes the channel funding process and enables the // channel to enter normal operating mode. func (f *Manager) handleChannelReady(peer lnpeer.Peer, msg *lnwire.ChannelReady) { @@ -3464,7 +3464,7 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, // during invoice creation. In the zero-conf case, it is also used to // provide a ChannelUpdate to the remote peer. This is done before the // call to InsertNextRevocation in case the call to PutPeerAlias fails. - // If it were to fail on the first call to handleFundingLocked, we + // If it were to fail on the first call to handleChannelReady, we // wouldn't want the channel to be usable yet. if channel.NegotiatedAliasFeature() { // If the AliasScid field is nil, we must fail out. We will @@ -3488,7 +3488,7 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, // This is only used in the upgrade case where a user toggles // the option-scid-alias feature-bit to on. We'll also send the // channel_ready message here in case the link is created - // before sendFundingLocked is called. + // before sendChannelReady is called. aliases := f.cfg.AliasManager.GetAliases( channel.ShortChannelID, ) diff --git a/funding/manager_test.go b/funding/manager_test.go index fe358e673..8779dd7b4 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -1082,7 +1082,7 @@ func assertChannelAnnouncements(t *testing.T, alice, bob *testNode, t.Helper() - // After the FundingLocked message is sent, Alice and Bob will each send + // After the ChannelReady message is sent, Alice and Bob will each send // the following messages to their gossiper: // 1) ChannelAnnouncement // 2) ChannelUpdate @@ -1222,7 +1222,7 @@ func assertChannelAnnouncements(t *testing.T, alice, bob *testNode, func assertAnnouncementSignatures(t *testing.T, alice, bob *testNode) { t.Helper() - // After the FundingLocked message is sent and six confirmations have + // After the ChannelReady message is sent and six confirmations have // been reached, the channel will be announced to the greater network // by having the nodes exchange announcement signatures. // Two distinct messages will be sent: @@ -1868,7 +1868,7 @@ func TestFundingManagerOfflinePeer(t *testing.T) { } // Before sending on the con chan, update Alice's NotifyWhenOnline - // function so that the next invocation in receivedFundingLocked will + // function so that the next invocation in receivedChannelReady will // use this new function. alice.fundingMgr.cfg.NotifyWhenOnline = func(peer [33]byte, connected chan<- lnpeer.Peer) { @@ -2272,7 +2272,7 @@ func TestFundingManagerFundingNotTimeoutInitiator(t *testing.T) { assertNumPendingChannelsBecomes(t, bob, 0) } -// TestFundingManagerReceiveFundingLockedTwice checks that the fundingManager +// TestFundingManagerReceiveChannelReadyTwice checks that the fundingManager // continues to operate as expected in case we receive a duplicate fundingLocked // message. func TestFundingManagerReceiveChannelReadyTwice(t *testing.T) { @@ -2480,7 +2480,7 @@ func TestFundingManagerRestartAfterChanAnn(t *testing.T) { assertNoFwdingPolicy(t, alice, bob, fundingOutPoint) } -// TestFundingManagerRestartAfterReceivingFundingLocked checks that the +// TestFundingManagerRestartAfterReceivingChannelReady checks that the // fundingManager continues to operate as expected after it has received // fundingLocked and then gets restarted. func TestFundingManagerRestartAfterReceivingChannelReady(t *testing.T) { @@ -3486,7 +3486,7 @@ func TestFundingManagerMaxPendingChannels(t *testing.T) { Tx: txs[i], } - // Expect both to be sending FundingLocked. + // Expect both to be sending ChannelReady. _ = assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 20aa90bb7..2b158d7dc 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -721,7 +721,7 @@ func (l *channelLink) syncChanStates() error { // done any state updates yet, then we'll retransmit the // funding locked message first. We do this, as at this point // we can't be sure if they've really received the - // FundingLocked message. + // ChannelReady message. if remoteChanSyncMsg.NextLocalCommitHeight == 1 && localChanSyncMsg.NextLocalCommitHeight == 1 && !l.channel.IsPending() { diff --git a/htlcswitch/switch_test.go b/htlcswitch/switch_test.go index b1e134954..099fdb8f6 100644 --- a/htlcswitch/switch_test.go +++ b/htlcswitch/switch_test.go @@ -82,7 +82,7 @@ func TestSwitchAddDuplicateLink(t *testing.T) { // TestSwitchHasActiveLink tests the behavior of HasActiveLink, and asserts that // it only returns true if a link's short channel id has confirmed (meaning the // channel is no longer pending) and it's EligibleToForward method returns true, -// i.e. it has received FundingLocked from the remote peer. +// i.e. it has received ChannelReady from the remote peer. func TestSwitchHasActiveLink(t *testing.T) { t.Parallel() diff --git a/lntest/README.md b/lntest/README.md index be28b218f..5752031ec 100644 --- a/lntest/README.md +++ b/lntest/README.md @@ -101,8 +101,8 @@ the real-world has. Aside from that, `lnd` has several places that use different code, which is triggered by the build flag `integration`, to speed up the tests. They are summarized as followings, -1. `funding.checkPeerFundingLockInterval`, which is used when we wait for the - peer to send us `FundingLocked`. This value is 1 second in `lnd`, and 10 +1. `funding.checkPeerChannelReadyInterval`, which is used when we wait for the + peer to send us `ChannelReady`. This value is 1 second in `lnd`, and 10 milliseconds in `lntest`. 2. `lncfg.ProtocolOptions`, which is used to specify protocol flags. In `lnd`, anchor and script enforced lease are enabled by default, while in `lntest`, diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 97b7ac44d..d715d5ed6 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -4063,7 +4063,7 @@ func (lc *LightningChannel) ProcessChanSyncMsg( // If we get a failure due to not knowing their next // point, then this is fine as they'll either send - // FundingLocked, or revoke their next state to allow + // ChannelReady, or revoke their next state to allow // us to continue forwards. case err == ErrNoWindow: @@ -7220,7 +7220,7 @@ func (lc *LightningChannel) generateRevocation(height uint64) (*lnwire.RevokeAnd // Along with this revocation, we'll also send the _next_ commitment // point that the remote party should use to create our next commitment // transaction. We use a +2 here as we already gave them a look ahead - // of size one after the FundingLocked message was sent: + // of size one after the ChannelReady message was sent: // // 0: current revocation, 1: their "next" revocation, 2: this revocation // diff --git a/lnwire/funding_locked.go b/lnwire/funding_locked.go index 0995f91d3..9027997de 100644 --- a/lnwire/funding_locked.go +++ b/lnwire/funding_locked.go @@ -8,9 +8,9 @@ import ( "github.com/lightningnetwork/lnd/tlv" ) -// FundingLocked is the message that both parties to a new channel creation +// ChannelReady is the message that both parties to a new channel creation // send once they have observed the funding transaction being confirmed on the -// blockchain. FundingLocked contains the signatures necessary for the channel +// blockchain. ChannelReady contains the signatures necessary for the channel // participants to advertise the existence of the channel to the rest of the // network. type ChannelReady struct { @@ -33,7 +33,7 @@ type ChannelReady struct { ExtraData ExtraOpaqueData } -// NewFundingLocked creates a new FundingLocked message, populating it with the +// NewChannelReady creates a new ChannelReady message, populating it with the // necessary IDs and revocation secret. func NewChannelReady(cid ChannelID, npcp *btcec.PublicKey) *ChannelReady { return &ChannelReady{ @@ -43,12 +43,12 @@ func NewChannelReady(cid ChannelID, npcp *btcec.PublicKey) *ChannelReady { } } -// A compile time check to ensure FundingLocked implements the lnwire.Message +// A compile time check to ensure ChannelReady implements the lnwire.Message // interface. var _ Message = (*ChannelReady)(nil) -// Decode deserializes the serialized FundingLocked message stored in the -// passed io.Reader into the target FundingLocked using the deserialization +// Decode deserializes the serialized ChannelReady message stored in the +// passed io.Reader into the target ChannelReady using the deserialization // rules defined by the passed protocol version. // // This is part of the lnwire.Message interface. @@ -80,7 +80,7 @@ func (c *ChannelReady) Decode(r io.Reader, pver uint32) error { return nil } -// Encode serializes the target FundingLocked message into the passed io.Writer +// Encode serializes the target ChannelReady message into the passed io.Writer // implementation. Serialization will observe the rules defined by the passed // protocol version. // @@ -107,7 +107,7 @@ func (c *ChannelReady) Encode(w *bytes.Buffer, pver uint32) error { } // MsgType returns the uint32 code which uniquely identifies this message as a -// FundingLocked message on the wire. +// ChannelReady message on the wire. // // This is part of the lnwire.Message interface. func (c *ChannelReady) MsgType() MessageType { diff --git a/lnwire/fuzz_test.go b/lnwire/fuzz_test.go index 7e3823773..f578663a3 100644 --- a/lnwire/fuzz_test.go +++ b/lnwire/fuzz_test.go @@ -288,7 +288,7 @@ func FuzzFundingCreated(f *testing.F) { func FuzzChannelReady(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { - // Prefix with MsgFundingLocked. + // Prefix with MsgChannelReady. data = prefixWithMsgType(data, MsgChannelReady) // Pass the message into our general fuzz harness for wire diff --git a/netann/chan_status_manager.go b/netann/chan_status_manager.go index 8f29888e5..8340c202c 100644 --- a/netann/chan_status_manager.go +++ b/netann/chan_status_manager.go @@ -54,7 +54,7 @@ type ChanStatusConfig struct { // 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 - // FundingLocked, and the remote peer is online. + // ChannelReady, and the remote peer is online. IsChannelActive func(lnwire.ChannelID) bool // ApplyChannelUpdate processes new ChannelUpdates signed by our node by From 465285efb81a5788818df71ceaec717a5aeca77a Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 16 Mar 2023 05:52:35 +0800 Subject: [PATCH 31/87] funding: replace `fundingLocked` with `channelReady` --- funding/manager.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/funding/manager.go b/funding/manager.go index c43b99830..fa6833e4f 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -605,7 +605,7 @@ func (c channelOpeningState) String() string { case markedOpen: return "markedOpen" case channelReadySent: - return "fundingLocked" + return "channelReady" case addedToRouterGraph: return "addedToRouterGraph" default: @@ -1004,7 +1004,7 @@ func (f *Manager) stateStep(channel *channeldb.OpenChannel, case markedOpen: err := f.sendChannelReady(channel, lnChannel) if err != nil { - return fmt.Errorf("failed sending fundingLocked: %v", + return fmt.Errorf("failed sending channelReady: %v", err) } @@ -1018,7 +1018,7 @@ func (f *Manager) stateStep(channel *channeldb.OpenChannel, ) if err != nil { return fmt.Errorf("error setting channel state to"+ - " fundingLockedSent: %v", err) + " channelReadySent: %v", err) } log.Debugf("Channel(%v) with ShortChanID %v: successfully "+ @@ -2998,7 +2998,7 @@ func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel, break } - log.Warnf("Unable to send fundingLocked to peer %x: %v. "+ + log.Warnf("Unable to send channelReady to peer %x: %v. "+ "Will retry when online", peerKey, err) } @@ -3406,7 +3406,7 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, f.handleChannelReadyMtx.Lock() _, ok := f.handleChannelReadyBarriers[msg.ChanID] if ok { - log.Infof("Already handling fundingLocked for "+ + log.Infof("Already handling channelReady for "+ "ChannelID(%v), ignoring.", msg.ChanID) f.handleChannelReadyMtx.Unlock() return @@ -3541,7 +3541,7 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, // commitment point, since another pedantic implementation might // verify it. if channel.RemoteNextRevocation != nil { - log.Infof("Received duplicate fundingLocked for "+ + log.Infof("Received duplicate channelReady for "+ "ChannelID(%v), ignoring.", chanID) return } From d4ad5f362f4b8e811856aeffe5981b3c43fbac75 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 16 Mar 2023 05:55:02 +0800 Subject: [PATCH 32/87] funding: replace `fundingLocked` found in docs This commit is created by running, ```shell find . -name "*.go" -exec sed -i '' 's/fundingLocked/channelReady/g' {} \; ``` --- funding/manager.go | 34 ++++++++++----------- funding/manager_test.go | 68 ++++++++++++++++++++--------------------- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/funding/manager.go b/funding/manager.go index fa6833e4f..05b3e2bcb 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -377,7 +377,7 @@ type Config struct { // NotifyWhenOnline allows the FundingManager to register with a // subsystem that will notify it when the peer comes online. This is - // used when sending the fundingLocked message, since it MUST be + // used when sending the channelReady message, since it MUST be // delivered after the funding transaction is confirmed. // // NOTE: The peerChan channel must be buffered. @@ -584,18 +584,18 @@ type channelOpeningState uint8 const ( // markedOpen is the opening state of a channel if the funding - // transaction is confirmed on-chain, but fundingLocked is not yet + // transaction is confirmed on-chain, but channelReady is not yet // successfully sent to the other peer. markedOpen channelOpeningState = iota - // fundingLockedSent is the opening state of a channel if the - // fundingLocked message has successfully been sent to the other peer, + // channelReadySent is the opening state of a channel if the + // channelReady message has successfully been sent to the other peer, // but we still haven't announced the channel to the network. channelReadySent // addedToRouterGraph is the opening state of a channel if the // channel has been successfully added to the router graph - // immediately after the fundingLocked message has been sent, but + // immediately after the channelReady message has been sent, but // we still haven't announced the channel to the network. addedToRouterGraph ) @@ -1000,7 +1000,7 @@ func (f *Manager) stateStep(channel *channeldb.OpenChannel, switch channelState { // The funding transaction was confirmed, but we did not successfully - // send the fundingLocked message to the peer, so let's do that now. + // send the channelReady message to the peer, so let's do that now. case markedOpen: err := f.sendChannelReady(channel, lnChannel) if err != nil { @@ -1008,7 +1008,7 @@ func (f *Manager) stateStep(channel *channeldb.OpenChannel, err) } - // As the fundingLocked message is now sent to the peer, the + // As the channelReady message is now sent to the peer, the // 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. @@ -1026,7 +1026,7 @@ func (f *Manager) stateStep(channel *channeldb.OpenChannel, return nil - // fundingLocked was sent to peer, but the channel was not added to the + // channelReady was sent to peer, but the channel was not added to the // router graph and the channel announcement was not sent. case channelReadySent: // We must wait until we've received the peer's funding locked @@ -2890,7 +2890,7 @@ func (f *Manager) handleFundingConfirmation( return nil } -// sendChannelReady creates and sends the fundingLocked message. +// sendChannelReady creates and sends the channelReady message. // This should be called after the funding transaction has been confirmed, // and the channelState is 'markedOpen'. func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel, @@ -2930,15 +2930,15 @@ func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel, } // If the peer has disconnected before we reach this point, we will need - // to wait for him to come back online before sending the fundingLocked - // message. This is special for fundingLocked, since failing to send any + // to wait for him to come back online before sending the channelReady + // message. This is special for channelReady, since failing to send any // of the previous messages in the funding flow just cancels the flow. // But now the funding transaction is confirmed, the channel is open - // and we have to make sure the peer gets the fundingLocked message when + // and we have to make sure the peer gets the channelReady message when // it comes back online. This is also crucial during restart of lnd, - // where we might try to resend the fundingLocked message before the + // where we might try to resend the channelReady message before the // server has had the time to connect to the peer. We keep trying to - // send fundingLocked until we succeed, or the fundingManager is shut + // send channelReady until we succeed, or the fundingManager is shut // down. for { peer, err := f.waitForPeerOnline(completeChan.IdentityPub) @@ -3140,7 +3140,7 @@ func (f *Manager) addToRouterGraph(completeChan *channeldb.OpenChannel, } // annAfterSixConfs broadcasts the necessary channel announcement messages to -// the network after 6 confs. Should be called after the fundingLocked message +// the network after 6 confs. Should be called after the channelReady message // is sent and the channel is added to the router graph (channelState is // 'addedToRouterGraph') and the channel is ready to be used. This is the last // step in the channel opening process, and the opening state will be deleted @@ -3412,7 +3412,7 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, return } - // If not already handling fundingLocked for this channel, set up + // If not already handling channelReady for this channel, set up // barrier, and move on. f.handleChannelReadyBarriers[msg.ChanID] = struct{}{} f.handleChannelReadyMtx.Unlock() @@ -3532,7 +3532,7 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, } // If the RemoteNextRevocation is non-nil, it means that we have - // already processed fundingLocked for this channel, so ignore. This + // already processed channelReady for this channel, so ignore. This // check is after the alias logic so we store the peer's most recent // alias. The spec requires us to validate that subsequent // channel_ready messages use the same per commitment point (the diff --git a/funding/manager_test.go b/funding/manager_test.go index 8779dd7b4..15ff462ac 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -1405,7 +1405,7 @@ func TestFundingManagerNormalWorkflow(t *testing.T) { assertMarkedOpen(t, alice, bob, fundingOutPoint) // After the funding transaction is mined, Alice will send - // fundingLocked to Bob. + // channelReady to Bob. channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) @@ -1418,7 +1418,7 @@ func TestFundingManagerNormalWorkflow(t *testing.T) { // Check that the state machine is updated accordingly assertChannelReadySent(t, alice, bob, fundingOutPoint) - // Exchange the fundingLocked messages. + // Exchange the channelReady messages. alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) @@ -1635,7 +1635,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) { ) // After the funding transaction gets mined, both nodes will send the - // fundingLocked message to the other peer. If the funding node fails + // channelReady message to the other peer. If the funding node fails // before this message has been successfully sent, it should retry // sending it on restart. We mimic this behavior by letting the // SendToPeer method return an error, as if the message was not @@ -1666,7 +1666,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) { assertMarkedOpen(t, alice, bob, fundingOutPoint) // After the funding transaction was mined, Bob should have successfully - // sent the fundingLocked message, while Alice failed sending it. In + // sent the channelReady message, while Alice failed sending it. In // Alice's case this means that there should be no messages for Bob, and // the channel should still be in state 'markedOpen' select { @@ -1684,11 +1684,11 @@ func TestFundingManagerRestartBehavior(t *testing.T) { // Alice should still be markedOpen assertDatabaseState(t, alice, fundingOutPoint, markedOpen) - // While Bob successfully sent fundingLocked. + // While Bob successfully sent channelReady. assertDatabaseState(t, bob, fundingOutPoint, channelReadySent) // We now recreate Alice's fundingManager with the correct sendMessage - // implementation, and expect it to retry sending the fundingLocked + // implementation, and expect it to retry sending the channelReady // message. We'll explicitly shut down Alice's funding manager to // prevent a race when overriding the sendMessage implementation. if err := alice.fundingMgr.Stop(); err != nil { @@ -1710,7 +1710,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) { t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) - // The state should now be fundingLockedSent + // The state should now be channelReadySent assertDatabaseState(t, alice, fundingOutPoint, channelReadySent) // Check that the channel announcements were never sent @@ -1722,7 +1722,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) { // Expected } - // Exchange the fundingLocked messages. + // Exchange the channelReady messages. alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) @@ -1771,7 +1771,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) { // TestFundingManagerOfflinePeer checks that the fundingManager waits for the // server to notify when the peer comes online, in case sending the -// fundingLocked message fails the first time. +// channelReady message fails the first time. func TestFundingManagerOfflinePeer(t *testing.T) { t.Parallel() @@ -1791,8 +1791,8 @@ func TestFundingManagerOfflinePeer(t *testing.T) { ) // After the funding transaction gets mined, both nodes will send the - // fundingLocked message to the other peer. If the funding node fails - // to send the fundingLocked message to the peer, it should wait for + // channelReady message to the other peer. If the funding node fails + // to send the channelReady message to the peer, it should wait for // the server to notify it that the peer is back online, and try again. // We'll save the current implementation of sendMessage to restore the // original behavior later on. @@ -1823,7 +1823,7 @@ func TestFundingManagerOfflinePeer(t *testing.T) { assertMarkedOpen(t, alice, bob, fundingOutPoint) // After the funding transaction was mined, Bob should have successfully - // sent the fundingLocked message, while Alice failed sending it. In + // sent the channelReady message, while Alice failed sending it. In // Alice's case this means that there should be no messages for Bob, and // the channel should still be in state 'markedOpen' select { @@ -1841,7 +1841,7 @@ func TestFundingManagerOfflinePeer(t *testing.T) { // Alice should still be markedOpen assertDatabaseState(t, alice, fundingOutPoint, markedOpen) - // While Bob successfully sent fundingLocked. + // While Bob successfully sent channelReady. assertDatabaseState(t, bob, fundingOutPoint, channelReadySent) // Alice should be waiting for the server to notify when Bob comes back @@ -1881,15 +1881,15 @@ func TestFundingManagerOfflinePeer(t *testing.T) { bob.sendMessage = workingSendMessage con <- bob - // This should make Alice send the fundingLocked. + // This should make Alice send the channelReady. channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) - // The state should now be fundingLockedSent + // The state should now be channelReadySent assertDatabaseState(t, alice, fundingOutPoint, channelReadySent) - // Exchange the fundingLocked messages. + // Exchange the channelReady messages. alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) @@ -2273,7 +2273,7 @@ func TestFundingManagerFundingNotTimeoutInitiator(t *testing.T) { } // TestFundingManagerReceiveChannelReadyTwice checks that the fundingManager -// continues to operate as expected in case we receive a duplicate fundingLocked +// continues to operate as expected in case we receive a duplicate channelReady // message. func TestFundingManagerReceiveChannelReadyTwice(t *testing.T) { t.Parallel() @@ -2310,7 +2310,7 @@ func TestFundingManagerReceiveChannelReadyTwice(t *testing.T) { assertMarkedOpen(t, alice, bob, fundingOutPoint) // After the funding transaction is mined, Alice will send - // fundingLocked to Bob. + // channelReady to Bob. channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) @@ -2323,7 +2323,7 @@ func TestFundingManagerReceiveChannelReadyTwice(t *testing.T) { // Check that the state machine is updated accordingly assertChannelReadySent(t, alice, bob, fundingOutPoint) - // Send the fundingLocked message twice to Alice, and once to Bob. + // Send the channelReady message twice to Alice, and once to Bob. alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) @@ -2341,7 +2341,7 @@ func TestFundingManagerReceiveChannelReadyTwice(t *testing.T) { // Expected } - // Another fundingLocked should also be ignored, since Alice should + // Another channelReady should also be ignored, since Alice should // have updated her database at this point. alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) select { @@ -2384,7 +2384,7 @@ func TestFundingManagerReceiveChannelReadyTwice(t *testing.T) { } // TestFundingManagerRestartAfterChanAnn checks that the fundingManager properly -// handles receiving a fundingLocked after the its own fundingLocked and channel +// handles receiving a channelReady after the its own channelReady and channel // announcement is sent and gets restarted. func TestFundingManagerRestartAfterChanAnn(t *testing.T) { t.Parallel() @@ -2421,7 +2421,7 @@ func TestFundingManagerRestartAfterChanAnn(t *testing.T) { assertMarkedOpen(t, alice, bob, fundingOutPoint) // After the funding transaction is mined, Alice will send - // fundingLocked to Bob. + // channelReady to Bob. channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) @@ -2434,7 +2434,7 @@ func TestFundingManagerRestartAfterChanAnn(t *testing.T) { // Check that the state machine is updated accordingly assertChannelReadySent(t, alice, bob, fundingOutPoint) - // Exchange the fundingLocked messages. + // Exchange the channelReady messages. alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) @@ -2454,7 +2454,7 @@ func TestFundingManagerRestartAfterChanAnn(t *testing.T) { waitForOpenUpdate(t, updateChan) // At this point we restart Alice's fundingManager, before she receives - // the fundingLocked message. After restart, she will receive it, and + // the channelReady message. After restart, she will receive it, and // we expect her to be able to handle it correctly. recreateAliceFundingManager(t, alice) @@ -2482,7 +2482,7 @@ func TestFundingManagerRestartAfterChanAnn(t *testing.T) { // TestFundingManagerRestartAfterReceivingChannelReady checks that the // fundingManager continues to operate as expected after it has received -// fundingLocked and then gets restarted. +// channelReady and then gets restarted. func TestFundingManagerRestartAfterReceivingChannelReady(t *testing.T) { t.Parallel() @@ -2518,7 +2518,7 @@ func TestFundingManagerRestartAfterReceivingChannelReady(t *testing.T) { assertMarkedOpen(t, alice, bob, fundingOutPoint) // After the funding transaction is mined, Alice will send - // fundingLocked to Bob. + // channelReady to Bob. channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) @@ -2531,10 +2531,10 @@ func TestFundingManagerRestartAfterReceivingChannelReady(t *testing.T) { // Check that the state machine is updated accordingly assertChannelReadySent(t, alice, bob, fundingOutPoint) - // Let Alice immediately get the fundingLocked message. + // Let Alice immediately get the channelReady message. alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) - // Also let Bob get the fundingLocked message. + // Also let Bob get the channelReady message. bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) // Check that they notify the breach arbiter and peer about the new @@ -2611,7 +2611,7 @@ func TestFundingManagerPrivateChannel(t *testing.T) { assertMarkedOpen(t, alice, bob, fundingOutPoint) // After the funding transaction is mined, Alice will send - // fundingLocked to Bob. + // channelReady to Bob. channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) @@ -2624,7 +2624,7 @@ func TestFundingManagerPrivateChannel(t *testing.T) { // Check that the state machine is updated accordingly assertChannelReadySent(t, alice, bob, fundingOutPoint) - // Exchange the fundingLocked messages. + // Exchange the channelReady messages. alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) @@ -2734,7 +2734,7 @@ func TestFundingManagerPrivateRestart(t *testing.T) { assertMarkedOpen(t, alice, bob, fundingOutPoint) // After the funding transaction is mined, Alice will send - // fundingLocked to Bob. + // channelReady to Bob. channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) @@ -2747,7 +2747,7 @@ func TestFundingManagerPrivateRestart(t *testing.T) { // Check that the state machine is updated accordingly assertChannelReadySent(t, alice, bob, fundingOutPoint) - // Exchange the fundingLocked messages. + // Exchange the channelReady messages. alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) @@ -3169,7 +3169,7 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) { } // After the funding transaction is mined, Alice will send - // fundingLocked to Bob. + // channelReady to Bob. channelReadyAlice := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) @@ -3179,7 +3179,7 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) { t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) - // Exchange the fundingLocked messages. + // Exchange the channelReady messages. alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) bob.fundingMgr.ProcessFundingMsg(channelReadyAlice, alice) From dc3f83c670ca1db90fabfb3270f41d378473de00 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 16 Mar 2023 06:04:27 +0800 Subject: [PATCH 33/87] funding+lnwire: rename and fix make lint Fix linter and rename `funding_locked.go` to `channel_ready.go` --- funding/manager.go | 34 +++++++---- funding/manager_test.go | 60 ++++++++++++------- .../{funding_locked.go => channel_ready.go} | 0 lnwire/lnwire_test.go | 1 - 4 files changed, 64 insertions(+), 31 deletions(-) rename lnwire/{funding_locked.go => channel_ready.go} (100%) diff --git a/funding/manager.go b/funding/manager.go index 05b3e2bcb..83c9a1d21 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -617,16 +617,30 @@ func (c channelOpeningState) String() string { // fundingManager. func NewFundingManager(cfg Config) (*Manager, error) { return &Manager{ - cfg: &cfg, - chanIDKey: cfg.TempChanIDSeed, - activeReservations: make(map[serializedPubKey]pendingChannels), - signedReservations: make(map[lnwire.ChannelID][32]byte), - newChanBarriers: make(map[lnwire.ChannelID]chan struct{}), - fundingMsgs: make(chan *fundingMsg, msgBufferSize), - fundingRequests: make(chan *InitFundingMsg, msgBufferSize), - localDiscoverySignals: make(map[lnwire.ChannelID]chan struct{}), - handleChannelReadyBarriers: make(map[lnwire.ChannelID]struct{}), - quit: make(chan struct{}), + cfg: &cfg, + chanIDKey: cfg.TempChanIDSeed, + activeReservations: make( + map[serializedPubKey]pendingChannels, + ), + signedReservations: make( + map[lnwire.ChannelID][32]byte, + ), + newChanBarriers: make( + map[lnwire.ChannelID]chan struct{}, + ), + fundingMsgs: make( + chan *fundingMsg, msgBufferSize, + ), + fundingRequests: make( + chan *InitFundingMsg, msgBufferSize, + ), + localDiscoverySignals: make( + map[lnwire.ChannelID]chan struct{}, + ), + handleChannelReadyBarriers: make( + map[lnwire.ChannelID]struct{}, + ), + quit: make(chan struct{}), }, nil } diff --git a/funding/manager_test.go b/funding/manager_test.go index 15ff462ac..dc40c4d8f 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -1406,14 +1406,16 @@ func TestFundingManagerNormalWorkflow(t *testing.T) { // After the funding transaction is mined, Alice will send // channelReady to Bob. - channelReadyAlice := assertFundingMsgSent( + channelReadyAlice, ok := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // And similarly Bob will send funding locked to Alice. - channelReadyBob := assertFundingMsgSent( + channelReadyBob, ok := assertFundingMsgSent( t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // Check that the state machine is updated accordingly assertChannelReadySent(t, alice, bob, fundingOutPoint) @@ -1677,9 +1679,10 @@ func TestFundingManagerRestartBehavior(t *testing.T) { } // Bob will send funding locked to Alice. - channelReadyBob := assertFundingMsgSent( + channelReadyBob, ok := assertFundingMsgSent( t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // Alice should still be markedOpen assertDatabaseState(t, alice, fundingOutPoint, markedOpen) @@ -1706,9 +1709,10 @@ func TestFundingManagerRestartBehavior(t *testing.T) { return errChan } - channelReadyAlice := assertFundingMsgSent( + channelReadyAlice, ok := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // The state should now be channelReadySent assertDatabaseState(t, alice, fundingOutPoint, channelReadySent) @@ -1834,9 +1838,10 @@ func TestFundingManagerOfflinePeer(t *testing.T) { } // Bob will send funding locked to Alice - channelReadyBob := assertFundingMsgSent( + channelReadyBob, ok := assertFundingMsgSent( t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // Alice should still be markedOpen assertDatabaseState(t, alice, fundingOutPoint, markedOpen) @@ -1882,9 +1887,10 @@ func TestFundingManagerOfflinePeer(t *testing.T) { con <- bob // This should make Alice send the channelReady. - channelReadyAlice := assertFundingMsgSent( + channelReadyAlice, ok := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // The state should now be channelReadySent assertDatabaseState(t, alice, fundingOutPoint, channelReadySent) @@ -2311,14 +2317,16 @@ func TestFundingManagerReceiveChannelReadyTwice(t *testing.T) { // After the funding transaction is mined, Alice will send // channelReady to Bob. - channelReadyAlice := assertFundingMsgSent( + channelReadyAlice, ok := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // And similarly Bob will send funding locked to Alice. - channelReadyBob := assertFundingMsgSent( + channelReadyBob, ok := assertFundingMsgSent( t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // Check that the state machine is updated accordingly assertChannelReadySent(t, alice, bob, fundingOutPoint) @@ -2422,14 +2430,16 @@ func TestFundingManagerRestartAfterChanAnn(t *testing.T) { // After the funding transaction is mined, Alice will send // channelReady to Bob. - channelReadyAlice := assertFundingMsgSent( + channelReadyAlice, ok := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // And similarly Bob will send funding locked to Alice. - channelReadyBob := assertFundingMsgSent( + channelReadyBob, ok := assertFundingMsgSent( t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // Check that the state machine is updated accordingly assertChannelReadySent(t, alice, bob, fundingOutPoint) @@ -2519,14 +2529,16 @@ func TestFundingManagerRestartAfterReceivingChannelReady(t *testing.T) { // After the funding transaction is mined, Alice will send // channelReady to Bob. - channelReadyAlice := assertFundingMsgSent( + channelReadyAlice, ok := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // And similarly Bob will send funding locked to Alice. - channelReadyBob := assertFundingMsgSent( + channelReadyBob, ok := assertFundingMsgSent( t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // Check that the state machine is updated accordingly assertChannelReadySent(t, alice, bob, fundingOutPoint) @@ -2612,14 +2624,16 @@ func TestFundingManagerPrivateChannel(t *testing.T) { // After the funding transaction is mined, Alice will send // channelReady to Bob. - channelReadyAlice := assertFundingMsgSent( + channelReadyAlice, ok := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // And similarly Bob will send funding locked to Alice. - channelReadyBob := assertFundingMsgSent( + channelReadyBob, ok := assertFundingMsgSent( t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // Check that the state machine is updated accordingly assertChannelReadySent(t, alice, bob, fundingOutPoint) @@ -2735,14 +2749,16 @@ func TestFundingManagerPrivateRestart(t *testing.T) { // After the funding transaction is mined, Alice will send // channelReady to Bob. - channelReadyAlice := assertFundingMsgSent( + channelReadyAlice, ok := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // And similarly Bob will send funding locked to Alice. - channelReadyBob := assertFundingMsgSent( + channelReadyBob, ok := assertFundingMsgSent( t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // Check that the state machine is updated accordingly assertChannelReadySent(t, alice, bob, fundingOutPoint) @@ -3170,14 +3186,16 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) { // After the funding transaction is mined, Alice will send // channelReady to Bob. - channelReadyAlice := assertFundingMsgSent( + channelReadyAlice, ok := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // And similarly Bob will send funding locked to Alice. - channelReadyBob := assertFundingMsgSent( + channelReadyBob, ok := assertFundingMsgSent( t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) // Exchange the channelReady messages. alice.fundingMgr.ProcessFundingMsg(channelReadyBob, bob) @@ -4203,16 +4221,18 @@ func TestFundingManagerZeroConf(t *testing.T) { } // Assert that Bob's channel_ready message has an AliasScid. - bobChannelReady := assertFundingMsgSent( + bobChannelReady, ok := assertFundingMsgSent( t, bob.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) require.NotNil(t, bobChannelReady.AliasScid) require.Equal(t, *bobChannelReady.AliasScid, alias) // Do the same for Alice as well. - aliceChannelReady := assertFundingMsgSent( + aliceChannelReady, ok := assertFundingMsgSent( t, alice.msgChan, "ChannelReady", ).(*lnwire.ChannelReady) + require.True(t, ok) require.NotNil(t, aliceChannelReady.AliasScid) require.Equal(t, *aliceChannelReady.AliasScid, alias) diff --git a/lnwire/funding_locked.go b/lnwire/channel_ready.go similarity index 100% rename from lnwire/funding_locked.go rename to lnwire/channel_ready.go diff --git a/lnwire/lnwire_test.go b/lnwire/lnwire_test.go index baefa4a6a..1ad93c96b 100644 --- a/lnwire/lnwire_test.go +++ b/lnwire/lnwire_test.go @@ -567,7 +567,6 @@ func TestLightningWireProtocol(t *testing.T) { v[0] = reflect.ValueOf(req) }, MsgChannelReady: func(v []reflect.Value, r *rand.Rand) { - var c [32]byte if _, err := r.Read(c[:]); err != nil { t.Fatalf("unable to generate chan id: %v", err) From c4aea6e7899352d9c5d3a09c7cb90f4b452778e1 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 16 Mar 2023 21:56:51 +0800 Subject: [PATCH 34/87] docs: update release note for `channel_ready` --- docs/release-notes/release-notes-0.16.1.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index 983f4f358..84485cc94 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -26,6 +26,13 @@ added to `lnrpc` so the node operator can know whether a certain request has happened or not. +* Message `funding_locked` [has been + renamed](https://github.com/lightningnetwork/lnd/pull/7517) to + `channel_ready` internally to match the specs update. This should not change + anything for the users since the message type(36) stays unchanged, except in + the logging all the appearance of `funding_locked` replated experssion is + replaced with `channel_ready`. + # Contributors (Alphabetical Order) * Elle Mouton From b16df45076c7fcf2657137b018c8b8f2af280bbc Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Thu, 9 Mar 2023 10:26:06 +0200 Subject: [PATCH 35/87] watchtower: add sessionID index In this commit, a new session-ID index is added to the tower client db with the help of a migration. This index holds a mapping from a db-assigned-ID (a uint64 encoded using BigSize encoding) to real session ID (33 bytes). This mapping will help us save space in future when persisting references to sessions. --- watchtower/wtdb/client_db.go | 82 ++++++++++- watchtower/wtdb/log.go | 2 + watchtower/wtdb/migration6/client_db.go | 114 ++++++++++++++ watchtower/wtdb/migration6/client_db_test.go | 147 +++++++++++++++++++ watchtower/wtdb/migration6/codec.go | 17 +++ watchtower/wtdb/migration6/log.go | 14 ++ watchtower/wtdb/version.go | 4 + 7 files changed, 373 insertions(+), 7 deletions(-) create mode 100644 watchtower/wtdb/migration6/client_db.go create mode 100644 watchtower/wtdb/migration6/client_db_test.go create mode 100644 watchtower/wtdb/migration6/codec.go create mode 100644 watchtower/wtdb/migration6/log.go diff --git a/watchtower/wtdb/client_db.go b/watchtower/wtdb/client_db.go index 3cbe0c6f1..2079a0c6f 100644 --- a/watchtower/wtdb/client_db.go +++ b/watchtower/wtdb/client_db.go @@ -35,10 +35,15 @@ var ( // cSessionBkt is a top-level bucket storing: // session-id => cSessionBody -> encoded ClientSessionBody + // => cSessionDBID -> db-assigned-id // => cSessionCommits => seqnum -> encoded CommittedUpdate // => cSessionAckRangeIndex => db-chan-id => start -> end cSessionBkt = []byte("client-session-bucket") + // cSessionDBID is a key used in the cSessionBkt to store the + // db-assigned-id of a session. + cSessionDBID = []byte("client-session-db-id") + // cSessionBody is a sub-bucket of cSessionBkt storing only the body of // the ClientSession. cSessionBody = []byte("client-session-body") @@ -55,6 +60,10 @@ var ( // db-assigned-id -> channel-ID cChanIDIndexBkt = []byte("client-channel-id-index") + // cSessionIDIndexBkt is a top-level bucket storing: + // db-assigned-id -> session-id + cSessionIDIndexBkt = []byte("client-session-id-index") + // cTowerBkt is a top-level bucket storing: // tower-id -> encoded Tower. cTowerBkt = []byte("client-tower-bucket") @@ -241,6 +250,7 @@ func initClientDBBuckets(tx kvdb.RwTx) error { cTowerIndexBkt, cTowerToSessionIndexBkt, cChanIDIndexBkt, + cSessionIDIndexBkt, } for _, bucket := range buckets { @@ -723,24 +733,58 @@ func (c *ClientDB) CreateClientSession(session *ClientSession) error { } } - // Add the new entry to the towerID-to-SessionID index. - indexBkt := towerToSessionIndex.NestedReadWriteBucket( - towerID.Bytes(), - ) - if indexBkt == nil { - return ErrTowerNotFound + // Get the session-ID index bucket. + dbIDIndex := tx.ReadWriteBucket(cSessionIDIndexBkt) + if dbIDIndex == nil { + return ErrUninitializedDB } - err = indexBkt.Put(session.ID[:], []byte{1}) + // Get a new, unique, ID for this session from the session-ID + // index bucket. + nextSeq, err := dbIDIndex.NextSequence() if err != nil { return err } + // Add the new entry to the dbID-to-SessionID index. + newIndex, err := writeBigSize(nextSeq) + if err != nil { + return err + } + + err = dbIDIndex.Put(newIndex, session.ID[:]) + if err != nil { + return err + } + + // Also add the db-assigned-id to the session bucket under the + // cSessionDBID key. sessionBkt, err := sessions.CreateBucket(session.ID[:]) if err != nil { return err } + err = sessionBkt.Put(cSessionDBID, newIndex) + if err != nil { + return err + } + + // TODO(elle): migrate the towerID-to-SessionID to use the + // new db-assigned sessionID's rather. + + // Add the new entry to the towerID-to-SessionID index. + towerSessions := towerToSessionIndex.NestedReadWriteBucket( + towerID.Bytes(), + ) + if towerSessions == nil { + return ErrTowerNotFound + } + + err = towerSessions.Put(session.ID[:], []byte{1}) + if err != nil { + return err + } + // Finally, write the client session's body in the sessions // bucket. return putClientSessionBody(sessionBkt, session) @@ -1882,6 +1926,30 @@ func getDBChanID(chanDetailsBkt kvdb.RBucket, chanID lnwire.ChannelID) (uint64, return id, idBytes, nil } +// getDBSessionID returns the db-assigned session ID for the given real session +// ID. It returns both the uint64 and byte representation. +func getDBSessionID(sessionsBkt kvdb.RBucket, sessionID SessionID) (uint64, + []byte, error) { + + sessionBkt := sessionsBkt.NestedReadBucket(sessionID[:]) + if sessionBkt == nil { + return 0, nil, ErrClientSessionNotFound + } + + idBytes := sessionBkt.Get(cSessionDBID) + if len(idBytes) == 0 { + return 0, nil, fmt.Errorf("no db-assigned ID found for "+ + "session ID %s", sessionID) + } + + id, err := readBigSize(idBytes) + if err != nil { + return 0, nil, err + } + + return id, idBytes, nil +} + // writeBigSize will encode the given uint64 as a BigSize byte slice. func writeBigSize(i uint64) ([]byte, error) { var b bytes.Buffer diff --git a/watchtower/wtdb/log.go b/watchtower/wtdb/log.go index f7952ba4e..638542abb 100644 --- a/watchtower/wtdb/log.go +++ b/watchtower/wtdb/log.go @@ -8,6 +8,7 @@ import ( "github.com/lightningnetwork/lnd/watchtower/wtdb/migration3" "github.com/lightningnetwork/lnd/watchtower/wtdb/migration4" "github.com/lightningnetwork/lnd/watchtower/wtdb/migration5" + "github.com/lightningnetwork/lnd/watchtower/wtdb/migration6" ) // log is a logger that is initialized with no output filters. This @@ -36,6 +37,7 @@ func UseLogger(logger btclog.Logger) { migration3.UseLogger(logger) migration4.UseLogger(logger) migration5.UseLogger(logger) + migration6.UseLogger(logger) } // logClosure is used to provide a closure over expensive logging operations so diff --git a/watchtower/wtdb/migration6/client_db.go b/watchtower/wtdb/migration6/client_db.go new file mode 100644 index 000000000..8d5ffbc29 --- /dev/null +++ b/watchtower/wtdb/migration6/client_db.go @@ -0,0 +1,114 @@ +package migration6 + +import ( + "bytes" + "encoding/binary" + "errors" + + "github.com/lightningnetwork/lnd/kvdb" + "github.com/lightningnetwork/lnd/tlv" +) + +var ( + // cSessionBkt is a top-level bucket storing: + // session-id => cSessionBody -> encoded ClientSessionBody + // => cSessionDBID -> db-assigned-id + // => cSessionCommits => seqnum -> encoded CommittedUpdate + // => cSessionAcks => seqnum -> encoded BackupID + cSessionBkt = []byte("client-session-bucket") + + // cSessionDBID is a key used in the cSessionBkt to store the + // db-assigned-id of a session. + cSessionDBID = []byte("client-session-db-id") + + // cSessionIDIndexBkt is a top-level bucket storing: + // db-assigned-id -> session-id + cSessionIDIndexBkt = []byte("client-session-id-index") + + // cSessionBody is a sub-bucket of cSessionBkt storing only the body of + // the ClientSession. + cSessionBody = []byte("client-session-body") + + // ErrUninitializedDB signals that top-level buckets for the database + // have not been initialized. + ErrUninitializedDB = errors.New("db not initialized") + + // ErrCorruptClientSession signals that the client session's on-disk + // structure deviates from what is expected. + ErrCorruptClientSession = errors.New("client session corrupted") + + byteOrder = binary.BigEndian +) + +// MigrateSessionIDIndex adds a new session ID index to the tower client db. +// This index is a mapping from db-assigned ID (a uint64 encoded using BigSize) +// to real session ID (33 bytes). This mapping will allow us to persist session +// pointers with fewer bytes in the future. +func MigrateSessionIDIndex(tx kvdb.RwTx) error { + log.Infof("Migrating the tower client db to add a new session ID " + + "index which stores a mapping from db-assigned ID to real " + + "session ID") + + // Create a new top-level bucket for the index. + indexBkt, err := tx.CreateTopLevelBucket(cSessionIDIndexBkt) + if err != nil { + return err + } + + // Get the existing top-level sessions bucket. + sessionsBkt := tx.ReadWriteBucket(cSessionBkt) + if sessionsBkt == nil { + return ErrUninitializedDB + } + + // Iterate over the sessions bucket where each key is a session-ID. + return sessionsBkt.ForEach(func(sessionID, _ []byte) error { + // Ask the DB for a new, unique, id for the index bucket. + nextSeq, err := indexBkt.NextSequence() + if err != nil { + return err + } + + newIndex, err := writeBigSize(nextSeq) + if err != nil { + return err + } + + // Add the new db-assigned-ID to real-session-ID pair to the + // new index bucket. + err = indexBkt.Put(newIndex, sessionID) + if err != nil { + return err + } + + // Get the sub-bucket for this specific session ID. + sessionBkt := sessionsBkt.NestedReadWriteBucket(sessionID) + if sessionBkt == nil { + return ErrCorruptClientSession + } + + // Here we ensure that the session bucket includes a session + // body. The only reason we do this is so that we can simulate + // a migration fail in a test to ensure that a migration fail + // results in an untouched db. + sessionBodyBytes := sessionBkt.Get(cSessionBody) + if sessionBodyBytes == nil { + return ErrCorruptClientSession + } + + // Add the db-assigned ID of the session to the session under + // the cSessionDBID key. + return sessionBkt.Put(cSessionDBID, newIndex) + }) +} + +// writeBigSize will encode the given uint64 as a BigSize byte slice. +func writeBigSize(i uint64) ([]byte, error) { + var b bytes.Buffer + err := tlv.WriteVarInt(&b, i, &[8]byte{}) + if err != nil { + return nil, err + } + + return b.Bytes(), nil +} diff --git a/watchtower/wtdb/migration6/client_db_test.go b/watchtower/wtdb/migration6/client_db_test.go new file mode 100644 index 000000000..c4928e2f9 --- /dev/null +++ b/watchtower/wtdb/migration6/client_db_test.go @@ -0,0 +1,147 @@ +package migration6 + +import ( + "bytes" + "testing" + + "github.com/lightningnetwork/lnd/channeldb/migtest" + "github.com/lightningnetwork/lnd/kvdb" + "github.com/lightningnetwork/lnd/tlv" +) + +var ( + // pre is the expected data in the sessions bucket before the migration. + pre = map[string]interface{}{ + sessionIDToString(100): map[string]interface{}{ + string(cSessionBody): string([]byte{1, 2, 3}), + }, + sessionIDToString(222): map[string]interface{}{ + string(cSessionBody): string([]byte{4, 5, 6}), + }, + } + + // preFailCorruptDB should fail the migration due to no session body + // being found for a given session ID. + preFailCorruptDB = map[string]interface{}{ + sessionIDToString(100): "", + } + + // post is the expected session index after migration. + postIndex = map[string]interface{}{ + indexToString(1): sessionIDToString(100), + indexToString(2): sessionIDToString(222), + } + + // postSessions is the expected data in the sessions bucket after the + // migration. + postSessions = map[string]interface{}{ + sessionIDToString(100): map[string]interface{}{ + string(cSessionBody): string([]byte{1, 2, 3}), + string(cSessionDBID): indexToString(1), + }, + sessionIDToString(222): map[string]interface{}{ + string(cSessionBody): string([]byte{4, 5, 6}), + string(cSessionDBID): indexToString(2), + }, + } +) + +// TestMigrateSessionIDIndex tests that the MigrateSessionIDIndex function +// correctly adds a new session-id index to the DB and also correctly updates +// the existing session bucket. +func TestMigrateSessionIDIndex(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + shouldFail bool + pre map[string]interface{} + postSessions map[string]interface{} + postIndex map[string]interface{} + }{ + { + name: "migration ok", + shouldFail: false, + pre: pre, + postSessions: postSessions, + postIndex: postIndex, + }, + { + name: "fail due to corrupt db", + shouldFail: true, + pre: preFailCorruptDB, + }, + { + name: "no channel details", + shouldFail: false, + pre: nil, + postSessions: nil, + postIndex: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + // Before the migration we have a details bucket. + before := func(tx kvdb.RwTx) error { + return migtest.RestoreDB( + tx, cSessionBkt, test.pre, + ) + } + + // After the migration, we should have an untouched + // summary bucket and a new index bucket. + after := func(tx kvdb.RwTx) error { + // If the migration fails, the details bucket + // should be untouched. + if test.shouldFail { + if err := migtest.VerifyDB( + tx, cSessionBkt, test.pre, + ); err != nil { + return err + } + + return nil + } + + // Else, we expect an updated summary bucket + // and a new index bucket. + err := migtest.VerifyDB( + tx, cSessionBkt, test.postSessions, + ) + if err != nil { + return err + } + + return migtest.VerifyDB( + tx, cSessionIDIndexBkt, test.postIndex, + ) + } + + migtest.ApplyMigration( + t, before, after, MigrateSessionIDIndex, + test.shouldFail, + ) + }) + } +} + +func indexToString(id uint64) string { + var newIndex bytes.Buffer + err := tlv.WriteVarInt(&newIndex, id, &[8]byte{}) + if err != nil { + panic(err) + } + + return newIndex.String() +} + +func sessionIDToString(id uint64) string { + var chanID SessionID + byteOrder.PutUint64(chanID[:], id) + return chanID.String() +} diff --git a/watchtower/wtdb/migration6/codec.go b/watchtower/wtdb/migration6/codec.go new file mode 100644 index 000000000..11edbf299 --- /dev/null +++ b/watchtower/wtdb/migration6/codec.go @@ -0,0 +1,17 @@ +package migration6 + +import ( + "encoding/hex" +) + +// SessionIDSize is 33-bytes; it is a serialized, compressed public key. +const SessionIDSize = 33 + +// SessionID is created from the remote public key of a client, and serves as a +// unique identifier and authentication for sending state updates. +type SessionID [SessionIDSize]byte + +// String returns a hex encoding of the session id. +func (s SessionID) String() string { + return hex.EncodeToString(s[:]) +} diff --git a/watchtower/wtdb/migration6/log.go b/watchtower/wtdb/migration6/log.go new file mode 100644 index 000000000..e43e7d27e --- /dev/null +++ b/watchtower/wtdb/migration6/log.go @@ -0,0 +1,14 @@ +package migration6 + +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/watchtower/wtdb/version.go b/watchtower/wtdb/version.go index dbcad3715..1a186044a 100644 --- a/watchtower/wtdb/version.go +++ b/watchtower/wtdb/version.go @@ -10,6 +10,7 @@ import ( "github.com/lightningnetwork/lnd/watchtower/wtdb/migration3" "github.com/lightningnetwork/lnd/watchtower/wtdb/migration4" "github.com/lightningnetwork/lnd/watchtower/wtdb/migration5" + "github.com/lightningnetwork/lnd/watchtower/wtdb/migration6" ) // txMigration is a function which takes a prior outdated version of the @@ -59,6 +60,9 @@ var clientDBVersions = []version{ { txMigration: migration5.MigrateCompleteTowerToSessionIndex, }, + { + txMigration: migration6.MigrateSessionIDIndex, + }, } // getLatestDBVersion returns the last known database version. From ee0353dd24e7819d12df6423375f53272fdd9b6e Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Thu, 9 Mar 2023 10:30:12 +0200 Subject: [PATCH 36/87] watchtower: build channel to sessionIDs index In this commit, a migration is added that adds an index from channel to sessionIDs (using the DB-assigned session IDs). This will make it easier in future to know which sessions have updates for which channels. --- watchtower/wtdb/client_db.go | 44 +++- watchtower/wtdb/log.go | 2 + watchtower/wtdb/migration7/client_db.go | 202 +++++++++++++++++++ watchtower/wtdb/migration7/client_db_test.go | 191 ++++++++++++++++++ watchtower/wtdb/migration7/codec.go | 29 +++ watchtower/wtdb/migration7/log.go | 14 ++ watchtower/wtdb/version.go | 4 + 7 files changed, 485 insertions(+), 1 deletion(-) create mode 100644 watchtower/wtdb/migration7/client_db.go create mode 100644 watchtower/wtdb/migration7/client_db_test.go create mode 100644 watchtower/wtdb/migration7/codec.go create mode 100644 watchtower/wtdb/migration7/log.go diff --git a/watchtower/wtdb/client_db.go b/watchtower/wtdb/client_db.go index 2079a0c6f..014e503db 100644 --- a/watchtower/wtdb/client_db.go +++ b/watchtower/wtdb/client_db.go @@ -23,8 +23,13 @@ var ( // cChanDetailsBkt is a top-level bucket storing: // channel-id => cChannelSummary -> encoded ClientChanSummary. // => cChanDBID -> db-assigned-id + // => cChanSessions => db-session-id -> 1 cChanDetailsBkt = []byte("client-channel-detail-bucket") + // cChanSessions is a sub-bucket of cChanDetailsBkt which stores: + // db-session-id -> 1 + cChanSessions = []byte("client-channel-sessions") + // cChanDBID is a key used in the cChanDetailsBkt to store the // db-assigned-id of a channel. cChanDBID = []byte("client-channel-db-id") @@ -1454,7 +1459,7 @@ func (c *ClientDB) AckUpdate(id *SessionID, seqNum uint16, return ErrUninitializedDB } - chanDetailsBkt := tx.ReadBucket(cChanDetailsBkt) + chanDetailsBkt := tx.ReadWriteBucket(cChanDetailsBkt) if chanDetailsBkt == nil { return ErrUninitializedDB } @@ -1538,6 +1543,23 @@ func (c *ClientDB) AckUpdate(id *SessionID, seqNum uint16, return err } + dbSessionID, _, err := getDBSessionID(sessions, *id) + if err != nil { + return err + } + + chanDetails := chanDetailsBkt.NestedReadWriteBucket( + committedUpdate.BackupID.ChanID[:], + ) + if chanDetails == nil { + return ErrChannelNotRegistered + } + + err = putChannelToSessionMapping(chanDetails, dbSessionID) + if err != nil { + return err + } + // Get the range index for the given session-channel pair. index, err := c.getRangeIndex(tx, *id, chanID) if err != nil { @@ -1548,6 +1570,26 @@ func (c *ClientDB) AckUpdate(id *SessionID, seqNum uint16, }, func() {}) } +// putChannelToSessionMapping adds the given session ID to a channel's +// cChanSessions bucket. +func putChannelToSessionMapping(chanDetails kvdb.RwBucket, + dbSessID uint64) error { + + chanSessIDsBkt, err := chanDetails.CreateBucketIfNotExists( + cChanSessions, + ) + if err != nil { + return err + } + + b, err := writeBigSize(dbSessID) + if err != nil { + return err + } + + return chanSessIDsBkt.Put(b, []byte{1}) +} + // getClientSessionBody loads the body of a ClientSession from the sessions // bucket corresponding to the serialized session id. This does not deserialize // the CommittedUpdates, AckUpdates or the Tower associated with the session. diff --git a/watchtower/wtdb/log.go b/watchtower/wtdb/log.go index 638542abb..639030631 100644 --- a/watchtower/wtdb/log.go +++ b/watchtower/wtdb/log.go @@ -9,6 +9,7 @@ import ( "github.com/lightningnetwork/lnd/watchtower/wtdb/migration4" "github.com/lightningnetwork/lnd/watchtower/wtdb/migration5" "github.com/lightningnetwork/lnd/watchtower/wtdb/migration6" + "github.com/lightningnetwork/lnd/watchtower/wtdb/migration7" ) // log is a logger that is initialized with no output filters. This @@ -38,6 +39,7 @@ func UseLogger(logger btclog.Logger) { migration4.UseLogger(logger) migration5.UseLogger(logger) migration6.UseLogger(logger) + migration7.UseLogger(logger) } // logClosure is used to provide a closure over expensive logging operations so diff --git a/watchtower/wtdb/migration7/client_db.go b/watchtower/wtdb/migration7/client_db.go new file mode 100644 index 000000000..0c3c4be40 --- /dev/null +++ b/watchtower/wtdb/migration7/client_db.go @@ -0,0 +1,202 @@ +package migration7 + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + + "github.com/lightningnetwork/lnd/kvdb" + "github.com/lightningnetwork/lnd/tlv" +) + +var ( + // cSessionBkt is a top-level bucket storing: + // session-id => cSessionBody -> encoded ClientSessionBody + // => cSessionDBID -> db-assigned-id + // => cSessionCommits => seqnum -> encoded CommittedUpdate + // => cSessionAckRangeIndex => chan-id => acked-index-range + cSessionBkt = []byte("client-session-bucket") + + // cChanDetailsBkt is a top-level bucket storing: + // channel-id => cChannelSummary -> encoded ClientChanSummary. + // => cChanDBID -> db-assigned-id + // => cChanSessions => db-session-id -> 1 + cChanDetailsBkt = []byte("client-channel-detail-bucket") + + // cChannelSummary is a sub-bucket of cChanDetailsBkt which stores the + // encoded body of ClientChanSummary. + cChannelSummary = []byte("client-channel-summary") + + // cChanSessions is a sub-bucket of cChanDetailsBkt which stores: + // session-id -> 1 + cChanSessions = []byte("client-channel-sessions") + + // cSessionAckRangeIndex is a sub-bucket of cSessionBkt storing: + // chan-id => start -> end + cSessionAckRangeIndex = []byte("client-session-ack-range-index") + + // cSessionDBID is a key used in the cSessionBkt to store the + // db-assigned-d of a session. + cSessionDBID = []byte("client-session-db-id") + + // cChanIDIndexBkt is a top-level bucket storing: + // db-assigned-id -> channel-ID + cChanIDIndexBkt = []byte("client-channel-id-index") + + // ErrUninitializedDB signals that top-level buckets for the database + // have not been initialized. + ErrUninitializedDB = errors.New("db not initialized") + + // ErrCorruptClientSession signals that the client session's on-disk + // structure deviates from what is expected. + ErrCorruptClientSession = errors.New("client session corrupted") + + // byteOrder is the default endianness used when serializing integers. + byteOrder = binary.BigEndian +) + +// MigrateChannelToSessionIndex migrates the tower client DB to add an index +// from channel-to-session. This will make it easier in future to check which +// sessions have updates for which channels. +func MigrateChannelToSessionIndex(tx kvdb.RwTx) error { + log.Infof("Migrating the tower client DB to build a new " + + "channel-to-session index") + + sessionsBkt := tx.ReadBucket(cSessionBkt) + if sessionsBkt == nil { + return ErrUninitializedDB + } + + chanDetailsBkt := tx.ReadWriteBucket(cChanDetailsBkt) + if chanDetailsBkt == nil { + return ErrUninitializedDB + } + + chanIDsBkt := tx.ReadBucket(cChanIDIndexBkt) + if chanIDsBkt == nil { + return ErrUninitializedDB + } + + // First gather all the new channel-to-session pairs that we want to + // add. + index, err := collectIndex(sessionsBkt) + if err != nil { + return err + } + + // Then persist those pairs to the db. + return persistIndex(chanDetailsBkt, chanIDsBkt, index) +} + +// collectIndex iterates through all the sessions and uses the keys in the +// cSessionAckRangeIndex bucket to collect all the channels that the session +// has updates for. The function returns a map from channel ID to session ID +// (using the db-assigned IDs for both). +func collectIndex(sessionsBkt kvdb.RBucket) (map[uint64]map[uint64]bool, + error) { + + index := make(map[uint64]map[uint64]bool) + err := sessionsBkt.ForEach(func(sessID, _ []byte) error { + sessionBkt := sessionsBkt.NestedReadBucket(sessID) + if sessionBkt == nil { + return ErrCorruptClientSession + } + + ackedRanges := sessionBkt.NestedReadBucket( + cSessionAckRangeIndex, + ) + if ackedRanges == nil { + return nil + } + + sessDBIDBytes := sessionBkt.Get(cSessionDBID) + if sessDBIDBytes == nil { + return ErrCorruptClientSession + } + + sessDBID, err := readUint64(sessDBIDBytes) + if err != nil { + return err + } + + return ackedRanges.ForEach(func(dbChanIDBytes, _ []byte) error { + dbChanID, err := readUint64(dbChanIDBytes) + if err != nil { + return err + } + + if _, ok := index[dbChanID]; !ok { + index[dbChanID] = make(map[uint64]bool) + } + + index[dbChanID][sessDBID] = true + + return nil + }) + }) + if err != nil { + return nil, err + } + + return index, nil +} + +// persistIndex adds the channel-to-session mapping in each channel's details +// bucket. +func persistIndex(chanDetailsBkt kvdb.RwBucket, chanIDsBkt kvdb.RBucket, + index map[uint64]map[uint64]bool) error { + + for dbChanID, sessIDs := range index { + dbChanIDBytes, err := writeUint64(dbChanID) + if err != nil { + return err + } + + realChanID := chanIDsBkt.Get(dbChanIDBytes) + + chanBkt := chanDetailsBkt.NestedReadWriteBucket(realChanID) + if chanBkt == nil { + return fmt.Errorf("channel not found") + } + + sessIDsBkt, err := chanBkt.CreateBucket(cChanSessions) + if err != nil { + return err + } + + for id := range sessIDs { + sessID, err := writeUint64(id) + if err != nil { + return err + } + + err = sessIDsBkt.Put(sessID, []byte{1}) + if err != nil { + return err + } + } + } + + return nil +} + +func writeUint64(i uint64) ([]byte, error) { + var b bytes.Buffer + err := tlv.WriteVarInt(&b, i, &[8]byte{}) + if err != nil { + return nil, err + } + + return b.Bytes(), nil +} + +func readUint64(b []byte) (uint64, error) { + r := bytes.NewReader(b) + i, err := tlv.ReadVarInt(r, &[8]byte{}) + if err != nil { + return 0, err + } + + return i, nil +} diff --git a/watchtower/wtdb/migration7/client_db_test.go b/watchtower/wtdb/migration7/client_db_test.go new file mode 100644 index 000000000..4f90edc47 --- /dev/null +++ b/watchtower/wtdb/migration7/client_db_test.go @@ -0,0 +1,191 @@ +package migration7 + +import ( + "testing" + + "github.com/lightningnetwork/lnd/channeldb/migtest" + "github.com/lightningnetwork/lnd/kvdb" +) + +var ( + // preDetails is the expected data of the channel details bucket before + // the migration. + preDetails = map[string]interface{}{ + channelIDString(100): map[string]interface{}{ + string(cChannelSummary): string([]byte{1, 2, 3}), + }, + channelIDString(222): map[string]interface{}{ + string(cChannelSummary): string([]byte{4, 5, 6}), + }, + } + + // preFailCorruptDB should fail the migration due to no channel summary + // being found for a given channel ID. + preFailCorruptDB = map[string]interface{}{ + channelIDString(30): map[string]interface{}{}, + } + + // channelIDIndex is the data in the channelID index that is used to + // find the mapping between the db-assigned channel ID and the real + // channel ID. + channelIDIndex = map[string]interface{}{ + uint64ToStr(10): channelIDString(100), + uint64ToStr(20): channelIDString(222), + } + + // sessions is the expected data in the sessions bucket before and + // after the migration. + sessions = map[string]interface{}{ + sessionIDString("1"): map[string]interface{}{ + string(cSessionAckRangeIndex): map[string]interface{}{ + uint64ToStr(10): map[string]interface{}{ + uint64ToStr(30): uint64ToStr(32), + uint64ToStr(34): uint64ToStr(34), + }, + uint64ToStr(20): map[string]interface{}{ + uint64ToStr(30): uint64ToStr(30), + }, + }, + string(cSessionDBID): uint64ToStr(66), + }, + sessionIDString("2"): map[string]interface{}{ + string(cSessionAckRangeIndex): map[string]interface{}{ + uint64ToStr(10): map[string]interface{}{ + uint64ToStr(33): uint64ToStr(33), + }, + }, + string(cSessionDBID): uint64ToStr(77), + }, + } + + // postDetails is the expected data in the channel details bucket after + // the migration. + postDetails = map[string]interface{}{ + channelIDString(100): map[string]interface{}{ + string(cChannelSummary): string([]byte{1, 2, 3}), + string(cChanSessions): map[string]interface{}{ + uint64ToStr(66): string([]byte{1}), + uint64ToStr(77): string([]byte{1}), + }, + }, + channelIDString(222): map[string]interface{}{ + string(cChannelSummary): string([]byte{4, 5, 6}), + string(cChanSessions): map[string]interface{}{ + uint64ToStr(66): string([]byte{1}), + }, + }, + } +) + +// TestMigrateChannelToSessionIndex tests that the MigrateChannelToSessionIndex +// function correctly builds the new channel-to-sessionID index to the tower +// client DB. +func TestMigrateChannelToSessionIndex(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + shouldFail bool + preDetails map[string]interface{} + preSessions map[string]interface{} + preChanIndex map[string]interface{} + postDetails map[string]interface{} + }{ + { + name: "migration ok", + shouldFail: false, + preDetails: preDetails, + preSessions: sessions, + preChanIndex: channelIDIndex, + postDetails: postDetails, + }, + { + name: "fail due to corrupt db", + shouldFail: true, + preDetails: preFailCorruptDB, + preSessions: sessions, + }, + { + name: "no sessions", + shouldFail: false, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + // Before the migration we have a channel details + // bucket, a sessions bucket, a session ID index bucket + // and a channel ID index bucket. + before := func(tx kvdb.RwTx) error { + err := migtest.RestoreDB( + tx, cChanDetailsBkt, test.preDetails, + ) + if err != nil { + return err + } + + err = migtest.RestoreDB( + tx, cSessionBkt, test.preSessions, + ) + if err != nil { + return err + } + + return migtest.RestoreDB( + tx, cChanIDIndexBkt, test.preChanIndex, + ) + } + + after := func(tx kvdb.RwTx) error { + // If the migration fails, the details bucket + // should be untouched. + if test.shouldFail { + if err := migtest.VerifyDB( + tx, cChanDetailsBkt, + test.preDetails, + ); err != nil { + return err + } + + return nil + } + + // Else, we expect an updated details bucket + // and a new index bucket. + return migtest.VerifyDB( + tx, cChanDetailsBkt, test.postDetails, + ) + } + + migtest.ApplyMigration( + t, before, after, MigrateChannelToSessionIndex, + test.shouldFail, + ) + }) + } +} + +func sessionIDString(id string) string { + var sessID SessionID + copy(sessID[:], id) + return sessID.String() +} + +func channelIDString(id uint64) string { + var chanID ChannelID + byteOrder.PutUint64(chanID[:], id) + return string(chanID[:]) +} + +func uint64ToStr(id uint64) string { + b, err := writeUint64(id) + if err != nil { + panic(err) + } + + return string(b) +} diff --git a/watchtower/wtdb/migration7/codec.go b/watchtower/wtdb/migration7/codec.go new file mode 100644 index 000000000..e94cfe67d --- /dev/null +++ b/watchtower/wtdb/migration7/codec.go @@ -0,0 +1,29 @@ +package migration7 + +import "encoding/hex" + +// SessionIDSize is 33-bytes; it is a serialized, compressed public key. +const SessionIDSize = 33 + +// SessionID is created from the remote public key of a client, and serves as a +// unique identifier and authentication for sending state updates. +type SessionID [SessionIDSize]byte + +// String returns a hex encoding of the session id. +func (s SessionID) String() string { + return hex.EncodeToString(s[:]) +} + +// ChannelID is a series of 32-bytes that uniquely identifies all channels +// within the network. The ChannelID is computed using the outpoint of the +// funding transaction (the txid, and output index). Given a funding output the +// ChannelID can be calculated by XOR'ing the big-endian serialization of the +// txid and the big-endian serialization of the output index, truncated to +// 2 bytes. +type ChannelID [32]byte + +// String returns the string representation of the ChannelID. This is just the +// hex string encoding of the ChannelID itself. +func (c ChannelID) String() string { + return hex.EncodeToString(c[:]) +} diff --git a/watchtower/wtdb/migration7/log.go b/watchtower/wtdb/migration7/log.go new file mode 100644 index 000000000..39f28b6c0 --- /dev/null +++ b/watchtower/wtdb/migration7/log.go @@ -0,0 +1,14 @@ +package migration7 + +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/watchtower/wtdb/version.go b/watchtower/wtdb/version.go index 1a186044a..b44ed80eb 100644 --- a/watchtower/wtdb/version.go +++ b/watchtower/wtdb/version.go @@ -11,6 +11,7 @@ import ( "github.com/lightningnetwork/lnd/watchtower/wtdb/migration4" "github.com/lightningnetwork/lnd/watchtower/wtdb/migration5" "github.com/lightningnetwork/lnd/watchtower/wtdb/migration6" + "github.com/lightningnetwork/lnd/watchtower/wtdb/migration7" ) // txMigration is a function which takes a prior outdated version of the @@ -63,6 +64,9 @@ var clientDBVersions = []version{ { txMigration: migration6.MigrateSessionIDIndex, }, + { + txMigration: migration7.MigrateChannelToSessionIndex, + }, } // getLatestDBVersion returns the last known database version. From 5283e2c341e40f36599c2d4a432e01c69a2fc1be Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 21 Oct 2022 13:19:48 +0200 Subject: [PATCH 37/87] watchtower/wtdb: remove unnecessary tower load --- watchtower/wtdb/client_db.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/watchtower/wtdb/client_db.go b/watchtower/wtdb/client_db.go index 014e503db..4801ca1ab 100644 --- a/watchtower/wtdb/client_db.go +++ b/watchtower/wtdb/client_db.go @@ -1023,20 +1023,14 @@ func (c *ClientDB) ListClientSessions(id *TowerID, return ErrUninitializedDB } - towers := tx.ReadBucket(cTowerBkt) - if towers == nil { - return ErrUninitializedDB - } - chanIDIndexBkt := tx.ReadBucket(cChanIDIndexBkt) if chanIDIndexBkt == nil { return ErrUninitializedDB } - var err error - // If no tower ID is specified, then fetch all the sessions // known to the db. + var err error if id == nil { clientSessions, err = c.listClientAllSessions( sessions, chanIDIndexBkt, filterFn, opts..., From a3050ed21377e1acf27b52a5c7f20abbcdd87c39 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 21 Oct 2022 11:18:31 +0200 Subject: [PATCH 38/87] watchtower: add GetClientSession func to DB This commit adds a new `GetClientSession` method to the tower client DB which can be used to fetch a session by its ID from the DB. --- watchtower/wtclient/interface.go | 5 +++++ watchtower/wtdb/client_db.go | 30 ++++++++++++++++++++++++++++++ watchtower/wtmock/client_db.go | 30 ++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/watchtower/wtclient/interface.go b/watchtower/wtclient/interface.go index 9751988ba..32ebe93ad 100644 --- a/watchtower/wtclient/interface.go +++ b/watchtower/wtclient/interface.go @@ -64,6 +64,11 @@ type DB interface { ...wtdb.ClientSessionListOption) ( map[wtdb.SessionID]*wtdb.ClientSession, error) + // GetClientSession loads the ClientSession with the given ID from the + // DB. + GetClientSession(wtdb.SessionID, + ...wtdb.ClientSessionListOption) (*wtdb.ClientSession, error) + // FetchSessionCommittedUpdates retrieves the current set of un-acked // updates of the given session. FetchSessionCommittedUpdates(id *wtdb.SessionID) ( diff --git a/watchtower/wtdb/client_db.go b/watchtower/wtdb/client_db.go index 4801ca1ab..eaf188470 100644 --- a/watchtower/wtdb/client_db.go +++ b/watchtower/wtdb/client_db.go @@ -1009,6 +1009,36 @@ func getSessionKeyIndex(keyIndexes kvdb.RwBucket, towerID TowerID, return byteOrder.Uint32(keyIndexBytes), nil } +// GetClientSession loads the ClientSession with the given ID from the DB. +func (c *ClientDB) GetClientSession(id SessionID, + opts ...ClientSessionListOption) (*ClientSession, error) { + + var sess *ClientSession + err := kvdb.View(c.db, func(tx kvdb.RTx) error { + sessionsBkt := tx.ReadBucket(cSessionBkt) + if sessionsBkt == nil { + return ErrUninitializedDB + } + + chanIDIndexBkt := tx.ReadBucket(cChanIDIndexBkt) + if chanIDIndexBkt == nil { + return ErrUninitializedDB + } + + session, err := c.getClientSession( + sessionsBkt, chanIDIndexBkt, id[:], nil, opts..., + ) + if err != nil { + return err + } + + sess = session + return nil + }, func() {}) + + return sess, err +} + // ListClientSessions returns the set of all client sessions known to the db. An // optional tower ID can be used to filter out any client sessions in the // response that do not correspond to this tower. diff --git a/watchtower/wtmock/client_db.go b/watchtower/wtmock/client_db.go index 071ee7782..9d38c2da2 100644 --- a/watchtower/wtmock/client_db.go +++ b/watchtower/wtmock/client_db.go @@ -554,6 +554,36 @@ func (m *ClientDB) FetchChanSummaries() (wtdb.ChannelSummaries, error) { return summaries, nil } +// GetClientSession loads the ClientSession with the given ID from the DB. +func (m *ClientDB) GetClientSession(id wtdb.SessionID, + opts ...wtdb.ClientSessionListOption) (*wtdb.ClientSession, error) { + + cfg := wtdb.NewClientSessionCfg() + for _, o := range opts { + o(cfg) + } + + session, ok := m.activeSessions[id] + if !ok { + return nil, wtdb.ErrClientSessionNotFound + } + + if cfg.PerMaxHeight != nil { + for chanID, index := range m.ackedUpdates[session.ID] { + cfg.PerMaxHeight(&session, chanID, index.MaxHeight()) + } + } + + if cfg.PerCommittedUpdate != nil { + for _, update := range m.committedUpdates[session.ID] { + update := update + cfg.PerCommittedUpdate(&session, &update) + } + } + + return &session, nil +} + // RegisterChannel registers a channel for use within the client database. For // now, all that is stored in the channel summary is the sweep pkscript that // we'd like any tower sweeps to pay into. In the future, this will be extended From 571966440c28f640c6bf2ab1385844a770b03f6c Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 21 Oct 2022 11:21:18 +0200 Subject: [PATCH 39/87] watchtower: add MarkChannelClosed db method This commit adds a `MarkChannelClosed` method to the tower client DB. This function can be called when a channel is closed and it will check the channel's associated sessions to see if any of them are "closable". Any closable sessions are added to a new `cClosableSessionsBkt` bucket so that they can be evaluated in future. Note that only the logic for this function is added in this commit and it is not yet called. --- watchtower/wtclient/interface.go | 9 ++ watchtower/wtdb/client_db.go | 261 ++++++++++++++++++++++++++++++ watchtower/wtdb/client_db_test.go | 163 ++++++++++++++++++- watchtower/wtmock/client_db.go | 134 +++++++++++++-- 4 files changed, 553 insertions(+), 14 deletions(-) diff --git a/watchtower/wtclient/interface.go b/watchtower/wtclient/interface.go index 32ebe93ad..e5fc5d22b 100644 --- a/watchtower/wtclient/interface.go +++ b/watchtower/wtclient/interface.go @@ -86,6 +86,15 @@ type DB interface { // their channel summaries. FetchChanSummaries() (wtdb.ChannelSummaries, error) + // MarkChannelClosed will mark a registered channel as closed by setting + // its closed-height as the given block height. It returns a list of + // session IDs for sessions that are now considered closable due to the + // close of this channel. The details for this channel will be deleted + // from the DB if there are no more sessions in the DB that contain + // updates for this channel. + MarkChannelClosed(chanID lnwire.ChannelID, blockHeight uint32) ( + []wtdb.SessionID, error) + // RegisterChannel registers a channel for use within the client // database. For now, all that is stored in the channel summary is the // sweep pkscript that we'd like any tower sweeps to pay into. In the diff --git a/watchtower/wtdb/client_db.go b/watchtower/wtdb/client_db.go index eaf188470..d88fd631e 100644 --- a/watchtower/wtdb/client_db.go +++ b/watchtower/wtdb/client_db.go @@ -24,6 +24,7 @@ var ( // channel-id => cChannelSummary -> encoded ClientChanSummary. // => cChanDBID -> db-assigned-id // => cChanSessions => db-session-id -> 1 + // => cChanClosedHeight -> block-height cChanDetailsBkt = []byte("client-channel-detail-bucket") // cChanSessions is a sub-bucket of cChanDetailsBkt which stores: @@ -34,6 +35,12 @@ var ( // db-assigned-id of a channel. cChanDBID = []byte("client-channel-db-id") + // cChanClosedHeight is a key used in the cChanDetailsBkt to store the + // block height at which the channel's closing transaction was mined in. + // If this there is no associated value for this key, then the channel + // has not yet been marked as closed. + cChanClosedHeight = []byte("client-channel-closed-height") + // cChannelSummary is a key used in cChanDetailsBkt to store the encoded // body of ClientChanSummary. cChannelSummary = []byte("client-channel-summary") @@ -83,6 +90,10 @@ var ( "client-tower-to-session-index-bucket", ) + // cClosableSessionsBkt is a top-level bucket storing: + // db-session-id -> last-channel-close-height + cClosableSessionsBkt = []byte("client-closable-sessions-bucket") + // ErrTowerNotFound signals that the target tower was not found in the // database. ErrTowerNotFound = errors.New("tower not found") @@ -156,6 +167,14 @@ var ( // ErrSessionFailedFilterFn indicates that a particular session did // not pass the filter func provided by the caller. ErrSessionFailedFilterFn = errors.New("session failed filter func") + + // errSessionHasOpenChannels is an error used to indicate that a + // session has updates for channels that are still open. + errSessionHasOpenChannels = errors.New("session has open channels") + + // errSessionHasUnackedUpdates is an error used to indicate that a + // session has un-acked updates. + errSessionHasUnackedUpdates = errors.New("session has un-acked updates") ) // NewBoltBackendCreator returns a function that creates a new bbolt backend for @@ -256,6 +275,7 @@ func initClientDBBuckets(tx kvdb.RwTx) error { cTowerToSessionIndexBkt, cChanIDIndexBkt, cSessionIDIndexBkt, + cClosableSessionsBkt, } for _, bucket := range buckets { @@ -1365,6 +1385,209 @@ func (c *ClientDB) MarkBackupIneligible(chanID lnwire.ChannelID, return nil } +// MarkChannelClosed will mark a registered channel as closed by setting its +// closed-height as the given block height. It returns a list of session IDs for +// sessions that are now considered closable due to the close of this channel. +// The details for this channel will be deleted from the DB if there are no more +// sessions in the DB that contain updates for this channel. +func (c *ClientDB) MarkChannelClosed(chanID lnwire.ChannelID, + blockHeight uint32) ([]SessionID, error) { + + var closableSessions []SessionID + err := kvdb.Update(c.db, func(tx kvdb.RwTx) error { + sessionsBkt := tx.ReadBucket(cSessionBkt) + if sessionsBkt == nil { + return ErrUninitializedDB + } + + chanDetailsBkt := tx.ReadWriteBucket(cChanDetailsBkt) + if chanDetailsBkt == nil { + return ErrUninitializedDB + } + + closableSessBkt := tx.ReadWriteBucket(cClosableSessionsBkt) + if closableSessBkt == nil { + return ErrUninitializedDB + } + + chanIDIndexBkt := tx.ReadBucket(cChanIDIndexBkt) + if chanIDIndexBkt == nil { + return ErrUninitializedDB + } + + sessIDIndexBkt := tx.ReadBucket(cSessionIDIndexBkt) + if sessIDIndexBkt == nil { + return ErrUninitializedDB + } + + chanDetails := chanDetailsBkt.NestedReadWriteBucket(chanID[:]) + if chanDetails == nil { + return ErrChannelNotRegistered + } + + // If there are no sessions for this channel, the channel + // details can be deleted. + chanSessIDsBkt := chanDetails.NestedReadBucket(cChanSessions) + if chanSessIDsBkt == nil { + return chanDetailsBkt.DeleteNestedBucket(chanID[:]) + } + + // Otherwise, mark the channel as closed. + var height [4]byte + byteOrder.PutUint32(height[:], blockHeight) + + err := chanDetails.Put(cChanClosedHeight, height[:]) + if err != nil { + return err + } + + // Now iterate through all the sessions of the channel to check + // if any of them are closeable. + return chanSessIDsBkt.ForEach(func(sessDBID, _ []byte) error { + sessDBIDInt, err := readBigSize(sessDBID) + if err != nil { + return err + } + + // Use the session-ID index to get the real session ID. + sID, err := getRealSessionID( + sessIDIndexBkt, sessDBIDInt, + ) + if err != nil { + return err + } + + isClosable, err := isSessionClosable( + sessionsBkt, chanDetailsBkt, chanIDIndexBkt, + sID, + ) + if err != nil { + return err + } + + if !isClosable { + return nil + } + + // Add session to "closableSessions" list and add the + // block height that this last channel was closed in. + // This will be used in future to determine when we + // should delete the session. + var height [4]byte + byteOrder.PutUint32(height[:], blockHeight) + err = closableSessBkt.Put(sessDBID, height[:]) + if err != nil { + return err + } + + closableSessions = append(closableSessions, *sID) + + return nil + }) + }, func() { + closableSessions = nil + }) + if err != nil { + return nil, err + } + + return closableSessions, nil +} + +// isSessionClosable returns true if a session is considered closable. A session +// is considered closable only if all the following points are true: +// 1) It has no un-acked updates. +// 2) It is exhausted (ie it can't accept any more updates) +// 3) All the channels that it has acked updates for are closed. +func isSessionClosable(sessionsBkt, chanDetailsBkt, chanIDIndexBkt kvdb.RBucket, + id *SessionID) (bool, error) { + + sessBkt := sessionsBkt.NestedReadBucket(id[:]) + if sessBkt == nil { + return false, ErrSessionNotFound + } + + commitsBkt := sessBkt.NestedReadBucket(cSessionCommits) + if commitsBkt == nil { + // If the session has no cSessionCommits bucket then we can be + // sure that no updates have ever been committed to the session + // and so it is not yet exhausted. + return false, nil + } + + // If the session has any un-acked updates, then it is not yet closable. + err := commitsBkt.ForEach(func(_, _ []byte) error { + return errSessionHasUnackedUpdates + }) + if errors.Is(err, errSessionHasUnackedUpdates) { + return false, nil + } else if err != nil { + return false, err + } + + session, err := getClientSessionBody(sessionsBkt, id[:]) + if err != nil { + return false, err + } + + // We have already checked that the session has no more committed + // updates. So now we can check if the session is exhausted. + if session.SeqNum < session.Policy.MaxUpdates { + // If the session is not yet exhausted, it is not yet closable. + return false, nil + } + + // If the session has no acked-updates, then something is wrong since + // the above check ensures that this session has been exhausted meaning + // that it should have MaxUpdates acked updates. + ackedRangeBkt := sessBkt.NestedReadBucket(cSessionAckRangeIndex) + if ackedRangeBkt == nil { + return false, fmt.Errorf("no acked-updates found for "+ + "exhausted session %s", id) + } + + // Iterate over each of the channels that the session has acked-updates + // for. If any of those channels are not closed, then the session is + // not yet closable. + err = ackedRangeBkt.ForEach(func(dbChanID, _ []byte) error { + dbChanIDInt, err := readBigSize(dbChanID) + if err != nil { + return err + } + + chanID, err := getRealChannelID(chanIDIndexBkt, dbChanIDInt) + if err != nil { + return err + } + + // Get the channel details bucket for the channel. + chanDetails := chanDetailsBkt.NestedReadBucket(chanID[:]) + if chanDetails == nil { + return fmt.Errorf("no channel details found for "+ + "channel %s referenced by session %s", chanID, + id) + } + + // If a closed height has been set, then the channel is closed. + closedHeight := chanDetails.Get(cChanClosedHeight) + if len(closedHeight) > 0 { + return nil + } + + // Otherwise, the channel is not yet closed meaning that the + // session is not yet closable. We break the ForEach by + // returning an error to indicate this. + return errSessionHasOpenChannels + }) + if errors.Is(err, errSessionHasOpenChannels) { + return false, nil + } else if err != nil { + return false, err + } + + return true, nil +} + // CommitUpdate persists the CommittedUpdate provided in the slot for (session, // seqNum). This allows the client to retransmit this update on startup. func (c *ClientDB) CommitUpdate(id *SessionID, @@ -2016,6 +2239,44 @@ func getDBSessionID(sessionsBkt kvdb.RBucket, sessionID SessionID) (uint64, return id, idBytes, nil } +func getRealSessionID(sessIDIndexBkt kvdb.RBucket, dbID uint64) (*SessionID, + error) { + + dbIDBytes, err := writeBigSize(dbID) + if err != nil { + return nil, err + } + + sessIDBytes := sessIDIndexBkt.Get(dbIDBytes) + if len(sessIDBytes) != SessionIDSize { + return nil, fmt.Errorf("session ID not found") + } + + var sessID SessionID + copy(sessID[:], sessIDBytes) + + return &sessID, nil +} + +func getRealChannelID(chanIDIndexBkt kvdb.RBucket, + dbID uint64) (*lnwire.ChannelID, error) { + + dbIDBytes, err := writeBigSize(dbID) + if err != nil { + return nil, err + } + + chanIDBytes := chanIDIndexBkt.Get(dbIDBytes) + if len(chanIDBytes) != 32 { //nolint:gomnd + return nil, fmt.Errorf("channel ID not found") + } + + var chanIDS lnwire.ChannelID + copy(chanIDS[:], chanIDBytes) + + return &chanIDS, nil +} + // writeBigSize will encode the given uint64 as a BigSize byte slice. func writeBigSize(i uint64) ([]byte, error) { var b bytes.Buffer diff --git a/watchtower/wtdb/client_db_test.go b/watchtower/wtdb/client_db_test.go index cd77ec77e..4f5f80749 100644 --- a/watchtower/wtdb/client_db_test.go +++ b/watchtower/wtdb/client_db_test.go @@ -3,6 +3,7 @@ package wtdb_test import ( crand "crypto/rand" "io" + "math/rand" "net" "testing" @@ -17,6 +18,8 @@ import ( "github.com/stretchr/testify/require" ) +const blobType = blob.TypeAltruistCommit + // pseudoAddr is a fake network address to be used for testing purposes. var pseudoAddr = &net.TCPAddr{IP: []byte{0x01, 0x00, 0x00, 0x00}, Port: 9911} @@ -193,6 +196,17 @@ func (h *clientDBHarness) ackUpdate(id *wtdb.SessionID, seqNum uint16, require.ErrorIs(h.t, err, expErr) } +func (h *clientDBHarness) markChannelClosed(id lnwire.ChannelID, + blockHeight uint32, expErr error) []wtdb.SessionID { + + h.t.Helper() + + closableSessions, err := h.db.MarkChannelClosed(id, blockHeight) + require.ErrorIs(h.t, err, expErr) + + return closableSessions +} + // newTower is a helper function that creates a new tower with a randomly // generated public key and inserts it into the client DB. func (h *clientDBHarness) newTower() *wtdb.Tower { @@ -605,6 +619,105 @@ func testCommitUpdate(h *clientDBHarness) { }, nil) } +// testMarkChannelClosed asserts the behaviour of MarkChannelClosed. +func testMarkChannelClosed(h *clientDBHarness) { + tower := h.newTower() + + // Create channel 1. + chanID1 := randChannelID(h.t) + + // Since we have not yet registered the channel, we expect an error + // when attempting to mark it as closed. + h.markChannelClosed(chanID1, 1, wtdb.ErrChannelNotRegistered) + + // Now register the channel. + h.registerChan(chanID1, nil, nil) + + // Since there are still no sessions that would have updates for the + // channel, marking it as closed now should succeed. + h.markChannelClosed(chanID1, 1, nil) + + // Register channel 2. + chanID2 := randChannelID(h.t) + h.registerChan(chanID2, nil, nil) + + // Create session1 with MaxUpdates set to 5. + session1 := h.randSession(h.t, tower.ID, 5) + h.insertSession(session1, nil) + + // Add an update for channel 2 in session 1 and ack it too. + update := randCommittedUpdateForChannel(h.t, chanID2, 1) + lastApplied := h.commitUpdate(&session1.ID, update, nil) + require.Zero(h.t, lastApplied) + h.ackUpdate(&session1.ID, 1, 1, nil) + + // Marking channel 2 now should not result in any closable sessions + // since session 1 is not yet exhausted. + sl := h.markChannelClosed(chanID2, 1, nil) + require.Empty(h.t, sl) + + // Create channel 3 and 4. + chanID3 := randChannelID(h.t) + h.registerChan(chanID3, nil, nil) + + chanID4 := randChannelID(h.t) + h.registerChan(chanID4, nil, nil) + + // Add an update for channel 4 and ack it. + update = randCommittedUpdateForChannel(h.t, chanID4, 2) + lastApplied = h.commitUpdate(&session1.ID, update, nil) + require.EqualValues(h.t, 1, lastApplied) + h.ackUpdate(&session1.ID, 2, 2, nil) + + // Add an update for channel 3 in session 1. But dont ack it yet. + update = randCommittedUpdateForChannel(h.t, chanID2, 3) + lastApplied = h.commitUpdate(&session1.ID, update, nil) + require.EqualValues(h.t, 2, lastApplied) + + // Mark channel 4 as closed & assert that session 1 is not seen as + // closable since it still has committed updates. + sl = h.markChannelClosed(chanID4, 1, nil) + require.Empty(h.t, sl) + + // Now ack the update we added above. + h.ackUpdate(&session1.ID, 3, 3, nil) + + // Mark channel 3 as closed & assert that session 1 is still not seen as + // closable since it is not yet exhausted. + sl = h.markChannelClosed(chanID3, 1, nil) + require.Empty(h.t, sl) + + // Create channel 5 and 6. + chanID5 := randChannelID(h.t) + h.registerChan(chanID5, nil, nil) + + chanID6 := randChannelID(h.t) + h.registerChan(chanID6, nil, nil) + + // Add an update for channel 5 and ack it. + update = randCommittedUpdateForChannel(h.t, chanID5, 4) + lastApplied = h.commitUpdate(&session1.ID, update, nil) + require.EqualValues(h.t, 3, lastApplied) + h.ackUpdate(&session1.ID, 4, 4, nil) + + // Add an update for channel 6 and ack it. + update = randCommittedUpdateForChannel(h.t, chanID6, 5) + lastApplied = h.commitUpdate(&session1.ID, update, nil) + require.EqualValues(h.t, 4, lastApplied) + h.ackUpdate(&session1.ID, 5, 5, nil) + + // The session is no exhausted. + // If we now close channel 5, session 1 should still not be closable + // since it has an update for channel 6 which is still open. + sl = h.markChannelClosed(chanID5, 1, nil) + require.Empty(h.t, sl) + + // Finally, if we close channel 6, session 1 _should_ be in the closable + // list. + sl = h.markChannelClosed(chanID6, 1, nil) + require.ElementsMatch(h.t, sl, []wtdb.SessionID{session1.ID}) +} + // testAckUpdate asserts the behavior of AckUpdate. func testAckUpdate(h *clientDBHarness) { const blobType = blob.TypeAltruistCommit @@ -821,6 +934,10 @@ func TestClientDB(t *testing.T) { name: "ack update", run: testAckUpdate, }, + { + name: "mark channel closed", + run: testMarkChannelClosed, + }, } for _, database := range dbs { @@ -841,12 +958,32 @@ func TestClientDB(t *testing.T) { // randCommittedUpdate generates a random committed update. func randCommittedUpdate(t *testing.T, seqNum uint16) *wtdb.CommittedUpdate { + t.Helper() + + chanID := randChannelID(t) + + return randCommittedUpdateForChannel(t, chanID, seqNum) +} + +func randChannelID(t *testing.T) lnwire.ChannelID { + t.Helper() + var chanID lnwire.ChannelID _, err := io.ReadFull(crand.Reader, chanID[:]) require.NoError(t, err) + return chanID +} + +// randCommittedUpdateForChannel generates a random committed update for the +// given channel ID. +func randCommittedUpdateForChannel(t *testing.T, chanID lnwire.ChannelID, + seqNum uint16) *wtdb.CommittedUpdate { + + t.Helper() + var hint blob.BreachHint - _, err = io.ReadFull(crand.Reader, hint[:]) + _, err := io.ReadFull(crand.Reader, hint[:]) require.NoError(t, err) encBlob := make([]byte, blob.Size(blob.FlagCommitOutputs.Type())) @@ -865,3 +1002,27 @@ func randCommittedUpdate(t *testing.T, seqNum uint16) *wtdb.CommittedUpdate { }, } } + +func (h *clientDBHarness) randSession(t *testing.T, + towerID wtdb.TowerID, maxUpdates uint16) *wtdb.ClientSession { + + t.Helper() + + var id wtdb.SessionID + rand.Read(id[:]) + + return &wtdb.ClientSession{ + ClientSessionBody: wtdb.ClientSessionBody{ + TowerID: towerID, + Policy: wtpolicy.Policy{ + TxPolicy: wtpolicy.TxPolicy{ + BlobType: blobType, + }, + MaxUpdates: maxUpdates, + }, + RewardPkScript: []byte{0x01, 0x02, 0x03}, + KeyIndex: h.nextKeyIndex(towerID, blobType), + }, + ID: id, + } +} diff --git a/watchtower/wtmock/client_db.go b/watchtower/wtmock/client_db.go index 9d38c2da2..2820d74cd 100644 --- a/watchtower/wtmock/client_db.go +++ b/watchtower/wtmock/client_db.go @@ -25,19 +25,26 @@ type rangeIndexArrayMap map[wtdb.SessionID]map[lnwire.ChannelID]*wtdb.RangeIndex type rangeIndexKVStore map[wtdb.SessionID]map[lnwire.ChannelID]*mockKVStore +type channel struct { + summary *wtdb.ClientChanSummary + closedHeight uint32 + sessions map[wtdb.SessionID]bool +} + // ClientDB is a mock, in-memory database or testing the watchtower client // behavior. type ClientDB struct { nextTowerID uint64 // to be used atomically mu sync.Mutex - summaries map[lnwire.ChannelID]wtdb.ClientChanSummary + channels map[lnwire.ChannelID]*channel activeSessions map[wtdb.SessionID]wtdb.ClientSession ackedUpdates rangeIndexArrayMap persistedAckedUpdates rangeIndexKVStore committedUpdates map[wtdb.SessionID][]wtdb.CommittedUpdate towerIndex map[towerPK]wtdb.TowerID towers map[wtdb.TowerID]*wtdb.Tower + closableSessions map[wtdb.SessionID]uint32 nextIndex uint32 indexes map[keyIndexKey]uint32 @@ -47,9 +54,7 @@ type ClientDB struct { // NewClientDB initializes a new mock ClientDB. func NewClientDB() *ClientDB { return &ClientDB{ - summaries: make( - map[lnwire.ChannelID]wtdb.ClientChanSummary, - ), + channels: make(map[lnwire.ChannelID]*channel), activeSessions: make( map[wtdb.SessionID]wtdb.ClientSession, ), @@ -58,10 +63,11 @@ func NewClientDB() *ClientDB { committedUpdates: make( map[wtdb.SessionID][]wtdb.CommittedUpdate, ), - towerIndex: make(map[towerPK]wtdb.TowerID), - towers: make(map[wtdb.TowerID]*wtdb.Tower), - indexes: make(map[keyIndexKey]uint32), - legacyIndexes: make(map[wtdb.TowerID]uint32), + towerIndex: make(map[towerPK]wtdb.TowerID), + towers: make(map[wtdb.TowerID]*wtdb.Tower), + indexes: make(map[keyIndexKey]uint32), + legacyIndexes: make(map[wtdb.TowerID]uint32), + closableSessions: make(map[wtdb.SessionID]uint32), } } @@ -503,6 +509,13 @@ func (m *ClientDB) AckUpdate(id *wtdb.SessionID, seqNum, continue } + // Add sessionID to channel. + channel, ok := m.channels[update.BackupID.ChanID] + if !ok { + return wtdb.ErrChannelNotRegistered + } + channel.sessions[*id] = true + // Remove the committed update from disk and mark the update as // acked. The tower last applied value is also recorded to send // along with the next update. @@ -545,15 +558,107 @@ func (m *ClientDB) FetchChanSummaries() (wtdb.ChannelSummaries, error) { defer m.mu.Unlock() summaries := make(map[lnwire.ChannelID]wtdb.ClientChanSummary) - for chanID, summary := range m.summaries { + for chanID, channel := range m.channels { summaries[chanID] = wtdb.ClientChanSummary{ - SweepPkScript: cloneBytes(summary.SweepPkScript), + SweepPkScript: cloneBytes( + channel.summary.SweepPkScript, + ), } } return summaries, nil } +// MarkChannelClosed will mark a registered channel as closed by setting +// its closed-height as the given block height. It returns a list of +// session IDs for sessions that are now considered closable due to the +// close of this channel. +func (m *ClientDB) MarkChannelClosed(chanID lnwire.ChannelID, + blockHeight uint32) ([]wtdb.SessionID, error) { + + m.mu.Lock() + defer m.mu.Unlock() + + channel, ok := m.channels[chanID] + if !ok { + return nil, wtdb.ErrChannelNotRegistered + } + + // If there are no sessions for this channel, the channel details can be + // deleted. + if len(channel.sessions) == 0 { + delete(m.channels, chanID) + return nil, nil + } + + // Mark the channel as closed. + channel.closedHeight = blockHeight + + // Now iterate through all the sessions of the channel to check if any + // of them are closeable. + var closableSessions []wtdb.SessionID + for sessID := range channel.sessions { + isClosable, err := m.isSessionClosable(sessID) + if err != nil { + return nil, err + } + + if !isClosable { + continue + } + + closableSessions = append(closableSessions, sessID) + + // Add session to "closableSessions" list and add the block + // height that this last channel was closed in. This will be + // used in future to determine when we should delete the + // session. + m.closableSessions[sessID] = blockHeight + } + + return closableSessions, nil +} + +// isSessionClosable returns true if a session is considered closable. A session +// is considered closable only if: +// 1) It has no un-acked updates +// 2) It is exhausted (ie it cant accept any more updates) +// 3) All the channels that it has acked-updates for are closed. +func (m *ClientDB) isSessionClosable(id wtdb.SessionID) (bool, error) { + // The session is not closable if it has un-acked updates. + if len(m.committedUpdates[id]) > 0 { + return false, nil + } + + sess, ok := m.activeSessions[id] + if !ok { + return false, wtdb.ErrClientSessionNotFound + } + + // The session is not closable if it is not yet exhausted. + if sess.SeqNum != sess.Policy.MaxUpdates { + return false, nil + } + + // Iterate over each of the channels that the session has acked-updates + // for. If any of those channels are not closed, then the session is + // not yet closable. + for chanID := range m.ackedUpdates[id] { + channel, ok := m.channels[chanID] + if !ok { + continue + } + + // Channel is not yet closed, and so we can not yet delete the + // session. + if channel.closedHeight == 0 { + return false, nil + } + } + + return true, nil +} + // GetClientSession loads the ClientSession with the given ID from the DB. func (m *ClientDB) GetClientSession(id wtdb.SessionID, opts ...wtdb.ClientSessionListOption) (*wtdb.ClientSession, error) { @@ -595,12 +700,15 @@ func (m *ClientDB) RegisterChannel(chanID lnwire.ChannelID, m.mu.Lock() defer m.mu.Unlock() - if _, ok := m.summaries[chanID]; ok { + if _, ok := m.channels[chanID]; ok { return wtdb.ErrChannelAlreadyRegistered } - m.summaries[chanID] = wtdb.ClientChanSummary{ - SweepPkScript: cloneBytes(sweepPkScript), + m.channels[chanID] = &channel{ + summary: &wtdb.ClientChanSummary{ + SweepPkScript: cloneBytes(sweepPkScript), + }, + sessions: make(map[wtdb.SessionID]bool), } return nil From 3577c829d316685da24d7e5b39b01f1061287b0e Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 21 Oct 2022 11:22:20 +0200 Subject: [PATCH 40/87] watchtower: add ListClosableSessions method This commit adds a new ListClosableSessions method to the tower client DB. This method will return a map of sessionIDs to block heights. The IDs belong to sessions that are considered closable and the block heights are the block height at which the last associated channel for the session was closed in. --- watchtower/wtclient/interface.go | 4 ++++ watchtower/wtdb/client_db.go | 40 +++++++++++++++++++++++++++++++ watchtower/wtdb/client_db_test.go | 18 +++++++++++++- watchtower/wtmock/client_db.go | 14 +++++++++++ 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/watchtower/wtclient/interface.go b/watchtower/wtclient/interface.go index e5fc5d22b..b5d2418ab 100644 --- a/watchtower/wtclient/interface.go +++ b/watchtower/wtclient/interface.go @@ -95,6 +95,10 @@ type DB interface { MarkChannelClosed(chanID lnwire.ChannelID, blockHeight uint32) ( []wtdb.SessionID, error) + // ListClosableSessions fetches and returns the IDs for all sessions + // marked as closable. + ListClosableSessions() (map[wtdb.SessionID]uint32, error) + // RegisterChannel registers a channel for use within the client // database. For now, all that is stored in the channel summary is the // sweep pkscript that we'd like any tower sweeps to pay into. In the diff --git a/watchtower/wtdb/client_db.go b/watchtower/wtdb/client_db.go index d88fd631e..4a74c7bb4 100644 --- a/watchtower/wtdb/client_db.go +++ b/watchtower/wtdb/client_db.go @@ -1385,6 +1385,46 @@ func (c *ClientDB) MarkBackupIneligible(chanID lnwire.ChannelID, return nil } +// ListClosableSessions fetches and returns the IDs for all sessions marked as +// closable. +func (c *ClientDB) ListClosableSessions() (map[SessionID]uint32, error) { + sessions := make(map[SessionID]uint32) + err := kvdb.View(c.db, func(tx kvdb.RTx) error { + csBkt := tx.ReadBucket(cClosableSessionsBkt) + if csBkt == nil { + return ErrUninitializedDB + } + + sessIDIndexBkt := tx.ReadBucket(cSessionIDIndexBkt) + if sessIDIndexBkt == nil { + return ErrUninitializedDB + } + + return csBkt.ForEach(func(dbIDBytes, heightBytes []byte) error { + dbID, err := readBigSize(dbIDBytes) + if err != nil { + return err + } + + sessID, err := getRealSessionID(sessIDIndexBkt, dbID) + if err != nil { + return err + } + + sessions[*sessID] = byteOrder.Uint32(heightBytes) + + return nil + }) + }, func() { + sessions = make(map[SessionID]uint32) + }) + if err != nil { + return nil, err + } + + return sessions, nil +} + // MarkChannelClosed will mark a registered channel as closed by setting its // closed-height as the given block height. It returns a list of session IDs for // sessions that are now considered closable due to the close of this channel. diff --git a/watchtower/wtdb/client_db_test.go b/watchtower/wtdb/client_db_test.go index 4f5f80749..73f4e5550 100644 --- a/watchtower/wtdb/client_db_test.go +++ b/watchtower/wtdb/client_db_test.go @@ -207,6 +207,17 @@ func (h *clientDBHarness) markChannelClosed(id lnwire.ChannelID, return closableSessions } +func (h *clientDBHarness) listClosableSessions( + expErr error) map[wtdb.SessionID]uint32 { + + h.t.Helper() + + closableSessions, err := h.db.ListClosableSessions() + require.ErrorIs(h.t, err, expErr) + + return closableSessions +} + // newTower is a helper function that creates a new tower with a randomly // generated public key and inserts it into the client DB. func (h *clientDBHarness) newTower() *wtdb.Tower { @@ -711,11 +722,16 @@ func testMarkChannelClosed(h *clientDBHarness) { // since it has an update for channel 6 which is still open. sl = h.markChannelClosed(chanID5, 1, nil) require.Empty(h.t, sl) + require.Empty(h.t, h.listClosableSessions(nil)) // Finally, if we close channel 6, session 1 _should_ be in the closable // list. - sl = h.markChannelClosed(chanID6, 1, nil) + sl = h.markChannelClosed(chanID6, 100, nil) require.ElementsMatch(h.t, sl, []wtdb.SessionID{session1.ID}) + slMap := h.listClosableSessions(nil) + require.InDeltaMapValues(h.t, slMap, map[wtdb.SessionID]uint32{ + session1.ID: 100, + }, 0) } // testAckUpdate asserts the behavior of AckUpdate. diff --git a/watchtower/wtmock/client_db.go b/watchtower/wtmock/client_db.go index 2820d74cd..f439e9182 100644 --- a/watchtower/wtmock/client_db.go +++ b/watchtower/wtmock/client_db.go @@ -551,6 +551,20 @@ func (m *ClientDB) AckUpdate(id *wtdb.SessionID, seqNum, return wtdb.ErrCommittedUpdateNotFound } +// ListClosableSessions fetches and returns the IDs for all sessions marked as +// closable. +func (m *ClientDB) ListClosableSessions() (map[wtdb.SessionID]uint32, error) { + m.mu.Lock() + defer m.mu.Unlock() + + cs := make(map[wtdb.SessionID]uint32, len(m.closableSessions)) + for id, height := range m.closableSessions { + cs[id] = height + } + + return cs, nil +} + // FetchChanSummaries loads a mapping from all registered channels to their // channel summaries. func (m *ClientDB) FetchChanSummaries() (wtdb.ChannelSummaries, error) { From e432261dab3593f04f8c9bc30e161bb3bb27b0bf Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 21 Oct 2022 11:23:20 +0200 Subject: [PATCH 41/87] watchtower: add DeleteSession method Add a DeleteSession method to the tower client DB. This can be used to delete a closable session along with any references to the session. --- watchtower/wtclient/interface.go | 6 + watchtower/wtdb/client_db.go | 181 ++++++++++++++++++++++++++++++ watchtower/wtdb/client_db_test.go | 15 +++ watchtower/wtmock/client_db.go | 28 +++++ 4 files changed, 230 insertions(+) diff --git a/watchtower/wtclient/interface.go b/watchtower/wtclient/interface.go index b5d2418ab..a69e9980f 100644 --- a/watchtower/wtclient/interface.go +++ b/watchtower/wtclient/interface.go @@ -99,6 +99,12 @@ type DB interface { // marked as closable. ListClosableSessions() (map[wtdb.SessionID]uint32, error) + // DeleteSession can be called when a session should be deleted from the + // DB. All references to the session will also be deleted from the DB. + // A session will only be deleted if it was previously marked as + // closable. + DeleteSession(id wtdb.SessionID) error + // RegisterChannel registers a channel for use within the client // database. For now, all that is stored in the channel summary is the // sweep pkscript that we'd like any tower sweeps to pay into. In the diff --git a/watchtower/wtdb/client_db.go b/watchtower/wtdb/client_db.go index 4a74c7bb4..c3e5447d6 100644 --- a/watchtower/wtdb/client_db.go +++ b/watchtower/wtdb/client_db.go @@ -168,6 +168,10 @@ var ( // not pass the filter func provided by the caller. ErrSessionFailedFilterFn = errors.New("session failed filter func") + // ErrSessionNotClosable is returned when a session is not found in the + // closable list. + ErrSessionNotClosable = errors.New("session is not closable") + // errSessionHasOpenChannels is an error used to indicate that a // session has updates for channels that are still open. errSessionHasOpenChannels = errors.New("session has open channels") @@ -175,6 +179,11 @@ var ( // errSessionHasUnackedUpdates is an error used to indicate that a // session has un-acked updates. errSessionHasUnackedUpdates = errors.New("session has un-acked updates") + + // errChannelHasMoreSessions is an error used to indicate that a channel + // has updates in other non-closed sessions. + errChannelHasMoreSessions = errors.New("channel has updates in " + + "other sessions") ) // NewBoltBackendCreator returns a function that creates a new bbolt backend for @@ -1053,6 +1062,7 @@ func (c *ClientDB) GetClientSession(id SessionID, } sess = session + return nil }, func() {}) @@ -1425,6 +1435,177 @@ func (c *ClientDB) ListClosableSessions() (map[SessionID]uint32, error) { return sessions, nil } +// DeleteSession can be called when a session should be deleted from the DB. +// All references to the session will also be deleted from the DB. Note that a +// session will only be deleted if was previously marked as closable. +func (c *ClientDB) DeleteSession(id SessionID) error { + return kvdb.Update(c.db, func(tx kvdb.RwTx) error { + sessionsBkt := tx.ReadWriteBucket(cSessionBkt) + if sessionsBkt == nil { + return ErrUninitializedDB + } + + closableBkt := tx.ReadWriteBucket(cClosableSessionsBkt) + if closableBkt == nil { + return ErrUninitializedDB + } + + chanDetailsBkt := tx.ReadWriteBucket(cChanDetailsBkt) + if chanDetailsBkt == nil { + return ErrUninitializedDB + } + + sessIDIndexBkt := tx.ReadWriteBucket(cSessionIDIndexBkt) + if sessIDIndexBkt == nil { + return ErrUninitializedDB + } + + chanIDIndexBkt := tx.ReadWriteBucket(cChanIDIndexBkt) + if chanIDIndexBkt == nil { + return ErrUninitializedDB + } + + towerToSessBkt := tx.ReadWriteBucket(cTowerToSessionIndexBkt) + if towerToSessBkt == nil { + return ErrUninitializedDB + } + + // Get the sub-bucket for this session ID. If it does not exist + // then the session has already been deleted and so our work is + // done. + sessionBkt := sessionsBkt.NestedReadBucket(id[:]) + if sessionBkt == nil { + return nil + } + + _, dbIDBytes, err := getDBSessionID(sessionsBkt, id) + if err != nil { + return err + } + + // First we check if the session has actually been marked as + // closable. + if closableBkt.Get(dbIDBytes) == nil { + return ErrSessionNotClosable + } + + sess, err := getClientSessionBody(sessionsBkt, id[:]) + if err != nil { + return err + } + + // Delete from the tower-to-sessionID index. + towerIndexBkt := towerToSessBkt.NestedReadWriteBucket( + sess.TowerID.Bytes(), + ) + if towerIndexBkt == nil { + return fmt.Errorf("no entry in the tower-to-session "+ + "index found for tower ID %v", sess.TowerID) + } + + err = towerIndexBkt.Delete(id[:]) + if err != nil { + return err + } + + // Delete entry from session ID index. + err = sessIDIndexBkt.Delete(dbIDBytes) + if err != nil { + return err + } + + // Delete the entry from the closable sessions index. + err = closableBkt.Delete(dbIDBytes) + if err != nil { + return err + } + + // Get the acked updates range index for the session. This is + // used to get the list of channels that the session has updates + // for. + ackRanges := sessionBkt.NestedReadBucket(cSessionAckRangeIndex) + if ackRanges == nil { + // A session would only be considered closable if it + // was exhausted. Meaning that it should not be the + // case that it has no acked-updates. + return fmt.Errorf("cannot delete session %s since it "+ + "is not yet exhausted", id) + } + + // For each of the channels, delete the session ID entry. + err = ackRanges.ForEach(func(chanDBID, _ []byte) error { + chanDBIDInt, err := readBigSize(chanDBID) + if err != nil { + return err + } + + chanID, err := getRealChannelID( + chanIDIndexBkt, chanDBIDInt, + ) + if err != nil { + return err + } + + chanDetails := chanDetailsBkt.NestedReadWriteBucket( + chanID[:], + ) + if chanDetails == nil { + return ErrChannelNotRegistered + } + + chanSessions := chanDetails.NestedReadWriteBucket( + cChanSessions, + ) + if chanSessions == nil { + return fmt.Errorf("no session list found for "+ + "channel %s", chanID) + } + + // Check that this session was actually listed in the + // session list for this channel. + if len(chanSessions.Get(dbIDBytes)) == 0 { + return fmt.Errorf("session %s not found in "+ + "the session list for channel %s", id, + chanID) + } + + // If it was, then delete it. + err = chanSessions.Delete(dbIDBytes) + if err != nil { + return err + } + + // If this was the last session for this channel, we can + // now delete the channel details for this channel + // completely. + err = chanSessions.ForEach(func(_, _ []byte) error { + return errChannelHasMoreSessions + }) + if errors.Is(err, errChannelHasMoreSessions) { + return nil + } else if err != nil { + return err + } + + // Delete the channel's entry from the channel-id-index. + dbID := chanDetails.Get(cChanDBID) + err = chanIDIndexBkt.Delete(dbID) + if err != nil { + return err + } + + // Delete the channel details. + return chanDetailsBkt.DeleteNestedBucket(chanID[:]) + }) + if err != nil { + return err + } + + // Delete the actual session. + return sessionsBkt.DeleteNestedBucket(id[:]) + }, func() {}) +} + // MarkChannelClosed will mark a registered channel as closed by setting its // closed-height as the given block height. It returns a list of session IDs for // sessions that are now considered closable due to the close of this channel. diff --git a/watchtower/wtdb/client_db_test.go b/watchtower/wtdb/client_db_test.go index 73f4e5550..b3d241175 100644 --- a/watchtower/wtdb/client_db_test.go +++ b/watchtower/wtdb/client_db_test.go @@ -218,6 +218,13 @@ func (h *clientDBHarness) listClosableSessions( return closableSessions } +func (h *clientDBHarness) deleteSession(id wtdb.SessionID, expErr error) { + h.t.Helper() + + err := h.db.DeleteSession(id) + require.ErrorIs(h.t, err, expErr) +} + // newTower is a helper function that creates a new tower with a randomly // generated public key and inserts it into the client DB. func (h *clientDBHarness) newTower() *wtdb.Tower { @@ -724,6 +731,10 @@ func testMarkChannelClosed(h *clientDBHarness) { require.Empty(h.t, sl) require.Empty(h.t, h.listClosableSessions(nil)) + // Also check that attempting to delete the session will fail since it + // is not yet considered closable. + h.deleteSession(session1.ID, wtdb.ErrSessionNotClosable) + // Finally, if we close channel 6, session 1 _should_ be in the closable // list. sl = h.markChannelClosed(chanID6, 100, nil) @@ -732,6 +743,10 @@ func testMarkChannelClosed(h *clientDBHarness) { require.InDeltaMapValues(h.t, slMap, map[wtdb.SessionID]uint32{ session1.ID: 100, }, 0) + + // Assert that we now can delete the session. + h.deleteSession(session1.ID, nil) + require.Empty(h.t, h.listClosableSessions(nil)) } // testAckUpdate asserts the behavior of AckUpdate. diff --git a/watchtower/wtmock/client_db.go b/watchtower/wtmock/client_db.go index f439e9182..7213f17b6 100644 --- a/watchtower/wtmock/client_db.go +++ b/watchtower/wtmock/client_db.go @@ -703,6 +703,34 @@ func (m *ClientDB) GetClientSession(id wtdb.SessionID, return &session, nil } +// DeleteSession can be called when a session should be deleted from the DB. +// All references to the session will also be deleted from the DB. Note that a +// session will only be deleted if it is considered closable. +func (m *ClientDB) DeleteSession(id wtdb.SessionID) error { + m.mu.Lock() + defer m.mu.Unlock() + + _, ok := m.closableSessions[id] + if !ok { + return wtdb.ErrSessionNotClosable + } + + // For each of the channels, delete the session ID entry. + for chanID := range m.ackedUpdates[id] { + c, ok := m.channels[chanID] + if !ok { + return wtdb.ErrChannelNotRegistered + } + + delete(c.sessions, id) + } + + delete(m.closableSessions, id) + delete(m.activeSessions, id) + + return nil +} + // RegisterChannel registers a channel for use within the client database. For // now, all that is stored in the channel summary is the sweep pkscript that // we'd like any tower sweeps to pay into. In the future, this will be extended From 0ed5c750c8bec4ca66254aee26dcfffcb05298a8 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 21 Oct 2022 11:24:02 +0200 Subject: [PATCH 42/87] watchtower: add GetTower to tower iterator Add a GetTower method to the tower iterator. --- watchtower/wtclient/candidate_iterator.go | 18 ++++++++++++++ .../wtclient/candidate_iterator_test.go | 24 ++++++++++++++++--- watchtower/wtclient/errors.go | 8 ++++++- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/watchtower/wtclient/candidate_iterator.go b/watchtower/wtclient/candidate_iterator.go index faf3169c6..10ef86465 100644 --- a/watchtower/wtclient/candidate_iterator.go +++ b/watchtower/wtclient/candidate_iterator.go @@ -29,6 +29,10 @@ type TowerCandidateIterator interface { // candidates available as long as they remain in the set. Reset() error + // GetTower gets the tower with the given ID from the iterator. If no + // such tower is found then ErrTowerNotInIterator is returned. + GetTower(id wtdb.TowerID) (*Tower, error) + // Next returns the next candidate tower. The iterator is not required // to return results in any particular order. If no more candidates are // available, ErrTowerCandidatesExhausted is returned. @@ -76,6 +80,20 @@ func (t *towerListIterator) Reset() error { return nil } +// GetTower gets the tower with the given ID from the iterator. If no such tower +// is found then ErrTowerNotInIterator is returned. +func (t *towerListIterator) GetTower(id wtdb.TowerID) (*Tower, error) { + t.mu.Lock() + defer t.mu.Unlock() + + tower, ok := t.candidates[id] + if !ok { + return nil, ErrTowerNotInIterator + } + + return tower, nil +} + // Next returns the next candidate tower. This iterator will always return // candidates in the order given when the iterator was instantiated. If no more // candidates are available, ErrTowerCandidatesExhausted is returned. diff --git a/watchtower/wtclient/candidate_iterator_test.go b/watchtower/wtclient/candidate_iterator_test.go index 7fe6ba723..70dfb7505 100644 --- a/watchtower/wtclient/candidate_iterator_test.go +++ b/watchtower/wtclient/candidate_iterator_test.go @@ -83,9 +83,15 @@ func assertNextCandidate(t *testing.T, i TowerCandidateIterator, c *Tower) { tower, err := i.Next() require.NoError(t, err) - require.True(t, tower.IdentityKey.IsEqual(c.IdentityKey)) - require.Equal(t, tower.ID, c.ID) - require.Equal(t, tower.Addresses.GetAll(), c.Addresses.GetAll()) + assertTowersEqual(t, c, tower) +} + +func assertTowersEqual(t *testing.T, expected, actual *Tower) { + t.Helper() + + require.True(t, expected.IdentityKey.IsEqual(actual.IdentityKey)) + require.Equal(t, expected.ID, actual.ID) + require.Equal(t, expected.Addresses.GetAll(), actual.Addresses.GetAll()) } // TestTowerCandidateIterator asserts the internal state of a @@ -155,4 +161,16 @@ func TestTowerCandidateIterator(t *testing.T) { towerIterator.AddCandidate(secondTower) assertActiveCandidate(t, towerIterator, secondTower, true) assertNextCandidate(t, towerIterator, secondTower) + + // Assert that the GetTower correctly returns the tower too. + tower, err := towerIterator.GetTower(secondTower.ID) + require.NoError(t, err) + assertTowersEqual(t, secondTower, tower) + + // Now remove the tower and assert that GetTower returns expected error. + err = towerIterator.RemoveCandidate(secondTower.ID, nil) + require.NoError(t, err) + + _, err = towerIterator.GetTower(secondTower.ID) + require.ErrorIs(t, err, ErrTowerNotInIterator) } diff --git a/watchtower/wtclient/errors.go b/watchtower/wtclient/errors.go index f496074bf..c6884bb35 100644 --- a/watchtower/wtclient/errors.go +++ b/watchtower/wtclient/errors.go @@ -1,6 +1,8 @@ package wtclient -import "errors" +import ( + "errors" +) var ( // ErrClientExiting signals that the watchtower client is shutting down. @@ -11,6 +13,10 @@ var ( ErrTowerCandidatesExhausted = errors.New("exhausted all tower " + "candidates") + // ErrTowerNotInIterator is returned when a requested tower was not + // found in the iterator. + ErrTowerNotInIterator = errors.New("tower not in iterator") + // ErrPermanentTowerFailure signals that the tower has reported that it // has permanently failed or the client believes this has happened based // on the tower's behavior. From 41e36c7ec788178fc111a26ea087fb12e64449ba Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 21 Oct 2022 11:24:46 +0200 Subject: [PATCH 43/87] watchtower: add wtclient.ClientSession constructor --- watchtower/wtclient/client.go | 22 +++++++--------------- watchtower/wtclient/interface.go | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/watchtower/wtclient/client.go b/watchtower/wtclient/client.go index 32622b7da..fda072840 100644 --- a/watchtower/wtclient/client.go +++ b/watchtower/wtclient/client.go @@ -435,27 +435,19 @@ func getTowerAndSessionCandidates(db DB, keyRing ECDHKeyRing, } for _, s := range sessions { - towerKeyDesc, err := keyRing.DeriveKey( - keychain.KeyLocator{ - Family: keychain.KeyFamilyTowerSession, - Index: s.KeyIndex, - }, + if !sessionFilter(s) { + continue + } + + cs, err := NewClientSessionFromDBSession( + s, tower, keyRing, ) if err != nil { return nil, err } - sessionKeyECDH := keychain.NewPubKeyECDH( - towerKeyDesc, keyRing, - ) - // Add the session to the set of candidate sessions. - candidateSessions[s.ID] = &ClientSession{ - ID: s.ID, - ClientSessionBody: s.ClientSessionBody, - Tower: tower, - SessionKeyECDH: sessionKeyECDH, - } + candidateSessions[s.ID] = cs perActiveTower(tower) } diff --git a/watchtower/wtclient/interface.go b/watchtower/wtclient/interface.go index a69e9980f..4dd9176ae 100644 --- a/watchtower/wtclient/interface.go +++ b/watchtower/wtclient/interface.go @@ -198,3 +198,30 @@ type ClientSession struct { // key used to connect to the watchtower. SessionKeyECDH keychain.SingleKeyECDH } + +// NewClientSessionFromDBSession converts a wtdb.ClientSession to a +// ClientSession. +func NewClientSessionFromDBSession(s *wtdb.ClientSession, tower *Tower, + keyRing ECDHKeyRing) (*ClientSession, error) { + + towerKeyDesc, err := keyRing.DeriveKey( + keychain.KeyLocator{ + Family: keychain.KeyFamilyTowerSession, + Index: s.KeyIndex, + }, + ) + if err != nil { + return nil, err + } + + sessionKeyECDH := keychain.NewPubKeyECDH( + towerKeyDesc, keyRing, + ) + + return &ClientSession{ + ID: s.ID, + ClientSessionBody: s.ClientSessionBody, + Tower: tower, + SessionKeyECDH: sessionKeyECDH, + }, nil +} From 16008c00321c1fb37b23f8e4d94744ab535a2870 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 21 Oct 2022 11:29:25 +0200 Subject: [PATCH 44/87] watchtower: handle channel closures Add a channel-close handler that waits for channel close events and marks channels as closed in the tower client DB. --- server.go | 16 ++ watchtower/wtclient/client.go | 147 ++++++++++- watchtower/wtclient/client_test.go | 406 +++++++++++++++++++++++------ 3 files changed, 483 insertions(+), 86 deletions(-) diff --git a/server.go b/server.go index 7758ebe8c..61b31ffa6 100644 --- a/server.go +++ b/server.go @@ -1512,7 +1512,16 @@ func newServer(cfg *Config, listenAddrs []net.Addr, ) } + fetchClosedChannel := s.chanStateDB.FetchClosedChannelForID + s.towerClient, err = wtclient.New(&wtclient.Config{ + FetchClosedChannel: fetchClosedChannel, + SubscribeChannelEvents: func() (subscribe.Subscription, + error) { + + return s.channelNotifier. + SubscribeChannelEvents() + }, Signer: cc.Wallet.Cfg.Signer, NewAddress: newSweepPkScriptGen(cc.Wallet), SecretKeyRing: s.cc.KeyRing, @@ -1536,6 +1545,13 @@ func newServer(cfg *Config, listenAddrs []net.Addr, blob.Type(blob.FlagAnchorChannel) s.anchorTowerClient, err = wtclient.New(&wtclient.Config{ + FetchClosedChannel: fetchClosedChannel, + SubscribeChannelEvents: func() (subscribe.Subscription, + error) { + + return s.channelNotifier. + SubscribeChannelEvents() + }, Signer: cc.Wallet.Cfg.Signer, NewAddress: newSweepPkScriptGen(cc.Wallet), SecretKeyRing: s.cc.KeyRing, diff --git a/watchtower/wtclient/client.go b/watchtower/wtclient/client.go index fda072840..c0a4c2331 100644 --- a/watchtower/wtclient/client.go +++ b/watchtower/wtclient/client.go @@ -2,6 +2,7 @@ package wtclient import ( "bytes" + "errors" "fmt" "net" "sync" @@ -12,10 +13,12 @@ import ( "github.com/btcsuite/btclog" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/channelnotifier" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/subscribe" "github.com/lightningnetwork/lnd/tor" "github.com/lightningnetwork/lnd/watchtower/wtdb" "github.com/lightningnetwork/lnd/watchtower/wtpolicy" @@ -146,6 +149,16 @@ type Config struct { // transaction. Signer input.Signer + // SubscribeChannelEvents can be used to subscribe to channel event + // notifications. + SubscribeChannelEvents func() (subscribe.Subscription, error) + + // FetchClosedChannel can be used to fetch the info about a closed + // channel. If the channel is not found or not yet closed then + // channeldb.ErrClosedChannelNotFound will be returned. + FetchClosedChannel func(cid lnwire.ChannelID) ( + *channeldb.ChannelCloseSummary, error) + // NewAddress generates a new on-chain sweep pkscript. NewAddress func() ([]byte, error) @@ -269,6 +282,7 @@ type TowerClient struct { staleTowers chan *staleTowerMsg wg sync.WaitGroup + quit chan struct{} forceQuit chan struct{} } @@ -319,6 +333,7 @@ func New(config *Config) (*TowerClient, error) { newTowers: make(chan *newTowerMsg), staleTowers: make(chan *staleTowerMsg), forceQuit: make(chan struct{}), + quit: make(chan struct{}), } // perUpdate is a callback function that will be used to inspect the @@ -364,7 +379,7 @@ func New(config *Config) (*TowerClient, error) { return } - log.Infof("Using private watchtower %s, offering policy %s", + c.log.Infof("Using private watchtower %s, offering policy %s", tower, cfg.Policy) // Add the tower to the set of candidate towers. @@ -540,10 +555,45 @@ func (c *TowerClient) Start() error { } } + chanSub, err := c.cfg.SubscribeChannelEvents() + if err != nil { + returnErr = err + return + } + + // Iterate over the list of registered channels and check if + // any of them can be marked as closed. + for id := range c.summaries { + isClosed, closedHeight, err := c.isChannelClosed(id) + if err != nil { + returnErr = err + return + } + + if !isClosed { + continue + } + + _, err = c.cfg.DB.MarkChannelClosed(id, closedHeight) + if err != nil { + c.log.Errorf("could not mark channel(%s) as "+ + "closed: %v", id, err) + + continue + } + + // Since the channel has been marked as closed, we can + // also remove it from the channel summaries map. + delete(c.summaries, id) + } + + c.wg.Add(1) + go c.handleChannelCloses(chanSub) + // Now start the session negotiator, which will allow us to // request new session as soon as the backupDispatcher starts // up. - err := c.negotiator.Start() + err = c.negotiator.Start() if err != nil { returnErr = err return @@ -591,6 +641,7 @@ func (c *TowerClient) Stop() error { // dispatcher to exit. The backup queue will signal it's // completion to the dispatcher, which releases the wait group // after all tasks have been assigned to session queues. + close(c.quit) c.wg.Wait() // 4. Since all valid tasks have been assigned to session @@ -772,6 +823,82 @@ func (c *TowerClient) nextSessionQueue() (*sessionQueue, error) { return c.getOrInitActiveQueue(candidateSession, updates), nil } +// handleChannelCloses listens for channel close events and marks channels as +// closed in the DB. +// +// NOTE: This method MUST be run as a goroutine. +func (c *TowerClient) handleChannelCloses(chanSub subscribe.Subscription) { + defer c.wg.Done() + + c.log.Debugf("Starting channel close handler") + defer c.log.Debugf("Stopping channel close handler") + + for { + select { + case update, ok := <-chanSub.Updates(): + if !ok { + c.log.Debugf("Channel notifier has exited") + return + } + + // We only care about channel-close events. + event, ok := update.(channelnotifier.ClosedChannelEvent) + if !ok { + continue + } + + chanID := lnwire.NewChanIDFromOutPoint( + &event.CloseSummary.ChanPoint, + ) + + c.log.Debugf("Received ClosedChannelEvent for "+ + "channel: %s", chanID) + + err := c.handleClosedChannel( + chanID, event.CloseSummary.CloseHeight, + ) + if err != nil { + c.log.Errorf("Could not handle channel close "+ + "event for channel(%s): %v", chanID, + err) + } + + case <-c.forceQuit: + return + + case <-c.quit: + return + } + } +} + +// handleClosedChannel handles the closure of a single channel. It will mark the +// channel as closed in the DB. +func (c *TowerClient) handleClosedChannel(chanID lnwire.ChannelID, + closeHeight uint32) error { + + c.backupMu.Lock() + defer c.backupMu.Unlock() + + // We only care about channels registered with the tower client. + if _, ok := c.summaries[chanID]; !ok { + return nil + } + + c.log.Debugf("Marking channel(%s) as closed", chanID) + + _, err := c.cfg.DB.MarkChannelClosed(chanID, closeHeight) + if err != nil { + return fmt.Errorf("could not mark channel(%s) as closed: %w", + chanID, err) + } + + delete(c.summaries, chanID) + delete(c.chanCommitHeights, chanID) + + return nil +} + // backupDispatcher processes events coming from the taskPipeline and is // responsible for detecting when the client needs to renegotiate a session to // fulfill continuing demand. The event loop exits after all tasks have been @@ -1145,6 +1272,22 @@ func (c *TowerClient) initActiveQueue(s *ClientSession, return sq } +// isChanClosed can be used to check if the channel with the given ID has been +// closed. If it has been, the block height in which its closing transaction was +// mined will also be returned. +func (c *TowerClient) isChannelClosed(id lnwire.ChannelID) (bool, uint32, + error) { + + chanSum, err := c.cfg.FetchClosedChannel(id) + if errors.Is(err, channeldb.ErrClosedChannelNotFound) { + return false, 0, nil + } else if err != nil { + return false, 0, err + } + + return true, chanSum.CloseHeight, nil +} + // AddTower adds a new watchtower reachable at the given address and considers // it for new sessions. If the watchtower already exists, then any new addresses // included will be considered when dialing it for session negotiations and diff --git a/watchtower/wtclient/client_test.go b/watchtower/wtclient/client_test.go index 1490c6d10..29c4e7a53 100644 --- a/watchtower/wtclient/client_test.go +++ b/watchtower/wtclient/client_test.go @@ -1,6 +1,7 @@ package wtclient_test import ( + "bytes" "encoding/binary" "errors" "fmt" @@ -16,11 +17,13 @@ import ( "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/channelnotifier" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/subscribe" "github.com/lightningnetwork/lnd/tor" "github.com/lightningnetwork/lnd/watchtower/blob" "github.com/lightningnetwork/lnd/watchtower/wtclient" @@ -393,8 +396,12 @@ type testHarness struct { server *wtserver.Server net *mockNet - mu sync.Mutex - channels map[lnwire.ChannelID]*mockChannel + channelEvents *mockSubscription + sendUpdatesOn bool + + mu sync.Mutex + channels map[lnwire.ChannelID]*mockChannel + closedChannels map[lnwire.ChannelID]uint32 quit chan struct{} } @@ -441,13 +448,50 @@ func newHarness(t *testing.T, cfg harnessCfg) *testHarness { mockNet := newMockNet() clientDB := wtmock.NewClientDB() - clientCfg := &wtclient.Config{ - Signer: signer, - Dial: mockNet.Dial, - DB: clientDB, - AuthDial: mockNet.AuthDial, - SecretKeyRing: wtmock.NewSecretKeyRing(), - Policy: cfg.policy, + h := &testHarness{ + t: t, + cfg: cfg, + signer: signer, + capacity: cfg.localBalance + cfg.remoteBalance, + clientDB: clientDB, + serverAddr: towerAddr, + serverDB: serverDB, + serverCfg: serverCfg, + net: mockNet, + channelEvents: newMockSubscription(t), + channels: make(map[lnwire.ChannelID]*mockChannel), + closedChannels: make(map[lnwire.ChannelID]uint32), + quit: make(chan struct{}), + } + t.Cleanup(func() { + close(h.quit) + }) + + fetchChannel := func(id lnwire.ChannelID) ( + *channeldb.ChannelCloseSummary, error) { + + h.mu.Lock() + defer h.mu.Unlock() + + height, ok := h.closedChannels[id] + if !ok { + return nil, channeldb.ErrClosedChannelNotFound + } + + return &channeldb.ChannelCloseSummary{CloseHeight: height}, nil + } + + h.clientCfg = &wtclient.Config{ + Signer: signer, + SubscribeChannelEvents: func() (subscribe.Subscription, error) { + return h.channelEvents, nil + }, + FetchClosedChannel: fetchChannel, + Dial: mockNet.Dial, + DB: clientDB, + AuthDial: mockNet.AuthDial, + SecretKeyRing: wtmock.NewSecretKeyRing(), + Policy: cfg.policy, NewAddress: func() ([]byte, error) { return addrScript, nil }, @@ -458,24 +502,6 @@ func newHarness(t *testing.T, cfg harnessCfg) *testHarness { ForceQuitDelay: 10 * time.Second, } - h := &testHarness{ - t: t, - cfg: cfg, - signer: signer, - capacity: cfg.localBalance + cfg.remoteBalance, - clientDB: clientDB, - clientCfg: clientCfg, - serverAddr: towerAddr, - serverDB: serverDB, - serverCfg: serverCfg, - net: mockNet, - channels: make(map[lnwire.ChannelID]*mockChannel), - quit: make(chan struct{}), - } - t.Cleanup(func() { - close(h.quit) - }) - if !cfg.noServerStart { h.startServer() t.Cleanup(h.stopServer) @@ -576,6 +602,41 @@ func (h *testHarness) channel(id uint64) *mockChannel { return c } +// closeChannel marks a channel as closed. +// +// NOTE: The method fails if a channel for id does not exist. +func (h *testHarness) closeChannel(id uint64, height uint32) { + h.t.Helper() + + h.mu.Lock() + defer h.mu.Unlock() + + chanID := chanIDFromInt(id) + + _, ok := h.channels[chanID] + require.Truef(h.t, ok, "unable to fetch channel %d", id) + + h.closedChannels[chanID] = height + delete(h.channels, chanID) + + chanPointHash, err := chainhash.NewHash(chanID[:]) + require.NoError(h.t, err) + + if !h.sendUpdatesOn { + return + } + + h.channelEvents.sendUpdate(channelnotifier.ClosedChannelEvent{ + CloseSummary: &channeldb.ChannelCloseSummary{ + ChanPoint: wire.OutPoint{ + Hash: *chanPointHash, + Index: 0, + }, + CloseHeight: height, + }, + }) +} + // registerChannel registers the channel identified by id with the client. func (h *testHarness) registerChannel(id uint64) { h.t.Helper() @@ -624,7 +685,7 @@ func (h *testHarness) backupState(id, i uint64, expErr error) { err := h.client.BackupState( &chanID, retribution, channeldb.SingleFunderBit, ) - require.ErrorIs(h.t, expErr, err) + require.ErrorIs(h.t, err, expErr) } // sendPayments instructs the channel identified by id to send amt to the remote @@ -770,11 +831,94 @@ func (h *testHarness) removeTower(pubKey *btcec.PublicKey, addr net.Addr) { require.NoError(h.t, err) } +// relevantSessions returns a list of session IDs that have acked updates for +// the given channel ID. +func (h *testHarness) relevantSessions(chanID uint64) []wtdb.SessionID { + h.t.Helper() + + var ( + sessionIDs []wtdb.SessionID + cID = chanIDFromInt(chanID) + ) + + collectSessions := wtdb.WithPerNumAckedUpdates( + func(session *wtdb.ClientSession, id lnwire.ChannelID, + _ uint16) { + + if !bytes.Equal(id[:], cID[:]) { + return + } + + sessionIDs = append(sessionIDs, session.ID) + }, + ) + + _, err := h.clientDB.ListClientSessions(nil, nil, collectSessions) + require.NoError(h.t, err) + + return sessionIDs +} + +// isSessionClosable returns true if the given session has been marked as +// closable in the DB. +func (h *testHarness) isSessionClosable(id wtdb.SessionID) bool { + h.t.Helper() + + cs, err := h.clientDB.ListClosableSessions() + require.NoError(h.t, err) + + _, ok := cs[id] + + return ok +} + +// mockSubscription is a mock subscription client that blocks on sends into the +// updates channel. +type mockSubscription struct { + t *testing.T + updates chan interface{} + + // Embed the subscription interface in this mock so that we satisfy it. + subscribe.Subscription +} + +// newMockSubscription creates a mock subscription. +func newMockSubscription(t *testing.T) *mockSubscription { + t.Helper() + + return &mockSubscription{ + t: t, + updates: make(chan interface{}), + } +} + +// sendUpdate sends an update into our updates channel, mocking the dispatch of +// an update from a subscription server. This call will fail the test if the +// update is not consumed within our timeout. +func (m *mockSubscription) sendUpdate(update interface{}) { + select { + case m.updates <- update: + + case <-time.After(waitTime): + m.t.Fatalf("update: %v timeout", update) + } +} + +// Updates returns the updates channel for the mock. +func (m *mockSubscription) Updates() <-chan interface{} { + return m.updates +} + const ( localBalance = lnwire.MilliSatoshi(100000000) remoteBalance = lnwire.MilliSatoshi(200000000) ) +var defaultTxPolicy = wtpolicy.TxPolicy{ + BlobType: blob.TypeAltruistCommit, + SweepFeeRate: wtpolicy.DefaultSweepFeeRate, +} + type clientTest struct { name string cfg harnessCfg @@ -791,10 +935,7 @@ var clientTests = []clientTest{ localBalance: localBalance, remoteBalance: remoteBalance, policy: wtpolicy.Policy{ - TxPolicy: wtpolicy.TxPolicy{ - BlobType: blob.TypeAltruistCommit, - SweepFeeRate: wtpolicy.DefaultSweepFeeRate, - }, + TxPolicy: defaultTxPolicy, MaxUpdates: 20000, }, noRegisterChan0: true, @@ -825,10 +966,7 @@ var clientTests = []clientTest{ localBalance: localBalance, remoteBalance: remoteBalance, policy: wtpolicy.Policy{ - TxPolicy: wtpolicy.TxPolicy{ - BlobType: blob.TypeAltruistCommit, - SweepFeeRate: wtpolicy.DefaultSweepFeeRate, - }, + TxPolicy: defaultTxPolicy, MaxUpdates: 20000, }, }, @@ -860,10 +998,7 @@ var clientTests = []clientTest{ localBalance: localBalance, remoteBalance: remoteBalance, policy: wtpolicy.Policy{ - TxPolicy: wtpolicy.TxPolicy{ - BlobType: blob.TypeAltruistCommit, - SweepFeeRate: wtpolicy.DefaultSweepFeeRate, - }, + TxPolicy: defaultTxPolicy, MaxUpdates: 5, }, }, @@ -927,10 +1062,7 @@ var clientTests = []clientTest{ localBalance: localBalance, remoteBalance: remoteBalance, policy: wtpolicy.Policy{ - TxPolicy: wtpolicy.TxPolicy{ - BlobType: blob.TypeAltruistCommit, - SweepFeeRate: wtpolicy.DefaultSweepFeeRate, - }, + TxPolicy: defaultTxPolicy, MaxUpdates: 20000, }, }, @@ -1006,10 +1138,7 @@ var clientTests = []clientTest{ localBalance: localBalance, remoteBalance: remoteBalance, policy: wtpolicy.Policy{ - TxPolicy: wtpolicy.TxPolicy{ - BlobType: blob.TypeAltruistCommit, - SweepFeeRate: wtpolicy.DefaultSweepFeeRate, - }, + TxPolicy: defaultTxPolicy, MaxUpdates: 5, }, }, @@ -1062,10 +1191,7 @@ var clientTests = []clientTest{ localBalance: 100000001, // ensure (% amt != 0) remoteBalance: 200000001, // ensure (% amt != 0) policy: wtpolicy.Policy{ - TxPolicy: wtpolicy.TxPolicy{ - BlobType: blob.TypeAltruistCommit, - SweepFeeRate: wtpolicy.DefaultSweepFeeRate, - }, + TxPolicy: defaultTxPolicy, MaxUpdates: 1000, }, }, @@ -1106,10 +1232,7 @@ var clientTests = []clientTest{ localBalance: localBalance, remoteBalance: remoteBalance, policy: wtpolicy.Policy{ - TxPolicy: wtpolicy.TxPolicy{ - BlobType: blob.TypeAltruistCommit, - SweepFeeRate: wtpolicy.DefaultSweepFeeRate, - }, + TxPolicy: defaultTxPolicy, MaxUpdates: 5, }, }, @@ -1156,10 +1279,7 @@ var clientTests = []clientTest{ localBalance: localBalance, remoteBalance: remoteBalance, policy: wtpolicy.Policy{ - TxPolicy: wtpolicy.TxPolicy{ - BlobType: blob.TypeAltruistCommit, - SweepFeeRate: wtpolicy.DefaultSweepFeeRate, - }, + TxPolicy: defaultTxPolicy, MaxUpdates: 5, }, noAckCreateSession: true, @@ -1212,10 +1332,7 @@ var clientTests = []clientTest{ localBalance: localBalance, remoteBalance: remoteBalance, policy: wtpolicy.Policy{ - TxPolicy: wtpolicy.TxPolicy{ - BlobType: blob.TypeAltruistCommit, - SweepFeeRate: wtpolicy.DefaultSweepFeeRate, - }, + TxPolicy: defaultTxPolicy, MaxUpdates: 5, }, noAckCreateSession: true, @@ -1274,10 +1391,7 @@ var clientTests = []clientTest{ localBalance: localBalance, remoteBalance: remoteBalance, policy: wtpolicy.Policy{ - TxPolicy: wtpolicy.TxPolicy{ - BlobType: blob.TypeAltruistCommit, - SweepFeeRate: wtpolicy.DefaultSweepFeeRate, - }, + TxPolicy: defaultTxPolicy, MaxUpdates: 10, }, }, @@ -1333,10 +1447,7 @@ var clientTests = []clientTest{ localBalance: localBalance, remoteBalance: remoteBalance, policy: wtpolicy.Policy{ - TxPolicy: wtpolicy.TxPolicy{ - BlobType: blob.TypeAltruistCommit, - SweepFeeRate: wtpolicy.DefaultSweepFeeRate, - }, + TxPolicy: defaultTxPolicy, MaxUpdates: 5, }, }, @@ -1381,10 +1492,7 @@ var clientTests = []clientTest{ localBalance: localBalance, remoteBalance: remoteBalance, policy: wtpolicy.Policy{ - TxPolicy: wtpolicy.TxPolicy{ - BlobType: blob.TypeAltruistCommit, - SweepFeeRate: wtpolicy.DefaultSweepFeeRate, - }, + TxPolicy: defaultTxPolicy, MaxUpdates: 5, }, }, @@ -1489,10 +1597,7 @@ var clientTests = []clientTest{ localBalance: localBalance, remoteBalance: remoteBalance, policy: wtpolicy.Policy{ - TxPolicy: wtpolicy.TxPolicy{ - BlobType: blob.TypeAltruistCommit, - SweepFeeRate: wtpolicy.DefaultSweepFeeRate, - }, + TxPolicy: defaultTxPolicy, MaxUpdates: 5, }, }, @@ -1557,10 +1662,7 @@ var clientTests = []clientTest{ localBalance: localBalance, remoteBalance: remoteBalance, policy: wtpolicy.Policy{ - TxPolicy: wtpolicy.TxPolicy{ - BlobType: blob.TypeAltruistCommit, - SweepFeeRate: wtpolicy.DefaultSweepFeeRate, - }, + TxPolicy: defaultTxPolicy, MaxUpdates: 5, }, noServerStart: true, @@ -1654,6 +1756,142 @@ var clientTests = []clientTest{ }, waitTime) require.NoError(h.t, err) }, + }, { + name: "assert that sessions are correctly marked as closable", + cfg: harnessCfg{ + localBalance: localBalance, + remoteBalance: remoteBalance, + policy: wtpolicy.Policy{ + TxPolicy: defaultTxPolicy, + MaxUpdates: 5, + }, + }, + fn: func(h *testHarness) { + const numUpdates = 5 + + // In this test we assert that a channel is correctly + // marked as closed and that sessions are also correctly + // marked as closable. + + // We start with the sendUpdatesOn parameter set to + // false so that we can test that channels are correctly + // evaluated at startup. + h.sendUpdatesOn = false + + // Advance channel 0 to create all states and back them + // all up. This will saturate the session with updates + // for channel 0 which means that the session should be + // considered closable when channel 0 is closed. + hints := h.advanceChannelN(0, numUpdates) + h.backupStates(0, 0, numUpdates, nil) + h.waitServerUpdates(hints, waitTime) + + // We expect only 1 session to have updates for this + // channel. + sessionIDs := h.relevantSessions(0) + require.Len(h.t, sessionIDs, 1) + + // Since channel 0 is still open, the session should not + // yet be closable. + require.False(h.t, h.isSessionClosable(sessionIDs[0])) + + // Close the channel. + h.closeChannel(0, 1) + + // Since updates are currently not being sent, we expect + // the session to still not be marked as closable. + require.False(h.t, h.isSessionClosable(sessionIDs[0])) + + // Restart the client. + h.client.ForceQuit() + h.startClient() + + // The session should now have been marked as closable. + err := wait.Predicate(func() bool { + return h.isSessionClosable(sessionIDs[0]) + }, waitTime) + require.NoError(h.t, err) + + // Now we set sendUpdatesOn to true and do the same with + // a new channel. A restart should now not be necessary + // anymore. + h.sendUpdatesOn = true + + h.makeChannel( + 1, h.cfg.localBalance, h.cfg.remoteBalance, + ) + h.registerChannel(1) + + hints = h.advanceChannelN(1, numUpdates) + h.backupStates(1, 0, numUpdates, nil) + h.waitServerUpdates(hints, waitTime) + + // Determine the ID of the session of interest. + sessionIDs = h.relevantSessions(1) + + // We expect only 1 session to have updates for this + // channel. + require.Len(h.t, sessionIDs, 1) + + // Assert that the session is not yet closable since + // the channel is still open. + require.False(h.t, h.isSessionClosable(sessionIDs[0])) + + // Now close the channel. + h.closeChannel(1, 1) + + // Since the updates have been turned on, the session + // should now show up as closable. + err = wait.Predicate(func() bool { + return h.isSessionClosable(sessionIDs[0]) + }, waitTime) + require.NoError(h.t, err) + + // Now we test that a session must be exhausted with all + // channels closed before it is seen as closable. + h.makeChannel( + 2, h.cfg.localBalance, h.cfg.remoteBalance, + ) + h.registerChannel(2) + + // Fill up only half of the session updates. + hints = h.advanceChannelN(2, numUpdates) + h.backupStates(2, 0, numUpdates/2, nil) + h.waitServerUpdates(hints[:numUpdates/2], waitTime) + + // Determine the ID of the session of interest. + sessionIDs = h.relevantSessions(2) + + // We expect only 1 session to have updates for this + // channel. + require.Len(h.t, sessionIDs, 1) + + // Now close the channel. + h.closeChannel(2, 1) + + // The session should _not_ be closable due to it not + // being exhausted yet. + require.False(h.t, h.isSessionClosable(sessionIDs[0])) + + // Create a new channel. + h.makeChannel( + 3, h.cfg.localBalance, h.cfg.remoteBalance, + ) + h.registerChannel(3) + + hints = h.advanceChannelN(3, numUpdates) + h.backupStates(3, 0, numUpdates, nil) + h.waitServerUpdates(hints, waitTime) + + // Close it. + h.closeChannel(3, 1) + + // Now the session should be closable. + err = wait.Predicate(func() bool { + return h.isSessionClosable(sessionIDs[0]) + }, waitTime) + require.NoError(h.t, err) + }, }, } From 2b08d3443f1b82f96d1b7a2ffb17ef959026a1f4 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 21 Oct 2022 11:30:23 +0200 Subject: [PATCH 45/87] watchtowers: add thread safe min-heap In this commit, a thread-safe min-heap is implemented. It will carry sessionCloseItems which carry a sessionID and a block height at which the session should be closed. --- watchtower/wtclient/client.go | 27 +++--- watchtower/wtclient/sess_close_min_heap.go | 95 +++++++++++++++++++ .../wtclient/sess_close_min_heap_test.go | 52 ++++++++++ 3 files changed, 162 insertions(+), 12 deletions(-) create mode 100644 watchtower/wtclient/sess_close_min_heap.go create mode 100644 watchtower/wtclient/sess_close_min_heap_test.go diff --git a/watchtower/wtclient/client.go b/watchtower/wtclient/client.go index c0a4c2331..b2ce38351 100644 --- a/watchtower/wtclient/client.go +++ b/watchtower/wtclient/client.go @@ -271,6 +271,8 @@ type TowerClient struct { sessionQueue *sessionQueue prevTask *backupTask + closableSessionQueue *sessionCloseMinHeap + backupMu sync.Mutex summaries wtdb.ChannelSummaries chanCommitHeights map[lnwire.ChannelID]uint64 @@ -322,18 +324,19 @@ func New(config *Config) (*TowerClient, error) { } c := &TowerClient{ - cfg: cfg, - log: plog, - pipeline: newTaskPipeline(plog), - chanCommitHeights: make(map[lnwire.ChannelID]uint64), - activeSessions: make(sessionQueueSet), - summaries: chanSummaries, - statTicker: time.NewTicker(DefaultStatInterval), - stats: new(ClientStats), - newTowers: make(chan *newTowerMsg), - staleTowers: make(chan *staleTowerMsg), - forceQuit: make(chan struct{}), - quit: make(chan struct{}), + cfg: cfg, + log: plog, + pipeline: newTaskPipeline(plog), + chanCommitHeights: make(map[lnwire.ChannelID]uint64), + activeSessions: make(sessionQueueSet), + summaries: chanSummaries, + closableSessionQueue: newSessionCloseMinHeap(), + statTicker: time.NewTicker(DefaultStatInterval), + stats: new(ClientStats), + newTowers: make(chan *newTowerMsg), + staleTowers: make(chan *staleTowerMsg), + forceQuit: make(chan struct{}), + quit: make(chan struct{}), } // perUpdate is a callback function that will be used to inspect the diff --git a/watchtower/wtclient/sess_close_min_heap.go b/watchtower/wtclient/sess_close_min_heap.go new file mode 100644 index 000000000..c5f58ec1a --- /dev/null +++ b/watchtower/wtclient/sess_close_min_heap.go @@ -0,0 +1,95 @@ +package wtclient + +import ( + "sync" + + "github.com/lightningnetwork/lnd/queue" + "github.com/lightningnetwork/lnd/watchtower/wtdb" +) + +// sessionCloseMinHeap is a thread-safe min-heap implementation that stores +// sessionCloseItem items and prioritises the item with the lowest block height. +type sessionCloseMinHeap struct { + queue queue.PriorityQueue + mu sync.Mutex +} + +// newSessionCloseMinHeap constructs a new sessionCloseMineHeap. +func newSessionCloseMinHeap() *sessionCloseMinHeap { + return &sessionCloseMinHeap{} +} + +// Len returns the length of the queue. +func (h *sessionCloseMinHeap) Len() int { + h.mu.Lock() + defer h.mu.Unlock() + + return h.queue.Len() +} + +// Empty returns true if the queue is empty. +func (h *sessionCloseMinHeap) Empty() bool { + h.mu.Lock() + defer h.mu.Unlock() + + return h.queue.Empty() +} + +// Push adds an item to the priority queue. +func (h *sessionCloseMinHeap) Push(item *sessionCloseItem) { + h.mu.Lock() + defer h.mu.Unlock() + + h.queue.Push(item) +} + +// Pop removes the top most item from the queue. +func (h *sessionCloseMinHeap) Pop() *sessionCloseItem { + h.mu.Lock() + defer h.mu.Unlock() + + if h.queue.Empty() { + return nil + } + + item := h.queue.Pop() + + return item.(*sessionCloseItem) //nolint:forcetypeassert +} + +// Top returns the top most item from the queue without removing it. +func (h *sessionCloseMinHeap) Top() *sessionCloseItem { + h.mu.Lock() + defer h.mu.Unlock() + + if h.queue.Empty() { + return nil + } + + item := h.queue.Top() + + return item.(*sessionCloseItem) //nolint:forcetypeassert +} + +// sessionCloseItem represents a session that is ready to be deleted. +type sessionCloseItem struct { + // sessionID is the ID of the session in question. + sessionID wtdb.SessionID + + // deleteHeight is the block height after which we can delete the + // session. + deleteHeight uint32 +} + +// Less returns true if the current item's delete height is less than the +// other sessionCloseItem's delete height. This results in lower block heights +// being popped first from the heap. +// +// NOTE: this is part of the queue.PriorityQueueItem interface. +func (s *sessionCloseItem) Less(other queue.PriorityQueueItem) bool { + o := other.(*sessionCloseItem).deleteHeight //nolint:forcetypeassert + + return s.deleteHeight < o +} + +var _ queue.PriorityQueueItem = (*sessionCloseItem)(nil) diff --git a/watchtower/wtclient/sess_close_min_heap_test.go b/watchtower/wtclient/sess_close_min_heap_test.go new file mode 100644 index 000000000..9983f5b93 --- /dev/null +++ b/watchtower/wtclient/sess_close_min_heap_test.go @@ -0,0 +1,52 @@ +package wtclient + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +// TestSessionCloseMinHeap asserts that the sessionCloseMinHeap behaves as +// expected. +func TestSessionCloseMinHeap(t *testing.T) { + t.Parallel() + + heap := newSessionCloseMinHeap() + require.Nil(t, heap.Pop()) + require.Nil(t, heap.Top()) + require.True(t, heap.Empty()) + require.Zero(t, heap.Len()) + + // Add an item with height 10. + item1 := &sessionCloseItem{ + sessionID: [33]byte{1, 2, 3}, + deleteHeight: 10, + } + + heap.Push(item1) + require.Equal(t, item1, heap.Top()) + require.False(t, heap.Empty()) + require.EqualValues(t, 1, heap.Len()) + + // Add a bunch more items with heights 1, 2, 6, 11, 6, 30, 9. + heap.Push(&sessionCloseItem{deleteHeight: 1}) + heap.Push(&sessionCloseItem{deleteHeight: 2}) + heap.Push(&sessionCloseItem{deleteHeight: 6}) + heap.Push(&sessionCloseItem{deleteHeight: 11}) + heap.Push(&sessionCloseItem{deleteHeight: 6}) + heap.Push(&sessionCloseItem{deleteHeight: 30}) + heap.Push(&sessionCloseItem{deleteHeight: 9}) + + // Now pop from the queue and assert that the items are returned in + // ascending order. + require.EqualValues(t, 1, heap.Pop().deleteHeight) + require.EqualValues(t, 2, heap.Pop().deleteHeight) + require.EqualValues(t, 6, heap.Pop().deleteHeight) + require.EqualValues(t, 6, heap.Pop().deleteHeight) + require.EqualValues(t, 9, heap.Pop().deleteHeight) + require.EqualValues(t, 10, heap.Pop().deleteHeight) + require.EqualValues(t, 11, heap.Pop().deleteHeight) + require.EqualValues(t, 30, heap.Pop().deleteHeight) + require.Nil(t, heap.Pop()) + require.Zero(t, heap.Len()) +} From 0209e6feb8246b5a61776580c24f5f9541dbbb39 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Thu, 9 Feb 2023 17:05:23 +0200 Subject: [PATCH 46/87] watchtower/wtclient: add Copy method to AddressIterator --- watchtower/wtclient/addr_iterator.go | 33 +++++++++++++++++++ watchtower/wtclient/addr_iterator_test.go | 5 +++ .../wtclient/candidate_iterator_test.go | 6 +--- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/watchtower/wtclient/addr_iterator.go b/watchtower/wtclient/addr_iterator.go index 87065c011..cb16d335a 100644 --- a/watchtower/wtclient/addr_iterator.go +++ b/watchtower/wtclient/addr_iterator.go @@ -69,6 +69,12 @@ type AddressIterator interface { // Reset clears the iterators state, and makes the address at the front // of the list the next item to be returned. Reset() + + // Copy constructs a new AddressIterator that has the same addresses + // as this iterator. + // + // NOTE that the address locks are not expected to be copied. + Copy() AddressIterator } // A compile-time check to ensure that addressIterator implements the @@ -324,6 +330,33 @@ func (a *addressIterator) GetAll() []net.Addr { a.mu.Lock() defer a.mu.Unlock() + return a.getAllUnsafe() +} + +// Copy constructs a new AddressIterator that has the same addresses +// as this iterator. +// +// NOTE that the address locks will not be copied. +func (a *addressIterator) Copy() AddressIterator { + a.mu.Lock() + defer a.mu.Unlock() + + addrs := a.getAllUnsafe() + + // Since newAddressIterator will only ever return an error if it is + // initialised with zero addresses, we can ignore the error here since + // we are initialising it with the set of addresses of this + // addressIterator which is by definition a non-empty list. + iter, _ := newAddressIterator(addrs...) + + return iter +} + +// getAllUnsafe returns a copy of all the addresses in the iterator. +// +// NOTE: this method is not thread safe and so must only be called once the +// addressIterator mutex is already being held. +func (a *addressIterator) getAllUnsafe() []net.Addr { var addrs []net.Addr cursor := a.addrList.Front() diff --git a/watchtower/wtclient/addr_iterator_test.go b/watchtower/wtclient/addr_iterator_test.go index d3674d985..89a35c4cb 100644 --- a/watchtower/wtclient/addr_iterator_test.go +++ b/watchtower/wtclient/addr_iterator_test.go @@ -97,6 +97,11 @@ func TestAddrIterator(t *testing.T) { addrList := iter.GetAll() require.ElementsMatch(t, addrList, []net.Addr{addr1, addr2, addr3}) + // Also check that an iterator constructed via the Copy method, also + // contains all the expected addresses. + newIterAddrs := iter.Copy().GetAll() + require.ElementsMatch(t, newIterAddrs, []net.Addr{addr1, addr2, addr3}) + // Let's now remove addr3. err = iter.Remove(addr3) require.NoError(t, err) diff --git a/watchtower/wtclient/candidate_iterator_test.go b/watchtower/wtclient/candidate_iterator_test.go index 70dfb7505..b4df80f4d 100644 --- a/watchtower/wtclient/candidate_iterator_test.go +++ b/watchtower/wtclient/candidate_iterator_test.go @@ -52,14 +52,10 @@ func randTower(t *testing.T) *Tower { func copyTower(t *testing.T, tower *Tower) *Tower { t.Helper() - addrs := tower.Addresses.GetAll() - addrIterator, err := newAddressIterator(addrs...) - require.NoError(t, err) - return &Tower{ ID: tower.ID, IdentityKey: tower.IdentityKey, - Addresses: addrIterator, + Addresses: tower.Addresses.Copy(), } } From 8478b56ce6609ccc4b63f59ae09490fe69d92e76 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 20 Mar 2023 10:56:23 +0200 Subject: [PATCH 47/87] watchtower: method to dial tower and send DeleteSession This commit adds a deleteSessionFromTower method which can be used to dial the tower that we created a given session with and then sends that tower the DeleteSession method. --- watchtower/wtclient/client.go | 124 ++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/watchtower/wtclient/client.go b/watchtower/wtclient/client.go index b2ce38351..464e93f16 100644 --- a/watchtower/wtclient/client.go +++ b/watchtower/wtclient/client.go @@ -902,6 +902,130 @@ func (c *TowerClient) handleClosedChannel(chanID lnwire.ChannelID, return nil } +// deleteSessionFromTower dials the tower that we created the session with and +// attempts to send the tower the DeleteSession message. +func (c *TowerClient) deleteSessionFromTower(sess *wtdb.ClientSession) error { + // First, we check if we have already loaded this tower in our + // candidate towers iterator. + tower, err := c.candidateTowers.GetTower(sess.TowerID) + if errors.Is(err, ErrTowerNotInIterator) { + // If not, then we attempt to load it from the DB. + dbTower, err := c.cfg.DB.LoadTowerByID(sess.TowerID) + if err != nil { + return err + } + + tower, err = NewTowerFromDBTower(dbTower) + if err != nil { + return err + } + } else if err != nil { + return err + } + + session, err := NewClientSessionFromDBSession( + sess, tower, c.cfg.SecretKeyRing, + ) + if err != nil { + return err + } + + localInit := wtwire.NewInitMessage( + lnwire.NewRawFeatureVector(wtwire.AltruistSessionsRequired), + c.cfg.ChainHash, + ) + + var ( + conn wtserver.Peer + + // addrIterator is a copy of the tower's address iterator. + // We use this copy so that iterating through the addresses does + // not affect any other threads using this iterator. + addrIterator = tower.Addresses.Copy() + towerAddr = addrIterator.Peek() + ) + // Attempt to dial the tower with its available addresses. + for { + conn, err = c.dial( + session.SessionKeyECDH, &lnwire.NetAddress{ + IdentityKey: tower.IdentityKey, + Address: towerAddr, + }, + ) + if err != nil { + // If there are more addrs available, immediately try + // those. + nextAddr, iteratorErr := addrIterator.Next() + if iteratorErr == nil { + towerAddr = nextAddr + continue + } + + // Otherwise, if we have exhausted the address list, + // exit. + addrIterator.Reset() + + return fmt.Errorf("failed to dial tower(%x) at any "+ + "available addresses", + tower.IdentityKey.SerializeCompressed()) + } + + break + } + defer conn.Close() + + // Send Init to tower. + err = c.sendMessage(conn, localInit) + if err != nil { + return err + } + + // Receive Init from tower. + remoteMsg, err := c.readMessage(conn) + if err != nil { + return err + } + + remoteInit, ok := remoteMsg.(*wtwire.Init) + if !ok { + return fmt.Errorf("watchtower %s responded with %T to Init", + towerAddr, remoteMsg) + } + + // Validate Init. + err = localInit.CheckRemoteInit(remoteInit, wtwire.FeatureNames) + if err != nil { + return err + } + + // Send DeleteSession to tower. + err = c.sendMessage(conn, &wtwire.DeleteSession{}) + if err != nil { + return err + } + + // Receive DeleteSessionReply from tower. + remoteMsg, err = c.readMessage(conn) + if err != nil { + return err + } + + deleteSessionReply, ok := remoteMsg.(*wtwire.DeleteSessionReply) + if !ok { + return fmt.Errorf("watchtower %s responded with %T to "+ + "DeleteSession", towerAddr, remoteMsg) + } + + switch deleteSessionReply.Code { + case wtwire.CodeOK, wtwire.DeleteSessionCodeNotFound: + return nil + default: + return fmt.Errorf("received error code %v in "+ + "DeleteSessionReply when attempting to delete "+ + "session from tower", deleteSessionReply.Code) + } +} + // backupDispatcher processes events coming from the taskPipeline and is // responsible for detecting when the client needs to renegotiate a session to // fulfill continuing demand. The event loop exits after all tasks have been From 26e628c0feaf814a1d6288c45ee33613232ebab7 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 20 Mar 2023 11:07:31 +0200 Subject: [PATCH 48/87] watchtowers: handle closable sessions Add a routine to the tower client that informs towers of sessions they can delete and also deletes any info about the session from the client DB. --- lncfg/wtclient.go | 5 + sample-lnd.conf | 6 + server.go | 9 ++ watchtower/wtclient/client.go | 186 ++++++++++++++++++++++++++++- watchtower/wtclient/client_test.go | 132 +++++++++++++++++++- 5 files changed, 331 insertions(+), 7 deletions(-) diff --git a/lncfg/wtclient.go b/lncfg/wtclient.go index 8b9f03939..7d4331112 100644 --- a/lncfg/wtclient.go +++ b/lncfg/wtclient.go @@ -17,6 +17,11 @@ type WtClient struct { // SweepFeeRate specifies the fee rate in sat/byte to be used when // constructing justice transactions sent to the tower. SweepFeeRate uint64 `long:"sweep-fee-rate" description:"Specifies the fee rate in sat/byte to be used when constructing justice transactions sent to the watchtower."` + + // SessionCloseRange is the range over which to choose a random number + // of blocks to wait after the last channel of a session is closed + // before sending the DeleteSession message to the tower server. + SessionCloseRange uint32 `long:"session-close-range" description:"The range over which to choose a random number of blocks to wait after the last channel of a session is closed before sending the DeleteSession message to the tower server. Set to 1 for no delay."` } // Validate ensures the user has provided a valid configuration. diff --git a/sample-lnd.conf b/sample-lnd.conf index 3dfc76da8..f0edda984 100644 --- a/sample-lnd.conf +++ b/sample-lnd.conf @@ -997,6 +997,12 @@ litecoin.node=ltcd ; supported at this time, if none are provided the tower will not be enabled. ; wtclient.private-tower-uris= +; The range over which to choose a random number of blocks to wait after the +; last channel of a session is closed before sending the DeleteSession message +; to the tower server. The default is currently 288. Note that setting this to +; a lower value will result in faster session cleanup _but_ that this comes +; along with reduced privacy from the tower server. +; wtclient.session-close-range=10 [healthcheck] diff --git a/server.go b/server.go index 61b31ffa6..eef43550b 100644 --- a/server.go +++ b/server.go @@ -1497,6 +1497,11 @@ func newServer(cfg *Config, listenAddrs []net.Addr, policy.SweepFeeRate = sweepRateSatPerVByte.FeePerKWeight() } + sessionCloseRange := uint32(wtclient.DefaultSessionCloseRange) + if cfg.WtClient.SessionCloseRange != 0 { + sessionCloseRange = cfg.WtClient.SessionCloseRange + } + if err := policy.Validate(); err != nil { return nil, err } @@ -1516,6 +1521,8 @@ func newServer(cfg *Config, listenAddrs []net.Addr, s.towerClient, err = wtclient.New(&wtclient.Config{ FetchClosedChannel: fetchClosedChannel, + SessionCloseRange: sessionCloseRange, + ChainNotifier: s.cc.ChainNotifier, SubscribeChannelEvents: func() (subscribe.Subscription, error) { @@ -1546,6 +1553,8 @@ func newServer(cfg *Config, listenAddrs []net.Addr, s.anchorTowerClient, err = wtclient.New(&wtclient.Config{ FetchClosedChannel: fetchClosedChannel, + SessionCloseRange: sessionCloseRange, + ChainNotifier: s.cc.ChainNotifier, SubscribeChannelEvents: func() (subscribe.Subscription, error) { diff --git a/watchtower/wtclient/client.go b/watchtower/wtclient/client.go index 464e93f16..e92b8b4cf 100644 --- a/watchtower/wtclient/client.go +++ b/watchtower/wtclient/client.go @@ -2,8 +2,10 @@ package wtclient import ( "bytes" + "crypto/rand" "errors" "fmt" + "math/big" "net" "sync" "time" @@ -12,6 +14,7 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btclog" "github.com/lightningnetwork/lnd/build" + "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channelnotifier" "github.com/lightningnetwork/lnd/input" @@ -43,6 +46,11 @@ const ( // client should abandon any pending updates or session negotiations // before terminating. DefaultForceQuitDelay = 10 * time.Second + + // DefaultSessionCloseRange is the range over which we will generate a + // random number of blocks to delay closing a session after its last + // channel has been closed. + DefaultSessionCloseRange = 288 ) // genSessionFilter constructs a filter that can be used to select sessions only @@ -159,6 +167,9 @@ type Config struct { FetchClosedChannel func(cid lnwire.ChannelID) ( *channeldb.ChannelCloseSummary, error) + // ChainNotifier can be used to subscribe to block notifications. + ChainNotifier chainntnfs.ChainNotifier + // NewAddress generates a new on-chain sweep pkscript. NewAddress func() ([]byte, error) @@ -214,6 +225,11 @@ type Config struct { // watchtowers. If the exponential backoff produces a timeout greater // than this value, the backoff will be clamped to MaxBackoff. MaxBackoff time.Duration + + // SessionCloseRange is the range over which we will generate a random + // number of blocks to delay closing a session after its last channel + // has been closed. + SessionCloseRange uint32 } // newTowerMsg is an internal message we'll use within the TowerClient to signal @@ -590,9 +606,34 @@ func (c *TowerClient) Start() error { delete(c.summaries, id) } + // Load all closable sessions. + closableSessions, err := c.cfg.DB.ListClosableSessions() + if err != nil { + returnErr = err + return + } + + err = c.trackClosableSessions(closableSessions) + if err != nil { + returnErr = err + return + } + c.wg.Add(1) go c.handleChannelCloses(chanSub) + // Subscribe to new block events. + blockEvents, err := c.cfg.ChainNotifier.RegisterBlockEpochNtfn( + nil, + ) + if err != nil { + returnErr = err + return + } + + c.wg.Add(1) + go c.handleClosableSessions(blockEvents) + // Now start the session negotiator, which will allow us to // request new session as soon as the backupDispatcher starts // up. @@ -876,7 +917,8 @@ func (c *TowerClient) handleChannelCloses(chanSub subscribe.Subscription) { } // handleClosedChannel handles the closure of a single channel. It will mark the -// channel as closed in the DB. +// channel as closed in the DB, then it will handle all the sessions that are +// now closable due to the channel closure. func (c *TowerClient) handleClosedChannel(chanID lnwire.ChannelID, closeHeight uint32) error { @@ -890,18 +932,146 @@ func (c *TowerClient) handleClosedChannel(chanID lnwire.ChannelID, c.log.Debugf("Marking channel(%s) as closed", chanID) - _, err := c.cfg.DB.MarkChannelClosed(chanID, closeHeight) + sessions, err := c.cfg.DB.MarkChannelClosed(chanID, closeHeight) if err != nil { return fmt.Errorf("could not mark channel(%s) as closed: %w", chanID, err) } + closableSessions := make(map[wtdb.SessionID]uint32, len(sessions)) + for _, sess := range sessions { + closableSessions[sess] = closeHeight + } + + c.log.Debugf("Tracking %d new closable sessions as a result of "+ + "closing channel %s", len(closableSessions), chanID) + + err = c.trackClosableSessions(closableSessions) + if err != nil { + return fmt.Errorf("could not track closable sessions: %w", err) + } + delete(c.summaries, chanID) delete(c.chanCommitHeights, chanID) return nil } +// handleClosableSessions listens for new block notifications. For each block, +// it checks the closableSessionQueue to see if there is a closable session with +// a delete-height smaller than or equal to the new block, if there is then the +// tower is informed that it can delete the session, and then we also delete it +// from our DB. +func (c *TowerClient) handleClosableSessions( + blocksChan *chainntnfs.BlockEpochEvent) { + + defer c.wg.Done() + + c.log.Debug("Starting closable sessions handler") + defer c.log.Debug("Stopping closable sessions handler") + + for { + select { + case newBlock := <-blocksChan.Epochs: + if newBlock == nil { + return + } + + height := uint32(newBlock.Height) + for { + select { + case <-c.quit: + return + default: + } + + // If there are no closable sessions that we + // need to handle, then we are done and can + // reevaluate when the next block comes. + item := c.closableSessionQueue.Top() + if item == nil { + break + } + + // If there is closable session but the delete + // height we have set for it is after the + // current block height, then our work is done. + if item.deleteHeight > height { + break + } + + // Otherwise, we pop this item from the heap + // and handle it. + c.closableSessionQueue.Pop() + + // Fetch the session from the DB so that we can + // extract the Tower info. + sess, err := c.cfg.DB.GetClientSession( + item.sessionID, + ) + if err != nil { + c.log.Errorf("error calling "+ + "GetClientSession for "+ + "session %s: %v", + item.sessionID, err) + + continue + } + + err = c.deleteSessionFromTower(sess) + if err != nil { + c.log.Errorf("error deleting "+ + "session %s from tower: %v", + sess.ID, err) + + continue + } + + err = c.cfg.DB.DeleteSession(item.sessionID) + if err != nil { + c.log.Errorf("could not delete "+ + "session(%s) from DB: %w", + sess.ID, err) + + continue + } + } + + case <-c.forceQuit: + return + + case <-c.quit: + return + } + } +} + +// trackClosableSessions takes in a map of session IDs to the earliest block +// height at which the session should be deleted. For each of the sessions, +// a random delay is added to the block height and the session is added to the +// closableSessionQueue. +func (c *TowerClient) trackClosableSessions( + sessions map[wtdb.SessionID]uint32) error { + + // For each closable session, add a random delay to its close + // height and add it to the closableSessionQueue. + for sID, blockHeight := range sessions { + delay, err := newRandomDelay(c.cfg.SessionCloseRange) + if err != nil { + return err + } + + deleteHeight := blockHeight + delay + + c.closableSessionQueue.Push(&sessionCloseItem{ + sessionID: sID, + deleteHeight: deleteHeight, + }) + } + + return nil +} + // deleteSessionFromTower dials the tower that we created the session with and // attempts to send the tower the DeleteSession message. func (c *TowerClient) deleteSessionFromTower(sess *wtdb.ClientSession) error { @@ -1671,3 +1841,15 @@ func (c *TowerClient) logMessage( preposition, peer.RemotePub().SerializeCompressed(), peer.RemoteAddr()) } + +func newRandomDelay(max uint32) (uint32, error) { + var maxDelay big.Int + maxDelay.SetUint64(uint64(max)) + + randDelay, err := rand.Int(rand.Reader, &maxDelay) + if err != nil { + return 0, err + } + + return uint32(randDelay.Uint64()), nil +} diff --git a/watchtower/wtclient/client_test.go b/watchtower/wtclient/client_test.go index 29c4e7a53..2657e691b 100644 --- a/watchtower/wtclient/client_test.go +++ b/watchtower/wtclient/client_test.go @@ -16,6 +16,7 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" + "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channelnotifier" "github.com/lightningnetwork/lnd/input" @@ -396,6 +397,9 @@ type testHarness struct { server *wtserver.Server net *mockNet + blockEvents *mockBlockSub + height int32 + channelEvents *mockSubscription sendUpdatesOn bool @@ -458,6 +462,7 @@ func newHarness(t *testing.T, cfg harnessCfg) *testHarness { serverDB: serverDB, serverCfg: serverCfg, net: mockNet, + blockEvents: newMockBlockSub(t), channelEvents: newMockSubscription(t), channels: make(map[lnwire.ChannelID]*mockChannel), closedChannels: make(map[lnwire.ChannelID]uint32), @@ -487,6 +492,7 @@ func newHarness(t *testing.T, cfg harnessCfg) *testHarness { return h.channelEvents, nil }, FetchClosedChannel: fetchChannel, + ChainNotifier: h.blockEvents, Dial: mockNet.Dial, DB: clientDB, AuthDial: mockNet.AuthDial, @@ -495,11 +501,12 @@ func newHarness(t *testing.T, cfg harnessCfg) *testHarness { NewAddress: func() ([]byte, error) { return addrScript, nil }, - ReadTimeout: timeout, - WriteTimeout: timeout, - MinBackoff: time.Millisecond, - MaxBackoff: time.Second, - ForceQuitDelay: 10 * time.Second, + ReadTimeout: timeout, + WriteTimeout: timeout, + MinBackoff: time.Millisecond, + MaxBackoff: time.Second, + ForceQuitDelay: 10 * time.Second, + SessionCloseRange: 1, } if !cfg.noServerStart { @@ -518,6 +525,16 @@ func newHarness(t *testing.T, cfg harnessCfg) *testHarness { return h } +// mine mimics the mining of new blocks by sending new block notifications. +func (h *testHarness) mine(numBlocks int) { + h.t.Helper() + + for i := 0; i < numBlocks; i++ { + h.height++ + h.blockEvents.sendNewBlock(h.height) + } +} + // startServer creates a new server using the harness's current serverCfg and // starts it after pointing the mockNet's callback to the new server. func (h *testHarness) startServer() { @@ -909,6 +926,44 @@ func (m *mockSubscription) Updates() <-chan interface{} { return m.updates } +// mockBlockSub mocks out the ChainNotifier. +type mockBlockSub struct { + t *testing.T + events chan *chainntnfs.BlockEpoch + + chainntnfs.ChainNotifier +} + +// newMockBlockSub creates a new mockBlockSub. +func newMockBlockSub(t *testing.T) *mockBlockSub { + t.Helper() + + return &mockBlockSub{ + t: t, + events: make(chan *chainntnfs.BlockEpoch), + } +} + +// RegisterBlockEpochNtfn returns a channel that can be used to listen for new +// blocks. +func (m *mockBlockSub) RegisterBlockEpochNtfn(_ *chainntnfs.BlockEpoch) ( + *chainntnfs.BlockEpochEvent, error) { + + return &chainntnfs.BlockEpochEvent{ + Epochs: m.events, + }, nil +} + +// sendNewBlock will send a new block on the notification channel. +func (m *mockBlockSub) sendNewBlock(height int32) { + select { + case m.events <- &chainntnfs.BlockEpoch{Height: height}: + + case <-time.After(waitTime): + m.t.Fatalf("timed out sending block: %d", height) + } +} + const ( localBalance = lnwire.MilliSatoshi(100000000) remoteBalance = lnwire.MilliSatoshi(200000000) @@ -1891,6 +1946,73 @@ var clientTests = []clientTest{ return h.isSessionClosable(sessionIDs[0]) }, waitTime) require.NoError(h.t, err) + + // Now we will mine a few blocks. This will cause the + // necessary session-close-range to be exceeded meaning + // that the client should send the DeleteSession message + // to the server. We will assert that both the client + // and server have deleted the appropriate sessions and + // channel info. + + // Before we mine blocks, assert that the client + // currently has 3 closable sessions. + closableSess, err := h.clientDB.ListClosableSessions() + require.NoError(h.t, err) + require.Len(h.t, closableSess, 3) + + // Assert that the server is also aware of all of these + // sessions. + for sid := range closableSess { + _, err := h.serverDB.GetSessionInfo(&sid) + require.NoError(h.t, err) + } + + // Also make a note of the total number of sessions the + // client has. + sessions, err := h.clientDB.ListClientSessions(nil, nil) + require.NoError(h.t, err) + require.Len(h.t, sessions, 4) + + h.mine(3) + + // The client should no longer have any closable + // sessions and the total list of client sessions should + // no longer include the three that it previously had + // marked as closable. The server should also no longer + // have these sessions in its DB. + err = wait.Predicate(func() bool { + sess, err := h.clientDB.ListClientSessions( + nil, nil, + ) + require.NoError(h.t, err) + + cs, err := h.clientDB.ListClosableSessions() + require.NoError(h.t, err) + + if len(sess) != 1 || len(cs) != 0 { + return false + } + + for sid := range closableSess { + _, ok := sess[sid] + if ok { + return false + } + + _, err := h.serverDB.GetSessionInfo( + &sid, + ) + if !errors.Is( + err, wtdb.ErrSessionNotFound, + ) { + return false + } + } + + return true + + }, waitTime) + require.NoError(h.t, err) }, }, } From d840761cc4a1c75678d29007f6e1ae8f5ad7b93c Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 26 Oct 2022 10:31:39 +0200 Subject: [PATCH 49/87] watchtower: dont load closed channel details In this commit, the FetchChanSummaries method is adapted to skip loading any channel summaries if the channel has been marked as closed. --- watchtower/wtclient/interface.go | 3 ++- watchtower/wtdb/client_db.go | 10 +++++++++- watchtower/wtmock/client_db.go | 8 +++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/watchtower/wtclient/interface.go b/watchtower/wtclient/interface.go index 4dd9176ae..4eebef4e5 100644 --- a/watchtower/wtclient/interface.go +++ b/watchtower/wtclient/interface.go @@ -83,7 +83,8 @@ type DB interface { NumAckedUpdates(id *wtdb.SessionID) (uint64, error) // FetchChanSummaries loads a mapping from all registered channels to - // their channel summaries. + // their channel summaries. Only the channels that have not yet been + // marked as closed will be loaded. FetchChanSummaries() (wtdb.ChannelSummaries, error) // MarkChannelClosed will mark a registered channel as closed by setting diff --git a/watchtower/wtdb/client_db.go b/watchtower/wtdb/client_db.go index c3e5447d6..53c643b6f 100644 --- a/watchtower/wtdb/client_db.go +++ b/watchtower/wtdb/client_db.go @@ -1284,7 +1284,8 @@ func (c *ClientDB) NumAckedUpdates(id *SessionID) (uint64, error) { } // FetchChanSummaries loads a mapping from all registered channels to their -// channel summaries. +// channel summaries. Only the channels that have not yet been marked as closed +// will be loaded. func (c *ClientDB) FetchChanSummaries() (ChannelSummaries, error) { var summaries map[lnwire.ChannelID]ClientChanSummary @@ -1300,6 +1301,13 @@ func (c *ClientDB) FetchChanSummaries() (ChannelSummaries, error) { return ErrCorruptChanDetails } + // If this channel has already been marked as closed, + // then its summary does not need to be loaded. + closedHeight := chanDetails.Get(cChanClosedHeight) + if len(closedHeight) > 0 { + return nil + } + var chanID lnwire.ChannelID copy(chanID[:], k) diff --git a/watchtower/wtmock/client_db.go b/watchtower/wtmock/client_db.go index 7213f17b6..e004fcdaf 100644 --- a/watchtower/wtmock/client_db.go +++ b/watchtower/wtmock/client_db.go @@ -566,13 +566,19 @@ func (m *ClientDB) ListClosableSessions() (map[wtdb.SessionID]uint32, error) { } // FetchChanSummaries loads a mapping from all registered channels to their -// channel summaries. +// channel summaries. Only the channels that have not yet been marked as closed +// will be loaded. func (m *ClientDB) FetchChanSummaries() (wtdb.ChannelSummaries, error) { m.mu.Lock() defer m.mu.Unlock() summaries := make(map[lnwire.ChannelID]wtdb.ClientChanSummary) for chanID, channel := range m.channels { + // Don't load the channel if it has been marked as closed. + if channel.closedHeight > 0 { + continue + } + summaries[chanID] = wtdb.ClientChanSummary{ SweepPkScript: cloneBytes( channel.summary.SweepPkScript, From bad80ff583fbbeecd76fd5645a98ffa7f781d4e4 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 6 Dec 2022 13:50:15 +0200 Subject: [PATCH 50/87] multi: make tower MaxUpdates configurable This is helpful in an itest environment where we want to quickly saturate a session. --- lncfg/wtclient.go | 4 ++++ sample-lnd.conf | 3 +++ server.go | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/lncfg/wtclient.go b/lncfg/wtclient.go index 7d4331112..feaae464c 100644 --- a/lncfg/wtclient.go +++ b/lncfg/wtclient.go @@ -22,6 +22,10 @@ type WtClient struct { // of blocks to wait after the last channel of a session is closed // before sending the DeleteSession message to the tower server. SessionCloseRange uint32 `long:"session-close-range" description:"The range over which to choose a random number of blocks to wait after the last channel of a session is closed before sending the DeleteSession message to the tower server. Set to 1 for no delay."` + + // MaxUpdates is the maximum number of updates to be backed up in a + // single tower sessions. + MaxUpdates uint16 `long:"max-updates" description:"The maximum number of updates to be backed up in a single session."` } // Validate ensures the user has provided a valid configuration. diff --git a/sample-lnd.conf b/sample-lnd.conf index f0edda984..b0499294b 100644 --- a/sample-lnd.conf +++ b/sample-lnd.conf @@ -1004,6 +1004,9 @@ litecoin.node=ltcd ; along with reduced privacy from the tower server. ; wtclient.session-close-range=10 +; The maximum number of updates to include in a tower session. +; wtclient.max-updates=1024 + [healthcheck] ; The number of times we should attempt to query our chain backend before diff --git a/server.go b/server.go index eef43550b..2224976e5 100644 --- a/server.go +++ b/server.go @@ -1497,6 +1497,10 @@ func newServer(cfg *Config, listenAddrs []net.Addr, policy.SweepFeeRate = sweepRateSatPerVByte.FeePerKWeight() } + if cfg.WtClient.MaxUpdates != 0 { + policy.MaxUpdates = cfg.WtClient.MaxUpdates + } + sessionCloseRange := uint32(wtclient.DefaultSessionCloseRange) if cfg.WtClient.SessionCloseRange != 0 { sessionCloseRange = cfg.WtClient.SessionCloseRange From 31beacc2c45492c53b9caaef31d5b9c4e720f430 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 17 Mar 2023 12:51:06 +0200 Subject: [PATCH 51/87] lnrpc/wtclientrpc: populate sessions from legacy channels --- lnrpc/wtclientrpc/wtclient.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lnrpc/wtclientrpc/wtclient.go b/lnrpc/wtclientrpc/wtclient.go index 415ae1702..335c370c8 100644 --- a/lnrpc/wtclientrpc/wtclient.go +++ b/lnrpc/wtclientrpc/wtclient.go @@ -309,6 +309,7 @@ func (c *WatchtowerClient) ListTowers(ctx context.Context, } t.SessionInfo = append(t.SessionInfo, rpcTower.SessionInfo...) + t.Sessions = append(t.Sessions, rpcTower.Sessions...) } towers := make([]*Tower, 0, len(rpcTowers)) @@ -365,6 +366,9 @@ func (c *WatchtowerClient) GetTowerInfo(ctx context.Context, rpcTower.SessionInfo = append( rpcTower.SessionInfo, rpcLegacyTower.SessionInfo..., ) + rpcTower.Sessions = append( + rpcTower.Sessions, rpcLegacyTower.Sessions..., + ) return rpcTower, nil } From 6f4034f7d1100615e13229964fdb7716dea25395 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 6 Dec 2022 13:52:00 +0200 Subject: [PATCH 52/87] lntest/itest: add session deletion itest --- itest/list_on_test.go | 4 + itest/lnd_watchtower_test.go | 172 +++++++++++++++++++++++++++++++++++ lntest/rpc/watchtower.go | 14 +++ 3 files changed, 190 insertions(+) create mode 100644 itest/lnd_watchtower_test.go diff --git a/itest/list_on_test.go b/itest/list_on_test.go index d2253969f..19f083cbb 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -515,4 +515,8 @@ var allTestCases = []*lntest.TestCase{ Name: "lookup htlc resolution", TestFunc: testLookupHtlcResolution, }, + { + Name: "watchtower session management", + TestFunc: testWatchtowerSessionManagement, + }, } diff --git a/itest/lnd_watchtower_test.go b/itest/lnd_watchtower_test.go new file mode 100644 index 000000000..3432848d8 --- /dev/null +++ b/itest/lnd_watchtower_test.go @@ -0,0 +1,172 @@ +package itest + +import ( + "fmt" + + "github.com/btcsuite/btcd/btcutil" + "github.com/lightningnetwork/lnd/funding" + "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/lnrpc/routerrpc" + "github.com/lightningnetwork/lnd/lnrpc/wtclientrpc" + "github.com/lightningnetwork/lnd/lntest" + "github.com/lightningnetwork/lnd/lntest/node" + "github.com/lightningnetwork/lnd/lntest/wait" + "github.com/stretchr/testify/require" +) + +// testWatchtowerSessionManagement tests that session deletion is done +// correctly. +func testWatchtowerSessionManagement(ht *lntest.HarnessTest) { + const ( + chanAmt = funding.MaxBtcFundingAmount + paymentAmt = 10_000 + numInvoices = 5 + maxUpdates = numInvoices * 2 + externalIP = "1.2.3.4" + sessionCloseRange = 1 + ) + + // Set up Wallis the watchtower who will be used by Dave to watch over + // his channel commitment transactions. + wallis := ht.NewNode("Wallis", []string{ + "--watchtower.active", + "--watchtower.externalip=" + externalIP, + }) + + wallisInfo := wallis.RPC.GetInfoWatchtower() + + // Assert that Wallis has one listener and it is 0.0.0.0:9911 or + // [::]:9911. Since no listener is explicitly specified, one of these + // should be the default depending on whether the host supports IPv6 or + // not. + require.Len(ht, wallisInfo.Listeners, 1) + listener := wallisInfo.Listeners[0] + require.True(ht, listener == "0.0.0.0:9911" || listener == "[::]:9911") + + // Assert the Wallis's URIs properly display the chosen external IP. + require.Len(ht, wallisInfo.Uris, 1) + require.Contains(ht, wallisInfo.Uris[0], externalIP) + + // Dave will be the tower client. + daveArgs := []string{ + "--wtclient.active", + fmt.Sprintf("--wtclient.max-updates=%d", maxUpdates), + fmt.Sprintf( + "--wtclient.session-close-range=%d", sessionCloseRange, + ), + } + dave := ht.NewNode("Dave", daveArgs) + + addTowerReq := &wtclientrpc.AddTowerRequest{ + Pubkey: wallisInfo.Pubkey, + Address: listener, + } + dave.RPC.AddTower(addTowerReq) + + // Assert that there exists a session between Dave and Wallis. + err := wait.NoError(func() error { + info := dave.RPC.GetTowerInfo(&wtclientrpc.GetTowerInfoRequest{ + Pubkey: wallisInfo.Pubkey, + IncludeSessions: true, + }) + + var numSessions uint32 + for _, sessionType := range info.SessionInfo { + numSessions += sessionType.NumSessions + } + if numSessions > 0 { + return nil + } + + return fmt.Errorf("expected a non-zero number of sessions") + }, defaultTimeout) + require.NoError(ht, err) + + // Before we make a channel, we'll load up Dave with some coins sent + // directly from the miner. + ht.FundCoins(btcutil.SatoshiPerBitcoin, dave) + + // Connect Dave and Alice. + ht.ConnectNodes(dave, ht.Alice) + + // Open a channel between Dave and Alice. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + } + chanPoint := ht.OpenChannel(dave, ht.Alice, params) + + // Since there are 2 updates made for every payment and the maximum + // number of updates per session has been set to 10, make 5 payments + // between the pair so that the session is exhausted. + alicePayReqs, _, _ := ht.CreatePayReqs( + ht.Alice, paymentAmt, numInvoices, + ) + + send := func(node *node.HarnessNode, payReq string) { + stream := node.RPC.SendPayment(&routerrpc.SendPaymentRequest{ + PaymentRequest: payReq, + TimeoutSeconds: 60, + FeeLimitMsat: noFeeLimitMsat, + }) + + ht.AssertPaymentStatusFromStream( + stream, lnrpc.Payment_SUCCEEDED, + ) + } + + for i := 0; i < numInvoices; i++ { + send(dave, alicePayReqs[i]) + } + + // assertNumBackups is a closure that asserts that Dave has a certain + // number of backups backed up to the tower. If mineOnFail is true, + // then a block will be mined each time the assertion fails. + assertNumBackups := func(expected int, mineOnFail bool) { + err = wait.NoError(func() error { + info := dave.RPC.GetTowerInfo( + &wtclientrpc.GetTowerInfoRequest{ + Pubkey: wallisInfo.Pubkey, + IncludeSessions: true, + }, + ) + + var numBackups uint32 + for _, sessionType := range info.SessionInfo { + for _, session := range sessionType.Sessions { + numBackups += session.NumBackups + } + } + + if numBackups == uint32(expected) { + return nil + } + + if mineOnFail { + ht.Miner.MineBlocksSlow(1) + } + + return fmt.Errorf("expected %d backups, got %d", + expected, numBackups) + }, defaultTimeout) + require.NoError(ht, err) + } + + // Assert that one of the sessions now has 10 backups. + assertNumBackups(10, false) + + // Now close the channel and wait for the close transaction to appear + // in the mempool so that it is included in a block when we mine. + ht.CloseChannelAssertPending(dave, chanPoint, false) + + // Mine enough blocks to surpass the session-close-range. This should + // trigger the session to be deleted. + ht.MineBlocksAndAssertNumTxes(sessionCloseRange+6, 1) + + // Wait for the session to be deleted. We know it has been deleted once + // the number of backups is back to zero. We check for number of backups + // instead of number of sessions because it is expected that the client + // would immediately negotiate another session after deleting the + // exhausted one. This time we set the "mineOnFail" parameter to true to + // ensure that the session deleting logic is run. + assertNumBackups(0, true) +} diff --git a/lntest/rpc/watchtower.go b/lntest/rpc/watchtower.go index 1b05d15ea..d5512e7a4 100644 --- a/lntest/rpc/watchtower.go +++ b/lntest/rpc/watchtower.go @@ -24,6 +24,20 @@ func (h *HarnessRPC) GetInfoWatchtower() *watchtowerrpc.GetInfoResponse { return info } +// GetTowerInfo makes an RPC call to the watchtower client of the given node and +// asserts. +func (h *HarnessRPC) GetTowerInfo( + req *wtclientrpc.GetTowerInfoRequest) *wtclientrpc.Tower { + + ctxt, cancel := context.WithTimeout(h.runCtx, DefaultTimeout) + defer cancel() + + info, err := h.WatchtowerClient.GetTowerInfo(ctxt, req) + h.NoError(err, "GetTowerInfo from WatchtowerClient") + + return info +} + // AddTower makes a RPC call to the WatchtowerClient of the given node and // asserts. func (h *HarnessRPC) AddTower( From ab98fc43fe1b459e444884dc26e2eeb3f48d9274 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 21 Oct 2022 22:08:27 +0200 Subject: [PATCH 53/87] docs: add release note for 7069 --- docs/release-notes/release-notes-0.16.1.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index 983f4f358..2b5cdc801 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -9,6 +9,9 @@ * [Allow caller to filter sessions at the time of reading them from disk](https://github.com/lightningnetwork/lnd/pull/7059) +* [Clean up sessions once all channels for which they have updates for are + closed. Also start sending the `DeleteSession` message to the + tower.](https://github.com/lightningnetwork/lnd/pull/7069) ## Misc From 7bc86ca42ebf665b2e6b422a079cc58819246e85 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 20 Mar 2023 17:06:48 +0200 Subject: [PATCH 54/87] watchtower: add PreEvaluateFilterFn callback In this commit, a PreEvaluateFilterFn option is added to the wtdb.ClientSessionListCfg and it is used instead of a separate ClientSessionFilterFn parameter. This neatens quiet a few function signatures. --- watchtower/wtclient/client.go | 36 ++++++++++-------------- watchtower/wtclient/client_test.go | 8 ++---- watchtower/wtclient/interface.go | 3 +- watchtower/wtdb/client_db.go | 45 ++++++++++++++++++++---------- watchtower/wtdb/client_db_test.go | 13 ++++----- watchtower/wtmock/client_db.go | 13 +++++---- 6 files changed, 61 insertions(+), 57 deletions(-) diff --git a/watchtower/wtclient/client.go b/watchtower/wtclient/client.go index e92b8b4cf..81c2d6b0c 100644 --- a/watchtower/wtclient/client.go +++ b/watchtower/wtclient/client.go @@ -410,8 +410,9 @@ func New(config *Config) (*TowerClient, error) { // current policy of the client, otherwise they will be ignored and new // sessions will be requested. candidateSessions, err := getTowerAndSessionCandidates( - cfg.DB, cfg.SecretKeyRing, c.genSessionFilter(true), - perActiveTower, wtdb.WithPerMaxHeight(perMaxHeight), + cfg.DB, cfg.SecretKeyRing, perActiveTower, + wtdb.WithPreEvalFilterFn(c.genSessionFilter(true)), + wtdb.WithPerMaxHeight(perMaxHeight), wtdb.WithPerCommittedUpdate(perCommittedUpdate), ) if err != nil { @@ -444,7 +445,6 @@ func New(config *Config) (*TowerClient, error) { // sessionFilter check then the perActiveTower call-back will be called on that // tower. func getTowerAndSessionCandidates(db DB, keyRing ECDHKeyRing, - sessionFilter wtdb.ClientSessionFilterFn, perActiveTower func(tower *Tower), opts ...wtdb.ClientSessionListOption) ( map[wtdb.SessionID]*ClientSession, error) { @@ -461,18 +461,12 @@ func getTowerAndSessionCandidates(db DB, keyRing ECDHKeyRing, return nil, err } - sessions, err := db.ListClientSessions( - &tower.ID, sessionFilter, opts..., - ) + sessions, err := db.ListClientSessions(&tower.ID, opts...) if err != nil { return nil, err } for _, s := range sessions { - if !sessionFilter(s) { - continue - } - cs, err := NewClientSessionFromDBSession( s, tower, keyRing, ) @@ -498,13 +492,10 @@ func getTowerAndSessionCandidates(db DB, keyRing ECDHKeyRing, // ClientSession's SessionPrivKey field is desired, otherwise, the existing // ListClientSessions method should be used. func getClientSessions(db DB, keyRing ECDHKeyRing, forTower *wtdb.TowerID, - sessionFilter wtdb.ClientSessionFilterFn, opts ...wtdb.ClientSessionListOption) ( map[wtdb.SessionID]*ClientSession, error) { - dbSessions, err := db.ListClientSessions( - forTower, sessionFilter, opts..., - ) + dbSessions, err := db.ListClientSessions(forTower, opts...) if err != nil { return nil, err } @@ -1635,7 +1626,7 @@ func (c *TowerClient) handleNewTower(msg *newTowerMsg) error { // Include all of its corresponding sessions to our set of candidates. sessions, err := getClientSessions( c.cfg.DB, c.cfg.SecretKeyRing, &tower.ID, - c.genSessionFilter(true), + wtdb.WithPreEvalFilterFn(c.genSessionFilter(true)), ) if err != nil { return fmt.Errorf("unable to determine sessions for tower %x: "+ @@ -1721,7 +1712,7 @@ func (c *TowerClient) handleStaleTower(msg *staleTowerMsg) error { // Otherwise, the tower should no longer be used for future session // negotiations and backups. pubKey := msg.pubKey.SerializeCompressed() - sessions, err := c.cfg.DB.ListClientSessions(&dbTower.ID, nil) + sessions, err := c.cfg.DB.ListClientSessions(&dbTower.ID) if err != nil { return fmt.Errorf("unable to retrieve sessions for tower %x: "+ "%v", pubKey, err) @@ -1752,9 +1743,10 @@ func (c *TowerClient) RegisteredTowers(opts ...wtdb.ClientSessionListOption) ( if err != nil { return nil, err } - clientSessions, err := c.cfg.DB.ListClientSessions( - nil, c.genSessionFilter(false), opts..., - ) + + opts = append(opts, wtdb.WithPreEvalFilterFn(c.genSessionFilter(false))) + + clientSessions, err := c.cfg.DB.ListClientSessions(nil, opts...) if err != nil { return nil, err } @@ -1795,9 +1787,9 @@ func (c *TowerClient) LookupTower(pubKey *btcec.PublicKey, return nil, err } - towerSessions, err := c.cfg.DB.ListClientSessions( - &tower.ID, c.genSessionFilter(false), opts..., - ) + opts = append(opts, wtdb.WithPreEvalFilterFn(c.genSessionFilter(false))) + + towerSessions, err := c.cfg.DB.ListClientSessions(&tower.ID, opts...) if err != nil { return nil, err } diff --git a/watchtower/wtclient/client_test.go b/watchtower/wtclient/client_test.go index 2657e691b..f870af527 100644 --- a/watchtower/wtclient/client_test.go +++ b/watchtower/wtclient/client_test.go @@ -870,7 +870,7 @@ func (h *testHarness) relevantSessions(chanID uint64) []wtdb.SessionID { }, ) - _, err := h.clientDB.ListClientSessions(nil, nil, collectSessions) + _, err := h.clientDB.ListClientSessions(nil, collectSessions) require.NoError(h.t, err) return sessionIDs @@ -1969,7 +1969,7 @@ var clientTests = []clientTest{ // Also make a note of the total number of sessions the // client has. - sessions, err := h.clientDB.ListClientSessions(nil, nil) + sessions, err := h.clientDB.ListClientSessions(nil) require.NoError(h.t, err) require.Len(h.t, sessions, 4) @@ -1981,9 +1981,7 @@ var clientTests = []clientTest{ // marked as closable. The server should also no longer // have these sessions in its DB. err = wait.Predicate(func() bool { - sess, err := h.clientDB.ListClientSessions( - nil, nil, - ) + sess, err := h.clientDB.ListClientSessions(nil) require.NoError(h.t, err) cs, err := h.clientDB.ListClosableSessions() diff --git a/watchtower/wtclient/interface.go b/watchtower/wtclient/interface.go index 4eebef4e5..8a6d9b320 100644 --- a/watchtower/wtclient/interface.go +++ b/watchtower/wtclient/interface.go @@ -60,8 +60,7 @@ type DB interface { // ListClientSessions returns the set of all client sessions known to // the db. An optional tower ID can be used to filter out any client // sessions in the response that do not correspond to this tower. - ListClientSessions(*wtdb.TowerID, wtdb.ClientSessionFilterFn, - ...wtdb.ClientSessionListOption) ( + ListClientSessions(*wtdb.TowerID, ...wtdb.ClientSessionListOption) ( map[wtdb.SessionID]*wtdb.ClientSession, error) // GetClientSession loads the ClientSession with the given ID from the diff --git a/watchtower/wtdb/client_db.go b/watchtower/wtdb/client_db.go index 53c643b6f..2e64e6122 100644 --- a/watchtower/wtdb/client_db.go +++ b/watchtower/wtdb/client_db.go @@ -517,7 +517,7 @@ func (c *ClientDB) RemoveTower(pubKey *btcec.PublicKey, addr net.Addr) error { towerSessions, err := c.listTowerSessions( towerID, sessions, chanIDIndexBkt, - towersToSessionsIndex, nil, + towersToSessionsIndex, WithPerCommittedUpdate(perCommittedUpdate), ) if err != nil { @@ -1055,7 +1055,7 @@ func (c *ClientDB) GetClientSession(id SessionID, } session, err := c.getClientSession( - sessionsBkt, chanIDIndexBkt, id[:], nil, opts..., + sessionsBkt, chanIDIndexBkt, id[:], opts..., ) if err != nil { return err @@ -1073,8 +1073,7 @@ func (c *ClientDB) GetClientSession(id SessionID, // optional tower ID can be used to filter out any client sessions in the // response that do not correspond to this tower. func (c *ClientDB) ListClientSessions(id *TowerID, - filterFn ClientSessionFilterFn, opts ...ClientSessionListOption) ( - map[SessionID]*ClientSession, error) { + opts ...ClientSessionListOption) (map[SessionID]*ClientSession, error) { var clientSessions map[SessionID]*ClientSession err := kvdb.View(c.db, func(tx kvdb.RTx) error { @@ -1093,7 +1092,7 @@ func (c *ClientDB) ListClientSessions(id *TowerID, var err error if id == nil { clientSessions, err = c.listClientAllSessions( - sessions, chanIDIndexBkt, filterFn, opts..., + sessions, chanIDIndexBkt, opts..., ) return err } @@ -1106,7 +1105,7 @@ func (c *ClientDB) ListClientSessions(id *TowerID, clientSessions, err = c.listTowerSessions( *id, sessions, chanIDIndexBkt, towerToSessionIndex, - filterFn, opts..., + opts..., ) return err }, func() { @@ -1121,8 +1120,7 @@ func (c *ClientDB) ListClientSessions(id *TowerID, // listClientAllSessions returns the set of all client sessions known to the db. func (c *ClientDB) listClientAllSessions(sessions, chanIDIndexBkt kvdb.RBucket, - filterFn ClientSessionFilterFn, opts ...ClientSessionListOption) ( - map[SessionID]*ClientSession, error) { + opts ...ClientSessionListOption) (map[SessionID]*ClientSession, error) { clientSessions := make(map[SessionID]*ClientSession) err := sessions.ForEach(func(k, _ []byte) error { @@ -1131,7 +1129,7 @@ func (c *ClientDB) listClientAllSessions(sessions, chanIDIndexBkt kvdb.RBucket, // committed updates and compute the highest known commit height // for each channel. session, err := c.getClientSession( - sessions, chanIDIndexBkt, k, filterFn, opts..., + sessions, chanIDIndexBkt, k, opts..., ) if errors.Is(err, ErrSessionFailedFilterFn) { return nil @@ -1153,8 +1151,8 @@ func (c *ClientDB) listClientAllSessions(sessions, chanIDIndexBkt kvdb.RBucket, // listTowerSessions returns the set of all client sessions known to the db // that are associated with the given tower id. func (c *ClientDB) listTowerSessions(id TowerID, sessionsBkt, chanIDIndexBkt, - towerToSessionIndex kvdb.RBucket, filterFn ClientSessionFilterFn, - opts ...ClientSessionListOption) (map[SessionID]*ClientSession, error) { + towerToSessionIndex kvdb.RBucket, opts ...ClientSessionListOption) ( + map[SessionID]*ClientSession, error) { towerIndexBkt := towerToSessionIndex.NestedReadBucket(id.Bytes()) if towerIndexBkt == nil { @@ -1168,7 +1166,7 @@ func (c *ClientDB) listTowerSessions(id TowerID, sessionsBkt, chanIDIndexBkt, // committed updates and compute the highest known commit height // for each channel. session, err := c.getClientSession( - sessionsBkt, chanIDIndexBkt, k, filterFn, opts..., + sessionsBkt, chanIDIndexBkt, k, opts..., ) if errors.Is(err, ErrSessionFailedFilterFn) { return nil @@ -2140,6 +2138,13 @@ type ClientSessionListCfg struct { // PerCommittedUpdate will, if set, be called for each of the session's // committed (un-acked) updates. PerCommittedUpdate PerCommittedUpdateCB + + // PreEvaluateFilterFn will be run after loading a session from the DB + // and _before_ any of the other call-back functions in + // ClientSessionListCfg. Therefore, if a session fails this filter + // function, then it will not be passed to any of the other call backs + // and won't be included in the return list. + PreEvaluateFilterFn ClientSessionFilterFn } // NewClientSessionCfg constructs a new ClientSessionListCfg. @@ -2174,12 +2179,22 @@ func WithPerCommittedUpdate(cb PerCommittedUpdateCB) ClientSessionListOption { } } +// WithPreEvalFilterFn constructs a functional option that will set a call-back +// function that will be called immediately after loading a session. If the +// session fails this filter function, then it will not be passed to any of the +// other evaluation call-back functions. +func WithPreEvalFilterFn(fn ClientSessionFilterFn) ClientSessionListOption { + return func(cfg *ClientSessionListCfg) { + cfg.PreEvaluateFilterFn = fn + } +} + // getClientSession loads the full ClientSession associated with the serialized // session id. This method populates the CommittedUpdates, AckUpdates and Tower // in addition to the ClientSession's body. func (c *ClientDB) getClientSession(sessionsBkt, chanIDIndexBkt kvdb.RBucket, - idBytes []byte, filterFn ClientSessionFilterFn, - opts ...ClientSessionListOption) (*ClientSession, error) { + idBytes []byte, opts ...ClientSessionListOption) (*ClientSession, + error) { cfg := NewClientSessionCfg() for _, o := range opts { @@ -2191,7 +2206,7 @@ func (c *ClientDB) getClientSession(sessionsBkt, chanIDIndexBkt kvdb.RBucket, return nil, err } - if filterFn != nil && !filterFn(session) { + if cfg.PreEvaluateFilterFn != nil && !cfg.PreEvaluateFilterFn(session) { return nil, ErrSessionFailedFilterFn } diff --git a/watchtower/wtdb/client_db_test.go b/watchtower/wtdb/client_db_test.go index b3d241175..26d02bcf3 100644 --- a/watchtower/wtdb/client_db_test.go +++ b/watchtower/wtdb/client_db_test.go @@ -52,12 +52,11 @@ func (h *clientDBHarness) insertSession(session *wtdb.ClientSession, } func (h *clientDBHarness) listSessions(id *wtdb.TowerID, - filterFn wtdb.ClientSessionFilterFn, opts ...wtdb.ClientSessionListOption) map[wtdb.SessionID]*wtdb.ClientSession { h.t.Helper() - sessions, err := h.db.ListClientSessions(id, filterFn, opts...) + sessions, err := h.db.ListClientSessions(id, opts...) require.NoError(h.t, err, "unable to list client sessions") return sessions @@ -84,7 +83,7 @@ func (h *clientDBHarness) createTower(lnAddr *lnwire.NetAddress, require.ErrorIs(h.t, err, expErr) require.NotZero(h.t, tower.ID, "tower id should never be 0") - for _, session := range h.listSessions(&tower.ID, nil) { + for _, session := range h.listSessions(&tower.ID) { require.Equal(h.t, wtdb.CSessionActive, session.Status) } @@ -127,7 +126,7 @@ func (h *clientDBHarness) removeTower(pubKey *btcec.PublicKey, addr net.Addr, return } - for _, session := range h.listSessions(&tower.ID, nil) { + for _, session := range h.listSessions(&tower.ID) { require.Equal(h.t, wtdb.CSessionInactive, session.Status, "expected status for session "+ "%v to be %v, got %v", session.ID, @@ -301,7 +300,7 @@ func testCreateClientSession(h *clientDBHarness) { // First, assert that this session is not already present in the // database. - _, ok := h.listSessions(nil, nil)[session.ID] + _, ok := h.listSessions(nil)[session.ID] require.Falsef(h.t, ok, "session for id %x should not exist yet", session.ID) @@ -329,7 +328,7 @@ func testCreateClientSession(h *clientDBHarness) { h.insertSession(session, nil) // Verify that the session now exists in the database. - _, ok = h.listSessions(nil, nil)[session.ID] + _, ok = h.listSessions(nil)[session.ID] require.Truef(h.t, ok, "session for id %x should exist now", session.ID) // Attempt to insert the session again, which should fail due to the @@ -377,7 +376,7 @@ func testFilterClientSessions(h *clientDBHarness) { // We should see the expected sessions for each tower when filtering // them. for towerID, expectedSessions := range towerSessions { - sessions := h.listSessions(&towerID, nil) + sessions := h.listSessions(&towerID) require.Len(h.t, sessions, len(expectedSessions)) for _, expectedSession := range expectedSessions { diff --git a/watchtower/wtmock/client_db.go b/watchtower/wtmock/client_db.go index e004fcdaf..22b21a563 100644 --- a/watchtower/wtmock/client_db.go +++ b/watchtower/wtmock/client_db.go @@ -89,7 +89,7 @@ func (m *ClientDB) CreateTower(lnAddr *lnwire.NetAddress) (*wtdb.Tower, error) { tower = m.towers[towerID] tower.AddAddress(lnAddr.Address) - towerSessions, err := m.listClientSessions(&towerID, nil) + towerSessions, err := m.listClientSessions(&towerID) if err != nil { return nil, err } @@ -141,7 +141,7 @@ func (m *ClientDB) RemoveTower(pubKey *btcec.PublicKey, addr net.Addr) error { return nil } - towerSessions, err := m.listClientSessions(&tower.ID, nil) + towerSessions, err := m.listClientSessions(&tower.ID) if err != nil { return err } @@ -226,20 +226,19 @@ func (m *ClientDB) MarkBackupIneligible(_ lnwire.ChannelID, _ uint64) error { // optional tower ID can be used to filter out any client sessions in the // response that do not correspond to this tower. func (m *ClientDB) ListClientSessions(tower *wtdb.TowerID, - filterFn wtdb.ClientSessionFilterFn, opts ...wtdb.ClientSessionListOption) ( map[wtdb.SessionID]*wtdb.ClientSession, error) { m.mu.Lock() defer m.mu.Unlock() - return m.listClientSessions(tower, filterFn, opts...) + + return m.listClientSessions(tower, opts...) } // listClientSessions returns the set of all client sessions known to the db. An // optional tower ID can be used to filter out any client sessions in the // response that do not correspond to this tower. func (m *ClientDB) listClientSessions(tower *wtdb.TowerID, - filterFn wtdb.ClientSessionFilterFn, opts ...wtdb.ClientSessionListOption) ( map[wtdb.SessionID]*wtdb.ClientSession, error) { @@ -255,7 +254,9 @@ func (m *ClientDB) listClientSessions(tower *wtdb.TowerID, continue } - if filterFn != nil && !filterFn(&session) { + if cfg.PreEvaluateFilterFn != nil && + !cfg.PreEvaluateFilterFn(&session) { + continue } From 49cd23725a77957512d91eb22fa3100ee2747053 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 20 Mar 2023 17:28:53 +0200 Subject: [PATCH 55/87] watchtower: add PostEvaluateFilterFn call-back option This commit adds a new PostEvaluateFilterFn call-back option to `wtdb.ClientSessionListCfg`. This call-back is run _after_ all the other evaluation call-backs in `wtdb.ClientSessionListCfg` and is only used to determine if the session should be included in the returned list or not. --- watchtower/wtdb/client_db.go | 25 +++++++++++++++++++++++++ watchtower/wtmock/client_db.go | 10 ++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/watchtower/wtdb/client_db.go b/watchtower/wtdb/client_db.go index 2e64e6122..5a18095b8 100644 --- a/watchtower/wtdb/client_db.go +++ b/watchtower/wtdb/client_db.go @@ -2145,6 +2145,12 @@ type ClientSessionListCfg struct { // function, then it will not be passed to any of the other call backs // and won't be included in the return list. PreEvaluateFilterFn ClientSessionFilterFn + + // PostEvaluateFilterFn will be run _after_ all the other call-back + // functions in ClientSessionListCfg. If a session fails this filter + // function then all it means is that it won't be included in the list + // of sessions to return. + PostEvaluateFilterFn ClientSessionFilterFn } // NewClientSessionCfg constructs a new ClientSessionListCfg. @@ -2189,6 +2195,19 @@ func WithPreEvalFilterFn(fn ClientSessionFilterFn) ClientSessionListOption { } } +// WithPostEvalFilterFn constructs a functional option that will set a call-back +// function that will be used to determine if a session should be included in +// the returned list. This differs from WithPreEvalFilterFn since that call-back +// is used to determine if the session should be evaluated at all (and thus +// run against the other ClientSessionListCfg call-backs) whereas the session +// will only reach the PostEvalFilterFn call-back once it has already been +// evaluated by all the other call-backs. +func WithPostEvalFilterFn(fn ClientSessionFilterFn) ClientSessionListOption { + return func(cfg *ClientSessionListCfg) { + cfg.PostEvaluateFilterFn = fn + } +} + // getClientSession loads the full ClientSession associated with the serialized // session id. This method populates the CommittedUpdates, AckUpdates and Tower // in addition to the ClientSession's body. @@ -2232,6 +2251,12 @@ func (c *ClientDB) getClientSession(sessionsBkt, chanIDIndexBkt kvdb.RBucket, return nil, err } + if cfg.PostEvaluateFilterFn != nil && + !cfg.PostEvaluateFilterFn(session) { + + return nil, ErrSessionFailedFilterFn + } + return session, nil } diff --git a/watchtower/wtmock/client_db.go b/watchtower/wtmock/client_db.go index 22b21a563..8d43a0e45 100644 --- a/watchtower/wtmock/client_db.go +++ b/watchtower/wtmock/client_db.go @@ -260,8 +260,6 @@ func (m *ClientDB) listClientSessions(tower *wtdb.TowerID, continue } - sessions[session.ID] = &session - if cfg.PerMaxHeight != nil { for chanID, index := range m.ackedUpdates[session.ID] { cfg.PerMaxHeight( @@ -285,6 +283,14 @@ func (m *ClientDB) listClientSessions(tower *wtdb.TowerID, cfg.PerCommittedUpdate(&session, &update) } } + + if cfg.PostEvaluateFilterFn != nil && + !cfg.PostEvaluateFilterFn(&session) { + + continue + } + + sessions[session.ID] = &session } return sessions, nil From 8623e6107d43b9ca7cf221bf68885f84da8944ad Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 20 Mar 2023 17:44:24 +0200 Subject: [PATCH 56/87] wtclient: don't unnecessarily load exhausted sessions In this commit, a new `ExhaustedSessionFilter` function is added and used as a PostEvalFilterFn used when loading sessions from the DB. It allows us to not unnecessarily load exhausted sessions into memory for areas of the code where they will not be needed. --- watchtower/wtclient/client.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/watchtower/wtclient/client.go b/watchtower/wtclient/client.go index 81c2d6b0c..9a26149c9 100644 --- a/watchtower/wtclient/client.go +++ b/watchtower/wtclient/client.go @@ -74,6 +74,14 @@ func (c *TowerClient) genSessionFilter( } } +// ExhaustedSessionFilter constructs a wtdb.ClientSessionFilterFn filter +// function that will filter out any sessions that have been exhausted. +func ExhaustedSessionFilter() wtdb.ClientSessionFilterFn { + return func(session *wtdb.ClientSession) bool { + return session.SeqNum < session.Policy.MaxUpdates + } +} + // RegisteredTower encompasses information about a registered watchtower with // the client. type RegisteredTower struct { @@ -414,6 +422,7 @@ func New(config *Config) (*TowerClient, error) { wtdb.WithPreEvalFilterFn(c.genSessionFilter(true)), wtdb.WithPerMaxHeight(perMaxHeight), wtdb.WithPerCommittedUpdate(perCommittedUpdate), + wtdb.WithPostEvalFilterFn(ExhaustedSessionFilter()), ) if err != nil { return nil, err @@ -1627,6 +1636,7 @@ func (c *TowerClient) handleNewTower(msg *newTowerMsg) error { sessions, err := getClientSessions( c.cfg.DB, c.cfg.SecretKeyRing, &tower.ID, wtdb.WithPreEvalFilterFn(c.genSessionFilter(true)), + wtdb.WithPostEvalFilterFn(ExhaustedSessionFilter()), ) if err != nil { return fmt.Errorf("unable to determine sessions for tower %x: "+ From 1af31bfea73531f60af1dd84e4c7cfcbb4dc3973 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 13 Feb 2023 17:02:18 +0200 Subject: [PATCH 57/87] wtclient: fix info log line format --- watchtower/wtclient/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/watchtower/wtclient/client.go b/watchtower/wtclient/client.go index 9a26149c9..96dcaa866 100644 --- a/watchtower/wtclient/client.go +++ b/watchtower/wtclient/client.go @@ -406,8 +406,8 @@ func New(config *Config) (*TowerClient, error) { return } - c.log.Infof("Using private watchtower %s, offering policy %s", - tower, cfg.Policy) + c.log.Infof("Using private watchtower %x, offering policy %s", + tower.IdentityKey.SerializeCompressed(), cfg.Policy) // Add the tower to the set of candidate towers. candidateTowers.AddCandidate(tower) From e6494889b06d688f4794006f2b340949f4f8aca6 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 20 Mar 2023 14:40:40 +0200 Subject: [PATCH 58/87] wtclientrpc: add excludeExhaustedSessions option Add a new `exclude_exhausted_sessions` field to the relevant wtclient.proto requests. This was chosen instead of "include_exhausted" so as to not break the API. --- lnrpc/wtclientrpc/wtclient.pb.go | 278 +++++++++++++----------- lnrpc/wtclientrpc/wtclient.proto | 8 + lnrpc/wtclientrpc/wtclient.swagger.json | 14 ++ 3 files changed, 175 insertions(+), 125 deletions(-) diff --git a/lnrpc/wtclientrpc/wtclient.pb.go b/lnrpc/wtclientrpc/wtclient.pb.go index 10f4559ee..f192d78cd 100644 --- a/lnrpc/wtclientrpc/wtclient.pb.go +++ b/lnrpc/wtclientrpc/wtclient.pb.go @@ -269,6 +269,9 @@ type GetTowerInfoRequest struct { Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"` // Whether we should include sessions with the watchtower in the response. IncludeSessions bool `protobuf:"varint,2,opt,name=include_sessions,json=includeSessions,proto3" json:"include_sessions,omitempty"` + // Whether to exclude exhausted sessions in the response info. This option + // is only meaningful if include_sessions is true. + ExcludeExhaustedSessions bool `protobuf:"varint,3,opt,name=exclude_exhausted_sessions,json=excludeExhaustedSessions,proto3" json:"exclude_exhausted_sessions,omitempty"` } func (x *GetTowerInfoRequest) Reset() { @@ -317,6 +320,13 @@ func (x *GetTowerInfoRequest) GetIncludeSessions() bool { return false } +func (x *GetTowerInfoRequest) GetExcludeExhaustedSessions() bool { + if x != nil { + return x.ExcludeExhaustedSessions + } + return false +} + type TowerSession struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -599,6 +609,9 @@ type ListTowersRequest struct { // Whether we should include sessions with the watchtower in the response. IncludeSessions bool `protobuf:"varint,1,opt,name=include_sessions,json=includeSessions,proto3" json:"include_sessions,omitempty"` + // Whether to exclude exhausted sessions in the response info. This option + // is only meaningful if include_sessions is true. + ExcludeExhaustedSessions bool `protobuf:"varint,2,opt,name=exclude_exhausted_sessions,json=excludeExhaustedSessions,proto3" json:"exclude_exhausted_sessions,omitempty"` } func (x *ListTowersRequest) Reset() { @@ -640,6 +653,13 @@ func (x *ListTowersRequest) GetIncludeSessions() bool { return false } +func (x *ListTowersRequest) GetExcludeExhaustedSessions() bool { + if x != nil { + return x.ExcludeExhaustedSessions + } + return false +} + type ListTowersResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -951,132 +971,140 @@ var file_wtclientrpc_wtclient_proto_rawDesc = []byte{ 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x58, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, - 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, - 0x75, 0x64, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe0, 0x01, 0x0a, 0x0c, - 0x54, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, - 0x6e, 0x75, 0x6d, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x0a, 0x6e, 0x75, 0x6d, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x2e, 0x0a, - 0x13, 0x6e, 0x75, 0x6d, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x6e, 0x75, 0x6d, 0x50, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x1f, 0x0a, - 0x0b, 0x6d, 0x61, 0x78, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x2f, - 0x0a, 0x12, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, - 0x62, 0x79, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0f, - 0x73, 0x77, 0x65, 0x65, 0x70, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x12, - 0x2d, 0x0a, 0x13, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, - 0x5f, 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x73, 0x77, - 0x65, 0x65, 0x70, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, 0x22, 0x9f, - 0x02, 0x0a, 0x05, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, - 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x3c, - 0x0a, 0x18, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x5f, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, - 0x42, 0x02, 0x18, 0x01, 0x52, 0x16, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x25, 0x0a, 0x0c, - 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x39, 0x0a, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x42, 0x02, 0x18, 0x01, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x40, - 0x0a, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, - 0x22, 0xe0, 0x01, 0x0a, 0x10, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x38, 0x0a, 0x18, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, - 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, - 0x21, 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, + 0x65, 0x22, 0x96, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, + 0x79, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x6e, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3c, 0x0a, 0x1a, + 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x65, 0x78, 0x68, 0x61, 0x75, 0x73, 0x74, 0x65, + 0x64, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x18, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x45, 0x78, 0x68, 0x61, 0x75, 0x73, 0x74, + 0x65, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe0, 0x01, 0x0a, 0x0c, 0x54, + 0x6f, 0x77, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, + 0x75, 0x6d, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0a, 0x6e, 0x75, 0x6d, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x2e, 0x0a, 0x13, + 0x6e, 0x75, 0x6d, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x6e, 0x75, 0x6d, 0x50, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x1f, 0x0a, 0x0b, + 0x6d, 0x61, 0x78, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x2f, 0x0a, + 0x12, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x62, + 0x79, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0f, 0x73, + 0x77, 0x65, 0x65, 0x70, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x12, 0x2d, + 0x0a, 0x13, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, + 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x73, 0x77, 0x65, + 0x65, 0x70, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, 0x22, 0x9f, 0x02, + 0x0a, 0x05, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, + 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x3c, 0x0a, + 0x18, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, + 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x42, + 0x02, 0x18, 0x01, 0x52, 0x16, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x25, 0x0a, 0x0c, 0x6e, + 0x75, 0x6d, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x39, 0x0a, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x38, 0x0a, 0x0b, 0x70, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, - 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, - 0x79, 0x70, 0x65, 0x22, 0x3e, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, - 0x75, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x22, 0x40, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x74, 0x6f, 0x77, - 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x77, 0x74, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x06, 0x74, - 0x6f, 0x77, 0x65, 0x72, 0x73, 0x22, 0x0e, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xf8, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x75, 0x6d, 0x5f, 0x62, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6e, 0x75, - 0x6d, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x6e, 0x75, 0x6d, 0x5f, - 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x6e, 0x75, 0x6d, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6e, 0x75, 0x6d, 0x5f, - 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x6e, 0x75, 0x6d, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x61, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x34, 0x0a, 0x16, 0x6e, 0x75, - 0x6d, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x65, 0x78, 0x68, 0x61, 0x75, - 0x73, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x6e, 0x75, 0x6d, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x78, 0x68, 0x61, 0x75, 0x73, 0x74, 0x65, 0x64, - 0x22, 0x49, 0x0a, 0x0d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x38, 0x0a, 0x0b, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x0a, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x22, 0x91, 0x01, 0x0a, 0x0e, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, - 0x0a, 0x0b, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, - 0x2f, 0x0a, 0x12, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, - 0x5f, 0x62, 0x79, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, - 0x0f, 0x73, 0x77, 0x65, 0x65, 0x70, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, - 0x12, 0x2d, 0x0a, 0x13, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, - 0x72, 0x5f, 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x73, - 0x77, 0x65, 0x65, 0x70, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, 0x2a, - 0x24, 0x0a, 0x0a, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, - 0x06, 0x4c, 0x45, 0x47, 0x41, 0x43, 0x59, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4e, 0x43, - 0x48, 0x4f, 0x52, 0x10, 0x01, 0x32, 0xc5, 0x03, 0x0a, 0x10, 0x57, 0x61, 0x74, 0x63, 0x68, 0x74, - 0x6f, 0x77, 0x65, 0x72, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x08, 0x41, 0x64, - 0x64, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x77, - 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, - 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, - 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x05, 0x53, 0x74, - 0x61, 0x74, 0x73, 0x12, 0x19, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, - 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, - 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x06, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1a, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1b, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, - 0x31, 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, 0x2f, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, - 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x42, + 0x02, 0x18, 0x01, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x40, 0x0a, + 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x0b, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x22, + 0xe0, 0x01, 0x0a, 0x10, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x38, 0x0a, 0x18, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x21, + 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x35, 0x0a, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x38, 0x0a, 0x0b, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, + 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, + 0x70, 0x65, 0x22, 0x7c, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x3c, 0x0a, 0x1a, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x65, 0x78, + 0x68, 0x61, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x45, + 0x78, 0x68, 0x61, 0x75, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x22, 0x40, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x74, 0x6f, 0x77, 0x65, 0x72, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x06, 0x74, 0x6f, 0x77, 0x65, + 0x72, 0x73, 0x22, 0x0e, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x22, 0xf8, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x75, 0x6d, 0x5f, 0x62, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6e, 0x75, 0x6d, 0x42, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x6e, 0x75, 0x6d, 0x5f, 0x70, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x11, 0x6e, 0x75, 0x6d, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x42, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6e, 0x75, 0x6d, 0x5f, 0x66, 0x61, 0x69, + 0x6c, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x10, 0x6e, 0x75, 0x6d, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x6e, 0x75, 0x6d, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x5f, 0x61, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x13, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x41, + 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x34, 0x0a, 0x16, 0x6e, 0x75, 0x6d, 0x5f, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x65, 0x78, 0x68, 0x61, 0x75, 0x73, 0x74, 0x65, + 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x78, 0x68, 0x61, 0x75, 0x73, 0x74, 0x65, 0x64, 0x22, 0x49, 0x0a, + 0x0d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, + 0x0a, 0x0b, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x70, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x22, 0x91, 0x01, 0x0a, 0x0e, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, + 0x61, 0x78, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x12, + 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x79, + 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0f, 0x73, 0x77, + 0x65, 0x65, 0x70, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x12, 0x2d, 0x0a, + 0x13, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x76, + 0x62, 0x79, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x73, 0x77, 0x65, 0x65, + 0x70, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, 0x2a, 0x24, 0x0a, 0x0a, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x45, + 0x47, 0x41, 0x43, 0x59, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, + 0x10, 0x01, 0x32, 0xc5, 0x03, 0x0a, 0x10, 0x57, 0x61, 0x74, 0x63, 0x68, 0x74, 0x6f, 0x77, 0x65, + 0x72, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x08, 0x41, 0x64, 0x64, 0x54, 0x6f, + 0x77, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1d, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x41, 0x64, 0x64, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x50, 0x0a, 0x0b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x12, + 0x1f, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x20, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x73, + 0x12, 0x1e, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1f, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x44, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x20, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x47, 0x65, 0x74, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x73, + 0x12, 0x19, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x77, 0x74, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x12, 0x1a, 0x2e, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, + 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, 0x31, 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, 0x2f, 0x77, 0x74, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x72, 0x70, 0x63, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/lnrpc/wtclientrpc/wtclient.proto b/lnrpc/wtclientrpc/wtclient.proto index 45bdd24ef..413f61afa 100644 --- a/lnrpc/wtclientrpc/wtclient.proto +++ b/lnrpc/wtclientrpc/wtclient.proto @@ -68,6 +68,10 @@ message GetTowerInfoRequest { // Whether we should include sessions with the watchtower in the response. bool include_sessions = 2; + + // Whether to exclude exhausted sessions in the response info. This option + // is only meaningful if include_sessions is true. + bool exclude_exhausted_sessions = 3; } message TowerSession { @@ -143,6 +147,10 @@ message TowerSessionInfo { message ListTowersRequest { // Whether we should include sessions with the watchtower in the response. bool include_sessions = 1; + + // Whether to exclude exhausted sessions in the response info. This option + // is only meaningful if include_sessions is true. + bool exclude_exhausted_sessions = 2; } message ListTowersResponse { diff --git a/lnrpc/wtclientrpc/wtclient.swagger.json b/lnrpc/wtclientrpc/wtclient.swagger.json index 830dd10fe..47c2c396a 100644 --- a/lnrpc/wtclientrpc/wtclient.swagger.json +++ b/lnrpc/wtclientrpc/wtclient.swagger.json @@ -41,6 +41,13 @@ "in": "query", "required": false, "type": "boolean" + }, + { + "name": "exclude_exhausted_sessions", + "description": "Whether to exclude exhausted sessions in the response info. This option\nis only meaningful if include_sessions is true.", + "in": "query", + "required": false, + "type": "boolean" } ], "tags": [ @@ -112,6 +119,13 @@ "in": "query", "required": false, "type": "boolean" + }, + { + "name": "exclude_exhausted_sessions", + "description": "Whether to exclude exhausted sessions in the response info. This option\nis only meaningful if include_sessions is true.", + "in": "query", + "required": false, + "type": "boolean" } ], "tags": [ From 13c656defe3b1e78a520e7e7be660a4af4d3319d Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 20 Mar 2023 17:57:42 +0200 Subject: [PATCH 59/87] lnrpc: use new ExcludeExhaustedSessions option --- lnrpc/wtclientrpc/wtclient.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lnrpc/wtclientrpc/wtclient.go b/lnrpc/wtclientrpc/wtclient.go index 335c370c8..1f45335fb 100644 --- a/lnrpc/wtclientrpc/wtclient.go +++ b/lnrpc/wtclientrpc/wtclient.go @@ -269,7 +269,7 @@ func (c *WatchtowerClient) ListTowers(ctx context.Context, } opts, ackCounts, committedUpdateCounts := constructFunctionalOptions( - req.IncludeSessions, + req.IncludeSessions, req.ExcludeExhaustedSessions, ) anchorTowers, err := c.cfg.AnchorClient.RegisteredTowers(opts...) @@ -334,7 +334,7 @@ func (c *WatchtowerClient) GetTowerInfo(ctx context.Context, } opts, ackCounts, committedUpdateCounts := constructFunctionalOptions( - req.IncludeSessions, + req.IncludeSessions, req.ExcludeExhaustedSessions, ) // Get the tower and its sessions from anchors client. @@ -377,9 +377,9 @@ func (c *WatchtowerClient) GetTowerInfo(ctx context.Context, // functional options to be used when fetching a tower from the DB. It also // returns a map of acked-update counts and one for un-acked-update counts that // will be populated once the db call has been made. -func constructFunctionalOptions(includeSessions bool) ( - []wtdb.ClientSessionListOption, map[wtdb.SessionID]uint16, - map[wtdb.SessionID]uint16) { +func constructFunctionalOptions(includeSessions, + excludeExhaustedSessions bool) ([]wtdb.ClientSessionListOption, + map[wtdb.SessionID]uint16, map[wtdb.SessionID]uint16) { var ( opts []wtdb.ClientSessionListOption @@ -407,6 +407,12 @@ func constructFunctionalOptions(includeSessions bool) ( wtdb.WithPerCommittedUpdate(perCommittedUpdate), } + if excludeExhaustedSessions { + opts = append(opts, wtdb.WithPostEvalFilterFn( + wtclient.ExhaustedSessionFilter(), + )) + } + return opts, ackCounts, committedUpdateCounts } From 957df98777187fd2bd7b004fb353d45df050d804 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 13 Feb 2023 17:30:10 +0200 Subject: [PATCH 60/87] lncli: add new exclude-exhausted-sessions option --- cmd/lncli/wtclient.go | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/cmd/lncli/wtclient.go b/cmd/lncli/wtclient.go index 93d24c80d..c08601c32 100644 --- a/cmd/lncli/wtclient.go +++ b/cmd/lncli/wtclient.go @@ -151,6 +151,12 @@ var listTowersCommand = cli.Command{ Usage: "include sessions with the watchtower in the " + "response", }, + cli.BoolFlag{ + Name: "exclude_exhausted_sessions", + Usage: "Whether to exclude exhausted sessions in " + + "the response info. This option is only " + + "meaningful if include_sessions is true", + }, }, Action: actionDecorator(listTowers), } @@ -160,7 +166,7 @@ func listTowers(ctx *cli.Context) error { // Display the command's help message if the number of arguments/flags // is not what we expect. - if ctx.NArg() > 0 || ctx.NumFlags() > 1 { + if ctx.NArg() > 0 || ctx.NumFlags() > 2 { return cli.ShowCommandHelp(ctx, "towers") } @@ -169,6 +175,9 @@ func listTowers(ctx *cli.Context) error { req := &wtclientrpc.ListTowersRequest{ IncludeSessions: ctx.Bool("include_sessions"), + ExcludeExhaustedSessions: ctx.Bool( + "exclude_exhausted_sessions", + ), } resp, err := client.ListTowers(ctxc, req) if err != nil { @@ -190,6 +199,12 @@ var getTowerCommand = cli.Command{ Usage: "include sessions with the watchtower in the " + "response", }, + cli.BoolFlag{ + Name: "exclude_exhausted_sessions", + Usage: "Whether to exclude exhausted sessions in " + + "the response info. This option is only " + + "meaningful if include_sessions is true", + }, }, Action: actionDecorator(getTower), } @@ -199,7 +214,7 @@ func getTower(ctx *cli.Context) error { // Display the command's help message if the number of arguments/flags // is not what we expect. - if ctx.NArg() != 1 || ctx.NumFlags() > 1 { + if ctx.NArg() != 1 || ctx.NumFlags() > 2 { return cli.ShowCommandHelp(ctx, "tower") } @@ -217,6 +232,9 @@ func getTower(ctx *cli.Context) error { req := &wtclientrpc.GetTowerInfoRequest{ Pubkey: pubKey, IncludeSessions: ctx.Bool("include_sessions"), + ExcludeExhaustedSessions: ctx.Bool( + "exclude_exhausted_sessions", + ), } resp, err := client.GetTowerInfo(ctxc, req) if err != nil { From a3e9f5b83c2dfd87050fe83747862e740351a6ca Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 20 Mar 2023 14:45:31 +0200 Subject: [PATCH 61/87] docs: add release note for 7405 --- docs/release-notes/release-notes-0.16.1.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index 2b5cdc801..b6e9a9f16 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -12,6 +12,10 @@ * [Clean up sessions once all channels for which they have updates for are closed. Also start sending the `DeleteSession` message to the tower.](https://github.com/lightningnetwork/lnd/pull/7069) +* [Don't load exhausted sessions when not + needed](https://github.com/lightningnetwork/lnd/pull/7405). Also add a new + `exclude_exhausted_sessions` boolean flag to the relevant lncli wtclient + commands. ## Misc From a266c3a4a99eabc27d41993b48feb69a99d1e24f Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 20 Mar 2023 19:22:34 +0100 Subject: [PATCH 62/87] itest: add assertion for PSBT change outputs With this commit we add more specific assertions to our PSBT signing test in order to make sure change outputs have the proper PSBT metadata associated with them, depending on their address type. --- itest/lnd_psbt_test.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/itest/lnd_psbt_test.go b/itest/lnd_psbt_test.go index 3d3b38c5f..57a0a67b7 100644 --- a/itest/lnd_psbt_test.go +++ b/itest/lnd_psbt_test.go @@ -1087,6 +1087,34 @@ func assertPsbtFundSignSpend(ht *lntest.HarnessTest, alice *node.HarnessNode, ) require.GreaterOrEqual(ht, fundResp.ChangeOutputIndex, int32(-1)) + // Make sure our change output has all the meta information required for + // signing. + fundedPacket, err := psbt.NewFromRawBytes( + bytes.NewReader(fundResp.FundedPsbt), false, + ) + require.NoError(ht, err) + + pOut := fundedPacket.Outputs[fundResp.ChangeOutputIndex] + require.NotEmpty(ht, pOut.Bip32Derivation) + derivation := pOut.Bip32Derivation[0] + _, err = btcec.ParsePubKey(derivation.PubKey) + require.NoError(ht, err) + require.Len(ht, derivation.Bip32Path, 5) + + // Ensure we get the change output properly decorated with all the new + // Taproot related fields, if it is a Taproot output. + if changeType == walletrpc.ChangeAddressType_CHANGE_ADDRESS_TYPE_P2TR { + require.NotEmpty(ht, pOut.TaprootBip32Derivation) + require.NotEmpty(ht, pOut.TaprootInternalKey) + + trDerivation := pOut.TaprootBip32Derivation[0] + require.Equal( + ht, trDerivation.XOnlyPubKey, pOut.TaprootInternalKey, + ) + _, err := schnorr.ParsePubKey(pOut.TaprootInternalKey) + require.NoError(ht, err) + } + var signedPsbt []byte if useFinalize { finalizeResp := alice.RPC.FinalizePsbt( From d019c82f07a83d27f891d6e58cc1082bca1433ba Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 20 Mar 2023 20:15:08 +0100 Subject: [PATCH 63/87] itest: assert change output type of SendCoins --- itest/lnd_misc_test.go | 145 ++++++++++++++++++++++++++--------------- 1 file changed, 94 insertions(+), 51 deletions(-) diff --git a/itest/lnd_misc_test.go b/itest/lnd_misc_test.go index 59da665e6..bd71fa842 100644 --- a/itest/lnd_misc_test.go +++ b/itest/lnd_misc_test.go @@ -6,6 +6,8 @@ import ( "io/ioutil" "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcwallet/wallet" "github.com/lightningnetwork/lnd/chainreg" "github.com/lightningnetwork/lnd/funding" @@ -757,10 +759,8 @@ func testAbandonChannel(ht *lntest.HarnessTest) { // testSweepAllCoins tests that we're able to properly sweep all coins from the // wallet into a single target address at the specified fee rate. -// -// TODO(yy): expand this test to also use P2TR. func testSweepAllCoins(ht *lntest.HarnessTest) { - // First, we'll make a new node, ainz who'll we'll use to test wallet + // First, we'll make a new node, Ainz who'll we'll use to test wallet // sweeping. // // NOTE: we won't use standby nodes here since the test will change @@ -772,60 +772,50 @@ func testSweepAllCoins(ht *lntest.HarnessTest) { ht.FundCoins(btcutil.SatoshiPerBitcoin, ainz) ht.FundCoinsNP2WKH(btcutil.SatoshiPerBitcoin, ainz) - // Ensure that we can't send coins to our own Pubkey. - info := ainz.RPC.GetInfo() - - // Create a label that we will used to label the transaction with. + // Create a label that will be used to label the transaction with. sendCoinsLabel := "send all coins" - sweepReq := &lnrpc.SendCoinsRequest{ - Addr: info.IdentityPubkey, + // Ensure that we can't send coins to our own Pubkey. + ainz.RPC.SendCoinsAssertErr(&lnrpc.SendCoinsRequest{ + Addr: ainz.RPC.GetInfo().IdentityPubkey, SendAll: true, Label: sendCoinsLabel, - } - ainz.RPC.SendCoinsAssertErr(sweepReq) + }) // Ensure that we can't send coins to another user's Pubkey. - info = ht.Alice.RPC.GetInfo() - - sweepReq = &lnrpc.SendCoinsRequest{ - Addr: info.IdentityPubkey, + ainz.RPC.SendCoinsAssertErr(&lnrpc.SendCoinsRequest{ + Addr: ht.Alice.RPC.GetInfo().IdentityPubkey, SendAll: true, Label: sendCoinsLabel, - } - ainz.RPC.SendCoinsAssertErr(sweepReq) + }) - // With the two coins above mined, we'll now instruct ainz to sweep all - // the coins to an external address not under its control. We will - // first attempt to send the coins to addresses that are not compatible + // With the two coins above mined, we'll now instruct Ainz to sweep all + // the coins to an external address not under its control. We will first + // attempt to send the coins to addresses that are not compatible // with the current network. This is to test that the wallet will - // prevent any onchain transactions to addresses that are not on the + // prevent any on-chain transactions to addresses that are not on the // same network as the user. // Send coins to a testnet3 address. - sweepReq = &lnrpc.SendCoinsRequest{ + ainz.RPC.SendCoinsAssertErr(&lnrpc.SendCoinsRequest{ Addr: "tb1qfc8fusa98jx8uvnhzavxccqlzvg749tvjw82tg", SendAll: true, Label: sendCoinsLabel, - } - ainz.RPC.SendCoinsAssertErr(sweepReq) + }) // Send coins to a mainnet address. - sweepReq = &lnrpc.SendCoinsRequest{ + ainz.RPC.SendCoinsAssertErr(&lnrpc.SendCoinsRequest{ Addr: "1MPaXKp5HhsLNjVSqaL7fChE3TVyrTMRT3", SendAll: true, Label: sendCoinsLabel, - } - ainz.RPC.SendCoinsAssertErr(sweepReq) + }) // Send coins to a compatible address. - minerAddr := ht.Miner.NewMinerAddress() - sweepReq = &lnrpc.SendCoinsRequest{ - Addr: minerAddr.String(), + ainz.RPC.SendCoins(&lnrpc.SendCoinsRequest{ + Addr: ht.Miner.NewMinerAddress().String(), SendAll: true, Label: sendCoinsLabel, - } - ainz.RPC.SendCoins(sweepReq) + }) // We'll mine a block which should include the sweep transaction we // generated above. @@ -849,6 +839,7 @@ func testSweepAllCoins(ht *lntest.HarnessTest) { for _, txn := range txResp.Transactions { if txn.TxHash == targetTx { target = txn + break } } @@ -883,28 +874,29 @@ func testSweepAllCoins(ht *lntest.HarnessTest) { // label our transaction with an empty label, and check that we fail as // expected. sweepHash := sweepTx.TxHash() - req := &walletrpc.LabelTransactionRequest{ - Txid: sweepHash[:], - Label: "", - Overwrite: false, - } - err := ainz.RPC.LabelTransactionAssertErr(req) + err := ainz.RPC.LabelTransactionAssertErr( + &walletrpc.LabelTransactionRequest{ + Txid: sweepHash[:], + Label: "", + Overwrite: false, + }, + ) // Our error will be wrapped in a rpc error, so we check that it // contains the error we expect. errZeroLabel := "cannot label transaction with empty label" - require.Contains(ht, err.Error(), errZeroLabel, - "expected: zero label errorv") + require.Contains(ht, err.Error(), errZeroLabel) // Next, we try to relabel our transaction without setting the overwrite // boolean. We expect this to fail, because the wallet requires setting // of this param to prevent accidental overwrite of labels. - req = &walletrpc.LabelTransactionRequest{ - Txid: sweepHash[:], - Label: "label that will not work", - Overwrite: false, - } - err = ainz.RPC.LabelTransactionAssertErr(req) + err = ainz.RPC.LabelTransactionAssertErr( + &walletrpc.LabelTransactionRequest{ + Txid: sweepHash[:], + Label: "label that will not work", + Overwrite: false, + }, + ) // Our error will be wrapped in a rpc error, so we check that it // contains the error we expect. @@ -913,12 +905,11 @@ func testSweepAllCoins(ht *lntest.HarnessTest) { // Finally, we overwrite our label with a new label, which should not // fail. newLabel := "new sweep tx label" - req = &walletrpc.LabelTransactionRequest{ + ainz.RPC.LabelTransaction(&walletrpc.LabelTransactionRequest{ Txid: sweepHash[:], Label: newLabel, Overwrite: true, - } - ainz.RPC.LabelTransaction(req) + }) waitTxLabel(sweepTxStr, newLabel) @@ -929,8 +920,60 @@ func testSweepAllCoins(ht *lntest.HarnessTest) { // If we try again, but this time specifying an amount, then the call // should fail. - sweepReq.Amount = 10000 - ainz.RPC.SendCoinsAssertErr(sweepReq) + ainz.RPC.SendCoinsAssertErr(&lnrpc.SendCoinsRequest{ + Addr: ht.Miner.NewMinerAddress().String(), + Amount: 10000, + SendAll: true, + Label: sendCoinsLabel, + }) + + // With all the edge cases tested, we'll now test the happy paths of + // change output types. + // We'll be using a "main" address where we send the funds to and from + // several times. + ht.FundCoins(btcutil.SatoshiPerBitcoin, ainz) + mainAddrResp := ainz.RPC.NewAddress(&lnrpc.NewAddressRequest{ + Type: lnrpc.AddressType_WITNESS_PUBKEY_HASH, + }) + spendAddrTypes := []lnrpc.AddressType{ + lnrpc.AddressType_NESTED_PUBKEY_HASH, + lnrpc.AddressType_WITNESS_PUBKEY_HASH, + lnrpc.AddressType_TAPROOT_PUBKEY, + } + for _, addrType := range spendAddrTypes { + ht.Logf("testing with address type %s", addrType) + + // First, spend all the coins in the wallet to an address of the + // given type so that UTXO will be picked when sending coins. + sendAllCoinsToAddrType(ht, ainz, addrType) + + // Let's send some coins to the main address. + const amt = 123456 + resp := ainz.RPC.SendCoins(&lnrpc.SendCoinsRequest{ + Addr: mainAddrResp.Address, + Amount: amt, + }) + block := ht.MineBlocksAndAssertNumTxes(1, 1)[0] + sweepTx := block.Transactions[1] + require.Equal(ht, sweepTx.TxHash().String(), resp.Txid) + + // Find the change output, it will be the one with an amount + // different from the amount we sent. + var changeOutput *wire.TxOut + for idx := range sweepTx.TxOut { + txOut := sweepTx.TxOut[idx] + if txOut.Value != amt { + changeOutput = txOut + break + } + } + require.NotNil(ht, changeOutput) + + // Assert the type of change output to be p2tr. + pkScript, err := txscript.ParsePkScript(changeOutput.PkScript) + require.NoError(ht, err) + require.Equal(ht, txscript.WitnessV1TaprootTy, pkScript.Class()) + } } // testListAddresses tests that we get all the addresses and their From 2b8e9a0d36071dfa04f67786affcca5995b4c04a Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Mon, 20 Mar 2023 16:35:09 +0800 Subject: [PATCH 64/87] multi: add more trace logs regarding link activate flow --- discovery/gossiper.go | 2 +- discovery/message_store.go | 9 ++++++++- htlcswitch/link.go | 3 +++ peer/brontide.go | 6 +++++- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/discovery/gossiper.go b/discovery/gossiper.go index c02cd0b10..5251c06b2 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -1294,7 +1294,7 @@ func (d *AuthenticatedGossiper) sendRemoteBatch(annBatch []msgWithSenders) { // We'll first attempt to filter out this new message for all peers // that have active gossip syncers active. for pub, syncer := range syncerPeers { - log.Tracef("Sending messages batch to GossipSyncer(%x)", pub) + log.Tracef("Sending messages batch to GossipSyncer(%s)", pub) syncer.FilterGossipMsgs(annBatch...) } diff --git a/discovery/message_store.go b/discovery/message_store.go index 40f2df78a..cf228eee7 100644 --- a/discovery/message_store.go +++ b/discovery/message_store.go @@ -111,7 +111,11 @@ func messageStoreKey(msg lnwire.Message, peerPubKey [33]byte) ([]byte, error) { // AddMessage adds a message to the store for this peer. func (s *MessageStore) AddMessage(msg lnwire.Message, peerPubKey [33]byte) error { - // Construct the key for which we'll find this message with in the store. + log.Tracef("Adding message of type %v to store for peer %x", + msg.MsgType(), peerPubKey) + + // Construct the key for which we'll find this message with in the + // store. msgKey, err := messageStoreKey(msg, peerPubKey) if err != nil { return err @@ -137,6 +141,9 @@ func (s *MessageStore) AddMessage(msg lnwire.Message, peerPubKey [33]byte) error func (s *MessageStore) DeleteMessage(msg lnwire.Message, peerPubKey [33]byte) error { + log.Tracef("Deleting message of type %v from store for peer %x", + msg.MsgType(), peerPubKey) + // Construct the key for which we'll find this message with in the // store. msgKey, err := messageStoreKey(msg, peerPubKey) diff --git a/htlcswitch/link.go b/htlcswitch/link.go index b1836c7c7..335ec351f 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -710,6 +710,9 @@ func (l *channelLink) syncChanStates() error { // first message sent MUST be the ChanSync message. select { case msg := <-l.upstream: + l.log.Tracef("Received msg=%v from peer(%x)", msg.MsgType(), + l.cfg.Peer.PubKey()) + remoteChanSyncMsg, ok := msg.(*lnwire.ChannelReestablish) if !ok { return fmt.Errorf("first message sent to sync "+ diff --git a/peer/brontide.go b/peer/brontide.go index 9ea85edd1..09f016851 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -776,7 +776,8 @@ func (p *Brontide) loadActiveChannels(chans []*channeldb.OpenChannel) ( chanID := lnwire.NewChanIDFromOutPoint(chanPoint) - p.log.Infof("loading ChannelPoint(%v)", chanPoint) + p.log.Infof("Loading ChannelPoint(%v), isPending=%v", + chanPoint, lnChan.IsPending()) // Skip adding any permanently irreconcilable channels to the // htlcswitch. @@ -1318,6 +1319,8 @@ func (ms *msgStream) AddMsg(msg lnwire.Message) { func waitUntilLinkActive(p *Brontide, cid lnwire.ChannelID) htlcswitch.ChannelUpdateHandler { + p.log.Tracef("Waiting for link=%v to be active", cid) + // Subscribe to receive channel events. // // NOTE: If the link is already active by SubscribeChannelEvents, then @@ -1395,6 +1398,7 @@ func newChanMsgStream(p *Brontide, cid lnwire.ChannelID) *msgStream { // If the link is still not active and the calling function // errored out, just return. if chanLink == nil { + p.log.Warnf("Link=%v is not active") return } } From 0dbb709929f7439229cfd515687c013e0395302c Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Wed, 22 Mar 2023 11:51:47 +0100 Subject: [PATCH 65/87] travis: increase timeout to 120 minutes --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c2117896a..45d8b6225 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,7 +36,7 @@ jobs: name: Bitcoind Integration ARM script: - bash ./scripts/install_bitcoind.sh - - GOMEMLIMIT=500MiB GOARM=7 GOARCH=arm GOOS=linux travis_wait 30 make itest-parallel backend=bitcoind + - GOMEMLIMIT=1024MiB GOARM=7 GOARCH=arm GOOS=linux travis_wait 120 make itest-parallel backend=bitcoind tranches=8 arch: arm64 after_failure: From 00fa2cb34a736dbcdc5500885d719bee2ff60cd7 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 22 Mar 2023 16:13:17 +0700 Subject: [PATCH 66/87] lnwallet: add verbose test logs for `TestWebAPIFeeEstimator` --- lnwallet/chainfee/estimator_test.go | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/lnwallet/chainfee/estimator_test.go b/lnwallet/chainfee/estimator_test.go index d7169b114..f3ec4efc6 100644 --- a/lnwallet/chainfee/estimator_test.go +++ b/lnwallet/chainfee/estimator_test.go @@ -5,7 +5,6 @@ import ( "encoding/json" "io" "reflect" - "strings" "testing" "github.com/btcsuite/btcd/btcutil" @@ -204,6 +203,10 @@ func TestWebAPIFeeEstimator(t *testing.T) { } // Construct mock fee source for the Estimator to pull fees from. + // + // This will create a `feeByBlockTarget` map with the following values, + // - 20: testFeeRate + // - 100: 42, which will be floored to feeFloor. testFees := make(map[uint32]uint32) for _, tc := range testCases { if tc.apiEst != 0 { @@ -233,25 +236,22 @@ func TestWebAPIFeeEstimator(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { est, err := estimator.EstimateFeePerKW(tc.target) - if tc.err != "" { - if err == nil || - !strings.Contains(err.Error(), tc.err) { - t.Fatalf("expected fee estimation to "+ - "fail, instead got: %v", err) - } - } else { - exp := SatPerKVByte(tc.est).FeePerKWeight() - if err != nil { - t.Fatalf("unable to estimate fee for "+ - "%v block target, got: %v", - tc.target, err) - } - if est != exp { - t.Fatalf("expected fee estimate of "+ - "%v, got %v", exp, est) - } + // Test an error case. + if tc.err != "" { + require.Error(t, err, "expected error") + require.ErrorContains(t, err, tc.err) + + return } + + // Test an non-error case. + require.NoErrorf(t, err, "error from target %v", + tc.target) + + exp := SatPerKVByte(tc.est).FeePerKWeight() + require.Equalf(t, exp, est, "target %v failed, fee "+ + "map is %v", tc.target, feeSource.fees) }) } } From a79ab8bafdf8d4a54a38a3662c5af31890de6623 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 22 Mar 2023 16:16:27 +0700 Subject: [PATCH 67/87] lntest: increase wait time to 5s when failed to close channel --- lntest/harness.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lntest/harness.go b/lntest/harness.go index 819a0a8d3..0508546a4 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -1132,7 +1132,7 @@ func (h *HarnessTest) CloseChannelAssertPending(hn *node.HarnessNode, // active htlcs` or `link failed to shutdown` if we close the // channel. We need to investigate the order of settling the // payments and updating commitments to properly fix it. - time.Sleep(2 * time.Second) + time.Sleep(5 * time.Second) // Give it another chance. stream = hn.RPC.CloseChannel(closeReq) From cbcbddfe29189873504a1128000e9bf1ea65b41e Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Sat, 18 Feb 2023 11:53:27 +0800 Subject: [PATCH 68/87] rpcserver: add `time_lock_delta` overflow check --- cmd/lncli/commands.go | 37 ++++++++++++++++++---- config.go | 4 +++ docs/release-notes/release-notes-0.16.1.md | 4 +++ lnrpc/invoicesrpc/addinvoice.go | 2 +- routing/router.go | 5 +++ rpcserver.go | 4 +++ 6 files changed, 48 insertions(+), 8 deletions(-) diff --git a/cmd/lncli/commands.go b/cmd/lncli/commands.go index 0cdecbd15..989afae19 100644 --- a/cmd/lncli/commands.go +++ b/cmd/lncli/commands.go @@ -21,6 +21,7 @@ import ( "github.com/lightninglabs/protobuf-hex-display/jsonpb" "github.com/lightninglabs/protobuf-hex-display/proto" "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/routing" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/signal" "github.com/urfave/cli" @@ -2029,7 +2030,7 @@ var updateChannelPolicyCommand = cli.Command{ "with a granularity of 0.000001 (millionths). Can not " + "be set at the same time as fee_rate.", }, - cli.Int64Flag{ + cli.Uint64Flag{ Name: "time_lock_delta", Usage: "the CLTV delta that will be applied to all " + "forwarded HTLCs", @@ -2080,6 +2081,25 @@ func parseChanPoint(s string) (*lnrpc.ChannelPoint, error) { }, nil } +// parseTimeLockDelta is expected to get a uint16 type of timeLockDelta, +// which maximum value is MaxTimeLockDelta. +func parseTimeLockDelta(timeLockDeltaStr string) (uint16, error) { + timeLockDeltaUnCheck, err := strconv.ParseUint( + timeLockDeltaStr, 10, 64, + ) + if err != nil { + return 0, fmt.Errorf("failed to parse time_lock_delta: %s "+ + "to uint64, err: %v", timeLockDeltaStr, err) + } + + if timeLockDeltaUnCheck > routing.MaxCLTVDelta { + return 0, fmt.Errorf("time_lock_delta is too big, "+ + "max value is %d", routing.MaxCLTVDelta) + } + + return uint16(timeLockDeltaUnCheck), nil +} + func updateChannelPolicy(ctx *cli.Context) error { ctxc := getContext() client, cleanUp := getClient(ctx) @@ -2089,7 +2109,7 @@ func updateChannelPolicy(ctx *cli.Context) error { baseFee int64 feeRate float64 feeRatePpm uint64 - timeLockDelta int64 + timeLockDelta uint16 err error ) args := ctx.Args() @@ -2127,12 +2147,15 @@ func updateChannelPolicy(ctx *cli.Context) error { switch { case ctx.IsSet("time_lock_delta"): - timeLockDelta = ctx.Int64("time_lock_delta") - case args.Present(): - timeLockDelta, err = strconv.ParseInt(args.First(), 10, 64) + timeLockDeltaStr := ctx.String("time_lock_delta") + timeLockDelta, err = parseTimeLockDelta(timeLockDeltaStr) if err != nil { - return fmt.Errorf("unable to decode time_lock_delta: %v", - err) + return err + } + case args.Present(): + timeLockDelta, err = parseTimeLockDelta(args.First()) + if err != nil { + return err } args = args.Tail() diff --git a/config.go b/config.go index e49bbc909..6130410e6 100644 --- a/config.go +++ b/config.go @@ -98,6 +98,10 @@ const ( // HTLCs on our channels. minTimeLockDelta = routing.MinCLTVDelta + // MaxTimeLockDelta is the maximum CLTV delta that can be applied to + // forwarded HTLCs. + MaxTimeLockDelta = routing.MaxCLTVDelta + // defaultAcceptorTimeout is the time after which an RPCAcceptor will time // out and return false if it hasn't yet received a response. defaultAcceptorTimeout = 15 * time.Second diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index b6e9a9f16..afb702380 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -4,6 +4,10 @@ * The `lncli wallet psbt fund` command now allows users to specify the [`--min_confs` flag](https://github.com/lightningnetwork/lnd/pull/7510). + +* [Add time_lock_delta overflow check for UpdateChannelPolicy](https://github.com/lightningnetwork/lnd/pull/7350) + that ensure `time_lock_delta` is greater or equal than `0` and less or equal than `65535` + ## Watchtowers diff --git a/lnrpc/invoicesrpc/addinvoice.go b/lnrpc/invoicesrpc/addinvoice.go index 00e88ecc1..745952147 100644 --- a/lnrpc/invoicesrpc/addinvoice.go +++ b/lnrpc/invoicesrpc/addinvoice.go @@ -348,7 +348,7 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig, // We'll use our current default CLTV value unless one was specified as // an option on the command line when creating an invoice. switch { - case invoice.CltvExpiry > math.MaxUint16: + case invoice.CltvExpiry > routing.MaxCLTVDelta: return nil, nil, fmt.Errorf("CLTV delta of %v is too large, "+ "max accepted is: %v", invoice.CltvExpiry, math.MaxUint16) diff --git a/routing/router.go b/routing/router.go index eea5189d9..f4de5a784 100644 --- a/routing/router.go +++ b/routing/router.go @@ -4,6 +4,7 @@ import ( "bytes" goErrors "errors" "fmt" + "math" "runtime" "strings" "sync" @@ -80,6 +81,10 @@ const ( // bitcoin (160 for litecoin), though we now clamp the lower end of this // range for user-chosen deltas to 18 blocks to be conservative. MinCLTVDelta = 18 + + // MaxCLTVDelta is the maximum CLTV value accepted by LND for all + // timelock deltas. + MaxCLTVDelta = math.MaxUint16 ) var ( diff --git a/rpcserver.go b/rpcserver.go index f531e8a5b..9dac0b977 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -6827,6 +6827,10 @@ func (r *rpcServer) UpdateChannelPolicy(ctx context.Context, return nil, fmt.Errorf("time lock delta of %v is too small, "+ "minimum supported is %v", req.TimeLockDelta, minTimeLockDelta) + } else if req.TimeLockDelta > uint32(MaxTimeLockDelta) { + return nil, fmt.Errorf("time lock delta of %v is too big, "+ + "maximum supported is %v", req.TimeLockDelta, + MaxTimeLockDelta) } baseFeeMsat := lnwire.MilliSatoshi(req.BaseFeeMsat) From e4a6a0f26f2929cc9bb5053b314c6fde67e4bc37 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Mon, 23 Jan 2023 14:22:40 +0800 Subject: [PATCH 69/87] lncli: add testcase for `parseTimeLockDelta` Signed-off-by: Eval EXEC --- cmd/lncli/commands_test.go | 53 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/cmd/lncli/commands_test.go b/cmd/lncli/commands_test.go index 48de92e78..17e32268b 100644 --- a/cmd/lncli/commands_test.go +++ b/cmd/lncli/commands_test.go @@ -2,6 +2,9 @@ package main import ( "errors" + "fmt" + "math" + "strconv" "testing" "github.com/stretchr/testify/require" @@ -68,3 +71,53 @@ func TestParseChanPoint(t *testing.T) { } } } + +// TestParseTimeLockDelta tests parseTimeLockDelta with various +// valid and invalid input values and verifies the output. +func TestParseTimeLockDelta(t *testing.T) { + t.Parallel() + testCases := []struct { + timeLockDeltaStr string + expectedTimeLockDelta uint16 + expectErr bool + expectedErrContent string + }{ + { + timeLockDeltaStr: "-1", + expectErr: true, + expectedErrContent: fmt.Sprintf( + "failed to parse time_lock_delta: %d "+ + "to uint64", -1, + ), + }, + { + timeLockDeltaStr: "0", + }, + { + timeLockDeltaStr: "3", + expectedTimeLockDelta: 3, + }, + { + timeLockDeltaStr: strconv.FormatUint( + uint64(math.MaxUint16), 10, + ), + expectedTimeLockDelta: math.MaxUint16, + }, + { + timeLockDeltaStr: "18446744073709551616", + expectErr: true, + expectedErrContent: fmt.Sprint( + "failed to parse time_lock_delta:" + + " 18446744073709551616 to uint64"), + }, + } + for _, tc := range testCases { + timeLockDelta, err := parseTimeLockDelta(tc.timeLockDeltaStr) + require.Equal(t, tc.expectedTimeLockDelta, timeLockDelta) + if tc.expectErr { + require.ErrorContains(t, err, tc.expectedErrContent) + } else { + require.NoError(t, err) + } + } +} From ddc4bc6b32f50f50aff2966ced3df8ecbdfb3436 Mon Sep 17 00:00:00 2001 From: ardevd Date: Tue, 21 Feb 2023 13:51:01 +0100 Subject: [PATCH 70/87] lncli: backup/verify/restore single channel from file author ardevd 1676983861 +0100 committer ardevd 1677705118 +0100 Write to the specified file if the user specifies a chan_point for backup and also specifies an output file to write the backup to. Fixes #7436 --- cmd/lncli/commands.go | 65 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/cmd/lncli/commands.go b/cmd/lncli/commands.go index 989afae19..b0e3c03c8 100644 --- a/cmd/lncli/commands.go +++ b/cmd/lncli/commands.go @@ -2314,8 +2314,9 @@ func exportChanBackup(ctx *cli.Context) error { } var ( - err error - chanPointStr string + err error + chanPointStr string + outputFileName string ) args := ctx.Args() @@ -2330,6 +2331,10 @@ func exportChanBackup(ctx *cli.Context) error { return fmt.Errorf("must specify chan_point if --all isn't set") } + if ctx.IsSet("output_file") { + outputFileName = ctx.String("output_file") + } + if chanPointStr != "" { chanPointRPC, err := parseChanPoint(chanPointStr) if err != nil { @@ -2357,6 +2362,14 @@ func exportChanBackup(ctx *cli.Context) error { Index: chanPointRPC.OutputIndex, } + if outputFileName != "" { + return os.WriteFile( + outputFileName, + chanBackup.ChanBackup, + 0666, + ) + } + printJSON(struct { ChanPoint string `json:"chan_point"` ChanBackup []byte `json:"chan_backup"` @@ -2378,9 +2391,9 @@ func exportChanBackup(ctx *cli.Context) error { return err } - if ctx.IsSet("output_file") { - return ioutil.WriteFile( - ctx.String("output_file"), + if outputFileName != "" { + return os.WriteFile( + outputFileName, chanBackup.MultiChanBackup.MultiChanBackup, 0666, ) @@ -2416,13 +2429,16 @@ var verifyChanBackupCommand = cli.Command{ backup for integrity. This is useful when a user has a backup, but is unsure as to if it's valid or for the target node. - The command will accept backups in one of three forms: + The command will accept backups in one of four forms: * A single channel packed SCB, which can be obtained from exportchanbackup. This should be passed in hex encoded format. * A packed multi-channel SCB, which couples several individual static channel backups in single blob. + + * A file path which points to a packed single-channel backup within a + file, using the same format that lnd does in its channel.backup file. * A file path which points to a packed multi-channel backup within a file, using the same format that lnd does in its channel.backup @@ -2439,6 +2455,13 @@ var verifyChanBackupCommand = cli.Command{ Usage: "a hex encoded multi-channel backup obtained " + "from exportchanbackup", }, + + cli.StringFlag{ + Name: "single_file", + Usage: "the path to a single-channel backup file", + TakesFile: true, + }, + cli.StringFlag{ Name: "multi_file", Usage: "the path to a multi-channel back up file", @@ -2499,7 +2522,7 @@ var restoreChanBackupCommand = cli.Command{ channel. If successful, this command will allows the user to recover the settled funds stored in the recovered channels. - The command will accept backups in one of three forms: + The command will accept backups in one of four forms: * A single channel packed SCB, which can be obtained from exportchanbackup. This should be passed in hex encoded format. @@ -2507,6 +2530,10 @@ var restoreChanBackupCommand = cli.Command{ * A packed multi-channel SCB, which couples several individual static channel backups in single blob. + * A file path which points to a packed single-channel backup within + a file, using the same format that lnd does in its channel.backup + file. + * A file path which points to a packed multi-channel backup within a file, using the same format that lnd does in its channel.backup file. @@ -2522,6 +2549,13 @@ var restoreChanBackupCommand = cli.Command{ Usage: "a hex encoded multi-channel backup obtained " + "from exportchanbackup", }, + + cli.StringFlag{ + Name: "single_file", + Usage: "the path to a single-channel backup file", + TakesFile: true, + }, + cli.StringFlag{ Name: "multi_file", Usage: "the path to a multi-channel back up file", @@ -2573,6 +2607,23 @@ func parseChanBackups(ctx *cli.Context) (*lnrpc.RestoreChanBackupRequest, error) }, }, nil + case ctx.IsSet("single_file"): + packedSingle, err := os.ReadFile(ctx.String("single_file")) + if err != nil { + return nil, fmt.Errorf("unable to decode single "+ + "packed backup: %v", err) + } + + return &lnrpc.RestoreChanBackupRequest{ + Backup: &lnrpc.RestoreChanBackupRequest_ChanBackups{ + ChanBackups: &lnrpc.ChannelBackups{ + ChanBackups: []*lnrpc.ChannelBackup{{ + ChanBackup: packedSingle, + }}, + }, + }, + }, nil + case ctx.IsSet("multi_file"): packedMulti, err := ioutil.ReadFile(ctx.String("multi_file")) if err != nil { From d1f961c598a493f2008c45f1eff82d53ed36379e Mon Sep 17 00:00:00 2001 From: ardevd Date: Mon, 27 Feb 2023 22:33:31 +0100 Subject: [PATCH 71/87] docs: added release notes --- docs/release-notes/release-notes-0.16.1.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index afb702380..6b6cd1346 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -8,6 +8,9 @@ * [Add time_lock_delta overflow check for UpdateChannelPolicy](https://github.com/lightningnetwork/lnd/pull/7350) that ensure `time_lock_delta` is greater or equal than `0` and less or equal than `65535` +* [Added ability to backup, verify and + restore single channels](https://github.com/lightningnetwork/lnd/pull/7437) + to and from a file on disk. ## Watchtowers @@ -39,6 +42,7 @@ # Contributors (Alphabetical Order) +* ardevd * Elle Mouton * Oliver Gugger * Tommy Volk From de80fffa6c6f39cbc44750e48aa7c12eed255cda Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Thu, 30 Mar 2023 12:29:06 +0200 Subject: [PATCH 72/87] wtclient: divide addr_iter tests into subtests Split out the existing tests into logical subtests. --- watchtower/wtclient/addr_iterator_test.go | 318 ++++++++++++---------- 1 file changed, 172 insertions(+), 146 deletions(-) diff --git a/watchtower/wtclient/addr_iterator_test.go b/watchtower/wtclient/addr_iterator_test.go index 89a35c4cb..1e58471dc 100644 --- a/watchtower/wtclient/addr_iterator_test.go +++ b/watchtower/wtclient/addr_iterator_test.go @@ -10,184 +10,210 @@ import ( // TestAddrIterator tests the behaviour of the addressIterator. func TestAddrIterator(t *testing.T) { - // Assert that an iterator can't be initialised with an empty address - // list. - _, err := newAddressIterator() - require.ErrorContains(t, err, "must have at least one address") + t.Parallel() + // Prep some addresses to use in the subtests. addr1, err := net.ResolveTCPAddr("tcp", "1.2.3.4:8000") require.NoError(t, err) - // Initialise the iterator with addr1. - iter, err := newAddressIterator(addr1) - require.NoError(t, err) - - // Attempting to remove addr1 should fail now since it is the only - // address in the iterator. - iter.Add(addr1) - err = iter.Remove(addr1) - require.ErrorIs(t, err, wtdb.ErrLastTowerAddr) - - // Adding a duplicate of addr1 and then calling Remove should still - // return an error. - err = iter.Remove(addr1) - require.ErrorIs(t, err, wtdb.ErrLastTowerAddr) - addr2, err := net.ResolveTCPAddr("tcp", "1.2.3.4:8001") require.NoError(t, err) - // Add addr2 to the iterator. - iter.Add(addr2) - - // Check that peek returns addr1. - a1 := iter.Peek() - require.NoError(t, err) - require.Equal(t, addr1, a1) - - // Calling peek multiple times should return the same result. - a1 = iter.Peek() - require.Equal(t, addr1, a1) - - // Calling Next should now return addr2. - a2, err := iter.Next() - require.NoError(t, err) - require.Equal(t, addr2, a2) - - // Assert that Peek now returns addr2. - a2 = iter.Peek() - require.NoError(t, err) - require.Equal(t, addr2, a2) - - // Calling Next should result in reaching the end of th list. - _, err = iter.Next() - require.ErrorIs(t, err, ErrAddressesExhausted) - - // Calling Peek now should reset the queue and return addr1. - a1 = iter.Peek() - require.Equal(t, addr1, a1) - - // Wind the list to the end again so that we can test the Reset func. - _, err = iter.Next() - require.NoError(t, err) - - _, err = iter.Next() - require.ErrorIs(t, err, ErrAddressesExhausted) - - iter.Reset() - - // Now Next should return addr 2. - a2, err = iter.Next() - require.NoError(t, err) - require.Equal(t, addr2, a2) - addr3, err := net.ResolveTCPAddr("tcp", "1.2.3.4:8002") require.NoError(t, err) - // Add addr3 now to ensure that the iteration works even if we are - // midway through the queue. - iter.Add(addr3) + t.Run("always at least one address", func(t *testing.T) { + t.Parallel() - // Now Next should return addr 3. - a3, err := iter.Next() - require.NoError(t, err) - require.Equal(t, addr3, a3) + // Assert that an iterator can't be initialised with an empty + // address list. + _, err := newAddressIterator() + require.ErrorContains(t, err, "must have at least one address") - // Quickly test that GetAll correctly returns a copy of all the - // addresses in the iterator. - addrList := iter.GetAll() - require.ElementsMatch(t, addrList, []net.Addr{addr1, addr2, addr3}) + // Initialise the iterator with addr1. + iter, err := newAddressIterator(addr1) + require.NoError(t, err) - // Also check that an iterator constructed via the Copy method, also - // contains all the expected addresses. - newIterAddrs := iter.Copy().GetAll() - require.ElementsMatch(t, newIterAddrs, []net.Addr{addr1, addr2, addr3}) + // Attempting to remove addr1 should fail now since it is the + // only address in the iterator. + iter.Add(addr1) + err = iter.Remove(addr1) + require.ErrorIs(t, err, wtdb.ErrLastTowerAddr) - // Let's now remove addr3. - err = iter.Remove(addr3) - require.NoError(t, err) + // Adding a duplicate of addr1 and then calling Remove should + // still return an error. + err = iter.Remove(addr1) + require.ErrorIs(t, err, wtdb.ErrLastTowerAddr) + }) - // Since addr3 is gone, Peek should return addr1. - a1 = iter.Peek() - require.Equal(t, addr1, a1) + t.Run("address iteration", func(t *testing.T) { + t.Parallel() - // Lastly, we will test the "locking" of addresses. + // Initialise the iterator with addr1. + iter, err := newAddressIterator(addr1) + require.NoError(t, err) - // First we test the locking of an address via the PeekAndLock function. - a1 = iter.PeekAndLock() - require.Equal(t, addr1, a1) - require.True(t, iter.HasLocked()) + // Add addr2 to the iterator. + iter.Add(addr2) - // Assert that we can't remove addr1 if there is a lock on it. - err = iter.Remove(addr1) - require.ErrorIs(t, err, ErrAddrInUse) + // Check that peek returns addr1. + a1 := iter.Peek() + require.NoError(t, err) + require.Equal(t, addr1, a1) - // Now release the lock on addr1. - iter.ReleaseLock(addr1) - require.False(t, iter.HasLocked()) + // Calling peek multiple times should return the same result. + a1 = iter.Peek() + require.Equal(t, addr1, a1) - // Since the lock has been released, we should now be able to remove - // addr1. - err = iter.Remove(addr1) - require.NoError(t, err) + // Calling Next should now return addr2. + a2, err := iter.Next() + require.NoError(t, err) + require.Equal(t, addr2, a2) - // Now we test the locking of an address via the NextAndLock function. - // To do this, we first re-add addr3. - iter.Add(addr3) + // Assert that Peek now returns addr2. + a2 = iter.Peek() + require.NoError(t, err) + require.Equal(t, addr2, a2) - a2, err = iter.NextAndLock() - require.NoError(t, err) - require.Equal(t, addr2, a2) - require.True(t, iter.HasLocked()) + // Calling Next should result in reaching the end of th list. + _, err = iter.Next() + require.ErrorIs(t, err, ErrAddressesExhausted) - // Assert that we can't remove addr2 if there is a lock on it. - err = iter.Remove(addr2) - require.ErrorIs(t, err, ErrAddrInUse) + // Calling Peek now should reset the queue and return addr1. + a1 = iter.Peek() + require.Equal(t, addr1, a1) - // Now release the lock on addr2. - iter.ReleaseLock(addr2) - require.False(t, iter.HasLocked()) + // Wind the list to the end again so that we can test the Reset + // func. + _, err = iter.Next() + require.NoError(t, err) - // Since the lock has been released, we should now be able to remove - // addr1. - err = iter.Remove(addr2) - require.NoError(t, err) + _, err = iter.Next() + require.ErrorIs(t, err, ErrAddressesExhausted) - // Only addr3 should still be left in the iterator. - addrList = iter.GetAll() - require.Len(t, addrList, 1) - require.Contains(t, addrList, addr3) + iter.Reset() - // Ensure that HasLocked acts correctly in the case where more than one - // address is being locked and unlock as well as the case where the same - // address is locked more than once. + // Now Next should return addr 2. + a2, err = iter.Next() + require.NoError(t, err) + require.Equal(t, addr2, a2) - require.False(t, iter.HasLocked()) + // Add addr3 now to ensure that the iteration works even if we + // are midway through the queue. + iter.Add(addr3) - a3 = iter.PeekAndLock() - require.Equal(t, addr3, a3) - require.True(t, iter.HasLocked()) + // Now Next should return addr 3. + a3, err := iter.Next() + require.NoError(t, err) + require.Equal(t, addr3, a3) - a3 = iter.PeekAndLock() - require.Equal(t, addr3, a3) - require.True(t, iter.HasLocked()) + // Quickly test that GetAll correctly returns a copy of all the + // addresses in the iterator. + addrList := iter.GetAll() + require.ElementsMatch( + t, addrList, []net.Addr{addr1, addr2, addr3}, + ) - iter.Add(addr2) - a2, err = iter.NextAndLock() - require.NoError(t, err) - require.Equal(t, addr2, a2) - require.True(t, iter.HasLocked()) + // Also check that an iterator constructed via the Copy method, + // also contains all the expected addresses. + newIterAddrs := iter.Copy().GetAll() + require.ElementsMatch( + t, newIterAddrs, []net.Addr{addr1, addr2, addr3}, + ) - // Now release addr2 and asset that HasLock is still true. - iter.ReleaseLock(addr2) - require.True(t, iter.HasLocked()) + // Let's now remove addr3. + err = iter.Remove(addr3) + require.NoError(t, err) - // Releasing one of the locks on addr3 now should still result in - // HasLocked returning true. - iter.ReleaseLock(addr3) - require.True(t, iter.HasLocked()) + // Since addr3 is gone, Peek should return addr1. + a1 = iter.Peek() + require.Equal(t, addr1, a1) + }) - // Releasing it again should now result in should still result in - // HasLocked returning false. - iter.ReleaseLock(addr3) - require.False(t, iter.HasLocked()) + t.Run("address locking", func(t *testing.T) { + t.Parallel() + + // Initialise the iterator with addr1 and addr2. + iter, err := newAddressIterator(addr1, addr2) + require.NoError(t, err) + + // First we test the locking of an address via the PeekAndLock + // function. + a1 := iter.PeekAndLock() + require.Equal(t, addr1, a1) + require.True(t, iter.HasLocked()) + + // Assert that we can't remove addr1 if there is a lock on it. + err = iter.Remove(addr1) + require.ErrorIs(t, err, ErrAddrInUse) + + // Now release the lock on addr1. + iter.ReleaseLock(addr1) + require.False(t, iter.HasLocked()) + + // Since the lock has been released, we should now be able to + // remove addr1. + err = iter.Remove(addr1) + require.NoError(t, err) + + // Now we test the locking of an address via the NextAndLock + // function. To do this, we first re-add addr3. + iter.Add(addr3) + + a2, err := iter.NextAndLock() + require.NoError(t, err) + require.Equal(t, addr2, a2) + require.True(t, iter.HasLocked()) + + // Assert that we can't remove addr2 if there is a lock on it. + err = iter.Remove(addr2) + require.ErrorIs(t, err, ErrAddrInUse) + + // Now release the lock on addr2. + iter.ReleaseLock(addr2) + require.False(t, iter.HasLocked()) + + // Since the lock has been released, we should now be able to + // remove addr1. + err = iter.Remove(addr2) + require.NoError(t, err) + + // Only addr3 should still be left in the iterator. + addrList := iter.GetAll() + require.Len(t, addrList, 1) + require.Contains(t, addrList, addr3) + + // Ensure that HasLocked acts correctly in the case where more + // than one address is being locked and unlock as well as the + // case where the same address is locked more than once. + require.False(t, iter.HasLocked()) + + a3 := iter.PeekAndLock() + require.Equal(t, addr3, a3) + require.True(t, iter.HasLocked()) + + a3 = iter.PeekAndLock() + require.Equal(t, addr3, a3) + require.True(t, iter.HasLocked()) + + iter.Add(addr2) + a2, err = iter.NextAndLock() + require.NoError(t, err) + require.Equal(t, addr2, a2) + require.True(t, iter.HasLocked()) + + // Now release addr2 and assert that HasLock is still true. + iter.ReleaseLock(addr2) + require.True(t, iter.HasLocked()) + + // Releasing one of the locks on addr3 now should still result + // in HasLocked returning true. + iter.ReleaseLock(addr3) + require.True(t, iter.HasLocked()) + + // Releasing it again should now result in should still result + // in HasLocked returning false. + iter.ReleaseLock(addr3) + require.False(t, iter.HasLocked()) + }) } From 104751451579eae998195a658a58381decf464f6 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Thu, 30 Mar 2023 11:45:34 +0200 Subject: [PATCH 73/87] wtclient: demo addr iterator panic This commit adds a test that shows that it is possible to cause the AddressIterator to panic if the `Next` method is ever called twice when the iterator is at the end of its list without Reset first being called. --- watchtower/wtclient/addr_iterator_test.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/watchtower/wtclient/addr_iterator_test.go b/watchtower/wtclient/addr_iterator_test.go index 1e58471dc..436be2a7e 100644 --- a/watchtower/wtclient/addr_iterator_test.go +++ b/watchtower/wtclient/addr_iterator_test.go @@ -216,4 +216,27 @@ func TestAddrIterator(t *testing.T) { iter.ReleaseLock(addr3) require.False(t, iter.HasLocked()) }) + + t.Run("calling Next twice without Reset panics", func(t *testing.T) { + t.Parallel() + + // This defer-function asserts that a panic does occur. + defer func() { + r := recover() + require.NotNilf(t, r, "the code did not panic") + }() + + // Initialise the iterator with addr1. + iter, err := newAddressIterator(addr1) + require.NoError(t, err) + + a1 := iter.Peek() + require.Equal(t, addr1, a1) + + _, err = iter.Next() + require.ErrorIs(t, err, ErrAddressesExhausted) + + _, err = iter.Next() + require.ErrorIs(t, err, ErrAddressesExhausted) + }) } From 9e4c8dd5090666f008361390d19a9c2bc8ecba17 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Thu, 30 Mar 2023 11:49:58 +0200 Subject: [PATCH 74/87] wtclient: make addr iterator panic safe Ensure that calling Next twice in a row without first calling Reset is safe when the iterator is at the end of its list. Also alter the towerListIterator to call Reset after hitting an error on Next. --- watchtower/wtclient/addr_iterator.go | 4 ++++ watchtower/wtclient/addr_iterator_test.go | 8 +------- watchtower/wtclient/candidate_iterator.go | 1 + 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/watchtower/wtclient/addr_iterator.go b/watchtower/wtclient/addr_iterator.go index cb16d335a..8abcb3891 100644 --- a/watchtower/wtclient/addr_iterator.go +++ b/watchtower/wtclient/addr_iterator.go @@ -162,6 +162,10 @@ func (a *addressIterator) next(lock bool) (net.Addr, error) { a.mu.Lock() defer a.mu.Unlock() + if a.currentTopAddr == nil { + return nil, ErrAddressesExhausted + } + // Set the next candidate to the subsequent element. a.currentTopAddr = a.currentTopAddr.Next() diff --git a/watchtower/wtclient/addr_iterator_test.go b/watchtower/wtclient/addr_iterator_test.go index 436be2a7e..a2e49ff90 100644 --- a/watchtower/wtclient/addr_iterator_test.go +++ b/watchtower/wtclient/addr_iterator_test.go @@ -217,15 +217,9 @@ func TestAddrIterator(t *testing.T) { require.False(t, iter.HasLocked()) }) - t.Run("calling Next twice without Reset panics", func(t *testing.T) { + t.Run("calling Next twice without Reset is safe", func(t *testing.T) { t.Parallel() - // This defer-function asserts that a panic does occur. - defer func() { - r := recover() - require.NotNilf(t, r, "the code did not panic") - }() - // Initialise the iterator with addr1. iter, err := newAddressIterator(addr1) require.NoError(t, err) diff --git a/watchtower/wtclient/candidate_iterator.go b/watchtower/wtclient/candidate_iterator.go index 10ef86465..29c4719f0 100644 --- a/watchtower/wtclient/candidate_iterator.go +++ b/watchtower/wtclient/candidate_iterator.go @@ -145,6 +145,7 @@ func (t *towerListIterator) AddCandidate(candidate *Tower) { for { next, err := candidate.Addresses.Next() if err != nil { + candidate.Addresses.Reset() break } From 4f7e871b42b5f359de2bc70163dcd53e708a39f2 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Thu, 30 Mar 2023 12:00:52 +0200 Subject: [PATCH 75/87] wtclient: add clarifying comments to the AddressIterator --- watchtower/wtclient/addr_iterator.go | 39 +++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/watchtower/wtclient/addr_iterator.go b/watchtower/wtclient/addr_iterator.go index 8abcb3891..5ada7d5de 100644 --- a/watchtower/wtclient/addr_iterator.go +++ b/watchtower/wtclient/addr_iterator.go @@ -162,11 +162,15 @@ func (a *addressIterator) next(lock bool) (net.Addr, error) { a.mu.Lock() defer a.mu.Unlock() + // In-case currentTopAddr is nil (meaning that Reset has not yet been + // called), return an error indicating this. if a.currentTopAddr == nil { return nil, ErrAddressesExhausted } - // Set the next candidate to the subsequent element. + // Set the next candidate to the subsequent element. If we are at the + // end of the address list, this could mean setting currentTopAddr to + // nil. a.currentTopAddr = a.currentTopAddr.Next() for a.currentTopAddr != nil { @@ -176,9 +180,26 @@ func (a *addressIterator) next(lock bool) (net.Addr, error) { // Check whether this address is still considered a candidate. // If it's not, we'll proceed to the next. candidate, ok := a.candidates[addrID] + + // If the address cannot be found in the candidate set, then + // this must mean that the Remove method was called for the + // address. The Remove method would have checked that the + // address is not the last one in the iterator and that it has + // no locks on it. It is therefor safe to remove. if !ok { + // Grab the next address candidate. This might be nil + // if the iterator is on the last item in the list. nextCandidate := a.currentTopAddr.Next() + + // Remove the address from the list that is no longer + // in the candidate set. a.addrList.Remove(a.currentTopAddr) + + // Set the current top to the next candidate. This might + // mean setting it to nil if the iterator is on its last + // item in which case the loop will be exited and an + // ErrAddressesExhausted exhausted error will be + // returned. a.currentTopAddr = nextCandidate continue } @@ -234,9 +255,25 @@ func (a *addressIterator) peek(lock bool) net.Addr { addrID := a.currentTopAddr.Value.(string) candidate, ok := a.candidates[addrID] + + // If the address cannot be found in the candidate set, then + // this must mean that the Remove method was called for the + // address. The Remove method would have checked that the + // address is not the last one in the iterator and that it has + // no locks on it. It is therefor safe to remove. if !ok { + // Grab the next address candidate. This might be nil + // if the iterator is on the last item in the list. nextCandidate := a.currentTopAddr.Next() + + // Remove the address from the list that is no longer + // in the candidate set. a.addrList.Remove(a.currentTopAddr) + + // Set the current top to the next candidate. This might + // mean setting it to nil if the iterator is on its last + // item but this will be reset at the top of the for + // loop. a.currentTopAddr = nextCandidate continue } From 82afb6a958fe7f1314da0068f346dd21206fe85c Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Thu, 30 Mar 2023 12:36:53 +0200 Subject: [PATCH 76/87] docs: add release note for 7556 --- docs/release-notes/release-notes-0.16.1.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index 6b6cd1346..790388eed 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -14,6 +14,8 @@ ## Watchtowers +* [Fix Address iterator + panic](https://github.com/lightningnetwork/lnd/pull/7556) * [Allow caller to filter sessions at the time of reading them from disk](https://github.com/lightningnetwork/lnd/pull/7059) * [Clean up sessions once all channels for which they have updates for are From e7f338fdeddd7314c2469b3390c3981a269bc799 Mon Sep 17 00:00:00 2001 From: ziggie Date: Mon, 20 Mar 2023 22:41:55 +0100 Subject: [PATCH 77/87] mod: bump version for psbt and btcwallet package --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index e24b7a8c2..23369d21e 100644 --- a/go.mod +++ b/go.mod @@ -6,10 +6,10 @@ require ( github.com/btcsuite/btcd v0.23.5-0.20230125025938-be056b0a0b2f github.com/btcsuite/btcd/btcec/v2 v2.3.2 github.com/btcsuite/btcd/btcutil v1.1.3 - github.com/btcsuite/btcd/btcutil/psbt v1.1.5 + github.com/btcsuite/btcd/btcutil/psbt v1.1.8 github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f - github.com/btcsuite/btcwallet v0.16.7 + github.com/btcsuite/btcwallet v0.16.8-0.20230324081040-520f650ce045 github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2 github.com/btcsuite/btcwallet/wallet/txrules v1.2.0 github.com/btcsuite/btcwallet/walletdb v1.4.0 diff --git a/go.sum b/go.sum index 76d2ebd0c..e26b250c1 100644 --- a/go.sum +++ b/go.sum @@ -80,8 +80,8 @@ github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUB github.com/btcsuite/btcd/btcutil v1.1.1/go.mod h1:nbKlBMNm9FGsdvKvu0essceubPiAcI57pYBNnsLAa34= github.com/btcsuite/btcd/btcutil v1.1.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ= github.com/btcsuite/btcd/btcutil v1.1.3/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= -github.com/btcsuite/btcd/btcutil/psbt v1.1.5 h1:x0ZRrYY8j75ThV6xBz86CkYAG82F5bzay4H5D1c8b/U= -github.com/btcsuite/btcd/btcutil/psbt v1.1.5/go.mod h1:kA6FLH/JfUx++j9pYU0pyu+Z8XGBQuuTmuKYUf6q7/U= +github.com/btcsuite/btcd/btcutil/psbt v1.1.8 h1:4voqtT8UppT7nmKQkXV+T9K8UyQjKOn2z/ycpmJK8wg= +github.com/btcsuite/btcd/btcutil/psbt v1.1.8/go.mod h1:kA6FLH/JfUx++j9pYU0pyu+Z8XGBQuuTmuKYUf6q7/U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 h1:KdUfX2zKommPRa+PD0sWZUyXe9w277ABlgELO7H04IM= @@ -89,8 +89,8 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2/go.mod h1:7SFka0XMvUgj3hfZtyd github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcwallet v0.16.7 h1:J6nBMMMc90n77/4QIfzRFn5XB1hPvMDfcgX5U6Ls0kI= -github.com/btcsuite/btcwallet v0.16.7/go.mod h1:J/q3/JxytAcuqR+zSTCRZ5K+0LtMuhxtCjLVXKDHBu0= +github.com/btcsuite/btcwallet v0.16.8-0.20230324081040-520f650ce045 h1:302lmdYbONzrLACkm9IlCobMYuYOjF8to+tUhaQsTzc= +github.com/btcsuite/btcwallet v0.16.8-0.20230324081040-520f650ce045/go.mod h1:WBcb0CNEgzjF2EdatcERzG7cd/lhHXtNJ4VjIePOdXM= github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2 h1:etuLgGEojecsDOYTII8rYiGHjGyV5xTqsXi+ZQ715UU= github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2/go.mod h1:Zpk/LOb2sKqwP2lmHjaZT9AdaKsHPSbNLm2Uql5IQ/0= github.com/btcsuite/btcwallet/wallet/txrules v1.2.0 h1:BtEN5Empw62/RVnZ0VcJaVtVlBijnLlJY+dwjAye2Bg= From 4da26fb65a669fbee68fa36e60259a8da8ef6d3b Mon Sep 17 00:00:00 2001 From: ziggie Date: Mon, 20 Mar 2023 22:43:15 +0100 Subject: [PATCH 78/87] btcwallet+rpcwallet: verify input data for psbt package Use the new method in the psbt package InputsReadyToSign which makes sure that each input has either nonWitness Utxo or witness Utxo data specified. --- lnwallet/btcwallet/psbt.go | 5 +++-- lnwallet/rpcwallet/rpcwallet.go | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lnwallet/btcwallet/psbt.go b/lnwallet/btcwallet/psbt.go index 7dbe12c2b..395c5667c 100644 --- a/lnwallet/btcwallet/psbt.go +++ b/lnwallet/btcwallet/psbt.go @@ -135,8 +135,9 @@ func (b *BtcWallet) SignPsbt(packet *psbt.Packet) ([]uint32, error) { var signedInputs []uint32 // Let's check that this is actually something we can and want to sign. - // We need at least one input and one output. - err := psbt.VerifyInputOutputLen(packet, true, true) + // We need at least one input and one output. In addition each + // input needs nonWitness Utxo or witness Utxo data specified. + err := psbt.InputsReadyToSign(packet) if err != nil { return nil, err } diff --git a/lnwallet/rpcwallet/rpcwallet.go b/lnwallet/rpcwallet/rpcwallet.go index 38f345c14..536ce6260 100644 --- a/lnwallet/rpcwallet/rpcwallet.go +++ b/lnwallet/rpcwallet/rpcwallet.go @@ -255,8 +255,9 @@ func (r *RPCKeyRing) SignPsbt(packet *psbt.Packet) ([]uint32, error) { // parameter in FinalizePsbt so we can get rid of this code duplication. func (r *RPCKeyRing) FinalizePsbt(packet *psbt.Packet, _ string) error { // Let's check that this is actually something we can and want to sign. - // We need at least one input and one output. - err := psbt.VerifyInputOutputLen(packet, true, true) + // We need at least one input and one output. In addition each + // input needs nonWitness Utxo or witness Utxo data specified. + err := psbt.InputsReadyToSign(packet) if err != nil { return err } From b649b552e664f5ec90711750058d454a2a1ddbce Mon Sep 17 00:00:00 2001 From: ziggie Date: Wed, 29 Mar 2023 23:33:32 +0200 Subject: [PATCH 79/87] itest: add test when signing without UTXO data Adds a testcase in the itest suite which tests that psbt input data needs its corresponding UTXO data when signing. --- itest/lnd_psbt_test.go | 15 +++++++++++++-- lntest/rpc/wallet_kit.go | 13 +++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/itest/lnd_psbt_test.go b/itest/lnd_psbt_test.go index 57a0a67b7..ffa680d75 100644 --- a/itest/lnd_psbt_test.go +++ b/itest/lnd_psbt_test.go @@ -1009,17 +1009,28 @@ func assertPsbtSpend(ht *lntest.HarnessTest, alice *node.HarnessNode, packet, err := psbt.NewFromUnsignedTx(pendingTx) require.NoError(ht, err) + // We first try to sign the psbt without the necessary input data + // which should fail with the expected error. + var buf bytes.Buffer + err = packet.Serialize(&buf) + require.NoError(ht, err) + + signReq := &walletrpc.SignPsbtRequest{FundedPsbt: buf.Bytes()} + err = alice.RPC.SignPsbtErr(signReq) + require.ErrorContains(ht, err, "input (index=0) doesn't specify "+ + "any UTXO info", "error does not match") + // Now let's add the meta information that we need for signing. packet.Inputs[0].WitnessUtxo = utxo packet.Inputs[0].NonWitnessUtxo = prevTx decorateUnsigned(packet) // That's it, we should be able to sign the PSBT now. - var buf bytes.Buffer + buf.Reset() err = packet.Serialize(&buf) require.NoError(ht, err) - signReq := &walletrpc.SignPsbtRequest{FundedPsbt: buf.Bytes()} + signReq = &walletrpc.SignPsbtRequest{FundedPsbt: buf.Bytes()} signResp := alice.RPC.SignPsbt(signReq) // Let's make sure we have a partial signature. diff --git a/lntest/rpc/wallet_kit.go b/lntest/rpc/wallet_kit.go index 1d0a12858..9a88fe6e7 100644 --- a/lntest/rpc/wallet_kit.go +++ b/lntest/rpc/wallet_kit.go @@ -263,6 +263,19 @@ func (h *HarnessRPC) SignPsbt( return resp } +// SignPsbtErr makes a RPC call to the node's WalletKitClient and asserts +// an error returned. +func (h *HarnessRPC) SignPsbtErr(req *walletrpc.SignPsbtRequest) error { + ctxt, cancel := context.WithTimeout(h.runCtx, DefaultTimeout) + defer cancel() + + _, err := h.WalletKit.SignPsbt(ctxt, req) + require.Errorf(h, err, "%s: expect sign psbt to return an error", + h.Name) + + return err +} + // ImportTapscript makes a RPC call to the node's WalletKitClient and asserts. // //nolint:lll From 71b8fac819ef6445ec44f41d5b4b436b5f2368b8 Mon Sep 17 00:00:00 2001 From: ziggie Date: Mon, 20 Mar 2023 23:47:35 +0100 Subject: [PATCH 80/87] docs: add release-notes --- docs/release-notes/release-notes-0.16.1.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index 0265abc4c..ebe476295 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -38,7 +38,7 @@ ## RPC -- A [debug log](https://github.com/lightningnetwork/lnd/pull/7514) has been +* A [debug log](https://github.com/lightningnetwork/lnd/pull/7514) has been added to `lnrpc` so the node operator can know whether a certain request has happened or not. @@ -48,6 +48,11 @@ anything for the users since the message type(36) stays unchanged, except in the logging all the appearance of `funding_locked` replated experssion is replaced with `channel_ready`. +## Bug Fixes + +* [Fix a bug where lnd crashes when psbt data is not fully +available](https://github.com/lightningnetwork/lnd/pull/7529). + # Contributors (Alphabetical Order) @@ -56,3 +61,4 @@ * Oliver Gugger * Tommy Volk * Yong Yu +* ziggie1984 \ No newline at end of file From 204585c620ea940ddb99ca49f0f1a088d851ec1f Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 27 Mar 2023 14:14:26 +0200 Subject: [PATCH 81/87] watchtower: demo StateUpdateCodeClientBehind error In this commit, a test is added to demonstrate how clients can end up getting the StateUpdateCodeClientBehind error from a tower server. This can happen if a client ever deletes their db. If they do this then the sessions they create with the tower will have the same IDs as the sessions created in the now deleted db. This is because the session keys (and thus session IDs) are calculated deterministically from a counter (which is reset if the db is deleted). The tower server then throws this error because the client would say that the sequence ID is 1 for the next update. --- watchtower/wtclient/client_test.go | 59 +++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/watchtower/wtclient/client_test.go b/watchtower/wtclient/client_test.go index f870af527..dc1d87842 100644 --- a/watchtower/wtclient/client_test.go +++ b/watchtower/wtclient/client_test.go @@ -1466,7 +1466,7 @@ var clientTests = []clientTest{ h.waitServerUpdates(hints[:numUpdates/2], time.Second) // Stop the client, which should have no more backups. - h.client.Stop() + require.NoError(h.t, h.client.Stop()) // Record the policy that the first half was stored // under. We'll expect the second half to also be stored @@ -1527,7 +1527,7 @@ var clientTests = []clientTest{ // Restart the client, so we can ensure the deduping is // maintained across restarts. - h.client.Stop() + require.NoError(h.t, h.client.Stop()) h.startClient() // Try to back up the full range of retributions. Only @@ -2013,6 +2013,61 @@ var clientTests = []clientTest{ require.NoError(h.t, err) }, }, + { + // Demonstrate that the client is unable to upload state updates + // to a tower if the client deletes its database after already + // having created and started to use a session with a tower. + // This happens because the session key is generated + // deterministically and will only be unique for new sessions + // if the same DB is used. The server therefore rejects these + // updates with the StateUpdateCodeClientBehind error. + name: "demonstrate the StateUpdateCodeClientBehind error", + cfg: harnessCfg{ + localBalance: localBalance, + remoteBalance: remoteBalance, + policy: wtpolicy.Policy{ + TxPolicy: defaultTxPolicy, + MaxUpdates: 5, + }, + }, + fn: func(h *testHarness) { + const ( + numUpdates = 5 + chanID = 0 + ) + + // Generate numUpdates retributions. + hints := h.advanceChannelN(chanID, numUpdates) + + // Back half of the states up. + h.backupStates(chanID, 0, numUpdates/2, nil) + + // Wait for the updates to be populated in the server's + // database. + h.waitServerUpdates(hints[:numUpdates/2], waitTime) + + // Now stop the client and reset its database. + require.NoError(h.t, h.client.Stop()) + + db := wtmock.NewClientDB() + h.clientDB = db + h.clientCfg.DB = db + + // Restart the client. + h.startClient() + + // We need to re-register the channel due to the client + // db being reset. + h.registerChannel(0) + + // Attempt to back up the remaining tasks. + h.backupStates(chanID, numUpdates/2, numUpdates, nil) + + // Show that the server does not get the remaining + // updates. + h.waitServerUpdates(nil, waitTime) + }, + }, } // TestClient executes the client test suite, asserting the ability to backup From 24016c35c7f011ec8aa31376175b202a8ebf7343 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 29 Mar 2023 12:15:17 +0200 Subject: [PATCH 82/87] watchtower: add forceNext to NextSessionKeyIndex This commit adds a forceNext boolean parameter to NextSessionKeyIndex. Setting this param to true will force the index to cycle over 1000 key indices before returning the new key. --- watchtower/wtclient/interface.go | 4 +-- watchtower/wtclient/session_negotiator.go | 2 +- watchtower/wtdb/client_db.go | 44 +++++++++++++++-------- watchtower/wtdb/client_db_test.go | 42 +++++++++++++++------- watchtower/wtmock/client_db.go | 28 ++++++++++----- 5 files changed, 81 insertions(+), 39 deletions(-) diff --git a/watchtower/wtclient/interface.go b/watchtower/wtclient/interface.go index 8a6d9b320..06126ae21 100644 --- a/watchtower/wtclient/interface.go +++ b/watchtower/wtclient/interface.go @@ -49,8 +49,8 @@ type DB interface { // (tower, blob type) pair until CreateClientSession is invoked for that // tower and index, at which point a new index for that tower can be // reserved. Multiple calls to this method before CreateClientSession is - // invoked should return the same index. - NextSessionKeyIndex(wtdb.TowerID, blob.Type) (uint32, error) + // invoked should return the same index unless forceNext is true. + NextSessionKeyIndex(wtdb.TowerID, blob.Type, bool) (uint32, error) // CreateClientSession saves a newly negotiated client session to the // client's database. This enables the session to be used across diff --git a/watchtower/wtclient/session_negotiator.go b/watchtower/wtclient/session_negotiator.go index db0f543a1..aafc44b2a 100644 --- a/watchtower/wtclient/session_negotiator.go +++ b/watchtower/wtclient/session_negotiator.go @@ -306,7 +306,7 @@ retryWithBackoff: // with this specific tower. If one is already reserved, the // existing index will be returned. keyIndex, err := n.cfg.DB.NextSessionKeyIndex( - tower.ID, n.cfg.Policy.BlobType, + tower.ID, n.cfg.Policy.BlobType, false, ) if err != nil { n.log.Debugf("Unable to reserve session key index "+ diff --git a/watchtower/wtdb/client_db.go b/watchtower/wtdb/client_db.go index 5a18095b8..a949021d1 100644 --- a/watchtower/wtdb/client_db.go +++ b/watchtower/wtdb/client_db.go @@ -643,9 +643,10 @@ func (c *ClientDB) ListTowers() ([]*Tower, error) { // particular tower id. The index is reserved for that tower until // CreateClientSession is invoked for that tower and index, at which point a new // index for that tower can be reserved. Multiple calls to this method before -// CreateClientSession is invoked should return the same index. +// CreateClientSession is invoked should return the same index unless forceNext +// is true. func (c *ClientDB) NextSessionKeyIndex(towerID TowerID, - blobType blob.Type) (uint32, error) { + blobType blob.Type, forceNext bool) (uint32, error) { var index uint32 err := kvdb.Update(c.db, func(tx kvdb.RwTx) error { @@ -654,33 +655,48 @@ func (c *ClientDB) NextSessionKeyIndex(towerID TowerID, return ErrUninitializedDB } - // Check the session key index to see if a key has already been - // reserved for this tower. If so, we'll deserialize and return - // the index directly. var err error - index, err = getSessionKeyIndex(keyIndex, towerID, blobType) - if err == nil { - return nil + if !forceNext { + // Check the session key index to see if a key has + // already been reserved for this tower. If so, we'll + // deserialize and return the index directly. + index, err = getSessionKeyIndex( + keyIndex, towerID, blobType, + ) + if err == nil { + return nil + } } - // Otherwise, generate a new session key index since the node - // doesn't already have reserved index. The error is ignored - // since NextSequence can't fail inside Update. - index64, _ := keyIndex.NextSequence() + // By default, we use the next available bucket sequence as the + // key index. But if forceNext is true, then it is assumed that + // some data loss occurred and so the sequence is incremented a + // by a jump of 1000 so that we can arrive at a brand new key + // index quicker. + currentSequence := keyIndex.Sequence() + nextIndex := currentSequence + 1 + if forceNext { + nextIndex = currentSequence + 1000 + } + + if err = keyIndex.SetSequence(nextIndex); err != nil { + return fmt.Errorf("could not set next bucket "+ + "sequence: %w", err) + } // As a sanity check, assert that the index is still in the // valid range of unhardened pubkeys. In the future, we should // move to only using hardened keys, and this will prevent any // overlap from occurring until then. This also prevents us from // overflowing uint32s. - if index64 > math.MaxInt32 { + if nextIndex > math.MaxInt32 { return fmt.Errorf("exhausted session key indexes") } // Create the key that will used to be store the reserved index. keyBytes := createSessionKeyIndexKey(towerID, blobType) - index = uint32(index64) + index = uint32(nextIndex) var indexBuf [4]byte byteOrder.PutUint32(indexBuf[:], index) diff --git a/watchtower/wtdb/client_db_test.go b/watchtower/wtdb/client_db_test.go index 26d02bcf3..80557f1f8 100644 --- a/watchtower/wtdb/client_db_test.go +++ b/watchtower/wtdb/client_db_test.go @@ -62,12 +62,12 @@ func (h *clientDBHarness) listSessions(id *wtdb.TowerID, return sessions } -func (h *clientDBHarness) nextKeyIndex(id wtdb.TowerID, - blobType blob.Type) uint32 { +func (h *clientDBHarness) nextKeyIndex(id wtdb.TowerID, blobType blob.Type, + forceNext bool) uint32 { h.t.Helper() - index, err := h.db.NextSessionKeyIndex(id, blobType) + index, err := h.db.NextSessionKeyIndex(id, blobType, forceNext) require.NoError(h.t, err, "unable to create next session key index") require.NotZero(h.t, index, "next key index should never be 0") @@ -309,7 +309,7 @@ func testCreateClientSession(h *clientDBHarness) { h.insertSession(session, wtdb.ErrNoReservedKeyIndex) // Now, reserve a session key for this tower. - keyIndex := h.nextKeyIndex(session.TowerID, blobType) + keyIndex := h.nextKeyIndex(session.TowerID, blobType, false) // The client session hasn't been updated with the reserved key index // (since it's still zero). Inserting should fail due to the mismatch. @@ -318,7 +318,7 @@ func testCreateClientSession(h *clientDBHarness) { // Reserve another key for the same index. Since no session has been // successfully created, it should return the same index to maintain // idempotency across restarts. - keyIndex2 := h.nextKeyIndex(session.TowerID, blobType) + keyIndex2 := h.nextKeyIndex(session.TowerID, blobType, false) require.Equalf(h.t, keyIndex, keyIndex2, "next key index should "+ "be idempotent: want: %v, got %v", keyIndex, keyIndex2) @@ -335,11 +335,23 @@ func testCreateClientSession(h *clientDBHarness) { // session already existing. h.insertSession(session, wtdb.ErrClientSessionAlreadyExists) - // Finally, assert that reserving another key index succeeds with a - // different key index, now that the first one has been finalized. - keyIndex3 := h.nextKeyIndex(session.TowerID, blobType) + // Assert that reserving another key index succeeds with a different key + // index, now that the first one has been finalized. + keyIndex3 := h.nextKeyIndex(session.TowerID, blobType, false) require.NotEqualf(h.t, keyIndex, keyIndex3, "key index still "+ "reserved after creating session") + + // Show that calling NextSessionKeyIndex again now will result in the + // same key being returned as long as forceNext remains false. + keyIndex4 := h.nextKeyIndex(session.TowerID, blobType, false) + require.Equal(h.t, keyIndex3, keyIndex4) + + // Finally, assert that if the forceNext param of the + // NextSessionKeyIndex method is true, then the key index returned will + // be different. + keyIndex5 := h.nextKeyIndex(session.TowerID, blobType, true) + require.NotEqual(h.t, keyIndex5, keyIndex4) + require.Equal(h.t, keyIndex3+1000, keyIndex5) } // testFilterClientSessions asserts that we can correctly filter client sessions @@ -352,7 +364,7 @@ func testFilterClientSessions(h *clientDBHarness) { towerSessions := make(map[wtdb.TowerID][]wtdb.SessionID) for i := 0; i < numSessions; i++ { tower := h.newTower() - keyIndex := h.nextKeyIndex(tower.ID, blobType) + keyIndex := h.nextKeyIndex(tower.ID, blobType, false) sessionID := wtdb.SessionID([33]byte{byte(i)}) h.insertSession(&wtdb.ClientSession{ ClientSessionBody: wtdb.ClientSessionBody{ @@ -499,7 +511,9 @@ func testRemoveTower(h *clientDBHarness) { MaxUpdates: 100, }, RewardPkScript: []byte{0x01, 0x02, 0x03}, - KeyIndex: h.nextKeyIndex(tower.ID, blobType), + KeyIndex: h.nextKeyIndex( + tower.ID, blobType, false, + ), }, ID: wtdb.SessionID([33]byte{0x01}), } @@ -581,7 +595,7 @@ func testCommitUpdate(h *clientDBHarness) { ) // Reserve a session key index and insert the session. - session.KeyIndex = h.nextKeyIndex(session.TowerID, blobType) + session.KeyIndex = h.nextKeyIndex(session.TowerID, blobType, false) h.insertSession(session, nil) // Now, try to commit the update that failed initially which should @@ -774,7 +788,7 @@ func testAckUpdate(h *clientDBHarness) { h.ackUpdate(&session.ID, 1, 0, wtdb.ErrClientSessionNotFound) // Reserve a session key and insert the client session. - session.KeyIndex = h.nextKeyIndex(session.TowerID, blobType) + session.KeyIndex = h.nextKeyIndex(session.TowerID, blobType, false) h.insertSession(session, nil) // Now, try to ack update 1. This should fail since update 1 was never @@ -1051,7 +1065,9 @@ func (h *clientDBHarness) randSession(t *testing.T, MaxUpdates: maxUpdates, }, RewardPkScript: []byte{0x01, 0x02, 0x03}, - KeyIndex: h.nextKeyIndex(towerID, blobType), + KeyIndex: h.nextKeyIndex( + towerID, blobType, false, + ), }, ID: id, } diff --git a/watchtower/wtmock/client_db.go b/watchtower/wtmock/client_db.go index 8d43a0e45..5b77da744 100644 --- a/watchtower/wtmock/client_db.go +++ b/watchtower/wtmock/client_db.go @@ -401,9 +401,10 @@ func (m *ClientDB) CreateClientSession(session *wtdb.ClientSession) error { // particular tower id. The index is reserved for that tower until // CreateClientSession is invoked for that tower and index, at which point a new // index for that tower can be reserved. Multiple calls to this method before -// CreateClientSession is invoked should return the same index. -func (m *ClientDB) NextSessionKeyIndex(towerID wtdb.TowerID, - blobType blob.Type) (uint32, error) { +// CreateClientSession is invoked should return the same index unless forceNext +// is set to true. +func (m *ClientDB) NextSessionKeyIndex(towerID wtdb.TowerID, blobType blob.Type, + forceNext bool) (uint32, error) { m.mu.Lock() defer m.mu.Unlock() @@ -413,15 +414,24 @@ func (m *ClientDB) NextSessionKeyIndex(towerID wtdb.TowerID, blobType: blobType, } - if index, err := m.getSessionKeyIndex(key); err == nil { - return index, nil + if !forceNext { + if index, err := m.getSessionKeyIndex(key); err == nil { + return index, nil + } } - m.nextIndex++ - index := m.nextIndex - m.indexes[key] = index + // By default, we use the next available bucket sequence as the key + // index. But if forceNext is true, then it is assumed that some data + // loss occurred and so the sequence is incremented a by a jump of 1000 + // so that we can arrive at a brand new key index quicker. + nextIndex := m.nextIndex + 1 + if forceNext { + nextIndex = m.nextIndex + 1000 + } + m.nextIndex = nextIndex + m.indexes[key] = nextIndex - return index, nil + return nextIndex, nil } func (m *ClientDB) getSessionKeyIndex(key keyIndexKey) (uint32, error) { From ba33f6a697697f397a48ed87de0b6e1d595c7013 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 29 Mar 2023 12:40:25 +0200 Subject: [PATCH 83/87] wtclient: spin session key indices if required If the tower returns CreateSessionCodeAlreadyExists in response to the CreateSession message from the client, then skip forward a few key indices until we find one that the server does not return the error for. This will allow a client to recover after a data loss incident. --- watchtower/wtclient/client_test.go | 19 +++--- watchtower/wtclient/errors.go | 5 ++ watchtower/wtclient/session_negotiator.go | 71 +++++++++++++++-------- 3 files changed, 59 insertions(+), 36 deletions(-) diff --git a/watchtower/wtclient/client_test.go b/watchtower/wtclient/client_test.go index dc1d87842..7be616d77 100644 --- a/watchtower/wtclient/client_test.go +++ b/watchtower/wtclient/client_test.go @@ -2014,14 +2014,12 @@ var clientTests = []clientTest{ }, }, { - // Demonstrate that the client is unable to upload state updates - // to a tower if the client deletes its database after already - // having created and started to use a session with a tower. - // This happens because the session key is generated - // deterministically and will only be unique for new sessions - // if the same DB is used. The server therefore rejects these - // updates with the StateUpdateCodeClientBehind error. - name: "demonstrate the StateUpdateCodeClientBehind error", + // Demonstrate that the client is unable to recover after + // deleting its database by skipping through key indices until + // it gets to one that does not result in the + // CreateSessionCodeAlreadyExists error code being returned from + // the server. + name: "continue after client database deletion", cfg: harnessCfg{ localBalance: localBalance, remoteBalance: remoteBalance, @@ -2063,9 +2061,8 @@ var clientTests = []clientTest{ // Attempt to back up the remaining tasks. h.backupStates(chanID, numUpdates/2, numUpdates, nil) - // Show that the server does not get the remaining - // updates. - h.waitServerUpdates(nil, waitTime) + // Show that the server does get the remaining updates. + h.waitServerUpdates(hints[numUpdates/2:], waitTime) }, }, } diff --git a/watchtower/wtclient/errors.go b/watchtower/wtclient/errors.go index c6884bb35..2cb070ac4 100644 --- a/watchtower/wtclient/errors.go +++ b/watchtower/wtclient/errors.go @@ -34,4 +34,9 @@ var ( // revoked state because the channel had not been previously registered // with the client. ErrUnregisteredChannel = errors.New("channel is not registered") + + // ErrSessionKeyAlreadyUsed indicates that the client attempted to + // create a new session with a tower with a session key that has already + // been used in the past. + ErrSessionKeyAlreadyUsed = errors.New("session key already used") ) diff --git a/watchtower/wtclient/session_negotiator.go b/watchtower/wtclient/session_negotiator.go index aafc44b2a..d137d45e1 100644 --- a/watchtower/wtclient/session_negotiator.go +++ b/watchtower/wtclient/session_negotiator.go @@ -1,6 +1,7 @@ package wtclient import ( + "errors" "fmt" "sync" "time" @@ -272,6 +273,7 @@ retryWithBackoff: } } +tryNextCandidate: for { select { case <-n.quit: @@ -302,28 +304,39 @@ retryWithBackoff: n.log.Debugf("Attempting session negotiation with tower=%x", towerPub) - // Before proceeding, we will reserve a session key index to use - // with this specific tower. If one is already reserved, the - // existing index will be returned. - keyIndex, err := n.cfg.DB.NextSessionKeyIndex( - tower.ID, n.cfg.Policy.BlobType, false, - ) - if err != nil { - n.log.Debugf("Unable to reserve session key index "+ - "for tower=%x: %v", towerPub, err) - continue - } + var forceNextKey bool + for { + // Before proceeding, we will reserve a session key + // index to use with this specific tower. If one is + // already reserved, the existing index will be + // returned. + keyIndex, err := n.cfg.DB.NextSessionKeyIndex( + tower.ID, n.cfg.Policy.BlobType, forceNextKey, + ) + if err != nil { + n.log.Debugf("Unable to reserve session key "+ + "index for tower=%x: %v", towerPub, err) - // We'll now attempt the CreateSession dance with the tower to - // get a new session, trying all addresses if necessary. - err = n.createSession(tower, keyIndex) - if err != nil { - // An unexpected error occurred, updpate our backoff. + goto tryNextCandidate + } + + // We'll now attempt the CreateSession dance with the + // tower to get a new session, trying all addresses if + // necessary. + err = n.createSession(tower, keyIndex) + if err == nil { + return + } else if errors.Is(err, ErrSessionKeyAlreadyUsed) { + forceNextKey = true + continue + } + + // An unexpected error occurred, update our backoff. updateBackoff() n.log.Debugf("Session negotiation with tower=%x "+ - "failed, trying again -- reason: %v", - tower.IdentityKey.SerializeCompressed(), err) + "failed, trying again -- reason: %v", towerPub, + err) goto retryWithBackoff } @@ -360,7 +373,10 @@ func (n *sessionNegotiator) createSession(tower *Tower, keyIndex uint32) error { err = n.tryAddress(sessionKey, keyIndex, tower, lnAddr) tower.Addresses.ReleaseLock(addr) switch { - case err == ErrPermanentTowerFailure: + case errors.Is(err, ErrSessionKeyAlreadyUsed): + return err + + case errors.Is(err, ErrPermanentTowerFailure): // TODO(conner): report to iterator? can then be reset // with restart fallthrough @@ -454,12 +470,7 @@ func (n *sessionNegotiator) tryAddress(sessionKey keychain.SingleKeyECDH, } switch createSessionReply.Code { - case wtwire.CodeOK, wtwire.CreateSessionCodeAlreadyExists: - - // TODO(conner): add last-applied to create session reply to - // handle case where we lose state, session already exists, and - // we want to possibly resume using the session - + case wtwire.CodeOK: // TODO(conner): validate reward address rewardPkScript := createSessionReply.Data @@ -500,6 +511,16 @@ func (n *sessionNegotiator) tryAddress(sessionKey keychain.SingleKeyECDH, return ErrNegotiatorExiting } + case wtwire.CreateSessionCodeAlreadyExists: + // TODO(conner): use the last-applied in the create session + // reply to handle case where we lose state, session already + // exists, and we want to possibly resume using the session. + // NOTE that this should not be done until the server code + // has been adapted to first check that the CreateSession + // request is for the same blob-type as the initial session. + + return ErrSessionKeyAlreadyUsed + // TODO(conner): handle error codes properly case wtwire.CreateSessionCodeRejectBlobType: return fmt.Errorf("tower rejected blob type: %v", From 381dd8d46055a1231e2775366cd95e8a9e315732 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 27 Mar 2023 14:21:52 +0200 Subject: [PATCH 84/87] docs: add release note for 7541 --- docs/release-notes/release-notes-0.16.1.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index ebe476295..3cd4890d5 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -25,6 +25,8 @@ needed](https://github.com/lightningnetwork/lnd/pull/7405). Also add a new `exclude_exhausted_sessions` boolean flag to the relevant lncli wtclient commands. +* [Recover from StateUpdateCodeClientBehind + error](https://github.com/lightningnetwork/lnd/pull/7541) after data loss. ## Misc From 2f994ceeaefd55dd57c0da0bf1964ec1c758d08c Mon Sep 17 00:00:00 2001 From: djkazic Date: Wed, 25 Jan 2023 12:23:43 -0500 Subject: [PATCH 85/87] mobile+mod+make: fix Makefile ldflags for mac and mobile --- Makefile | 8 ++++---- docs/release-notes/release-notes-0.16.0.md | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 1c1e074b2..e40e57710 100644 --- a/Makefile +++ b/Makefile @@ -277,22 +277,22 @@ vendor: apple: vendor mobile-rpc @$(call print, "Building iOS and macOS cxframework ($(IOS_BUILD)).") mkdir -p $(IOS_BUILD_DIR) - $(GOMOBILE_BIN) bind -target=ios,iossimulator,macos -tags="mobile $(DEV_TAGS) $(RPC_TAGS)" $(RELEASE_LDFLAGS) -v -o $(IOS_BUILD) $(MOBILE_PKG) + $(GOMOBILE_BIN) bind -target=ios,iossimulator,macos -tags="mobile $(DEV_TAGS) $(RPC_TAGS)" -ldflags "$(RELEASE_LDFLAGS)" -v -o $(IOS_BUILD) $(MOBILE_PKG) ios: vendor mobile-rpc @$(call print, "Building iOS cxframework ($(IOS_BUILD)).") mkdir -p $(IOS_BUILD_DIR) - $(GOMOBILE_BIN) bind -target=ios,iossimulator -tags="mobile $(DEV_TAGS) $(RPC_TAGS)" $(RELEASE_LDFLAGS) -v -o $(IOS_BUILD) $(MOBILE_PKG) + $(GOMOBILE_BIN) bind -target=ios,iossimulator -tags="mobile $(DEV_TAGS) $(RPC_TAGS)" -ldflags "$(RELEASE_LDFLAGS)" -v -o $(IOS_BUILD) $(MOBILE_PKG) macos: vendor mobile-rpc @$(call print, "Building macOS cxframework ($(IOS_BUILD)).") mkdir -p $(IOS_BUILD_DIR) - $(GOMOBILE_BIN) bind -target=macos -tags="mobile $(DEV_TAGS) $(RPC_TAGS)" $(RELEASE_LDFLAGS) -v -o $(IOS_BUILD) $(MOBILE_PKG) + $(GOMOBILE_BIN) bind -target=macos -tags="mobile $(DEV_TAGS) $(RPC_TAGS)" -ldflags "$(RELEASE_LDFLAGS)" -v -o $(IOS_BUILD) $(MOBILE_PKG) android: vendor mobile-rpc @$(call print, "Building Android library ($(ANDROID_BUILD)).") mkdir -p $(ANDROID_BUILD_DIR) - $(GOMOBILE_BIN) bind -target=android -tags="mobile $(DEV_TAGS) $(RPC_TAGS)" $(RELEASE_LDFLAGS) -v -o $(ANDROID_BUILD) $(MOBILE_PKG) + $(GOMOBILE_BIN) bind -target=android -tags="mobile $(DEV_TAGS) $(RPC_TAGS)" -ldflags "$(RELEASE_LDFLAGS)" -v -o $(ANDROID_BUILD) $(MOBILE_PKG) mobile: ios android diff --git a/docs/release-notes/release-notes-0.16.0.md b/docs/release-notes/release-notes-0.16.0.md index 4b033687c..51606d0a3 100644 --- a/docs/release-notes/release-notes-0.16.0.md +++ b/docs/release-notes/release-notes-0.16.0.md @@ -200,6 +200,9 @@ https://github.com/lightningnetwork/lnd/pull/6963/) * [A wire parsing bug has been fixed that would cause lnd to be unable _decode_ certain large transactions](https://github.com/lightningnetwork/lnd/pull/7100). +* [ldflags were being incorrectly passed]( +https://github.com/lightningnetwork/lnd/pull/7359) + ## Invoices * Define a new [InvoiceDB](https://github.com/lightningnetwork/lnd/pull/7215) From bb5faf0f5a6db96af8986aa8172696e049b20e3c Mon Sep 17 00:00:00 2001 From: djkazic Date: Fri, 27 Jan 2023 15:38:38 -0500 Subject: [PATCH 86/87] make+docs: pull in modules patch --- Makefile | 12 ++++----- docs/release-notes/release-notes-0.16.0.md | 3 --- docs/release-notes/release-notes-0.16.1.md | 4 +++ go.mod | 3 ++- go.sum | 4 ++- mobile/README.md | 30 +++++++++------------- mobile/bindings.go | 1 + 7 files changed, 28 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index e40e57710..d563b3dd9 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ GOIMPORTS_PKG := github.com/rinchsan/gosimports/cmd/gosimports GO_BIN := ${GOPATH}/bin BTCD_BIN := $(GO_BIN)/btcd GOIMPORTS_BIN := $(GO_BIN)/gosimports -GOMOBILE_BIN := GO111MODULE=off $(GO_BIN)/gomobile +GOMOBILE_BIN := $(GO_BIN)/gomobile GOACC_BIN := $(GO_BIN)/go-acc MOBILE_BUILD_DIR :=${GOPATH}/src/$(MOBILE_PKG)/build @@ -274,25 +274,25 @@ vendor: @$(call print, "Re-creating vendor directory.") rm -r vendor/; go mod vendor -apple: vendor mobile-rpc +apple: mobile-rpc @$(call print, "Building iOS and macOS cxframework ($(IOS_BUILD)).") mkdir -p $(IOS_BUILD_DIR) $(GOMOBILE_BIN) bind -target=ios,iossimulator,macos -tags="mobile $(DEV_TAGS) $(RPC_TAGS)" -ldflags "$(RELEASE_LDFLAGS)" -v -o $(IOS_BUILD) $(MOBILE_PKG) -ios: vendor mobile-rpc +ios: mobile-rpc @$(call print, "Building iOS cxframework ($(IOS_BUILD)).") mkdir -p $(IOS_BUILD_DIR) $(GOMOBILE_BIN) bind -target=ios,iossimulator -tags="mobile $(DEV_TAGS) $(RPC_TAGS)" -ldflags "$(RELEASE_LDFLAGS)" -v -o $(IOS_BUILD) $(MOBILE_PKG) -macos: vendor mobile-rpc +macos: mobile-rpc @$(call print, "Building macOS cxframework ($(IOS_BUILD)).") mkdir -p $(IOS_BUILD_DIR) $(GOMOBILE_BIN) bind -target=macos -tags="mobile $(DEV_TAGS) $(RPC_TAGS)" -ldflags "$(RELEASE_LDFLAGS)" -v -o $(IOS_BUILD) $(MOBILE_PKG) -android: vendor mobile-rpc +android: mobile-rpc @$(call print, "Building Android library ($(ANDROID_BUILD)).") mkdir -p $(ANDROID_BUILD_DIR) - $(GOMOBILE_BIN) bind -target=android -tags="mobile $(DEV_TAGS) $(RPC_TAGS)" -ldflags "$(RELEASE_LDFLAGS)" -v -o $(ANDROID_BUILD) $(MOBILE_PKG) + $(GOMOBILE_BIN) bind -target=android -androidapi 21 -tags="mobile $(DEV_TAGS) $(RPC_TAGS)" -ldflags "$(RELEASE_LDFLAGS)" -v -o $(ANDROID_BUILD) $(MOBILE_PKG) mobile: ios android diff --git a/docs/release-notes/release-notes-0.16.0.md b/docs/release-notes/release-notes-0.16.0.md index 51606d0a3..4b033687c 100644 --- a/docs/release-notes/release-notes-0.16.0.md +++ b/docs/release-notes/release-notes-0.16.0.md @@ -200,9 +200,6 @@ https://github.com/lightningnetwork/lnd/pull/6963/) * [A wire parsing bug has been fixed that would cause lnd to be unable _decode_ certain large transactions](https://github.com/lightningnetwork/lnd/pull/7100). -* [ldflags were being incorrectly passed]( -https://github.com/lightningnetwork/lnd/pull/7359) - ## Invoices * Define a new [InvoiceDB](https://github.com/lightningnetwork/lnd/pull/7215) diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index 6b6cd1346..dbac5088a 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -24,6 +24,10 @@ `exclude_exhausted_sessions` boolean flag to the relevant lncli wtclient commands. +## Build +* [ldflags were being incorrectly passed]( +https://github.com/lightningnetwork/lnd/pull/7359) + ## Misc * [Return `FEE_INSUFFICIENT` before checking balance for incoming low-fee diff --git a/go.mod b/go.mod index e24b7a8c2..e3b587250 100644 --- a/go.mod +++ b/go.mod @@ -52,8 +52,9 @@ require ( go.etcd.io/etcd/client/v3 v3.5.7 golang.org/x/crypto v0.1.0 golang.org/x/exp v0.0.0-20221111094246-ab4555d3164f + golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 golang.org/x/net v0.4.0 - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c + golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde golang.org/x/term v0.3.0 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba google.golang.org/grpc v1.41.0 diff --git a/go.sum b/go.sum index 76d2ebd0c..4d8c21e8d 100644 --- a/go.sum +++ b/go.sum @@ -654,6 +654,7 @@ golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= @@ -721,8 +722,9 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde h1:ejfdSekXMDxDLbRrJMwUk6KnSLZ2McaUCVcIKM+N6jc= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/mobile/README.md b/mobile/README.md index d30bfa9d6..4aa0d7e9d 100644 --- a/mobile/README.md +++ b/mobile/README.md @@ -13,16 +13,8 @@ To build for Android, you need either ### Go and Go mobile -First, follow the instructions to [install Go](https://github.com/lightningnetwork/lnd/blob/master/docs/INSTALL.md#building-a-development-version-from-source). - -Then, install [Go mobile](https://github.com/golang/go/wiki/Mobile) and -initialize it: - -```shell -go install golang.org/x/mobile/cmd/gomobile@latest -go mod download golang.org/x/mobile -gomobile init -``` +First, follow the instructions to [install +Go](https://github.com/lightningnetwork/lnd/blob/master/docs/INSTALL.md#building-a-development-version-from-source). ### Docker @@ -42,14 +34,8 @@ Note that `gomobile` only supports building projects from `$GOPATH` at this point. However, with the introduction of Go modules, the source code files are no longer installed there by default. -To be able to do so, we must turn off module and using the now deprecated -`go get` command before turning modules back on again. - ```shell -go env -w GO111MODULE="off" -go get github.com/lightningnetwork/lnd -go get golang.org/x/mobile/bind -go env -w GO111MODULE="on" +git clone https://github.com/lightningnetwork/lnd.git $GOPATH/src/github.com/lightningnetwork/lnd ``` Finally, let’s change directory to the newly created lnd folder inside `$GOPATH`: @@ -58,13 +44,21 @@ Finally, let’s change directory to the newly created lnd folder inside `$GOPAT cd $GOPATH/src/github.com/lightningnetwork/lnd ``` -It is not recommended building from the master branch for mainnet. To checkout +It is not recommended building from the master branch for mainnet. To check out the latest tagged release of lnd, run ```shell git checkout $(git describe --match "v[0-9]*" --abbrev=0) ``` +Then, install [Go mobile](https://github.com/golang/go/wiki/Mobile) and +initialize it: + +```shell +go install golang.org/x/mobile/cmd/gomobile +gomobile init +``` + ### iOS ```shell diff --git a/mobile/bindings.go b/mobile/bindings.go index eff63f718..e5fe5f71f 100644 --- a/mobile/bindings.go +++ b/mobile/bindings.go @@ -13,6 +13,7 @@ import ( flags "github.com/jessevdk/go-flags" "github.com/lightningnetwork/lnd" "github.com/lightningnetwork/lnd/signal" + _ "golang.org/x/mobile/bind" "google.golang.org/grpc" ) From 41016587eb735698fc05f0ced9fc9142c08d0016 Mon Sep 17 00:00:00 2001 From: djkazic Date: Thu, 26 Jan 2023 20:15:14 -0500 Subject: [PATCH 87/87] Add peer_scid_alias field to lnrpc.Channel --- docs/release-notes/release-notes-0.16.1.md | 2 + lnrpc/lightning.pb.go | 4706 ++++++++++---------- lnrpc/lightning.proto | 3 + lnrpc/lightning.swagger.json | 5 + rpcserver.go | 6 + 5 files changed, 2375 insertions(+), 2347 deletions(-) diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index 6b6cd1346..1b0cdc971 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -39,6 +39,8 @@ - A [debug log](https://github.com/lightningnetwork/lnd/pull/7514) has been added to `lnrpc` so the node operator can know whether a certain request has happened or not. +* [Add peer_scid_alias to the response of + `listchannels`](https://github.com/lightningnetwork/lnd/pull/7366) # Contributors (Alphabetical Order) diff --git a/lnrpc/lightning.pb.go b/lnrpc/lightning.pb.go index 2bb01b923..1fe76cc2a 100644 --- a/lnrpc/lightning.pb.go +++ b/lnrpc/lightning.pb.go @@ -4581,6 +4581,8 @@ type Channel struct { ZeroConfConfirmedScid uint64 `protobuf:"varint,33,opt,name=zero_conf_confirmed_scid,json=zeroConfConfirmedScid,proto3" json:"zero_conf_confirmed_scid,omitempty"` // The configured alias name of our peer. PeerAlias string `protobuf:"bytes,34,opt,name=peer_alias,json=peerAlias,proto3" json:"peer_alias,omitempty"` + // This is the peer SCID alias. + PeerScidAlias uint64 `protobuf:"varint,35,opt,name=peer_scid_alias,json=peerScidAlias,proto3" json:"peer_scid_alias,omitempty"` } func (x *Channel) Reset() { @@ -4857,6 +4859,13 @@ func (x *Channel) GetPeerAlias() string { return "" } +func (x *Channel) GetPeerScidAlias() uint64 { + if x != nil { + return x.PeerScidAlias + } + return 0 +} + type ListChannelsRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -17547,7 +17556,7 @@ var file_lightning_proto_rawDesc = []byte{ 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x6d, 0x61, 0x78, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x48, 0x74, 0x6c, 0x63, 0x73, 0x22, - 0xed, 0x0a, 0x0a, 0x07, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x61, + 0x99, 0x0b, 0x0a, 0x07, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x6d, 0x6f, @@ -17633,2374 +17642,2377 @@ var file_lightning_proto_rawDesc = []byte{ 0x63, 0x69, 0x64, 0x18, 0x21, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x7a, 0x65, 0x72, 0x6f, 0x43, 0x6f, 0x6e, 0x66, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x53, 0x63, 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x22, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x65, 0x65, 0x72, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22, - 0xdf, 0x01, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x76, - 0x65, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61, 0x63, - 0x74, 0x69, 0x76, 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x61, 0x63, - 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0c, 0x69, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1f, 0x0a, - 0x0b, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x21, - 0x0a, 0x0c, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4f, 0x6e, 0x6c, - 0x79, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x65, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x04, 0x70, 0x65, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x6c, - 0x69, 0x61, 0x73, 0x5f, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0f, 0x70, 0x65, 0x65, 0x72, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, - 0x70, 0x22, 0x42, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x08, 0x63, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x08, 0x63, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x22, 0x41, 0x0a, 0x08, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4d, 0x61, - 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x69, 0x64, 0x12, 0x18, - 0x0a, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, - 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, - 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x45, - 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x0a, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x5f, 0x6d, - 0x61, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4d, 0x61, 0x70, 0x52, 0x09, 0x61, 0x6c, 0x69, 0x61, - 0x73, 0x4d, 0x61, 0x70, 0x73, 0x22, 0xb6, 0x06, 0x0a, 0x13, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 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, 0x1b, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x65, 0x65, 0x72, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, + 0x2a, 0x0a, 0x0f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x69, 0x64, 0x5f, 0x61, 0x6c, 0x69, + 0x61, 0x73, 0x18, 0x23, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x0d, 0x70, 0x65, + 0x65, 0x72, 0x53, 0x63, 0x69, 0x64, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22, 0xdf, 0x01, 0x0a, 0x13, + 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x6e, + 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, + 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, + 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x6e, 0x61, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, + 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, + 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x12, 0x0a, + 0x04, 0x70, 0x65, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x70, 0x65, 0x65, + 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x5f, + 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x70, 0x65, + 0x65, 0x72, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x22, 0x42, 0x0a, + 0x14, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x73, 0x22, 0x41, 0x0a, 0x08, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4d, 0x61, 0x70, 0x12, 0x1b, 0x0a, + 0x09, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x08, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x6c, + 0x69, 0x61, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x07, 0x61, 0x6c, 0x69, + 0x61, 0x73, 0x65, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x45, 0x0a, 0x13, 0x4c, 0x69, + 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x2e, 0x0a, 0x0a, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x5f, 0x6d, 0x61, 0x70, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x6c, + 0x69, 0x61, 0x73, 0x4d, 0x61, 0x70, 0x52, 0x09, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x4d, 0x61, 0x70, + 0x73, 0x22, 0xb6, 0x06, 0x0a, 0x13, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6c, 0x6f, + 0x73, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 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, 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, 0x1d, 0x0a, 0x0a, 0x63, + 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x6c, + 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x48, 0x61, + 0x73, 0x68, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x70, 0x75, 0x62, + 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x6d, 0x6f, 0x74, + 0x65, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 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, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x68, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6c, 0x6f, 0x73, 0x65, + 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, + 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0e, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, + 0x2e, 0x0a, 0x13, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x62, + 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x74, 0x69, + 0x6d, 0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, + 0x45, 0x0a, 0x0a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x2e, + 0x43, 0x6c, 0x6f, 0x73, 0x75, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x63, 0x6c, 0x6f, + 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x37, 0x0a, 0x0e, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, + 0x52, 0x0d, 0x6f, 0x70, 0x65, 0x6e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, + 0x39, 0x0a, 0x0f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, + 0x6f, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x0e, 0x63, 0x6c, 0x6f, 0x73, + 0x65, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x33, 0x0a, 0x0b, 0x72, 0x65, + 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x11, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x1f, 0x0a, 0x0b, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x5f, 0x73, 0x63, 0x69, 0x64, 0x73, 0x18, 0x0e, + 0x20, 0x03, 0x28, 0x04, 0x52, 0x0a, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x53, 0x63, 0x69, 0x64, 0x73, + 0x12, 0x3b, 0x0a, 0x18, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x5f, 0x73, 0x63, 0x69, 0x64, 0x18, 0x0f, 0x20, 0x01, + 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x15, 0x7a, 0x65, 0x72, 0x6f, 0x43, 0x6f, 0x6e, 0x66, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x53, 0x63, 0x69, 0x64, 0x22, 0x8a, 0x01, + 0x0a, 0x0b, 0x43, 0x6c, 0x6f, 0x73, 0x75, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x15, 0x0a, + 0x11, 0x43, 0x4f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x56, 0x45, 0x5f, 0x43, 0x4c, 0x4f, + 0x53, 0x45, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f, 0x46, 0x4f, + 0x52, 0x43, 0x45, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x52, + 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x4c, 0x4f, 0x53, + 0x45, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x42, 0x52, 0x45, 0x41, 0x43, 0x48, 0x5f, 0x43, 0x4c, + 0x4f, 0x53, 0x45, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x46, 0x55, 0x4e, 0x44, 0x49, 0x4e, 0x47, + 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x0d, 0x0a, 0x09, 0x41, + 0x42, 0x41, 0x4e, 0x44, 0x4f, 0x4e, 0x45, 0x44, 0x10, 0x05, 0x22, 0xeb, 0x01, 0x0a, 0x0a, 0x52, + 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0f, 0x72, 0x65, 0x73, + 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x6c, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x32, 0x0a, 0x07, 0x6f, 0x75, 0x74, + 0x63, 0x6f, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, + 0x63, 0x6f, 0x6d, 0x65, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x63, 0x6f, 0x6d, 0x65, 0x12, 0x2b, 0x0a, + 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 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, 0x1d, 0x0a, 0x0a, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x61, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x77, 0x65, + 0x65, 0x70, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, + 0x77, 0x65, 0x65, 0x70, 0x54, 0x78, 0x69, 0x64, 0x22, 0xde, 0x01, 0x0a, 0x15, 0x43, 0x6c, 0x6f, + 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x76, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x63, 0x6f, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x76, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x66, 0x6f, + 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x46, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, + 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x72, 0x65, 0x6d, + 0x6f, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x72, 0x65, 0x61, + 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x62, 0x72, 0x65, 0x61, 0x63, 0x68, + 0x12, 0x29, 0x0a, 0x10, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x66, 0x75, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x61, + 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, + 0x61, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x65, 0x64, 0x22, 0x50, 0x0a, 0x16, 0x43, 0x6c, 0x6f, + 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, + 0x79, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x22, 0x8b, 0x05, 0x0a, 0x04, + 0x50, 0x65, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, + 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x5f, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x79, 0x74, + 0x65, 0x73, 0x53, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, + 0x72, 0x65, 0x63, 0x76, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x52, 0x65, 0x63, 0x76, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x61, 0x74, 0x5f, 0x73, 0x65, 0x6e, + 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x73, 0x61, 0x74, 0x53, 0x65, 0x6e, 0x74, + 0x12, 0x19, 0x0a, 0x08, 0x73, 0x61, 0x74, 0x5f, 0x72, 0x65, 0x63, 0x76, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x07, 0x73, 0x61, 0x74, 0x52, 0x65, 0x63, 0x76, 0x12, 0x18, 0x0a, 0x07, 0x69, + 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x6e, + 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x70, 0x69, 0x6e, 0x67, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x31, 0x0a, 0x09, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, + 0x65, 0x72, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x73, 0x79, 0x6e, + 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x50, 0x65, 0x65, 0x72, 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, 0x2f, 0x0a, 0x06, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x65, 0x64, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x12, 0x1d, 0x0a, + 0x0a, 0x66, 0x6c, 0x61, 0x70, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x09, 0x66, 0x6c, 0x61, 0x70, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0c, + 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x66, 0x6c, 0x61, 0x70, 0x5f, 0x6e, 0x73, 0x18, 0x0e, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x46, 0x6c, 0x61, 0x70, 0x4e, 0x73, 0x12, 0x2a, + 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x50, + 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 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, 0x50, 0x0a, 0x08, 0x53, 0x79, 0x6e, 0x63, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x53, + 0x59, 0x4e, 0x43, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5f, + 0x53, 0x59, 0x4e, 0x43, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x41, 0x53, 0x53, 0x49, 0x56, + 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x49, 0x4e, 0x4e, + 0x45, 0x44, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x03, 0x22, 0x46, 0x0a, 0x10, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x65, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1c, 0x0a, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x22, 0x35, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6c, 0x61, 0x74, + 0x65, 0x73, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x36, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, + 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, + 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, + 0x22, 0x17, 0x0a, 0x15, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x84, 0x01, 0x0a, 0x09, 0x50, 0x65, + 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, + 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x2e, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, + 0x0b, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x4f, 0x4e, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x10, + 0x0a, 0x0c, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x4f, 0x46, 0x46, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x01, + 0x22, 0x10, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x22, 0x82, 0x07, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, + 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x48, 0x61, 0x73, + 0x68, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x75, + 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, + 0x69, 0x61, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, + 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x14, 0x6e, 0x75, 0x6d, 0x5f, 0x70, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x6e, 0x75, 0x6d, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x6e, 0x75, 0x6d, 0x5f, + 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x6e, 0x75, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x6e, 0x75, 0x6d, 0x5f, + 0x69, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x6e, 0x75, 0x6d, 0x49, 0x6e, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1b, 0x0a, 0x09, + 0x6e, 0x75, 0x6d, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x08, 0x6e, 0x75, 0x6d, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1d, 0x0a, 0x0a, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x32, 0x0a, 0x15, 0x62, + 0x65, 0x73, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x62, 0x65, 0x73, 0x74, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x26, 0x0a, 0x0f, 0x73, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x79, 0x6e, 0x63, 0x65, 0x64, + 0x54, 0x6f, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x79, 0x6e, 0x63, 0x65, + 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0d, 0x73, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x54, 0x6f, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, + 0x1c, 0x0a, 0x07, 0x74, 0x65, 0x73, 0x74, 0x6e, 0x65, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, + 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x74, 0x65, 0x73, 0x74, 0x6e, 0x65, 0x74, 0x12, 0x24, 0x0a, + 0x06, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x72, 0x69, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x04, 0x75, 0x72, 0x69, 0x73, 0x12, 0x40, 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 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, 0x38, 0x0a, 0x18, 0x72, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, + 0x65, 0x70, 0x74, 0x6f, 0x72, 0x18, 0x15, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x72, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x48, 0x74, 0x6c, 0x63, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, + 0x74, 0x6f, 0x72, 0x12, 0x3f, 0x0a, 0x1c, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x66, 0x69, 0x6e, + 0x61, 0x6c, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x48, 0x74, 0x6c, 0x63, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 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, 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, 0x22, 0x18, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x52, 0x65, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x22, 0x87, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, + 0x0d, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x4d, 0x6f, + 0x64, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x66, + 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, + 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, + 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x01, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, 0x37, 0x0a, 0x05, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x7a, 0x0a, 0x12, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x68, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x68, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x75, + 0x6d, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x73, 0x5f, 0x6c, 0x65, 0x66, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x73, 0x4c, 0x65, 0x66, 0x74, + 0x22, 0x4d, 0x0a, 0x11, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4f, 0x70, 0x65, 0x6e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 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, 0x22, + 0x51, 0x0a, 0x12, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, + 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x6c, 0x6f, + 0x73, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x22, 0xa6, 0x02, 0x0a, 0x13, 0x43, 0x6c, 0x6f, 0x73, 0x65, 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, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x24, 0x0a, 0x0c, 0x73, + 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x73, 0x61, 0x74, 0x50, 0x65, 0x72, 0x42, 0x79, 0x74, + 0x65, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x6c, + 0x69, 0x76, 0x65, 0x72, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x22, 0x0a, 0x0d, + 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, + 0x12, 0x29, 0x0a, 0x11, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, + 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x6d, 0x61, 0x78, + 0x46, 0x65, 0x65, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, 0x22, 0x96, 0x01, 0x0a, 0x11, + 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x12, 0x3b, 0x0a, 0x0d, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, + 0x52, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x3a, + 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, + 0x09, 0x63, 0x68, 0x61, 0x6e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x22, 0x46, 0x0a, 0x0d, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0b, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x79, 0x0a, 0x13, + 0x52, 0x65, 0x61, 0x64, 0x79, 0x46, 0x6f, 0x72, 0x50, 0x73, 0x62, 0x74, 0x46, 0x75, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x66, 0x75, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x25, 0x0a, 0x0e, + 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x73, 0x62, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x04, 0x70, 0x73, 0x62, 0x74, 0x22, 0xf3, 0x01, 0x0a, 0x17, 0x42, 0x61, 0x74, 0x63, + 0x68, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x33, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, + 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x08, + 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x22, 0x0a, 0x0d, 0x73, 0x61, 0x74, + 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0b, 0x73, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, 0x12, 0x1b, 0x0a, + 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x73, 0x70, + 0x65, 0x6e, 0x64, 0x5f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0xf5, 0x02, + 0x0a, 0x10, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6e, 0x6f, 0x64, 0x65, 0x50, 0x75, 0x62, + 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x14, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x66, 0x75, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x12, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x41, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x73, 0x61, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, 0x75, 0x73, 0x68, 0x53, 0x61, 0x74, + 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x69, + 0x6e, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x48, 0x74, 0x6c, 0x63, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x28, + 0x0a, 0x10, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x63, 0x73, 0x76, 0x5f, 0x64, 0x65, 0x6c, + 0x61, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, + 0x43, 0x73, 0x76, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6c, 0x6f, 0x73, + 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x26, 0x0a, + 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, + 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x3e, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, + 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x5b, 0x0a, 0x18, 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, 0x3f, 0x0a, 0x10, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x52, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x73, 0x22, 0xed, 0x07, 0x0a, 0x12, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x73, 0x61, 0x74, + 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x0b, 0x73, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, 0x12, 0x1f, 0x0a, + 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0a, 0x6e, 0x6f, 0x64, 0x65, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x30, + 0x0a, 0x12, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x10, + 0x6e, 0x6f, 0x64, 0x65, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x12, 0x30, 0x0a, 0x14, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, 0x75, 0x73, 0x68, 0x53, 0x61, 0x74, 0x12, 0x1f, 0x0a, + 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x24, + 0x0a, 0x0c, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x73, 0x61, 0x74, 0x50, 0x65, 0x72, + 0x42, 0x79, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x22, + 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x48, 0x74, 0x6c, 0x63, 0x4d, 0x73, + 0x61, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x63, 0x73, 0x76, + 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x72, 0x65, + 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x73, 0x76, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x1b, 0x0a, 0x09, + 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x08, 0x6d, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x73, 0x70, 0x65, + 0x6e, 0x64, 0x5f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x18, 0x0c, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, + 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x35, 0x0a, 0x0c, 0x66, + 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x68, 0x69, 0x6d, 0x18, 0x0e, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x53, 0x68, 0x69, 0x6d, 0x52, 0x0b, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x68, + 0x69, 0x6d, 0x12, 0x43, 0x0a, 0x1f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x78, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x69, 0x6e, 0x5f, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, + 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x72, 0x65, 0x6d, + 0x6f, 0x74, 0x65, 0x4d, 0x61, 0x78, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x49, 0x6e, 0x46, 0x6c, 0x69, + 0x67, 0x68, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x65, 0x6d, 0x6f, 0x74, + 0x65, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4d, 0x61, 0x78, 0x48, 0x74, 0x6c, 0x63, + 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x63, + 0x73, 0x76, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x4c, 0x6f, 0x63, + 0x61, 0x6c, 0x43, 0x73, 0x76, 0x12, 0x3e, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, + 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x63, 0x6f, + 0x6e, 0x66, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x7a, 0x65, 0x72, 0x6f, 0x43, 0x6f, + 0x6e, 0x66, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x69, 0x64, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, + 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x63, 0x69, 0x64, 0x41, 0x6c, 0x69, 0x61, + 0x73, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x15, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x12, 0x19, 0x0a, 0x08, + 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, + 0x66, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x75, 0x73, 0x65, 0x5f, 0x62, + 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, + 0x73, 0x65, 0x42, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x75, 0x73, 0x65, + 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0a, 0x75, 0x73, 0x65, 0x46, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x17, 0x72, + 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x72, 0x65, + 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x53, + 0x61, 0x74, 0x22, 0xf3, 0x01, 0x0a, 0x10, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x39, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x5f, + 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x12, 0x37, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4f, 0x70, 0x65, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, + 0x00, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x39, 0x0a, 0x09, 0x70, + 0x73, 0x62, 0x74, 0x5f, 0x66, 0x75, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x79, 0x46, 0x6f, 0x72, 0x50, + 0x73, 0x62, 0x74, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x08, 0x70, 0x73, + 0x62, 0x74, 0x46, 0x75, 0x6e, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0d, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x42, 0x08, + 0x0a, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x48, 0x0a, 0x0a, 0x4b, 0x65, 0x79, 0x4c, + 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, 0x66, 0x61, + 0x6d, 0x69, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6b, 0x65, 0x79, 0x46, + 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x49, 0x6e, 0x64, + 0x65, 0x78, 0x22, 0x5f, 0x0a, 0x0d, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x6f, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x72, 0x61, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x72, 0x61, 0x77, 0x4b, + 0x65, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x5f, 0x6c, + 0x6f, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x06, 0x6b, 0x65, 0x79, + 0x4c, 0x6f, 0x63, 0x22, 0xf0, 0x01, 0x0a, 0x0d, 0x43, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, + 0x74, 0x53, 0x68, 0x69, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6d, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x03, 0x61, 0x6d, 0x74, 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, 0x31, 0x0a, 0x09, 0x6c, + 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x6f, 0x72, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x12, 0x1d, + 0x0a, 0x0a, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x09, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, + 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, + 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x68, 0x61, 0x77, 0x5f, 0x68, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x68, 0x61, 0x77, + 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x6e, 0x0a, 0x08, 0x50, 0x73, 0x62, 0x74, 0x53, 0x68, + 0x69, 0x6d, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, + 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x70, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x61, + 0x73, 0x65, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x62, + 0x61, 0x73, 0x65, 0x50, 0x73, 0x62, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x6f, 0x5f, 0x70, 0x75, + 0x62, 0x6c, 0x69, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6e, 0x6f, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x22, 0x85, 0x01, 0x0a, 0x0b, 0x46, 0x75, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x53, 0x68, 0x69, 0x6d, 0x12, 0x3e, 0x0a, 0x0f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x73, 0x68, 0x69, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, + 0x74, 0x53, 0x68, 0x69, 0x6d, 0x48, 0x00, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x69, + 0x6e, 0x74, 0x53, 0x68, 0x69, 0x6d, 0x12, 0x2e, 0x0a, 0x09, 0x70, 0x73, 0x62, 0x74, 0x5f, 0x73, + 0x68, 0x69, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x50, 0x73, 0x62, 0x74, 0x53, 0x68, 0x69, 0x6d, 0x48, 0x00, 0x52, 0x08, 0x70, 0x73, + 0x62, 0x74, 0x53, 0x68, 0x69, 0x6d, 0x42, 0x06, 0x0a, 0x04, 0x73, 0x68, 0x69, 0x6d, 0x22, 0x3b, + 0x0a, 0x11, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x68, 0x69, 0x6d, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, + 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x70, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x22, 0x81, 0x01, 0x0a, 0x11, + 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x73, 0x62, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x70, 0x73, 0x62, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x66, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x73, + 0x62, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, + 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x70, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6b, + 0x69, 0x70, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x22, + 0x80, 0x01, 0x0a, 0x13, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x73, 0x62, 0x74, 0x46, + 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x65, + 0x64, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, + 0x67, 0x6e, 0x65, 0x64, 0x50, 0x73, 0x62, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0d, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x64, + 0x12, 0x20, 0x0a, 0x0c, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x61, 0x77, 0x5f, 0x74, 0x78, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x61, 0x77, + 0x54, 0x78, 0x22, 0x99, 0x02, 0x0a, 0x14, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x67, 0x12, 0x39, 0x0a, 0x0d, 0x73, + 0x68, 0x69, 0x6d, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x53, 0x68, 0x69, 0x6d, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x68, 0x69, 0x6d, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x3b, 0x0a, 0x0b, 0x73, 0x68, 0x69, 0x6d, 0x5f, 0x63, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x68, 0x69, 0x6d, 0x43, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x48, 0x00, 0x52, 0x0a, 0x73, 0x68, 0x69, 0x6d, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x12, 0x3b, 0x0a, 0x0b, 0x70, 0x73, 0x62, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x69, + 0x66, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x73, 0x62, 0x74, 0x56, 0x65, 0x72, 0x69, + 0x66, 0x79, 0x48, 0x00, 0x52, 0x0a, 0x70, 0x73, 0x62, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x12, 0x41, 0x0a, 0x0d, 0x70, 0x73, 0x62, 0x74, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x73, 0x62, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6c, + 0x69, 0x7a, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x70, 0x73, 0x62, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6c, + 0x69, 0x7a, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x22, 0x16, + 0x0a, 0x14, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, + 0x65, 0x70, 0x52, 0x65, 0x73, 0x70, 0x22, 0xcc, 0x01, 0x0a, 0x0b, 0x50, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x48, 0x54, 0x4c, 0x43, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, + 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, + 0x6e, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x75, + 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x75, + 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x6d, 0x61, 0x74, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0e, 0x6d, 0x61, 0x74, 0x75, 0x72, 0x69, 0x74, 0x79, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, + 0x2e, 0x0a, 0x13, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x74, 0x69, 0x6c, 0x5f, 0x6d, 0x61, + 0x74, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x73, 0x54, 0x69, 0x6c, 0x4d, 0x61, 0x74, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, + 0x73, 0x74, 0x61, 0x67, 0x65, 0x22, 0x18, 0x0a, 0x16, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, + 0xf3, 0x12, 0x0a, 0x17, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6c, 0x69, 0x6d, 0x62, 0x6f, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, + 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4c, + 0x69, 0x6d, 0x62, 0x6f, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x65, 0x0a, 0x15, 0x70, + 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 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, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x13, 0x70, + 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x73, 0x12, 0x6a, 0x0a, 0x18, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6c, + 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 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, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x42, 0x02, 0x18, 0x01, 0x52, 0x16, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, + 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x76, + 0x0a, 0x1e, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, + 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 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, 0x2e, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x43, 0x6c, 0x6f, 0x73, + 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x1b, 0x70, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x43, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x68, 0x0a, 0x16, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, + 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 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, 0x2e, 0x57, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6c, + 0x6f, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x14, 0x77, 0x61, 0x69, 0x74, + 0x69, 0x6e, 0x67, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, + 0x1a, 0x9f, 0x04, 0x0a, 0x0e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x6e, 0x6f, + 0x64, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, + 0x6d, 0x6f, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x75, 0x62, 0x12, 0x23, 0x0a, 0x0d, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 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, 0x23, 0x0a, 0x0d, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, + 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x62, 0x61, 0x6c, 0x61, + 0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x72, 0x65, 0x6d, 0x6f, 0x74, + 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x16, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x5f, 0x73, + 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x43, + 0x68, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x53, 0x61, 0x74, 0x12, 0x35, 0x0a, + 0x17, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x72, 0x65, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, + 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x53, 0x61, 0x74, 0x12, 0x2e, 0x0a, 0x09, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, + 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x09, 0x69, 0x6e, 0x69, 0x74, 0x69, + 0x61, 0x74, 0x6f, 0x72, 0x12, 0x3e, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, + 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x36, 0x0a, 0x17, 0x6e, 0x75, 0x6d, 0x5f, 0x66, 0x6f, 0x72, 0x77, + 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x6e, 0x75, 0x6d, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, + 0x64, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, + 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x66, 0x6c, 0x61, 0x67, + 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x68, 0x61, 0x6e, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, + 0x61, 0x74, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, + 0x74, 0x65, 0x1a, 0xc5, 0x01, 0x0a, 0x12, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4f, 0x70, + 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x47, 0x0a, 0x07, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 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, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x66, 0x65, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x46, 0x65, + 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x77, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1c, 0x0a, 0x0a, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x65, + 0x72, 0x5f, 0x6b, 0x77, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x66, 0x65, 0x65, 0x50, + 0x65, 0x72, 0x4b, 0x77, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x1a, 0xf4, 0x01, 0x0a, 0x13, 0x57, + 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x12, 0x47, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2d, 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, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x6c, + 0x69, 0x6d, 0x62, 0x6f, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x69, 0x6d, 0x62, 0x6f, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x12, 0x4c, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 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, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x21, + 0x0a, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x69, + 0x64, 0x1a, 0xa3, 0x02, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x54, 0x78, 0x69, 0x64, + 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x54, 0x78, 0x69, + 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, + 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x69, + 0x64, 0x12, 0x2f, 0x0a, 0x14, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x11, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x46, 0x65, 0x65, 0x53, + 0x61, 0x74, 0x12, 0x31, 0x0a, 0x15, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x12, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x46, + 0x65, 0x65, 0x53, 0x61, 0x74, 0x12, 0x40, 0x0a, 0x1d, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, + 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x66, + 0x65, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x19, 0x72, 0x65, + 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x46, 0x65, 0x65, 0x53, 0x61, 0x74, 0x1a, 0x7b, 0x0a, 0x0d, 0x43, 0x6c, 0x6f, 0x73, 0x65, + 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x47, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 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, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, + 0x54, 0x78, 0x69, 0x64, 0x1a, 0xee, 0x03, 0x0a, 0x12, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x43, 0x6c, + 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x47, 0x0a, 0x07, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 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, 0x2e, 0x50, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x07, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x5f, + 0x74, 0x78, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x6f, 0x73, + 0x69, 0x6e, 0x67, 0x54, 0x78, 0x69, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x69, 0x6d, 0x62, 0x6f, + 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, + 0x6c, 0x69, 0x6d, 0x62, 0x6f, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x27, 0x0a, 0x0f, + 0x6d, 0x61, 0x74, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x6d, 0x61, 0x74, 0x75, 0x72, 0x69, 0x74, 0x79, 0x48, + 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x5f, + 0x74, 0x69, 0x6c, 0x5f, 0x6d, 0x61, 0x74, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x11, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x54, 0x69, 0x6c, 0x4d, 0x61, 0x74, + 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x65, 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x10, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x65, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, + 0x63, 0x65, 0x12, 0x37, 0x0a, 0x0d, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x68, 0x74, + 0x6c, 0x63, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x54, 0x4c, 0x43, 0x52, 0x0c, 0x70, + 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x74, 0x6c, 0x63, 0x73, 0x12, 0x55, 0x0a, 0x06, 0x61, + 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3d, 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, 0x2e, 0x46, 0x6f, 0x72, 0x63, + 0x65, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x41, + 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x06, 0x61, 0x6e, 0x63, 0x68, + 0x6f, 0x72, 0x22, 0x31, 0x0a, 0x0b, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x49, 0x4d, 0x42, 0x4f, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, + 0x52, 0x45, 0x43, 0x4f, 0x56, 0x45, 0x52, 0x45, 0x44, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4c, + 0x4f, 0x53, 0x54, 0x10, 0x02, 0x22, 0x1a, 0x0a, 0x18, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0xff, 0x04, 0x0a, 0x12, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x33, 0x0a, 0x0c, 0x6f, 0x70, 0x65, 0x6e, + 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x48, 0x00, + 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x43, 0x0a, + 0x0e, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, + 0x79, 0x48, 0x00, 0x52, 0x0d, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x12, 0x3c, 0x0a, 0x0e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x03, 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, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x12, 0x40, 0x0a, 0x10, 0x69, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 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, 0x48, + 0x00, 0x52, 0x0f, 0x69, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x12, 0x48, 0x0a, 0x14, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x70, + 0x65, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x12, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x4b, 0x0a, 0x16, + 0x66, 0x75, 0x6c, 0x6c, 0x79, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x5f, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x07, 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, 0x14, 0x66, 0x75, 0x6c, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, + 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x38, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 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, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x22, 0x92, 0x01, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x4f, 0x50, 0x45, 0x4e, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, + 0x45, 0x4c, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44, 0x5f, 0x43, + 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x41, 0x43, 0x54, 0x49, + 0x56, 0x45, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, + 0x49, 0x4e, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, + 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x4f, 0x50, + 0x45, 0x4e, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x10, 0x04, 0x12, 0x1a, 0x0a, 0x16, + 0x46, 0x55, 0x4c, 0x4c, 0x59, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x44, 0x5f, 0x43, + 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x10, 0x05, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x22, 0x74, 0x0a, 0x14, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, + 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x75, 0x6e, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, + 0x65, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x57, 0x61, 0x6c, + 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x22, 0xbd, 0x03, 0x0a, 0x15, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, + 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x12, 0x2b, 0x0a, 0x11, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x5f, 0x62, 0x61, + 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x2f, 0x0a, + 0x13, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x6c, + 0x61, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x75, 0x6e, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x25, + 0x0a, 0x0e, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x42, 0x61, + 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x3f, 0x0a, 0x1c, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, + 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x19, 0x72, 0x65, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x6e, 0x63, 0x68, + 0x6f, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x12, 0x59, 0x0a, 0x0f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x30, 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, 0x2e, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, + 0x65, 0x1a, 0x5e, 0x0a, 0x13, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x61, 0x6c, 0x61, + 0x6e, 0x63, 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, 0x31, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, + 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x2e, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x73, + 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x73, 0x61, 0x74, 0x12, 0x12, 0x0a, + 0x04, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x6d, 0x73, 0x61, + 0x74, 0x22, 0x17, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, + 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x80, 0x04, 0x0a, 0x16, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x62, 0x61, 0x6c, 0x61, + 0x6e, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x14, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6f, + 0x70, 0x65, 0x6e, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x12, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4f, 0x70, + 0x65, 0x6e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x0d, 0x6c, 0x6f, 0x63, + 0x61, 0x6c, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x34, 0x0a, + 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x0d, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x42, 0x61, 0x6c, 0x61, + 0x6e, 0x63, 0x65, 0x12, 0x45, 0x0a, 0x17, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x64, + 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x15, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x4c, 0x6f, + 0x63, 0x61, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x47, 0x0a, 0x18, 0x75, 0x6e, + 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x62, + 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x16, 0x75, 0x6e, 0x73, + 0x65, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x42, 0x61, 0x6c, 0x61, + 0x6e, 0x63, 0x65, 0x12, 0x4a, 0x0a, 0x1a, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6f, + 0x70, 0x65, 0x6e, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, + 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x17, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4f, + 0x70, 0x65, 0x6e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, + 0x4c, 0x0a, 0x1b, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x5f, + 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x18, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4f, 0x70, 0x65, 0x6e, + 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, 0xcb, 0x06, + 0x0a, 0x12, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x61, 0x6d, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x61, 0x6d, 0x74, 0x12, + 0x19, 0x0a, 0x08, 0x61, 0x6d, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x07, 0x61, 0x6d, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x66, 0x69, + 0x6e, 0x61, 0x6c, 0x5f, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x43, 0x6c, 0x74, 0x76, 0x44, + 0x65, 0x6c, 0x74, 0x61, 0x12, 0x2c, 0x0a, 0x09, 0x66, 0x65, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x46, 0x65, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x08, 0x66, 0x65, 0x65, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x6e, 0x6f, + 0x64, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, + 0x65, 0x64, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x0d, 0x69, 0x67, 0x6e, 0x6f, 0x72, + 0x65, 0x64, 0x5f, 0x65, 0x64, 0x67, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x64, 0x67, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x6f, 0x72, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x45, + 0x64, 0x67, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, + 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x13, 0x75, 0x73, + 0x65, 0x5f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x75, 0x73, 0x65, 0x4d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x34, 0x0a, 0x0d, 0x69, 0x67, + 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x61, + 0x69, 0x72, 0x52, 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x50, 0x61, 0x69, 0x72, 0x73, + 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x0b, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x63, 0x6c, 0x74, 0x76, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, + 0x60, 0x0a, 0x13, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 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, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x43, 0x75, 0x73, 0x74, + 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, + 0x64, 0x65, 0x73, 0x74, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, + 0x73, 0x12, 0x2c, 0x0a, 0x10, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, + 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, + 0x0e, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, + 0x26, 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, 0x70, 0x75, 0x62, 0x6b, + 0x65, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x48, 0x6f, + 0x70, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x0b, 0x72, 0x6f, 0x75, 0x74, 0x65, + 0x5f, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x10, 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, 0x36, 0x0a, 0x0d, 0x64, 0x65, + 0x73, 0x74, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x11, 0x20, 0x03, 0x28, + 0x0e, 0x32, 0x11, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x42, 0x69, 0x74, 0x52, 0x0c, 0x64, 0x65, 0x73, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x18, + 0x12, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x50, 0x72, 0x65, 0x66, 0x1a, + 0x44, 0x0a, 0x16, 0x44, 0x65, 0x73, 0x74, 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, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x2e, 0x0a, 0x08, 0x4e, + 0x6f, 0x64, 0x65, 0x50, 0x61, 0x69, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, + 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x74, 0x6f, 0x22, 0x5d, 0x0a, 0x0b, 0x45, + 0x64, 0x67, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 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, 0x2b, 0x0a, + 0x11, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x76, 0x65, 0x72, + 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x22, 0x5e, 0x0a, 0x13, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x24, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, + 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x73, + 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x72, 0x6f, 0x62, 0x22, 0xb1, 0x04, 0x0a, 0x03, 0x48, + 0x6f, 0x70, 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, 0x69, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x26, - 0x0a, 0x0f, 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, - 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, - 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, - 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, - 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 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, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x65, - 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, - 0x6c, 0x6f, 0x73, 0x65, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, - 0x74, 0x74, 0x6c, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0e, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x6c, 0x61, - 0x6e, 0x63, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, - 0x65, 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x11, 0x74, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x42, 0x61, 0x6c, 0x61, - 0x6e, 0x63, 0x65, 0x12, 0x45, 0x0a, 0x0a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x75, 0x6d, 0x6d, - 0x61, 0x72, 0x79, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x75, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x09, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x37, 0x0a, 0x0e, 0x6f, 0x70, - 0x65, 0x6e, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x0b, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, - 0x61, 0x74, 0x6f, 0x72, 0x52, 0x0d, 0x6f, 0x70, 0x65, 0x6e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, - 0x74, 0x6f, 0x72, 0x12, 0x39, 0x0a, 0x0f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x69, 0x6e, 0x69, - 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x0e, - 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x33, - 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0d, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x5f, 0x73, 0x63, 0x69, - 0x64, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0a, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x53, - 0x63, 0x69, 0x64, 0x73, 0x12, 0x3b, 0x0a, 0x18, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x63, 0x6f, 0x6e, - 0x66, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x5f, 0x73, 0x63, 0x69, 0x64, - 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x15, 0x7a, 0x65, 0x72, 0x6f, - 0x43, 0x6f, 0x6e, 0x66, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x53, 0x63, 0x69, - 0x64, 0x22, 0x8a, 0x01, 0x0a, 0x0b, 0x43, 0x6c, 0x6f, 0x73, 0x75, 0x72, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x4f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x56, 0x45, - 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x4c, 0x4f, 0x43, 0x41, - 0x4c, 0x5f, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x01, 0x12, - 0x16, 0x0a, 0x12, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, - 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x42, 0x52, 0x45, 0x41, 0x43, - 0x48, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x46, 0x55, 0x4e, - 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, - 0x0d, 0x0a, 0x09, 0x41, 0x42, 0x41, 0x4e, 0x44, 0x4f, 0x4e, 0x45, 0x44, 0x10, 0x05, 0x22, 0xeb, - 0x01, 0x0a, 0x0a, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, - 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0e, 0x72, - 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x32, 0x0a, - 0x07, 0x6f, 0x75, 0x74, 0x63, 0x6f, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x4f, 0x75, 0x74, 0x63, 0x6f, 0x6d, 0x65, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x63, 0x6f, 0x6d, - 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 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, 0x1d, - 0x0a, 0x0a, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x09, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x61, 0x74, 0x12, 0x1d, 0x0a, - 0x0a, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x73, 0x77, 0x65, 0x65, 0x70, 0x54, 0x78, 0x69, 0x64, 0x22, 0xde, 0x01, 0x0a, - 0x15, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6f, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x63, 0x6f, 0x6f, - 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x5f, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x6c, - 0x6f, 0x63, 0x61, 0x6c, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x6d, - 0x6f, 0x74, 0x65, 0x5f, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x62, 0x72, 0x65, 0x61, 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x62, 0x72, - 0x65, 0x61, 0x63, 0x68, 0x12, 0x29, 0x0a, 0x10, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, - 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, - 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x12, - 0x1c, 0x0a, 0x09, 0x61, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x09, 0x61, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x65, 0x64, 0x22, 0x50, 0x0a, - 0x16, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x75, - 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x22, - 0x8b, 0x05, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, - 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, - 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x09, 0x62, 0x79, 0x74, 0x65, 0x73, 0x53, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x79, - 0x74, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x63, 0x76, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x52, 0x65, 0x63, 0x76, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x61, 0x74, - 0x5f, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x73, 0x61, 0x74, - 0x53, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x61, 0x74, 0x5f, 0x72, 0x65, 0x63, 0x76, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x73, 0x61, 0x74, 0x52, 0x65, 0x63, 0x76, 0x12, - 0x18, 0x0a, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x69, 0x6e, - 0x67, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x70, 0x69, - 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x31, 0x0a, 0x09, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x08, 0x73, 0x79, 0x6e, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x66, 0x65, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 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, 0x2f, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x65, 0x64, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x6c, 0x61, 0x70, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x66, 0x6c, 0x61, 0x70, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x20, 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x66, 0x6c, 0x61, 0x70, 0x5f, 0x6e, 0x73, - 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x46, 0x6c, 0x61, 0x70, - 0x4e, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x69, 0x6e, 0x67, 0x5f, - 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x6c, - 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x1a, 0x4b, + 0x27, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x6e, + 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x28, 0x0a, 0x0e, 0x61, 0x6d, 0x74, 0x5f, + 0x74, 0x6f, 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x42, 0x02, 0x18, 0x01, 0x52, 0x0c, 0x61, 0x6d, 0x74, 0x54, 0x6f, 0x46, 0x6f, 0x72, 0x77, 0x61, + 0x72, 0x64, 0x12, 0x14, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x42, + 0x02, 0x18, 0x01, 0x52, 0x03, 0x66, 0x65, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x69, + 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, + 0x12, 0x2d, 0x0a, 0x13, 0x61, 0x6d, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, + 0x72, 0x64, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x61, + 0x6d, 0x74, 0x54, 0x6f, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x4d, 0x73, 0x61, 0x74, 0x12, + 0x19, 0x0a, 0x08, 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x07, 0x66, 0x65, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x75, + 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, + 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0b, 0x74, 0x6c, 0x76, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x74, 0x6c, + 0x76, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x2f, 0x0a, 0x0a, 0x6d, 0x70, 0x70, 0x5f, + 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x50, 0x50, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x09, + 0x6d, 0x70, 0x70, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x2f, 0x0a, 0x0a, 0x61, 0x6d, 0x70, + 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x4d, 0x50, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, + 0x09, 0x61, 0x6d, 0x70, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x44, 0x0a, 0x0e, 0x63, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x0b, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x6f, 0x70, 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, 0x1a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0d, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 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, 0x54, + 0x0a, 0x09, 0x4d, 0x50, 0x50, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 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, 0x24, + 0x0a, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6d, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6d, 0x74, + 0x4d, 0x73, 0x61, 0x74, 0x22, 0x62, 0x0a, 0x09, 0x41, 0x4d, 0x50, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 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, 0x22, 0xe1, 0x01, 0x0a, 0x05, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x12, 0x21, 0x0a, 0x0a, 0x74, 0x6f, + 0x74, 0x61, 0x6c, 0x5f, 0x66, 0x65, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, + 0x18, 0x01, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x46, 0x65, 0x65, 0x73, 0x12, 0x1f, 0x0a, + 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6d, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x42, 0x02, 0x18, 0x01, 0x52, 0x08, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6d, 0x74, 0x12, 0x1e, + 0x0a, 0x04, 0x68, 0x6f, 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x6f, 0x70, 0x52, 0x04, 0x68, 0x6f, 0x70, 0x73, 0x12, 0x26, + 0x0a, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x66, 0x65, 0x65, 0x73, 0x5f, 0x6d, 0x73, 0x61, + 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x46, 0x65, + 0x65, 0x73, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, + 0x61, 0x6d, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, + 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6d, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x22, 0x55, 0x0a, 0x0f, + 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x17, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x73, 0x22, 0xae, 0x01, 0x0a, 0x08, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x28, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 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, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x75, + 0x6d, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x25, 0x0a, + 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x61, 0x70, 0x61, + 0x63, 0x69, 0x74, 0x79, 0x12, 0x2e, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, + 0x18, 0x04, 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, 0x08, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x73, 0x22, 0xc6, 0x03, 0x0a, 0x0d, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, + 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6c, 0x61, 0x73, + 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x30, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x18, 0x04, 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, 0x09, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, + 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x3e, + 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x22, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, + 0x6e, 0x67, 0x4e, 0x6f, 0x64, 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, 0x4e, + 0x0a, 0x0e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, + 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, + 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 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, 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, 0x50, 0x0a, 0x08, 0x53, - 0x79, 0x6e, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, - 0x57, 0x4e, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x43, 0x54, - 0x49, 0x56, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x41, - 0x53, 0x53, 0x49, 0x56, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, - 0x50, 0x49, 0x4e, 0x4e, 0x45, 0x44, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x03, 0x22, 0x46, 0x0a, - 0x10, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x65, 0x64, 0x45, 0x72, 0x72, 0x6f, - 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x35, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, - 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6c, 0x61, 0x74, - 0x65, 0x73, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0b, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x36, 0x0a, 0x11, - 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x21, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x0b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x05, 0x70, - 0x65, 0x65, 0x72, 0x73, 0x22, 0x17, 0x0a, 0x15, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x84, 0x01, - 0x0a, 0x09, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, - 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, - 0x62, 0x4b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x2e, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x4f, 0x4e, 0x4c, 0x49, 0x4e, 0x45, - 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x4f, 0x46, 0x46, 0x4c, 0x49, - 0x4e, 0x45, 0x10, 0x01, 0x22, 0x10, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x82, 0x07, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x14, - 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, - 0x6c, 0x69, 0x61, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x11, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x14, 0x6e, 0x75, - 0x6d, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x6e, 0x75, 0x6d, 0x50, 0x65, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x2e, 0x0a, 0x13, - 0x6e, 0x75, 0x6d, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x6e, 0x75, 0x6d, 0x41, 0x63, - 0x74, 0x69, 0x76, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x32, 0x0a, 0x15, - 0x6e, 0x75, 0x6d, 0x5f, 0x69, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x6e, 0x75, 0x6d, - 0x49, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, - 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x75, 0x6d, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6e, 0x75, 0x6d, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x21, 0x0a, - 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, - 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, - 0x32, 0x0a, 0x15, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, - 0x62, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x5f, 0x74, 0x6f, - 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x79, - 0x6e, 0x63, 0x65, 0x64, 0x54, 0x6f, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x26, 0x0a, 0x0f, 0x73, - 0x79, 0x6e, 0x63, 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x12, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x54, 0x6f, 0x47, 0x72, - 0x61, 0x70, 0x68, 0x12, 0x1c, 0x0a, 0x07, 0x74, 0x65, 0x73, 0x74, 0x6e, 0x65, 0x74, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x74, 0x65, 0x73, 0x74, 0x6e, 0x65, - 0x74, 0x12, 0x24, 0x0a, 0x06, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, - 0x06, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x72, 0x69, 0x73, 0x18, - 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x75, 0x72, 0x69, 0x73, 0x12, 0x40, 0x0a, 0x08, 0x66, - 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 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, 0x38, 0x0a, - 0x18, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x6f, 0x72, 0x18, 0x15, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x16, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x48, 0x74, 0x6c, 0x63, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x63, 0x65, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x3f, 0x0a, 0x1c, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x72, 0x65, 0x73, 0x6f, - 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x48, 0x74, 0x6c, 0x63, 0x52, 0x65, 0x73, - 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x4b, 0x0a, 0x0d, 0x46, 0x65, 0x61, 0x74, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 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, 0x3b, 0x0a, + 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, 0x98, 0x03, 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, + 0x65, 0x6c, 0x74, 0x61, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x69, 0x6e, 0x5f, 0x68, 0x74, 0x6c, 0x63, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x69, 0x6e, 0x48, 0x74, 0x6c, 0x63, 0x12, + 0x22, 0x0a, 0x0d, 0x66, 0x65, 0x65, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x66, 0x65, 0x65, 0x42, 0x61, 0x73, 0x65, 0x4d, + 0x73, 0x61, 0x74, 0x12, 0x2d, 0x0a, 0x13, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, + 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x10, 0x66, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x4d, 0x73, + 0x61, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 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, 0x1f, 0x0a, 0x0b, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x12, 0x4e, 0x0a, 0x0e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 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, 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, 0x2e, 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, 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, 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, 0x22, 0x18, 0x0a, 0x16, 0x47, - 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x87, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, - 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x6d, 0x6f, - 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, - 0x72, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, - 0x72, 0x79, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x10, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x69, 0x6e, 0x69, 0x73, - 0x68, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, - 0x37, 0x0a, 0x05, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x18, - 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x7a, 0x0a, 0x12, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1b, - 0x0a, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x68, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x08, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x68, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x24, - 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x73, 0x5f, 0x6c, 0x65, 0x66, 0x74, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x73, - 0x4c, 0x65, 0x66, 0x74, 0x22, 0x4d, 0x0a, 0x11, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4f, - 0x70, 0x65, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 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, 0x22, 0x51, 0x0a, 0x12, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6c, - 0x6f, 0x73, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, - 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0b, 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, - 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, - 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0xa6, 0x02, 0x0a, 0x13, 0x43, 0x6c, 0x6f, 0x73, 0x65, - 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, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x1f, - 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x12, - 0x24, 0x0a, 0x0c, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x73, 0x61, 0x74, 0x50, 0x65, - 0x72, 0x42, 0x79, 0x74, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, - 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0f, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x22, 0x0a, 0x0d, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x76, 0x62, 0x79, 0x74, - 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, - 0x62, 0x79, 0x74, 0x65, 0x12, 0x29, 0x0a, 0x11, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x65, 0x65, 0x5f, - 0x70, 0x65, 0x72, 0x5f, 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0e, 0x6d, 0x61, 0x78, 0x46, 0x65, 0x65, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, 0x22, - 0x96, 0x01, 0x0a, 0x11, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x0d, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x70, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x48, 0x00, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x42, 0x08, - 0x0a, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x46, 0x0a, 0x0d, 0x50, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x21, 0x0a, - 0x0c, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, - 0x22, 0x79, 0x0a, 0x13, 0x52, 0x65, 0x61, 0x64, 0x79, 0x46, 0x6f, 0x72, 0x50, 0x73, 0x62, 0x74, - 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x75, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0e, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x73, 0x62, 0x74, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x70, 0x73, 0x62, 0x74, 0x22, 0xf3, 0x01, 0x0a, 0x17, - 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x33, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1f, 0x0a, 0x0b, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x22, 0x0a, - 0x0d, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x73, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, - 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x73, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x73, 0x12, 0x2b, - 0x0a, 0x11, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x5f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, - 0x6d, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x73, 0x70, 0x65, 0x6e, 0x64, - 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, - 0x61, 0x62, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, - 0x6c, 0x22, 0xf5, 0x02, 0x0a, 0x10, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, 0x6e, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x70, - 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6e, 0x6f, 0x64, - 0x65, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x14, 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x5f, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x46, 0x75, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x75, 0x73, - 0x68, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, 0x75, 0x73, - 0x68, 0x53, 0x61, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x22, - 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x48, 0x74, 0x6c, 0x63, 0x4d, 0x73, - 0x61, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x63, 0x73, 0x76, - 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x72, 0x65, - 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x73, 0x76, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x23, 0x0a, 0x0d, - 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x70, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x3e, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x5b, 0x0a, 0x18, 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, 0x3f, 0x0a, 0x10, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x22, 0xed, 0x07, 0x0a, 0x12, 0x4f, 0x70, 0x65, 0x6e, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, - 0x0d, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, - 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6e, 0x6f, 0x64, 0x65, 0x50, 0x75, 0x62, 0x6b, - 0x65, 0x79, 0x12, 0x30, 0x0a, 0x12, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, - 0x79, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, - 0x18, 0x01, 0x52, 0x10, 0x6e, 0x6f, 0x64, 0x65, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x53, 0x74, - 0x72, 0x69, 0x6e, 0x67, 0x12, 0x30, 0x0a, 0x14, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x66, 0x75, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x12, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x75, 0x73, 0x68, 0x5f, 0x73, - 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, 0x75, 0x73, 0x68, 0x53, 0x61, - 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x6f, - 0x6e, 0x66, 0x12, 0x24, 0x0a, 0x0c, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x79, - 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x73, 0x61, - 0x74, 0x50, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, - 0x61, 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, - 0x74, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, - 0x73, 0x61, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x48, 0x74, - 0x6c, 0x63, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, - 0x5f, 0x63, 0x73, 0x76, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x73, 0x76, 0x44, 0x65, 0x6c, 0x61, 0x79, - 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x73, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x73, 0x12, 0x2b, 0x0a, - 0x11, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x5f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, - 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x55, - 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6c, - 0x6f, 0x73, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, - 0x35, 0x0a, 0x0c, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x68, 0x69, 0x6d, 0x18, - 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x68, 0x69, 0x6d, 0x52, 0x0b, 0x66, 0x75, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x53, 0x68, 0x69, 0x6d, 0x12, 0x43, 0x0a, 0x1f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, - 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x69, 0x6e, 0x5f, 0x66, 0x6c, - 0x69, 0x67, 0x68, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x1a, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4d, 0x61, 0x78, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x49, - 0x6e, 0x46, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, - 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x73, 0x18, - 0x10, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4d, 0x61, 0x78, - 0x48, 0x74, 0x6c, 0x63, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x6c, 0x6f, 0x63, - 0x61, 0x6c, 0x5f, 0x63, 0x73, 0x76, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6d, 0x61, - 0x78, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x43, 0x73, 0x76, 0x12, 0x3e, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x12, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x7a, 0x65, 0x72, - 0x6f, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x7a, 0x65, - 0x72, 0x6f, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x69, 0x64, 0x5f, 0x61, - 0x6c, 0x69, 0x61, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x63, 0x69, 0x64, - 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, - 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, - 0x12, 0x19, 0x0a, 0x08, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x16, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x07, 0x66, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x75, - 0x73, 0x65, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x42, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x12, 0x20, 0x0a, - 0x0c, 0x75, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x18, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x46, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x12, - 0x35, 0x0a, 0x17, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x72, - 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x14, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x53, 0x61, 0x74, 0x22, 0xf3, 0x01, 0x0a, 0x10, 0x4f, 0x70, 0x65, 0x6e, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x39, 0x0a, 0x0c, 0x63, - 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x50, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x37, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x6f, - 0x70, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4f, 0x70, 0x65, 0x6e, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x4f, 0x70, 0x65, 0x6e, 0x12, - 0x39, 0x0a, 0x09, 0x70, 0x73, 0x62, 0x74, 0x5f, 0x66, 0x75, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x79, - 0x46, 0x6f, 0x72, 0x50, 0x73, 0x62, 0x74, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, - 0x52, 0x08, 0x70, 0x73, 0x62, 0x74, 0x46, 0x75, 0x6e, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, - 0x49, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x48, 0x0a, 0x0a, - 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x6b, 0x65, - 0x79, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, - 0x6b, 0x65, 0x79, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x65, 0x79, - 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6b, 0x65, - 0x79, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x5f, 0x0a, 0x0d, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x72, 0x61, 0x77, 0x5f, 0x6b, - 0x65, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, - 0x72, 0x61, 0x77, 0x4b, 0x65, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x07, 0x6b, - 0x65, 0x79, 0x5f, 0x6c, 0x6f, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x52, - 0x06, 0x6b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x22, 0xf0, 0x01, 0x0a, 0x0d, 0x43, 0x68, 0x61, 0x6e, - 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x68, 0x69, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6d, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x61, 0x6d, 0x74, 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, - 0x31, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x44, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x4b, - 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x65, - 0x79, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x70, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x68, 0x61, - 0x77, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, - 0x74, 0x68, 0x61, 0x77, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x6e, 0x0a, 0x08, 0x50, 0x73, - 0x62, 0x74, 0x53, 0x68, 0x69, 0x6d, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0d, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x1b, - 0x0a, 0x09, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x08, 0x62, 0x61, 0x73, 0x65, 0x50, 0x73, 0x62, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, - 0x6f, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x09, 0x6e, 0x6f, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x22, 0x85, 0x01, 0x0a, 0x0b, 0x46, - 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x68, 0x69, 0x6d, 0x12, 0x3e, 0x0a, 0x0f, 0x63, 0x68, - 0x61, 0x6e, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x73, 0x68, 0x69, 0x6d, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, - 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x68, 0x69, 0x6d, 0x48, 0x00, 0x52, 0x0d, 0x63, 0x68, 0x61, - 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x68, 0x69, 0x6d, 0x12, 0x2e, 0x0a, 0x09, 0x70, 0x73, - 0x62, 0x74, 0x5f, 0x73, 0x68, 0x69, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x73, 0x62, 0x74, 0x53, 0x68, 0x69, 0x6d, 0x48, 0x00, - 0x52, 0x08, 0x70, 0x73, 0x62, 0x74, 0x53, 0x68, 0x69, 0x6d, 0x42, 0x06, 0x0a, 0x04, 0x73, 0x68, - 0x69, 0x6d, 0x22, 0x3b, 0x0a, 0x11, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x68, 0x69, - 0x6d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0d, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x22, - 0x81, 0x01, 0x0a, 0x11, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x73, 0x62, 0x74, 0x56, - 0x65, 0x72, 0x69, 0x66, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x5f, - 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x66, 0x75, 0x6e, 0x64, - 0x65, 0x64, 0x50, 0x73, 0x62, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0d, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x23, - 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x69, 0x6e, 0x61, 0x6c, - 0x69, 0x7a, 0x65, 0x22, 0x80, 0x01, 0x0a, 0x13, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, - 0x73, 0x62, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, - 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x73, 0x62, 0x74, 0x12, 0x26, 0x0a, 0x0f, - 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, - 0x61, 0x6e, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x61, - 0x77, 0x5f, 0x74, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x66, 0x69, 0x6e, 0x61, - 0x6c, 0x52, 0x61, 0x77, 0x54, 0x78, 0x22, 0x99, 0x02, 0x0a, 0x14, 0x46, 0x75, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x67, 0x12, - 0x39, 0x0a, 0x0d, 0x73, 0x68, 0x69, 0x6d, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, - 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x68, 0x69, 0x6d, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x68, - 0x69, 0x6d, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x3b, 0x0a, 0x0b, 0x73, 0x68, - 0x69, 0x6d, 0x5f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, - 0x68, 0x69, 0x6d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x48, 0x00, 0x52, 0x0a, 0x73, 0x68, 0x69, - 0x6d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x12, 0x3b, 0x0a, 0x0b, 0x70, 0x73, 0x62, 0x74, 0x5f, - 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x73, 0x62, 0x74, - 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x48, 0x00, 0x52, 0x0a, 0x70, 0x73, 0x62, 0x74, 0x56, 0x65, - 0x72, 0x69, 0x66, 0x79, 0x12, 0x41, 0x0a, 0x0d, 0x70, 0x73, 0x62, 0x74, 0x5f, 0x66, 0x69, 0x6e, - 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x73, 0x62, 0x74, 0x46, - 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x70, 0x73, 0x62, 0x74, 0x46, - 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x74, 0x72, 0x69, 0x67, 0x67, - 0x65, 0x72, 0x22, 0x16, 0x0a, 0x14, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x53, 0x74, 0x65, 0x70, 0x52, 0x65, 0x73, 0x70, 0x22, 0xcc, 0x01, 0x0a, 0x0b, 0x50, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x54, 0x4c, 0x43, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, - 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e, - 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, - 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x6d, 0x61, - 0x74, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x6d, 0x61, 0x74, 0x75, 0x72, 0x69, 0x74, 0x79, 0x48, 0x65, 0x69, - 0x67, 0x68, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x74, 0x69, - 0x6c, 0x5f, 0x6d, 0x61, 0x74, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x11, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x54, 0x69, 0x6c, 0x4d, 0x61, 0x74, 0x75, 0x72, - 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x22, 0x18, 0x0a, 0x16, 0x50, 0x65, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x22, 0xf3, 0x12, 0x0a, 0x17, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x2e, 0x0a, 0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6c, 0x69, 0x6d, 0x62, 0x6f, 0x5f, 0x62, - 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x4c, 0x69, 0x6d, 0x62, 0x6f, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, - 0x65, 0x0a, 0x15, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x5f, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, - 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, 0x2e, 0x50, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x52, 0x13, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x6a, 0x0a, 0x18, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 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, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x02, 0x18, 0x01, 0x52, 0x16, 0x70, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x43, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x73, 0x12, 0x76, 0x0a, 0x1e, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x6f, - 0x72, 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 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, 0x2e, 0x46, 0x6f, 0x72, 0x63, 0x65, - 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x1b, 0x70, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x43, 0x6c, 0x6f, 0x73, 0x69, - 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x68, 0x0a, 0x16, 0x77, 0x61, - 0x69, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 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, 0x2e, 0x57, 0x61, 0x69, 0x74, 0x69, - 0x6e, 0x67, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x14, - 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x73, 0x1a, 0x9f, 0x04, 0x0a, 0x0e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x72, 0x65, 0x6d, 0x6f, 0x74, - 0x65, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0d, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x75, 0x62, 0x12, - 0x23, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 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, 0x23, 0x0a, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x42, 0x61, - 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, - 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x72, - 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x16, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x6c, 0x6f, - 0x63, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x53, 0x61, - 0x74, 0x12, 0x35, 0x0a, 0x17, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, - 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x14, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x52, 0x65, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x53, 0x61, 0x74, 0x12, 0x2e, 0x0a, 0x09, 0x69, 0x6e, 0x69, 0x74, - 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x09, 0x69, - 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x3e, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x36, 0x0a, 0x17, 0x6e, 0x75, 0x6d, 0x5f, - 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, - 0x67, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x6e, 0x75, 0x6d, 0x46, 0x6f, - 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, - 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, - 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x68, 0x61, - 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, - 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, - 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x1a, 0xc5, 0x01, 0x0a, 0x12, 0x50, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x47, 0x0a, - 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, - 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, 0x2e, 0x50, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x07, 0x63, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x5f, 0x66, 0x65, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x46, 0x65, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, - 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1c, 0x0a, 0x0a, 0x66, 0x65, - 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x6b, 0x77, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, - 0x66, 0x65, 0x65, 0x50, 0x65, 0x72, 0x4b, 0x77, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x1a, 0xf4, - 0x01, 0x0a, 0x13, 0x57, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x47, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 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, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, - 0x23, 0x0a, 0x0d, 0x6c, 0x69, 0x6d, 0x62, 0x6f, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x69, 0x6d, 0x62, 0x6f, 0x42, 0x61, 0x6c, - 0x61, 0x6e, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, - 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 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, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, - 0x74, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, - 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, - 0x67, 0x54, 0x78, 0x69, 0x64, 0x1a, 0xa3, 0x02, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x74, - 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x54, 0x78, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x74, - 0x78, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x6d, 0x6f, 0x74, - 0x65, 0x54, 0x78, 0x69, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, - 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x54, 0x78, 0x69, 0x64, 0x12, 0x2f, 0x0a, 0x14, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x63, - 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x11, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x46, 0x65, 0x65, 0x53, 0x61, 0x74, 0x12, 0x31, 0x0a, 0x15, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, - 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x46, 0x65, 0x65, 0x53, 0x61, 0x74, 0x12, 0x40, 0x0a, 0x1d, 0x72, 0x65, 0x6d, - 0x6f, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x19, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, - 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x46, 0x65, 0x65, 0x53, 0x61, 0x74, 0x1a, 0x7b, 0x0a, 0x0d, 0x43, - 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x47, 0x0a, 0x07, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 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, 0x2e, 0x50, 0x65, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x07, 0x63, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, - 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x6f, - 0x73, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x69, 0x64, 0x1a, 0xee, 0x03, 0x0a, 0x12, 0x46, 0x6f, 0x72, - 0x63, 0x65, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, - 0x47, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2d, 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, - 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, - 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x6f, 0x73, - 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x63, 0x6c, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x69, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x6c, - 0x69, 0x6d, 0x62, 0x6f, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x69, 0x6d, 0x62, 0x6f, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, - 0x12, 0x27, 0x0a, 0x0f, 0x6d, 0x61, 0x74, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x68, 0x65, 0x69, - 0x67, 0x68, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x6d, 0x61, 0x74, 0x75, 0x72, - 0x69, 0x74, 0x79, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x73, 0x5f, 0x74, 0x69, 0x6c, 0x5f, 0x6d, 0x61, 0x74, 0x75, 0x72, 0x69, 0x74, 0x79, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x54, 0x69, - 0x6c, 0x4d, 0x61, 0x74, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x63, - 0x6f, 0x76, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x65, 0x64, 0x42, - 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x37, 0x0a, 0x0d, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x54, 0x4c, - 0x43, 0x52, 0x0c, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x74, 0x6c, 0x63, 0x73, 0x12, - 0x55, 0x0a, 0x06, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x3d, 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, 0x2e, - 0x46, 0x6f, 0x72, 0x63, 0x65, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x2e, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x06, - 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x22, 0x31, 0x0a, 0x0b, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x49, 0x4d, 0x42, 0x4f, 0x10, 0x00, - 0x12, 0x0d, 0x0a, 0x09, 0x52, 0x45, 0x43, 0x4f, 0x56, 0x45, 0x52, 0x45, 0x44, 0x10, 0x01, 0x12, - 0x08, 0x0a, 0x04, 0x4c, 0x4f, 0x53, 0x54, 0x10, 0x02, 0x22, 0x1a, 0x0a, 0x18, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xff, 0x04, 0x0a, 0x12, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x33, 0x0a, 0x0c, - 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x48, 0x00, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x12, 0x43, 0x0a, 0x0e, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x75, - 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x48, 0x00, 0x52, 0x0d, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x3c, 0x0a, 0x0e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, - 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x03, 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, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x40, 0x0a, 0x10, 0x69, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, - 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 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, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x48, 0x0a, 0x14, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x12, 0x70, 0x65, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x12, 0x4b, 0x0a, 0x16, 0x66, 0x75, 0x6c, 0x6c, 0x79, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, - 0x65, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x07, 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, 0x14, 0x66, 0x75, 0x6c, 0x6c, 0x79, 0x52, 0x65, - 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x38, 0x0a, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 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, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x92, 0x01, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x4f, 0x50, 0x45, 0x4e, 0x5f, 0x43, - 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4c, 0x4f, 0x53, - 0x45, 0x44, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, - 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x10, 0x02, - 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5f, 0x43, 0x48, 0x41, - 0x4e, 0x4e, 0x45, 0x4c, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, - 0x47, 0x5f, 0x4f, 0x50, 0x45, 0x4e, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x10, 0x04, - 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x55, 0x4c, 0x4c, 0x59, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, - 0x45, 0x44, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x10, 0x05, 0x42, 0x09, 0x0a, 0x07, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x74, 0x0a, 0x14, 0x57, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, - 0x2b, 0x0a, 0x11, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x6c, - 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x72, 0x6d, 0x65, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x2f, 0x0a, 0x13, - 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, - 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x75, 0x6e, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x16, 0x0a, - 0x14, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xbd, 0x03, 0x0a, 0x15, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x23, 0x0a, 0x0d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x61, 0x6c, - 0x61, 0x6e, 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, - 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, - 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, - 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, - 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, - 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x6c, - 0x61, 0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x6b, - 0x65, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x3f, 0x0a, 0x1c, 0x72, 0x65, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x61, 0x6e, - 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x19, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, - 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x12, 0x59, 0x0a, 0x0f, 0x61, 0x63, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x30, 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, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x61, - 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x1a, 0x5e, 0x0a, 0x13, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 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, 0x31, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x2e, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x10, 0x0a, 0x03, 0x73, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x73, 0x61, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x04, 0x6d, 0x73, 0x61, 0x74, 0x22, 0x17, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x80, - 0x04, 0x0a, 0x16, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x07, 0x62, 0x61, 0x6c, - 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, - 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x14, 0x70, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x12, 0x70, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x4f, 0x70, 0x65, 0x6e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x32, 0x0a, - 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, - 0x65, 0x12, 0x34, 0x0a, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x62, 0x61, 0x6c, 0x61, - 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x0d, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, - 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x45, 0x0a, 0x17, 0x75, 0x6e, 0x73, 0x65, 0x74, - 0x74, 0x6c, 0x65, 0x64, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, - 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x15, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x74, 0x6c, - 0x65, 0x64, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x47, - 0x0a, 0x18, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x6d, 0x6f, - 0x74, 0x65, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, - 0x16, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, - 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x4a, 0x0a, 0x1a, 0x70, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x62, 0x61, - 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x17, 0x70, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x4f, 0x70, 0x65, 0x6e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x42, 0x61, 0x6c, 0x61, - 0x6e, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x1b, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6f, - 0x70, 0x65, 0x6e, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, - 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x18, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x4f, 0x70, 0x65, 0x6e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, - 0x65, 0x22, 0xcb, 0x06, 0x0a, 0x12, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6d, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, - 0x61, 0x6d, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x6d, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, - 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x61, 0x6d, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x28, - 0x0a, 0x10, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x64, 0x65, 0x6c, - 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x43, - 0x6c, 0x74, 0x76, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x2c, 0x0a, 0x09, 0x66, 0x65, 0x65, 0x5f, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x08, 0x66, 0x65, - 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, - 0x64, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x69, - 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x0d, 0x69, - 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x65, 0x64, 0x67, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x64, 0x67, 0x65, 0x4c, - 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0c, 0x69, 0x67, 0x6e, 0x6f, - 0x72, 0x65, 0x64, 0x45, 0x64, 0x67, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x2e, - 0x0a, 0x13, 0x75, 0x73, 0x65, 0x5f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x75, 0x73, 0x65, - 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x34, - 0x0a, 0x0d, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x73, 0x18, - 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, - 0x64, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x50, - 0x61, 0x69, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x63, 0x6c, 0x74, 0x76, 0x4c, 0x69, - 0x6d, 0x69, 0x74, 0x12, 0x60, 0x0a, 0x13, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x75, 0x73, 0x74, - 0x6f, 0x6d, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x30, 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, 0x2e, 0x44, 0x65, 0x73, 0x74, - 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x11, 0x64, 0x65, 0x73, 0x74, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x2c, 0x0a, 0x10, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, - 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x04, 0x42, - 0x02, 0x30, 0x01, 0x52, 0x0e, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, - 0x6e, 0x49, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, - 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x6c, 0x61, - 0x73, 0x74, 0x48, 0x6f, 0x70, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x0b, 0x72, - 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, + 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, + 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, 0xc3, 0x09, 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, 0x36, - 0x0a, 0x0d, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, - 0x11, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x69, 0x74, 0x52, 0x0c, 0x64, 0x65, 0x73, 0x74, 0x46, 0x65, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x70, - 0x72, 0x65, 0x66, 0x18, 0x12, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x50, - 0x72, 0x65, 0x66, 0x1a, 0x44, 0x0a, 0x16, 0x44, 0x65, 0x73, 0x74, 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, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, - 0x2e, 0x0a, 0x08, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x61, 0x69, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x66, - 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, - 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x74, 0x6f, 0x22, - 0x5d, 0x0a, 0x0b, 0x45, 0x64, 0x67, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 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, 0x2b, 0x0a, 0x11, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, - 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x64, 0x69, - 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x22, 0x5e, - 0x0a, 0x13, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, - 0x75, 0x74, 0x65, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x73, - 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x01, 0x52, 0x0b, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x72, 0x6f, 0x62, 0x22, 0xb1, - 0x04, 0x0a, 0x03, 0x48, 0x6f, 0x70, 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, 0x27, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x63, 0x61, 0x70, 0x61, - 0x63, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0c, - 0x63, 0x68, 0x61, 0x6e, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x28, 0x0a, 0x0e, - 0x61, 0x6d, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0c, 0x61, 0x6d, 0x74, 0x54, 0x6f, 0x46, - 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x03, 0x66, 0x65, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x65, 0x78, - 0x70, 0x69, 0x72, 0x79, 0x12, 0x2d, 0x0a, 0x13, 0x61, 0x6d, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x66, - 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x10, 0x61, 0x6d, 0x74, 0x54, 0x6f, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x4d, - 0x73, 0x61, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x65, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x66, 0x65, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x17, - 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0b, 0x74, 0x6c, 0x76, 0x5f, 0x70, - 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, - 0x52, 0x0a, 0x74, 0x6c, 0x76, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x2f, 0x0a, 0x0a, - 0x6d, 0x70, 0x70, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x10, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x50, 0x50, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x52, 0x09, 0x6d, 0x70, 0x70, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x2f, 0x0a, - 0x0a, 0x61, 0x6d, 0x70, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x4d, 0x50, 0x52, 0x65, 0x63, - 0x6f, 0x72, 0x64, 0x52, 0x09, 0x61, 0x6d, 0x70, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x44, - 0x0a, 0x0e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, - 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x48, - 0x6f, 0x70, 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, 0x1a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 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, 0x54, 0x0a, 0x09, 0x4d, 0x50, 0x50, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 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, 0x24, 0x0a, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6d, 0x74, 0x5f, - 0x6d, 0x73, 0x61, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x6f, 0x74, 0x61, - 0x6c, 0x41, 0x6d, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x22, 0x62, 0x0a, 0x09, 0x41, 0x4d, 0x50, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 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, 0x22, 0xe1, 0x01, 0x0a, - 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, - 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x12, 0x21, - 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x66, 0x65, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x46, 0x65, 0x65, - 0x73, 0x12, 0x1f, 0x0a, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6d, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x08, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, - 0x6d, 0x74, 0x12, 0x1e, 0x0a, 0x04, 0x68, 0x6f, 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x0a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x6f, 0x70, 0x52, 0x04, 0x68, 0x6f, - 0x70, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x66, 0x65, 0x65, 0x73, - 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x6f, 0x74, - 0x61, 0x6c, 0x46, 0x65, 0x65, 0x73, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6d, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6d, 0x74, 0x4d, 0x73, 0x61, 0x74, - 0x22, 0x55, 0x0a, 0x0f, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x10, - 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x22, 0xae, 0x01, 0x0a, 0x08, 0x4e, 0x6f, 0x64, 0x65, - 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x28, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, - 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, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x21, - 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x61, 0x70, 0x61, 0x63, - 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x6f, 0x74, 0x61, 0x6c, - 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x2e, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x04, 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, 0x08, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x22, 0xc6, 0x03, 0x0a, 0x0d, 0x4c, 0x69, 0x67, - 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x61, - 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x70, - 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x75, - 0x62, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x30, 0x0a, 0x09, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x04, 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, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, - 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, - 0x6f, 0x72, 0x12, 0x3e, 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x06, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x67, - 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 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, 0x4e, 0x0a, 0x0e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x65, 0x63, - 0x6f, 0x72, 0x64, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, + 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, 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, 0xfc, 0x03, 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, 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, - 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, 0x3b, 0x0a, 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, 0x98, - 0x03, 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, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x69, 0x6e, 0x5f, - 0x68, 0x74, 0x6c, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x69, 0x6e, 0x48, - 0x74, 0x6c, 0x63, 0x12, 0x22, 0x0a, 0x0d, 0x66, 0x65, 0x65, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, - 0x6d, 0x73, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x66, 0x65, 0x65, 0x42, - 0x61, 0x73, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x2d, 0x0a, 0x13, 0x66, 0x65, 0x65, 0x5f, 0x72, - 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x66, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x6c, - 0x6c, 0x69, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, - 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, - 0x65, 0x64, 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, 0x1f, 0x0a, 0x0b, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6c, 0x61, 0x73, - 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x4e, 0x0a, 0x0e, 0x63, 0x75, 0x73, 0x74, 0x6f, - 0x6d, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x27, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 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, 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, 0x2e, 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, 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, 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, 0xc3, - 0x09, 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, 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, 0xfc, 0x03, 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, 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, + 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, 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, 0x8a, 0x05, 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, 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, 0x8a, 0x05, 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, 0x22, 0x46, 0x0a, 0x0d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x10, 0x00, 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, 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, 0x78, 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, 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, + 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, + 0x22, 0x46, 0x0a, 0x0d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 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, 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, 0x78, 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, 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, 0xb0, 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, 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, 0xb3, 0x01, 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, 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, 0xf6, 0x02, 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, 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, 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, 0xb0, 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, 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, 0xb3, 0x01, 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, 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, 0xf6, 0x02, 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, 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, + 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, 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, 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, 0xb0, 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, 0xef, 0x05, 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, 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, - 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, 0x78, - 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, 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, 0xd9, 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, + 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, 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, 0xb0, 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, 0xef, 0x05, 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, 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, 0x2a, 0xcf, 0x04, 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, 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, 0xf0, 0x26, 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, 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, - 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, + 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, 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, 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, 0x78, 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, 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, 0xd9, 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, + 0x2a, 0xcf, 0x04, 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, 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, 0xf0, 0x26, 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, 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, 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, - 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, - 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, + 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, 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, + 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, 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, - 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, - 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, + 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, 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, 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, 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, + 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, 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, - 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, 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, 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 ( diff --git a/lnrpc/lightning.proto b/lnrpc/lightning.proto index c27e35e28..88b8d73d2 100644 --- a/lnrpc/lightning.proto +++ b/lnrpc/lightning.proto @@ -1542,6 +1542,9 @@ message Channel { // The configured alias name of our peer. string peer_alias = 34; + + // This is the peer SCID alias. + uint64 peer_scid_alias = 35 [jstype = JS_STRING]; } message ListChannelsRequest { diff --git a/lnrpc/lightning.swagger.json b/lnrpc/lightning.swagger.json index 13e3611d9..6ed3cbc92 100644 --- a/lnrpc/lightning.swagger.json +++ b/lnrpc/lightning.swagger.json @@ -3568,6 +3568,11 @@ "peer_alias": { "type": "string", "description": "The configured alias name of our peer." + }, + "peer_scid_alias": { + "type": "string", + "format": "uint64", + "description": "This is the peer SCID alias." } } }, diff --git a/rpcserver.go b/rpcserver.go index 9dac0b977..c1d1b7b7c 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -4097,6 +4097,7 @@ func createRPCOpenChannel(r *rpcServer, dbChannel *channeldb.OpenChannel, nodePub := dbChannel.IdentityPub nodeID := hex.EncodeToString(nodePub.SerializeCompressed()) chanPoint := dbChannel.FundingOutpoint + chanID := lnwire.NewChanIDFromOutPoint(&chanPoint) // As this is required for display purposes, we'll calculate // the weight of the commitment transaction. We also add on the @@ -4132,6 +4133,10 @@ func createRPCOpenChannel(r *rpcServer, dbChannel *channeldb.OpenChannel, // Fetch the set of aliases for the channel. channelAliases := r.server.aliasMgr.GetAliases(dbScid) + // Fetch the peer alias. If one does not exist, errNoPeerAlias + // is returned and peerScidAlias will be an empty ShortChannelID. + peerScidAlias, _ := r.server.aliasMgr.GetPeerAlias(chanID) + channel := &lnrpc.Channel{ Active: isActive, Private: isPrivate(dbChannel), @@ -4160,6 +4165,7 @@ func createRPCOpenChannel(r *rpcServer, dbChannel *channeldb.OpenChannel, &dbChannel.RemoteChanCfg, ), AliasScids: make([]uint64, 0, len(channelAliases)), + PeerScidAlias: peerScidAlias.ToUint64(), ZeroConf: dbChannel.IsZeroConf(), ZeroConfConfirmedScid: dbChannel.ZeroConfRealScid().ToUint64(), // TODO: remove the following deprecated fields