From 7cc6ef2ffd27d497d757ff6eb7f7c8c6b1047d48 Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Fri, 10 Jun 2022 16:51:26 +0200 Subject: [PATCH 01/17] mod: bump btcd to latest tagged version --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 36b634c..7982039 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module github.com/lightninglabs/loop require ( - github.com/btcsuite/btcd v0.22.0-beta.0.20220413172512-bf64c8bdbbbf + github.com/btcsuite/btcd v0.23.1 github.com/btcsuite/btcd/btcec/v2 v2.2.0 github.com/btcsuite/btcd/btcutil v1.1.1 github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 diff --git a/go.sum b/go.sum index 34aaa67..cbf7080 100644 --- a/go.sum +++ b/go.sum @@ -75,8 +75,9 @@ github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tj github.com/btcsuite/btcd v0.22.0-beta.0.20220204213055-eaf0459ff879/go.mod h1:osu7EoKiL36UThEgzYPqdRaxeo0NU8VoXqgcnwpey0g= github.com/btcsuite/btcd v0.22.0-beta.0.20220207191057-4dc4ff7963b4/go.mod h1:7alexyj/lHlOtr2PJK7L/+HDJZpcGDn/pAU98r7DY08= github.com/btcsuite/btcd v0.22.0-beta.0.20220316175102-8d5c75c28923/go.mod h1:taIcYprAW2g6Z9S0gGUxyR+zDwimyDMK5ePOX+iJ2ds= -github.com/btcsuite/btcd v0.22.0-beta.0.20220413172512-bf64c8bdbbbf h1:8lTakMpAAOKTe60bNhiEjUDtcZAlrst2MF49ekuA9yI= github.com/btcsuite/btcd v0.22.0-beta.0.20220413172512-bf64c8bdbbbf/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= +github.com/btcsuite/btcd v0.23.1 h1:IB8cVQcC2X5mHbnfirLG5IZnkWYNTPlLZVrxUYSotbE= +github.com/btcsuite/btcd v0.23.1/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.1/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= From 9b37d744a008bd248e412fb0b03e96c09d38aa9b Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Sun, 24 Apr 2022 22:29:13 +0200 Subject: [PATCH 02/17] multi: add ProtocolVersion_HTLC_V3 --- go.mod | 3 + go.sum | 2 - loopdb/protocol_version.go | 9 +- loopdb/protocol_version_test.go | 2 + swap.go | 24 ++- swapserverrpc/server.pb.go | 289 ++++++++++++++++---------------- swapserverrpc/server.proto | 3 + 7 files changed, 178 insertions(+), 154 deletions(-) diff --git a/go.mod b/go.mod index 7982039..6162bcf 100644 --- a/go.mod +++ b/go.mod @@ -32,4 +32,7 @@ require ( gopkg.in/macaroon.v2 v2.1.0 ) +// TODO(bhandras): remove when the next swapserverrpc is tagged. +replace github.com/lightninglabs/loop/swapserverrpc => ./swapserverrpc + go 1.16 diff --git a/go.sum b/go.sum index cbf7080..ac0430f 100644 --- a/go.sum +++ b/go.sum @@ -485,8 +485,6 @@ github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2/go.mod h1:ant github.com/lightninglabs/lndclient v0.15.0-0/go.mod h1:ORS/YFe9hAXlzN/Uj+gvTmrnXEml6yD6dWwzCjpTJyQ= github.com/lightninglabs/lndclient v0.15.0-6 h1:wFNmHtZSV54FzPZsPOX3/rwRIRUlLJLvWB760hzPCag= github.com/lightninglabs/lndclient v0.15.0-6/go.mod h1:bQrzrVGpBuaM2c6mapsAdbnhsXJydOU6gFAKvevEzgo= -github.com/lightninglabs/loop/swapserverrpc v1.0.1 h1:z99vrpRgQ834FC/C0Qx8HLtE0RX0WBDa1gAu7yOGPsg= -github.com/lightninglabs/loop/swapserverrpc v1.0.1/go.mod h1:imy1/sqnb70EEyBKMo4pHwwLBPW8uYahWZ8s+1Xcq1o= github.com/lightninglabs/neutrino v0.13.2/go.mod h1:Cv/v8oHiPhuGiGvGgO+rIMhwCwEdsQFu6as840i2afw= github.com/lightninglabs/neutrino v0.14.1 h1:ALFckeS3CPmWZmX75vxZaWvz2TUebuASH+CR4cqVo18= github.com/lightninglabs/neutrino v0.14.1/go.mod h1:SV9ccrw2m6t6UvJX8xB//W0Dv+LEwMTbjg4V/Fb5KwU= diff --git a/loopdb/protocol_version.go b/loopdb/protocol_version.go index 202028c..0d93266 100644 --- a/loopdb/protocol_version.go +++ b/loopdb/protocol_version.go @@ -51,13 +51,17 @@ const ( // in order to enhance off-chain payments corresponding to a swap. ProtocolVersionRoutingPlugin = 9 + // ProtocolVersionHtlcV3 indicates that the client will now use the new + // HTLC v3 (P2TR) script for swaps. + ProtocolVersionHtlcV3 = 10 + // ProtocolVersionUnrecorded is set for swaps were created before we // started saving protocol version with swaps. ProtocolVersionUnrecorded ProtocolVersion = math.MaxUint32 // CurrentRPCProtocolVersion defines the version of the RPC protocol // that is currently supported by the loop client. - CurrentRPCProtocolVersion = looprpc.ProtocolVersion_ROUTING_PLUGIN + CurrentRPCProtocolVersion = looprpc.ProtocolVersion_HTLC_V3 // CurrentInternalProtocolVersion defines the RPC current protocol in // the internal representation. @@ -102,6 +106,9 @@ func (p ProtocolVersion) String() string { case ProtocolVersionRoutingPlugin: return "Routing Plugin" + case ProtocolVersionHtlcV3: + return "HTLC V3" + default: return "Unknown" } diff --git a/loopdb/protocol_version_test.go b/loopdb/protocol_version_test.go index bcaa913..cb7d3b2 100644 --- a/loopdb/protocol_version_test.go +++ b/loopdb/protocol_version_test.go @@ -24,6 +24,7 @@ func TestProtocolVersionSanity(t *testing.T) { ProtocolVersionLoopOutCancel, ProtocolVersionProbe, ProtocolVersionRoutingPlugin, + ProtocolVersionHtlcV3, } rpcVersions := [...]looprpc.ProtocolVersion{ @@ -37,6 +38,7 @@ func TestProtocolVersionSanity(t *testing.T) { looprpc.ProtocolVersion_LOOP_OUT_CANCEL, looprpc.ProtocolVersion_PROBE, looprpc.ProtocolVersion_ROUTING_PLUGIN, + looprpc.ProtocolVersion_HTLC_V3, } require.Equal(t, len(versions), len(rpcVersions)) diff --git a/swap.go b/swap.go index 193bdde..bfb034c 100644 --- a/swap.go +++ b/swap.go @@ -53,18 +53,24 @@ func newSwapKit(hash lntypes.Hash, swapType swap.Type, cfg *swapConfig, func GetHtlcScriptVersion( protocolVersion loopdb.ProtocolVersion) swap.ScriptVersion { - if protocolVersion != loopdb.ProtocolVersionUnrecorded && - protocolVersion >= loopdb.ProtocolVersionHtlcV2 { - - // Use HTLC v2 script only if we know the swap was initiated - // with a client that supports HTLC v2. Unrecorded protocol - // version implies that there was no protocol version stored - // along side a serialized swap that we're resuming in which - // case the swap was initiated with HTLC v1 script. + // Unrecorded protocol version implies that there was no protocol + // version stored along side a serialized swap that we're resuming in + // which case the swap was initiated with HTLC v1 script. + if protocolVersion == loopdb.ProtocolVersionUnrecorded { + return swap.HtlcV1 + } + + // If the swap was initiated before we had our v2 script, use v1. + if protocolVersion < loopdb.ProtocolVersionHtlcV2 { + return swap.HtlcV1 + } + + // If the swap was initiated before we had our v3 script, use v2. + if protocolVersion < loopdb.ProtocolVersionHtlcV3 { return swap.HtlcV2 } - return swap.HtlcV1 + return swap.HtlcV3 } // getHtlc composes and returns the on-chain swap script. diff --git a/swapserverrpc/server.pb.go b/swapserverrpc/server.pb.go index 3b84e02..fac9999 100644 --- a/swapserverrpc/server.pb.go +++ b/swapserverrpc/server.pb.go @@ -62,21 +62,24 @@ const ( // The client may ask the server to use a custom routing helper plugin in // order to enhance off-chain payments corresponding to a swap. ProtocolVersion_ROUTING_PLUGIN ProtocolVersion = 9 + // The client will use the new v3 (taproot) HTLC scripts. + ProtocolVersion_HTLC_V3 ProtocolVersion = 10 ) // Enum value maps for ProtocolVersion. var ( ProtocolVersion_name = map[int32]string{ - 0: "LEGACY", - 1: "MULTI_LOOP_OUT", - 2: "NATIVE_SEGWIT_LOOP_IN", - 3: "PREIMAGE_PUSH_LOOP_OUT", - 4: "USER_EXPIRY_LOOP_OUT", - 5: "HTLC_V2", - 6: "MULTI_LOOP_IN", - 7: "LOOP_OUT_CANCEL", - 8: "PROBE", - 9: "ROUTING_PLUGIN", + 0: "LEGACY", + 1: "MULTI_LOOP_OUT", + 2: "NATIVE_SEGWIT_LOOP_IN", + 3: "PREIMAGE_PUSH_LOOP_OUT", + 4: "USER_EXPIRY_LOOP_OUT", + 5: "HTLC_V2", + 6: "MULTI_LOOP_IN", + 7: "LOOP_OUT_CANCEL", + 8: "PROBE", + 9: "ROUTING_PLUGIN", + 10: "HTLC_V3", } ProtocolVersion_value = map[string]int32{ "LEGACY": 0, @@ -89,6 +92,7 @@ var ( "LOOP_OUT_CANCEL": 7, "PROBE": 8, "ROUTING_PLUGIN": 9, + "HTLC_V3": 10, } ) @@ -2524,7 +2528,7 @@ var file_server_proto_rawDesc = []byte{ 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x18, 0x0a, 0x16, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, - 0x65, 0x73, 0x2a, 0xd6, 0x01, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, + 0x65, 0x73, 0x2a, 0xe3, 0x01, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x45, 0x47, 0x41, 0x43, 0x59, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x4e, 0x41, 0x54, 0x49, 0x56, 0x45, @@ -2537,140 +2541,141 @@ var file_server_proto_rawDesc = []byte{ 0x4f, 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x06, 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x07, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x52, 0x4f, 0x42, 0x45, 0x10, 0x08, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x4f, 0x55, 0x54, 0x49, - 0x4e, 0x47, 0x5f, 0x50, 0x4c, 0x55, 0x47, 0x49, 0x4e, 0x10, 0x09, 0x2a, 0x9e, 0x04, 0x0a, 0x0f, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, - 0x14, 0x0a, 0x10, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, - 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, - 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x01, - 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, - 0x53, 0x53, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, - 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x12, - 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, - 0x5f, 0x4e, 0x4f, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x10, 0x04, 0x12, 0x25, 0x0a, 0x21, 0x53, 0x45, - 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x56, 0x41, - 0x4c, 0x49, 0x44, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x4d, 0x4f, 0x55, 0x4e, 0x54, 0x10, - 0x05, 0x12, 0x23, 0x0a, 0x1f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, - 0x45, 0x44, 0x5f, 0x4f, 0x46, 0x46, 0x5f, 0x43, 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, - 0x45, 0x4f, 0x55, 0x54, 0x10, 0x06, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, - 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, - 0x07, 0x12, 0x1f, 0x0a, 0x1b, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, - 0x45, 0x44, 0x5f, 0x53, 0x57, 0x41, 0x50, 0x5f, 0x44, 0x45, 0x41, 0x44, 0x4c, 0x49, 0x4e, 0x45, - 0x10, 0x08, 0x12, 0x22, 0x0a, 0x1e, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, - 0x4c, 0x45, 0x44, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x41, - 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x09, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, - 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, - 0x45, 0x44, 0x10, 0x0a, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x55, - 0x4e, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, - 0x45, 0x10, 0x0b, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x48, 0x54, - 0x4c, 0x43, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x0c, 0x12, 0x1f, - 0x0a, 0x1b, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, - 0x50, 0x52, 0x45, 0x50, 0x41, 0x59, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x0d, 0x12, - 0x20, 0x0a, 0x1c, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, - 0x5f, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, - 0x0e, 0x12, 0x27, 0x0a, 0x23, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, - 0x45, 0x44, 0x5f, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x50, 0x4c, 0x45, 0x5f, 0x53, 0x57, 0x41, 0x50, - 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x53, 0x10, 0x0f, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x45, - 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x49, 0x54, - 0x49, 0x41, 0x4c, 0x49, 0x5a, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x10, 0x2a, 0x4a, 0x0a, 0x10, - 0x52, 0x6f, 0x75, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, - 0x4e, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x52, 0x45, 0x50, 0x41, 0x59, 0x5f, 0x52, 0x4f, - 0x55, 0x54, 0x45, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, - 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x10, 0x02, 0x2a, 0xf1, 0x01, 0x0a, 0x14, 0x50, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, - 0x6e, 0x12, 0x1b, 0x0a, 0x17, 0x4c, 0x4e, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, - 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1e, - 0x0a, 0x1a, 0x4c, 0x4e, 0x44, 0x5f, 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, 0x1f, - 0x0a, 0x1b, 0x4c, 0x4e, 0x44, 0x5f, 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, - 0x1c, 0x0a, 0x18, 0x4c, 0x4e, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, - 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x30, 0x0a, - 0x2c, 0x4c, 0x4e, 0x44, 0x5f, 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, - 0x2b, 0x0a, 0x27, 0x4c, 0x4e, 0x44, 0x5f, 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, 0x27, 0x0a, 0x0d, - 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x08, 0x0a, - 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x4c, 0x4f, 0x57, 0x5f, 0x48, - 0x49, 0x47, 0x48, 0x10, 0x01, 0x32, 0x8a, 0x09, 0x0a, 0x0a, 0x53, 0x77, 0x61, 0x70, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x12, 0x4f, 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, - 0x65, 0x72, 0x6d, 0x73, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, - 0x54, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x4f, 0x0a, 0x0e, 0x4e, 0x65, 0x77, 0x4c, 0x6f, 0x6f, 0x70, - 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, 0x12, 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, - 0x74, 0x50, 0x75, 0x73, 0x68, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x29, 0x2e, - 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, - 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x50, 0x75, 0x73, 0x68, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, - 0x50, 0x75, 0x73, 0x68, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, - 0x75, 0x6f, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, - 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, - 0x65, 0x72, 0x6d, 0x73, 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x4e, 0x47, 0x5f, 0x50, 0x4c, 0x55, 0x47, 0x49, 0x4e, 0x10, 0x09, 0x12, 0x0b, 0x0a, 0x07, 0x48, + 0x54, 0x4c, 0x43, 0x5f, 0x56, 0x33, 0x10, 0x0a, 0x2a, 0x9e, 0x04, 0x0a, 0x0f, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x10, + 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x48, 0x54, 0x4c, + 0x43, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x01, 0x12, 0x12, 0x0a, + 0x0e, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, + 0x02, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, + 0x45, 0x44, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, + 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x4e, 0x4f, + 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x10, 0x04, 0x12, 0x25, 0x0a, 0x21, 0x53, 0x45, 0x52, 0x56, 0x45, + 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, + 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x4d, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x05, 0x12, 0x23, + 0x0a, 0x1f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, + 0x4f, 0x46, 0x46, 0x5f, 0x43, 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, + 0x54, 0x10, 0x06, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, + 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x07, 0x12, 0x1f, + 0x0a, 0x1b, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, + 0x53, 0x57, 0x41, 0x50, 0x5f, 0x44, 0x45, 0x41, 0x44, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x08, 0x12, + 0x22, 0x0a, 0x1e, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, + 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, + 0x4e, 0x10, 0x09, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x54, 0x49, + 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, + 0x0a, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x55, 0x4e, 0x45, 0x58, + 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x0b, + 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, + 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x0c, 0x12, 0x1f, 0x0a, 0x1b, 0x53, + 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x50, 0x52, 0x45, + 0x50, 0x41, 0x59, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x0d, 0x12, 0x20, 0x0a, 0x1c, + 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x49, 0x4e, + 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x0e, 0x12, 0x27, + 0x0a, 0x23, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, + 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x50, 0x4c, 0x45, 0x5f, 0x53, 0x57, 0x41, 0x50, 0x5f, 0x53, 0x43, + 0x52, 0x49, 0x50, 0x54, 0x53, 0x10, 0x0f, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x45, 0x52, 0x56, 0x45, + 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, + 0x49, 0x5a, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x10, 0x2a, 0x4a, 0x0a, 0x10, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x11, 0x0a, + 0x0d, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, + 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x52, 0x45, 0x50, 0x41, 0x59, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, + 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x52, 0x4f, + 0x55, 0x54, 0x45, 0x10, 0x02, 0x2a, 0xf1, 0x01, 0x0a, 0x14, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1b, + 0x0a, 0x17, 0x4c, 0x4e, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, + 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x4c, + 0x4e, 0x44, 0x5f, 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, 0x1f, 0x0a, 0x1b, 0x4c, + 0x4e, 0x44, 0x5f, 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, 0x1c, 0x0a, 0x18, + 0x4c, 0x4e, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, + 0x4f, 0x4e, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x30, 0x0a, 0x2c, 0x4c, 0x4e, + 0x44, 0x5f, 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, 0x2b, 0x0a, 0x27, + 0x4c, 0x4e, 0x44, 0x5f, 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, 0x27, 0x0a, 0x0d, 0x52, 0x6f, 0x75, + 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, + 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x4c, 0x4f, 0x57, 0x5f, 0x48, 0x49, 0x47, 0x48, + 0x10, 0x01, 0x32, 0x8a, 0x09, 0x0a, 0x0a, 0x53, 0x77, 0x61, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x12, 0x4f, 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, + 0x73, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, + 0x6d, 0x73, 0x12, 0x4f, 0x0a, 0x0e, 0x4e, 0x65, 0x77, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, + 0x53, 0x77, 0x61, 0x70, 0x12, 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x50, 0x75, + 0x73, 0x68, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x29, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, + 0x75, 0x74, 0x50, 0x75, 0x73, 0x68, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x50, 0x75, 0x73, + 0x68, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x4f, 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, + 0x65, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, + 0x74, 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, + 0x73, 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, 0x65, - 0x72, 0x6d, 0x73, 0x12, 0x4c, 0x0a, 0x0d, 0x4e, 0x65, 0x77, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, - 0x53, 0x77, 0x61, 0x70, 0x12, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, - 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, - 0x12, 0x65, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, - 0x70, 0x49, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, - 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x11, 0x43, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, 0x12, 0x21, 0x2e, 0x6c, + 0x12, 0x4c, 0x0a, 0x0d, 0x4e, 0x65, 0x77, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x53, 0x77, 0x61, + 0x70, 0x12, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, + 0x0a, 0x0b, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x21, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, + 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, + 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, + 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x28, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x65, 0x0a, + 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, + 0x70, 0x49, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x11, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4c, 0x6f, + 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, + 0x74, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4c, 0x6f, 0x6f, - 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, - 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x05, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x12, 0x1b, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, - 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, + 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x42, 0x0a, 0x05, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x16, 0x52, 0x65, 0x63, 0x6f, 0x6d, - 0x6d, 0x65, 0x6e, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x67, 0x69, - 0x6e, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x63, 0x6f, - 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, - 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, - 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x57, 0x0a, 0x13, 0x52, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x12, 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, - 0x71, 0x1a, 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, - 0x65, 0x73, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6c, - 0x6f, 0x6f, 0x70, 0x2f, 0x73, 0x77, 0x61, 0x70, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, - 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, + 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x16, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, + 0x64, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x22, + 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, + 0x6e, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, + 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x63, + 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x57, 0x0a, 0x13, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1f, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x6f, + 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1f, + 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, + 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x42, + 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, + 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, + 0x2f, 0x73, 0x77, 0x61, 0x70, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/swapserverrpc/server.proto b/swapserverrpc/server.proto index a8e3799..6aa265a 100644 --- a/swapserverrpc/server.proto +++ b/swapserverrpc/server.proto @@ -92,6 +92,9 @@ enum ProtocolVersion { // The client may ask the server to use a custom routing helper plugin in // order to enhance off-chain payments corresponding to a swap. ROUTING_PLUGIN = 9; + + // The client will use the new v3 (taproot) HTLC scripts. + HTLC_V3 = 10; } message ServerLoopOutRequest { From 00cf4bf71c7d47a89e8f4885f22fcf0e0fbb12b5 Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Sat, 14 May 2022 17:47:15 +0200 Subject: [PATCH 03/17] multi: make the next protocol version optional --- loopd/config.go | 3 +++ loopd/daemon.go | 6 +++++ loopdb/protocol_version.go | 46 ++++++++++++++++++++++++++++----- loopdb/protocol_version_test.go | 15 ++++++++--- loopin.go | 2 +- loopout.go | 2 +- swap_server_client.go | 26 +++++++++---------- 7 files changed, 74 insertions(+), 26 deletions(-) diff --git a/loopd/config.go b/loopd/config.go index b3460e3..43cb003 100644 --- a/loopd/config.go +++ b/loopd/config.go @@ -149,6 +149,8 @@ type Config struct { TotalPaymentTimeout time.Duration `long:"totalpaymenttimeout" description:"The timeout to use for off-chain payments."` MaxPaymentRetries int `long:"maxpaymentretries" description:"The maximum number of times an off-chain payment may be retried."` + EnableExperimental bool `long:"experimental" description:"Enable experimental features: taproot HTLCs and MuSig2 loop out sweeps."` + Lnd *lndConfig `group:"lnd" namespace:"lnd"` Server *loopServerConfig `group:"server" namespace:"server"` @@ -185,6 +187,7 @@ func DefaultConfig() Config { LoopOutMaxParts: defaultLoopOutMaxParts, TotalPaymentTimeout: defaultTotalPaymentTimeout, MaxPaymentRetries: defaultMaxPaymentRetries, + EnableExperimental: false, Lnd: &lndConfig{ Host: "localhost:10009", MacaroonPath: DefaultLndMacaroonPath, diff --git a/loopd/daemon.go b/loopd/daemon.go index 71f1a6b..b8eff04 100644 --- a/loopd/daemon.go +++ b/loopd/daemon.go @@ -348,6 +348,12 @@ func (d *Daemon) startWebServers() error { // this method fails with an error then no goroutine was started yet and no // cleanup is necessary. If it succeeds, then goroutines have been spawned. func (d *Daemon) initialize(withMacaroonService bool) error { + if d.cfg.EnableExperimental { + loopdb.EnableExperimentalProtocol() + } + + log.Infof("Protocol version: %v", loopdb.CurrentProtocolVersion()) + // If no swap server is specified, use the default addresses for mainnet // and testnet. if d.cfg.Server.Host == "" { diff --git a/loopdb/protocol_version.go b/loopdb/protocol_version.go index 0d93266..06e0e32 100644 --- a/loopdb/protocol_version.go +++ b/loopdb/protocol_version.go @@ -59,18 +59,50 @@ const ( // started saving protocol version with swaps. ProtocolVersionUnrecorded ProtocolVersion = math.MaxUint32 - // CurrentRPCProtocolVersion defines the version of the RPC protocol - // that is currently supported by the loop client. - CurrentRPCProtocolVersion = looprpc.ProtocolVersion_HTLC_V3 + // stableRPCProtocolVersion defines the current stable RPC protocol + // version. + stableRPCProtocolVersion = looprpc.ProtocolVersion_ROUTING_PLUGIN - // CurrentInternalProtocolVersion defines the RPC current protocol in - // the internal representation. - CurrentInternalProtocolVersion = ProtocolVersion(CurrentRPCProtocolVersion) + // experimentalRPCProtocolVersion defines the RPC protocol version that + // includes all currently experimentally released features. + experimentalRPCProtocolVersion = looprpc.ProtocolVersion_HTLC_V3 ) +var ( + // currentRPCProtocolVersion holds the version of the RPC protocol + // that the client selected to use for new swaps. Shouldn't be lower + // than the previous protocol version. + currentRPCProtocolVersion = stableRPCProtocolVersion +) + +// CurrentRPCProtocolVersion returns the RPC protocol version selected to be +// used for new swaps. +func CurrentRPCProtocolVersion() looprpc.ProtocolVersion { + return currentRPCProtocolVersion +} + +// CurrentProtocolVersion returns the internal protocol version selected to be +// used for new swaps. +func CurrentProtocolVersion() ProtocolVersion { + return ProtocolVersion(currentRPCProtocolVersion) +} + +// EnableExperimentalProtocol sets the current protocol version to include all +// experimental features. Do not call this function directly: used in loopd and +// unit tests only. +func EnableExperimentalProtocol() { + currentRPCProtocolVersion = experimentalRPCProtocolVersion +} + +// ResetCurrentProtocolVersion resets the current protocol version to the stable +// protocol. Note: used in integration tests only! +func ResetCurrentProtocolVersion() { + currentRPCProtocolVersion = stableRPCProtocolVersion +} + // Valid returns true if the value of the ProtocolVersion is valid. func (p ProtocolVersion) Valid() bool { - return p <= CurrentInternalProtocolVersion + return p <= ProtocolVersion(experimentalRPCProtocolVersion) } // String returns the string representation of a protocol version. diff --git a/loopdb/protocol_version_test.go b/loopdb/protocol_version_test.go index cb7d3b2..2e7f7f5 100644 --- a/loopdb/protocol_version_test.go +++ b/loopdb/protocol_version_test.go @@ -48,12 +48,19 @@ func TestProtocolVersionSanity(t *testing.T) { // Finally test that the current version contants are up to date require.Equal(t, - CurrentInternalProtocolVersion, - versions[len(versions)-1], + CurrentProtocolVersion(), + versions[len(versions)-2], ) require.Equal(t, - uint32(CurrentInternalProtocolVersion), - uint32(CurrentRPCProtocolVersion), + uint32(CurrentProtocolVersion()), + uint32(CurrentRPCProtocolVersion()), + ) + + EnableExperimentalProtocol() + + require.Equal(t, + CurrentProtocolVersion(), + ProtocolVersion(experimentalRPCProtocolVersion), ) } diff --git a/loopin.go b/loopin.go index d4e7e57..9d88a93 100644 --- a/loopin.go +++ b/loopin.go @@ -244,7 +244,7 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig, MaxMinerFee: request.MaxMinerFee, MaxSwapFee: request.MaxSwapFee, Label: request.Label, - ProtocolVersion: loopdb.CurrentInternalProtocolVersion, + ProtocolVersion: loopdb.CurrentProtocolVersion(), }, } diff --git a/loopout.go b/loopout.go index ecfcac1..10d01de 100644 --- a/loopout.go +++ b/loopout.go @@ -177,7 +177,7 @@ func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig, MaxMinerFee: request.MaxMinerFee, MaxSwapFee: request.MaxSwapFee, Label: request.Label, - ProtocolVersion: loopdb.CurrentInternalProtocolVersion, + ProtocolVersion: loopdb.CurrentProtocolVersion(), }, OutgoingChanSet: chanSet, } diff --git a/swap_server_client.go b/swap_server_client.go index 799ac87..10f0709 100644 --- a/swap_server_client.go +++ b/swap_server_client.go @@ -174,7 +174,7 @@ func (s *grpcSwapServerClient) GetLoopOutTerms(ctx context.Context) ( defer rpcCancel() terms, err := s.server.LoopOutTerms(rpcCtx, &looprpc.ServerLoopOutTermsRequest{ - ProtocolVersion: loopdb.CurrentRPCProtocolVersion, + ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), }, ) if err != nil { @@ -199,7 +199,7 @@ func (s *grpcSwapServerClient) GetLoopOutQuote(ctx context.Context, &looprpc.ServerLoopOutQuoteRequest{ Amt: uint64(amt), SwapPublicationDeadline: swapPublicationDeadline.Unix(), - ProtocolVersion: loopdb.CurrentRPCProtocolVersion, + ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), Expiry: expiry, }, ) @@ -231,7 +231,7 @@ func (s *grpcSwapServerClient) GetLoopInTerms(ctx context.Context) ( defer rpcCancel() terms, err := s.server.LoopInTerms(rpcCtx, &looprpc.ServerLoopInTermsRequest{ - ProtocolVersion: loopdb.CurrentRPCProtocolVersion, + ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), }, ) if err != nil { @@ -258,7 +258,7 @@ func (s *grpcSwapServerClient) GetLoopInQuote(ctx context.Context, req := &looprpc.ServerLoopInQuoteRequest{ Amt: uint64(amt), - ProtocolVersion: loopdb.CurrentRPCProtocolVersion, + ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), Pubkey: pubKey[:], } @@ -343,7 +343,7 @@ func (s *grpcSwapServerClient) Probe(ctx context.Context, amt btcutil.Amount, req := &looprpc.ServerProbeRequest{ Amt: uint64(amt), Target: target[:], - ProtocolVersion: loopdb.CurrentRPCProtocolVersion, + ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), RouteHints: rpcRouteHints, } @@ -368,7 +368,7 @@ func (s *grpcSwapServerClient) NewLoopOutSwap(ctx context.Context, Amt: uint64(amount), ReceiverKey: receiverKey[:], SwapPublicationDeadline: swapPublicationDeadline.Unix(), - ProtocolVersion: loopdb.CurrentRPCProtocolVersion, + ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), Expiry: expiry, UserAgent: UserAgent(initiator), }, @@ -403,7 +403,7 @@ func (s *grpcSwapServerClient) PushLoopOutPreimage(ctx context.Context, _, err := s.server.LoopOutPushPreimage(rpcCtx, &looprpc.ServerLoopOutPushPreimageRequest{ - ProtocolVersion: loopdb.CurrentRPCProtocolVersion, + ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), Preimage: preimage[:], }, ) @@ -424,7 +424,7 @@ func (s *grpcSwapServerClient) NewLoopInSwap(ctx context.Context, Amt: uint64(amount), SenderKey: senderKey[:], SwapInvoice: swapInvoice, - ProtocolVersion: loopdb.CurrentRPCProtocolVersion, + ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), ProbeInvoice: probeInvoice, UserAgent: UserAgent(initiator), } @@ -469,7 +469,7 @@ func (s *grpcSwapServerClient) SubscribeLoopInUpdates(ctx context.Context, resp, err := s.server.SubscribeLoopInUpdates( ctx, &looprpc.SubscribeUpdatesRequest{ - ProtocolVersion: loopdb.CurrentRPCProtocolVersion, + ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), SwapHash: hash[:], }, ) @@ -500,7 +500,7 @@ func (s *grpcSwapServerClient) SubscribeLoopOutUpdates(ctx context.Context, resp, err := s.server.SubscribeLoopOutUpdates( ctx, &looprpc.SubscribeUpdatesRequest{ - ProtocolVersion: loopdb.CurrentRPCProtocolVersion, + ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), SwapHash: hash[:], }, ) @@ -639,7 +639,7 @@ func (s *grpcSwapServerClient) CancelLoopOutSwap(ctx context.Context, details *outCancelDetails) error { req := &looprpc.CancelLoopOutSwapRequest{ - ProtocolVersion: loopdb.CurrentRPCProtocolVersion, + ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), SwapHash: details.hash[:], PaymentAddress: details.paymentAddr[:], } @@ -660,7 +660,7 @@ func (s *grpcSwapServerClient) RecommendRoutingPlugin(ctx context.Context, swapHash lntypes.Hash, paymentAddr [32]byte) (RoutingPluginType, error) { req := &looprpc.RecommendRoutingPluginReq{ - ProtocolVersion: loopdb.CurrentRPCProtocolVersion, + ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), SwapHash: swapHash[:], PaymentAddress: paymentAddr[:], } @@ -704,7 +704,7 @@ func (s *grpcSwapServerClient) ReportRoutingResult(ctx context.Context, } req := &looprpc.ReportRoutingResultReq{ - ProtocolVersion: loopdb.CurrentRPCProtocolVersion, + ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), SwapHash: swapHash[:], PaymentAddress: paymentAddr[:], Plugin: rpcRoutingPlugin, From 152677fcc7956d60bcce9a402e1a5fb722fa9fef Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Mon, 16 May 2022 15:56:23 +0200 Subject: [PATCH 04/17] test: fix naming in client tests --- client_test.go | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/client_test.go b/client_test.go index 6a315bc..b12f1bf 100644 --- a/client_test.go +++ b/client_test.go @@ -45,9 +45,9 @@ var ( defaultConfirmations = int32(loopdb.DefaultLoopOutHtlcConfirmations) ) -// TestSuccess tests the loop out happy flow, using a custom htlc confirmation -// target. -func TestSuccess(t *testing.T) { +// TestLoopOutSuccess tests the loop out happy flow, using a custom htlc +// confirmation target. +func TestLoopOutSuccess(t *testing.T) { defer test.Guard(t)() ctx := createClientTestContext(t, nil) @@ -70,15 +70,15 @@ func TestSuccess(t *testing.T) { // Expect client to register for conf. confIntent := ctx.AssertRegisterConf(false, req.HtlcConfirmations) - testSuccess(ctx, testRequest.Amount, info.SwapHash, + testLoopOutSuccess(ctx, testRequest.Amount, info.SwapHash, signalPrepaymentResult, signalSwapPaymentResult, false, confIntent, swap.HtlcV2, ) } -// TestFailOffchain tests the handling of swap for which the server failed the -// payments. -func TestFailOffchain(t *testing.T) { +// TestLoopOutFailOffchain tests the handling of swap for which the server +// failed the payments. +func TestLoopOutFailOffchain(t *testing.T) { defer test.Guard(t)() ctx := createClientTestContext(t, nil) @@ -110,8 +110,9 @@ func TestFailOffchain(t *testing.T) { ctx.finish() } -// TestWrongAmount asserts that the client checks the server invoice amounts. -func TestFailWrongAmount(t *testing.T) { +// TestLoopOutWrongAmount asserts that the client checks the server invoice +// amounts. +func TestLoopOutFailWrongAmount(t *testing.T) { defer test.Guard(t)() test := func(t *testing.T, modifier func(*serverMock), @@ -148,9 +149,9 @@ func TestFailWrongAmount(t *testing.T) { } -// TestResume tests that swaps in various states are properly resumed after a -// restart. -func TestResume(t *testing.T) { +// TestLoopOutResume tests that swaps in various states are properly resumed +// after a restart. +func TestLoopOutResume(t *testing.T) { defer test.Guard(t)() defaultConfs := loopdb.DefaultLoopOutHtlcConfirmations @@ -165,26 +166,26 @@ func TestResume(t *testing.T) { t.Run(version.String(), func(t *testing.T) { t.Run("not expired", func(t *testing.T) { - testResume( + testLoopOutResume( t, defaultConfs, false, false, true, version, ) }) t.Run("not expired, custom confirmations", func(t *testing.T) { - testResume( + testLoopOutResume( t, 3, false, false, true, version, ) }) t.Run("expired not revealed", func(t *testing.T) { - testResume( + testLoopOutResume( t, defaultConfs, true, false, false, version, ) }) t.Run("expired revealed", func(t *testing.T) { - testResume( + testLoopOutResume( t, defaultConfs, true, true, true, version, ) @@ -193,7 +194,7 @@ func TestResume(t *testing.T) { } } -func testResume(t *testing.T, confs uint32, expired, preimageRevealed, +func testLoopOutResume(t *testing.T, confs uint32, expired, preimageRevealed, expectSuccess bool, protocolVersion loopdb.ProtocolVersion) { defer test.Guard(t)() @@ -302,7 +303,7 @@ func testResume(t *testing.T, confs uint32, expired, preimageRevealed, // Because there is no reliable payment yet, an invoice is assumed to be // paid after resume. - testSuccess(ctx, amt, hash, + testLoopOutSuccess(ctx, amt, hash, func(r error) {}, func(r error) {}, preimageRevealed, @@ -310,7 +311,7 @@ func testResume(t *testing.T, confs uint32, expired, preimageRevealed, ) } -func testSuccess(ctx *testContext, amt btcutil.Amount, hash lntypes.Hash, +func testLoopOutSuccess(ctx *testContext, amt btcutil.Amount, hash lntypes.Hash, signalPrepaymentResult, signalSwapPaymentResult func(error), preimageRevealed bool, confIntent *test.ConfRegistration, scriptVersion swap.ScriptVersion) { From 901a935514e2d2800d2d9a25586fd938bbf6a237 Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Sun, 24 Apr 2022 22:59:41 +0200 Subject: [PATCH 05/17] loopin: enable p2tr htlcs without keyspend --- client.go | 83 ++-- cmd/loop/loopin.go | 13 +- cmd/loop/main.go | 5 + interface.go | 7 + liquidity/liquidity.go | 5 +- loopd/swapclient_server.go | 53 ++- loopin.go | 67 +++- loopin_test.go | 227 +++++++---- looprpc/client.pb.go | 746 +++++++++++++++++++----------------- looprpc/client.proto | 6 + looprpc/client.swagger.json | 8 + swap.go | 6 + 12 files changed, 737 insertions(+), 489 deletions(-) diff --git a/client.go b/client.go index b6bed80..e43dee4 100644 --- a/client.go +++ b/client.go @@ -213,35 +213,56 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) { } for _, swp := range loopInSwaps { - htlcNP2WSH, err := swap.NewHtlc( - GetHtlcScriptVersion(swp.Contract.ProtocolVersion), - swp.Contract.CltvExpiry, swp.Contract.SenderKey, - swp.Contract.ReceiverKey, swp.Hash, swap.HtlcNP2WSH, - s.lndServices.ChainParams, - ) - if err != nil { - return nil, err + swapInfo := &SwapInfo{ + SwapType: swap.TypeIn, + SwapContract: swp.Contract.SwapContract, + SwapStateData: swp.State(), + SwapHash: swp.Hash, + LastUpdate: swp.LastUpdateTime(), } - htlcP2WSH, err := swap.NewHtlc( - GetHtlcScriptVersion(swp.Contract.ProtocolVersion), - swp.Contract.CltvExpiry, swp.Contract.SenderKey, - swp.Contract.ReceiverKey, swp.Hash, swap.HtlcP2WSH, - s.lndServices.ChainParams, + scriptVersion := GetHtlcScriptVersion( + swp.Contract.SwapContract.ProtocolVersion, ) - if err != nil { - return nil, err + + if scriptVersion == swap.HtlcV3 { + htlcP2TR, err := swap.NewHtlc( + swap.HtlcV3, swp.Contract.CltvExpiry, + swp.Contract.SenderKey, swp.Contract.ReceiverKey, + swp.Hash, swap.HtlcP2TR, + s.lndServices.ChainParams, + ) + if err != nil { + return nil, err + } + + swapInfo.HtlcAddressP2TR = htlcP2TR.Address + } else { + htlcNP2WSH, err := swap.NewHtlc( + swap.HtlcV1, swp.Contract.CltvExpiry, + swp.Contract.SenderKey, swp.Contract.ReceiverKey, + swp.Hash, swap.HtlcNP2WSH, + s.lndServices.ChainParams, + ) + if err != nil { + return nil, err + } + + htlcP2WSH, err := swap.NewHtlc( + swap.HtlcV2, swp.Contract.CltvExpiry, + swp.Contract.SenderKey, swp.Contract.ReceiverKey, + swp.Hash, swap.HtlcP2WSH, + s.lndServices.ChainParams, + ) + if err != nil { + return nil, err + } + + swapInfo.HtlcAddressP2WSH = htlcP2WSH.Address + swapInfo.HtlcAddressNP2WSH = htlcNP2WSH.Address } - swaps = append(swaps, &SwapInfo{ - SwapType: swap.TypeIn, - SwapContract: swp.Contract.SwapContract, - SwapStateData: swp.State(), - SwapHash: swp.Hash, - LastUpdate: swp.LastUpdateTime(), - HtlcAddressP2WSH: htlcP2WSH.Address, - HtlcAddressNP2WSH: htlcNP2WSH.Address, - }) + swaps = append(swaps, swapInfo) } return swaps, nil @@ -546,11 +567,17 @@ func (s *Client) LoopIn(globalCtx context.Context, // Return hash so that the caller can identify this swap in the updates // stream. swapInfo := &LoopInSwapInfo{ - SwapHash: swap.hash, - HtlcAddressP2WSH: swap.htlcP2WSH.Address, - HtlcAddressNP2WSH: swap.htlcNP2WSH.Address, - ServerMessage: initResult.serverMessage, + SwapHash: swap.hash, + ServerMessage: initResult.serverMessage, } + + if loopdb.CurrentProtocolVersion() < loopdb.ProtocolVersionHtlcV3 { + swapInfo.HtlcAddressNP2WSH = swap.htlcNP2WSH.Address + swapInfo.HtlcAddressP2WSH = swap.htlcP2WSH.Address + } else { + swapInfo.HtlcAddressP2TR = swap.htlcP2TR.Address + } + return swapInfo, nil } diff --git a/cmd/loop/loopin.go b/cmd/loop/loopin.go index 30766b3..add0cba 100644 --- a/cmd/loop/loopin.go +++ b/cmd/loop/loopin.go @@ -205,13 +205,20 @@ func loopIn(ctx *cli.Context) error { fmt.Printf("Swap initiated\n") fmt.Printf("ID: %v\n", resp.Id) - if external { - fmt.Printf("HTLC address (NP2WSH): %v\n", resp.HtlcAddressNp2Wsh) + if resp.HtlcAddressP2Tr != "" { + fmt.Printf("HTLC address (P2TR): %v\n", resp.HtlcAddressP2Tr) + } else { + if external { + fmt.Printf("HTLC address (NP2WSH): %v\n", + resp.HtlcAddressNp2Wsh) + } + fmt.Printf("HTLC address (P2WSH): %v\n", resp.HtlcAddressP2Wsh) } - fmt.Printf("HTLC address (P2WSH): %v\n", resp.HtlcAddressP2Wsh) + if resp.ServerMessage != "" { fmt.Printf("Server message: %v\n", resp.ServerMessage) } + fmt.Println() fmt.Printf("Run `loop monitor` to monitor progress.\n") diff --git a/cmd/loop/main.go b/cmd/loop/main.go index e2f213e..bca93d7 100644 --- a/cmd/loop/main.go +++ b/cmd/loop/main.go @@ -345,6 +345,7 @@ func logSwap(swap *looprpc.SwapStatus) { fmt.Printf("%v %v %v %v -", time.Unix(0, swap.LastUpdateTime).Format(time.RFC3339), swap.Type, swapState, btcutil.Amount(swap.Amt)) + if swap.HtlcAddressP2Wsh != "" { fmt.Printf(" P2WSH: %v", swap.HtlcAddressP2Wsh) } @@ -352,6 +353,10 @@ func logSwap(swap *looprpc.SwapStatus) { if swap.HtlcAddressNp2Wsh != "" { fmt.Printf(" NP2WSH: %v", swap.HtlcAddressNp2Wsh) } + + if swap.HtlcAddressP2Tr != "" { + fmt.Printf(" P2TR: %v", swap.HtlcAddressP2Tr) + } } if swap.State != looprpc.SwapState_INITIATED && diff --git a/interface.go b/interface.go index d1caa9e..9318d54 100644 --- a/interface.go +++ b/interface.go @@ -298,6 +298,9 @@ type LoopInSwapInfo struct { // nolint // where the loop-in funds may be paid. HtlcAddressNP2WSH btcutil.Address + // HtlcAddresP2TR contains the v3 (pay to taproot) htlc address. + HtlcAddressP2TR btcutil.Address + // ServerMessages is the human-readable message received from the loop // server. ServerMessage string @@ -351,6 +354,10 @@ type SwapInfo struct { // swap htlc. This is only used for external loop-in. HtlcAddressNP2WSH btcutil.Address + // HtlcAddressP2TR stores the address of the P2TR (taproot) swap htlc. + // This is used for both internal and external loop-in and loop out. + HtlcAddressP2TR btcutil.Address + // ExternalHtlc is set to true for external loop-in swaps. ExternalHtlc bool diff --git a/liquidity/liquidity.go b/liquidity/liquidity.go index 2721c71..59d6426 100644 --- a/liquidity/liquidity.go +++ b/liquidity/liquidity.go @@ -407,8 +407,9 @@ func (m *Manager) autoloop(ctx context.Context) error { } log.Infof("loop in automatically dispatched: hash: %v, "+ - "address: %v", loopIn.SwapHash, - loopIn.HtlcAddressNP2WSH) + "address: np2wsh(%v), p2wsh(%v), p2tr(%v)", + loopIn.SwapHash, loopIn.HtlcAddressNP2WSH, + loopIn.HtlcAddressP2WSH, loopIn.HtlcAddressP2TR) } return nil diff --git a/loopd/swapclient_server.go b/loopd/swapclient_server.go index c52fd7d..f97bfc6 100644 --- a/loopd/swapclient_server.go +++ b/loopd/swapclient_server.go @@ -217,20 +217,33 @@ func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) ( } var swapType clientrpc.SwapType - var htlcAddress, htlcAddressP2WSH, htlcAddressNP2WSH string + var ( + htlcAddress string + htlcAddressP2TR string + htlcAddressP2WSH string + htlcAddressNP2WSH string + ) var outGoingChanSet []uint64 var lastHop []byte switch loopSwap.SwapType { case swap.TypeIn: swapType = clientrpc.SwapType_LOOP_IN - htlcAddressP2WSH = loopSwap.HtlcAddressP2WSH.EncodeAddress() - if loopSwap.ExternalHtlc { - htlcAddressNP2WSH = loopSwap.HtlcAddressNP2WSH.EncodeAddress() - htlcAddress = htlcAddressNP2WSH + if loopSwap.HtlcAddressP2TR != nil { + htlcAddressP2TR = loopSwap.HtlcAddressP2TR.EncodeAddress() + htlcAddress = htlcAddressP2TR } else { - htlcAddress = htlcAddressP2WSH + htlcAddressP2WSH = + loopSwap.HtlcAddressP2WSH.EncodeAddress() + + if loopSwap.ExternalHtlc { + htlcAddressNP2WSH = + loopSwap.HtlcAddressNP2WSH.EncodeAddress() + htlcAddress = htlcAddressNP2WSH + } else { + htlcAddress = htlcAddressP2WSH + } } if loopSwap.LastHop != nil { @@ -257,6 +270,7 @@ func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) ( InitiationTime: loopSwap.InitiationTime.UnixNano(), LastUpdateTime: loopSwap.LastUpdate.UnixNano(), HtlcAddress: htlcAddress, + HtlcAddressP2Tr: htlcAddressP2TR, HtlcAddressP2Wsh: htlcAddressP2WSH, HtlcAddressNp2Wsh: htlcAddressNP2WSH, Type: swapType, @@ -618,8 +632,7 @@ func (s *swapClientServer) Probe(ctx context.Context, } func (s *swapClientServer) LoopIn(ctx context.Context, - in *clientrpc.LoopInRequest) ( - *clientrpc.SwapResponse, error) { + in *clientrpc.LoopInRequest) (*clientrpc.SwapResponse, error) { log.Infof("Loop in request received") @@ -665,17 +678,25 @@ func (s *swapClientServer) LoopIn(ctx context.Context, } response := &clientrpc.SwapResponse{ - Id: swapInfo.SwapHash.String(), - IdBytes: swapInfo.SwapHash[:], - HtlcAddressP2Wsh: swapInfo.HtlcAddressP2WSH.String(), - ServerMessage: swapInfo.ServerMessage, + Id: swapInfo.SwapHash.String(), + IdBytes: swapInfo.SwapHash[:], + ServerMessage: swapInfo.ServerMessage, } - if req.ExternalHtlc { - response.HtlcAddressNp2Wsh = swapInfo.HtlcAddressNP2WSH.String() - response.HtlcAddress = response.HtlcAddressNp2Wsh // nolint:staticcheck + if loopdb.CurrentProtocolVersion() < loopdb.ProtocolVersionHtlcV3 { + if req.ExternalHtlc { + np2wshAddr := swapInfo.HtlcAddressNP2WSH.String() + response.HtlcAddress = np2wshAddr + response.HtlcAddressNp2Wsh = np2wshAddr + } else { + p2wshAddr := swapInfo.HtlcAddressP2WSH.String() + response.HtlcAddress = p2wshAddr + response.HtlcAddressP2Wsh = p2wshAddr + } } else { - response.HtlcAddress = response.HtlcAddressP2Wsh // nolint:staticcheck + p2trAddr := swapInfo.HtlcAddressP2TR.String() + response.HtlcAddress = p2trAddr + response.HtlcAddressP2Tr = p2trAddr } return response, nil diff --git a/loopin.go b/loopin.go index 9d88a93..3e89c91 100644 --- a/loopin.go +++ b/loopin.go @@ -62,6 +62,8 @@ type loopInSwap struct { htlcNP2WSH *swap.Htlc + htlcP2TR *swap.Htlc + // htlcTxHash is the confirmed htlc tx id. htlcTxHash *chainhash.Hash @@ -402,6 +404,18 @@ func validateLoopInContract(lnd *lndclient.LndServices, // initHtlcs creates and updates the native and nested segwit htlcs // of the loopInSwap. func (s *loopInSwap) initHtlcs() error { + if IsTaprootSwap(&s.SwapContract) { + htlcP2TR, err := s.swapKit.getHtlc(swap.HtlcP2TR) + if err != nil { + return err + } + + s.swapKit.log.Infof("Htlc address (P2TR): %v", htlcP2TR.Address) + s.htlcP2TR = htlcP2TR + + return nil + } + htlcP2WSH, err := s.swapKit.getHtlc(swap.HtlcP2WSH) if err != nil { return err @@ -427,8 +441,13 @@ func (s *loopInSwap) sendUpdate(ctx context.Context) error { info := s.swapInfo() s.log.Infof("Loop in swap state: %v", info.State) - info.HtlcAddressP2WSH = s.htlcP2WSH.Address - info.HtlcAddressNP2WSH = s.htlcNP2WSH.Address + if IsTaprootSwap(&s.SwapContract) { + info.HtlcAddressP2TR = s.htlcP2TR.Address + } else { + info.HtlcAddressP2WSH = s.htlcP2WSH.Address + info.HtlcAddressNP2WSH = s.htlcNP2WSH.Address + } + info.ExternalHtlc = s.ExternalHtlc // In order to avoid potentially dangerous ownership sharing @@ -605,16 +624,29 @@ func (s *loopInSwap) waitForHtlcConf(globalCtx context.Context) ( notifier := s.lnd.ChainNotifier - confChanP2WSH, confErrP2WSH, err := notifier.RegisterConfirmationsNtfn( - ctx, s.htlcTxHash, s.htlcP2WSH.PkScript, 1, s.InitiationHeight, - ) + notifyConfirmation := func(htlc *swap.Htlc) ( + chan *chainntnfs.TxConfirmation, chan error, error) { + + if htlc == nil { + return nil, nil, nil + } + + return notifier.RegisterConfirmationsNtfn( + ctx, s.htlcTxHash, htlc.PkScript, 1, s.InitiationHeight, + ) + } + + confChanP2WSH, confErrP2WSH, err := notifyConfirmation(s.htlcP2WSH) if err != nil { return nil, err } - confChanNP2WSH, confErrNP2WSH, err := notifier.RegisterConfirmationsNtfn( - ctx, s.htlcTxHash, s.htlcNP2WSH.PkScript, 1, s.InitiationHeight, - ) + confChanNP2WSH, confErrNP2WSH, err := notifyConfirmation(s.htlcNP2WSH) + if err != nil { + return nil, err + } + + confChanP2TR, confErrP2TR, err := notifyConfirmation(s.htlcP2TR) if err != nil { return nil, err } @@ -633,6 +665,11 @@ func (s *loopInSwap) waitForHtlcConf(globalCtx context.Context) ( s.htlc = s.htlcNP2WSH s.log.Infof("NP2WSH htlc confirmed") + // P2TR htlc confirmed. + case conf = <-confChanP2TR: + s.htlc = s.htlcP2TR + s.log.Infof("P2TR htlc confirmed") + // Conf ntfn error. case err := <-confErrP2WSH: return nil, err @@ -641,6 +678,10 @@ func (s *loopInSwap) waitForHtlcConf(globalCtx context.Context) ( case err := <-confErrNP2WSH: return nil, err + // Conf ntfn error. + case err := <-confErrP2TR: + return nil, err + // Keep up with block height. case notification := <-s.blockEpochChan: s.height = notification.(int32) @@ -697,10 +738,16 @@ func (s *loopInSwap) publishOnChainHtlc(ctx context.Context) (bool, error) { s.log.Infof("Publishing on chain HTLC with fee rate %v", feeRate) - // Internal loop-in is always P2WSH. + var pkScript []byte + if IsTaprootSwap(&s.SwapContract) { + pkScript = s.htlcP2TR.PkScript + } else { + pkScript = s.htlcP2WSH.PkScript + } + tx, err := s.lnd.WalletKit.SendOutputs( ctx, []*wire.TxOut{{ - PkScript: s.htlcP2WSH.PkScript, + PkScript: pkScript, Value: int64(s.LoopInContract.AmountRequested), }}, feeRate, labels.LoopInHtlcLabel(swap.ShortHash(&s.hash)), ) diff --git a/loopin_test.go b/loopin_test.go index bdf47da..79200f0 100644 --- a/loopin_test.go +++ b/loopin_test.go @@ -2,6 +2,7 @@ package loop import ( "context" + "fmt" "testing" "github.com/btcsuite/btcd/btcutil" @@ -27,6 +28,19 @@ var ( // TestLoopInSuccess tests the success scenario where the swap completes the // happy flow. func TestLoopInSuccess(t *testing.T) { + t.Run("stable protocol", func(t *testing.T) { + testLoopInSuccess(t) + }) + + t.Run("experimental protocol", func(t *testing.T) { + loopdb.EnableExperimentalProtocol() + defer loopdb.ResetCurrentProtocolVersion() + + testLoopInSuccess(t) + }) +} + +func testLoopInSuccess(t *testing.T) { defer test.Guard(t)() ctx := newLoopInTestContext(t) @@ -47,13 +61,13 @@ func TestLoopInSuccess(t *testing.T) { if err != nil { t.Fatal(err) } - swap := initResult.swap + inSwap := initResult.swap ctx.store.assertLoopInStored() errChan := make(chan error) go func() { - err := swap.execute(context.Background(), ctx.cfg, height) + err := inSwap.execute(context.Background(), ctx.cfg, height) if err != nil { log.Error(err) } @@ -87,10 +101,15 @@ func TestLoopInSuccess(t *testing.T) { require.NotNil(t, state.HtlcTxHash) require.Equal(t, cost, state.Cost) - // Expect register for htlc conf. - <-ctx.lnd.RegisterConfChannel + // Expect register for htlc conf (only one, since the htlc is p2tr). <-ctx.lnd.RegisterConfChannel + // If the swap is legacy, then we'll register two confirmation + // notifications. + if !IsTaprootSwap(&inSwap.SwapContract) { + <-ctx.lnd.RegisterConfChannel + } + // Confirm htlc. ctx.lnd.ConfChannel <- &chainntnfs.TxConfirmation{ Tx: &htlcTx, @@ -112,8 +131,13 @@ func TestLoopInSuccess(t *testing.T) { // Server spends htlc. successTx := wire.MsgTx{} + witness, err := inSwap.htlc.GenSuccessWitness( + []byte{}, inSwap.contract.Preimage, + ) + require.NoError(t, err) + successTx.AddTxIn(&wire.TxIn{ - Witness: [][]byte{{}, {}, {}}, + Witness: witness, }) ctx.lnd.SpendChannel <- &chainntnfs.SpendDetail{ @@ -134,33 +158,52 @@ func TestLoopInSuccess(t *testing.T) { // and the client is forced to reclaim the funds using the timeout tx. func TestLoopInTimeout(t *testing.T) { testAmt := int64(testLoopInRequest.Amount) - t.Run("internal htlc", func(t *testing.T) { - testLoopInTimeout(t, swap.HtlcP2WSH, 0) - }) + testCases := []struct { + name string + externalValue int64 + }{ + { + name: "internal htlc", + externalValue: 0, + }, + { + name: "external htlc", + externalValue: testAmt, + }, + { + name: "external htlc amount too high", + externalValue: testAmt + 1, + }, + { + name: "external htlc amount too low", + externalValue: testAmt - 1, + }, + } - outputTypes := []swap.HtlcOutputType{swap.HtlcP2WSH, swap.HtlcNP2WSH} + for _, next := range []bool{false, true} { + next := next - for _, outputType := range outputTypes { - outputType := outputType - t.Run(outputType.String(), func(t *testing.T) { - t.Run("external htlc", func(t *testing.T) { - testLoopInTimeout(t, outputType, testAmt) - }) + for _, testCase := range testCases { + testCase := testCase - t.Run("external amount too high", func(t *testing.T) { - testLoopInTimeout(t, outputType, testAmt+1) - }) + name := testCase.name + if next { + name += " experimental protocol" + } + + t.Run(name, func(t *testing.T) { + if next { + loopdb.EnableExperimentalProtocol() + defer loopdb.ResetCurrentProtocolVersion() + } - t.Run("external amount too low", func(t *testing.T) { - testLoopInTimeout(t, outputType, testAmt-1) + testLoopInTimeout(t, testCase.externalValue) }) - }) + } } } -func testLoopInTimeout(t *testing.T, - outputType swap.HtlcOutputType, externalValue int64) { - +func testLoopInTimeout(t *testing.T, externalValue int64) { defer test.Guard(t)() ctx := newLoopInTestContext(t) @@ -181,13 +224,13 @@ func testLoopInTimeout(t *testing.T, if err != nil { t.Fatal(err) } - s := initResult.swap + inSwap := initResult.swap ctx.store.assertLoopInStored() errChan := make(chan error) go func() { - err := s.execute(context.Background(), ctx.cfg, height) + err := inSwap.execute(context.Background(), ctx.cfg, height) if err != nil { log.Error(err) } @@ -203,9 +246,11 @@ func testLoopInTimeout(t *testing.T, htlcTx wire.MsgTx cost loopdb.SwapCost ) + if externalValue == 0 { // Expect htlc to be published. htlcTx = <-ctx.lnd.SendOutputsChannel + cost = loopdb.SwapCost{ Onchain: getTxFee( &htlcTx, test.DefaultMockFee.FeePerKVByte(), @@ -220,11 +265,16 @@ func testLoopInTimeout(t *testing.T, } else { // Create an external htlc publish tx. var pkScript []byte - if outputType == swap.HtlcNP2WSH { - pkScript = s.htlcNP2WSH.PkScript + if !IsTaprootSwap(&inSwap.SwapContract) { + if req.ExternalHtlc { + pkScript = inSwap.htlcNP2WSH.PkScript + } else { + pkScript = inSwap.htlcP2WSH.PkScript + } } else { - pkScript = s.htlcP2WSH.PkScript + pkScript = inSwap.htlcP2TR.PkScript } + htlcTx = wire.MsgTx{ TxOut: []*wire.TxOut{ { @@ -237,7 +287,12 @@ func testLoopInTimeout(t *testing.T, // Expect register for htlc conf. <-ctx.lnd.RegisterConfChannel - <-ctx.lnd.RegisterConfChannel + + // If the swap is legacy, then we'll register two confirmation + // notifications. + if !IsTaprootSwap(&inSwap.SwapContract) { + <-ctx.lnd.RegisterConfChannel + } // Confirm htlc. ctx.lnd.ConfChannel <- &chainntnfs.TxConfirmation{ @@ -265,7 +320,7 @@ func testLoopInTimeout(t *testing.T, ctx.assertSubscribeInvoice(ctx.server.swapHash) // Let htlc expire. - ctx.blockEpochChan <- s.LoopInContract.CltvExpiry + ctx.blockEpochChan <- inSwap.LoopInContract.CltvExpiry // Expect a signing request for the htlc tx output value. signReq := <-ctx.lnd.SignOutputRawChannel @@ -278,9 +333,9 @@ func testLoopInTimeout(t *testing.T, // We can just get our sweep fee as we would in the swap code because // our estimate is static. - fee, err := s.sweeper.GetSweepFee( - context.Background(), s.htlc.AddTimeoutToEstimator, - s.timeoutAddr, TimeoutTxConfTarget, + fee, err := inSwap.sweeper.GetSweepFee( + context.Background(), inSwap.htlc.AddTimeoutToEstimator, + inSwap.timeoutAddr, TimeoutTxConfTarget, ) require.NoError(t, err) cost.Onchain += fee @@ -313,52 +368,71 @@ func TestLoopInResume(t *testing.T) { storedVersion := []loopdb.ProtocolVersion{ loopdb.ProtocolVersionUnrecorded, loopdb.ProtocolVersionHtlcV2, + loopdb.ProtocolVersionHtlcV3, } - htlcVersion := []swap.ScriptVersion{ - swap.HtlcV1, - swap.HtlcV2, + testCases := []struct { + name string + state loopdb.SwapState + expired bool + }{ + { + name: "initiated", + state: loopdb.StateInitiated, + expired: false, + }, + { + name: "initiated expired", + state: loopdb.StateInitiated, + expired: true, + }, + { + name: "htlc published", + state: loopdb.StateHtlcPublished, + expired: false, + }, } - for i, version := range storedVersion { - version := version - scriptVersion := htlcVersion[i] - - t.Run(version.String(), func(t *testing.T) { - t.Run("initiated", func(t *testing.T) { - testLoopInResume( - t, loopdb.StateInitiated, false, - version, scriptVersion, - ) - }) - - t.Run("initiated expired", func(t *testing.T) { - testLoopInResume( - t, loopdb.StateInitiated, true, - version, scriptVersion, - ) - }) + for _, next := range []bool{false, true} { + for _, version := range storedVersion { + version := version + for _, testCase := range testCases { + testCase := testCase - t.Run("htlc published", func(t *testing.T) { - testLoopInResume( - t, loopdb.StateHtlcPublished, false, - version, scriptVersion, + name := fmt.Sprintf( + "%v %v", testCase, version.String(), ) - }) - }) + if next { + name += " next protocol" + } + + t.Run(name, func(t *testing.T) { + testLoopInResume( + t, testCase.state, + testCase.expired, + version, + ) + }) + } + } } } func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool, - storedVersion loopdb.ProtocolVersion, scriptVersion swap.ScriptVersion) { + storedVersion loopdb.ProtocolVersion) { defer test.Guard(t)() ctx := newLoopInTestContext(t) cfg := newSwapConfig(&ctx.lnd.LndServices, ctx.store, ctx.server) - senderKey := [33]byte{4} - receiverKey := [33]byte{5} + // Create sender and receiver keys. + _, senderPubKey := test.CreateKey(1) + _, receiverPubKey := test.CreateKey(2) + + var senderKey, receiverKey [33]byte + copy(receiverKey[:], receiverPubKey.SerializeCompressed()) + copy(senderKey[:], senderPubKey.SerializeCompressed()) contract := &loopdb.LoopInContract{ HtlcConfTarget: 2, @@ -397,9 +471,16 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool, pendSwap.Loop.Events[0].Cost = cost } + scriptVersion := GetHtlcScriptVersion(storedVersion) + + outputType := swap.HtlcNP2WSH + if scriptVersion == swap.HtlcV3 { + outputType = swap.HtlcP2TR + } + htlc, err := swap.NewHtlc( scriptVersion, contract.CltvExpiry, contract.SenderKey, - contract.ReceiverKey, testPreimage.Hash(), swap.HtlcNP2WSH, + contract.ReceiverKey, testPreimage.Hash(), outputType, cfg.lnd.ChainParams, ) if err != nil { @@ -411,7 +492,7 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool, t.Fatal(err) } - swap, err := resumeLoopInSwap( + inSwap, err := resumeLoopInSwap( context.Background(), cfg, pendSwap, ) @@ -428,7 +509,7 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool, errChan := make(chan error) go func() { - err := swap.execute(context.Background(), ctx.cfg, height) + err := inSwap.execute(context.Background(), ctx.cfg, height) if err != nil { log.Error(err) } @@ -489,7 +570,12 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool, // Expect register for htlc conf. <-ctx.lnd.RegisterConfChannel - <-ctx.lnd.RegisterConfChannel + + // If the swap is legacy, then we'll register two confirmation + // notifications. + if !IsTaprootSwap(&inSwap.SwapContract) { + <-ctx.lnd.RegisterConfChannel + } // Confirm htlc. ctx.lnd.ConfChannel <- &chainntnfs.TxConfirmation{ @@ -513,8 +599,11 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool, // Server spends htlc. successTx := wire.MsgTx{} + witness, err := htlc.GenSuccessWitness([]byte{}, testPreimage) + require.NoError(t, err) + successTx.AddTxIn(&wire.TxIn{ - Witness: [][]byte{{}, {}, {}}, + Witness: witness, }) successTxHash := successTx.TxHash() diff --git a/looprpc/client.pb.go b/looprpc/client.pb.go index 874638b..5ab4186 100644 --- a/looprpc/client.pb.go +++ b/looprpc/client.pb.go @@ -811,6 +811,8 @@ type SwapResponse struct { //The native segwit address of the on-chain htlc. //Used for both loop-in and loop-out. HtlcAddressP2Wsh string `protobuf:"bytes,5,opt,name=htlc_address_p2wsh,json=htlcAddressP2wsh,proto3" json:"htlc_address_p2wsh,omitempty"` + // The address of the v3 (taproot) htlc. Used for both loop-in and loop-out. + HtlcAddressP2Tr string `protobuf:"bytes,7,opt,name=htlc_address_p2tr,json=htlcAddressP2tr,proto3" json:"htlc_address_p2tr,omitempty"` // A human-readable message received from the loop server. ServerMessage string `protobuf:"bytes,6,opt,name=server_message,json=serverMessage,proto3" json:"server_message,omitempty"` } @@ -884,6 +886,13 @@ func (x *SwapResponse) GetHtlcAddressP2Wsh() string { return "" } +func (x *SwapResponse) GetHtlcAddressP2Tr() string { + if x != nil { + return x.HtlcAddressP2Tr + } + return "" +} + func (x *SwapResponse) GetServerMessage() string { if x != nil { return x.ServerMessage @@ -980,6 +989,8 @@ type SwapStatus struct { HtlcAddressP2Wsh string `protobuf:"bytes,12,opt,name=htlc_address_p2wsh,json=htlcAddressP2wsh,proto3" json:"htlc_address_p2wsh,omitempty"` // HTLC address (nested segwit), used in loop-in swaps only. HtlcAddressNp2Wsh string `protobuf:"bytes,13,opt,name=htlc_address_np2wsh,json=htlcAddressNp2wsh,proto3" json:"htlc_address_np2wsh,omitempty"` + // The address of the v3 (taproot) htlc. Used for both loop-in and loop-out. + HtlcAddressP2Tr string `protobuf:"bytes,18,opt,name=htlc_address_p2tr,json=htlcAddressP2tr,proto3" json:"htlc_address_p2tr,omitempty"` // Swap server cost CostServer int64 `protobuf:"varint,8,opt,name=cost_server,json=costServer,proto3" json:"cost_server,omitempty"` // On-chain transaction cost @@ -1105,6 +1116,13 @@ func (x *SwapStatus) GetHtlcAddressNp2Wsh() string { return "" } +func (x *SwapStatus) GetHtlcAddressP2Tr() string { + if x != nil { + return x.HtlcAddressP2Tr + } + return "" +} + func (x *SwapStatus) GetCostServer() int64 { if x != nil { return x.CostServer @@ -2787,7 +2805,7 @@ var file_client_proto_rawDesc = []byte{ 0x32, 0x12, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 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, 0x0a, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x22, 0xe9, 0x01, 0x0a, 0x0c, 0x53, + 0x08, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x22, 0x95, 0x02, 0x0a, 0x0c, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, @@ -2800,370 +2818,376 @@ var file_client_proto_rawDesc = []byte{ 0x68, 0x12, 0x2c, 0x0a, 0x12, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x70, 0x32, 0x77, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x68, 0x74, 0x6c, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x32, 0x77, 0x73, 0x68, 0x12, - 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x10, 0x0a, 0x0e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xfb, 0x04, 0x0a, 0x0a, 0x53, 0x77, 0x61, - 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6d, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x61, 0x6d, 0x74, 0x12, 0x12, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, - 0x08, 0x69, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x07, 0x69, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x77, 0x61, 0x70, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, - 0x28, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3d, 0x0a, 0x0e, 0x66, 0x61, 0x69, - 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x61, 0x69, 0x6c, - 0x75, 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x0d, 0x66, 0x61, 0x69, 0x6c, 0x75, - 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x69, 0x74, - 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0e, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, - 0x65, 0x12, 0x28, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6c, 0x61, 0x73, - 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0c, 0x68, - 0x74, 0x6c, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x68, 0x74, 0x6c, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x5f, 0x70, 0x32, 0x77, 0x73, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, - 0x68, 0x74, 0x6c, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x32, 0x77, 0x73, 0x68, - 0x12, 0x2e, 0x0a, 0x13, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x5f, 0x6e, 0x70, 0x32, 0x77, 0x73, 0x68, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x68, - 0x74, 0x6c, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4e, 0x70, 0x32, 0x77, 0x73, 0x68, - 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x73, 0x74, 0x5f, 0x6f, 0x6e, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x6f, 0x73, 0x74, 0x4f, 0x6e, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x73, 0x74, 0x5f, 0x6f, 0x66, 0x66, - 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x73, - 0x74, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x61, 0x73, - 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6c, 0x61, 0x73, - 0x74, 0x48, 0x6f, 0x70, 0x12, 0x2a, 0x0a, 0x11, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, - 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x11, 0x20, 0x03, 0x28, 0x04, 0x52, - 0x0f, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x53, 0x65, 0x74, - 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x12, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, - 0x61, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3e, 0x0a, 0x11, 0x4c, 0x69, - 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x29, 0x0a, 0x05, 0x73, 0x77, 0x61, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x05, 0x73, 0x77, 0x61, 0x70, 0x73, 0x22, 0x21, 0x0a, 0x0f, 0x53, 0x77, - 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x22, 0x0e, 0x0a, - 0x0c, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x7f, 0x0a, - 0x0f, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6d, 0x69, 0x6e, 0x53, 0x77, - 0x61, 0x70, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x5f, - 0x73, 0x77, 0x61, 0x70, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x53, 0x77, 0x61, 0x70, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x03, - 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x22, 0xcc, - 0x01, 0x0a, 0x10, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, - 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6d, 0x69, - 0x6e, 0x53, 0x77, 0x61, 0x70, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6d, - 0x61, 0x78, 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x53, 0x77, 0x61, 0x70, 0x41, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x6c, 0x74, 0x76, 0x5f, - 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x6d, 0x69, 0x6e, - 0x43, 0x6c, 0x74, 0x76, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x78, - 0x5f, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x43, 0x6c, 0x74, 0x76, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x4a, - 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x03, 0x10, - 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x22, 0xa8, 0x02, - 0x0a, 0x0c, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, - 0x0a, 0x03, 0x61, 0x6d, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x61, 0x6d, 0x74, - 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x54, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x68, 0x74, - 0x6c, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x48, 0x74, 0x6c, 0x63, 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x65, 0x61, 0x64, 0x6c, - 0x69, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x17, 0x73, 0x77, 0x61, 0x70, 0x50, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69, - 0x6e, 0x65, 0x12, 0x27, 0x0a, 0x10, 0x6c, 0x6f, 0x6f, 0x70, 0x5f, 0x69, 0x6e, 0x5f, 0x6c, 0x61, - 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x6c, 0x6f, - 0x6f, 0x70, 0x49, 0x6e, 0x4c, 0x61, 0x73, 0x74, 0x48, 0x6f, 0x70, 0x12, 0x41, 0x0a, 0x13, 0x6c, - 0x6f, 0x6f, 0x70, 0x5f, 0x69, 0x6e, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x68, 0x69, 0x6e, - 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x6c, 0x6f, - 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x18, - 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x22, 0xb0, 0x01, 0x0a, 0x0f, 0x49, 0x6e, 0x51, - 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0c, - 0x73, 0x77, 0x61, 0x70, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0a, 0x73, 0x77, 0x61, 0x70, 0x46, 0x65, 0x65, 0x53, 0x61, 0x74, 0x12, 0x2f, - 0x0a, 0x14, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f, 0x66, - 0x65, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x68, 0x74, - 0x6c, 0x63, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x46, 0x65, 0x65, 0x53, 0x61, 0x74, 0x12, - 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x09, 0x63, 0x6c, 0x74, 0x76, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x1f, - 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4a, - 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0xf3, 0x01, 0x0a, 0x10, - 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x20, 0x0a, 0x0c, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x61, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x73, 0x77, 0x61, 0x70, 0x46, 0x65, 0x65, 0x53, - 0x61, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x72, 0x65, 0x70, 0x61, 0x79, 0x5f, 0x61, 0x6d, 0x74, - 0x5f, 0x73, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x70, - 0x61, 0x79, 0x41, 0x6d, 0x74, 0x53, 0x61, 0x74, 0x12, 0x2b, 0x0a, 0x12, 0x68, 0x74, 0x6c, 0x63, - 0x5f, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x68, 0x74, 0x6c, 0x63, 0x53, 0x77, 0x65, 0x65, 0x70, 0x46, - 0x65, 0x65, 0x53, 0x61, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x70, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0f, 0x73, 0x77, 0x61, 0x70, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x73, - 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x63, 0x6c, 0x74, 0x76, 0x44, 0x65, 0x6c, 0x74, 0x61, - 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x54, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x22, 0x70, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6d, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, - 0x61, 0x6d, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6c, 0x61, 0x73, 0x74, 0x48, 0x6f, 0x70, 0x12, 0x33, - 0x0a, 0x0b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 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, 0x22, 0x0f, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3c, 0x0a, 0x0e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x4c, 0x73, 0x61, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x06, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x73, 0x22, 0xbb, 0x02, 0x0a, 0x09, 0x4c, 0x73, 0x61, 0x74, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x6d, 0x61, 0x63, 0x61, 0x72, 0x6f, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x62, 0x61, 0x73, 0x65, 0x4d, 0x61, - 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, - 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x65, 0x69, - 0x6d, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, - 0x61, 0x69, 0x64, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, - 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x69, 0x64, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x31, - 0x0a, 0x15, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x61, - 0x69, 0x64, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x72, - 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x46, 0x65, 0x65, 0x50, 0x61, 0x69, 0x64, 0x4d, 0x73, 0x61, - 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x12, 0x21, - 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, - 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, - 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8a, - 0x06, 0x0a, 0x13, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, - 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2c, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, - 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x72, - 0x75, 0x6c, 0x65, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x70, 0x6d, 0x18, - 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x66, 0x65, 0x65, 0x50, 0x70, 0x6d, 0x12, 0x3d, 0x0a, - 0x1c, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, - 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x17, 0x73, 0x77, 0x65, 0x65, 0x70, 0x46, 0x65, 0x65, 0x52, 0x61, 0x74, - 0x65, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x10, - 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x70, 0x6d, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x53, 0x77, 0x61, 0x70, 0x46, - 0x65, 0x65, 0x50, 0x70, 0x6d, 0x12, 0x2d, 0x0a, 0x13, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x6f, 0x75, - 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x70, 0x6d, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x46, 0x65, - 0x65, 0x50, 0x70, 0x6d, 0x12, 0x3a, 0x0a, 0x1a, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x72, 0x65, 0x70, - 0x61, 0x79, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70, - 0x70, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x65, - 0x70, 0x61, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x46, 0x65, 0x65, 0x50, 0x70, 0x6d, - 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x72, 0x65, 0x70, 0x61, 0x79, 0x5f, 0x73, - 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x65, - 0x70, 0x61, 0x79, 0x53, 0x61, 0x74, 0x12, 0x29, 0x0a, 0x11, 0x6d, 0x61, 0x78, 0x5f, 0x6d, 0x69, - 0x6e, 0x65, 0x72, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x4d, 0x69, 0x6e, 0x65, 0x72, 0x46, 0x65, 0x65, 0x53, 0x61, - 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x5f, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x73, 0x77, - 0x65, 0x65, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x2e, 0x0a, - 0x13, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, - 0x5f, 0x73, 0x65, 0x63, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x66, 0x61, 0x69, 0x6c, - 0x75, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x53, 0x65, 0x63, 0x12, 0x1a, 0x0a, - 0x08, 0x61, 0x75, 0x74, 0x6f, 0x6c, 0x6f, 0x6f, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x08, 0x61, 0x75, 0x74, 0x6f, 0x6c, 0x6f, 0x6f, 0x70, 0x12, 0x2e, 0x0a, 0x13, 0x61, 0x75, 0x74, - 0x6f, 0x6c, 0x6f, 0x6f, 0x70, 0x5f, 0x62, 0x75, 0x64, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x61, 0x74, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x61, 0x75, 0x74, 0x6f, 0x6c, 0x6f, 0x6f, 0x70, - 0x42, 0x75, 0x64, 0x67, 0x65, 0x74, 0x53, 0x61, 0x74, 0x12, 0x39, 0x0a, 0x19, 0x61, 0x75, 0x74, - 0x6f, 0x6c, 0x6f, 0x6f, 0x70, 0x5f, 0x62, 0x75, 0x64, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x61, 0x75, - 0x74, 0x6f, 0x6c, 0x6f, 0x6f, 0x70, 0x42, 0x75, 0x64, 0x67, 0x65, 0x74, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x53, 0x65, 0x63, 0x12, 0x2b, 0x0a, 0x12, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x6d, 0x61, 0x78, - 0x5f, 0x69, 0x6e, 0x5f, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x0f, 0x61, 0x75, 0x74, 0x6f, 0x4d, 0x61, 0x78, 0x49, 0x6e, 0x46, 0x6c, 0x69, 0x67, 0x68, - 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x69, 0x6e, 0x53, - 0x77, 0x61, 0x70, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x61, 0x78, - 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x53, 0x77, 0x61, 0x70, 0x41, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x12, 0x28, 0x0a, 0x10, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x68, 0x74, 0x6c, - 0x63, 0x43, 0x6f, 0x6e, 0x66, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x84, 0x02, 0x0a, 0x0d, - 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x1d, 0x0a, - 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x09, - 0x73, 0x77, 0x61, 0x70, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x11, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x54, 0x79, - 0x70, 0x65, 0x52, 0x08, 0x73, 0x77, 0x61, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, - 0x62, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x71, - 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, - 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x11, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, - 0x6f, 0x6c, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x5f, - 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x11, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, - 0x6c, 0x64, 0x22, 0x59, 0x0a, 0x19, 0x53, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, - 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x3c, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, - 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, - 0x73, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x22, 0x1c, 0x0a, - 0x1a, 0x53, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, - 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x53, - 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x22, 0x72, 0x0a, 0x0c, 0x44, 0x69, 0x73, 0x71, 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, - 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, - 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x2b, 0x0a, 0x06, 0x72, 0x65, 0x61, - 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x06, - 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0xb6, 0x01, 0x0a, 0x14, 0x53, 0x75, 0x67, 0x67, 0x65, + 0x2a, 0x0a, 0x11, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, + 0x70, 0x32, 0x74, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x68, 0x74, 0x6c, 0x63, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x32, 0x74, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x10, 0x0a, 0x0e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x22, 0xa7, 0x05, 0x0a, 0x0a, 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6d, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x03, 0x61, 0x6d, 0x74, 0x12, 0x12, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x64, 0x5f, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x69, 0x64, 0x42, + 0x79, 0x74, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, + 0x70, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x05, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3d, 0x0a, 0x0e, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, + 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, + 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x0d, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, 0x65, + 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x28, 0x0a, + 0x10, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0c, 0x68, 0x74, 0x6c, 0x63, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, + 0x01, 0x52, 0x0b, 0x68, 0x74, 0x6c, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2c, + 0x0a, 0x12, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x70, + 0x32, 0x77, 0x73, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x68, 0x74, 0x6c, 0x63, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x32, 0x77, 0x73, 0x68, 0x12, 0x2e, 0x0a, 0x13, + 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x6e, 0x70, 0x32, + 0x77, 0x73, 0x68, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x68, 0x74, 0x6c, 0x63, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4e, 0x70, 0x32, 0x77, 0x73, 0x68, 0x12, 0x2a, 0x0a, 0x11, + 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x70, 0x32, 0x74, + 0x72, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x68, 0x74, 0x6c, 0x63, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x50, 0x32, 0x74, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x73, 0x74, + 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, + 0x6f, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x73, + 0x74, 0x5f, 0x6f, 0x6e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0b, 0x63, 0x6f, 0x73, 0x74, 0x4f, 0x6e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x23, 0x0a, 0x0d, + 0x63, 0x6f, 0x73, 0x74, 0x5f, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x73, 0x74, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x18, 0x10, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6c, 0x61, 0x73, 0x74, 0x48, 0x6f, 0x70, 0x12, 0x2a, 0x0a, 0x11, + 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x73, 0x65, + 0x74, 0x18, 0x11, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0f, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, + 0x67, 0x43, 0x68, 0x61, 0x6e, 0x53, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x12, + 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x22, 0x3e, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x05, 0x73, 0x77, 0x61, 0x70, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, + 0x2e, 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x05, 0x73, 0x77, 0x61, + 0x70, 0x73, 0x22, 0x21, 0x0a, 0x0f, 0x53, 0x77, 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x02, 0x69, 0x64, 0x22, 0x0e, 0x0a, 0x0c, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x7f, 0x0a, 0x0f, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x69, 0x6e, 0x5f, + 0x73, 0x77, 0x61, 0x70, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0d, 0x6d, 0x69, 0x6e, 0x53, 0x77, 0x61, 0x70, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x53, 0x77, + 0x61, 0x70, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, + 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, + 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x22, 0xcc, 0x01, 0x0a, 0x10, 0x4f, 0x75, 0x74, 0x54, 0x65, + 0x72, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x6d, + 0x69, 0x6e, 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6d, 0x69, 0x6e, 0x53, 0x77, 0x61, 0x70, 0x41, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6d, 0x61, + 0x78, 0x53, 0x77, 0x61, 0x70, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x6d, + 0x69, 0x6e, 0x5f, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x43, 0x6c, 0x74, 0x76, 0x44, 0x65, 0x6c, 0x74, + 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x64, 0x65, + 0x6c, 0x74, 0x61, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x43, 0x6c, + 0x74, 0x76, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, + 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, + 0x04, 0x08, 0x07, 0x10, 0x08, 0x22, 0xa8, 0x02, 0x0a, 0x0c, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6d, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x03, 0x61, 0x6d, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, + 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x63, + 0x6f, 0x6e, 0x66, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x48, 0x74, 0x6c, 0x63, 0x12, 0x3a, + 0x0a, 0x19, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x64, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x17, 0x73, 0x77, 0x61, 0x70, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x27, 0x0a, 0x10, 0x6c, 0x6f, + 0x6f, 0x70, 0x5f, 0x69, 0x6e, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x6c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x4c, 0x61, 0x73, 0x74, + 0x48, 0x6f, 0x70, 0x12, 0x41, 0x0a, 0x13, 0x6c, 0x6f, 0x6f, 0x70, 0x5f, 0x69, 0x6e, 0x5f, 0x72, + 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x12, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, + 0x48, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x6c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x6f, 0x75, 0x74, + 0x65, 0x48, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, + 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, + 0x22, 0xb0, 0x01, 0x0a, 0x0f, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x66, 0x65, 0x65, + 0x5f, 0x73, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x73, 0x77, 0x61, 0x70, + 0x46, 0x65, 0x65, 0x53, 0x61, 0x74, 0x12, 0x2f, 0x0a, 0x14, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x68, 0x74, 0x6c, 0x63, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, + 0x68, 0x46, 0x65, 0x65, 0x53, 0x61, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x74, 0x76, 0x5f, + 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x63, 0x6c, 0x74, + 0x76, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x63, 0x6f, 0x6e, + 0x66, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, + 0x04, 0x10, 0x05, 0x22, 0xf3, 0x01, 0x0a, 0x10, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x73, 0x77, 0x61, 0x70, + 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, + 0x73, 0x77, 0x61, 0x70, 0x46, 0x65, 0x65, 0x53, 0x61, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x72, + 0x65, 0x70, 0x61, 0x79, 0x5f, 0x61, 0x6d, 0x74, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x70, 0x61, 0x79, 0x41, 0x6d, 0x74, 0x53, 0x61, 0x74, + 0x12, 0x2b, 0x0a, 0x12, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x66, + 0x65, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x68, 0x74, + 0x6c, 0x63, 0x53, 0x77, 0x65, 0x65, 0x70, 0x46, 0x65, 0x65, 0x53, 0x61, 0x74, 0x12, 0x2a, 0x0a, + 0x11, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x65, + 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x77, 0x61, 0x70, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x74, + 0x76, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x63, + 0x6c, 0x74, 0x76, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, + 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x63, + 0x6f, 0x6e, 0x66, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x70, 0x0a, 0x0c, 0x50, 0x72, 0x6f, + 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6d, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x61, 0x6d, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6c, + 0x61, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6c, + 0x61, 0x73, 0x74, 0x48, 0x6f, 0x70, 0x12, 0x33, 0x0a, 0x0b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, + 0x68, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 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, 0x22, 0x0f, 0x0a, 0x0d, 0x50, + 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0f, 0x0a, 0x0d, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3c, 0x0a, + 0x0e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x2a, 0x0a, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x12, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x73, 0x61, 0x74, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x52, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x22, 0xbb, 0x02, 0x0a, 0x09, + 0x4c, 0x73, 0x61, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x61, 0x73, + 0x65, 0x5f, 0x6d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0c, 0x62, 0x61, 0x73, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x12, 0x21, + 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, + 0x68, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x65, + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x70, 0x61, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x10, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x69, 0x64, 0x5f, 0x6d, 0x73, 0x61, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, + 0x69, 0x64, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x31, 0x0a, 0x15, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, + 0x67, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x61, 0x69, 0x64, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x46, 0x65, + 0x65, 0x50, 0x61, 0x69, 0x64, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x69, 0x6d, + 0x65, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, + 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, + 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x47, 0x65, 0x74, + 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8a, 0x06, 0x0a, 0x13, 0x4c, 0x69, 0x71, 0x75, 0x69, + 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2c, + 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, + 0x79, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x17, 0x0a, 0x07, + 0x66, 0x65, 0x65, 0x5f, 0x70, 0x70, 0x6d, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x66, + 0x65, 0x65, 0x50, 0x70, 0x6d, 0x12, 0x3d, 0x0a, 0x1c, 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x66, + 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, + 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x17, 0x73, 0x77, 0x65, + 0x65, 0x70, 0x46, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, + 0x62, 0x79, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x77, 0x61, 0x70, + 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x70, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, + 0x6d, 0x61, 0x78, 0x53, 0x77, 0x61, 0x70, 0x46, 0x65, 0x65, 0x50, 0x70, 0x6d, 0x12, 0x2d, 0x0a, + 0x13, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x65, 0x65, + 0x5f, 0x70, 0x70, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x52, + 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x46, 0x65, 0x65, 0x50, 0x70, 0x6d, 0x12, 0x3a, 0x0a, 0x1a, + 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x72, 0x65, 0x70, 0x61, 0x79, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x69, + 0x6e, 0x67, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x70, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x16, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x69, + 0x6e, 0x67, 0x46, 0x65, 0x65, 0x50, 0x70, 0x6d, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, + 0x70, 0x72, 0x65, 0x70, 0x61, 0x79, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x53, 0x61, 0x74, 0x12, 0x29, + 0x0a, 0x11, 0x6d, 0x61, 0x78, 0x5f, 0x6d, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x66, 0x65, 0x65, 0x5f, + 0x73, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x4d, 0x69, + 0x6e, 0x65, 0x72, 0x46, 0x65, 0x65, 0x53, 0x61, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x77, 0x65, + 0x65, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x73, 0x77, 0x65, 0x65, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x54, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, + 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x73, 0x65, 0x63, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x11, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x6f, + 0x66, 0x66, 0x53, 0x65, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x6c, 0x6f, 0x6f, + 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x6c, 0x6f, 0x6f, + 0x70, 0x12, 0x2e, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x6f, 0x6c, 0x6f, 0x6f, 0x70, 0x5f, 0x62, 0x75, + 0x64, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, + 0x61, 0x75, 0x74, 0x6f, 0x6c, 0x6f, 0x6f, 0x70, 0x42, 0x75, 0x64, 0x67, 0x65, 0x74, 0x53, 0x61, + 0x74, 0x12, 0x39, 0x0a, 0x19, 0x61, 0x75, 0x74, 0x6f, 0x6c, 0x6f, 0x6f, 0x70, 0x5f, 0x62, 0x75, + 0x64, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x18, 0x0c, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x61, 0x75, 0x74, 0x6f, 0x6c, 0x6f, 0x6f, 0x70, 0x42, 0x75, + 0x64, 0x67, 0x65, 0x74, 0x53, 0x74, 0x61, 0x72, 0x74, 0x53, 0x65, 0x63, 0x12, 0x2b, 0x0a, 0x12, + 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x6e, 0x5f, 0x66, 0x6c, 0x69, 0x67, + 0x68, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x61, 0x75, 0x74, 0x6f, 0x4d, 0x61, + 0x78, 0x49, 0x6e, 0x46, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x69, 0x6e, + 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0e, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x69, 0x6e, 0x53, 0x77, 0x61, 0x70, 0x41, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x53, + 0x77, 0x61, 0x70, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x68, 0x74, 0x6c, + 0x63, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x11, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x0e, 0x68, 0x74, 0x6c, 0x63, 0x43, 0x6f, 0x6e, 0x66, 0x54, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x22, 0x84, 0x02, 0x0a, 0x0d, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, + 0x79, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x09, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x73, 0x77, 0x61, 0x70, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x52, 0x75, + 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x12, + 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, + 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, + 0x6e, 0x67, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x6f, + 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, + 0x67, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0x59, 0x0a, 0x19, 0x53, 0x65, + 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, + 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, + 0x65, 0x74, 0x65, 0x72, 0x73, 0x22, 0x1c, 0x0a, 0x1a, 0x53, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, + 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x53, 0x77, + 0x61, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x72, 0x0a, 0x0c, 0x44, 0x69, + 0x73, 0x71, 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, + 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, + 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, + 0x79, 0x12, 0x2b, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x75, 0x74, 0x6f, + 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0xb6, + 0x01, 0x0a, 0x14, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x08, 0x6c, 0x6f, 0x6f, 0x70, 0x5f, + 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x52, 0x07, 0x6c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x6c, + 0x6f, 0x6f, 0x70, 0x5f, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x52, 0x06, 0x6c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x12, 0x39, 0x0a, 0x0c, + 0x64, 0x69, 0x73, 0x71, 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69, 0x73, + 0x71, 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x71, 0x75, + 0x61, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2a, 0x25, 0x0a, 0x08, 0x53, 0x77, 0x61, 0x70, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, + 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x01, 0x2a, 0x73, + 0x0a, 0x09, 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x49, + 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x50, 0x52, + 0x45, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x45, 0x56, 0x45, 0x41, 0x4c, 0x45, 0x44, 0x10, + 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, + 0x48, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, + 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x13, + 0x0a, 0x0f, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, + 0x44, 0x10, 0x05, 0x2a, 0xed, 0x01, 0x0a, 0x0d, 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, 0x1b, + 0x0a, 0x17, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, + 0x5f, 0x4f, 0x46, 0x46, 0x43, 0x48, 0x41, 0x49, 0x4e, 0x10, 0x01, 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, 0x02, 0x12, 0x20, 0x0a, 0x1c, 0x46, 0x41, 0x49, 0x4c, 0x55, + 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x57, 0x45, 0x45, 0x50, 0x5f, + 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x03, 0x12, 0x25, 0x0a, 0x21, 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, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x04, + 0x12, 0x1c, 0x0a, 0x18, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, + 0x4f, 0x4e, 0x5f, 0x54, 0x45, 0x4d, 0x50, 0x4f, 0x52, 0x41, 0x52, 0x59, 0x10, 0x05, 0x12, 0x23, + 0x0a, 0x1f, 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, 0x41, 0x4d, 0x4f, 0x55, 0x4e, + 0x54, 0x10, 0x06, 0x2a, 0x2f, 0x0a, 0x11, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, + 0x52, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, + 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x48, 0x52, 0x45, 0x53, 0x48, 0x4f, + 0x4c, 0x44, 0x10, 0x01, 0x2a, 0xa6, 0x03, 0x0a, 0x0a, 0x41, 0x75, 0x74, 0x6f, 0x52, 0x65, 0x61, + 0x73, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, + 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x22, 0x0a, 0x1e, + 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x42, 0x55, 0x44, 0x47, + 0x45, 0x54, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x01, + 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, + 0x53, 0x57, 0x45, 0x45, 0x50, 0x5f, 0x46, 0x45, 0x45, 0x53, 0x10, 0x02, 0x12, 0x1e, 0x0a, 0x1a, + 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x42, 0x55, 0x44, 0x47, + 0x45, 0x54, 0x5f, 0x45, 0x4c, 0x41, 0x50, 0x53, 0x45, 0x44, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, + 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x5f, 0x46, + 0x4c, 0x49, 0x47, 0x48, 0x54, 0x10, 0x04, 0x12, 0x18, 0x0a, 0x14, 0x41, 0x55, 0x54, 0x4f, 0x5f, + 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x57, 0x41, 0x50, 0x5f, 0x46, 0x45, 0x45, 0x10, + 0x05, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, + 0x5f, 0x4d, 0x49, 0x4e, 0x45, 0x52, 0x5f, 0x46, 0x45, 0x45, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, + 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x50, 0x52, 0x45, 0x50, + 0x41, 0x59, 0x10, 0x07, 0x12, 0x1f, 0x0a, 0x1b, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, + 0x53, 0x4f, 0x4e, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x42, 0x41, 0x43, 0x4b, + 0x4f, 0x46, 0x46, 0x10, 0x08, 0x12, 0x18, 0x0a, 0x14, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, + 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x09, 0x12, + 0x17, 0x0a, 0x13, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4c, + 0x4f, 0x4f, 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x0a, 0x12, 0x1c, 0x0a, 0x18, 0x41, 0x55, 0x54, 0x4f, + 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4c, 0x49, 0x51, 0x55, 0x49, 0x44, 0x49, 0x54, + 0x59, 0x5f, 0x4f, 0x4b, 0x10, 0x0b, 0x12, 0x23, 0x0a, 0x1f, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, + 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x42, 0x55, 0x44, 0x47, 0x45, 0x54, 0x5f, 0x49, 0x4e, 0x53, + 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x10, 0x0c, 0x12, 0x20, 0x0a, 0x1c, 0x41, + 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x49, + 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x10, 0x0d, 0x32, 0xc2, 0x07, + 0x0a, 0x0a, 0x53, 0x77, 0x61, 0x70, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x07, + 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x12, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x4c, 0x6f, 0x6f, 0x70, 0x49, + 0x6e, 0x12, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x70, + 0x49, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x39, 0x0a, 0x07, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x12, 0x17, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x30, 0x01, 0x12, 0x42, 0x0a, 0x09, 0x4c, + 0x69, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x32, 0x0a, 0x08, 0x6c, 0x6f, 0x6f, 0x70, 0x5f, 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x70, - 0x4f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x6c, 0x6f, 0x6f, 0x70, - 0x4f, 0x75, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x6c, 0x6f, 0x6f, 0x70, 0x5f, 0x69, 0x6e, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, - 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x06, 0x6c, 0x6f, - 0x6f, 0x70, 0x49, 0x6e, 0x12, 0x39, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x71, 0x75, 0x61, 0x6c, 0x69, - 0x66, 0x69, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69, 0x73, 0x71, 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, 0x65, - 0x64, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x71, 0x75, 0x61, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2a, - 0x25, 0x0a, 0x08, 0x53, 0x77, 0x61, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x4c, - 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x4c, 0x4f, 0x4f, - 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x01, 0x2a, 0x73, 0x0a, 0x09, 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x45, 0x44, - 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x50, 0x52, 0x45, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x52, - 0x45, 0x56, 0x45, 0x41, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x48, 0x54, 0x4c, - 0x43, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0b, 0x0a, - 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, - 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, - 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, 0x44, 0x10, 0x05, 0x2a, 0xed, 0x01, 0x0a, 0x0d, - 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, 0x1b, 0x0a, 0x17, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, - 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4f, 0x46, 0x46, 0x43, 0x48, 0x41, 0x49, - 0x4e, 0x10, 0x01, 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, 0x02, 0x12, - 0x20, 0x0a, 0x1c, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, - 0x4e, 0x5f, 0x53, 0x57, 0x45, 0x45, 0x50, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, - 0x03, 0x12, 0x25, 0x0a, 0x21, 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, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x04, 0x12, 0x1c, 0x0a, 0x18, 0x46, 0x41, 0x49, 0x4c, - 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x54, 0x45, 0x4d, 0x50, 0x4f, - 0x52, 0x41, 0x52, 0x59, 0x10, 0x05, 0x12, 0x23, 0x0a, 0x1f, 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, 0x41, 0x4d, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x06, 0x2a, 0x2f, 0x0a, 0x11, 0x4c, - 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0d, 0x0a, - 0x09, 0x54, 0x48, 0x52, 0x45, 0x53, 0x48, 0x4f, 0x4c, 0x44, 0x10, 0x01, 0x2a, 0xa6, 0x03, 0x0a, - 0x0a, 0x41, 0x75, 0x74, 0x6f, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x13, 0x41, - 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, - 0x57, 0x4e, 0x10, 0x00, 0x12, 0x22, 0x0a, 0x1e, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, - 0x53, 0x4f, 0x4e, 0x5f, 0x42, 0x55, 0x44, 0x47, 0x45, 0x54, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x53, - 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x55, 0x54, 0x4f, - 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x57, 0x45, 0x45, 0x50, 0x5f, 0x46, 0x45, - 0x45, 0x53, 0x10, 0x02, 0x12, 0x1e, 0x0a, 0x1a, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, - 0x53, 0x4f, 0x4e, 0x5f, 0x42, 0x55, 0x44, 0x47, 0x45, 0x54, 0x5f, 0x45, 0x4c, 0x41, 0x50, 0x53, - 0x45, 0x44, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, - 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x5f, 0x46, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x10, 0x04, 0x12, - 0x18, 0x0a, 0x14, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x53, - 0x57, 0x41, 0x50, 0x5f, 0x46, 0x45, 0x45, 0x10, 0x05, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x55, 0x54, - 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x49, 0x4e, 0x45, 0x52, 0x5f, 0x46, - 0x45, 0x45, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, - 0x53, 0x4f, 0x4e, 0x5f, 0x50, 0x52, 0x45, 0x50, 0x41, 0x59, 0x10, 0x07, 0x12, 0x1f, 0x0a, 0x1b, - 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x46, 0x41, 0x49, 0x4c, - 0x55, 0x52, 0x45, 0x5f, 0x42, 0x41, 0x43, 0x4b, 0x4f, 0x46, 0x46, 0x10, 0x08, 0x12, 0x18, 0x0a, - 0x14, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4c, 0x4f, 0x4f, - 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x09, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x55, 0x54, 0x4f, 0x5f, - 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x0a, - 0x12, 0x1c, 0x0a, 0x18, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, - 0x4c, 0x49, 0x51, 0x55, 0x49, 0x44, 0x49, 0x54, 0x59, 0x5f, 0x4f, 0x4b, 0x10, 0x0b, 0x12, 0x23, - 0x0a, 0x1f, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x42, 0x55, - 0x44, 0x47, 0x45, 0x54, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, - 0x54, 0x10, 0x0c, 0x12, 0x20, 0x0a, 0x1c, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, - 0x4f, 0x4e, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, - 0x45, 0x4e, 0x54, 0x10, 0x0d, 0x32, 0xc2, 0x07, 0x0a, 0x0a, 0x53, 0x77, 0x61, 0x70, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x07, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x12, - 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x37, 0x0a, 0x06, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x12, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x07, 0x4d, 0x6f, 0x6e, 0x69, - 0x74, 0x6f, 0x72, 0x12, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x6f, - 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x30, 0x01, 0x12, 0x42, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, - 0x12, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, - 0x77, 0x61, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x08, 0x53, 0x77, 0x61, 0x70, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, - 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, - 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x12, 0x40, 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, - 0x6d, 0x73, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x65, 0x72, - 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, - 0x75, 0x6f, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x51, - 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x6f, - 0x70, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x47, 0x65, 0x74, - 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x51, - 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x05, - 0x50, 0x72, 0x6f, 0x62, 0x65, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, - 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4c, 0x73, 0x61, 0x74, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, + 0x39, 0x0a, 0x08, 0x53, 0x77, 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x40, 0x0a, 0x0c, 0x4c, 0x6f, + 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x54, + 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0c, + 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, + 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, + 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, + 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, + 0x6f, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, + 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x12, 0x15, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, + 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0d, + 0x47, 0x65, 0x74, 0x4c, 0x73, 0x61, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x71, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, + 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, + 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x5d, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x22, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, + 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x71, 0x75, 0x69, - 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x5d, - 0x0a, 0x12, 0x53, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x73, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, - 0x0c, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x12, 0x1c, 0x2e, - 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x53, - 0x77, 0x61, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x53, 0x77, 0x61, - 0x70, 0x73, 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, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, - 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x1a, 0x23, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x4c, 0x69, + 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0c, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, + 0x53, 0x77, 0x61, 0x70, 0x73, 0x12, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, + 0x67, 0x67, 0x65, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 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, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6c, + 0x6f, 0x6f, 0x70, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( diff --git a/looprpc/client.proto b/looprpc/client.proto index 7856c0d..26d41a2 100644 --- a/looprpc/client.proto +++ b/looprpc/client.proto @@ -317,6 +317,9 @@ message SwapResponse { */ string htlc_address_p2wsh = 5; + // The address of the v3 (taproot) htlc. Used for both loop-in and loop-out. + string htlc_address_p2tr = 7; + // A human-readable message received from the loop server. string server_message = 6; } @@ -387,6 +390,9 @@ message SwapStatus { // HTLC address (nested segwit), used in loop-in swaps only. string htlc_address_np2wsh = 13; + // The address of the v3 (taproot) htlc. Used for both loop-in and loop-out. + string htlc_address_p2tr = 18; + // Swap server cost int64 cost_server = 8; diff --git a/looprpc/client.swagger.json b/looprpc/client.swagger.json index 9f20c54..5e43d6c 100644 --- a/looprpc/client.swagger.json +++ b/looprpc/client.swagger.json @@ -1044,6 +1044,10 @@ "type": "string", "description": "The native segwit address of the on-chain htlc.\nUsed for both loop-in and loop-out." }, + "htlc_address_p2tr": { + "type": "string", + "description": "The address of the v3 (taproot) htlc. Used for both loop-in and loop-out." + }, "server_message": { "type": "string", "description": "A human-readable message received from the loop server." @@ -1114,6 +1118,10 @@ "type": "string", "description": "HTLC address (nested segwit), used in loop-in swaps only." }, + "htlc_address_p2tr": { + "type": "string", + "description": "The address of the v3 (taproot) htlc. Used for both loop-in and loop-out." + }, "cost_server": { "type": "string", "format": "int64", diff --git a/swap.go b/swap.go index bfb034c..56dc8fa 100644 --- a/swap.go +++ b/swap.go @@ -73,6 +73,12 @@ func GetHtlcScriptVersion( return swap.HtlcV3 } +// IsTaproot returns true if the swap referenced by the passed swap contract +// uses the v3 (taproot) htlc. +func IsTaprootSwap(swapContract *loopdb.SwapContract) bool { + return GetHtlcScriptVersion(swapContract.ProtocolVersion) == swap.HtlcV3 +} + // getHtlc composes and returns the on-chain swap script. func (s *swapKit) getHtlc(outputType swap.HtlcOutputType) (*swap.Htlc, error) { return swap.NewHtlc( From 391ef57ea34d9684d018f49a285242e8cec3fe2a Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Sun, 24 Apr 2022 22:59:59 +0200 Subject: [PATCH 06/17] loopout: enable p2tr without keyspend --- client.go | 43 +++++++++++++------- client_test.go | 20 ++++++++-- interface.go | 6 +-- liquidity/liquidity.go | 3 +- loopd/swapclient_server.go | 31 ++++++++++----- loopout.go | 24 ++++++++--- loopout_test.go | 81 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 171 insertions(+), 37 deletions(-) diff --git a/client.go b/client.go index e43dee4..d34dfb4 100644 --- a/client.go +++ b/client.go @@ -192,24 +192,39 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) { swaps := make([]*SwapInfo, 0, len(loopInSwaps)+len(loopOutSwaps)) for _, swp := range loopOutSwaps { + swapInfo := &SwapInfo{ + SwapType: swap.TypeOut, + SwapContract: swp.Contract.SwapContract, + SwapStateData: swp.State(), + SwapHash: swp.Hash, + LastUpdate: swp.LastUpdateTime(), + } + scriptVersion := GetHtlcScriptVersion( + swp.Contract.ProtocolVersion, + ) + + outputType := swap.HtlcP2WSH + if scriptVersion == swap.HtlcV3 { + outputType = swap.HtlcP2TR + } + htlc, err := swap.NewHtlc( - GetHtlcScriptVersion(swp.Contract.ProtocolVersion), + scriptVersion, swp.Contract.CltvExpiry, swp.Contract.SenderKey, - swp.Contract.ReceiverKey, swp.Hash, swap.HtlcP2WSH, - s.lndServices.ChainParams, + swp.Contract.ReceiverKey, swp.Hash, + outputType, s.lndServices.ChainParams, ) if err != nil { return nil, err } - swaps = append(swaps, &SwapInfo{ - SwapType: swap.TypeOut, - SwapContract: swp.Contract.SwapContract, - SwapStateData: swp.State(), - SwapHash: swp.Hash, - LastUpdate: swp.LastUpdateTime(), - HtlcAddressP2WSH: htlc.Address, - }) + if outputType == swap.HtlcP2TR { + swapInfo.HtlcAddressP2TR = htlc.Address + } else { + swapInfo.HtlcAddressP2WSH = htlc.Address + } + + swaps = append(swaps, swapInfo) } for _, swp := range loopInSwaps { @@ -426,9 +441,9 @@ func (s *Client) LoopOut(globalCtx context.Context, // Return hash so that the caller can identify this swap in the updates // stream. return &LoopOutSwapInfo{ - SwapHash: swap.hash, - HtlcAddressP2WSH: swap.htlc.Address, - ServerMessage: initResult.serverMessage, + SwapHash: swap.hash, + HtlcAddress: swap.htlc.Address, + ServerMessage: initResult.serverMessage, }, nil } diff --git a/client_test.go b/client_test.go index b12f1bf..7a77f10 100644 --- a/client_test.go +++ b/client_test.go @@ -159,6 +159,7 @@ func TestLoopOutResume(t *testing.T) { storedVersion := []loopdb.ProtocolVersion{ loopdb.ProtocolVersionUnrecorded, loopdb.ProtocolVersionHtlcV2, + loopdb.ProtocolVersionHtlcV3, } for _, version := range storedVersion { @@ -283,9 +284,15 @@ func testLoopOutResume(t *testing.T, confs uint32, expired, preimageRevealed, // Assert that the loopout htlc equals to the expected one. scriptVersion := GetHtlcScriptVersion(protocolVersion) + + outputType := swap.HtlcP2TR + if scriptVersion != swap.HtlcV3 { + outputType = swap.HtlcP2WSH + } + htlc, err := swap.NewHtlc( scriptVersion, pendingSwap.Contract.CltvExpiry, senderKey, - receiverKey, hash, swap.HtlcP2WSH, &chaincfg.TestNet3Params, + receiverKey, hash, outputType, &chaincfg.TestNet3Params, ) require.NoError(t, err) require.Equal(t, htlc.PkScript, confIntent.PkScript) @@ -345,8 +352,15 @@ func testLoopOutSuccess(ctx *testContext, amt btcutil.Amount, hash lntypes.Hash, ctx.T.Fatalf("client not sweeping from htlc tx") } - preImageIndex := 1 - if scriptVersion == swap.HtlcV2 { + var preImageIndex int + switch scriptVersion { + case swap.HtlcV1: + preImageIndex = 1 + + case swap.HtlcV2: + preImageIndex = 0 + + case swap.HtlcV3: preImageIndex = 0 } diff --git a/interface.go b/interface.go index 9318d54..72b3e0e 100644 --- a/interface.go +++ b/interface.go @@ -312,9 +312,9 @@ type LoopOutSwapInfo struct { // nolint:revive // SwapHash contains the sha256 hash of the swap preimage. SwapHash lntypes.Hash - // HtlcAddressP2WSH contains the native segwit swap htlc address that - // the server will publish to. - HtlcAddressP2WSH btcutil.Address + // HtlcAddress contains the swap htlc address that the server will + // publish to. + HtlcAddress btcutil.Address // ServerMessages is the human-readable message received from the loop // server. diff --git a/liquidity/liquidity.go b/liquidity/liquidity.go index 59d6426..360e35c 100644 --- a/liquidity/liquidity.go +++ b/liquidity/liquidity.go @@ -386,8 +386,7 @@ func (m *Manager) autoloop(ctx context.Context) error { } log.Infof("loop out automatically dispatched: hash: %v, "+ - "address: %v", loopOut.SwapHash, - loopOut.HtlcAddressP2WSH) + "address: %v", loopOut.SwapHash, loopOut.HtlcAddress) } for _, in := range suggestion.InSwaps { diff --git a/loopd/swapclient_server.go b/loopd/swapclient_server.go index f97bfc6..d2bfbb6 100644 --- a/loopd/swapclient_server.go +++ b/loopd/swapclient_server.go @@ -150,13 +150,21 @@ func (s *swapClientServer) LoopOut(ctx context.Context, return nil, err } - return &clientrpc.SwapResponse{ - Id: info.SwapHash.String(), - IdBytes: info.SwapHash[:], - HtlcAddress: info.HtlcAddressP2WSH.String(), - HtlcAddressP2Wsh: info.HtlcAddressP2WSH.String(), - ServerMessage: info.ServerMessage, - }, nil + htlcAddress := info.HtlcAddress.String() + resp := &clientrpc.SwapResponse{ + Id: info.SwapHash.String(), + IdBytes: info.SwapHash[:], + HtlcAddress: htlcAddress, + ServerMessage: info.ServerMessage, + } + + if loopdb.CurrentProtocolVersion() < loopdb.ProtocolVersionHtlcV3 { + resp.HtlcAddressP2Wsh = htlcAddress + } else { + resp.HtlcAddressP2Tr = htlcAddress + } + + return resp, nil } func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) ( @@ -252,8 +260,13 @@ func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) ( case swap.TypeOut: swapType = clientrpc.SwapType_LOOP_OUT - htlcAddressP2WSH = loopSwap.HtlcAddressP2WSH.EncodeAddress() - htlcAddress = htlcAddressP2WSH + if loopSwap.HtlcAddressP2WSH != nil { + htlcAddressP2WSH = loopSwap.HtlcAddressP2WSH.EncodeAddress() + htlcAddress = htlcAddressP2WSH + } else { + htlcAddressP2TR = loopSwap.HtlcAddressP2TR.EncodeAddress() + htlcAddress = htlcAddressP2TR + } outGoingChanSet = loopSwap.OutgoingChanSet diff --git a/loopout.go b/loopout.go index 10d01de..56d679d 100644 --- a/loopout.go +++ b/loopout.go @@ -183,14 +183,20 @@ func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig, } swapKit := newSwapKit( - swapHash, swap.TypeOut, - cfg, &contract.SwapContract, + swapHash, swap.TypeOut, cfg, &contract.SwapContract, ) swapKit.lastUpdateTime = initiationTime + scriptVersion := GetHtlcScriptVersion(loopdb.CurrentProtocolVersion()) + outputType := swap.HtlcP2TR + if scriptVersion != swap.HtlcV3 { + // Default to using P2WSH for legacy htlcs. + outputType = swap.HtlcP2WSH + } + // Create the htlc. - htlc, err := swapKit.getHtlc(swap.HtlcP2WSH) + htlc, err := swapKit.getHtlc(outputType) if err != nil { return nil, err } @@ -239,12 +245,18 @@ func resumeLoopOutSwap(reqContext context.Context, cfg *swapConfig, log.Infof("Resuming loop out swap %v", hash) swapKit := newSwapKit( - hash, swap.TypeOut, cfg, - &pend.Contract.SwapContract, + hash, swap.TypeOut, cfg, &pend.Contract.SwapContract, ) + scriptVersion := GetHtlcScriptVersion(pend.Contract.ProtocolVersion) + outputType := swap.HtlcP2TR + if scriptVersion != swap.HtlcV3 { + // Default to using P2WSH for legacy htlcs. + outputType = swap.HtlcP2WSH + } + // Create the htlc. - htlc, err := swapKit.getHtlc(swap.HtlcP2WSH) + htlc, err := swapKit.getHtlc(outputType) if err != nil { return nil, err } diff --git a/loopout_test.go b/loopout_test.go index 8350a5a..e821aaa 100644 --- a/loopout_test.go +++ b/loopout_test.go @@ -24,6 +24,22 @@ import ( // TestLoopOutPaymentParameters tests the first part of the loop out process up // to the point where the off-chain payments are made. func TestLoopOutPaymentParameters(t *testing.T) { + t.Run("stable protocol", func(t *testing.T) { + testLoopOutPaymentParameters(t) + }) + + t.Run("experimental protocol", func(t *testing.T) { + loopdb.EnableExperimentalProtocol() + defer loopdb.ResetCurrentProtocolVersion() + + testLoopOutPaymentParameters(t) + }) +} + +// TestLoopOutPaymentParameters tests the first part of the loop out process up +// to the point where the off-chain payments are made. +func testLoopOutPaymentParameters(t *testing.T) { + defer test.Guard(t)() // Set up test context objects. @@ -144,6 +160,19 @@ func TestLoopOutPaymentParameters(t *testing.T) { // TestLateHtlcPublish tests that the client is not revealing the preimage if // there are not enough blocks left. func TestLateHtlcPublish(t *testing.T) { + t.Run("stable protocol", func(t *testing.T) { + testLateHtlcPublish(t) + }) + + t.Run("experimental protocol", func(t *testing.T) { + loopdb.EnableExperimentalProtocol() + defer loopdb.ResetCurrentProtocolVersion() + + testLateHtlcPublish(t) + }) +} + +func testLateHtlcPublish(t *testing.T) { defer test.Guard(t)() lnd := test.NewMockLnd() @@ -232,6 +261,19 @@ func TestLateHtlcPublish(t *testing.T) { // TestCustomSweepConfTarget ensures we are able to sweep a Loop Out HTLC with a // custom confirmation target. func TestCustomSweepConfTarget(t *testing.T) { + t.Run("stable protocol", func(t *testing.T) { + testCustomSweepConfTarget(t) + }) + + t.Run("experimental protocol", func(t *testing.T) { + loopdb.EnableExperimentalProtocol() + defer loopdb.ResetCurrentProtocolVersion() + + testCustomSweepConfTarget(t) + }) +} + +func testCustomSweepConfTarget(t *testing.T) { defer test.Guard(t)() lnd := test.NewMockLnd() @@ -433,6 +475,19 @@ func TestCustomSweepConfTarget(t *testing.T) { // to start with a fee rate that will be too high, then progress to an // acceptable one. func TestPreimagePush(t *testing.T) { + t.Run("stable protocol", func(t *testing.T) { + testPreimagePush(t) + }) + + t.Run("experimental protocol", func(t *testing.T) { + loopdb.EnableExperimentalProtocol() + defer loopdb.ResetCurrentProtocolVersion() + + testPreimagePush(t) + }) +} + +func testPreimagePush(t *testing.T) { defer test.Guard(t)() lnd := test.NewMockLnd() @@ -604,6 +659,19 @@ func TestPreimagePush(t *testing.T) { // we have revealed our preimage, demonstrating that we do not reveal our // preimage once we've reached our expiry height. func TestExpiryBeforeReveal(t *testing.T) { + t.Run("stable protocol", func(t *testing.T) { + testExpiryBeforeReveal(t) + }) + + t.Run("experimental protocol", func(t *testing.T) { + loopdb.EnableExperimentalProtocol() + defer loopdb.ResetCurrentProtocolVersion() + + testExpiryBeforeReveal(t) + }) +} + +func testExpiryBeforeReveal(t *testing.T) { defer test.Guard(t)() lnd := test.NewMockLnd() @@ -719,6 +787,19 @@ func TestExpiryBeforeReveal(t *testing.T) { // TestFailedOffChainCancelation tests sending of a cancelation message to // the server when a swap fails due to off-chain routing. func TestFailedOffChainCancelation(t *testing.T) { + t.Run("stable protocol", func(t *testing.T) { + testFailedOffChainCancelation(t) + }) + + t.Run("experimental protocol", func(t *testing.T) { + loopdb.EnableExperimentalProtocol() + defer loopdb.ResetCurrentProtocolVersion() + + testFailedOffChainCancelation(t) + }) +} + +func testFailedOffChainCancelation(t *testing.T) { defer test.Guard(t)() lnd := test.NewMockLnd() From bf59159ddbcfcec86e4c3079624cf49a10c425d2 Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Mon, 16 May 2022 18:37:53 +0200 Subject: [PATCH 07/17] client: LoopOutQuote to support estimate using v3 htlc --- client.go | 40 +++++++++++++++++++++++++++------------- swap/htlc.go | 29 +++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/client.go b/client.go index d34dfb4..498378e 100644 --- a/client.go +++ b/client.go @@ -499,7 +499,23 @@ func (s *Client) LoopOutQuote(ctx context.Context, log.Infof("Offchain swap destination: %x", quote.SwapPaymentDest) - swapFee := quote.SwapFee + minerFee, err := s.getLoopOutSweepFee(ctx, request.SweepConfTarget) + if err != nil { + return nil, err + } + + return &LoopOutQuote{ + SwapFee: quote.SwapFee, + MinerFee: minerFee, + PrepayAmount: quote.PrepayAmount, + SwapPaymentDest: quote.SwapPaymentDest, + }, nil +} + +// getLoopOutSweepFee is a helper method to estimate the loop out htlc sweep +// fee to a p2wsh address. +func (s *Client) getLoopOutSweepFee(ctx context.Context, confTarget int32) ( + btcutil.Amount, error) { // Generate dummy p2wsh address for fee estimation. The p2wsh address // type is chosen because it adds the most weight of all output types @@ -509,23 +525,21 @@ func (s *Client) LoopOutQuote(ctx context.Context, wsh[:], s.lndServices.ChainParams, ) if err != nil { - return nil, err + return 0, err } - minerFee, err := s.sweeper.GetSweepFee( - ctx, swap.QuoteHtlc.AddSuccessToEstimator, - p2wshAddress, request.SweepConfTarget, + scriptVersion := GetHtlcScriptVersion( + loopdb.CurrentProtocolVersion(), ) - if err != nil { - return nil, err + + htlc := swap.QuoteHtlcP2TR + if scriptVersion != swap.HtlcV3 { + htlc = swap.QuoteHtlcP2WSH } - return &LoopOutQuote{ - SwapFee: swapFee, - MinerFee: minerFee, - PrepayAmount: quote.PrepayAmount, - SwapPaymentDest: quote.SwapPaymentDest, - }, nil + return s.sweeper.GetSweepFee( + ctx, htlc.AddSuccessToEstimator, p2wshAddress, confTarget, + ) } // LoopOutTerms returns the terms on which the server executes swaps. diff --git a/swap/htlc.go b/swap/htlc.go index 56d9618..5df0309 100644 --- a/swap/htlc.go +++ b/swap/htlc.go @@ -108,17 +108,30 @@ type Htlc struct { } var ( - quoteKey [33]byte + // dummyPubKey is a valid public key use for the quote htlc + // construction. + dummyPubKey = [33]byte{ + 0x03, 0x26, 0x89, 0xc7, 0xc2, 0xda, 0xb1, 0x33, 0x09, 0xfb, + 0x14, 0x3e, 0x0e, 0x8f, 0xe3, 0x96, 0x34, 0x25, 0x21, 0x88, + 0x7e, 0x97, 0x66, 0x90, 0xb6, 0xb4, 0x7f, 0x5b, 0x2a, 0x4b, + 0x7d, 0x44, 0x8e, + } + // quoteHash is an empty hash used for the quote htlc construction. quoteHash lntypes.Hash - // QuoteHtlc is a template script just used for fee estimation. It uses - // the maximum value for cltv expiry to get the maximum (worst case) - // script size. - QuoteHtlc, _ = NewHtlc( - HtlcV2, - ^int32(0), quoteKey, quoteKey, quoteHash, HtlcP2WSH, - &chaincfg.MainNetParams, + // QuoteHtlcP2WSH is a template script just used for sweep fee + // estimation. + QuoteHtlcP2WSH, _ = NewHtlc( + HtlcV2, ^int32(0), dummyPubKey, dummyPubKey, quoteHash, + HtlcP2WSH, &chaincfg.MainNetParams, + ) + + // QuoteHtlcP2TR is a template script just used for sweep fee + // estimation. + QuoteHtlcP2TR, _ = NewHtlc( + HtlcV3, ^int32(0), dummyPubKey, dummyPubKey, quoteHash, + HtlcP2TR, &chaincfg.MainNetParams, ) // ErrInvalidScriptVersion is returned when an unknown htlc version From ce3026daa940b00766759588db877133d25de95b Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Mon, 16 May 2022 18:38:50 +0200 Subject: [PATCH 08/17] client: LoopInQuote to support v3 htlc for fee estimate --- client.go | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/client.go b/client.go index 498378e..bec66a2 100644 --- a/client.go +++ b/client.go @@ -682,7 +682,7 @@ func (s *Client) LoopInQuote(ctx context.Context, // // TODO(guggero): Thread through error code from lnd to avoid string // matching. - minerFee, err := s.lndServices.Client.EstimateFeeToP2WSH( + minerFee, err := s.estimateFee( ctx, request.Amount, request.HtlcConfTarget, ) if err != nil && strings.Contains(err.Error(), "insufficient funds") { @@ -703,6 +703,39 @@ func (s *Client) LoopInQuote(ctx context.Context, }, nil } +// estimateFee is a helper method to estimate the total fee for paying the +// passed amount with the given conf target. It'll assume taproot destination +// if the protocol version indicates that we're using taproot htlcs. +func (s *Client) estimateFee(ctx context.Context, amt btcutil.Amount, + confTarget int32) (btcutil.Amount, error) { + + var ( + address btcutil.Address + err error + ) + // Generate a dummy address for fee estimation. + witnessProg := [32]byte{} + + scriptVersion := GetHtlcScriptVersion( + loopdb.CurrentProtocolVersion(), + ) + + if scriptVersion != swap.HtlcV3 { + address, err = btcutil.NewAddressWitnessScriptHash( + witnessProg[:], s.lndServices.ChainParams, + ) + } else { + address, err = btcutil.NewAddressTaproot( + witnessProg[:], s.lndServices.ChainParams, + ) + } + if err != nil { + return 0, err + } + + return s.lndServices.Client.EstimateFee(ctx, address, amt, confTarget) +} + // LoopInTerms returns the terms on which the server executes swaps. func (s *Client) LoopInTerms(ctx context.Context) ( *LoopInTerms, error) { From a252e2c706639823fbafe8f26467542b19ec1730 Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Sun, 24 Apr 2022 22:32:17 +0200 Subject: [PATCH 09/17] loopdb: add the local pubkey's keylocator to the persisted contract --- loopdb/codec.go | 40 +++++++++++++++++++++++++++++ loopdb/codec_test.go | 45 +++++++++++++++++++++++++++++++++ loopdb/loop.go | 6 +++++ loopdb/store.go | 60 ++++++++++++++++++++++++++++++++++++++++++++ loopin.go | 1 + loopout.go | 1 + 6 files changed, 153 insertions(+) diff --git a/loopdb/codec.go b/loopdb/codec.go index d0f2ee2..fd3fa6e 100644 --- a/loopdb/codec.go +++ b/loopdb/codec.go @@ -1,7 +1,11 @@ package loopdb import ( + "bytes" "fmt" + + "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/keychain" ) // itob returns an 8-byte big endian representation of v. @@ -40,3 +44,39 @@ func MarshalProtocolVersion(version ProtocolVersion) []byte { return versionBytes[:] } + +// MarshalKeyLocator marshals a keychain.KeyLocator to a byte slice. +func MarshalKeyLocator(keyLocator keychain.KeyLocator) ([]byte, error) { + var ( + scratch [8]byte + buf bytes.Buffer + ) + + err := channeldb.EKeyLocator(&buf, &keyLocator, &scratch) + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +// UnmarshalKeyLocator unmarshals a keychain.KeyLocator from a byte slice. +func UnmarshalKeyLocator(data []byte) (keychain.KeyLocator, error) { + if data == nil { + return keychain.KeyLocator{}, nil + } + + var ( + scratch [8]byte + keyLocator keychain.KeyLocator + ) + + err := channeldb.DKeyLocator( + bytes.NewReader(data), &keyLocator, &scratch, 8, + ) + if err != nil { + return keychain.KeyLocator{}, err + } + + return keyLocator, nil +} diff --git a/loopdb/codec_test.go b/loopdb/codec_test.go index 5d58e86..1d01c6a 100644 --- a/loopdb/codec_test.go +++ b/loopdb/codec_test.go @@ -1,8 +1,10 @@ package loopdb import ( + "math" "testing" + "github.com/lightningnetwork/lnd/keychain" "github.com/stretchr/testify/require" ) @@ -51,3 +53,46 @@ func TestProtocolVersionMarshalUnMarshal(t *testing.T) { require.Equal(t, ProtocolVersionUnrecorded, version) } } + +// TestKeyLocatorMarshalUnMarshal tests that marshalling and unmarshalling +// keychain.KeyLocator works correctly. +func TestKeyLocatorMarshalUnMarshal(t *testing.T) { + t.Parallel() + + tests := []struct { + keyLoc keychain.KeyLocator + }{ + { + // Test that an empty keylocator is serialized and + // deserialized correctly. + keyLoc: keychain.KeyLocator{}, + }, + { + // Test that the max value keylocator is serialized and + // deserialized correctly. + keyLoc: keychain.KeyLocator{ + Family: keychain.KeyFamily(math.MaxUint32), + Index: math.MaxUint32, + }, + }, + { + // Test that an arbitrary keylocator is serialized and + // deserialized correctly. + keyLoc: keychain.KeyLocator{ + Family: keychain.KeyFamily(5), + Index: 7, + }, + }, + } + + for _, test := range tests { + test := test + + buf, err := MarshalKeyLocator(test.keyLoc) + require.NoError(t, err) + + keyLoc, err := UnmarshalKeyLocator(buf) + require.NoError(t, err) + require.Equal(t, test.keyLoc, keyLoc) + } +} diff --git a/loopdb/loop.go b/loopdb/loop.go index 07d9d4b..98f195a 100644 --- a/loopdb/loop.go +++ b/loopdb/loop.go @@ -6,6 +6,7 @@ import ( "time" "github.com/btcsuite/btcd/btcutil" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lntypes" ) @@ -26,6 +27,11 @@ type SwapContract struct { // HTLC. ReceiverKey [33]byte + // ClientKeyLocator is the key locator (family and index) for the client + // key. It is for the receiver key if this is a loop out contract, or + // the sender key if this is a loop in contract. + ClientKeyLocator keychain.KeyLocator + // CltvExpiry is the total absolute CLTV expiry of the swap. CltvExpiry int32 diff --git a/loopdb/store.go b/loopdb/store.go index 67fdcd6..1343974 100644 --- a/loopdb/store.go +++ b/loopdb/store.go @@ -102,6 +102,16 @@ var ( // parameters. liquidtyParamsKey = []byte("params") + // keyLocatorKey is the key that stores the receiver key's locator info + // for loop outs or the sender key's locator info for loop ins. This is + // required for MuSig2 swaps. Only serialized/deserialized for swaps + // that have protocol version >= ProtocolVersionHtlcV3. + // + // path: loopInBucket/loopOutBucket -> swapBucket[hash] -> keyLocatorKey + // + // value: concatenation of uint32 values [family, index]. + keyLocatorKey = []byte("keylocator") + byteOrder = binary.BigEndian keyLength = 33 @@ -327,6 +337,16 @@ func (s *boltSwapStore) FetchLoopOutSwaps() ([]*LoopOut, error) { return err } + // Try to unmarshal the key locator. + if contract.ProtocolVersion >= ProtocolVersionHtlcV3 { + contract.ClientKeyLocator, err = UnmarshalKeyLocator( + swapBucket.Get(keyLocatorKey), + ) + if err != nil { + return err + } + } + loop := LoopOut{ Loop: Loop{ Events: updates, @@ -464,6 +484,16 @@ func (s *boltSwapStore) FetchLoopInSwaps() ([]*LoopIn, error) { return err } + // Try to unmarshal the key locator. + if contract.ProtocolVersion >= ProtocolVersionHtlcV3 { + contract.ClientKeyLocator, err = UnmarshalKeyLocator( + swapBucket.Get(keyLocatorKey), + ) + if err != nil { + return err + } + } + loop := LoopIn{ Loop: Loop{ Events: updates, @@ -583,6 +613,21 @@ func (s *boltSwapStore) CreateLoopOut(hash lntypes.Hash, return err } + // Store the key locator for swaps with taproot htlc. + if swap.ProtocolVersion >= ProtocolVersionHtlcV3 { + keyLocator, err := MarshalKeyLocator( + swap.ClientKeyLocator, + ) + if err != nil { + return err + } + + err = swapBucket.Put(keyLocatorKey, keyLocator) + if err != nil { + return err + } + } + // Finally, we'll create an empty updates bucket for this swap // to track any future updates to the swap itself. _, err = swapBucket.CreateBucket(updatesBucketKey) @@ -634,6 +679,21 @@ func (s *boltSwapStore) CreateLoopIn(hash lntypes.Hash, return err } + // Store the key locator for swaps with taproot htlc. + if swap.ProtocolVersion >= ProtocolVersionHtlcV3 { + keyLocator, err := MarshalKeyLocator( + swap.ClientKeyLocator, + ) + if err != nil { + return err + } + + err = swapBucket.Put(keyLocatorKey, keyLocator) + if err != nil { + return err + } + } + // Finally, we'll create an empty updates bucket for this swap // to track any future updates to the swap itself. _, err = swapBucket.CreateBucket(updatesBucketKey) diff --git a/loopin.go b/loopin.go index 3e89c91..6326581 100644 --- a/loopin.go +++ b/loopin.go @@ -240,6 +240,7 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig, InitiationTime: initiationTime, ReceiverKey: swapResp.receiverKey, SenderKey: senderKey, + ClientKeyLocator: keyDesc.KeyLocator, Preimage: swapPreimage, AmountRequested: request.Amount, CltvExpiry: swapResp.expiry, diff --git a/loopout.go b/loopout.go index 56d679d..9368e40 100644 --- a/loopout.go +++ b/loopout.go @@ -171,6 +171,7 @@ func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig, InitiationTime: initiationTime, ReceiverKey: receiverKey, SenderKey: swapResp.senderKey, + ClientKeyLocator: keyDesc.KeyLocator, Preimage: swapPreimage, AmountRequested: request.Amount, CltvExpiry: request.Expiry, From 1abbe648d1f7785cb7bb81c72aeaec14ac5a9bf4 Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Wed, 4 May 2022 22:25:40 +0200 Subject: [PATCH 10/17] rpc: fix swapserverrpc build --- swapserverrpc/gen_protos.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/swapserverrpc/gen_protos.sh b/swapserverrpc/gen_protos.sh index 0ce3a8f..715844c 100755 --- a/swapserverrpc/gen_protos.sh +++ b/swapserverrpc/gen_protos.sh @@ -9,6 +9,7 @@ function generate() { do protoc -I/usr/local/include -I. -I.. \ --go_out . --go_opt paths=source_relative \ + --go-grpc_out . --go-grpc_opt paths=source_relative \ "${file}" done } From 5c04b8db05f16494414828d5c54b86132f977518 Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Thu, 9 Jun 2022 20:24:57 +0200 Subject: [PATCH 11/17] test: add richer implementation to MuSig2CreateSession --- test/signer_mock.go | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/test/signer_mock.go b/test/signer_mock.go index 8faac8e..16a725d 100644 --- a/test/signer_mock.go +++ b/test/signer_mock.go @@ -3,9 +3,11 @@ package test import ( "bytes" "context" + "encoding/hex" "fmt" "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/schnorr" "github.com/btcsuite/btcd/wire" "github.com/lightninglabs/lndclient" "github.com/lightningnetwork/lnd/input" @@ -68,7 +70,21 @@ func (s *mockSigner) MuSig2CreateSession(context.Context, *keychain.KeyLocator, [][32]byte, ...lndclient.MuSig2SessionOpts) (*input.MuSig2SessionInfo, error) { - return nil, nil + const testPubKey = "F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9" + pubKeyBytes, err := hex.DecodeString(testPubKey) + if err != nil { + return nil, err + } + + combinedKey, err := schnorr.ParsePubKey(pubKeyBytes) + if err != nil { + return nil, err + } + + return &input.MuSig2SessionInfo{ + CombinedKey: combinedKey, + HaveAllNonces: true, + }, nil } // MuSig2RegisterNonces registers one or more public nonces of other signing @@ -77,7 +93,7 @@ func (s *mockSigner) MuSig2CreateSession(context.Context, *keychain.KeyLocator, func (s *mockSigner) MuSig2RegisterNonces(context.Context, [32]byte, [][66]byte) (bool, error) { - return false, nil + return true, nil } // MuSig2Sign creates a partial signature using the local signing key From d3401f809f283d8a6528f60017e9d776a5e74e44 Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Wed, 11 May 2022 20:10:01 +0200 Subject: [PATCH 12/17] loopout: fix flaky loopout preimage push and expiry tests --- loopout_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/loopout_test.go b/loopout_test.go index e821aaa..d23e1a3 100644 --- a/loopout_test.go +++ b/loopout_test.go @@ -581,6 +581,11 @@ func testPreimagePush(t *testing.T) { // preimage is not revealed, we also do not expect a preimage push. expiryChan <- testTime + // Since we don't have a reliable mechanism to non-intrusively avoid + // races by setting the fee estimate too soon, let's sleep here a bit + // to ensure the first sweep fails. + time.Sleep(500 * time.Millisecond) + // Now we decrease our fees for the swap's confirmation target to less // than the maximum miner fee. ctx.Lnd.SetFeeEstimate(testReq.SweepConfTarget, chainfee.SatPerKWeight( @@ -760,6 +765,11 @@ func testExpiryBeforeReveal(t *testing.T) { // won't attempt a sweep at this point. expiryChan <- testTime + // Since we don't have a reliable mechanism to non-intrusively avoid + // races by setting the fee estimate too soon, let's sleep here a bit + // to ensure the first sweep fails. + time.Sleep(500 * time.Millisecond) + // Now we decrease our conf target to less than our max miner fee. lnd.SetFeeEstimate(testReq.SweepConfTarget, chainfee.SatPerKWeight( testReq.MaxMinerFee/2, From 32557a57ea4a1b0aad6f9ad4f9638943ef31ff68 Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Wed, 4 May 2022 22:26:24 +0200 Subject: [PATCH 13/17] swapserverrpc: add MuSig2SignSweep function --- server_mock_test.go | 7 + swap_server_client.go | 33 ++ swapserverrpc/server.pb.go | 553 +++++++++++++++++++++----------- swapserverrpc/server.proto | 27 ++ swapserverrpc/server_grpc.pb.go | 36 +++ 5 files changed, 476 insertions(+), 180 deletions(-) diff --git a/server_mock_test.go b/server_mock_test.go index 3e928a6..3e7de66 100644 --- a/server_mock_test.go +++ b/server_mock_test.go @@ -9,6 +9,7 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" "github.com/lightninglabs/lndclient" + "github.com/lightninglabs/loop/loopdb" "github.com/lightninglabs/loop/test" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/lntypes" @@ -253,3 +254,9 @@ func (s *serverMock) ReportRoutingResult(_ context.Context, _ lntypes.Hash, return nil } + +func (s *serverMock) MuSig2SignSweep(_ context.Context, _ loopdb.ProtocolVersion, + _ lntypes.Hash, _ [32]byte, _ []byte, _ []byte) ([]byte, []byte, error) { + + return nil, nil, nil +} diff --git a/swap_server_client.go b/swap_server_client.go index 10f0709..4072f07 100644 --- a/swap_server_client.go +++ b/swap_server_client.go @@ -121,6 +121,13 @@ type swapServerClient interface { swapHash lntypes.Hash, paymentAddr [32]byte, plugin RoutingPluginType, success bool, attempts int32, totalTime int64) error + + // MuSig2SignSweep calls the server to cooperatively sign the MuSig2 + // htlc spend. Returns the server's nonce and partial signature. + MuSig2SignSweep(ctx context.Context, + protocolVersion loopdb.ProtocolVersion, swapHash lntypes.Hash, + paymentAddr [32]byte, nonce []byte, sigHash []byte) ( + []byte, []byte, error) } type grpcSwapServerClient struct { @@ -720,6 +727,32 @@ func (s *grpcSwapServerClient) ReportRoutingResult(ctx context.Context, return err } +// MuSig2SignSweep calls the server to cooperatively sign the MuSig2 htlc +// spend. Returns the server's nonce and partial signature. +func (s *grpcSwapServerClient) MuSig2SignSweep(ctx context.Context, + protocolVersion loopdb.ProtocolVersion, swapHash lntypes.Hash, + paymentAddr [32]byte, nonce []byte, sigHash []byte) ( + []byte, []byte, error) { + + req := &looprpc.MuSig2SignSweepReq{ + ProtocolVersion: looprpc.ProtocolVersion(protocolVersion), + SwapHash: swapHash[:], + PaymentAddress: paymentAddr[:], + Nonce: nonce, + SigHash: sigHash, + } + + rpcCtx, rpcCancel := context.WithTimeout(ctx, globalCallTimeout) + defer rpcCancel() + + res, err := s.server.MuSig2SignSweep(rpcCtx, req) + if err != nil { + return nil, nil, err + } + + return res.Nonce, res.PartialSignature, nil +} + func rpcRouteCancel(details *outCancelDetails) ( *looprpc.CancelLoopOutSwapRequest_RouteCancel, error) { diff --git a/swapserverrpc/server.pb.go b/swapserverrpc/server.pb.go index fac9999..2ec129f 100644 --- a/swapserverrpc/server.pb.go +++ b/swapserverrpc/server.pb.go @@ -2263,6 +2263,147 @@ func (*ReportRoutingResultRes) Descriptor() ([]byte, []int) { return file_server_proto_rawDescGZIP(), []int{26} } +type MuSig2SignSweepReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProtocolVersion ProtocolVersion `protobuf:"varint,1,opt,name=protocol_version,json=protocolVersion,proto3,enum=looprpc.ProtocolVersion" json:"protocol_version,omitempty"` + // The swap hash. + SwapHash []byte `protobuf:"bytes,2,opt,name=swap_hash,json=swapHash,proto3" json:"swap_hash,omitempty"` + // The payment address for the swap invoice, used to ensure that only the + // swap owner can obtain the partial signature. + PaymentAddress []byte `protobuf:"bytes,3,opt,name=payment_address,json=paymentAddress,proto3" json:"payment_address,omitempty"` + // The local public nonce. + Nonce []byte `protobuf:"bytes,4,opt,name=nonce,proto3" json:"nonce,omitempty"` + // The sighash of the htlc sweep. + SigHash []byte `protobuf:"bytes,5,opt,name=sig_hash,json=sigHash,proto3" json:"sig_hash,omitempty"` +} + +func (x *MuSig2SignSweepReq) Reset() { + *x = MuSig2SignSweepReq{} + if protoimpl.UnsafeEnabled { + mi := &file_server_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MuSig2SignSweepReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MuSig2SignSweepReq) ProtoMessage() {} + +func (x *MuSig2SignSweepReq) ProtoReflect() protoreflect.Message { + mi := &file_server_proto_msgTypes[27] + 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 MuSig2SignSweepReq.ProtoReflect.Descriptor instead. +func (*MuSig2SignSweepReq) Descriptor() ([]byte, []int) { + return file_server_proto_rawDescGZIP(), []int{27} +} + +func (x *MuSig2SignSweepReq) GetProtocolVersion() ProtocolVersion { + if x != nil { + return x.ProtocolVersion + } + return ProtocolVersion_LEGACY +} + +func (x *MuSig2SignSweepReq) GetSwapHash() []byte { + if x != nil { + return x.SwapHash + } + return nil +} + +func (x *MuSig2SignSweepReq) GetPaymentAddress() []byte { + if x != nil { + return x.PaymentAddress + } + return nil +} + +func (x *MuSig2SignSweepReq) GetNonce() []byte { + if x != nil { + return x.Nonce + } + return nil +} + +func (x *MuSig2SignSweepReq) GetSigHash() []byte { + if x != nil { + return x.SigHash + } + return nil +} + +type MuSig2SignSweepRes struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The server side public nonce. + Nonce []byte `protobuf:"bytes,1,opt,name=nonce,proto3" json:"nonce,omitempty"` + // The partial signature of the server for the requested sighash. + PartialSignature []byte `protobuf:"bytes,2,opt,name=partial_signature,json=partialSignature,proto3" json:"partial_signature,omitempty"` +} + +func (x *MuSig2SignSweepRes) Reset() { + *x = MuSig2SignSweepRes{} + if protoimpl.UnsafeEnabled { + mi := &file_server_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MuSig2SignSweepRes) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MuSig2SignSweepRes) ProtoMessage() {} + +func (x *MuSig2SignSweepRes) ProtoReflect() protoreflect.Message { + mi := &file_server_proto_msgTypes[28] + 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 MuSig2SignSweepRes.ProtoReflect.Descriptor instead. +func (*MuSig2SignSweepRes) Descriptor() ([]byte, []int) { + return file_server_proto_rawDescGZIP(), []int{28} +} + +func (x *MuSig2SignSweepRes) GetNonce() []byte { + if x != nil { + return x.Nonce + } + return nil +} + +func (x *MuSig2SignSweepRes) GetPartialSignature() []byte { + if x != nil { + return x.PartialSignature + } + return nil +} + var File_server_proto protoreflect.FileDescriptor var file_server_proto_rawDesc = []byte{ @@ -2528,154 +2669,177 @@ var file_server_proto_rawDesc = []byte{ 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x18, 0x0a, 0x16, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, - 0x65, 0x73, 0x2a, 0xe3, 0x01, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x45, 0x47, 0x41, 0x43, 0x59, - 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, - 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x4e, 0x41, 0x54, 0x49, 0x56, 0x45, - 0x5f, 0x53, 0x45, 0x47, 0x57, 0x49, 0x54, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x49, 0x4e, 0x10, - 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x50, 0x52, 0x45, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x50, 0x55, - 0x53, 0x48, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x03, 0x12, 0x18, 0x0a, - 0x14, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x59, 0x5f, 0x4c, 0x4f, 0x4f, - 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x04, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x54, 0x4c, 0x43, 0x5f, - 0x56, 0x32, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x5f, 0x4c, 0x4f, - 0x4f, 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x06, 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, - 0x4f, 0x55, 0x54, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x07, 0x12, 0x09, 0x0a, 0x05, - 0x50, 0x52, 0x4f, 0x42, 0x45, 0x10, 0x08, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x4f, 0x55, 0x54, 0x49, - 0x4e, 0x47, 0x5f, 0x50, 0x4c, 0x55, 0x47, 0x49, 0x4e, 0x10, 0x09, 0x12, 0x0b, 0x0a, 0x07, 0x48, - 0x54, 0x4c, 0x43, 0x5f, 0x56, 0x33, 0x10, 0x0a, 0x2a, 0x9e, 0x04, 0x0a, 0x0f, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x10, - 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x45, 0x44, - 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x48, 0x54, 0x4c, - 0x43, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x01, 0x12, 0x12, 0x0a, - 0x0e, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, - 0x02, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, - 0x45, 0x44, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, - 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x4e, 0x4f, - 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x10, 0x04, 0x12, 0x25, 0x0a, 0x21, 0x53, 0x45, 0x52, 0x56, 0x45, - 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, - 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x4d, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x05, 0x12, 0x23, - 0x0a, 0x1f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, - 0x4f, 0x46, 0x46, 0x5f, 0x43, 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, - 0x54, 0x10, 0x06, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, - 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x07, 0x12, 0x1f, - 0x0a, 0x1b, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, - 0x53, 0x57, 0x41, 0x50, 0x5f, 0x44, 0x45, 0x41, 0x44, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x08, 0x12, - 0x22, 0x0a, 0x1e, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, - 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, - 0x4e, 0x10, 0x09, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x54, 0x49, - 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, - 0x0a, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x55, 0x4e, 0x45, 0x58, - 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x0b, - 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, - 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x0c, 0x12, 0x1f, 0x0a, 0x1b, 0x53, - 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x50, 0x52, 0x45, - 0x50, 0x41, 0x59, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x0d, 0x12, 0x20, 0x0a, 0x1c, - 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x49, 0x4e, - 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x0e, 0x12, 0x27, - 0x0a, 0x23, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, - 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x50, 0x4c, 0x45, 0x5f, 0x53, 0x57, 0x41, 0x50, 0x5f, 0x53, 0x43, - 0x52, 0x49, 0x50, 0x54, 0x53, 0x10, 0x0f, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x45, 0x52, 0x56, 0x45, - 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, - 0x49, 0x5a, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x10, 0x2a, 0x4a, 0x0a, 0x10, 0x52, 0x6f, 0x75, - 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x11, 0x0a, - 0x0d, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, - 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x52, 0x45, 0x50, 0x41, 0x59, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, - 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x52, 0x4f, - 0x55, 0x54, 0x45, 0x10, 0x02, 0x2a, 0xf1, 0x01, 0x0a, 0x14, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, - 0x74, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1b, - 0x0a, 0x17, 0x4c, 0x4e, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, - 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x4c, - 0x4e, 0x44, 0x5f, 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, 0x1f, 0x0a, 0x1b, 0x4c, - 0x4e, 0x44, 0x5f, 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, 0x1c, 0x0a, 0x18, - 0x4c, 0x4e, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, - 0x4f, 0x4e, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x30, 0x0a, 0x2c, 0x4c, 0x4e, + 0x65, 0x73, 0x22, 0xd0, 0x01, 0x0a, 0x12, 0x4d, 0x75, 0x53, 0x69, 0x67, 0x32, 0x53, 0x69, 0x67, + 0x6e, 0x53, 0x77, 0x65, 0x65, 0x70, 0x52, 0x65, 0x71, 0x12, 0x43, 0x0a, 0x10, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1b, + 0x0a, 0x09, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x08, 0x73, 0x77, 0x61, 0x70, 0x48, 0x61, 0x73, 0x68, 0x12, 0x27, 0x0a, 0x0f, 0x70, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x69, + 0x67, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x73, 0x69, + 0x67, 0x48, 0x61, 0x73, 0x68, 0x22, 0x57, 0x0a, 0x12, 0x4d, 0x75, 0x53, 0x69, 0x67, 0x32, 0x53, + 0x69, 0x67, 0x6e, 0x53, 0x77, 0x65, 0x65, 0x70, 0x52, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, + 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, + 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x70, 0x61, + 0x72, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2a, 0xe3, + 0x01, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x45, 0x47, 0x41, 0x43, 0x59, 0x10, 0x00, 0x12, 0x12, + 0x0a, 0x0e, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, + 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x4e, 0x41, 0x54, 0x49, 0x56, 0x45, 0x5f, 0x53, 0x45, 0x47, + 0x57, 0x49, 0x54, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x02, 0x12, 0x1a, 0x0a, + 0x16, 0x50, 0x52, 0x45, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x50, 0x55, 0x53, 0x48, 0x5f, 0x4c, + 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, 0x55, 0x53, 0x45, + 0x52, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x59, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, + 0x54, 0x10, 0x04, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x56, 0x32, 0x10, 0x05, + 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x49, + 0x4e, 0x10, 0x06, 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x5f, + 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x07, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x52, 0x4f, 0x42, + 0x45, 0x10, 0x08, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x4f, 0x55, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x50, + 0x4c, 0x55, 0x47, 0x49, 0x4e, 0x10, 0x09, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x54, 0x4c, 0x43, 0x5f, + 0x56, 0x33, 0x10, 0x0a, 0x2a, 0x9e, 0x04, 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, + 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x45, 0x52, 0x56, + 0x45, 0x52, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, + 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x50, 0x55, + 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x45, 0x52, + 0x56, 0x45, 0x52, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x02, 0x12, 0x19, 0x0a, + 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x55, + 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, + 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x4e, 0x4f, 0x5f, 0x48, 0x54, 0x4c, + 0x43, 0x10, 0x04, 0x12, 0x25, 0x0a, 0x21, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, + 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x48, 0x54, 0x4c, + 0x43, 0x5f, 0x41, 0x4d, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x05, 0x12, 0x23, 0x0a, 0x1f, 0x53, 0x45, + 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x4f, 0x46, 0x46, 0x5f, + 0x43, 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x06, 0x12, + 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, + 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x07, 0x12, 0x1f, 0x0a, 0x1b, 0x53, 0x45, + 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x53, 0x57, 0x41, 0x50, + 0x5f, 0x44, 0x45, 0x41, 0x44, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x08, 0x12, 0x22, 0x0a, 0x1e, 0x53, + 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x48, 0x54, 0x4c, + 0x43, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x09, 0x12, + 0x1c, 0x0a, 0x18, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, + 0x54, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x0a, 0x12, 0x1d, 0x0a, + 0x19, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x55, 0x4e, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, + 0x45, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x0b, 0x12, 0x19, 0x0a, 0x15, + 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x43, 0x4f, 0x4e, 0x46, + 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x0c, 0x12, 0x1f, 0x0a, 0x1b, 0x53, 0x45, 0x52, 0x56, 0x45, + 0x52, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x50, 0x52, 0x45, 0x50, 0x41, 0x59, 0x5f, + 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x0d, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x45, 0x52, 0x56, + 0x45, 0x52, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, + 0x45, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x0e, 0x12, 0x27, 0x0a, 0x23, 0x53, 0x45, + 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x4d, 0x55, 0x4c, 0x54, + 0x49, 0x50, 0x4c, 0x45, 0x5f, 0x53, 0x57, 0x41, 0x50, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, + 0x53, 0x10, 0x0f, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, + 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x49, 0x5a, 0x41, 0x54, + 0x49, 0x4f, 0x4e, 0x10, 0x10, 0x2a, 0x4a, 0x0a, 0x10, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x4f, 0x55, + 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, + 0x50, 0x52, 0x45, 0x50, 0x41, 0x59, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x10, 0x01, 0x12, 0x11, + 0x0a, 0x0d, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x10, + 0x02, 0x2a, 0xf1, 0x01, 0x0a, 0x14, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x46, 0x61, 0x69, + 0x6c, 0x75, 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x17, 0x4c, 0x4e, 0x44, 0x5f, 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, 0x2b, 0x0a, 0x27, - 0x4c, 0x4e, 0x44, 0x5f, 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, 0x27, 0x0a, 0x0d, 0x52, 0x6f, 0x75, - 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, - 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x4c, 0x4f, 0x57, 0x5f, 0x48, 0x49, 0x47, 0x48, - 0x10, 0x01, 0x32, 0x8a, 0x09, 0x0a, 0x0a, 0x53, 0x77, 0x61, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x12, 0x4f, 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, - 0x73, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, - 0x6d, 0x73, 0x12, 0x4f, 0x0a, 0x0e, 0x4e, 0x65, 0x77, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, - 0x53, 0x77, 0x61, 0x70, 0x12, 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x50, 0x75, - 0x73, 0x68, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x29, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, - 0x75, 0x74, 0x50, 0x75, 0x73, 0x68, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x50, 0x75, 0x73, - 0x68, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x4f, 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, - 0x65, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, - 0x74, 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, - 0x73, 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, - 0x12, 0x4c, 0x0a, 0x0d, 0x4e, 0x65, 0x77, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x53, 0x77, 0x61, - 0x70, 0x12, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, - 0x0a, 0x0b, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x21, 0x2e, + 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x4c, 0x4e, 0x44, 0x5f, 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, 0x1f, 0x0a, 0x1b, 0x4c, 0x4e, 0x44, 0x5f, 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, 0x1c, 0x0a, 0x18, 0x4c, 0x4e, 0x44, 0x5f, + 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x45, + 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x30, 0x0a, 0x2c, 0x4c, 0x4e, 0x44, 0x5f, 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, 0x2b, 0x0a, 0x27, 0x4c, 0x4e, 0x44, 0x5f, + 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, 0x27, 0x0a, 0x0d, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, + 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, + 0x12, 0x0c, 0x0a, 0x08, 0x4c, 0x4f, 0x57, 0x5f, 0x48, 0x49, 0x47, 0x48, 0x10, 0x01, 0x32, 0xd7, + 0x09, 0x0a, 0x0a, 0x53, 0x77, 0x61, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x4f, 0x0a, + 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, - 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, - 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x62, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x28, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, - 0x63, 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x65, 0x0a, - 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, - 0x70, 0x49, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x11, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4c, 0x6f, - 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, - 0x74, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4c, 0x6f, 0x6f, - 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x42, 0x0a, 0x05, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x16, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, - 0x64, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x22, + 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x4f, + 0x0a, 0x0e, 0x4e, 0x65, 0x77, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, + 0x12, 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x6c, 0x0a, 0x13, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x50, 0x75, 0x73, 0x68, 0x50, 0x72, + 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x29, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, + 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x50, 0x75, + 0x73, 0x68, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x50, 0x75, 0x73, 0x68, 0x50, 0x72, 0x65, + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, + 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x22, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, + 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x4c, + 0x0a, 0x0b, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x21, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, + 0x6f, 0x70, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x4c, 0x0a, 0x0d, + 0x4e, 0x65, 0x77, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x53, 0x77, 0x61, 0x70, 0x12, 0x1c, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, + 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, + 0x49, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x4c, 0x6f, + 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, + 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, + 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x67, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, + 0x70, 0x4f, 0x75, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, + 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x65, 0x0a, 0x16, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, + 0x12, 0x5a, 0x0a, 0x11, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, + 0x74, 0x53, 0x77, 0x61, 0x70, 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, + 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, + 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x05, + 0x50, 0x72, 0x6f, 0x62, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x60, 0x0a, 0x16, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x52, 0x6f, 0x75, + 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x52, 0x6f, + 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, - 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x63, - 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, - 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x57, 0x0a, 0x13, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1f, 0x2e, - 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x6f, - 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1f, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, - 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x42, - 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, - 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, - 0x2f, 0x73, 0x77, 0x61, 0x70, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x73, 0x12, 0x57, 0x0a, 0x13, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x6f, 0x75, 0x74, + 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, + 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x69, + 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x0f, 0x4d, + 0x75, 0x53, 0x69, 0x67, 0x32, 0x53, 0x69, 0x67, 0x6e, 0x53, 0x77, 0x65, 0x65, 0x70, 0x12, 0x1b, + 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x75, 0x53, 0x69, 0x67, 0x32, 0x53, + 0x69, 0x67, 0x6e, 0x53, 0x77, 0x65, 0x65, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x75, 0x53, 0x69, 0x67, 0x32, 0x53, 0x69, 0x67, 0x6e, + 0x53, 0x77, 0x65, 0x65, 0x70, 0x52, 0x65, 0x73, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, + 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x73, 0x77, 0x61, 0x70, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2691,7 +2855,7 @@ func file_server_proto_rawDescGZIP() []byte { } var file_server_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_server_proto_msgTypes = make([]protoimpl.MessageInfo, 27) +var file_server_proto_msgTypes = make([]protoimpl.MessageInfo, 29) var file_server_proto_goTypes = []interface{}{ (ProtocolVersion)(0), // 0: looprpc.ProtocolVersion (ServerSwapState)(0), // 1: looprpc.ServerSwapState @@ -2725,14 +2889,16 @@ var file_server_proto_goTypes = []interface{}{ (*RecommendRoutingPluginRes)(nil), // 29: looprpc.RecommendRoutingPluginRes (*ReportRoutingResultReq)(nil), // 30: looprpc.ReportRoutingResultReq (*ReportRoutingResultRes)(nil), // 31: looprpc.ReportRoutingResultRes - (*RouteHint)(nil), // 32: looprpc.RouteHint + (*MuSig2SignSweepReq)(nil), // 32: looprpc.MuSig2SignSweepReq + (*MuSig2SignSweepRes)(nil), // 33: looprpc.MuSig2SignSweepRes + (*RouteHint)(nil), // 34: looprpc.RouteHint } var file_server_proto_depIdxs = []int32{ 0, // 0: looprpc.ServerLoopOutRequest.protocol_version:type_name -> looprpc.ProtocolVersion 0, // 1: looprpc.ServerLoopOutQuoteRequest.protocol_version:type_name -> looprpc.ProtocolVersion 0, // 2: looprpc.ServerLoopOutTermsRequest.protocol_version:type_name -> looprpc.ProtocolVersion 0, // 3: looprpc.ServerLoopInRequest.protocol_version:type_name -> looprpc.ProtocolVersion - 32, // 4: looprpc.ServerLoopInQuoteRequest.route_hints:type_name -> looprpc.RouteHint + 34, // 4: looprpc.ServerLoopInQuoteRequest.route_hints:type_name -> looprpc.RouteHint 0, // 5: looprpc.ServerLoopInQuoteRequest.protocol_version:type_name -> looprpc.ProtocolVersion 0, // 6: looprpc.ServerLoopInTermsRequest.protocol_version:type_name -> looprpc.ProtocolVersion 0, // 7: looprpc.ServerLoopOutPushPreimageRequest.protocol_version:type_name -> looprpc.ProtocolVersion @@ -2745,42 +2911,45 @@ var file_server_proto_depIdxs = []int32{ 0, // 14: looprpc.CancelLoopOutSwapRequest.protocol_version:type_name -> looprpc.ProtocolVersion 22, // 15: looprpc.CancelLoopOutSwapRequest.route_cancel:type_name -> looprpc.RouteCancel 0, // 16: looprpc.ServerProbeRequest.protocol_version:type_name -> looprpc.ProtocolVersion - 32, // 17: looprpc.ServerProbeRequest.route_hints:type_name -> looprpc.RouteHint + 34, // 17: looprpc.ServerProbeRequest.route_hints:type_name -> looprpc.RouteHint 0, // 18: looprpc.RecommendRoutingPluginReq.protocol_version:type_name -> looprpc.ProtocolVersion 4, // 19: looprpc.RecommendRoutingPluginRes.plugin:type_name -> looprpc.RoutingPlugin 0, // 20: looprpc.ReportRoutingResultReq.protocol_version:type_name -> looprpc.ProtocolVersion 4, // 21: looprpc.ReportRoutingResultReq.plugin:type_name -> looprpc.RoutingPlugin - 9, // 22: looprpc.SwapServer.LoopOutTerms:input_type -> looprpc.ServerLoopOutTermsRequest - 5, // 23: looprpc.SwapServer.NewLoopOutSwap:input_type -> looprpc.ServerLoopOutRequest - 17, // 24: looprpc.SwapServer.LoopOutPushPreimage:input_type -> looprpc.ServerLoopOutPushPreimageRequest - 7, // 25: looprpc.SwapServer.LoopOutQuote:input_type -> looprpc.ServerLoopOutQuoteRequest - 15, // 26: looprpc.SwapServer.LoopInTerms:input_type -> looprpc.ServerLoopInTermsRequest - 11, // 27: looprpc.SwapServer.NewLoopInSwap:input_type -> looprpc.ServerLoopInRequest - 13, // 28: looprpc.SwapServer.LoopInQuote:input_type -> looprpc.ServerLoopInQuoteRequest - 19, // 29: looprpc.SwapServer.SubscribeLoopOutUpdates:input_type -> looprpc.SubscribeUpdatesRequest - 19, // 30: looprpc.SwapServer.SubscribeLoopInUpdates:input_type -> looprpc.SubscribeUpdatesRequest - 24, // 31: looprpc.SwapServer.CancelLoopOutSwap:input_type -> looprpc.CancelLoopOutSwapRequest - 26, // 32: looprpc.SwapServer.Probe:input_type -> looprpc.ServerProbeRequest - 28, // 33: looprpc.SwapServer.RecommendRoutingPlugin:input_type -> looprpc.RecommendRoutingPluginReq - 30, // 34: looprpc.SwapServer.ReportRoutingResult:input_type -> looprpc.ReportRoutingResultReq - 10, // 35: looprpc.SwapServer.LoopOutTerms:output_type -> looprpc.ServerLoopOutTerms - 6, // 36: looprpc.SwapServer.NewLoopOutSwap:output_type -> looprpc.ServerLoopOutResponse - 18, // 37: looprpc.SwapServer.LoopOutPushPreimage:output_type -> looprpc.ServerLoopOutPushPreimageResponse - 8, // 38: looprpc.SwapServer.LoopOutQuote:output_type -> looprpc.ServerLoopOutQuote - 16, // 39: looprpc.SwapServer.LoopInTerms:output_type -> looprpc.ServerLoopInTerms - 12, // 40: looprpc.SwapServer.NewLoopInSwap:output_type -> looprpc.ServerLoopInResponse - 14, // 41: looprpc.SwapServer.LoopInQuote:output_type -> looprpc.ServerLoopInQuoteResponse - 20, // 42: looprpc.SwapServer.SubscribeLoopOutUpdates:output_type -> looprpc.SubscribeLoopOutUpdatesResponse - 21, // 43: looprpc.SwapServer.SubscribeLoopInUpdates:output_type -> looprpc.SubscribeLoopInUpdatesResponse - 25, // 44: looprpc.SwapServer.CancelLoopOutSwap:output_type -> looprpc.CancelLoopOutSwapResponse - 27, // 45: looprpc.SwapServer.Probe:output_type -> looprpc.ServerProbeResponse - 29, // 46: looprpc.SwapServer.RecommendRoutingPlugin:output_type -> looprpc.RecommendRoutingPluginRes - 31, // 47: looprpc.SwapServer.ReportRoutingResult:output_type -> looprpc.ReportRoutingResultRes - 35, // [35:48] is the sub-list for method output_type - 22, // [22:35] is the sub-list for method input_type - 22, // [22:22] is the sub-list for extension type_name - 22, // [22:22] is the sub-list for extension extendee - 0, // [0:22] is the sub-list for field type_name + 0, // 22: looprpc.MuSig2SignSweepReq.protocol_version:type_name -> looprpc.ProtocolVersion + 9, // 23: looprpc.SwapServer.LoopOutTerms:input_type -> looprpc.ServerLoopOutTermsRequest + 5, // 24: looprpc.SwapServer.NewLoopOutSwap:input_type -> looprpc.ServerLoopOutRequest + 17, // 25: looprpc.SwapServer.LoopOutPushPreimage:input_type -> looprpc.ServerLoopOutPushPreimageRequest + 7, // 26: looprpc.SwapServer.LoopOutQuote:input_type -> looprpc.ServerLoopOutQuoteRequest + 15, // 27: looprpc.SwapServer.LoopInTerms:input_type -> looprpc.ServerLoopInTermsRequest + 11, // 28: looprpc.SwapServer.NewLoopInSwap:input_type -> looprpc.ServerLoopInRequest + 13, // 29: looprpc.SwapServer.LoopInQuote:input_type -> looprpc.ServerLoopInQuoteRequest + 19, // 30: looprpc.SwapServer.SubscribeLoopOutUpdates:input_type -> looprpc.SubscribeUpdatesRequest + 19, // 31: looprpc.SwapServer.SubscribeLoopInUpdates:input_type -> looprpc.SubscribeUpdatesRequest + 24, // 32: looprpc.SwapServer.CancelLoopOutSwap:input_type -> looprpc.CancelLoopOutSwapRequest + 26, // 33: looprpc.SwapServer.Probe:input_type -> looprpc.ServerProbeRequest + 28, // 34: looprpc.SwapServer.RecommendRoutingPlugin:input_type -> looprpc.RecommendRoutingPluginReq + 30, // 35: looprpc.SwapServer.ReportRoutingResult:input_type -> looprpc.ReportRoutingResultReq + 32, // 36: looprpc.SwapServer.MuSig2SignSweep:input_type -> looprpc.MuSig2SignSweepReq + 10, // 37: looprpc.SwapServer.LoopOutTerms:output_type -> looprpc.ServerLoopOutTerms + 6, // 38: looprpc.SwapServer.NewLoopOutSwap:output_type -> looprpc.ServerLoopOutResponse + 18, // 39: looprpc.SwapServer.LoopOutPushPreimage:output_type -> looprpc.ServerLoopOutPushPreimageResponse + 8, // 40: looprpc.SwapServer.LoopOutQuote:output_type -> looprpc.ServerLoopOutQuote + 16, // 41: looprpc.SwapServer.LoopInTerms:output_type -> looprpc.ServerLoopInTerms + 12, // 42: looprpc.SwapServer.NewLoopInSwap:output_type -> looprpc.ServerLoopInResponse + 14, // 43: looprpc.SwapServer.LoopInQuote:output_type -> looprpc.ServerLoopInQuoteResponse + 20, // 44: looprpc.SwapServer.SubscribeLoopOutUpdates:output_type -> looprpc.SubscribeLoopOutUpdatesResponse + 21, // 45: looprpc.SwapServer.SubscribeLoopInUpdates:output_type -> looprpc.SubscribeLoopInUpdatesResponse + 25, // 46: looprpc.SwapServer.CancelLoopOutSwap:output_type -> looprpc.CancelLoopOutSwapResponse + 27, // 47: looprpc.SwapServer.Probe:output_type -> looprpc.ServerProbeResponse + 29, // 48: looprpc.SwapServer.RecommendRoutingPlugin:output_type -> looprpc.RecommendRoutingPluginRes + 31, // 49: looprpc.SwapServer.ReportRoutingResult:output_type -> looprpc.ReportRoutingResultRes + 33, // 50: looprpc.SwapServer.MuSig2SignSweep:output_type -> looprpc.MuSig2SignSweepRes + 37, // [37:51] is the sub-list for method output_type + 23, // [23:37] is the sub-list for method input_type + 23, // [23:23] is the sub-list for extension type_name + 23, // [23:23] is the sub-list for extension extendee + 0, // [0:23] is the sub-list for field type_name } func init() { file_server_proto_init() } @@ -3114,6 +3283,30 @@ func file_server_proto_init() { return nil } } + file_server_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MuSig2SignSweepReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_server_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MuSig2SignSweepRes); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_server_proto_msgTypes[19].OneofWrappers = []interface{}{ (*CancelLoopOutSwapRequest_RouteCancel)(nil), @@ -3124,7 +3317,7 @@ func file_server_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_server_proto_rawDesc, NumEnums: 5, - NumMessages: 27, + NumMessages: 29, NumExtensions: 0, NumServices: 1, }, diff --git a/swapserverrpc/server.proto b/swapserverrpc/server.proto index 6aa265a..e3240c4 100644 --- a/swapserverrpc/server.proto +++ b/swapserverrpc/server.proto @@ -43,6 +43,8 @@ service SwapServer { rpc ReportRoutingResult (ReportRoutingResultReq) returns (ReportRoutingResultRes); + + rpc MuSig2SignSweep (MuSig2SignSweepReq) returns (MuSig2SignSweepRes); } /** @@ -526,3 +528,28 @@ message ReportRoutingResultReq { message ReportRoutingResultRes { } + +message MuSig2SignSweepReq { + ProtocolVersion protocol_version = 1; + + // The swap hash. + bytes swap_hash = 2; + + // The payment address for the swap invoice, used to ensure that only the + // swap owner can obtain the partial signature. + bytes payment_address = 3; + + // The local public nonce. + bytes nonce = 4; + + // The sighash of the htlc sweep. + bytes sig_hash = 5; +} + +message MuSig2SignSweepRes { + // The server side public nonce. + bytes nonce = 1; + + // The partial signature of the server for the requested sighash. + bytes partial_signature = 2; +} diff --git a/swapserverrpc/server_grpc.pb.go b/swapserverrpc/server_grpc.pb.go index 20f9f28..d0b3226 100644 --- a/swapserverrpc/server_grpc.pb.go +++ b/swapserverrpc/server_grpc.pb.go @@ -31,6 +31,7 @@ type SwapServerClient interface { Probe(ctx context.Context, in *ServerProbeRequest, opts ...grpc.CallOption) (*ServerProbeResponse, error) RecommendRoutingPlugin(ctx context.Context, in *RecommendRoutingPluginReq, opts ...grpc.CallOption) (*RecommendRoutingPluginRes, error) ReportRoutingResult(ctx context.Context, in *ReportRoutingResultReq, opts ...grpc.CallOption) (*ReportRoutingResultRes, error) + MuSig2SignSweep(ctx context.Context, in *MuSig2SignSweepReq, opts ...grpc.CallOption) (*MuSig2SignSweepRes, error) } type swapServerClient struct { @@ -204,6 +205,15 @@ func (c *swapServerClient) ReportRoutingResult(ctx context.Context, in *ReportRo return out, nil } +func (c *swapServerClient) MuSig2SignSweep(ctx context.Context, in *MuSig2SignSweepReq, opts ...grpc.CallOption) (*MuSig2SignSweepRes, error) { + out := new(MuSig2SignSweepRes) + err := c.cc.Invoke(ctx, "/looprpc.SwapServer/MuSig2SignSweep", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // SwapServerServer is the server API for SwapServer service. // All implementations must embed UnimplementedSwapServerServer // for forward compatibility @@ -221,6 +231,7 @@ type SwapServerServer interface { Probe(context.Context, *ServerProbeRequest) (*ServerProbeResponse, error) RecommendRoutingPlugin(context.Context, *RecommendRoutingPluginReq) (*RecommendRoutingPluginRes, error) ReportRoutingResult(context.Context, *ReportRoutingResultReq) (*ReportRoutingResultRes, error) + MuSig2SignSweep(context.Context, *MuSig2SignSweepReq) (*MuSig2SignSweepRes, error) mustEmbedUnimplementedSwapServerServer() } @@ -267,6 +278,9 @@ func (UnimplementedSwapServerServer) RecommendRoutingPlugin(context.Context, *Re func (UnimplementedSwapServerServer) ReportRoutingResult(context.Context, *ReportRoutingResultReq) (*ReportRoutingResultRes, error) { return nil, status.Errorf(codes.Unimplemented, "method ReportRoutingResult not implemented") } +func (UnimplementedSwapServerServer) MuSig2SignSweep(context.Context, *MuSig2SignSweepReq) (*MuSig2SignSweepRes, error) { + return nil, status.Errorf(codes.Unimplemented, "method MuSig2SignSweep not implemented") +} func (UnimplementedSwapServerServer) mustEmbedUnimplementedSwapServerServer() {} // UnsafeSwapServerServer may be embedded to opt out of forward compatibility for this service. @@ -520,6 +534,24 @@ func _SwapServer_ReportRoutingResult_Handler(srv interface{}, ctx context.Contex return interceptor(ctx, in, info, handler) } +func _SwapServer_MuSig2SignSweep_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MuSig2SignSweepReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SwapServerServer).MuSig2SignSweep(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/looprpc.SwapServer/MuSig2SignSweep", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SwapServerServer).MuSig2SignSweep(ctx, req.(*MuSig2SignSweepReq)) + } + return interceptor(ctx, in, info, handler) +} + // SwapServer_ServiceDesc is the grpc.ServiceDesc for SwapServer service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -571,6 +603,10 @@ var SwapServer_ServiceDesc = grpc.ServiceDesc{ MethodName: "ReportRoutingResult", Handler: _SwapServer_ReportRoutingResult_Handler, }, + { + MethodName: "MuSig2SignSweep", + Handler: _SwapServer_MuSig2SignSweep_Handler, + }, }, Streams: []grpc.StreamDesc{ { From 82b58e5c0ed7f4cef4d5628dd0d9244d6fab8efa Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Thu, 5 May 2022 11:59:31 +0200 Subject: [PATCH 14/17] loopout: attempt cooperative musig2 sweep This commit adds optional cooperative musig2 sweep by calling the server to create a partial signature for the sweep if we'd otherwise be allowed to spend the htlc. If the cooperative musig2 spend fails, we always fall back to use the scriptpath spend. --- client_test.go | 31 +++- loopout.go | 436 +++++++++++++++++++++++++++++++++++++++-------- loopout_test.go | 116 ++++++++++--- swap/htlc.go | 4 +- sweep/sweeper.go | 60 +++++++ 5 files changed, 546 insertions(+), 101 deletions(-) diff --git a/client_test.go b/client_test.go index 7a77f10..46b5a28 100644 --- a/client_test.go +++ b/client_test.go @@ -309,7 +309,6 @@ func testLoopOutResume(t *testing.T, confs uint32, expired, preimageRevealed, // Because there is no reliable payment yet, an invoice is assumed to be // paid after resume. - testLoopOutSuccess(ctx, amt, hash, func(r error) {}, func(r error) {}, @@ -336,14 +335,31 @@ func testLoopOutSuccess(ctx *testContext, amt btcutil.Amount, hash lntypes.Hash, // Publish tick. ctx.expiryChan <- testTime - // Expect a signing request. - <-ctx.Lnd.SignOutputRawChannel + // Expect a signing request in the non taproot case. + if scriptVersion != swap.HtlcV3 { + <-ctx.Lnd.SignOutputRawChannel + } if !preimageRevealed { ctx.assertStatus(loopdb.StatePreimageRevealed) ctx.assertStorePreimageReveal() } + // When using taproot htlcs the flow is different as we do reveal the + // preimage before sweeping in order for the server to trust us with + // our MuSig2 signing attempts. + if scriptVersion == swap.HtlcV3 { + ctx.assertPreimagePush(testPreimage) + + // Try MuSig2 signing first and fail it so that we go for a + // normal sweep. + for i := 0; i < maxMusigSweepRetries; i++ { + ctx.expiryChan <- testTime + ctx.assertPreimagePush(testPreimage) + } + <-ctx.Lnd.SignOutputRawChannel + } + // Expect client on-chain sweep of HTLC. sweepTx := ctx.ReceiveTx() @@ -376,10 +392,11 @@ func testLoopOutSuccess(ctx *testContext, amt btcutil.Amount, hash lntypes.Hash, preimage, err := lntypes.MakePreimage(clientPreImage) require.NoError(ctx.T, err) - ctx.assertPreimagePush(preimage) - - // Simulate server pulling payment. - signalSwapPaymentResult(nil) + if scriptVersion != swap.HtlcV3 { + ctx.assertPreimagePush(preimage) + // Simulate server pulling payment. + signalSwapPaymentResult(nil) + } ctx.NotifySpend(sweepTx, 0) diff --git a/loopout.go b/loopout.go index 9368e40..6fff4bd 100644 --- a/loopout.go +++ b/loopout.go @@ -10,8 +10,11 @@ import ( "sync" "time" + "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/lightninglabs/lndclient" "github.com/lightninglabs/loop/labels" @@ -20,18 +23,25 @@ import ( "github.com/lightninglabs/loop/sweep" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/zpay32" ) -// loopInternalHops indicate the number of hops that a loop out swap makes in -// the server's off-chain infrastructure. We are ok reporting failure distances -// from the server up until this point, because every swap takes these two -// hops, so surfacing this information does not identify the client in any way. -// After this point, the client does not report failure distances, so that -// sender-privacy is preserved. -const loopInternalHops = 2 +const ( + // loopInternalHops indicate the number of hops that a loop out swap + // makes in the server's off-chain infrastructure. We are ok reporting + // failure distances from the server up until this point, because every + // swap takes these two hops, so surfacing this information does not + // identify the client in any way. After this point, the client does not + // report failure distances, so that sender-privacy is preserved. + loopInternalHops = 2 + + // We'll try to sweep with MuSig2 at most 10 times. If that fails we'll + // fail back to using standard scriptspend sweep. + maxMusigSweepRetries = 10 +) var ( // MinLoopOutPreimageRevealDelta configures the minimum number of @@ -169,8 +179,8 @@ func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig, SwapContract: loopdb.SwapContract{ InitiationHeight: currentHeight, InitiationTime: initiationTime, - ReceiverKey: receiverKey, SenderKey: swapResp.senderKey, + ReceiverKey: receiverKey, ClientKeyLocator: keyDesc.KeyLocator, Preimage: swapPreimage, AmountRequested: request.Amount, @@ -526,11 +536,8 @@ func (s *loopOutSwap) executeSwap(globalCtx context.Context) error { } // Try to spend htlc and continue (rbf) until a spend has confirmed. - spendDetails, err := s.waitForHtlcSpendConfirmed(globalCtx, - *htlcOutpoint, - func() error { - return s.sweep(globalCtx, *htlcOutpoint, htlcValue) - }, + spendDetails, err := s.waitForHtlcSpendConfirmed( + globalCtx, *htlcOutpoint, htlcValue, ) if err != nil { return err @@ -1025,14 +1032,14 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) ( // sweep offchain. So we must make sure we sweep successfully before on-chain // timeout. func (s *loopOutSwap) waitForHtlcSpendConfirmed(globalCtx context.Context, - htlc wire.OutPoint, spendFunc func() error) (*chainntnfs.SpendDetail, - error) { + htlcOutpoint wire.OutPoint, htlcValue btcutil.Amount) ( + *chainntnfs.SpendDetail, error) { // Register the htlc spend notification. ctx, cancel := context.WithCancel(globalCtx) defer cancel() spendChan, spendErr, err := s.lnd.ChainNotifier.RegisterSpendNtfn( - ctx, &htlc, s.htlc.PkScript, s.InitiationHeight, + ctx, &htlcOutpoint, s.htlc.PkScript, s.InitiationHeight, ) if err != nil { return nil, fmt.Errorf("register spend ntfn: %v", err) @@ -1048,16 +1055,26 @@ func (s *loopOutSwap) waitForHtlcSpendConfirmed(globalCtx context.Context, return nil, fmt.Errorf("track payment: %v", err) } - // paymentComplete tracks whether our payment is complete, and is used - // to decide whether we need to push our preimage to the server. - var paymentComplete bool + var ( + // paymentComplete tracks whether our payment is complete, and + // is used to decide whether we need to push our preimage to + // the server. + paymentComplete bool + // musigSweepTryCount tracts the number of cooperative, MuSig2 + // sweep attempts. + musigSweepTryCount int + // musigSweepSuccess tracks whether at least one MuSig2 sweep + // txn was successfully published to the mempool. + musigSweepSuccess bool + ) timerChan := s.timerFactory(republishDelay) for { select { // Htlc spend, break loop. case spendDetails := <-spendChan: - s.log.Infof("Htlc spend by tx: %v", spendDetails.SpenderTxHash) + s.log.Infof("Htlc spend by tx: %v", + spendDetails.SpenderTxHash) return spendDetails, nil @@ -1113,23 +1130,112 @@ func (s *loopOutSwap) waitForHtlcSpendConfirmed(globalCtx context.Context, // Some time after start or after arrival of a new block, try // to spend again. case <-timerChan: - err := spendFunc() - if err != nil { - return nil, err - } + if IsTaprootSwap(&s.SwapContract) { + // sweepConfTarget will return false if the + // preimage is not revealed yet but the conf + // target is closer than 20 blocks. In this case + // to be sure we won't attempt to sweep at all + // and we won't reveal the preimage either. + _, canSweep := s.sweepConfTarget() + if !canSweep { + s.log.Infof("Aborting swap, timed " + + "out on-chain") + + s.state = loopdb.StateFailTimeout + err := s.persistState(ctx) + if err != nil { + log.Warnf("unable to persist " + + "state") + } - // If the result of our spend func was that the swap - // has reached a final state, then we return nil spend - // details, because there is no further action required - // for this swap. - if s.state.Type() != loopdb.StateTypePending { - return nil, nil - } + return nil, nil + } + + // When using taproot HTLCs we're pushing the + // preimage before attempting to sweep. This + // way the server will know that the swap will + // go through and we'll be able to MuSig2 + // cosign our sweep transaction. In the worst + // case if the server is uncooperative for any + // reason we can still sweep using scriptpath + // spend. + err = s.setStatePreimageRevealed(ctx) + if err != nil { + return nil, err + } + + if !paymentComplete { + // Push the preimage for as long as the + // server is able to settle the swap + // invoice. So that we can continue + // with the MuSig2 sweep afterwards. + s.pushPreimage(ctx) + } + + // Now attempt to publish a MuSig2 sweep txn. + // Only attempt at most maxMusigSweepRetires + // times to still leave time for an emergency + // script path sweep. + if musigSweepTryCount < maxMusigSweepRetries { + success := s.sweepMuSig2( + ctx, htlcOutpoint, htlcValue, + ) + if !success { + musigSweepTryCount++ + } else { + // Mark that we had a sweep + // that was successful. There's + // no need for the script spend + // now we can just keep pushing + // new sweeps to bump the fee. + musigSweepSuccess = true + } + } else if !musigSweepSuccess { + // Attempt to script path sweep. If the + // sweep fails, we can't do any better + // than go on and try again later as + // the preimage is alredy revealed and + // the server settled the swap payment. + // From the server's point of view the + // swap is succeeded at this point so + // we are free to retry as long as we + // want. + err := s.sweep( + ctx, htlcOutpoint, htlcValue, + ) + if err != nil { + log.Warnf("Failed to publish "+ + "non-cooperative "+ + "sweep: %v", err) + } + } - // If our off chain payment is not yet complete, we - // try to push our preimage to the server. - if !paymentComplete { - s.pushPreimage(ctx) + // If the result of our spend func was that the + // swap has reached a final state, then we + // return nil spend details, because there is + // no further action required for this swap. + if s.state.Type() != loopdb.StateTypePending { + return nil, nil + } + } else { + err := s.sweep(ctx, htlcOutpoint, htlcValue) + if err != nil { + return nil, err + } + + // If the result of our spend func was that the + // swap has reached a final state, then we + // return nil spend details, because there is no + // further action required for this swap. + if s.state.Type() != loopdb.StateTypePending { + return nil, nil + } + + // If our off chain payment is not yet complete, + // we try to push our preimage to the server. + if !paymentComplete { + s.pushPreimage(ctx) + } } // Context canceled. @@ -1238,24 +1344,120 @@ func (s *loopOutSwap) failOffChain(ctx context.Context, paymentType paymentType, } } -// sweep tries to sweep the given htlc to a destination address. It takes into -// account the max miner fee and marks the preimage as revealed when it -// published the tx. If the preimage has not yet been revealed, and the time -// during which we can safely reveal it has passed, the swap will be marked -// as failed, and the function will return. -// -// TODO: Use lnd sweeper? -func (s *loopOutSwap) sweep(ctx context.Context, - htlcOutpoint wire.OutPoint, - htlcValue btcutil.Amount) error { +// createMuSig2SweepTxn creates a taproot keyspend sweep transaction and +// attempts to cooperate with the server to create a MuSig2 signature witness. +func (s *loopOutSwap) createMuSig2SweepTxn( + ctx context.Context, htlcOutpoint wire.OutPoint, + htlcValue btcutil.Amount, fee btcutil.Amount) (*wire.MsgTx, error) { - witnessFunc := func(sig []byte) (wire.TxWitness, error) { - return s.htlc.GenSuccessWitness(sig, s.Preimage) + // First assemble our taproot keyspend sweep transaction and get the + // sig hash. + sweepTx, sigHash, err := s.sweeper.CreateUnsignedTaprootKeySpendSweepTx( + ctx, uint32(s.height), s.htlc, htlcOutpoint, htlcValue, fee, + s.DestAddr, + ) + if err != nil { + return nil, err } - // Retrieve the full script required to unlock the output. - redeemScript := s.htlc.SuccessScript() + var schnorrSenderKey, schnorrReceiverKey [32]byte + copy(schnorrSenderKey[:], s.SenderKey[1:]) + copy(schnorrReceiverKey[:], s.ReceiverKey[1:]) + + htlc, ok := s.htlc.HtlcScript.(*swap.HtlcScriptV3) + if !ok { + return nil, fmt.Errorf("non taproot htlc") + } + + // Now we're creating a local MuSig2 session using the receiver key's + // key locator and the htlc's root hash. + musig2SessionInfo, err := s.lnd.Signer.MuSig2CreateSession( + ctx, &s.ClientKeyLocator, + [][32]byte{schnorrSenderKey, schnorrReceiverKey}, + lndclient.MuSig2TaprootTweakOpt(htlc.RootHash[:], false), + ) + if err != nil { + return nil, err + } + + // With the session active, we can now send the server our public nonce + // and the sig hash, so that it can create it's own MuSig2 session and + // return the server side nonce and partial signature. + serverNonce, serverSig, err := s.swapKit.server.MuSig2SignSweep( + ctx, s.SwapContract.ProtocolVersion, s.hash, + s.swapInvoicePaymentAddr, musig2SessionInfo.PublicNonce[:], + sigHash, + ) + if err != nil { + return nil, err + } + + var serverPublicNonce [musig2.PubNonceSize]byte + copy(serverPublicNonce[:], serverNonce) + + // Register the server's nonce before attempting to create our partial + // signature. + haveAllNonces, err := s.lnd.Signer.MuSig2RegisterNonces( + ctx, musig2SessionInfo.SessionID, + [][musig2.PubNonceSize]byte{serverPublicNonce}, + ) + if err != nil { + return nil, err + } + + // Sanity check that we have all the nonces. + if !haveAllNonces { + return nil, fmt.Errorf("invalid MuSig2 session: nonces missing") + } + + var digest [32]byte + copy(digest[:], sigHash) + + // Since our MuSig2 session has all nonces, we can now create the local + // partial signature by signing the sig hash. + _, err = s.lnd.Signer.MuSig2Sign( + ctx, musig2SessionInfo.SessionID, digest, false, + ) + if err != nil { + return nil, err + } + + // Now combine the partial signatures to use the final combined + // signature in the sweep transaction's witness. + haveAllSigs, finalSig, err := s.lnd.Signer.MuSig2CombineSig( + ctx, musig2SessionInfo.SessionID, [][]byte{serverSig}, + ) + if err != nil { + return nil, err + } + + if !haveAllSigs { + return nil, fmt.Errorf("failed to combine signatures") + } + + // To be sure that we're good, parse and validate that the combined + // signature is indeed valid for the sig hash and the internal pubkey. + sig, err := schnorr.ParseSignature(finalSig) + if err != nil { + return nil, err + } + + if !sig.Verify(sigHash, htlc.TaprootKey) { + return nil, fmt.Errorf("invalid combined signature") + } + // Now that we know the signature is correct, we can fill it in to our + // witness. + sweepTx.TxIn[0].Witness = wire.TxWitness{ + finalSig, + } + + return sweepTx, nil +} + +// sweepConfTarget returns the confirmation target for the htlc sweep or false +// if we're too late. +func (s *loopOutSwap) sweepConfTarget() (int32, bool) { remainingBlocks := s.CltvExpiry - s.height blocksToLastReveal := remainingBlocks - MinLoopOutPreimageRevealDelta preimageRevealed := s.state == loopdb.StatePreimageRevealed @@ -1271,7 +1473,7 @@ func (s *loopOutSwap) sweep(ctx context.Context, s.height) s.state = loopdb.StateFailTimeout - return nil + return 0, false } // Calculate the transaction fee based on the confirmation target @@ -1286,42 +1488,84 @@ func (s *loopOutSwap) sweep(ctx context.Context, confTarget = DefaultSweepConfTarget } - fee, err := s.sweeper.GetSweepFee( - ctx, s.htlc.AddSuccessToEstimator, s.DestAddr, confTarget, - ) - if err != nil { - return err - } + return confTarget, true +} +// clampSweepFee will clamp the passed in sweep fee to the maximum configured +// miner fee. Returns false if sweeping should not continue. Note that in the +// MuSig2 case we always continue as the preimage is revealed to the server +// before cooperatively signing the sweep transaction. +func (s *loopOutSwap) clampSweepFee(fee btcutil.Amount) (btcutil.Amount, bool) { // Ensure it doesn't exceed our maximum fee allowed. if fee > s.MaxMinerFee { s.log.Warnf("Required fee %v exceeds max miner fee of %v", fee, s.MaxMinerFee) - if preimageRevealed { + if s.state == loopdb.StatePreimageRevealed { // The currently required fee exceeds the max, but we // already revealed the preimage. The best we can do now // is to republish with the max fee. fee = s.MaxMinerFee } else { s.log.Warnf("Not revealing preimage") - return nil + return 0, false } } - // Create sweep tx. - sweepTx, err := s.sweeper.CreateSweepTx( - ctx, s.height, s.htlc.SuccessSequence(), s.htlc, htlcOutpoint, - s.ReceiverKey, redeemScript, witnessFunc, htlcValue, fee, - s.DestAddr, + return fee, true +} + +// sweepMuSig2 attempts to sweep the on-chain HTLC using MuSig2. If anything +// fails, we'll log it but will simply return to allow further retries. Since +// the preimage is revealed by the time we attempt to MuSig2 sweep, we'll need +// to fall back to a script spend sweep if all MuSig2 sweep attempts fail (for +// example the server could be down due to maintenance or any other issue +// making the cooperative sweep fail). +func (s *loopOutSwap) sweepMuSig2(ctx context.Context, + htlcOutpoint wire.OutPoint, htlcValue btcutil.Amount) bool { + + addInputToEstimator := func(e *input.TxWeightEstimator) error { + e.AddTaprootKeySpendInput(txscript.SigHashDefault) + return nil + } + + confTarget, _ := s.sweepConfTarget() + fee, err := s.sweeper.GetSweepFee( + ctx, addInputToEstimator, s.DestAddr, confTarget, ) if err != nil { - return err + s.log.Warnf("Failed to estimate fee MuSig2 sweep txn: %v", err) + return false } - // Before publishing the tx, already mark the preimage as revealed. This - // is a precaution in case the publish call never returns and would - // leave us thinking we didn't reveal yet. + fee, _ = s.clampSweepFee(fee) + + // Now attempt the co-signing of the txn. + sweepTx, err := s.createMuSig2SweepTxn( + ctx, htlcOutpoint, htlcValue, fee, + ) + if err != nil { + s.log.Warnf("Failed to create MuSig2 sweep txn: %v", err) + return false + } + + // Finally, try publish the txn. + s.log.Infof("Sweep on chain HTLC using MuSig2 to address %v "+ + "fee %v (tx %v)", s.DestAddr, fee, sweepTx.TxHash()) + + err = s.lnd.WalletKit.PublishTransaction( + ctx, sweepTx, + labels.LoopOutSweepSuccess(swap.ShortHash(&s.hash)), + ) + if err != nil { + s.log.Warnf("Publish of MuSig2 sweep failed: %v", err) + return false + } + + return true +} + +func (s *loopOutSwap) setStatePreimageRevealed(ctx context.Context) error { if s.state != loopdb.StatePreimageRevealed { s.state = loopdb.StatePreimageRevealed @@ -1331,6 +1575,60 @@ func (s *loopOutSwap) sweep(ctx context.Context, } } + return nil +} + +// sweep tries to sweep the given htlc to a destination address. It takes into +// account the max miner fee and unless the preimage is already revealed +// (MuSig2 case), marks the preimage as revealed when it published the tx. If +// the preimage has not yet been revealed, and the time during which we can +// safely reveal it has passed, the swap will be marked as failed, and the +// function will return. +func (s *loopOutSwap) sweep(ctx context.Context, htlcOutpoint wire.OutPoint, + htlcValue btcutil.Amount) error { + + confTarget, canSweep := s.sweepConfTarget() + if !canSweep { + return nil + } + + fee, err := s.sweeper.GetSweepFee( + ctx, s.htlc.AddSuccessToEstimator, s.DestAddr, confTarget, + ) + if err != nil { + return err + } + + fee, canSweep = s.clampSweepFee(fee) + if !canSweep { + return nil + } + + witnessFunc := func(sig []byte) (wire.TxWitness, error) { + return s.htlc.GenSuccessWitness(sig, s.Preimage) + } + + // Retrieve the full script required to unlock the output. + redeemScript := s.htlc.SuccessScript() + + // Create sweep tx. + sweepTx, err := s.sweeper.CreateSweepTx( + ctx, s.height, s.htlc.SuccessSequence(), s.htlc, + htlcOutpoint, s.ReceiverKey, redeemScript, witnessFunc, + htlcValue, fee, s.DestAddr, + ) + if err != nil { + return err + } + + // Before publishing the tx, already mark the preimage as revealed. This + // is a precaution in case the publish call never returns and would + // leave us thinking we didn't reveal yet. + err = s.setStatePreimageRevealed(ctx) + if err != nil { + return err + } + // Publish tx. s.log.Infof("Sweep on chain HTLC to address %v with fee %v (tx %v)", s.DestAddr, fee, sweepTx.TxHash()) @@ -1364,8 +1662,8 @@ func validateLoopOutContract(lnd *lndclient.LndServices, if swapInvoiceHash != swapHash { return fmt.Errorf( - "cannot initiate swap, swap invoice hash %v not equal generated swap hash %v", - swapInvoiceHash, swapHash) + "cannot initiate swap, swap invoice hash %v not equal "+ + "generated swap hash %v", swapInvoiceHash, swapHash) } _, _, _, prepayInvoiceAmt, err := swap.DecodeInvoice( diff --git a/loopout_test.go b/loopout_test.go index d23e1a3..5af0ee9 100644 --- a/loopout_test.go +++ b/loopout_test.go @@ -39,7 +39,6 @@ func TestLoopOutPaymentParameters(t *testing.T) { // TestLoopOutPaymentParameters tests the first part of the loop out process up // to the point where the off-chain payments are made. func testLoopOutPaymentParameters(t *testing.T) { - defer test.Guard(t)() // Set up test context objects. @@ -372,7 +371,9 @@ func testCustomSweepConfTarget(t *testing.T) { expiryChan <- time.Now() // Expect a signing request for the HTLC success transaction. - <-ctx.Lnd.SignOutputRawChannel + if !IsTaprootSwap(&swap.SwapContract) { + <-ctx.Lnd.SignOutputRawChannel + } cfg.store.(*storeMock).assertLoopOutState(loopdb.StatePreimageRevealed) status := <-statusChan @@ -381,6 +382,24 @@ func testCustomSweepConfTarget(t *testing.T) { loopdb.StatePreimageRevealed, status.State) } + // When using taproot htlcs the flow is different as we do reveal the + // preimage before sweeping in order for the server to trust us with + // our MuSig2 signing attempts. + if IsTaprootSwap(&swap.SwapContract) { + preimage := <-server.preimagePush + require.Equal(t, swap.Preimage, preimage) + + // Try MuSig2 signing first and fail it so that we go for a + // normal sweep. + for i := 0; i < maxMusigSweepRetries; i++ { + expiryChan <- time.Now() + preimage := <-server.preimagePush + require.Equal(t, swap.Preimage, preimage) + } + + <-ctx.Lnd.SignOutputRawChannel + } + // assertSweepTx performs some sanity checks on a sweep transaction to // ensure it was constructed correctly. assertSweepTx := func(expConfTarget int32) *wire.MsgTx { @@ -424,8 +443,10 @@ func testCustomSweepConfTarget(t *testing.T) { // Once we have published an on chain sweep, we expect a preimage to // have been pushed to our server. - preimage := <-server.preimagePush - require.Equal(t, swap.Preimage, preimage) + if !IsTaprootSwap(&swap.SwapContract) { + preimage := <-server.preimagePush + require.Equal(t, swap.Preimage, preimage) + } // Now that we have pushed our preimage to the sever, we send an update // indicating that our off chain htlc is settled. We do this so that @@ -581,6 +602,36 @@ func testPreimagePush(t *testing.T) { // preimage is not revealed, we also do not expect a preimage push. expiryChan <- testTime + // When using taproot htlcs the flow is different as we do reveal the + // preimage before sweeping in order for the server to trust us with + // our MuSig2 signing attempts. + if IsTaprootSwap(&swap.SwapContract) { + cfg.store.(*storeMock).assertLoopOutState( + loopdb.StatePreimageRevealed, + ) + status := <-statusChan + require.Equal( + t, status.State, loopdb.StatePreimageRevealed, + ) + + preimage := <-server.preimagePush + require.Equal(t, swap.Preimage, preimage) + + // Try MuSig2 signing first and fail it so that we go for a + // normal sweep. + for i := 0; i < maxMusigSweepRetries; i++ { + expiryChan <- time.Now() + + preimage := <-server.preimagePush + require.Equal(t, swap.Preimage, preimage) + } + + <-ctx.Lnd.SignOutputRawChannel + + // We expect the sweep tx to have been published. + ctx.ReceiveTx() + } + // Since we don't have a reliable mechanism to non-intrusively avoid // races by setting the fee estimate too soon, let's sleep here a bit // to ensure the first sweep fails. @@ -597,30 +648,45 @@ func testPreimagePush(t *testing.T) { blockEpochChan <- ctx.Lnd.Height + 2 expiryChan <- testTime + if IsTaprootSwap(&swap.SwapContract) { + preimage := <-server.preimagePush + require.Equal(t, swap.Preimage, preimage) + } + // Expect a signing request for the HTLC success transaction. <-ctx.Lnd.SignOutputRawChannel - // This is the first time we have swept, so we expect our preimage - // revealed state to be set. - cfg.store.(*storeMock).assertLoopOutState(loopdb.StatePreimageRevealed) - status := <-statusChan - require.Equal( - t, status.State, loopdb.StatePreimageRevealed, - ) + if !IsTaprootSwap(&swap.SwapContract) { + // This is the first time we have swept, so we expect our + // preimage revealed state to be set. + cfg.store.(*storeMock).assertLoopOutState( + loopdb.StatePreimageRevealed, + ) + status := <-statusChan + require.Equal( + t, status.State, loopdb.StatePreimageRevealed, + ) + } // We expect the sweep tx to have been published. ctx.ReceiveTx() - // Once we have published an on chain sweep, we expect a preimage to - // have been pushed to the server after the sweep. - preimage := <-server.preimagePush - require.Equal(t, swap.Preimage, preimage) + if !IsTaprootSwap(&swap.SwapContract) { + // Once we have published an on chain sweep, we expect a + // preimage to have been pushed to the server after the sweep. + preimage := <-server.preimagePush + require.Equal(t, swap.Preimage, preimage) + } // To mock a server failure, we do not send a payment settled update // for our off chain payment yet. We also do not confirm our sweep on // chain yet so we can test our preimage push retry logic. Instead, we // tick the expiry chan again to prompt another sweep. expiryChan <- testTime + if IsTaprootSwap(&swap.SwapContract) { + preimage := <-server.preimagePush + require.Equal(t, swap.Preimage, preimage) + } // We expect another signing request for out sweep, and publish of our // sweep transaction. @@ -630,8 +696,11 @@ func testPreimagePush(t *testing.T) { // Since we have not yet been notified of an off chain settle, and we // have attempted to sweep again, we expect another preimage push // attempt. - preimage = <-server.preimagePush - require.Equal(t, swap.Preimage, preimage) + + if !IsTaprootSwap(&swap.SwapContract) { + preimage := <-server.preimagePush + require.Equal(t, swap.Preimage, preimage) + } // This time, we send a payment succeeded update into our payment stream // to reflect that the server received our preimage push and settled off @@ -652,7 +721,7 @@ func testPreimagePush(t *testing.T) { ctx.NotifySpend(sweepTx, 0) cfg.store.(*storeMock).assertLoopOutState(loopdb.StateSuccess) - status = <-statusChan + status := <-statusChan require.Equal( t, status.State, loopdb.StateSuccess, ) @@ -668,12 +737,11 @@ func TestExpiryBeforeReveal(t *testing.T) { testExpiryBeforeReveal(t) }) - t.Run("experimental protocol", func(t *testing.T) { - loopdb.EnableExperimentalProtocol() - defer loopdb.ResetCurrentProtocolVersion() - - testExpiryBeforeReveal(t) - }) + // Note that there's no point of testing this case with the new + // protocol where we use taproot htlc and attempt MuSig2 sweep. The + // reason is that the preimage is revealed to the server once the + // htlc is confirmed in order to facilitate the cooperative signing of + // the sweep transaction. } func testExpiryBeforeReveal(t *testing.T) { diff --git a/swap/htlc.go b/swap/htlc.go index 5df0309..3fdc7c9 100644 --- a/swap/htlc.go +++ b/swap/htlc.go @@ -866,7 +866,9 @@ func (h *HtlcScriptV3) GenTimeoutWitness( // IsSuccessWitness checks whether the given stack is valid for // redeeming the htlc. func (h *HtlcScriptV3) IsSuccessWitness(witness wire.TxWitness) bool { - return len(witness) == 4 + // The witness has four elements if this is a script spend or one + // element if this is a keyspend. + return len(witness) == 4 || len(witness) == 1 } // TimeoutScript returns the redeem script required to unlock the htlc after diff --git a/sweep/sweeper.go b/sweep/sweeper.go index 775fe19..7389a9c 100644 --- a/sweep/sweeper.go +++ b/sweep/sweeper.go @@ -19,6 +19,66 @@ type Sweeper struct { Lnd *lndclient.LndServices } +// CreateUnsignedTaprootKeySpendSweepTx creates a taproot htlc sweep tx using +// keyspend. Returns the raw unsigned txn and the sighash or an error. +func (s *Sweeper) CreateUnsignedTaprootKeySpendSweepTx( + ctx context.Context, lockTime uint32, + htlc *swap.Htlc, htlcOutpoint wire.OutPoint, + amount, fee btcutil.Amount, destAddr btcutil.Address) ( + *wire.MsgTx, []byte, error) { + + if htlc.Version != swap.HtlcV3 { + return nil, nil, fmt.Errorf("invalid htlc version") + } + + // Compose tx. + sweepTx := wire.NewMsgTx(2) + sweepTx.LockTime = lockTime + + // Add HTLC input. + sweepTx.AddTxIn(&wire.TxIn{ + PreviousOutPoint: htlcOutpoint, + SignatureScript: htlc.SigScript, + }) + + // Add output for the destination address. + sweepPkScript, err := txscript.PayToAddrScript(destAddr) + if err != nil { + return nil, nil, err + } + + sweepTx.AddTxOut(&wire.TxOut{ + PkScript: sweepPkScript, + Value: int64(amount - fee), + }) + + // We need our previous outputs for taproot spends, and there's no + // harm including them for segwit v0, so we always include our prevOut. + prevOut := []*wire.TxOut{ + { + Value: int64(amount), + PkScript: htlc.PkScript, + }, + } + + // We now need to create the raw sighash of the transaction, as that + // will be the message we're signing collaboratively. + prevOutputFetcher := txscript.NewCannedPrevOutputFetcher( + prevOut[0].PkScript, prevOut[0].Value, + ) + sigHashes := txscript.NewTxSigHashes(sweepTx, prevOutputFetcher) + + taprootSigHash, err := txscript.CalcTaprootSignatureHash( + sigHashes, txscript.SigHashDefault, sweepTx, 0, + prevOutputFetcher, + ) + if err != nil { + return nil, nil, err + } + + return sweepTx, taprootSigHash, nil +} + // CreateSweepTx creates an htlc sweep tx. func (s *Sweeper) CreateSweepTx( globalCtx context.Context, height int32, sequence uint32, From 5d7b0abdf559ea976086dbc688a8b784b9e43cdb Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Fri, 24 Jun 2022 13:57:42 +0200 Subject: [PATCH 15/17] loopout: add unit test for the MuSig2 sweep case --- client.go | 14 +++ executor.go | 4 + loopout.go | 11 +- loopout_test.go | 238 ++++++++++++++++++++++++++++++++++++++------ test/signer_mock.go | 2 +- testcontext_test.go | 12 +++ 6 files changed, 244 insertions(+), 37 deletions(-) diff --git a/client.go b/client.go index bec66a2..5e739c0 100644 --- a/client.go +++ b/client.go @@ -9,6 +9,8 @@ import ( "sync/atomic" "time" + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/schnorr" "github.com/btcsuite/btcd/btcutil" "github.com/lightninglabs/aperture/lsat" "github.com/lightninglabs/lndclient" @@ -158,6 +160,18 @@ func NewClient(dbDir string, cfg *ClientConfig) (*Client, func(), error) { totalPaymentTimeout: cfg.TotalPaymentTimeout, maxPaymentRetries: cfg.MaxPaymentRetries, cancelSwap: swapServerClient.CancelLoopOutSwap, + verifySchnorrSig: func(pubKey *btcec.PublicKey, hash, sig []byte) error { + schnorrSig, err := schnorr.ParseSignature(sig) + if err != nil { + return err + } + + if !schnorrSig.Verify(hash, pubKey) { + return fmt.Errorf("invalid signature") + } + + return nil + }, }) client := &Client{ diff --git a/executor.go b/executor.go index 2ac94e7..d0ce0af 100644 --- a/executor.go +++ b/executor.go @@ -8,6 +8,7 @@ import ( "sync/atomic" "time" + "github.com/btcsuite/btcd/btcec/v2" "github.com/lightninglabs/lndclient" "github.com/lightninglabs/loop/loopdb" "github.com/lightninglabs/loop/sweep" @@ -31,6 +32,8 @@ type executorConfig struct { maxPaymentRetries int cancelSwap func(ctx context.Context, details *outCancelDetails) error + + verifySchnorrSig func(pubKey *btcec.PublicKey, hash, sig []byte) error } // executor is responsible for executing swaps. @@ -153,6 +156,7 @@ func (s *executor) run(mainCtx context.Context, totalPaymentTimout: s.executorConfig.totalPaymentTimeout, maxPaymentRetries: s.executorConfig.maxPaymentRetries, cancelSwap: s.executorConfig.cancelSwap, + verifySchnorrSig: s.executorConfig.verifySchnorrSig, }, height) if err != nil && err != context.Canceled { log.Errorf("Execute error: %v", err) diff --git a/loopout.go b/loopout.go index 6fff4bd..0e58f38 100644 --- a/loopout.go +++ b/loopout.go @@ -10,7 +10,7 @@ import ( "sync" "time" - "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -96,6 +96,7 @@ type executeConfig struct { totalPaymentTimout time.Duration maxPaymentRetries int cancelSwap func(context.Context, *outCancelDetails) error + verifySchnorrSig func(pubKey *btcec.PublicKey, hash, sig []byte) error } // loopOutInitResult contains information about a just-initiated loop out swap. @@ -1437,15 +1438,13 @@ func (s *loopOutSwap) createMuSig2SweepTxn( // To be sure that we're good, parse and validate that the combined // signature is indeed valid for the sig hash and the internal pubkey. - sig, err := schnorr.ParseSignature(finalSig) + err = s.executeConfig.verifySchnorrSig( + htlc.TaprootKey, sigHash, finalSig, + ) if err != nil { return nil, err } - if !sig.Verify(sigHash, htlc.TaprootKey) { - return nil, fmt.Errorf("invalid combined signature") - } - // Now that we know the signature is correct, we can fill it in to our // witness. sweepTx.TxIn[0].Witness = wire.TxWitness{ diff --git a/loopout_test.go b/loopout_test.go index 5af0ee9..ea41d10 100644 --- a/loopout_test.go +++ b/loopout_test.go @@ -9,6 +9,7 @@ import ( "time" "github.com/btcsuite/btcd/blockchain" + "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/wire" "github.com/lightninglabs/lndclient" @@ -87,12 +88,13 @@ func testLoopOutPaymentParameters(t *testing.T) { go func() { err := swap.execute(swapCtx, &executeConfig{ - statusChan: statusChan, - sweeper: sweeper, - blockEpochChan: blockEpochChan, - timerFactory: timerFactory, - loopOutMaxParts: maxParts, - cancelSwap: server.CancelLoopOutSwap, + statusChan: statusChan, + sweeper: sweeper, + blockEpochChan: blockEpochChan, + timerFactory: timerFactory, + loopOutMaxParts: maxParts, + cancelSwap: server.CancelLoopOutSwap, + verifySchnorrSig: mockVerifySchnorrSigFail, }, height) if err != nil { log.Error(err) @@ -209,11 +211,12 @@ func testLateHtlcPublish(t *testing.T) { errChan := make(chan error) go func() { err := swap.execute(context.Background(), &executeConfig{ - statusChan: statusChan, - sweeper: sweeper, - blockEpochChan: blockEpochChan, - timerFactory: timerFactory, - cancelSwap: server.CancelLoopOutSwap, + statusChan: statusChan, + sweeper: sweeper, + blockEpochChan: blockEpochChan, + timerFactory: timerFactory, + cancelSwap: server.CancelLoopOutSwap, + verifySchnorrSig: mockVerifySchnorrSigFail, }, height) if err != nil { log.Error(err) @@ -320,11 +323,12 @@ func testCustomSweepConfTarget(t *testing.T) { errChan := make(chan error) go func() { err := swap.execute(context.Background(), &executeConfig{ - statusChan: statusChan, - blockEpochChan: blockEpochChan, - timerFactory: timerFactory, - sweeper: sweeper, - cancelSwap: server.CancelLoopOutSwap, + statusChan: statusChan, + blockEpochChan: blockEpochChan, + timerFactory: timerFactory, + sweeper: sweeper, + cancelSwap: server.CancelLoopOutSwap, + verifySchnorrSig: mockVerifySchnorrSigFail, }, ctx.Lnd.Height) if err != nil { log.Error(err) @@ -550,11 +554,12 @@ func testPreimagePush(t *testing.T) { errChan := make(chan error) go func() { err := swap.execute(context.Background(), &executeConfig{ - statusChan: statusChan, - blockEpochChan: blockEpochChan, - timerFactory: timerFactory, - sweeper: sweeper, - cancelSwap: server.CancelLoopOutSwap, + statusChan: statusChan, + blockEpochChan: blockEpochChan, + timerFactory: timerFactory, + sweeper: sweeper, + cancelSwap: server.CancelLoopOutSwap, + verifySchnorrSig: mockVerifySchnorrSigFail, }, ctx.Lnd.Height) if err != nil { log.Error(err) @@ -783,10 +788,11 @@ func testExpiryBeforeReveal(t *testing.T) { errChan := make(chan error) go func() { err := swap.execute(context.Background(), &executeConfig{ - statusChan: statusChan, - blockEpochChan: blockEpochChan, - timerFactory: timerFactory, - sweeper: sweeper, + statusChan: statusChan, + blockEpochChan: blockEpochChan, + timerFactory: timerFactory, + sweeper: sweeper, + verifySchnorrSig: mockVerifySchnorrSigFail, }, ctx.Lnd.Height) if err != nil { log.Error(err) @@ -909,11 +915,12 @@ func testFailedOffChainCancelation(t *testing.T) { errChan := make(chan error) go func() { cfg := &executeConfig{ - statusChan: statusChan, - sweeper: sweeper, - blockEpochChan: blockEpochChan, - timerFactory: timerFactory, - cancelSwap: server.CancelLoopOutSwap, + statusChan: statusChan, + sweeper: sweeper, + blockEpochChan: blockEpochChan, + timerFactory: timerFactory, + cancelSwap: server.CancelLoopOutSwap, + verifySchnorrSig: mockVerifySchnorrSigFail, } err := swap.execute(context.Background(), cfg, ctx.Lnd.Height) @@ -1011,3 +1018,174 @@ func testFailedOffChainCancelation(t *testing.T) { require.Equal(t, state.State, loopdb.StateFailOffchainPayments) require.NoError(t, <-errChan) } + +// TestLoopOutMuSig2Sweep tests the loop out sweep flow when the MuSig2 signing +// process is successful. +func TestLoopOutMuSig2Sweep(t *testing.T) { + defer test.Guard(t)() + + // TODO(bhandras): remove when MuSig2 is default. + loopdb.EnableExperimentalProtocol() + defer loopdb.ResetCurrentProtocolVersion() + + lnd := test.NewMockLnd() + ctx := test.NewContext(t, lnd) + server := newServerMock(lnd) + + testReq := *testRequest + testReq.SweepConfTarget = 10 + testReq.Expiry = ctx.Lnd.Height + testLoopOutMinOnChainCltvDelta + + // We set our mock fee estimate for our target sweep confs to be our + // max miner fee * 2. With MuSig2 we still expect that the client will + // publish the sweep but with the fee clamped to the maximum allowed + // miner fee as the preimage is revealed before the sweep txn is + // published. + ctx.Lnd.SetFeeEstimate( + testReq.SweepConfTarget, chainfee.SatPerKWeight( + testReq.MaxMinerFee*2, + ), + ) + + cfg := newSwapConfig( + &lnd.LndServices, newStoreMock(t), server, + ) + + initResult, err := newLoopOutSwap( + context.Background(), cfg, ctx.Lnd.Height, &testReq, + ) + require.NoError(t, err) + swap := initResult.swap + + // Set up the required dependencies to execute the swap. + sweeper := &sweep.Sweeper{Lnd: &lnd.LndServices} + blockEpochChan := make(chan interface{}) + statusChan := make(chan SwapInfo) + expiryChan := make(chan time.Time) + timerFactory := func(_ time.Duration) <-chan time.Time { + return expiryChan + } + + errChan := make(chan error) + + // Mock a successful signature verify to make sure we don't fail + // creating the MuSig2 sweep. + mockVerifySchnorrSigSuccess := func(pubKey *btcec.PublicKey, hash, + sig []byte) error { + + return nil + } + + go func() { + err := swap.execute(context.Background(), &executeConfig{ + statusChan: statusChan, + blockEpochChan: blockEpochChan, + timerFactory: timerFactory, + sweeper: sweeper, + cancelSwap: server.CancelLoopOutSwap, + verifySchnorrSig: mockVerifySchnorrSigSuccess, + }, ctx.Lnd.Height) + if err != nil { + log.Error(err) + } + errChan <- err + }() + + // The swap should be found in its initial state. + cfg.store.(*storeMock).assertLoopOutStored() + state := <-statusChan + require.Equal(t, loopdb.StateInitiated, state.State) + + // We'll then pay both the swap and prepay invoice, which should trigger + // the server to publish the on-chain HTLC. + signalSwapPaymentResult := ctx.AssertPaid(swapInvoiceDesc) + signalPrepaymentResult := ctx.AssertPaid(prepayInvoiceDesc) + + signalSwapPaymentResult(nil) + signalPrepaymentResult(nil) + + // Notify the confirmation notification for the HTLC. + ctx.AssertRegisterConf(false, defaultConfirmations) + + blockEpochChan <- ctx.Lnd.Height + 1 + + htlcTx := wire.NewMsgTx(2) + htlcTx.AddTxOut(&wire.TxOut{ + Value: int64(swap.AmountRequested), + PkScript: swap.htlc.PkScript, + }) + + ctx.NotifyConf(htlcTx) + + // The client should then register for a spend of the HTLC and attempt + // to sweep it using the custom confirmation target. + ctx.AssertRegisterSpendNtfn(swap.htlc.PkScript) + + // Assert that we made a query to track our payment, as required for + // preimage push tracking. + trackPayment := ctx.AssertTrackPayment() + + // Tick the expiry channel, we are still using our client confirmation + // target at this stage which has fees higher than our max acceptable + // fee. We do not expect a sweep attempt at this point. Since our + // preimage is not revealed, we also do not expect a preimage push. + expiryChan <- testTime + + // When using taproot htlcs the flow is different as we do reveal the + // preimage before sweeping in order for the server to trust us with + // our MuSig2 signing attempts. + cfg.store.(*storeMock).assertLoopOutState( + loopdb.StatePreimageRevealed, + ) + status := <-statusChan + require.Equal( + t, status.State, loopdb.StatePreimageRevealed, + ) + + preimage := <-server.preimagePush + require.Equal(t, swap.Preimage, preimage) + + // We expect the sweep tx to have been published. + ctx.ReceiveTx() + + // Since we don't have a reliable mechanism to non-intrusively avoid + // races by setting the fee estimate too soon, let's sleep here a bit + // to ensure the first sweep fails. + time.Sleep(500 * time.Millisecond) + + // Now we decrease our fees for the swap's confirmation target to less + // than the maximum miner fee. + ctx.Lnd.SetFeeEstimate(testReq.SweepConfTarget, chainfee.SatPerKWeight( + testReq.MaxMinerFee/2, + )) + + // Now when we report a new block and tick our expiry fee timer, and + // fees are acceptably low so we expect our sweep to be published. + blockEpochChan <- ctx.Lnd.Height + 2 + expiryChan <- testTime + + preimage = <-server.preimagePush + require.Equal(t, swap.Preimage, preimage) + + // We expect the sweep tx to have been published. + sweepTx := ctx.ReceiveTx() + + // This time, we send a payment succeeded update into our payment stream + // to reflect that the server received our preimage push and settled off + // chain. + trackPayment.Updates <- lndclient.PaymentStatus{ + State: lnrpc.Payment_SUCCEEDED, + } + + // Make sure our sweep tx has a single witness indicating keyspend. + require.Len(t, sweepTx.TxIn[0].Witness, 1) + + // Finally, we put this swap out of its misery and notify a successful + // spend our our sweepTx and assert that the swap succeeds. + ctx.NotifySpend(sweepTx, 0) + + cfg.store.(*storeMock).assertLoopOutState(loopdb.StateSuccess) + status = <-statusChan + require.Equal(t, status.State, loopdb.StateSuccess) + require.NoError(t, <-errChan) +} diff --git a/test/signer_mock.go b/test/signer_mock.go index 16a725d..e7e0261 100644 --- a/test/signer_mock.go +++ b/test/signer_mock.go @@ -116,7 +116,7 @@ func (s *mockSigner) MuSig2Sign(context.Context, [32]byte, [32]byte, func (s *mockSigner) MuSig2CombineSig(context.Context, [32]byte, [][]byte) (bool, []byte, error) { - return false, nil, nil + return true, nil, nil } // MuSig2Cleanup removes a session from memory to free up resources. diff --git a/testcontext_test.go b/testcontext_test.go index c846572..afc6a90 100644 --- a/testcontext_test.go +++ b/testcontext_test.go @@ -2,9 +2,11 @@ package loop import ( "context" + "fmt" "testing" "time" + "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/wire" "github.com/lightninglabs/lndclient" @@ -40,6 +42,15 @@ type testContext struct { stop func() } +// mockVerifySchnorrSigFail is used to simulate failed taproot keyspend +// signature verification. If passed to the executeConfig we'll test an +// uncooperative server and will fall back to scriptspend sweep. +func mockVerifySchnorrSigFail(pubKey *btcec.PublicKey, hash, + sig []byte) error { + + return fmt.Errorf("invalid sig") +} + func newSwapClient(config *clientConfig) *Client { sweeper := &sweep.Sweeper{ Lnd: config.LndServices, @@ -53,6 +64,7 @@ func newSwapClient(config *clientConfig) *Client { sweeper: sweeper, createExpiryTimer: config.CreateExpiryTimer, cancelSwap: config.Server.CancelLoopOutSwap, + verifySchnorrSig: mockVerifySchnorrSigFail, }) return &Client{ From 85145ca4bbea1dcde386d85fc08f3dd9c96ec75e Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Thu, 23 Jun 2022 17:11:00 +0100 Subject: [PATCH 16/17] loop: set minimum LND version to 0.15.0 --- loopd/run.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/loopd/run.go b/loopd/run.go index 1122de9..250cd38 100644 --- a/loopd/run.go +++ b/loopd/run.go @@ -26,8 +26,8 @@ var ( // listed build tags/subservers need to be enabled. LoopMinRequiredLndVersion = &verrpc.Version{ AppMajor: 0, - AppMinor: 14, - AppPatch: 2, + AppMinor: 15, + AppPatch: 0, BuildTags: []string{ "signrpc", "walletrpc", "chainrpc", "invoicesrpc", }, From 5f4b34d8b4ee36b2ddc8a4f2f602eacd370502c6 Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Thu, 23 Jun 2022 17:14:00 +0100 Subject: [PATCH 17/17] docs: update release notes --- release_notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/release_notes.md b/release_notes.md index c71d135..06a0e44 100644 --- a/release_notes.md +++ b/release_notes.md @@ -16,6 +16,8 @@ This file tracks release notes for the loop client. #### New Features +* P2TR HTLCs and privacy preserving and cheaper MuSig2 loopout sweeps are now supported as an experimental feature when running `loopd` with the`--experimental` flag. + #### Breaking Changes #### Bug Fixes