From 4253ff744e219bfb853afbeaddc0c03dd352155e Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 3 Mar 2021 19:32:14 -0800 Subject: [PATCH 01/29] lnwire: introduce new explicit ChannelType TLV record In this commit, we add a new TLV record that's intended to be used as an explicit channel commitment type for a new form of funding negotiation, and later on a dynamic commitment upgrade protocol. As defined, we have 3 channel types: base (the OG), tweakless, and anchors w/ zero fee HTLCs. We omit the original variant of anchors as it was never truly deployed from the PoV of lnd. --- lnwire/channel_type.go | 58 +++++++++++++++++++++++++++++++++++++ lnwire/channel_type_test.go | 28 ++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 lnwire/channel_type.go create mode 100644 lnwire/channel_type_test.go diff --git a/lnwire/channel_type.go b/lnwire/channel_type.go new file mode 100644 index 00000000000..a0696048bef --- /dev/null +++ b/lnwire/channel_type.go @@ -0,0 +1,58 @@ +package lnwire + +import ( + "io" + + "github.com/lightningnetwork/lnd/tlv" +) + +const ( + // ChannelTypeRecordType is the type of the experimental record used + // to denote which channel type is being negotiated. + ChannelTypeRecordType tlv.Type = 1 +) + +// ChannelType represents a specific channel type as a set of feature bits that +// comprise it. +type ChannelType RawFeatureVector + +// featureBitLen returns the length in bytes of the encoded feature bits. +func (c ChannelType) featureBitLen() uint64 { + fv := RawFeatureVector(c) + return uint64(fv.SerializeSize()) +} + +// Record returns a TLV record that can be used to encode/decode the channel +// type from a given TLV stream. +func (c *ChannelType) Record() tlv.Record { + return tlv.MakeDynamicRecord( + ChannelTypeRecordType, c, c.featureBitLen, channelTypeEncoder, + channelTypeDecoder, + ) +} + +// channelTypeEncoder is a custom TLV encoder for the ChannelType record. +func channelTypeEncoder(w io.Writer, val interface{}, buf *[8]byte) error { + if v, ok := val.(*ChannelType); ok { + // Encode the feature bits as a byte slice without its length + // prepended, as that's already taken care of by the TLV record. + fv := RawFeatureVector(*v) + return fv.encode(w, fv.SerializeSize(), 8) + } + + return tlv.NewTypeForEncodingErr(val, "lnwire.ChannelType") +} + +// channelTypeDecoder is a custom TLV decoder for the ChannelType record. +func channelTypeDecoder(r io.Reader, val interface{}, buf *[8]byte, l uint64) error { + if v, ok := val.(*ChannelType); ok { + fv := NewRawFeatureVector() + if err := fv.decode(r, int(l), 8); err != nil { + return err + } + *v = ChannelType(*fv) + return nil + } + + return tlv.NewTypeForEncodingErr(val, "lnwire.ChannelType") +} diff --git a/lnwire/channel_type_test.go b/lnwire/channel_type_test.go new file mode 100644 index 00000000000..0edef0779a0 --- /dev/null +++ b/lnwire/channel_type_test.go @@ -0,0 +1,28 @@ +package lnwire + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +// TestChannelTypeEncodeDecode tests that we're able to properly encode and +// decode channel types within TLV streams. +func TestChannelTypeEncodeDecode(t *testing.T) { + t.Parallel() + + chanType := ChannelType(*NewRawFeatureVector( + StaticRemoteKeyRequired, + AnchorsZeroFeeHtlcTxRequired, + )) + + var extraData ExtraOpaqueData + require.NoError(t, extraData.PackRecords(chanType.Record())) + + var chanType2 ChannelType + tlvs, err := extraData.ExtractRecords(chanType2.Record()) + require.NoError(t, err) + + require.Contains(t, tlvs, ChannelTypeRecordType) + require.Equal(t, chanType, chanType2) +} From 822a3afb8a6b51fdc685bc4e839fd562f7aaf6fc Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 3 Mar 2021 19:37:00 -0800 Subject: [PATCH 02/29] lnwire: add new ChannelType field as TLV record to Open/AcceptChannel In this commit, we add a new ChannelType field as a new TLV record to the OpenChannel message. During this change, we make a few tweaks to the generic TLV encode/decode methods for the ExtraOpaqueData struct to have it work on the level of tlv.RecordProducer instead of tlv.Record, as this reduces line noise a bit. We also partially undo existing logic that would attempt to "prepend" any new TLV records to the end of the ExtraOpaqueData if one was already present within the struct. This is based on the assumption that if we've read a message from disk to order to re-send/transmit it, then the ExtraOpaqueData is fully populated so we'll write that as is. Otherwise, a message is being encoded for the first time, and we expect all fields that are known TLV fields to be specified within the struct itself. This change required the unit tests to be modified slightly, as we'll always encode a fresh set of TLV records if none was already specified within the struct. --- lnwire/accept_channel.go | 86 ++++++++---------------------- lnwire/channel_type_test.go | 4 +- lnwire/extra_bytes.go | 37 ++++++++++++- lnwire/extra_bytes_test.go | 22 +++++--- lnwire/lnwire_test.go | 29 +++++----- lnwire/open_channel.go | 31 ++++++++--- lnwire/typed_delivery_addr.go | 6 +-- lnwire/typed_delivery_addr_test.go | 4 +- 8 files changed, 114 insertions(+), 105 deletions(-) diff --git a/lnwire/accept_channel.go b/lnwire/accept_channel.go index f88a1a08fba..3cac6ca9e25 100644 --- a/lnwire/accept_channel.go +++ b/lnwire/accept_channel.go @@ -1,11 +1,11 @@ package lnwire import ( - "fmt" "io" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcutil" + "github.com/lightningnetwork/lnd/tlv" ) // AcceptChannel is the message Bob sends to Alice after she initiates the @@ -94,6 +94,10 @@ type AcceptChannel struct { // and its length followed by the script will be written if it is set. UpfrontShutdownScript DeliveryAddress + // ChannelType is the explicit channel type the initiator wishes to + // open. + ChannelType *ChannelType + // ExtraData is the set of data that was appended to this message to // fill out the full maximum transport message size. These fields can // be used to specify optional data such as custom TLV fields. @@ -116,11 +120,11 @@ var _ Message = (*AcceptChannel)(nil) // // This is part of the lnwire.Message interface. func (a *AcceptChannel) Encode(w io.Writer, pver uint32) error { - // Since the upfront script is encoded as a TLV record, concatenate it - // with the ExtraData, and write them as one. - tlvRecords, err := packShutdownScript( - a.UpfrontShutdownScript, a.ExtraData, - ) + recordProducers := []tlv.RecordProducer{&a.UpfrontShutdownScript} + if a.ChannelType != nil { + recordProducers = append(recordProducers, a.ChannelType) + } + err := EncodeMessageExtraData(&a.ExtraData, recordProducers...) if err != nil { return err } @@ -140,7 +144,7 @@ func (a *AcceptChannel) Encode(w io.Writer, pver uint32) error { a.DelayedPaymentPoint, a.HtlcPoint, a.FirstCommitmentPoint, - tlvRecords, + a.ExtraData, ) } @@ -179,72 +183,24 @@ func (a *AcceptChannel) Decode(r io.Reader, pver uint32) error { return err } - a.UpfrontShutdownScript, a.ExtraData, err = parseShutdownScript( - tlvRecords, + // Next we'll parse out the set of known records, keeping the raw tlv + // bytes untouched to ensure we don't drop any bytes erroneously. + var chanType ChannelType + typeMap, err := tlvRecords.ExtractRecords( + &a.UpfrontShutdownScript, &chanType, ) if err != nil { return err } - return nil -} - -// packShutdownScript takes an upfront shutdown script and an opaque data blob -// and concatenates them. -func packShutdownScript(addr DeliveryAddress, extraData ExtraOpaqueData) ( - ExtraOpaqueData, error) { - - // We'll always write the upfront shutdown script record, regardless of - // the script being empty. - var tlvRecords ExtraOpaqueData - - // Pack it into a data blob as a TLV record. - err := tlvRecords.PackRecords(addr.NewRecord()) - if err != nil { - return nil, fmt.Errorf("unable to pack upfront shutdown "+ - "script as TLV record: %v", err) - } - - // Concatenate the remaining blob with the shutdown script record. - tlvRecords = append(tlvRecords, extraData...) - return tlvRecords, nil -} - -// parseShutdownScript reads and extract the upfront shutdown script from the -// passe data blob. It returns the script, if any, and the remainder of the -// data blob. -// -// This can be used to parse extra data for the OpenChannel and AcceptChannel -// messages, where the shutdown script is mandatory if extra TLV data is -// present. -func parseShutdownScript(tlvRecords ExtraOpaqueData) (DeliveryAddress, - ExtraOpaqueData, error) { - - // If no TLV data is present there can't be any script available. - if len(tlvRecords) == 0 { - return nil, tlvRecords, nil + // Set the corresponding TLV types if they were included in the stream. + if val, ok := typeMap[ChannelTypeRecordType]; ok && val == nil { + a.ChannelType = &chanType } - // Otherwise the shutdown script MUST be present. - var addr DeliveryAddress - tlvs, err := tlvRecords.ExtractRecords(addr.NewRecord()) - if err != nil { - return nil, nil, err - } - - // Not among TLV records, this means the data was invalid. - if _, ok := tlvs[DeliveryAddrType]; !ok { - return nil, nil, fmt.Errorf("no shutdown script in non-empty " + - "data blob") - } + a.ExtraData = tlvRecords - // Now that we have retrieved the address (which can be zero-length), - // we'll remove the bytes encoding it from the TLV data before - // returning it. - addrLen := len(addr) - tlvRecords = tlvRecords[addrLen+2:] - - return addr, tlvRecords, nil + return nil } // MsgType returns the MessageType code which uniquely identifies this message diff --git a/lnwire/channel_type_test.go b/lnwire/channel_type_test.go index 0edef0779a0..dd8e02439aa 100644 --- a/lnwire/channel_type_test.go +++ b/lnwire/channel_type_test.go @@ -17,10 +17,10 @@ func TestChannelTypeEncodeDecode(t *testing.T) { )) var extraData ExtraOpaqueData - require.NoError(t, extraData.PackRecords(chanType.Record())) + require.NoError(t, extraData.PackRecords(&chanType)) var chanType2 ChannelType - tlvs, err := extraData.ExtractRecords(chanType2.Record()) + tlvs, err := extraData.ExtractRecords(&chanType2) require.NoError(t, err) require.Contains(t, tlvs, ChannelTypeRecordType) diff --git a/lnwire/extra_bytes.go b/lnwire/extra_bytes.go index 22fd20bd837..95ca1e384e1 100644 --- a/lnwire/extra_bytes.go +++ b/lnwire/extra_bytes.go @@ -2,6 +2,7 @@ package lnwire import ( "bytes" + "fmt" "io" "io/ioutil" @@ -50,7 +51,17 @@ func (e *ExtraOpaqueData) Decode(r io.Reader) error { // PackRecords attempts to encode the set of tlv records into the target // ExtraOpaqueData instance. The records will be encoded as a raw TLV stream // and stored within the backing slice pointer. -func (e *ExtraOpaqueData) PackRecords(records ...tlv.Record) error { +func (e *ExtraOpaqueData) PackRecords(recordProducers ...tlv.RecordProducer) error { + // First, assemble all the records passed in in series. + records := make([]tlv.Record, 0, len(recordProducers)) + for _, producer := range recordProducers { + records = append(records, producer.Record()) + } + + // Ensure that the set of records are sorted before we encode them into + // the stream, to ensure they're canonical. + tlv.SortRecords(records) + tlvStream, err := tlv.NewStream(records...) if err != nil { return err @@ -70,9 +81,15 @@ func (e *ExtraOpaqueData) PackRecords(records ...tlv.Record) error { // it were a tlv stream. The set of raw parsed types is returned, and any // passed records (if found in the stream) will be parsed into the proper // tlv.Record. -func (e *ExtraOpaqueData) ExtractRecords(records ...tlv.Record) ( +func (e *ExtraOpaqueData) ExtractRecords(recordProducers ...tlv.RecordProducer) ( tlv.TypeMap, error) { + // First, assemble all the records passed in in series. + records := make([]tlv.Record, 0, len(recordProducers)) + for _, producer := range recordProducers { + records = append(records, producer.Record()) + } + extraBytesReader := bytes.NewReader(*e) tlvStream, err := tlv.NewStream(records...) @@ -82,3 +99,19 @@ func (e *ExtraOpaqueData) ExtractRecords(records ...tlv.Record) ( return tlvStream.DecodeWithParsedTypes(extraBytesReader) } + +// EncodeMessageExtraData encodes the given recordProducers into the given +// extraData. +func EncodeMessageExtraData(extraData *ExtraOpaqueData, + recordProducers ...tlv.RecordProducer) error { + + // Treat extraData as a mutable reference. + if extraData == nil { + return fmt.Errorf("extra data cannot be nil") + } + + // Pack in the series of TLV records into this message. The order we + // pass them in doesn't matter, as the method will ensure that things + // are all properly sorted. + return extraData.PackRecords(recordProducers...) +} diff --git a/lnwire/extra_bytes_test.go b/lnwire/extra_bytes_test.go index 39271d6aa29..88ffcc307ca 100644 --- a/lnwire/extra_bytes_test.go +++ b/lnwire/extra_bytes_test.go @@ -86,6 +86,14 @@ func TestExtraOpaqueDataEncodeDecode(t *testing.T) { } } +type recordProducer struct { + record tlv.Record +} + +func (r *recordProducer) Record() tlv.Record { + return r.record +} + // TestExtraOpaqueDataPackUnpackRecords tests that we're able to pack a set of // tlv.Records into a stream, and unpack them on the other side to obtain the // same set of records. @@ -102,23 +110,23 @@ func TestExtraOpaqueDataPackUnpackRecords(t *testing.T) { hop1 uint32 = 99 hop2 uint32 ) - testRecords := []tlv.Record{ - tlv.MakePrimitiveRecord(type1, &channelType1), - tlv.MakePrimitiveRecord(type2, &hop1), + testRecordsProducers := []tlv.RecordProducer{ + &recordProducer{tlv.MakePrimitiveRecord(type1, &channelType1)}, + &recordProducer{tlv.MakePrimitiveRecord(type2, &hop1)}, } // Now that we have our set of sample records and types, we'll encode // them into the passed ExtraOpaqueData instance. var extraBytes ExtraOpaqueData - if err := extraBytes.PackRecords(testRecords...); err != nil { + if err := extraBytes.PackRecords(testRecordsProducers...); err != nil { t.Fatalf("unable to pack records: %v", err) } // We'll now simulate decoding these types _back_ into records on the // other side. - newRecords := []tlv.Record{ - tlv.MakePrimitiveRecord(type1, &channelType2), - tlv.MakePrimitiveRecord(type2, &hop2), + newRecords := []tlv.RecordProducer{ + &recordProducer{tlv.MakePrimitiveRecord(type1, &channelType2)}, + &recordProducer{tlv.MakePrimitiveRecord(type2, &hop2)}, } typeMap, err := extraBytes.ExtractRecords(newRecords...) if err != nil { diff --git a/lnwire/lnwire_test.go b/lnwire/lnwire_test.go index 14082bfe93f..e54afe8072c 100644 --- a/lnwire/lnwire_test.go +++ b/lnwire/lnwire_test.go @@ -18,8 +18,8 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" - "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/tor" + "github.com/stretchr/testify/assert" ) var ( @@ -284,9 +284,7 @@ func TestLightningWireProtocol(t *testing.T) { t.Fatalf("unable to read msg: %v", err) return false } - if !reflect.DeepEqual(msg, newMsg) { - t.Fatalf("messages don't match after re-encoding: %v "+ - "vs %v", spew.Sdump(msg), spew.Sdump(newMsg)) + if !assert.Equalf(t, msg, newMsg, "message mismatch") { return false } @@ -369,17 +367,16 @@ func TestLightningWireProtocol(t *testing.T) { t.Fatalf("unable to generate delivery address: %v", err) return } + + req.ChannelType = new(ChannelType) + *req.ChannelType = ChannelType(*randRawFeatureVector(r)) } else { req.UpfrontShutdownScript = []byte{} } - // 1/2 chance how having more TLV data after the - // shutdown script. + // 1/2 chance additional TLV data. if r.Intn(2) == 0 { - // TLV type 1 of length 2. - req.ExtraData = []byte{1, 2, 0xff, 0xff} - } else { - req.ExtraData = []byte{} + req.ExtraData = []byte{0xfd, 0x00, 0xff, 0x00} } v[0] = reflect.ValueOf(req) @@ -439,16 +436,16 @@ func TestLightningWireProtocol(t *testing.T) { t.Fatalf("unable to generate delivery address: %v", err) return } + + req.ChannelType = new(ChannelType) + *req.ChannelType = ChannelType(*randRawFeatureVector(r)) } else { req.UpfrontShutdownScript = []byte{} } - // 1/2 chance how having more TLV data after the - // shutdown script. + + // 1/2 chance additional TLV data. if r.Intn(2) == 0 { - // TLV type 1 of length 2. - req.ExtraData = []byte{1, 2, 0xff, 0xff} - } else { - req.ExtraData = []byte{} + req.ExtraData = []byte{0xfd, 0x00, 0xff, 0x00} } v[0] = reflect.ValueOf(req) diff --git a/lnwire/open_channel.go b/lnwire/open_channel.go index 9407d0037a7..dca6a8b1c05 100644 --- a/lnwire/open_channel.go +++ b/lnwire/open_channel.go @@ -6,6 +6,7 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcutil" + "github.com/lightningnetwork/lnd/tlv" ) // FundingFlag represents the possible bit mask values for the ChannelFlags @@ -129,6 +130,10 @@ type OpenChannel struct { // and its length followed by the script will be written if it is set. UpfrontShutdownScript DeliveryAddress + // ChannelType is the explicit channel type the initiator wishes to + // open. + ChannelType *ChannelType + // ExtraData is the set of data that was appended to this message to // fill out the full maximum transport message size. These fields can // be used to specify optional data such as custom TLV fields. @@ -151,11 +156,11 @@ var _ Message = (*OpenChannel)(nil) // // This is part of the lnwire.Message interface. func (o *OpenChannel) Encode(w io.Writer, pver uint32) error { - // Since the upfront script is encoded as a TLV record, concatenate it - // with the ExtraData, and write them as one. - tlvRecords, err := packShutdownScript( - o.UpfrontShutdownScript, o.ExtraData, - ) + recordProducers := []tlv.RecordProducer{&o.UpfrontShutdownScript} + if o.ChannelType != nil { + recordProducers = append(recordProducers, o.ChannelType) + } + err := EncodeMessageExtraData(&o.ExtraData, recordProducers...) if err != nil { return err } @@ -179,7 +184,7 @@ func (o *OpenChannel) Encode(w io.Writer, pver uint32) error { o.HtlcPoint, o.FirstCommitmentPoint, o.ChannelFlags, - tlvRecords, + o.ExtraData, ) } @@ -222,13 +227,23 @@ func (o *OpenChannel) Decode(r io.Reader, pver uint32) error { return err } - o.UpfrontShutdownScript, o.ExtraData, err = parseShutdownScript( - tlvRecords, + // Next we'll parse out the set of known records, keeping the raw tlv + // bytes untouched to ensure we don't drop any bytes erroneously. + var chanType ChannelType + typeMap, err := tlvRecords.ExtractRecords( + &o.UpfrontShutdownScript, &chanType, ) if err != nil { return err } + // Set the corresponding TLV types if they were included in the stream. + if val, ok := typeMap[ChannelTypeRecordType]; ok && val == nil { + o.ChannelType = &chanType + } + + o.ExtraData = tlvRecords + return nil } diff --git a/lnwire/typed_delivery_addr.go b/lnwire/typed_delivery_addr.go index 9ad53b1aeed..90a101b346b 100644 --- a/lnwire/typed_delivery_addr.go +++ b/lnwire/typed_delivery_addr.go @@ -24,11 +24,11 @@ const ( // p2wpkh. type DeliveryAddress []byte -// NewRecord returns a TLV record that can be used to encode the delivery -// address within the ExtraData TLV stream. This was intorudced in order to +// Record returns a TLV record that can be used to encode the delivery +// address within the ExtraData TLV stream. This was introduced in order to // allow the OpenChannel/AcceptChannel messages to properly be extended with // TLV types. -func (d *DeliveryAddress) NewRecord() tlv.Record { +func (d *DeliveryAddress) Record() tlv.Record { addrBytes := (*[]byte)(d) return tlv.MakeDynamicRecord( diff --git a/lnwire/typed_delivery_addr_test.go b/lnwire/typed_delivery_addr_test.go index d5d9c703a18..9d00bc8bd8f 100644 --- a/lnwire/typed_delivery_addr_test.go +++ b/lnwire/typed_delivery_addr_test.go @@ -15,13 +15,13 @@ func TestDeliveryAddressEncodeDecode(t *testing.T) { ) var extraData ExtraOpaqueData - err := extraData.PackRecords(addr.NewRecord()) + err := extraData.PackRecords(&addr) if err != nil { t.Fatal(err) } var addr2 DeliveryAddress - tlvs, err := extraData.ExtractRecords(addr2.NewRecord()) + tlvs, err := extraData.ExtractRecords(&addr2) if err != nil { t.Fatal(err) } From 55aef0bad298d89a2b5bab5096791cb42abee113 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 3 Mar 2021 19:39:12 -0800 Subject: [PATCH 03/29] lnwire: add new feature bits for explicit channel type negotiation If these bits are present, then both sides can examine the new CommitmentType TLV field that's present and use this in place of the existing implicit commiment type negotiation. With this change, it's now possible to actually deprecate old unsupported commitment types properly. --- feature/default_sets.go | 4 ++++ feature/deps.go | 4 ++++ lnwire/features.go | 22 ++++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/feature/default_sets.go b/feature/default_sets.go index 9103f903c0a..5ee98792a36 100644 --- a/feature/default_sets.go +++ b/feature/default_sets.go @@ -60,4 +60,8 @@ var defaultSetDesc = setDesc{ lnwire.AMPRequired: { SetInvoiceAmp: {}, // 9A }, + lnwire.ExplicitChannelTypeOptional: { + SetInit: {}, // I + SetNodeAnn: {}, // N + }, } diff --git a/feature/deps.go b/feature/deps.go index 51ee37e9bfc..d6f57cb901c 100644 --- a/feature/deps.go +++ b/feature/deps.go @@ -58,9 +58,13 @@ var deps = depDesc{ lnwire.AnchorsOptional: { lnwire.StaticRemoteKeyOptional: {}, }, + lnwire.AnchorsZeroFeeHtlcTxOptional: { + lnwire.StaticRemoteKeyOptional: {}, + }, lnwire.AMPOptional: { lnwire.PaymentAddrOptional: {}, }, + lnwire.ExplicitChannelTypeOptional: {}, } // ValidateDeps asserts that a feature vector sets all features and their diff --git a/lnwire/features.go b/lnwire/features.go index 9dfa07ee1e3..575413468a2 100644 --- a/lnwire/features.go +++ b/lnwire/features.go @@ -139,6 +139,26 @@ const ( // sender-generated preimages according to BOLT XX. AMPOptional FeatureBit = 31 + // ExplicitChannelTypeRequired is a required bit that denotes that a + // connection established with this node is to use explicit channel + // commitment types for negotiation instead of the existing implicit + // negotiation methods. With this bit, there is no longer a "default" + // implicit channel commitment type, allowing a connection to + // open/maintain types of several channels over its lifetime. + // + // TODO: Decide on actual feature bit value. + ExplicitChannelTypeRequired = 2020 + + // ExplicitChannelTypeOptional is an optional bit that denotes that a + // connection established with this node is to use explicit channel + // commitment types for negotiation instead of the existing implicit + // negotiation methods. With this bit, there is no longer a "default" + // implicit channel commitment type, allowing a connection to + // open/maintain types of several channels over its lifetime. + // + // TODO: Decide on actual feature bit value. + ExplicitChannelTypeOptional = 2021 + // maxAllowedSize is a maximum allowed size of feature vector. // // NOTE: Within the protocol, the maximum allowed message size is 65535 @@ -184,6 +204,8 @@ var Features = map[FeatureBit]string{ WumboChannelsOptional: "wumbo-channels", AMPRequired: "amp", AMPOptional: "amp", + ExplicitChannelTypeOptional: "explicit-commitment-type", + ExplicitChannelTypeRequired: "explicit-commitment-type", } // RawFeatureVector represents a set of feature bits as defined in BOLT-09. A From 268990a21aae0a3142603fecd9fb1daf8a32c388 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 3 Mar 2021 19:39:53 -0800 Subject: [PATCH 04/29] rpc: add new commitment_type field to OpenChannelRequest This field will be examined later down the stack along with the set of feature bits to determine if explicit channel commitment type negotiation is possible or not. --- funding/manager.go | 5 + lnrpc/lightning.pb.go | 1208 +++++++++++++++++----------------- lnrpc/lightning.proto | 22 +- lnrpc/lightning.swagger.json | 12 +- rpcserver.go | 28 + 5 files changed, 667 insertions(+), 608 deletions(-) diff --git a/funding/manager.go b/funding/manager.go index 63269ccb675..2a0473b33d6 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -240,6 +240,11 @@ type InitFundingMsg struct { // protocol. PendingChanID [32]byte + // ChannelType allows the caller to use an explicit channel type for the + // funding negotiation. This type will only be observed if BOTH sides + // support explicit channel type negotiation. + ChannelType *lnwire.ChannelType + // Updates is a channel which updates to the opening status of the channel // are sent on. Updates chan *lnrpc.OpenStatusUpdate diff --git a/lnrpc/lightning.pb.go b/lnrpc/lightning.pb.go index d4be95e5477..81beed880b6 100644 --- a/lnrpc/lightning.pb.go +++ b/lnrpc/lightning.pb.go @@ -80,39 +80,39 @@ func (AddressType) EnumDescriptor() ([]byte, []int) { type CommitmentType int32 const ( + // + //Returned when the commitment type isn't known or unavailable. + CommitmentType_UNKNOWN_COMMITMENT_TYPE CommitmentType = 0 // //A channel using the legacy commitment format having tweaked to_remote //keys. - CommitmentType_LEGACY CommitmentType = 0 + CommitmentType_LEGACY CommitmentType = 1 // //A channel that uses the modern commitment format where the key in the //output of the remote party does not change each state. This makes back //up and recovery easier as when the channel is closed, the funds go //directly to that key. - CommitmentType_STATIC_REMOTE_KEY CommitmentType = 1 + CommitmentType_STATIC_REMOTE_KEY CommitmentType = 2 // //A channel that uses a commitment format that has anchor outputs on the //commitments, allowing fee bumping after a force close transaction has //been broadcast. - CommitmentType_ANCHORS CommitmentType = 2 - // - //Returned when the commitment type isn't known or unavailable. - CommitmentType_UNKNOWN_COMMITMENT_TYPE CommitmentType = 999 + CommitmentType_ANCHORS CommitmentType = 3 ) // Enum value maps for CommitmentType. var ( CommitmentType_name = map[int32]string{ - 0: "LEGACY", - 1: "STATIC_REMOTE_KEY", - 2: "ANCHORS", - 999: "UNKNOWN_COMMITMENT_TYPE", + 0: "UNKNOWN_COMMITMENT_TYPE", + 1: "LEGACY", + 2: "STATIC_REMOTE_KEY", + 3: "ANCHORS", } CommitmentType_value = map[string]int32{ - "LEGACY": 0, - "STATIC_REMOTE_KEY": 1, - "ANCHORS": 2, - "UNKNOWN_COMMITMENT_TYPE": 999, + "UNKNOWN_COMMITMENT_TYPE": 0, + "LEGACY": 1, + "STATIC_REMOTE_KEY": 2, + "ANCHORS": 3, } ) @@ -4146,7 +4146,7 @@ func (x *Channel) GetCommitmentType() CommitmentType { if x != nil { return x.CommitmentType } - return CommitmentType_LEGACY + return CommitmentType_UNKNOWN_COMMITMENT_TYPE } func (x *Channel) GetLifetime() int64 { @@ -6092,6 +6092,10 @@ type OpenChannelRequest struct { //Max local csv is the maximum csv delay we will allow for our own commitment //transaction. MaxLocalCsv uint32 `protobuf:"varint,17,opt,name=max_local_csv,json=maxLocalCsv,proto3" json:"max_local_csv,omitempty"` + // + //The explicit commitment type to use. Note this field will only be used if + //the remote peer supports explicit channel negotiation. + CommitmentType CommitmentType `protobuf:"varint,18,opt,name=commitment_type,json=commitmentType,proto3,enum=lnrpc.CommitmentType" json:"commitment_type,omitempty"` } func (x *OpenChannelRequest) Reset() { @@ -6247,6 +6251,13 @@ func (x *OpenChannelRequest) GetMaxLocalCsv() uint32 { return 0 } +func (x *OpenChannelRequest) GetCommitmentType() CommitmentType { + if x != nil { + return x.CommitmentType + } + return CommitmentType_UNKNOWN_COMMITMENT_TYPE +} + type OpenStatusUpdate struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -14361,7 +14372,7 @@ func (x *PendingChannelsResponse_PendingChannel) GetCommitmentType() CommitmentT if x != nil { return x.CommitmentType } - return CommitmentType_LEGACY + return CommitmentType_UNKNOWN_COMMITMENT_TYPE } type PendingChannelsResponse_PendingOpenChannel struct { @@ -15495,7 +15506,7 @@ var file_lightning_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x73, 0x62, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x04, 0x70, 0x73, 0x62, 0x74, 0x22, 0xc0, 0x05, 0x0a, 0x12, 0x4f, 0x70, + 0x01, 0x28, 0x0c, 0x52, 0x04, 0x70, 0x73, 0x62, 0x74, 0x22, 0x80, 0x06, 0x0a, 0x12, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, @@ -15539,7 +15550,11 @@ var file_lightning_proto_rawDesc = []byte{ 0x63, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4d, 0x61, 0x78, 0x48, 0x74, 0x6c, 0x63, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x63, 0x73, 0x76, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0b, 0x6d, 0x61, 0x78, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x43, 0x73, 0x76, 0x22, 0xf3, 0x01, 0x0a, + 0x0b, 0x6d, 0x61, 0x78, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x43, 0x73, 0x76, 0x12, 0x3e, 0x0a, 0x0f, + 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x12, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0e, 0x63, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0xf3, 0x01, 0x0a, 0x10, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x39, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, @@ -16848,362 +16863,362 @@ var file_lightning_proto_rawDesc = []byte{ 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x02, 0x12, 0x1d, 0x0a, 0x19, 0x55, 0x4e, 0x55, 0x53, 0x45, 0x44, 0x5f, 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, - 0x03, 0x2a, 0x5e, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x45, 0x47, 0x41, 0x43, 0x59, 0x10, 0x00, 0x12, - 0x15, 0x0a, 0x11, 0x53, 0x54, 0x41, 0x54, 0x49, 0x43, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, - 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, - 0x53, 0x10, 0x02, 0x12, 0x1c, 0x0a, 0x17, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x43, - 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0xe7, - 0x07, 0x2a, 0x61, 0x0a, 0x09, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x15, - 0x0a, 0x11, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, - 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, - 0x4f, 0x52, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, - 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x10, 0x02, - 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x42, 0x4f, - 0x54, 0x48, 0x10, 0x03, 0x2a, 0x60, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, - 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, - 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4e, 0x43, 0x48, - 0x4f, 0x52, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x49, 0x4e, 0x47, - 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4f, 0x55, 0x54, 0x47, 0x4f, - 0x49, 0x4e, 0x47, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, - 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x04, 0x2a, 0x71, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, - 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x63, 0x6f, 0x6d, 0x65, 0x12, 0x13, 0x0a, 0x0f, 0x4f, - 0x55, 0x54, 0x43, 0x4f, 0x4d, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, - 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0d, 0x0a, - 0x09, 0x55, 0x4e, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, - 0x41, 0x42, 0x41, 0x4e, 0x44, 0x4f, 0x4e, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x46, - 0x49, 0x52, 0x53, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x10, 0x04, 0x12, 0x0b, 0x0a, 0x07, - 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x05, 0x2a, 0x39, 0x0a, 0x0e, 0x4e, 0x6f, 0x64, - 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, - 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x42, 0x45, 0x54, 0x57, - 0x45, 0x45, 0x4e, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x52, 0x41, 0x4c, 0x49, - 0x54, 0x59, 0x10, 0x01, 0x2a, 0x3b, 0x0a, 0x10, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x48, - 0x54, 0x4c, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x43, 0x43, 0x45, - 0x50, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, - 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, - 0x02, 0x2a, 0xd9, 0x01, 0x0a, 0x14, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x46, 0x61, 0x69, - 0x6c, 0x75, 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x13, 0x46, 0x41, - 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, - 0x45, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, - 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, - 0x1b, 0x0a, 0x17, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, - 0x4e, 0x5f, 0x4e, 0x4f, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, - 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x45, - 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x2c, 0x0a, 0x28, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, - 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, - 0x43, 0x54, 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, - 0x4c, 0x53, 0x10, 0x04, 0x12, 0x27, 0x0a, 0x23, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, - 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, - 0x45, 0x4e, 0x54, 0x5f, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x05, 0x2a, 0xcf, 0x04, - 0x0a, 0x0a, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x69, 0x74, 0x12, 0x18, 0x0a, 0x14, - 0x44, 0x41, 0x54, 0x41, 0x4c, 0x4f, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x45, 0x43, 0x54, - 0x5f, 0x52, 0x45, 0x51, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x44, 0x41, 0x54, 0x41, 0x4c, 0x4f, - 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x45, 0x43, 0x54, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x01, - 0x12, 0x17, 0x0a, 0x13, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x5f, 0x52, 0x4f, 0x55, 0x49, - 0x4e, 0x47, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x03, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x46, + 0x03, 0x2a, 0x5d, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x43, + 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, + 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x45, 0x47, 0x41, 0x43, 0x59, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, + 0x53, 0x54, 0x41, 0x54, 0x49, 0x43, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, + 0x59, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x10, 0x03, + 0x2a, 0x61, 0x0a, 0x09, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x15, 0x0a, + 0x11, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, + 0x57, 0x4e, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, + 0x52, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x49, + 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x10, 0x02, 0x12, + 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x42, 0x4f, 0x54, + 0x48, 0x10, 0x03, 0x2a, 0x60, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, + 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4e, 0x43, 0x48, 0x4f, + 0x52, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x49, 0x4e, 0x47, 0x5f, + 0x48, 0x54, 0x4c, 0x43, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4f, 0x55, 0x54, 0x47, 0x4f, 0x49, + 0x4e, 0x47, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4d, + 0x4d, 0x49, 0x54, 0x10, 0x04, 0x2a, 0x71, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x63, 0x6f, 0x6d, 0x65, 0x12, 0x13, 0x0a, 0x0f, 0x4f, 0x55, + 0x54, 0x43, 0x4f, 0x4d, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, + 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, + 0x55, 0x4e, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x41, + 0x42, 0x41, 0x4e, 0x44, 0x4f, 0x4e, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x46, 0x49, + 0x52, 0x53, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x10, 0x04, 0x12, 0x0b, 0x0a, 0x07, 0x54, + 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x05, 0x2a, 0x39, 0x0a, 0x0e, 0x4e, 0x6f, 0x64, 0x65, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, + 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x42, 0x45, 0x54, 0x57, 0x45, + 0x45, 0x4e, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x52, 0x41, 0x4c, 0x49, 0x54, + 0x59, 0x10, 0x01, 0x2a, 0x3b, 0x0a, 0x10, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x48, 0x54, + 0x4c, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x43, 0x43, 0x45, 0x50, + 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, 0x44, + 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x02, + 0x2a, 0xd9, 0x01, 0x0a, 0x14, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x46, 0x61, 0x69, 0x6c, + 0x75, 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x13, 0x46, 0x41, 0x49, + 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, + 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, + 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x1b, + 0x0a, 0x17, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, + 0x5f, 0x4e, 0x4f, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x46, + 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x45, 0x52, + 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x2c, 0x0a, 0x28, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, + 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, + 0x54, 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, + 0x53, 0x10, 0x04, 0x12, 0x27, 0x0a, 0x23, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, + 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, + 0x4e, 0x54, 0x5f, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x05, 0x2a, 0xcf, 0x04, 0x0a, + 0x0a, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x69, 0x74, 0x12, 0x18, 0x0a, 0x14, 0x44, + 0x41, 0x54, 0x41, 0x4c, 0x4f, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x45, 0x43, 0x54, 0x5f, + 0x52, 0x45, 0x51, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x44, 0x41, 0x54, 0x41, 0x4c, 0x4f, 0x53, + 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x45, 0x43, 0x54, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x01, 0x12, + 0x17, 0x0a, 0x13, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x5f, 0x52, 0x4f, 0x55, 0x49, 0x4e, + 0x47, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x03, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x46, 0x52, + 0x4f, 0x4e, 0x54, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x5f, 0x53, 0x43, 0x52, + 0x49, 0x50, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x04, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x46, 0x52, 0x4f, 0x4e, 0x54, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x5f, 0x53, 0x43, - 0x52, 0x49, 0x50, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x04, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, - 0x46, 0x52, 0x4f, 0x4e, 0x54, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x5f, 0x53, - 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x47, - 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x52, 0x45, - 0x51, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, - 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x07, 0x12, 0x11, 0x0a, 0x0d, 0x54, - 0x4c, 0x56, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x08, 0x12, 0x11, - 0x0a, 0x0d, 0x54, 0x4c, 0x56, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x4f, 0x50, 0x54, 0x10, - 0x09, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x54, 0x5f, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, - 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x0a, 0x12, 0x1a, 0x0a, - 0x16, 0x45, 0x58, 0x54, 0x5f, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, - 0x49, 0x45, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0b, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x54, 0x41, - 0x54, 0x49, 0x43, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x52, - 0x45, 0x51, 0x10, 0x0c, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x54, 0x41, 0x54, 0x49, 0x43, 0x5f, 0x52, - 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0d, 0x12, - 0x14, 0x0a, 0x10, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x5f, - 0x52, 0x45, 0x51, 0x10, 0x0e, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, - 0x5f, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0f, 0x12, 0x0b, 0x0a, 0x07, 0x4d, - 0x50, 0x50, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x10, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x50, 0x50, 0x5f, - 0x4f, 0x50, 0x54, 0x10, 0x11, 0x12, 0x16, 0x0a, 0x12, 0x57, 0x55, 0x4d, 0x42, 0x4f, 0x5f, 0x43, - 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x12, 0x12, 0x16, 0x0a, - 0x12, 0x57, 0x55, 0x4d, 0x42, 0x4f, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x53, 0x5f, - 0x4f, 0x50, 0x54, 0x10, 0x13, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, - 0x5f, 0x52, 0x45, 0x51, 0x10, 0x14, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, - 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x15, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4e, 0x43, 0x48, 0x4f, - 0x52, 0x53, 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43, - 0x5f, 0x52, 0x45, 0x51, 0x10, 0x16, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, + 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x47, 0x4f, + 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x52, 0x45, 0x51, + 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, + 0x52, 0x49, 0x45, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x07, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x4c, + 0x56, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x08, 0x12, 0x11, 0x0a, + 0x0d, 0x54, 0x4c, 0x56, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x09, + 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x54, 0x5f, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, + 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x0a, 0x12, 0x1a, 0x0a, 0x16, + 0x45, 0x58, 0x54, 0x5f, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, + 0x45, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0b, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x54, 0x41, 0x54, + 0x49, 0x43, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x52, 0x45, + 0x51, 0x10, 0x0c, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x54, 0x41, 0x54, 0x49, 0x43, 0x5f, 0x52, 0x45, + 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0d, 0x12, 0x14, + 0x0a, 0x10, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x52, + 0x45, 0x51, 0x10, 0x0e, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, + 0x41, 0x44, 0x44, 0x52, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0f, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x50, + 0x50, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x10, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x50, 0x50, 0x5f, 0x4f, + 0x50, 0x54, 0x10, 0x11, 0x12, 0x16, 0x0a, 0x12, 0x57, 0x55, 0x4d, 0x42, 0x4f, 0x5f, 0x43, 0x48, + 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x12, 0x12, 0x16, 0x0a, 0x12, + 0x57, 0x55, 0x4d, 0x42, 0x4f, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x53, 0x5f, 0x4f, + 0x50, 0x54, 0x10, 0x13, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, + 0x52, 0x45, 0x51, 0x10, 0x14, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, + 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x15, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, - 0x4f, 0x50, 0x54, 0x10, 0x17, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f, 0x52, 0x45, 0x51, - 0x10, 0x1e, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x1f, 0x32, - 0xc9, 0x21, 0x0a, 0x09, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x4a, 0x0a, - 0x0d, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1b, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, - 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0e, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, - 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, - 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x44, 0x0a, 0x0b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, - 0x65, 0x46, 0x65, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, - 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, - 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x53, - 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x6f, - 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x4c, - 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x4c, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x72, + 0x52, 0x45, 0x51, 0x10, 0x16, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, + 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4f, + 0x50, 0x54, 0x10, 0x17, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f, 0x52, 0x45, 0x51, 0x10, + 0x1e, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x1f, 0x32, 0xc9, + 0x21, 0x0a, 0x09, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x4a, 0x0a, 0x0d, + 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, + 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x01, 0x12, - 0x3b, 0x0a, 0x08, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x6e, 0x79, 0x12, 0x16, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, - 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0a, - 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x44, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, - 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, - 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, - 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0e, 0x44, 0x69, 0x73, 0x63, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, - 0x65, 0x72, 0x73, 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x13, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x62, 0x65, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1c, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x10, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, - 0x38, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x15, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x47, 0x65, 0x74, - 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, + 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x74, + 0x61, 0x69, 0x6c, 0x73, 0x12, 0x44, 0x0a, 0x0b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, + 0x46, 0x65, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, + 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, + 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x53, 0x65, + 0x6e, 0x64, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x69, + 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x4c, 0x69, + 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x4c, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x01, 0x12, 0x3b, + 0x0a, 0x08, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x6e, 0x79, 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, + 0x61, 0x6e, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0a, 0x4e, + 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, + 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, + 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x44, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x12, + 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, + 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, + 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, + 0x72, 0x73, 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, + 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x13, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x65, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1c, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x10, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x38, + 0x0a, 0x07, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, + 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x50, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1d, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x50, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, - 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1a, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x4d, - 0x0a, 0x0e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, - 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, - 0x0f, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x79, 0x6e, 0x63, - 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, - 0x12, 0x43, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, + 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0c, + 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1a, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, + 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, + 0x0e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, + 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0f, + 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x4c, 0x0a, 0x10, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x65, 0x70, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x67, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, - 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x65, 0x70, 0x52, - 0x65, 0x73, 0x70, 0x12, 0x50, 0x0a, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, - 0x63, 0x65, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x28, 0x01, 0x30, 0x01, 0x12, 0x46, 0x0a, 0x0c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, - 0x6f, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, - 0x0e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, - 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b, - 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x28, 0x01, 0x30, 0x01, 0x12, 0x3a, 0x0a, - 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x79, 0x6e, 0x63, - 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, - 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x53, 0x65, 0x6e, - 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, + 0x43, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x19, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x30, 0x01, 0x12, 0x4c, 0x0a, 0x10, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x65, 0x70, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x4d, 0x73, 0x67, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x65, 0x70, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x50, 0x0a, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, + 0x65, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x28, 0x01, 0x30, 0x01, 0x12, 0x46, 0x0a, 0x0c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, + 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x0e, + 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1c, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x53, + 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x28, 0x01, 0x30, 0x01, 0x12, 0x3a, 0x0a, 0x0f, + 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x12, + 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x28, 0x01, 0x30, - 0x01, 0x12, 0x41, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x53, 0x79, 0x6e, 0x63, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, - 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, - 0x63, 0x65, 0x12, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, - 0x63, 0x65, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, - 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, - 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x19, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x0d, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x49, 0x6e, - 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1a, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x30, 0x01, 0x12, 0x32, 0x0a, 0x0c, - 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x13, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x53, 0x74, 0x72, 0x69, 0x6e, - 0x67, 0x1a, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, - 0x12, 0x47, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, + 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x28, 0x01, 0x30, 0x01, + 0x12, 0x41, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x53, + 0x79, 0x6e, 0x63, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, + 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, + 0x65, 0x12, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, + 0x65, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, + 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0c, + 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x0d, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x76, + 0x6f, 0x69, 0x63, 0x65, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x62, 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x30, 0x01, 0x12, 0x32, 0x0a, 0x0c, 0x44, + 0x65, 0x63, 0x6f, 0x64, 0x65, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x13, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x1a, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, + 0x47, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, + 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, - 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, - 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x40, 0x0a, 0x0d, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x47, 0x72, 0x61, - 0x70, 0x68, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x47, 0x72, - 0x61, 0x70, 0x68, 0x12, 0x47, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, - 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0b, - 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x45, 0x64, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4e, 0x6f, - 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, - 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x44, 0x0a, 0x0b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x19, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x35, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x70, 0x44, 0x61, - 0x65, 0x6d, 0x6f, 0x6e, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, - 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, - 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, - 0x72, 0x61, 0x70, 0x68, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x53, 0x75, 0x62, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x41, 0x0a, 0x0a, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, - 0x65, 0x76, 0x65, 0x6c, 0x12, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x62, - 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, - 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x46, 0x65, 0x65, - 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, - 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x13, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x46, 0x6f, 0x72, - 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1f, + 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x40, 0x0a, 0x0d, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x47, 0x72, 0x61, 0x70, + 0x68, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, + 0x70, 0x68, 0x12, 0x47, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, + 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0b, 0x47, + 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x45, 0x64, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, + 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, + 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x44, + 0x0a, 0x0b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x19, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x35, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x70, 0x44, 0x61, 0x65, + 0x6d, 0x6f, 0x6e, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x15, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x72, + 0x61, 0x70, 0x68, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x47, 0x72, 0x61, 0x70, 0x68, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x41, 0x0a, 0x0a, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, + 0x76, 0x65, 0x6c, 0x12, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x62, 0x75, + 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x46, 0x65, 0x65, 0x52, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, + 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, + 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x46, 0x6f, 0x72, 0x77, + 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1f, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, + 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, - 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, - 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x4e, 0x0a, 0x13, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x21, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x12, 0x54, 0x0a, 0x17, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x6c, 0x6c, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x1e, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, - 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x4e, 0x0a, 0x10, 0x56, 0x65, 0x72, 0x69, 0x66, - 0x79, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x19, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, - 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, - 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x58, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6e, 0x72, + 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x4e, 0x0a, 0x13, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x21, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x19, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x30, 0x01, 0x12, 0x47, 0x0a, 0x0c, 0x42, 0x61, 0x6b, - 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x42, 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, - 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, - 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, - 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, - 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, - 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x4c, 0x69, 0x73, - 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, + 0x12, 0x54, 0x0a, 0x17, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x6c, 0x6c, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x1e, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, 0x78, + 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x4e, 0x0a, 0x10, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, 0x61, + 0x70, 0x73, 0x68, 0x6f, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, + 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, + 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x43, + 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, + 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x30, 0x01, 0x12, 0x47, 0x0a, 0x0c, 0x42, 0x61, 0x6b, 0x65, + 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x42, 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6b, + 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, + 0x6e, 0x49, 0x44, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, + 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, + 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, - 0x69, 0x6e, 0x67, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, + 0x6e, 0x67, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -17465,240 +17480,241 @@ var file_lightning_proto_depIdxs = []int32{ 74, // 35: lnrpc.CloseStatusUpdate.close_pending:type_name -> lnrpc.PendingUpdate 71, // 36: lnrpc.CloseStatusUpdate.chan_close:type_name -> lnrpc.ChannelCloseUpdate 82, // 37: lnrpc.OpenChannelRequest.funding_shim:type_name -> lnrpc.FundingShim - 74, // 38: lnrpc.OpenStatusUpdate.chan_pending:type_name -> lnrpc.PendingUpdate - 70, // 39: lnrpc.OpenStatusUpdate.chan_open:type_name -> lnrpc.ChannelOpenUpdate - 75, // 40: lnrpc.OpenStatusUpdate.psbt_fund:type_name -> lnrpc.ReadyForPsbtFunding - 78, // 41: lnrpc.KeyDescriptor.key_loc:type_name -> lnrpc.KeyLocator - 28, // 42: lnrpc.ChanPointShim.chan_point:type_name -> lnrpc.ChannelPoint - 79, // 43: lnrpc.ChanPointShim.local_key:type_name -> lnrpc.KeyDescriptor - 80, // 44: lnrpc.FundingShim.chan_point_shim:type_name -> lnrpc.ChanPointShim - 81, // 45: lnrpc.FundingShim.psbt_shim:type_name -> lnrpc.PsbtShim - 82, // 46: lnrpc.FundingTransitionMsg.shim_register:type_name -> lnrpc.FundingShim - 83, // 47: lnrpc.FundingTransitionMsg.shim_cancel:type_name -> lnrpc.FundingShimCancel - 84, // 48: lnrpc.FundingTransitionMsg.psbt_verify:type_name -> lnrpc.FundingPsbtVerify - 85, // 49: lnrpc.FundingTransitionMsg.psbt_finalize:type_name -> lnrpc.FundingPsbtFinalize - 189, // 50: lnrpc.PendingChannelsResponse.pending_open_channels:type_name -> lnrpc.PendingChannelsResponse.PendingOpenChannel - 192, // 51: lnrpc.PendingChannelsResponse.pending_closing_channels:type_name -> lnrpc.PendingChannelsResponse.ClosedChannel - 193, // 52: lnrpc.PendingChannelsResponse.pending_force_closing_channels:type_name -> lnrpc.PendingChannelsResponse.ForceClosedChannel - 190, // 53: lnrpc.PendingChannelsResponse.waiting_close_channels:type_name -> lnrpc.PendingChannelsResponse.WaitingCloseChannel - 51, // 54: lnrpc.ChannelEventUpdate.open_channel:type_name -> lnrpc.Channel - 54, // 55: lnrpc.ChannelEventUpdate.closed_channel:type_name -> lnrpc.ChannelCloseSummary - 28, // 56: lnrpc.ChannelEventUpdate.active_channel:type_name -> lnrpc.ChannelPoint - 28, // 57: lnrpc.ChannelEventUpdate.inactive_channel:type_name -> lnrpc.ChannelPoint - 74, // 58: lnrpc.ChannelEventUpdate.pending_open_channel:type_name -> lnrpc.PendingUpdate - 13, // 59: lnrpc.ChannelEventUpdate.type:type_name -> lnrpc.ChannelEventUpdate.UpdateType - 194, // 60: lnrpc.WalletBalanceResponse.account_balance:type_name -> lnrpc.WalletBalanceResponse.AccountBalanceEntry - 96, // 61: lnrpc.ChannelBalanceResponse.local_balance:type_name -> lnrpc.Amount - 96, // 62: lnrpc.ChannelBalanceResponse.remote_balance:type_name -> lnrpc.Amount - 96, // 63: lnrpc.ChannelBalanceResponse.unsettled_local_balance:type_name -> lnrpc.Amount - 96, // 64: lnrpc.ChannelBalanceResponse.unsettled_remote_balance:type_name -> lnrpc.Amount - 96, // 65: lnrpc.ChannelBalanceResponse.pending_open_local_balance:type_name -> lnrpc.Amount - 96, // 66: lnrpc.ChannelBalanceResponse.pending_open_remote_balance:type_name -> lnrpc.Amount - 22, // 67: lnrpc.QueryRoutesRequest.fee_limit:type_name -> lnrpc.FeeLimit - 101, // 68: lnrpc.QueryRoutesRequest.ignored_edges:type_name -> lnrpc.EdgeLocator - 100, // 69: lnrpc.QueryRoutesRequest.ignored_pairs:type_name -> lnrpc.NodePair - 195, // 70: lnrpc.QueryRoutesRequest.dest_custom_records:type_name -> lnrpc.QueryRoutesRequest.DestCustomRecordsEntry - 129, // 71: lnrpc.QueryRoutesRequest.route_hints:type_name -> lnrpc.RouteHint - 8, // 72: lnrpc.QueryRoutesRequest.dest_features:type_name -> lnrpc.FeatureBit - 106, // 73: lnrpc.QueryRoutesResponse.routes:type_name -> lnrpc.Route - 104, // 74: lnrpc.Hop.mpp_record:type_name -> lnrpc.MPPRecord - 105, // 75: lnrpc.Hop.amp_record:type_name -> lnrpc.AMPRecord - 196, // 76: lnrpc.Hop.custom_records:type_name -> lnrpc.Hop.CustomRecordsEntry - 103, // 77: lnrpc.Route.hops:type_name -> lnrpc.Hop - 109, // 78: lnrpc.NodeInfo.node:type_name -> lnrpc.LightningNode - 112, // 79: lnrpc.NodeInfo.channels:type_name -> lnrpc.ChannelEdge - 110, // 80: lnrpc.LightningNode.addresses:type_name -> lnrpc.NodeAddress - 197, // 81: lnrpc.LightningNode.features:type_name -> lnrpc.LightningNode.FeaturesEntry - 111, // 82: lnrpc.ChannelEdge.node1_policy:type_name -> lnrpc.RoutingPolicy - 111, // 83: lnrpc.ChannelEdge.node2_policy:type_name -> lnrpc.RoutingPolicy - 109, // 84: lnrpc.ChannelGraph.nodes:type_name -> lnrpc.LightningNode - 112, // 85: lnrpc.ChannelGraph.edges:type_name -> lnrpc.ChannelEdge - 5, // 86: lnrpc.NodeMetricsRequest.types:type_name -> lnrpc.NodeMetricType - 198, // 87: lnrpc.NodeMetricsResponse.betweenness_centrality:type_name -> lnrpc.NodeMetricsResponse.BetweennessCentralityEntry - 125, // 88: lnrpc.GraphTopologyUpdate.node_updates:type_name -> lnrpc.NodeUpdate - 126, // 89: lnrpc.GraphTopologyUpdate.channel_updates:type_name -> lnrpc.ChannelEdgeUpdate - 127, // 90: lnrpc.GraphTopologyUpdate.closed_chans:type_name -> lnrpc.ClosedChannelUpdate - 110, // 91: lnrpc.NodeUpdate.node_addresses:type_name -> lnrpc.NodeAddress - 199, // 92: lnrpc.NodeUpdate.features:type_name -> lnrpc.NodeUpdate.FeaturesEntry - 28, // 93: lnrpc.ChannelEdgeUpdate.chan_point:type_name -> lnrpc.ChannelPoint - 111, // 94: lnrpc.ChannelEdgeUpdate.routing_policy:type_name -> lnrpc.RoutingPolicy - 28, // 95: lnrpc.ClosedChannelUpdate.chan_point:type_name -> lnrpc.ChannelPoint - 128, // 96: lnrpc.RouteHint.hop_hints:type_name -> lnrpc.HopHint - 129, // 97: lnrpc.Invoice.route_hints:type_name -> lnrpc.RouteHint - 14, // 98: lnrpc.Invoice.state:type_name -> lnrpc.Invoice.InvoiceState - 131, // 99: lnrpc.Invoice.htlcs:type_name -> lnrpc.InvoiceHTLC - 200, // 100: lnrpc.Invoice.features:type_name -> lnrpc.Invoice.FeaturesEntry - 6, // 101: lnrpc.InvoiceHTLC.state:type_name -> lnrpc.InvoiceHTLCState - 201, // 102: lnrpc.InvoiceHTLC.custom_records:type_name -> lnrpc.InvoiceHTLC.CustomRecordsEntry - 132, // 103: lnrpc.InvoiceHTLC.amp:type_name -> lnrpc.AMP - 130, // 104: lnrpc.ListInvoiceResponse.invoices:type_name -> lnrpc.Invoice - 15, // 105: lnrpc.Payment.status:type_name -> lnrpc.Payment.PaymentStatus - 139, // 106: lnrpc.Payment.htlcs:type_name -> lnrpc.HTLCAttempt - 7, // 107: lnrpc.Payment.failure_reason:type_name -> lnrpc.PaymentFailureReason - 16, // 108: lnrpc.HTLCAttempt.status:type_name -> lnrpc.HTLCAttempt.HTLCStatus - 106, // 109: lnrpc.HTLCAttempt.route:type_name -> lnrpc.Route - 179, // 110: lnrpc.HTLCAttempt.failure:type_name -> lnrpc.Failure - 138, // 111: lnrpc.ListPaymentsResponse.payments:type_name -> lnrpc.Payment - 28, // 112: lnrpc.AbandonChannelRequest.channel_point:type_name -> lnrpc.ChannelPoint - 129, // 113: lnrpc.PayReq.route_hints:type_name -> lnrpc.RouteHint - 202, // 114: lnrpc.PayReq.features:type_name -> lnrpc.PayReq.FeaturesEntry - 152, // 115: lnrpc.FeeReportResponse.channel_fees:type_name -> lnrpc.ChannelFeeReport - 28, // 116: lnrpc.PolicyUpdateRequest.chan_point:type_name -> lnrpc.ChannelPoint - 157, // 117: lnrpc.ForwardingHistoryResponse.forwarding_events:type_name -> lnrpc.ForwardingEvent - 28, // 118: lnrpc.ExportChannelBackupRequest.chan_point:type_name -> lnrpc.ChannelPoint - 28, // 119: lnrpc.ChannelBackup.chan_point:type_name -> lnrpc.ChannelPoint - 28, // 120: lnrpc.MultiChanBackup.chan_points:type_name -> lnrpc.ChannelPoint - 164, // 121: lnrpc.ChanBackupSnapshot.single_chan_backups:type_name -> lnrpc.ChannelBackups - 161, // 122: lnrpc.ChanBackupSnapshot.multi_chan_backup:type_name -> lnrpc.MultiChanBackup - 160, // 123: lnrpc.ChannelBackups.chan_backups:type_name -> lnrpc.ChannelBackup - 164, // 124: lnrpc.RestoreChanBackupRequest.chan_backups:type_name -> lnrpc.ChannelBackups - 169, // 125: lnrpc.BakeMacaroonRequest.permissions:type_name -> lnrpc.MacaroonPermission - 169, // 126: lnrpc.MacaroonPermissionList.permissions:type_name -> lnrpc.MacaroonPermission - 203, // 127: lnrpc.ListPermissionsResponse.method_permissions:type_name -> lnrpc.ListPermissionsResponse.MethodPermissionsEntry - 17, // 128: lnrpc.Failure.code:type_name -> lnrpc.Failure.FailureCode - 180, // 129: lnrpc.Failure.channel_update:type_name -> lnrpc.ChannelUpdate - 182, // 130: lnrpc.MacaroonId.ops:type_name -> lnrpc.Op - 150, // 131: lnrpc.Peer.FeaturesEntry.value:type_name -> lnrpc.Feature - 150, // 132: lnrpc.GetInfoResponse.FeaturesEntry.value:type_name -> lnrpc.Feature - 2, // 133: lnrpc.PendingChannelsResponse.PendingChannel.initiator:type_name -> lnrpc.Initiator - 1, // 134: lnrpc.PendingChannelsResponse.PendingChannel.commitment_type:type_name -> lnrpc.CommitmentType - 188, // 135: lnrpc.PendingChannelsResponse.PendingOpenChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel - 188, // 136: lnrpc.PendingChannelsResponse.WaitingCloseChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel - 191, // 137: lnrpc.PendingChannelsResponse.WaitingCloseChannel.commitments:type_name -> lnrpc.PendingChannelsResponse.Commitments - 188, // 138: lnrpc.PendingChannelsResponse.ClosedChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel - 188, // 139: lnrpc.PendingChannelsResponse.ForceClosedChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel - 88, // 140: lnrpc.PendingChannelsResponse.ForceClosedChannel.pending_htlcs:type_name -> lnrpc.PendingHTLC - 12, // 141: lnrpc.PendingChannelsResponse.ForceClosedChannel.anchor:type_name -> lnrpc.PendingChannelsResponse.ForceClosedChannel.AnchorState - 93, // 142: lnrpc.WalletBalanceResponse.AccountBalanceEntry.value:type_name -> lnrpc.WalletAccountBalance - 150, // 143: lnrpc.LightningNode.FeaturesEntry.value:type_name -> lnrpc.Feature - 117, // 144: lnrpc.NodeMetricsResponse.BetweennessCentralityEntry.value:type_name -> lnrpc.FloatMetric - 150, // 145: lnrpc.NodeUpdate.FeaturesEntry.value:type_name -> lnrpc.Feature - 150, // 146: lnrpc.Invoice.FeaturesEntry.value:type_name -> lnrpc.Feature - 150, // 147: lnrpc.PayReq.FeaturesEntry.value:type_name -> lnrpc.Feature - 176, // 148: lnrpc.ListPermissionsResponse.MethodPermissionsEntry.value:type_name -> lnrpc.MacaroonPermissionList - 94, // 149: lnrpc.Lightning.WalletBalance:input_type -> lnrpc.WalletBalanceRequest - 97, // 150: lnrpc.Lightning.ChannelBalance:input_type -> lnrpc.ChannelBalanceRequest - 20, // 151: lnrpc.Lightning.GetTransactions:input_type -> lnrpc.GetTransactionsRequest - 31, // 152: lnrpc.Lightning.EstimateFee:input_type -> lnrpc.EstimateFeeRequest - 35, // 153: lnrpc.Lightning.SendCoins:input_type -> lnrpc.SendCoinsRequest - 37, // 154: lnrpc.Lightning.ListUnspent:input_type -> lnrpc.ListUnspentRequest - 20, // 155: lnrpc.Lightning.SubscribeTransactions:input_type -> lnrpc.GetTransactionsRequest - 33, // 156: lnrpc.Lightning.SendMany:input_type -> lnrpc.SendManyRequest - 39, // 157: lnrpc.Lightning.NewAddress:input_type -> lnrpc.NewAddressRequest - 41, // 158: lnrpc.Lightning.SignMessage:input_type -> lnrpc.SignMessageRequest - 43, // 159: lnrpc.Lightning.VerifyMessage:input_type -> lnrpc.VerifyMessageRequest - 45, // 160: lnrpc.Lightning.ConnectPeer:input_type -> lnrpc.ConnectPeerRequest - 47, // 161: lnrpc.Lightning.DisconnectPeer:input_type -> lnrpc.DisconnectPeerRequest - 60, // 162: lnrpc.Lightning.ListPeers:input_type -> lnrpc.ListPeersRequest - 62, // 163: lnrpc.Lightning.SubscribePeerEvents:input_type -> lnrpc.PeerEventSubscription - 64, // 164: lnrpc.Lightning.GetInfo:input_type -> lnrpc.GetInfoRequest - 66, // 165: lnrpc.Lightning.GetRecoveryInfo:input_type -> lnrpc.GetRecoveryInfoRequest - 89, // 166: lnrpc.Lightning.PendingChannels:input_type -> lnrpc.PendingChannelsRequest - 52, // 167: lnrpc.Lightning.ListChannels:input_type -> lnrpc.ListChannelsRequest - 91, // 168: lnrpc.Lightning.SubscribeChannelEvents:input_type -> lnrpc.ChannelEventSubscription - 56, // 169: lnrpc.Lightning.ClosedChannels:input_type -> lnrpc.ClosedChannelsRequest - 76, // 170: lnrpc.Lightning.OpenChannelSync:input_type -> lnrpc.OpenChannelRequest - 76, // 171: lnrpc.Lightning.OpenChannel:input_type -> lnrpc.OpenChannelRequest - 86, // 172: lnrpc.Lightning.FundingStateStep:input_type -> lnrpc.FundingTransitionMsg - 27, // 173: lnrpc.Lightning.ChannelAcceptor:input_type -> lnrpc.ChannelAcceptResponse - 72, // 174: lnrpc.Lightning.CloseChannel:input_type -> lnrpc.CloseChannelRequest - 144, // 175: lnrpc.Lightning.AbandonChannel:input_type -> lnrpc.AbandonChannelRequest - 23, // 176: lnrpc.Lightning.SendPayment:input_type -> lnrpc.SendRequest - 23, // 177: lnrpc.Lightning.SendPaymentSync:input_type -> lnrpc.SendRequest - 25, // 178: lnrpc.Lightning.SendToRoute:input_type -> lnrpc.SendToRouteRequest - 25, // 179: lnrpc.Lightning.SendToRouteSync:input_type -> lnrpc.SendToRouteRequest - 130, // 180: lnrpc.Lightning.AddInvoice:input_type -> lnrpc.Invoice - 135, // 181: lnrpc.Lightning.ListInvoices:input_type -> lnrpc.ListInvoiceRequest - 134, // 182: lnrpc.Lightning.LookupInvoice:input_type -> lnrpc.PaymentHash - 137, // 183: lnrpc.Lightning.SubscribeInvoices:input_type -> lnrpc.InvoiceSubscription - 148, // 184: lnrpc.Lightning.DecodePayReq:input_type -> lnrpc.PayReqString - 140, // 185: lnrpc.Lightning.ListPayments:input_type -> lnrpc.ListPaymentsRequest - 142, // 186: lnrpc.Lightning.DeleteAllPayments:input_type -> lnrpc.DeleteAllPaymentsRequest - 113, // 187: lnrpc.Lightning.DescribeGraph:input_type -> lnrpc.ChannelGraphRequest - 115, // 188: lnrpc.Lightning.GetNodeMetrics:input_type -> lnrpc.NodeMetricsRequest - 118, // 189: lnrpc.Lightning.GetChanInfo:input_type -> lnrpc.ChanInfoRequest - 107, // 190: lnrpc.Lightning.GetNodeInfo:input_type -> lnrpc.NodeInfoRequest - 99, // 191: lnrpc.Lightning.QueryRoutes:input_type -> lnrpc.QueryRoutesRequest - 119, // 192: lnrpc.Lightning.GetNetworkInfo:input_type -> lnrpc.NetworkInfoRequest - 121, // 193: lnrpc.Lightning.StopDaemon:input_type -> lnrpc.StopRequest - 123, // 194: lnrpc.Lightning.SubscribeChannelGraph:input_type -> lnrpc.GraphTopologySubscription - 146, // 195: lnrpc.Lightning.DebugLevel:input_type -> lnrpc.DebugLevelRequest - 151, // 196: lnrpc.Lightning.FeeReport:input_type -> lnrpc.FeeReportRequest - 154, // 197: lnrpc.Lightning.UpdateChannelPolicy:input_type -> lnrpc.PolicyUpdateRequest - 156, // 198: lnrpc.Lightning.ForwardingHistory:input_type -> lnrpc.ForwardingHistoryRequest - 159, // 199: lnrpc.Lightning.ExportChannelBackup:input_type -> lnrpc.ExportChannelBackupRequest - 162, // 200: lnrpc.Lightning.ExportAllChannelBackups:input_type -> lnrpc.ChanBackupExportRequest - 163, // 201: lnrpc.Lightning.VerifyChanBackup:input_type -> lnrpc.ChanBackupSnapshot - 165, // 202: lnrpc.Lightning.RestoreChannelBackups:input_type -> lnrpc.RestoreChanBackupRequest - 167, // 203: lnrpc.Lightning.SubscribeChannelBackups:input_type -> lnrpc.ChannelBackupSubscription - 170, // 204: lnrpc.Lightning.BakeMacaroon:input_type -> lnrpc.BakeMacaroonRequest - 172, // 205: lnrpc.Lightning.ListMacaroonIDs:input_type -> lnrpc.ListMacaroonIDsRequest - 174, // 206: lnrpc.Lightning.DeleteMacaroonID:input_type -> lnrpc.DeleteMacaroonIDRequest - 177, // 207: lnrpc.Lightning.ListPermissions:input_type -> lnrpc.ListPermissionsRequest - 95, // 208: lnrpc.Lightning.WalletBalance:output_type -> lnrpc.WalletBalanceResponse - 98, // 209: lnrpc.Lightning.ChannelBalance:output_type -> lnrpc.ChannelBalanceResponse - 21, // 210: lnrpc.Lightning.GetTransactions:output_type -> lnrpc.TransactionDetails - 32, // 211: lnrpc.Lightning.EstimateFee:output_type -> lnrpc.EstimateFeeResponse - 36, // 212: lnrpc.Lightning.SendCoins:output_type -> lnrpc.SendCoinsResponse - 38, // 213: lnrpc.Lightning.ListUnspent:output_type -> lnrpc.ListUnspentResponse - 19, // 214: lnrpc.Lightning.SubscribeTransactions:output_type -> lnrpc.Transaction - 34, // 215: lnrpc.Lightning.SendMany:output_type -> lnrpc.SendManyResponse - 40, // 216: lnrpc.Lightning.NewAddress:output_type -> lnrpc.NewAddressResponse - 42, // 217: lnrpc.Lightning.SignMessage:output_type -> lnrpc.SignMessageResponse - 44, // 218: lnrpc.Lightning.VerifyMessage:output_type -> lnrpc.VerifyMessageResponse - 46, // 219: lnrpc.Lightning.ConnectPeer:output_type -> lnrpc.ConnectPeerResponse - 48, // 220: lnrpc.Lightning.DisconnectPeer:output_type -> lnrpc.DisconnectPeerResponse - 61, // 221: lnrpc.Lightning.ListPeers:output_type -> lnrpc.ListPeersResponse - 63, // 222: lnrpc.Lightning.SubscribePeerEvents:output_type -> lnrpc.PeerEvent - 65, // 223: lnrpc.Lightning.GetInfo:output_type -> lnrpc.GetInfoResponse - 67, // 224: lnrpc.Lightning.GetRecoveryInfo:output_type -> lnrpc.GetRecoveryInfoResponse - 90, // 225: lnrpc.Lightning.PendingChannels:output_type -> lnrpc.PendingChannelsResponse - 53, // 226: lnrpc.Lightning.ListChannels:output_type -> lnrpc.ListChannelsResponse - 92, // 227: lnrpc.Lightning.SubscribeChannelEvents:output_type -> lnrpc.ChannelEventUpdate - 57, // 228: lnrpc.Lightning.ClosedChannels:output_type -> lnrpc.ClosedChannelsResponse - 28, // 229: lnrpc.Lightning.OpenChannelSync:output_type -> lnrpc.ChannelPoint - 77, // 230: lnrpc.Lightning.OpenChannel:output_type -> lnrpc.OpenStatusUpdate - 87, // 231: lnrpc.Lightning.FundingStateStep:output_type -> lnrpc.FundingStateStepResp - 26, // 232: lnrpc.Lightning.ChannelAcceptor:output_type -> lnrpc.ChannelAcceptRequest - 73, // 233: lnrpc.Lightning.CloseChannel:output_type -> lnrpc.CloseStatusUpdate - 145, // 234: lnrpc.Lightning.AbandonChannel:output_type -> lnrpc.AbandonChannelResponse - 24, // 235: lnrpc.Lightning.SendPayment:output_type -> lnrpc.SendResponse - 24, // 236: lnrpc.Lightning.SendPaymentSync:output_type -> lnrpc.SendResponse - 24, // 237: lnrpc.Lightning.SendToRoute:output_type -> lnrpc.SendResponse - 24, // 238: lnrpc.Lightning.SendToRouteSync:output_type -> lnrpc.SendResponse - 133, // 239: lnrpc.Lightning.AddInvoice:output_type -> lnrpc.AddInvoiceResponse - 136, // 240: lnrpc.Lightning.ListInvoices:output_type -> lnrpc.ListInvoiceResponse - 130, // 241: lnrpc.Lightning.LookupInvoice:output_type -> lnrpc.Invoice - 130, // 242: lnrpc.Lightning.SubscribeInvoices:output_type -> lnrpc.Invoice - 149, // 243: lnrpc.Lightning.DecodePayReq:output_type -> lnrpc.PayReq - 141, // 244: lnrpc.Lightning.ListPayments:output_type -> lnrpc.ListPaymentsResponse - 143, // 245: lnrpc.Lightning.DeleteAllPayments:output_type -> lnrpc.DeleteAllPaymentsResponse - 114, // 246: lnrpc.Lightning.DescribeGraph:output_type -> lnrpc.ChannelGraph - 116, // 247: lnrpc.Lightning.GetNodeMetrics:output_type -> lnrpc.NodeMetricsResponse - 112, // 248: lnrpc.Lightning.GetChanInfo:output_type -> lnrpc.ChannelEdge - 108, // 249: lnrpc.Lightning.GetNodeInfo:output_type -> lnrpc.NodeInfo - 102, // 250: lnrpc.Lightning.QueryRoutes:output_type -> lnrpc.QueryRoutesResponse - 120, // 251: lnrpc.Lightning.GetNetworkInfo:output_type -> lnrpc.NetworkInfo - 122, // 252: lnrpc.Lightning.StopDaemon:output_type -> lnrpc.StopResponse - 124, // 253: lnrpc.Lightning.SubscribeChannelGraph:output_type -> lnrpc.GraphTopologyUpdate - 147, // 254: lnrpc.Lightning.DebugLevel:output_type -> lnrpc.DebugLevelResponse - 153, // 255: lnrpc.Lightning.FeeReport:output_type -> lnrpc.FeeReportResponse - 155, // 256: lnrpc.Lightning.UpdateChannelPolicy:output_type -> lnrpc.PolicyUpdateResponse - 158, // 257: lnrpc.Lightning.ForwardingHistory:output_type -> lnrpc.ForwardingHistoryResponse - 160, // 258: lnrpc.Lightning.ExportChannelBackup:output_type -> lnrpc.ChannelBackup - 163, // 259: lnrpc.Lightning.ExportAllChannelBackups:output_type -> lnrpc.ChanBackupSnapshot - 168, // 260: lnrpc.Lightning.VerifyChanBackup:output_type -> lnrpc.VerifyChanBackupResponse - 166, // 261: lnrpc.Lightning.RestoreChannelBackups:output_type -> lnrpc.RestoreBackupResponse - 163, // 262: lnrpc.Lightning.SubscribeChannelBackups:output_type -> lnrpc.ChanBackupSnapshot - 171, // 263: lnrpc.Lightning.BakeMacaroon:output_type -> lnrpc.BakeMacaroonResponse - 173, // 264: lnrpc.Lightning.ListMacaroonIDs:output_type -> lnrpc.ListMacaroonIDsResponse - 175, // 265: lnrpc.Lightning.DeleteMacaroonID:output_type -> lnrpc.DeleteMacaroonIDResponse - 178, // 266: lnrpc.Lightning.ListPermissions:output_type -> lnrpc.ListPermissionsResponse - 208, // [208:267] is the sub-list for method output_type - 149, // [149:208] is the sub-list for method input_type - 149, // [149:149] is the sub-list for extension type_name - 149, // [149:149] is the sub-list for extension extendee - 0, // [0:149] is the sub-list for field type_name + 1, // 38: lnrpc.OpenChannelRequest.commitment_type:type_name -> lnrpc.CommitmentType + 74, // 39: lnrpc.OpenStatusUpdate.chan_pending:type_name -> lnrpc.PendingUpdate + 70, // 40: lnrpc.OpenStatusUpdate.chan_open:type_name -> lnrpc.ChannelOpenUpdate + 75, // 41: lnrpc.OpenStatusUpdate.psbt_fund:type_name -> lnrpc.ReadyForPsbtFunding + 78, // 42: lnrpc.KeyDescriptor.key_loc:type_name -> lnrpc.KeyLocator + 28, // 43: lnrpc.ChanPointShim.chan_point:type_name -> lnrpc.ChannelPoint + 79, // 44: lnrpc.ChanPointShim.local_key:type_name -> lnrpc.KeyDescriptor + 80, // 45: lnrpc.FundingShim.chan_point_shim:type_name -> lnrpc.ChanPointShim + 81, // 46: lnrpc.FundingShim.psbt_shim:type_name -> lnrpc.PsbtShim + 82, // 47: lnrpc.FundingTransitionMsg.shim_register:type_name -> lnrpc.FundingShim + 83, // 48: lnrpc.FundingTransitionMsg.shim_cancel:type_name -> lnrpc.FundingShimCancel + 84, // 49: lnrpc.FundingTransitionMsg.psbt_verify:type_name -> lnrpc.FundingPsbtVerify + 85, // 50: lnrpc.FundingTransitionMsg.psbt_finalize:type_name -> lnrpc.FundingPsbtFinalize + 189, // 51: lnrpc.PendingChannelsResponse.pending_open_channels:type_name -> lnrpc.PendingChannelsResponse.PendingOpenChannel + 192, // 52: lnrpc.PendingChannelsResponse.pending_closing_channels:type_name -> lnrpc.PendingChannelsResponse.ClosedChannel + 193, // 53: lnrpc.PendingChannelsResponse.pending_force_closing_channels:type_name -> lnrpc.PendingChannelsResponse.ForceClosedChannel + 190, // 54: lnrpc.PendingChannelsResponse.waiting_close_channels:type_name -> lnrpc.PendingChannelsResponse.WaitingCloseChannel + 51, // 55: lnrpc.ChannelEventUpdate.open_channel:type_name -> lnrpc.Channel + 54, // 56: lnrpc.ChannelEventUpdate.closed_channel:type_name -> lnrpc.ChannelCloseSummary + 28, // 57: lnrpc.ChannelEventUpdate.active_channel:type_name -> lnrpc.ChannelPoint + 28, // 58: lnrpc.ChannelEventUpdate.inactive_channel:type_name -> lnrpc.ChannelPoint + 74, // 59: lnrpc.ChannelEventUpdate.pending_open_channel:type_name -> lnrpc.PendingUpdate + 13, // 60: lnrpc.ChannelEventUpdate.type:type_name -> lnrpc.ChannelEventUpdate.UpdateType + 194, // 61: lnrpc.WalletBalanceResponse.account_balance:type_name -> lnrpc.WalletBalanceResponse.AccountBalanceEntry + 96, // 62: lnrpc.ChannelBalanceResponse.local_balance:type_name -> lnrpc.Amount + 96, // 63: lnrpc.ChannelBalanceResponse.remote_balance:type_name -> lnrpc.Amount + 96, // 64: lnrpc.ChannelBalanceResponse.unsettled_local_balance:type_name -> lnrpc.Amount + 96, // 65: lnrpc.ChannelBalanceResponse.unsettled_remote_balance:type_name -> lnrpc.Amount + 96, // 66: lnrpc.ChannelBalanceResponse.pending_open_local_balance:type_name -> lnrpc.Amount + 96, // 67: lnrpc.ChannelBalanceResponse.pending_open_remote_balance:type_name -> lnrpc.Amount + 22, // 68: lnrpc.QueryRoutesRequest.fee_limit:type_name -> lnrpc.FeeLimit + 101, // 69: lnrpc.QueryRoutesRequest.ignored_edges:type_name -> lnrpc.EdgeLocator + 100, // 70: lnrpc.QueryRoutesRequest.ignored_pairs:type_name -> lnrpc.NodePair + 195, // 71: lnrpc.QueryRoutesRequest.dest_custom_records:type_name -> lnrpc.QueryRoutesRequest.DestCustomRecordsEntry + 129, // 72: lnrpc.QueryRoutesRequest.route_hints:type_name -> lnrpc.RouteHint + 8, // 73: lnrpc.QueryRoutesRequest.dest_features:type_name -> lnrpc.FeatureBit + 106, // 74: lnrpc.QueryRoutesResponse.routes:type_name -> lnrpc.Route + 104, // 75: lnrpc.Hop.mpp_record:type_name -> lnrpc.MPPRecord + 105, // 76: lnrpc.Hop.amp_record:type_name -> lnrpc.AMPRecord + 196, // 77: lnrpc.Hop.custom_records:type_name -> lnrpc.Hop.CustomRecordsEntry + 103, // 78: lnrpc.Route.hops:type_name -> lnrpc.Hop + 109, // 79: lnrpc.NodeInfo.node:type_name -> lnrpc.LightningNode + 112, // 80: lnrpc.NodeInfo.channels:type_name -> lnrpc.ChannelEdge + 110, // 81: lnrpc.LightningNode.addresses:type_name -> lnrpc.NodeAddress + 197, // 82: lnrpc.LightningNode.features:type_name -> lnrpc.LightningNode.FeaturesEntry + 111, // 83: lnrpc.ChannelEdge.node1_policy:type_name -> lnrpc.RoutingPolicy + 111, // 84: lnrpc.ChannelEdge.node2_policy:type_name -> lnrpc.RoutingPolicy + 109, // 85: lnrpc.ChannelGraph.nodes:type_name -> lnrpc.LightningNode + 112, // 86: lnrpc.ChannelGraph.edges:type_name -> lnrpc.ChannelEdge + 5, // 87: lnrpc.NodeMetricsRequest.types:type_name -> lnrpc.NodeMetricType + 198, // 88: lnrpc.NodeMetricsResponse.betweenness_centrality:type_name -> lnrpc.NodeMetricsResponse.BetweennessCentralityEntry + 125, // 89: lnrpc.GraphTopologyUpdate.node_updates:type_name -> lnrpc.NodeUpdate + 126, // 90: lnrpc.GraphTopologyUpdate.channel_updates:type_name -> lnrpc.ChannelEdgeUpdate + 127, // 91: lnrpc.GraphTopologyUpdate.closed_chans:type_name -> lnrpc.ClosedChannelUpdate + 110, // 92: lnrpc.NodeUpdate.node_addresses:type_name -> lnrpc.NodeAddress + 199, // 93: lnrpc.NodeUpdate.features:type_name -> lnrpc.NodeUpdate.FeaturesEntry + 28, // 94: lnrpc.ChannelEdgeUpdate.chan_point:type_name -> lnrpc.ChannelPoint + 111, // 95: lnrpc.ChannelEdgeUpdate.routing_policy:type_name -> lnrpc.RoutingPolicy + 28, // 96: lnrpc.ClosedChannelUpdate.chan_point:type_name -> lnrpc.ChannelPoint + 128, // 97: lnrpc.RouteHint.hop_hints:type_name -> lnrpc.HopHint + 129, // 98: lnrpc.Invoice.route_hints:type_name -> lnrpc.RouteHint + 14, // 99: lnrpc.Invoice.state:type_name -> lnrpc.Invoice.InvoiceState + 131, // 100: lnrpc.Invoice.htlcs:type_name -> lnrpc.InvoiceHTLC + 200, // 101: lnrpc.Invoice.features:type_name -> lnrpc.Invoice.FeaturesEntry + 6, // 102: lnrpc.InvoiceHTLC.state:type_name -> lnrpc.InvoiceHTLCState + 201, // 103: lnrpc.InvoiceHTLC.custom_records:type_name -> lnrpc.InvoiceHTLC.CustomRecordsEntry + 132, // 104: lnrpc.InvoiceHTLC.amp:type_name -> lnrpc.AMP + 130, // 105: lnrpc.ListInvoiceResponse.invoices:type_name -> lnrpc.Invoice + 15, // 106: lnrpc.Payment.status:type_name -> lnrpc.Payment.PaymentStatus + 139, // 107: lnrpc.Payment.htlcs:type_name -> lnrpc.HTLCAttempt + 7, // 108: lnrpc.Payment.failure_reason:type_name -> lnrpc.PaymentFailureReason + 16, // 109: lnrpc.HTLCAttempt.status:type_name -> lnrpc.HTLCAttempt.HTLCStatus + 106, // 110: lnrpc.HTLCAttempt.route:type_name -> lnrpc.Route + 179, // 111: lnrpc.HTLCAttempt.failure:type_name -> lnrpc.Failure + 138, // 112: lnrpc.ListPaymentsResponse.payments:type_name -> lnrpc.Payment + 28, // 113: lnrpc.AbandonChannelRequest.channel_point:type_name -> lnrpc.ChannelPoint + 129, // 114: lnrpc.PayReq.route_hints:type_name -> lnrpc.RouteHint + 202, // 115: lnrpc.PayReq.features:type_name -> lnrpc.PayReq.FeaturesEntry + 152, // 116: lnrpc.FeeReportResponse.channel_fees:type_name -> lnrpc.ChannelFeeReport + 28, // 117: lnrpc.PolicyUpdateRequest.chan_point:type_name -> lnrpc.ChannelPoint + 157, // 118: lnrpc.ForwardingHistoryResponse.forwarding_events:type_name -> lnrpc.ForwardingEvent + 28, // 119: lnrpc.ExportChannelBackupRequest.chan_point:type_name -> lnrpc.ChannelPoint + 28, // 120: lnrpc.ChannelBackup.chan_point:type_name -> lnrpc.ChannelPoint + 28, // 121: lnrpc.MultiChanBackup.chan_points:type_name -> lnrpc.ChannelPoint + 164, // 122: lnrpc.ChanBackupSnapshot.single_chan_backups:type_name -> lnrpc.ChannelBackups + 161, // 123: lnrpc.ChanBackupSnapshot.multi_chan_backup:type_name -> lnrpc.MultiChanBackup + 160, // 124: lnrpc.ChannelBackups.chan_backups:type_name -> lnrpc.ChannelBackup + 164, // 125: lnrpc.RestoreChanBackupRequest.chan_backups:type_name -> lnrpc.ChannelBackups + 169, // 126: lnrpc.BakeMacaroonRequest.permissions:type_name -> lnrpc.MacaroonPermission + 169, // 127: lnrpc.MacaroonPermissionList.permissions:type_name -> lnrpc.MacaroonPermission + 203, // 128: lnrpc.ListPermissionsResponse.method_permissions:type_name -> lnrpc.ListPermissionsResponse.MethodPermissionsEntry + 17, // 129: lnrpc.Failure.code:type_name -> lnrpc.Failure.FailureCode + 180, // 130: lnrpc.Failure.channel_update:type_name -> lnrpc.ChannelUpdate + 182, // 131: lnrpc.MacaroonId.ops:type_name -> lnrpc.Op + 150, // 132: lnrpc.Peer.FeaturesEntry.value:type_name -> lnrpc.Feature + 150, // 133: lnrpc.GetInfoResponse.FeaturesEntry.value:type_name -> lnrpc.Feature + 2, // 134: lnrpc.PendingChannelsResponse.PendingChannel.initiator:type_name -> lnrpc.Initiator + 1, // 135: lnrpc.PendingChannelsResponse.PendingChannel.commitment_type:type_name -> lnrpc.CommitmentType + 188, // 136: lnrpc.PendingChannelsResponse.PendingOpenChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel + 188, // 137: lnrpc.PendingChannelsResponse.WaitingCloseChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel + 191, // 138: lnrpc.PendingChannelsResponse.WaitingCloseChannel.commitments:type_name -> lnrpc.PendingChannelsResponse.Commitments + 188, // 139: lnrpc.PendingChannelsResponse.ClosedChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel + 188, // 140: lnrpc.PendingChannelsResponse.ForceClosedChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel + 88, // 141: lnrpc.PendingChannelsResponse.ForceClosedChannel.pending_htlcs:type_name -> lnrpc.PendingHTLC + 12, // 142: lnrpc.PendingChannelsResponse.ForceClosedChannel.anchor:type_name -> lnrpc.PendingChannelsResponse.ForceClosedChannel.AnchorState + 93, // 143: lnrpc.WalletBalanceResponse.AccountBalanceEntry.value:type_name -> lnrpc.WalletAccountBalance + 150, // 144: lnrpc.LightningNode.FeaturesEntry.value:type_name -> lnrpc.Feature + 117, // 145: lnrpc.NodeMetricsResponse.BetweennessCentralityEntry.value:type_name -> lnrpc.FloatMetric + 150, // 146: lnrpc.NodeUpdate.FeaturesEntry.value:type_name -> lnrpc.Feature + 150, // 147: lnrpc.Invoice.FeaturesEntry.value:type_name -> lnrpc.Feature + 150, // 148: lnrpc.PayReq.FeaturesEntry.value:type_name -> lnrpc.Feature + 176, // 149: lnrpc.ListPermissionsResponse.MethodPermissionsEntry.value:type_name -> lnrpc.MacaroonPermissionList + 94, // 150: lnrpc.Lightning.WalletBalance:input_type -> lnrpc.WalletBalanceRequest + 97, // 151: lnrpc.Lightning.ChannelBalance:input_type -> lnrpc.ChannelBalanceRequest + 20, // 152: lnrpc.Lightning.GetTransactions:input_type -> lnrpc.GetTransactionsRequest + 31, // 153: lnrpc.Lightning.EstimateFee:input_type -> lnrpc.EstimateFeeRequest + 35, // 154: lnrpc.Lightning.SendCoins:input_type -> lnrpc.SendCoinsRequest + 37, // 155: lnrpc.Lightning.ListUnspent:input_type -> lnrpc.ListUnspentRequest + 20, // 156: lnrpc.Lightning.SubscribeTransactions:input_type -> lnrpc.GetTransactionsRequest + 33, // 157: lnrpc.Lightning.SendMany:input_type -> lnrpc.SendManyRequest + 39, // 158: lnrpc.Lightning.NewAddress:input_type -> lnrpc.NewAddressRequest + 41, // 159: lnrpc.Lightning.SignMessage:input_type -> lnrpc.SignMessageRequest + 43, // 160: lnrpc.Lightning.VerifyMessage:input_type -> lnrpc.VerifyMessageRequest + 45, // 161: lnrpc.Lightning.ConnectPeer:input_type -> lnrpc.ConnectPeerRequest + 47, // 162: lnrpc.Lightning.DisconnectPeer:input_type -> lnrpc.DisconnectPeerRequest + 60, // 163: lnrpc.Lightning.ListPeers:input_type -> lnrpc.ListPeersRequest + 62, // 164: lnrpc.Lightning.SubscribePeerEvents:input_type -> lnrpc.PeerEventSubscription + 64, // 165: lnrpc.Lightning.GetInfo:input_type -> lnrpc.GetInfoRequest + 66, // 166: lnrpc.Lightning.GetRecoveryInfo:input_type -> lnrpc.GetRecoveryInfoRequest + 89, // 167: lnrpc.Lightning.PendingChannels:input_type -> lnrpc.PendingChannelsRequest + 52, // 168: lnrpc.Lightning.ListChannels:input_type -> lnrpc.ListChannelsRequest + 91, // 169: lnrpc.Lightning.SubscribeChannelEvents:input_type -> lnrpc.ChannelEventSubscription + 56, // 170: lnrpc.Lightning.ClosedChannels:input_type -> lnrpc.ClosedChannelsRequest + 76, // 171: lnrpc.Lightning.OpenChannelSync:input_type -> lnrpc.OpenChannelRequest + 76, // 172: lnrpc.Lightning.OpenChannel:input_type -> lnrpc.OpenChannelRequest + 86, // 173: lnrpc.Lightning.FundingStateStep:input_type -> lnrpc.FundingTransitionMsg + 27, // 174: lnrpc.Lightning.ChannelAcceptor:input_type -> lnrpc.ChannelAcceptResponse + 72, // 175: lnrpc.Lightning.CloseChannel:input_type -> lnrpc.CloseChannelRequest + 144, // 176: lnrpc.Lightning.AbandonChannel:input_type -> lnrpc.AbandonChannelRequest + 23, // 177: lnrpc.Lightning.SendPayment:input_type -> lnrpc.SendRequest + 23, // 178: lnrpc.Lightning.SendPaymentSync:input_type -> lnrpc.SendRequest + 25, // 179: lnrpc.Lightning.SendToRoute:input_type -> lnrpc.SendToRouteRequest + 25, // 180: lnrpc.Lightning.SendToRouteSync:input_type -> lnrpc.SendToRouteRequest + 130, // 181: lnrpc.Lightning.AddInvoice:input_type -> lnrpc.Invoice + 135, // 182: lnrpc.Lightning.ListInvoices:input_type -> lnrpc.ListInvoiceRequest + 134, // 183: lnrpc.Lightning.LookupInvoice:input_type -> lnrpc.PaymentHash + 137, // 184: lnrpc.Lightning.SubscribeInvoices:input_type -> lnrpc.InvoiceSubscription + 148, // 185: lnrpc.Lightning.DecodePayReq:input_type -> lnrpc.PayReqString + 140, // 186: lnrpc.Lightning.ListPayments:input_type -> lnrpc.ListPaymentsRequest + 142, // 187: lnrpc.Lightning.DeleteAllPayments:input_type -> lnrpc.DeleteAllPaymentsRequest + 113, // 188: lnrpc.Lightning.DescribeGraph:input_type -> lnrpc.ChannelGraphRequest + 115, // 189: lnrpc.Lightning.GetNodeMetrics:input_type -> lnrpc.NodeMetricsRequest + 118, // 190: lnrpc.Lightning.GetChanInfo:input_type -> lnrpc.ChanInfoRequest + 107, // 191: lnrpc.Lightning.GetNodeInfo:input_type -> lnrpc.NodeInfoRequest + 99, // 192: lnrpc.Lightning.QueryRoutes:input_type -> lnrpc.QueryRoutesRequest + 119, // 193: lnrpc.Lightning.GetNetworkInfo:input_type -> lnrpc.NetworkInfoRequest + 121, // 194: lnrpc.Lightning.StopDaemon:input_type -> lnrpc.StopRequest + 123, // 195: lnrpc.Lightning.SubscribeChannelGraph:input_type -> lnrpc.GraphTopologySubscription + 146, // 196: lnrpc.Lightning.DebugLevel:input_type -> lnrpc.DebugLevelRequest + 151, // 197: lnrpc.Lightning.FeeReport:input_type -> lnrpc.FeeReportRequest + 154, // 198: lnrpc.Lightning.UpdateChannelPolicy:input_type -> lnrpc.PolicyUpdateRequest + 156, // 199: lnrpc.Lightning.ForwardingHistory:input_type -> lnrpc.ForwardingHistoryRequest + 159, // 200: lnrpc.Lightning.ExportChannelBackup:input_type -> lnrpc.ExportChannelBackupRequest + 162, // 201: lnrpc.Lightning.ExportAllChannelBackups:input_type -> lnrpc.ChanBackupExportRequest + 163, // 202: lnrpc.Lightning.VerifyChanBackup:input_type -> lnrpc.ChanBackupSnapshot + 165, // 203: lnrpc.Lightning.RestoreChannelBackups:input_type -> lnrpc.RestoreChanBackupRequest + 167, // 204: lnrpc.Lightning.SubscribeChannelBackups:input_type -> lnrpc.ChannelBackupSubscription + 170, // 205: lnrpc.Lightning.BakeMacaroon:input_type -> lnrpc.BakeMacaroonRequest + 172, // 206: lnrpc.Lightning.ListMacaroonIDs:input_type -> lnrpc.ListMacaroonIDsRequest + 174, // 207: lnrpc.Lightning.DeleteMacaroonID:input_type -> lnrpc.DeleteMacaroonIDRequest + 177, // 208: lnrpc.Lightning.ListPermissions:input_type -> lnrpc.ListPermissionsRequest + 95, // 209: lnrpc.Lightning.WalletBalance:output_type -> lnrpc.WalletBalanceResponse + 98, // 210: lnrpc.Lightning.ChannelBalance:output_type -> lnrpc.ChannelBalanceResponse + 21, // 211: lnrpc.Lightning.GetTransactions:output_type -> lnrpc.TransactionDetails + 32, // 212: lnrpc.Lightning.EstimateFee:output_type -> lnrpc.EstimateFeeResponse + 36, // 213: lnrpc.Lightning.SendCoins:output_type -> lnrpc.SendCoinsResponse + 38, // 214: lnrpc.Lightning.ListUnspent:output_type -> lnrpc.ListUnspentResponse + 19, // 215: lnrpc.Lightning.SubscribeTransactions:output_type -> lnrpc.Transaction + 34, // 216: lnrpc.Lightning.SendMany:output_type -> lnrpc.SendManyResponse + 40, // 217: lnrpc.Lightning.NewAddress:output_type -> lnrpc.NewAddressResponse + 42, // 218: lnrpc.Lightning.SignMessage:output_type -> lnrpc.SignMessageResponse + 44, // 219: lnrpc.Lightning.VerifyMessage:output_type -> lnrpc.VerifyMessageResponse + 46, // 220: lnrpc.Lightning.ConnectPeer:output_type -> lnrpc.ConnectPeerResponse + 48, // 221: lnrpc.Lightning.DisconnectPeer:output_type -> lnrpc.DisconnectPeerResponse + 61, // 222: lnrpc.Lightning.ListPeers:output_type -> lnrpc.ListPeersResponse + 63, // 223: lnrpc.Lightning.SubscribePeerEvents:output_type -> lnrpc.PeerEvent + 65, // 224: lnrpc.Lightning.GetInfo:output_type -> lnrpc.GetInfoResponse + 67, // 225: lnrpc.Lightning.GetRecoveryInfo:output_type -> lnrpc.GetRecoveryInfoResponse + 90, // 226: lnrpc.Lightning.PendingChannels:output_type -> lnrpc.PendingChannelsResponse + 53, // 227: lnrpc.Lightning.ListChannels:output_type -> lnrpc.ListChannelsResponse + 92, // 228: lnrpc.Lightning.SubscribeChannelEvents:output_type -> lnrpc.ChannelEventUpdate + 57, // 229: lnrpc.Lightning.ClosedChannels:output_type -> lnrpc.ClosedChannelsResponse + 28, // 230: lnrpc.Lightning.OpenChannelSync:output_type -> lnrpc.ChannelPoint + 77, // 231: lnrpc.Lightning.OpenChannel:output_type -> lnrpc.OpenStatusUpdate + 87, // 232: lnrpc.Lightning.FundingStateStep:output_type -> lnrpc.FundingStateStepResp + 26, // 233: lnrpc.Lightning.ChannelAcceptor:output_type -> lnrpc.ChannelAcceptRequest + 73, // 234: lnrpc.Lightning.CloseChannel:output_type -> lnrpc.CloseStatusUpdate + 145, // 235: lnrpc.Lightning.AbandonChannel:output_type -> lnrpc.AbandonChannelResponse + 24, // 236: lnrpc.Lightning.SendPayment:output_type -> lnrpc.SendResponse + 24, // 237: lnrpc.Lightning.SendPaymentSync:output_type -> lnrpc.SendResponse + 24, // 238: lnrpc.Lightning.SendToRoute:output_type -> lnrpc.SendResponse + 24, // 239: lnrpc.Lightning.SendToRouteSync:output_type -> lnrpc.SendResponse + 133, // 240: lnrpc.Lightning.AddInvoice:output_type -> lnrpc.AddInvoiceResponse + 136, // 241: lnrpc.Lightning.ListInvoices:output_type -> lnrpc.ListInvoiceResponse + 130, // 242: lnrpc.Lightning.LookupInvoice:output_type -> lnrpc.Invoice + 130, // 243: lnrpc.Lightning.SubscribeInvoices:output_type -> lnrpc.Invoice + 149, // 244: lnrpc.Lightning.DecodePayReq:output_type -> lnrpc.PayReq + 141, // 245: lnrpc.Lightning.ListPayments:output_type -> lnrpc.ListPaymentsResponse + 143, // 246: lnrpc.Lightning.DeleteAllPayments:output_type -> lnrpc.DeleteAllPaymentsResponse + 114, // 247: lnrpc.Lightning.DescribeGraph:output_type -> lnrpc.ChannelGraph + 116, // 248: lnrpc.Lightning.GetNodeMetrics:output_type -> lnrpc.NodeMetricsResponse + 112, // 249: lnrpc.Lightning.GetChanInfo:output_type -> lnrpc.ChannelEdge + 108, // 250: lnrpc.Lightning.GetNodeInfo:output_type -> lnrpc.NodeInfo + 102, // 251: lnrpc.Lightning.QueryRoutes:output_type -> lnrpc.QueryRoutesResponse + 120, // 252: lnrpc.Lightning.GetNetworkInfo:output_type -> lnrpc.NetworkInfo + 122, // 253: lnrpc.Lightning.StopDaemon:output_type -> lnrpc.StopResponse + 124, // 254: lnrpc.Lightning.SubscribeChannelGraph:output_type -> lnrpc.GraphTopologyUpdate + 147, // 255: lnrpc.Lightning.DebugLevel:output_type -> lnrpc.DebugLevelResponse + 153, // 256: lnrpc.Lightning.FeeReport:output_type -> lnrpc.FeeReportResponse + 155, // 257: lnrpc.Lightning.UpdateChannelPolicy:output_type -> lnrpc.PolicyUpdateResponse + 158, // 258: lnrpc.Lightning.ForwardingHistory:output_type -> lnrpc.ForwardingHistoryResponse + 160, // 259: lnrpc.Lightning.ExportChannelBackup:output_type -> lnrpc.ChannelBackup + 163, // 260: lnrpc.Lightning.ExportAllChannelBackups:output_type -> lnrpc.ChanBackupSnapshot + 168, // 261: lnrpc.Lightning.VerifyChanBackup:output_type -> lnrpc.VerifyChanBackupResponse + 166, // 262: lnrpc.Lightning.RestoreChannelBackups:output_type -> lnrpc.RestoreBackupResponse + 163, // 263: lnrpc.Lightning.SubscribeChannelBackups:output_type -> lnrpc.ChanBackupSnapshot + 171, // 264: lnrpc.Lightning.BakeMacaroon:output_type -> lnrpc.BakeMacaroonResponse + 173, // 265: lnrpc.Lightning.ListMacaroonIDs:output_type -> lnrpc.ListMacaroonIDsResponse + 175, // 266: lnrpc.Lightning.DeleteMacaroonID:output_type -> lnrpc.DeleteMacaroonIDResponse + 178, // 267: lnrpc.Lightning.ListPermissions:output_type -> lnrpc.ListPermissionsResponse + 209, // [209:268] is the sub-list for method output_type + 150, // [150:209] is the sub-list for method input_type + 150, // [150:150] is the sub-list for extension type_name + 150, // [150:150] is the sub-list for extension extendee + 0, // [0:150] is the sub-list for field type_name } func init() { file_lightning_proto_init() } diff --git a/lnrpc/lightning.proto b/lnrpc/lightning.proto index 0a59c6c13e5..93923c9148d 100644 --- a/lnrpc/lightning.proto +++ b/lnrpc/lightning.proto @@ -1115,11 +1115,16 @@ message HTLC { } enum CommitmentType { + /* + Returned when the commitment type isn't known or unavailable. + */ + UNKNOWN_COMMITMENT_TYPE = 0; + /* A channel using the legacy commitment format having tweaked to_remote keys. */ - LEGACY = 0; + LEGACY = 1; /* A channel that uses the modern commitment format where the key in the @@ -1127,19 +1132,14 @@ enum CommitmentType { up and recovery easier as when the channel is closed, the funds go directly to that key. */ - STATIC_REMOTE_KEY = 1; + STATIC_REMOTE_KEY = 2; /* A channel that uses a commitment format that has anchor outputs on the commitments, allowing fee bumping after a force close transaction has been broadcast. */ - ANCHORS = 2; - - /* - Returned when the commitment type isn't known or unavailable. - */ - UNKNOWN_COMMITMENT_TYPE = 999; + ANCHORS = 3; } message ChannelConstraints { @@ -1862,6 +1862,12 @@ message OpenChannelRequest { transaction. */ uint32 max_local_csv = 17; + + /* + The explicit commitment type to use. Note this field will only be used if + the remote peer supports explicit channel negotiation. + */ + CommitmentType commitment_type = 18; } message OpenStatusUpdate { oneof update { diff --git a/lnrpc/lightning.swagger.json b/lnrpc/lightning.swagger.json index 5dcb04bd72b..8be7b600ad4 100644 --- a/lnrpc/lightning.swagger.json +++ b/lnrpc/lightning.swagger.json @@ -3498,13 +3498,13 @@ "lnrpcCommitmentType": { "type": "string", "enum": [ + "UNKNOWN_COMMITMENT_TYPE", "LEGACY", "STATIC_REMOTE_KEY", - "ANCHORS", - "UNKNOWN_COMMITMENT_TYPE" + "ANCHORS" ], - "default": "LEGACY", - "description": " - LEGACY: A channel using the legacy commitment format having tweaked to_remote\nkeys.\n - STATIC_REMOTE_KEY: A channel that uses the modern commitment format where the key in the\noutput of the remote party does not change each state. This makes back\nup and recovery easier as when the channel is closed, the funds go\ndirectly to that key.\n - ANCHORS: A channel that uses a commitment format that has anchor outputs on the\ncommitments, allowing fee bumping after a force close transaction has\nbeen broadcast.\n - UNKNOWN_COMMITMENT_TYPE: Returned when the commitment type isn't known or unavailable." + "default": "UNKNOWN_COMMITMENT_TYPE", + "description": " - UNKNOWN_COMMITMENT_TYPE: Returned when the commitment type isn't known or unavailable.\n - LEGACY: A channel using the legacy commitment format having tweaked to_remote\nkeys.\n - STATIC_REMOTE_KEY: A channel that uses the modern commitment format where the key in the\noutput of the remote party does not change each state. This makes back\nup and recovery easier as when the channel is closed, the funds go\ndirectly to that key.\n - ANCHORS: A channel that uses a commitment format that has anchor outputs on the\ncommitments, allowing fee bumping after a force close transaction has\nbeen broadcast." }, "lnrpcConnectPeerRequest": { "type": "object", @@ -4919,6 +4919,10 @@ "type": "integer", "format": "int64", "description": "Max local csv is the maximum csv delay we will allow for our own commitment\ntransaction." + }, + "commitment_type": { + "$ref": "#/definitions/lnrpcCommitmentType", + "description": "The explicit commitment type to use. Note this field will only be used if\nthe remote peer supports explicit channel negotiation." } } }, diff --git a/rpcserver.go b/rpcserver.go index 8ff36d964b4..fa25bf2b703 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -1913,6 +1913,33 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest, err) } + var channelType *lnwire.ChannelType + switch in.CommitmentType { + case lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE: + break + + case lnrpc.CommitmentType_LEGACY: + channelType = new(lnwire.ChannelType) + *channelType = lnwire.ChannelType(*lnwire.NewRawFeatureVector()) + + case lnrpc.CommitmentType_STATIC_REMOTE_KEY: + channelType = new(lnwire.ChannelType) + *channelType = lnwire.ChannelType(*lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyRequired, + )) + + case lnrpc.CommitmentType_ANCHORS: + channelType = new(lnwire.ChannelType) + *channelType = lnwire.ChannelType(*lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyRequired, + lnwire.AnchorsZeroFeeHtlcTxRequired, + )) + + default: + return nil, fmt.Errorf("unhandled request channel type %v", + in.CommitmentType) + } + // Instruct the server to trigger the necessary events to attempt to // open a new channel. A stream is returned in place, this stream will // be used to consume updates of the state of the pending channel. @@ -1930,6 +1957,7 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest, MaxValueInFlight: maxValue, MaxHtlcs: maxHtlcs, MaxLocalCsv: uint16(in.MaxLocalCsv), + ChannelType: channelType, }, nil } From 459d7dc9d2671ceccd7ff9341633124531eef152 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Mon, 12 Jul 2021 17:41:50 -0700 Subject: [PATCH 05/29] lnwire: extend RawFeatureVector with helper methods --- lnwire/features.go | 41 ++++++++++++++++++++++++++++++++++---- lnwire/features_test.go | 44 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/lnwire/features.go b/lnwire/features.go index 575413468a2..d2ef0a6237a 100644 --- a/lnwire/features.go +++ b/lnwire/features.go @@ -214,19 +214,51 @@ var Features = map[FeatureBit]string{ // can be serialized and deserialized to/from a byte representation that is // transmitted in Lightning network messages. type RawFeatureVector struct { - features map[FeatureBit]bool + features map[FeatureBit]struct{} } // NewRawFeatureVector creates a feature vector with all of the feature bits // given as arguments enabled. func NewRawFeatureVector(bits ...FeatureBit) *RawFeatureVector { - fv := &RawFeatureVector{features: make(map[FeatureBit]bool)} + fv := &RawFeatureVector{features: make(map[FeatureBit]struct{})} for _, bit := range bits { fv.Set(bit) } return fv } +// IsEmpty returns whether the feature vector contains any feature bits. +func (fv RawFeatureVector) IsEmpty() bool { + return len(fv.features) == 0 +} + +// OnlyContains determines whether only the specified feature bits are found. +func (fv RawFeatureVector) OnlyContains(bits ...FeatureBit) bool { + if len(bits) != len(fv.features) { + return false + } + for _, bit := range bits { + if !fv.IsSet(bit) { + return false + } + } + return true +} + +// Equals determines whether two features vectors contain exactly the same +// features. +func (fv RawFeatureVector) Equals(other *RawFeatureVector) bool { + if len(fv.features) != len(other.features) { + return false + } + for bit := range fv.features { + if _, ok := other.features[bit]; !ok { + return false + } + } + return true +} + // Merges sets all feature bits in other on the receiver's feature vector. func (fv *RawFeatureVector) Merge(other *RawFeatureVector) error { for bit := range other.features { @@ -249,12 +281,13 @@ func (fv *RawFeatureVector) Clone() *RawFeatureVector { // IsSet returns whether a particular feature bit is enabled in the vector. func (fv *RawFeatureVector) IsSet(feature FeatureBit) bool { - return fv.features[feature] + _, ok := fv.features[feature] + return ok } // Set marks a feature as enabled in the vector. func (fv *RawFeatureVector) Set(feature FeatureBit) { - fv.features[feature] = true + fv.features[feature] = struct{}{} } // SafeSet sets the chosen feature bit in the feature vector, but returns an diff --git a/lnwire/features_test.go b/lnwire/features_test.go index 3eed2b1b403..d4be13d4cfa 100644 --- a/lnwire/features_test.go +++ b/lnwire/features_test.go @@ -353,3 +353,47 @@ func TestFeatures(t *testing.T) { }) } } + +func TestRawFeatureVectorOnlyContains(t *testing.T) { + t.Parallel() + + features := []FeatureBit{ + StaticRemoteKeyOptional, + AnchorsZeroFeeHtlcTxOptional, + ExplicitChannelTypeRequired, + } + fv := NewRawFeatureVector(features...) + require.True(t, fv.OnlyContains(features...)) + require.False(t, fv.OnlyContains(features[:1]...)) +} + +func TestEqualRawFeatureVectors(t *testing.T) { + t.Parallel() + + a := NewRawFeatureVector( + StaticRemoteKeyOptional, + AnchorsZeroFeeHtlcTxOptional, + ExplicitChannelTypeRequired, + ) + b := a.Clone() + require.True(t, a.Equals(b)) + + b.Unset(ExplicitChannelTypeRequired) + require.False(t, a.Equals(b)) + + b.Set(ExplicitChannelTypeOptional) + require.False(t, a.Equals(b)) +} + +func TestIsEmptyFeatureVector(t *testing.T) { + t.Parallel() + + fv := NewRawFeatureVector() + require.True(t, fv.IsEmpty()) + + fv.Set(StaticRemoteKeyOptional) + require.False(t, fv.IsEmpty()) + + fv.Unset(StaticRemoteKeyOptional) + require.True(t, fv.IsEmpty()) +} From de79673dd70ea997399727d3afac5d9d766774cd Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 9 Jun 2021 12:43:39 -0700 Subject: [PATCH 06/29] funding: add explicit commitment type negotiation support This commit adds the ability for a channel initiator/responder to determine whether the channel to be opened can use a specific commitment type through explicit negotiation. It also includes the existing implicit negotiation logic to fall back on if explicit negotiation is not supported. --- funding/commitment_type_negotiation.go | 120 ++++++++++++ funding/commitment_type_negotiation_test.go | 191 ++++++++++++++++++++ 2 files changed, 311 insertions(+) create mode 100644 funding/commitment_type_negotiation.go create mode 100644 funding/commitment_type_negotiation_test.go diff --git a/funding/commitment_type_negotiation.go b/funding/commitment_type_negotiation.go new file mode 100644 index 00000000000..e66dc78b290 --- /dev/null +++ b/funding/commitment_type_negotiation.go @@ -0,0 +1,120 @@ +package funding + +import ( + "errors" + + "github.com/lightningnetwork/lnd/lnwallet" + "github.com/lightningnetwork/lnd/lnwire" +) + +var ( + // errUnsupportedExplicitNegotiation is an error returned when explicit + // channel commitment negotiation is attempted but either peer of the + // channel does not support it. + errUnsupportedExplicitNegotiation = errors.New("explicit channel " + + "type negotiation not supported") + + // errUnsupportedCommitmentType is an error returned when a specific + // channel commitment type is being explicitly negotiated but either + // peer of the channel does not support it. + errUnsupportedChannelType = errors.New("requested channel type " + + "not supported") +) + +// negotiateCommitmentType negotiates the commitment type of a newly opened +// channel. If a channelType is provided, explicit negotiation for said type +// will be attempted if the set of both local and remote features support it. +// Otherwise, implicit negotiation will be attempted. +func negotiateCommitmentType(channelType *lnwire.ChannelType, + local, remote *lnwire.FeatureVector) (lnwallet.CommitmentType, error) { + + if channelType != nil { + if !hasFeatures(local, remote, lnwire.ExplicitChannelTypeOptional) { + return 0, errUnsupportedExplicitNegotiation + } + return explicitNegotiateCommitmentType( + *channelType, local, remote, + ) + } + + return implicitNegotiateCommitmentType(local, remote), nil +} + +// explicitNegotiateCommitmentType attempts to explicitly negotiate for a +// specific channel type. Since the channel type is comprised of a set of even +// feature bits, we also make sure each feature is supported by both peers. An +// error is returned if either peer does not support said channel type. +func explicitNegotiateCommitmentType(channelType lnwire.ChannelType, + local, remote *lnwire.FeatureVector) (lnwallet.CommitmentType, error) { + + channelFeatures := lnwire.RawFeatureVector(channelType) + + switch { + // Anchors zero fee + static remote key features only. + case channelFeatures.OnlyContains( + lnwire.AnchorsZeroFeeHtlcTxRequired, + lnwire.StaticRemoteKeyRequired, + ): + if !hasFeatures( + local, remote, + lnwire.AnchorsZeroFeeHtlcTxOptional, + lnwire.StaticRemoteKeyOptional, + ) { + return 0, errUnsupportedChannelType + } + return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, nil + + // Static remote key feature only. + case channelFeatures.OnlyContains(lnwire.StaticRemoteKeyRequired): + if !hasFeatures(local, remote, lnwire.StaticRemoteKeyOptional) { + return 0, errUnsupportedChannelType + } + return lnwallet.CommitmentTypeTweakless, nil + + // No features, use legacy commitment type. + case channelFeatures.IsEmpty(): + return lnwallet.CommitmentTypeLegacy, nil + + default: + return 0, errUnsupportedChannelType + } +} + +// implicitNegotiateCommitmentType negotiates the commitment type of a channel +// implicitly by choosing the latest type supported by the local and remote +// fetures. +func implicitNegotiateCommitmentType(local, + remote *lnwire.FeatureVector) lnwallet.CommitmentType { + + // If both peers are signalling support for anchor commitments with + // zero-fee HTLC transactions, we'll use this type. + if hasFeatures(local, remote, lnwire.AnchorsZeroFeeHtlcTxOptional) { + return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx + } + + // Since we don't want to support the "legacy" anchor type, we will fall + // back to static remote key if the nodes don't support the zero fee + // HTLC tx anchor type. + // + // If both nodes are signaling the proper feature bit for tweakless + // commitments, we'll use that. + if hasFeatures(local, remote, lnwire.StaticRemoteKeyOptional) { + return lnwallet.CommitmentTypeTweakless + } + + // Otherwise we'll fall back to the legacy type. + return lnwallet.CommitmentTypeLegacy +} + +// hasFeatures determines whether a set of features is supported by both the set +// of local and remote features. +func hasFeatures(local, remote *lnwire.FeatureVector, + features ...lnwire.FeatureBit) bool { + + for _, feature := range features { + if !local.HasFeature(feature) || !remote.HasFeature(feature) { + return false + } + } + return true +} diff --git a/funding/commitment_type_negotiation_test.go b/funding/commitment_type_negotiation_test.go new file mode 100644 index 00000000000..c9ac25a7a87 --- /dev/null +++ b/funding/commitment_type_negotiation_test.go @@ -0,0 +1,191 @@ +package funding + +import ( + "testing" + + "github.com/lightningnetwork/lnd/lnwallet" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/stretchr/testify/require" +) + +// TestCommitmentTypeNegotiation tests all of the possible paths of a channel +// commitment type negotiation. +func TestCommitmentTypeNegotiation(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + channelFeatures *lnwire.RawFeatureVector + localFeatures *lnwire.RawFeatureVector + remoteFeatures *lnwire.RawFeatureVector + expectsRes lnwallet.CommitmentType + expectsErr error + }{ + { + name: "explicit missing remote negotiation feature", + channelFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyRequired, + lnwire.AnchorsZeroFeeHtlcTxRequired, + ), + localFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyOptional, + lnwire.AnchorsZeroFeeHtlcTxOptional, + lnwire.ExplicitChannelTypeOptional, + ), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyOptional, + lnwire.AnchorsZeroFeeHtlcTxOptional, + ), + expectsErr: errUnsupportedExplicitNegotiation, + }, + { + name: "explicit missing remote commitment feature", + channelFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyRequired, + lnwire.AnchorsZeroFeeHtlcTxRequired, + ), + localFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyOptional, + lnwire.AnchorsZeroFeeHtlcTxOptional, + lnwire.ExplicitChannelTypeOptional, + ), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyOptional, + lnwire.ExplicitChannelTypeOptional, + ), + expectsErr: errUnsupportedChannelType, + }, + { + name: "explicit anchors", + channelFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyRequired, + lnwire.AnchorsZeroFeeHtlcTxRequired, + ), + localFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyOptional, + lnwire.AnchorsZeroFeeHtlcTxOptional, + lnwire.ExplicitChannelTypeOptional, + ), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyOptional, + lnwire.AnchorsZeroFeeHtlcTxOptional, + lnwire.ExplicitChannelTypeOptional, + ), + expectsRes: lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, + expectsErr: nil, + }, + { + name: "explicit tweakless", + channelFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyRequired, + ), + localFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyOptional, + lnwire.AnchorsZeroFeeHtlcTxOptional, + lnwire.ExplicitChannelTypeOptional, + ), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyOptional, + lnwire.AnchorsZeroFeeHtlcTxOptional, + lnwire.ExplicitChannelTypeOptional, + ), + expectsRes: lnwallet.CommitmentTypeTweakless, + expectsErr: nil, + }, + { + name: "explicit legacy", + channelFeatures: lnwire.NewRawFeatureVector(), + localFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyOptional, + lnwire.AnchorsZeroFeeHtlcTxOptional, + lnwire.ExplicitChannelTypeOptional, + ), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyOptional, + lnwire.AnchorsZeroFeeHtlcTxOptional, + lnwire.ExplicitChannelTypeOptional, + ), + expectsRes: lnwallet.CommitmentTypeLegacy, + expectsErr: nil, + }, + { + name: "implicit anchors", + channelFeatures: nil, + localFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyOptional, + lnwire.AnchorsZeroFeeHtlcTxOptional, + lnwire.ExplicitChannelTypeOptional, + ), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyOptional, + lnwire.AnchorsZeroFeeHtlcTxOptional, + lnwire.ExplicitChannelTypeOptional, + ), + expectsRes: lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, + expectsErr: nil, + }, + { + name: "implicit tweakless", + channelFeatures: nil, + localFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyOptional, + lnwire.AnchorsZeroFeeHtlcTxOptional, + ), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyOptional, + ), + expectsRes: lnwallet.CommitmentTypeTweakless, + expectsErr: nil, + }, + { + name: "implicit legacy", + channelFeatures: nil, + localFeatures: lnwire.NewRawFeatureVector(), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyOptional, + lnwire.AnchorsZeroFeeHtlcTxOptional, + ), + expectsRes: lnwallet.CommitmentTypeLegacy, + expectsErr: nil, + }, + } + + for _, testCase := range testCases { + testCase := testCase + ok := t.Run(testCase.name, func(t *testing.T) { + localFeatures := lnwire.NewFeatureVector( + testCase.localFeatures, lnwire.Features, + ) + remoteFeatures := lnwire.NewFeatureVector( + testCase.remoteFeatures, lnwire.Features, + ) + + var channelType *lnwire.ChannelType + if testCase.channelFeatures != nil { + channelType = new(lnwire.ChannelType) + *channelType = lnwire.ChannelType( + *testCase.channelFeatures, + ) + } + localType, err := negotiateCommitmentType( + channelType, localFeatures, remoteFeatures, + ) + require.Equal(t, testCase.expectsErr, err) + + remoteType, err := negotiateCommitmentType( + channelType, remoteFeatures, localFeatures, + ) + require.Equal(t, testCase.expectsErr, err) + + if testCase.expectsErr != nil { + return + } + + require.Equal(t, testCase.expectsRes, localType) + require.Equal(t, testCase.expectsRes, remoteType) + }) + if !ok { + return + } + } +} From ce2918e9504d56be22e48dee5d1cb0a0756b8907 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 3 Mar 2021 19:43:59 -0800 Subject: [PATCH 07/29] funding: use explicit commitment type negotiation when possible In this commit, we modify the existing logic that defaults to implicit commitment type negotiation to support explicit negotiation if the new feature bit is set. This change allows us to ditch the notion of a "default" commitment type, as we'll now use feature bits to signal our understanding of a commiment type, but allow peers to select which commitment type they actually wish to use. In addition, this explicit negotiation removes the need for using the required bit of any commitment types. Instead, if an implementation wishes to no longer support a commitment type, they should simply stop advertising the optional bit. --- funding/manager.go | 93 +++++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 42 deletions(-) diff --git a/funding/manager.go b/funding/manager.go index 2a0473b33d6..f600390440d 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -147,6 +147,10 @@ type reservationWithCtx struct { // maxLocalCsv is the maximum csv we will accept from the remote. maxLocalCsv uint16 + // channelType is the explicit channel type proposed by the initiator of + // the channel. + channelType *lnwire.ChannelType + updateMtx sync.RWMutex lastUpdated time.Time @@ -1137,43 +1141,6 @@ func (f *Manager) ProcessFundingMsg(msg lnwire.Message, peer lnpeer.Peer) { } } -// commitmentType returns the commitment type to use for the channel, based on -// the features the two peers have available. -func commitmentType(localFeatures, - remoteFeatures *lnwire.FeatureVector) lnwallet.CommitmentType { - - // If both peers are signalling support for anchor commitments with - // zero-fee HTLC transactions, we'll use this type. - localZeroFee := localFeatures.HasFeature( - lnwire.AnchorsZeroFeeHtlcTxOptional, - ) - remoteZeroFee := remoteFeatures.HasFeature( - lnwire.AnchorsZeroFeeHtlcTxOptional, - ) - if localZeroFee && remoteZeroFee { - return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx - } - - // Since we don't want to support the "legacy" anchor type, we will - // fall back to static remote key if the nodes don't support the zero - // fee HTLC tx anchor type. - localTweakless := localFeatures.HasFeature( - lnwire.StaticRemoteKeyOptional, - ) - remoteTweakless := remoteFeatures.HasFeature( - lnwire.StaticRemoteKeyOptional, - ) - - // If both nodes are signaling the proper feature bit for tweakless - // copmmitments, we'll use that. - if localTweakless && remoteTweakless { - return lnwallet.CommitmentTypeTweakless - } - - // Otherwise we'll fall back to the legacy type. - return lnwallet.CommitmentTypeLegacy -} - // handleFundingOpen creates an initial 'ChannelReservation' within the wallet, // then responds to the source peer with an accept channel message progressing // the funding workflow. @@ -1314,10 +1281,19 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer, // // Before we init the channel, we'll also check to see what commitment // format we can use with this peer. This is dependent on *both* us and - // the remote peer are signaling the proper feature bit. - commitType := commitmentType( - peer.LocalFeatures(), peer.RemoteFeatures(), + // the remote peer are signaling the proper feature bit if we're using + // implicit negotiation, and simply the channel type sent over if we're + // using explicit negotiation. + commitType, err := negotiateCommitmentType( + msg.ChannelType, peer.LocalFeatures(), peer.RemoteFeatures(), ) + if err != nil { + // TODO(roasbeef): should be using soft errors + log.Errorf("channel type negotiation failed: %v", err) + f.failFundingFlow(peer, msg.PendingChannelID, err) + return + } + chainHash := chainhash.Hash(msg.ChainHash) req := &lnwallet.InitFundingReserveMsg{ ChainHash: &chainHash, @@ -1447,6 +1423,7 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer, remoteMaxValue: remoteMaxValue, remoteMaxHtlcs: maxHtlcs, maxLocalCsv: f.cfg.MaxLocalCSVDelay, + channelType: msg.ChannelType, err: make(chan error, 1), peer: peer, } @@ -1519,6 +1496,7 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer, HtlcPoint: ourContribution.HtlcBasePoint.PubKey, FirstCommitmentPoint: ourContribution.FirstCommitmentPoint, UpfrontShutdownScript: ourContribution.UpfrontShutdown, + ChannelType: msg.ChannelType, } if err := peer.SendMessage(true, &fundingAccept); err != nil { @@ -1550,6 +1528,29 @@ func (f *Manager) handleFundingAccept(peer lnpeer.Peer, log.Infof("Recv'd fundingResponse for pending_id(%x)", pendingChanID[:]) + // We'll want to quickly check that ChannelType echoed by the channel + // request recipient matches what we proposed. + // + // TODO: Return errors as funding.Error to give context to remote peer? + if resCtx.channelType != nil { + if msg.ChannelType == nil { + err := errors.New("explicit channel type not echoed back") + f.failFundingFlow(peer, msg.PendingChannelID, err) + return + } + proposedFeatures := lnwire.RawFeatureVector(*resCtx.channelType) + ackedFeatures := lnwire.RawFeatureVector(*msg.ChannelType) + if !proposedFeatures.Equals(&ackedFeatures) { + err := errors.New("channel type mismatch") + f.failFundingFlow(peer, msg.PendingChannelID, err) + return + } + } else if msg.ChannelType != nil { + err := errors.New("received unexpected channel type") + f.failFundingFlow(peer, msg.PendingChannelID, err) + return + } + // The required number of confirmations should not be greater than the // maximum number of confirmations required by the ChainNotifier to // properly dispatch confirmations. @@ -3183,9 +3184,15 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) { // Before we init the channel, we'll also check to see what commitment // format we can use with this peer. This is dependent on *both* us and // the remote peer are signaling the proper feature bit. - commitType := commitmentType( - msg.Peer.LocalFeatures(), msg.Peer.RemoteFeatures(), + commitType, err := negotiateCommitmentType( + msg.ChannelType, msg.Peer.LocalFeatures(), + msg.Peer.RemoteFeatures(), ) + if err != nil { + log.Errorf("channel type negotiation failed: %v", err) + msg.Err <- err + return + } // First, we'll query the fee estimator for a fee that should get the // commitment transaction confirmed by the next few blocks (conf target @@ -3277,6 +3284,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) { remoteMaxValue: maxValue, remoteMaxHtlcs: maxHtlcs, maxLocalCsv: maxCSV, + channelType: msg.ChannelType, reservation: reservation, peer: msg.Peer, updates: msg.Updates, @@ -3320,6 +3328,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) { FirstCommitmentPoint: ourContribution.FirstCommitmentPoint, ChannelFlags: channelFlags, UpfrontShutdownScript: shutdown, + ChannelType: msg.ChannelType, } if err := msg.Peer.SendMessage(true, &fundingOpen); err != nil { e := fmt.Errorf("unable to send funding request message: %v", From 082c0195adc83f2ce114874a6be02672c6e4875e Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 9 Jun 2021 12:49:01 -0700 Subject: [PATCH 08/29] lntest: replace `commitType` type with rpc alternative --- lntest/itest/lnd_channel_backup_test.go | 5 +- lntest/itest/lnd_channel_balance_test.go | 10 +-- lntest/itest/lnd_channel_force_close.go | 32 ++++----- lntest/itest/lnd_funding_test.go | 38 +++++------ .../lnd_multi-hop-error-propagation_test.go | 2 +- .../lnd_multi-hop_htlc_aggregation_test.go | 10 +-- ...d_multi-hop_htlc_local_chain_claim_test.go | 11 ++-- .../lnd_multi-hop_htlc_local_timeout_test.go | 4 +- ...ulti-hop_htlc_receiver_chain_claim_test.go | 6 +- ..._multi-hop_htlc_remote_chain_claim_test.go | 12 ++-- ..._force_close_on_chain_htlc_timeout_test.go | 8 ++- ..._force_close_on_chain_htlc_timeout_test.go | 8 +-- lntest/itest/lnd_multi-hop_test.go | 16 ++--- lntest/itest/lnd_onchain_test.go | 2 +- lntest/itest/utils.go | 66 ++++--------------- 15 files changed, 96 insertions(+), 134 deletions(-) diff --git a/lntest/itest/lnd_channel_backup_test.go b/lntest/itest/lnd_channel_backup_test.go index 89558dcb35c..3dbbe1edf84 100644 --- a/lntest/itest/lnd_channel_backup_test.go +++ b/lntest/itest/lnd_channel_backup_test.go @@ -822,7 +822,10 @@ func testChanRestoreScenario(t *harnessTest, net *lntest.NetworkHarness, "--maxbackoff=1s", } if testCase.anchorCommit { - nodeArgs = append(nodeArgs, commitTypeAnchors.Args()...) + anchorNodeArgs := nodeArgsForCommitType( + lnrpc.CommitmentType_ANCHORS, + ) + nodeArgs = append(nodeArgs, anchorNodeArgs...) } // First, we'll create a brand new node we'll use within the test. If diff --git a/lntest/itest/lnd_channel_balance_test.go b/lntest/itest/lnd_channel_balance_test.go index 14552fd5ae6..a4760a8e522 100644 --- a/lntest/itest/lnd_channel_balance_test.go +++ b/lntest/itest/lnd_channel_balance_test.go @@ -83,10 +83,10 @@ func testChannelBalance(net *lntest.NetworkHarness, t *harnessTest) { // As this is a single funder channel, Alice's balance should be // exactly 0.5 BTC since now state transitions have taken place yet. - checkChannelBalance(net.Alice, amount-cType.calcStaticFee(0), 0) + checkChannelBalance(net.Alice, amount-calcStaticFee(cType, 0), 0) // Ensure Bob currently has no available balance within the channel. - checkChannelBalance(net.Bob, 0, amount-cType.calcStaticFee(0)) + checkChannelBalance(net.Bob, 0, amount-calcStaticFee(cType, 0)) // Finally close the channel between Alice and Bob, asserting that the // channel has been properly closed on-chain. @@ -179,11 +179,11 @@ func testChannelUnsettledBalance(net *lntest.NetworkHarness, t *harnessTest) { // Check alice's channel balance, which should have zero remote and zero // pending balance. - checkChannelBalance(net.Alice, chanAmt-cType.calcStaticFee(0), 0, 0, 0) + checkChannelBalance(net.Alice, chanAmt-calcStaticFee(cType, 0), 0, 0, 0) // Check carol's channel balance, which should have zero local and zero // pending balance. - checkChannelBalance(carol, 0, chanAmt-cType.calcStaticFee(0), 0, 0) + checkChannelBalance(carol, 0, chanAmt-calcStaticFee(cType, 0), 0, 0) // Channel should be ready for payments. const ( @@ -264,7 +264,7 @@ func testChannelUnsettledBalance(net *lntest.NetworkHarness, t *harnessTest) { // Check alice's channel balance, which should have a remote unsettled // balance that equals to the amount of invoices * payAmt. The remote // balance remains zero. - aliceLocal := chanAmt - cType.calcStaticFee(0) - numInvoices*payAmt + aliceLocal := chanAmt - calcStaticFee(cType, 0) - numInvoices*payAmt checkChannelBalance(net.Alice, aliceLocal, 0, 0, numInvoices*payAmt) // Check carol's channel balance, which should have a local unsettled diff --git a/lntest/itest/lnd_channel_force_close.go b/lntest/itest/lnd_channel_force_close.go index 9077a7c4829..bdc99eaab5a 100644 --- a/lntest/itest/lnd_channel_force_close.go +++ b/lntest/itest/lnd_channel_force_close.go @@ -79,7 +79,7 @@ func testCommitmentTransactionDeadline(net *lntest.NetworkHarness, setupNode := func(name string) *lntest.HarnessNode { // Create the node. args := []string{"--hodl.exit-settle"} - args = append(args, commitTypeAnchors.Args()...) + args = append(args, nodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS)...) node := net.NewNode(t.t, name, args) // Send some coins to the node. @@ -240,9 +240,9 @@ func calculateTxnsFeeRate(t *testing.T, func testChannelForceClosure(net *lntest.NetworkHarness, t *harnessTest) { // We'll test the scenario for some of the commitment types, to ensure // outputs can be swept. - commitTypes := []commitType{ - commitTypeLegacy, - commitTypeAnchors, + commitTypes := []lnrpc.CommitmentType{ + lnrpc.CommitmentType_LEGACY, + lnrpc.CommitmentType_ANCHORS, } for _, channelType := range commitTypes { @@ -257,7 +257,7 @@ func testChannelForceClosure(net *lntest.NetworkHarness, t *harnessTest) { success := t.t.Run(testName, func(t *testing.T) { ht := newHarnessTest(t, net) - args := channelType.Args() + args := nodeArgsForCommitType(channelType) alice := net.NewNode(ht.t, "Alice", args) defer shutdownAndAssert(net, ht, alice) @@ -291,7 +291,7 @@ func testChannelForceClosure(net *lntest.NetworkHarness, t *harnessTest) { } func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest, - alice, carol *lntest.HarnessNode, channelType commitType) { + alice, carol *lntest.HarnessNode, channelType lnrpc.CommitmentType) { ctxb := context.Background() @@ -405,7 +405,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest, // sweep the HTLC second level output one block earlier (than the // nursery that waits an additional block, and handles non-anchor // channels). So we set a maturity height that is one less. - if channelType == commitTypeAnchors { + if channelType == lnrpc.CommitmentType_ANCHORS { htlcCsvMaturityHeight = padCLTV( startHeight + defaultCLTV + defaultCSV, ) @@ -489,7 +489,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest, // also expect the anchor sweep tx to be in the mempool. expectedTxes := 1 expectedFeeRate := commitFeeRate - if channelType == commitTypeAnchors { + if channelType == lnrpc.CommitmentType_ANCHORS { expectedTxes = 2 expectedFeeRate = actualFeeRate } @@ -526,7 +526,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest, // If we expect anchors, add alice's anchor to our expected set of // reports. - if channelType == commitTypeAnchors { + if channelType == lnrpc.CommitmentType_ANCHORS { aliceReports[aliceAnchor.OutPoint.String()] = &lnrpc.Resolution{ ResolutionType: lnrpc.ResolutionType_ANCHOR, Outcome: lnrpc.ResolutionOutcome_CLAIMED, @@ -583,7 +583,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest, "limbo") } expectedRecoveredBalance := int64(0) - if channelType == commitTypeAnchors { + if channelType == lnrpc.CommitmentType_ANCHORS { expectedRecoveredBalance = anchorSize } if forceClose.RecoveredBalance != expectedRecoveredBalance { @@ -632,7 +632,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest, ) // If we have anchors, add an anchor resolution for carol. - if channelType == commitTypeAnchors { + if channelType == lnrpc.CommitmentType_ANCHORS { carolReports[carolAnchor.OutPoint.String()] = &lnrpc.Resolution{ ResolutionType: lnrpc.ResolutionType_ANCHOR, Outcome: lnrpc.ResolutionOutcome_CLAIMED, @@ -707,7 +707,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest, "limbo") } expectedRecoveredBalance := int64(0) - if channelType == commitTypeAnchors { + if channelType == lnrpc.CommitmentType_ANCHORS { expectedRecoveredBalance = anchorSize } if forceClose.RecoveredBalance != expectedRecoveredBalance { @@ -941,7 +941,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest, expectedTxes = numInvoices // In case of anchors, the timeout txs will be aggregated into one. - if channelType == commitTypeAnchors { + if channelType == lnrpc.CommitmentType_ANCHORS { expectedTxes = 1 } @@ -959,7 +959,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest, // this is an anchor channel, the transactions are aggregated by the // sweeper into one. numInputs := 1 - if channelType == commitTypeAnchors { + if channelType == lnrpc.CommitmentType_ANCHORS { numInputs = numInvoices + 1 } @@ -1087,7 +1087,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest, // Advance the chain until just before the 2nd-layer CSV delays expire. // For anchor channels thhis is one block earlier. numBlocks := uint32(defaultCSV - 1) - if channelType == commitTypeAnchors { + if channelType == lnrpc.CommitmentType_ANCHORS { numBlocks = defaultCSV - 2 } @@ -1318,7 +1318,7 @@ func channelForceClosureTest(net *lntest.NetworkHarness, t *harnessTest, // In addition, if this is an anchor-enabled channel, further add the // anchor size. - if channelType == commitTypeAnchors { + if channelType == lnrpc.CommitmentType_ANCHORS { carolExpectedBalance += btcutil.Amount(anchorSize) } diff --git a/lntest/itest/lnd_funding_test.go b/lntest/itest/lnd_funding_test.go index 492d70e5e75..320d0a4a589 100644 --- a/lntest/itest/lnd_funding_test.go +++ b/lntest/itest/lnd_funding_test.go @@ -31,19 +31,19 @@ func testBasicChannelFunding(net *lntest.NetworkHarness, t *harnessTest) { // Run through the test with combinations of all the different // commitment types. - allTypes := []commitType{ - commitTypeLegacy, - commitTypeTweakless, - commitTypeAnchors, + allTypes := []lnrpc.CommitmentType{ + lnrpc.CommitmentType_LEGACY, + lnrpc.CommitmentType_STATIC_REMOTE_KEY, + lnrpc.CommitmentType_ANCHORS, } // testFunding is a function closure that takes Carol and Dave's // commitment types and test the funding flow. - testFunding := func(carolCommitType, daveCommitType commitType) { + testFunding := func(carolCommitType, daveCommitType lnrpc.CommitmentType) { // Based on the current tweak variable for Carol, we'll // preferentially signal the legacy commitment format. We do // the same for Dave shortly below. - carolArgs := carolCommitType.Args() + carolArgs := nodeArgsForCommitType(carolCommitType) carol := net.NewNode(t.t, "Carol", carolArgs) defer shutdownAndAssert(net, t, carol) @@ -52,7 +52,7 @@ func testBasicChannelFunding(net *lntest.NetworkHarness, t *harnessTest) { ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) net.SendCoins(ctxt, t.t, btcutil.SatoshiPerBitcoin, carol) - daveArgs := daveCommitType.Args() + daveArgs := nodeArgsForCommitType(daveCommitType) dave := net.NewNode(t.t, "Dave", daveArgs) defer shutdownAndAssert(net, t, dave) @@ -85,20 +85,20 @@ func testBasicChannelFunding(net *lntest.NetworkHarness, t *harnessTest) { // Dave supports anchors, type will be what // Carol supports. - case commitTypeAnchors: + case lnrpc.CommitmentType_ANCHORS: // Dave only supports tweakless, channel will // be downgraded to this type if Carol supports // anchors. - case commitTypeTweakless: - if expType == commitTypeAnchors { - expType = commitTypeTweakless + case lnrpc.CommitmentType_STATIC_REMOTE_KEY: + if expType == lnrpc.CommitmentType_ANCHORS { + expType = lnrpc.CommitmentType_STATIC_REMOTE_KEY } // Dave only supoprts legacy type, channel will // be downgraded to this type. - case commitTypeLegacy: - expType = commitTypeLegacy + case lnrpc.CommitmentType_LEGACY: + expType = lnrpc.CommitmentType_LEGACY default: t.Fatalf("invalid commit type %v", daveCommitType) @@ -107,13 +107,13 @@ func testBasicChannelFunding(net *lntest.NetworkHarness, t *harnessTest) { // Check that the signalled type matches what we // expect. switch { - case expType == commitTypeAnchors && + case expType == lnrpc.CommitmentType_ANCHORS && chansCommitType == lnrpc.CommitmentType_ANCHORS: - case expType == commitTypeTweakless && + case expType == lnrpc.CommitmentType_STATIC_REMOTE_KEY && chansCommitType == lnrpc.CommitmentType_STATIC_REMOTE_KEY: - case expType == commitTypeLegacy && + case expType == lnrpc.CommitmentType_LEGACY && chansCommitType == lnrpc.CommitmentType_LEGACY: default: @@ -226,7 +226,7 @@ func basicChannelFundingTest(t *harnessTest, net *lntest.NetworkHarness, // With the channel open, ensure that the amount specified above has // properly been pushed to Bob. - aliceLocalBalance := chanAmt - pushAmt - cType.calcStaticFee(0) + aliceLocalBalance := chanAmt - pushAmt - calcStaticFee(cType, 0) checkChannelBalance( alice, aliceChannelBalance, aliceLocalBalance, pushAmt, ) @@ -351,8 +351,8 @@ func testUnconfirmedChannelFunding(net *lntest.NetworkHarness, t *harnessTest) { // // Note that atm we haven't obtained the chanPoint yet, so we use the // type directly. - cType := commitTypeTweakless - carolLocalBalance := chanAmt - pushAmt - cType.calcStaticFee(0) + cType := lnrpc.CommitmentType_STATIC_REMOTE_KEY + carolLocalBalance := chanAmt - pushAmt - calcStaticFee(cType, 0) checkChannelBalance(carol, 0, 0, carolLocalBalance, pushAmt) // For Alice, her local/remote balances should be zero, and the diff --git a/lntest/itest/lnd_multi-hop-error-propagation_test.go b/lntest/itest/lnd_multi-hop-error-propagation_test.go index 1bbed544d16..662b18534b2 100644 --- a/lntest/itest/lnd_multi-hop-error-propagation_test.go +++ b/lntest/itest/lnd_multi-hop-error-propagation_test.go @@ -40,7 +40,7 @@ func testHtlcErrorPropagation(net *lntest.NetworkHarness, t *harnessTest) { t.Fatalf("unable to get channel type: %v", err) } - commitFee := cType.calcStaticFee(0) + commitFee := calcStaticFee(cType, 0) assertBaseBalance := func() { // Alice has opened a channel with Bob with zero push amount, so // it's remote balance is zero. diff --git a/lntest/itest/lnd_multi-hop_htlc_aggregation_test.go b/lntest/itest/lnd_multi-hop_htlc_aggregation_test.go index 3c91eed1f78..1bad6fc1d3a 100644 --- a/lntest/itest/lnd_multi-hop_htlc_aggregation_test.go +++ b/lntest/itest/lnd_multi-hop_htlc_aggregation_test.go @@ -23,7 +23,7 @@ import ( // case of anchor channels, the second-level spends can also be aggregated and // properly feebumped, so we'll check that as well. func testMultiHopHtlcAggregation(net *lntest.NetworkHarness, t *harnessTest, - alice, bob *lntest.HarnessNode, c commitType) { + alice, bob *lntest.HarnessNode, c lnrpc.CommitmentType) { const finalCltvDelta = 40 ctxb := context.Background() @@ -188,7 +188,7 @@ func testMultiHopHtlcAggregation(net *lntest.NetworkHarness, t *harnessTest, // Bob's force close transaction should now be found in the mempool. If // there are anchors, we also expect Bob's anchor sweep. expectedTxes := 1 - if c == commitTypeAnchors { + if c == lnrpc.CommitmentType_ANCHORS { expectedTxes = 2 } @@ -262,7 +262,7 @@ func testMultiHopHtlcAggregation(net *lntest.NetworkHarness, t *harnessTest, // one, the same is the case for the timeout transactions. In this case // Carol will also sweep her anchor output in a separate tx (since it // will be low fee). - if c == commitTypeAnchors { + if c == lnrpc.CommitmentType_ANCHORS { expectedTxes = 4 } @@ -298,7 +298,7 @@ func testMultiHopHtlcAggregation(net *lntest.NetworkHarness, t *harnessTest, // In case of anchor we expect all the timeout and success second // levels to be aggregated into one tx. For earlier channel types, they // will be separate transactions. - if c == commitTypeAnchors { + if c == lnrpc.CommitmentType_ANCHORS { require.Len(t.t, timeoutTxs, 1) require.Len(t.t, successTxs, 1) } else { @@ -375,7 +375,7 @@ func testMultiHopHtlcAggregation(net *lntest.NetworkHarness, t *harnessTest, // Mining one additional block, Bob's second level tx is mature, and he // can sweep the output. - case c == commitTypeAnchors: + case c == lnrpc.CommitmentType_ANCHORS: _ = mineBlocks(t, net, 1, 1) // In case this is a non-anchor channel type, we must mine 2 blocks, as diff --git a/lntest/itest/lnd_multi-hop_htlc_local_chain_claim_test.go b/lntest/itest/lnd_multi-hop_htlc_local_chain_claim_test.go index 0e37cd3a370..6f4ffc08ac5 100644 --- a/lntest/itest/lnd_multi-hop_htlc_local_chain_claim_test.go +++ b/lntest/itest/lnd_multi-hop_htlc_local_chain_claim_test.go @@ -20,7 +20,7 @@ import ( // preimage via the witness beacon, we properly settle the HTLC on-chain using // the HTLC success transaction in order to ensure we don't lose any funds. func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest, - alice, bob *lntest.HarnessNode, c commitType) { + alice, bob *lntest.HarnessNode, c lnrpc.CommitmentType) { ctxb := context.Background() @@ -87,13 +87,14 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest, // immediately, so he force closes his commitment transaction. ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) bobForceClose := closeChannelAndAssertType( - ctxt, t, net, bob, aliceChanPoint, c == commitTypeAnchors, true, + ctxt, t, net, bob, aliceChanPoint, + c == lnrpc.CommitmentType_ANCHORS, true, ) // Alice will sweep her commitment output immediately. If there are // anchors, Alice will also sweep hers. expectedTxes := 1 - if c == commitTypeAnchors { + if c == lnrpc.CommitmentType_ANCHORS { expectedTxes = 2 } _, err = waitForNTxsInMempool( @@ -162,7 +163,7 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest, // If there are anchors on the commitment, Bob will also sweep his // anchor. expectedTxes = 2 - if c == commitTypeAnchors { + if c == lnrpc.CommitmentType_ANCHORS { expectedTxes = 3 } txes, err := getNTxsFromMempool( @@ -189,7 +190,7 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest, // If this is a channel of the anchor type, we will subtract one block // from the default CSV, as the Sweeper will handle the input, and the Sweeper // sweeps the input as soon as the lock expires. - case commitTypeAnchors: + case lnrpc.CommitmentType_ANCHORS: secondLevelMaturity = defaultCSV - 1 // For non-anchor channel types, the nursery will handle sweeping the diff --git a/lntest/itest/lnd_multi-hop_htlc_local_timeout_test.go b/lntest/itest/lnd_multi-hop_htlc_local_timeout_test.go index e110f7defb2..a40a0c8d2e2 100644 --- a/lntest/itest/lnd_multi-hop_htlc_local_timeout_test.go +++ b/lntest/itest/lnd_multi-hop_htlc_local_timeout_test.go @@ -21,7 +21,7 @@ import ( // canceled backwards. Once the timeout has been reached, then we should sweep // it on-chain, and cancel the HTLC backwards. func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest, - alice, bob *lntest.HarnessNode, c commitType) { + alice, bob *lntest.HarnessNode, c lnrpc.CommitmentType) { ctxb := context.Background() @@ -104,7 +104,7 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest, // Bob's force close transaction should now be found in the mempool. If // there are anchors, we also expect Bob's anchor sweep. expectedTxes := 1 - if c == commitTypeAnchors { + if c == lnrpc.CommitmentType_ANCHORS { expectedTxes = 2 } diff --git a/lntest/itest/lnd_multi-hop_htlc_receiver_chain_claim_test.go b/lntest/itest/lnd_multi-hop_htlc_receiver_chain_claim_test.go index eb55344cfa2..ba264515308 100644 --- a/lntest/itest/lnd_multi-hop_htlc_receiver_chain_claim_test.go +++ b/lntest/itest/lnd_multi-hop_htlc_receiver_chain_claim_test.go @@ -22,7 +22,7 @@ import ( // extract the preimage from the sweep transaction, and finish settling the // HTLC backwards into the route. func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest, - alice, bob *lntest.HarnessNode, c commitType) { + alice, bob *lntest.HarnessNode, c lnrpc.CommitmentType) { ctxb := context.Background() @@ -113,7 +113,7 @@ func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest, // transaction in order to go to the chain and sweep her HTLC. If there // are anchors, Carol also sweeps hers. expectedTxes := 1 - if c == commitTypeAnchors { + if c == lnrpc.CommitmentType_ANCHORS { expectedTxes = 2 } _, err = getNTxsFromMempool( @@ -150,7 +150,7 @@ func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest, // and settle the HTLC back off-chain. Bob will also sweep his anchor, // if present. expectedTxes = 2 - if c == commitTypeAnchors { + if c == lnrpc.CommitmentType_ANCHORS { expectedTxes = 3 } txes, err := getNTxsFromMempool( diff --git a/lntest/itest/lnd_multi-hop_htlc_remote_chain_claim_test.go b/lntest/itest/lnd_multi-hop_htlc_remote_chain_claim_test.go index 842c5c2981a..77ac1373d9f 100644 --- a/lntest/itest/lnd_multi-hop_htlc_remote_chain_claim_test.go +++ b/lntest/itest/lnd_multi-hop_htlc_remote_chain_claim_test.go @@ -20,7 +20,7 @@ import ( // HTLC directly on-chain using the preimage in order to ensure that we don't // lose any funds. func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest, - alice, bob *lntest.HarnessNode, c commitType) { + alice, bob *lntest.HarnessNode, c lnrpc.CommitmentType) { ctxb := context.Background() @@ -87,8 +87,8 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest // transaction. ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) aliceForceClose := closeChannelAndAssertType( - ctxt, t, net, alice, aliceChanPoint, c == commitTypeAnchors, - true, + ctxt, t, net, alice, aliceChanPoint, + c == lnrpc.CommitmentType_ANCHORS, true, ) // Wait for the channel to be marked pending force close. @@ -99,7 +99,7 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest // After closeChannelAndAssertType returns, it has mined a block so now // bob will attempt to redeem his anchor commitment (if the channel // type is of that type). - if c == commitTypeAnchors { + if c == lnrpc.CommitmentType_ANCHORS { _, err = waitForNTxsInMempool( net.Miner.Client, 1, minerMempoolTimeout, ) @@ -149,7 +149,7 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest require.NoError(t.t, err) expectedTxes := 1 - if c == commitTypeAnchors { + if c == lnrpc.CommitmentType_ANCHORS { expectedTxes = 2 } @@ -189,7 +189,7 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest // the output is not timelocked since Carol was the one force closing. // If there are anchors, Bob should also sweep his. expectedTxes = 2 - if c == commitTypeAnchors { + if c == lnrpc.CommitmentType_ANCHORS { expectedTxes = 3 } txes, err := getNTxsFromMempool( diff --git a/lntest/itest/lnd_multi-hop_local_force_close_on_chain_htlc_timeout_test.go b/lntest/itest/lnd_multi-hop_local_force_close_on_chain_htlc_timeout_test.go index 0d148652c4b..d61278e0c7a 100644 --- a/lntest/itest/lnd_multi-hop_local_force_close_on_chain_htlc_timeout_test.go +++ b/lntest/itest/lnd_multi-hop_local_force_close_on_chain_htlc_timeout_test.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/btcsuite/btcutil" + "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest/wait" @@ -17,7 +18,7 @@ import ( // that's timed out. At this point, the node should timeout the HTLC using the // HTLC timeout transaction, then cancel it backwards as normal. func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness, - t *harnessTest, alice, bob *lntest.HarnessNode, c commitType) { + t *harnessTest, alice, bob *lntest.HarnessNode, c lnrpc.CommitmentType) { ctxb := context.Background() @@ -73,7 +74,8 @@ func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness, // resolution mode for both of them. ctxt, _ := context.WithTimeout(ctxb, channelCloseTimeout) closeChannelAndAssertType( - ctxt, t, net, bob, bobChanPoint, c == commitTypeAnchors, true, + ctxt, t, net, bob, bobChanPoint, + c == lnrpc.CommitmentType_ANCHORS, true, ) // At this point, Bob should have a pending force close channel as he @@ -95,7 +97,7 @@ func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness, // We'll mine defaultCSV blocks in order to generate the sweep // transaction of Bob's funding output. If there are anchors, mine // Carol's anchor sweep too. - if c == commitTypeAnchors { + if c == lnrpc.CommitmentType_ANCHORS { _, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout) require.NoError(t.t, err) } diff --git a/lntest/itest/lnd_multi-hop_remote_force_close_on_chain_htlc_timeout_test.go b/lntest/itest/lnd_multi-hop_remote_force_close_on_chain_htlc_timeout_test.go index cf237c89263..a20466135b4 100644 --- a/lntest/itest/lnd_multi-hop_remote_force_close_on_chain_htlc_timeout_test.go +++ b/lntest/itest/lnd_multi-hop_remote_force_close_on_chain_htlc_timeout_test.go @@ -20,7 +20,7 @@ import ( // transaction once the timeout has expired. Once we sweep the transaction, we // should also cancel back the initial HTLC. func testMultiHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness, - t *harnessTest, alice, bob *lntest.HarnessNode, c commitType) { + t *harnessTest, alice, bob *lntest.HarnessNode, c lnrpc.CommitmentType) { ctxb := context.Background() @@ -85,8 +85,8 @@ func testMultiHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness, // Carol has an anchor, it will be swept too. ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) closeChannelAndAssertType( - ctxt, t, net, carol, bobChanPoint, c == commitTypeAnchors, - true, + ctxt, t, net, carol, bobChanPoint, + c == lnrpc.CommitmentType_ANCHORS, true, ) // At this point, Bob should have a pending force close channel as @@ -98,7 +98,7 @@ func testMultiHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness, // Bob can sweep his output immediately. If there is an anchor, Bob will // sweep that as well. expectedTxes := 1 - if c == commitTypeAnchors { + if c == lnrpc.CommitmentType_ANCHORS { expectedTxes = 2 } diff --git a/lntest/itest/lnd_multi-hop_test.go b/lntest/itest/lnd_multi-hop_test.go index 536cc63100b..b7e7dce85c4 100644 --- a/lntest/itest/lnd_multi-hop_test.go +++ b/lntest/itest/lnd_multi-hop_test.go @@ -19,7 +19,7 @@ func testMultiHopHtlcClaims(net *lntest.NetworkHarness, t *harnessTest) { type testCase struct { name string test func(net *lntest.NetworkHarness, t *harnessTest, alice, - bob *lntest.HarnessNode, c commitType) + bob *lntest.HarnessNode, c lnrpc.CommitmentType) } subTests := []testCase{ @@ -68,19 +68,19 @@ func testMultiHopHtlcClaims(net *lntest.NetworkHarness, t *harnessTest) { }, } - commitTypes := []commitType{ - commitTypeLegacy, - commitTypeAnchors, + commitTypes := []lnrpc.CommitmentType{ + lnrpc.CommitmentType_LEGACY, + lnrpc.CommitmentType_ANCHORS, } for _, commitType := range commitTypes { + commitType := commitType testName := fmt.Sprintf("committype=%v", commitType.String()) - commitType := commitType success := t.t.Run(testName, func(t *testing.T) { ht := newHarnessTest(t, net) - args := commitType.Args() + args := nodeArgsForCommitType(commitType) alice := net.NewNode(t, "Alice", args) defer shutdownAndAssert(net, ht, alice) @@ -203,7 +203,7 @@ func checkPaymentStatus(ctxt context.Context, node *lntest.HarnessNode, } func createThreeHopNetwork(t *harnessTest, net *lntest.NetworkHarness, - alice, bob *lntest.HarnessNode, carolHodl bool, c commitType) ( + alice, bob *lntest.HarnessNode, carolHodl bool, c lnrpc.CommitmentType) ( *lnrpc.ChannelPoint, *lnrpc.ChannelPoint, *lntest.HarnessNode) { ctxb := context.Background() @@ -246,7 +246,7 @@ func createThreeHopNetwork(t *harnessTest, net *lntest.NetworkHarness, // Next, we'll create a new node "carol" and have Bob connect to her. If // the carolHodl flag is set, we'll make carol always hold onto the // HTLC, this way it'll force Bob to go to chain to resolve the HTLC. - carolFlags := c.Args() + carolFlags := nodeArgsForCommitType(c) if carolHodl { carolFlags = append(carolFlags, "--hodl.exit-settle") } diff --git a/lntest/itest/lnd_onchain_test.go b/lntest/itest/lnd_onchain_test.go index f3e278e1707..f79d0a9c14a 100644 --- a/lntest/itest/lnd_onchain_test.go +++ b/lntest/itest/lnd_onchain_test.go @@ -168,7 +168,7 @@ func testCPFP(net *lntest.NetworkHarness, t *harnessTest) { // wallet. func testAnchorReservedValue(net *lntest.NetworkHarness, t *harnessTest) { // Start two nodes supporting anchor channels. - args := commitTypeAnchors.Args() + args := nodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) alice := net.NewNode(t.t, "Alice", args) defer shutdownAndAssert(net, t, alice) diff --git a/lntest/itest/utils.go b/lntest/itest/utils.go index 1d354a126af..c6945096ec3 100644 --- a/lntest/itest/utils.go +++ b/lntest/itest/utils.go @@ -203,45 +203,15 @@ func getChanInfo(ctx context.Context, node *lntest.HarnessNode) ( return channelInfo.Channels[0], nil } -// commitType is a simple enum used to run though the basic funding flow with -// different commitment formats. -type commitType byte - -const ( - // commitTypeLegacy is the old school commitment type. - commitTypeLegacy commitType = iota - - // commiTypeTweakless is the commitment type where the remote key is - // static (non-tweaked). - commitTypeTweakless - - // commitTypeAnchors is the kind of commitment that has extra outputs - // used for anchoring down to commitment using CPFP. - commitTypeAnchors -) - -// String returns that name of the commitment type. -func (c commitType) String() string { - switch c { - case commitTypeLegacy: - return "legacy" - case commitTypeTweakless: - return "tweakless" - case commitTypeAnchors: - return "anchors" - default: - return "invalid" - } -} - -// Args returns the command line flag to supply to enable this commitment type. -func (c commitType) Args() []string { - switch c { - case commitTypeLegacy: +// nodeArgsForCommitType returns the command line flag to supply to enable this +// commitment type. +func nodeArgsForCommitType(commitType lnrpc.CommitmentType) []string { + switch commitType { + case lnrpc.CommitmentType_LEGACY: return []string{"--protocol.legacy.committweak"} - case commitTypeTweakless: + case lnrpc.CommitmentType_STATIC_REMOTE_KEY: return []string{} - case commitTypeAnchors: + case lnrpc.CommitmentType_ANCHORS: return []string{"--protocol.anchors"} } @@ -251,7 +221,7 @@ func (c commitType) Args() []string { // calcStaticFee calculates appropriate fees for commitment transactions. This // function provides a simple way to allow test balance assertions to take fee // calculations into account. -func (c commitType) calcStaticFee(numHTLCs int) btcutil.Amount { +func calcStaticFee(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount { const htlcWeight = input.HTLCWeight var ( feePerKw = chainfee.SatPerKVByte(50000).FeePerKWeight() @@ -263,7 +233,7 @@ func (c commitType) calcStaticFee(numHTLCs int) btcutil.Amount { // the value of the two anchors to the resulting fee the initiator // pays. In addition the fee rate is capped at 10 sat/vbyte for anchor // channels. - if c == commitTypeAnchors { + if c == lnrpc.CommitmentType_ANCHORS { feePerKw = chainfee.SatPerKVByte( lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte * 1000, ).FeePerKWeight() @@ -278,7 +248,7 @@ func (c commitType) calcStaticFee(numHTLCs int) btcutil.Amount { // channelCommitType retrieves the active channel commitment type for the given // chan point. func channelCommitType(node *lntest.HarnessNode, - chanPoint *lnrpc.ChannelPoint) (commitType, error) { + chanPoint *lnrpc.ChannelPoint) (lnrpc.CommitmentType, error) { ctxb := context.Background() ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) @@ -291,21 +261,7 @@ func channelCommitType(node *lntest.HarnessNode, for _, c := range channels.Channels { if c.ChannelPoint == txStr(chanPoint) { - switch c.CommitmentType { - - // If the anchor output size is non-zero, we are - // dealing with the anchor type. - case lnrpc.CommitmentType_ANCHORS: - return commitTypeAnchors, nil - - // StaticRemoteKey means it is tweakless, - case lnrpc.CommitmentType_STATIC_REMOTE_KEY: - return commitTypeTweakless, nil - - // Otherwise legacy. - default: - return commitTypeLegacy, nil - } + return c.CommitmentType, nil } } From 478f6403057da224309ee552bc6f3b62a1726438 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 9 Jun 2021 16:38:45 -0700 Subject: [PATCH 09/29] lntest: use explicit channel commitment negotiation for multi-hop itests --- lntest/harness.go | 5 +++++ lntest/itest/lnd_multi-hop_test.go | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lntest/harness.go b/lntest/harness.go index ae31ccf04fe..0977930dcab 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -968,6 +968,10 @@ type OpenChannelParams struct { // SatPerVByte is the amount of satoshis to spend in chain fees per virtual // byte of the transaction. SatPerVByte btcutil.Amount + + // CommitmentType is the commitment type that should be used for the + // channel to be opened. + CommitmentType lnrpc.CommitmentType } // OpenChannel attempts to open a channel between srcNode and destNode with the @@ -1006,6 +1010,7 @@ func (n *NetworkHarness) OpenChannel(ctx context.Context, RemoteMaxHtlcs: uint32(p.RemoteMaxHtlcs), FundingShim: p.FundingShim, SatPerByte: int64(p.SatPerVByte), + CommitmentType: p.CommitmentType, } respStream, err := srcNode.OpenChannel(ctx, openReq) diff --git a/lntest/itest/lnd_multi-hop_test.go b/lntest/itest/lnd_multi-hop_test.go index b7e7dce85c4..0001f7d0c10 100644 --- a/lntest/itest/lnd_multi-hop_test.go +++ b/lntest/itest/lnd_multi-hop_test.go @@ -227,7 +227,8 @@ func createThreeHopNetwork(t *harnessTest, net *lntest.NetworkHarness, aliceChanPoint := openChannelAndAssert( ctxt, t, net, alice, bob, lntest.OpenChannelParams{ - Amt: chanAmt, + Amt: chanAmt, + CommitmentType: c, }, ) @@ -270,7 +271,8 @@ func createThreeHopNetwork(t *harnessTest, net *lntest.NetworkHarness, bobChanPoint := openChannelAndAssert( ctxt, t, net, bob, carol, lntest.OpenChannelParams{ - Amt: chanAmt, + Amt: chanAmt, + CommitmentType: c, }, ) ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) From 450f2be57d20cbec0cfcfbdfe86bef79e6dd6266 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Fri, 30 Jul 2021 14:49:57 -0700 Subject: [PATCH 10/29] lncli: add channel type flag to openchannel command --- cmd/lncli/cmd_open_channel.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/cmd/lncli/cmd_open_channel.go b/cmd/lncli/cmd_open_channel.go index a2c1a530359..cac46cae35b 100644 --- a/cmd/lncli/cmd_open_channel.go +++ b/cmd/lncli/cmd_open_channel.go @@ -57,6 +57,9 @@ Signed base64 encoded PSBT or hex encoded raw wire TX (or path to text file): ` // the user from choosing a large file by accident and running into out // of memory issues or other weird errors. psbtMaxFileSize = 1024 * 1024 + + channelTypeTweakless = "tweakless" + channelTypeAnchors = "anchors" ) // TODO(roasbeef): change default number of confirmations @@ -200,6 +203,12 @@ var openChannelCommand = cli.Command{ Usage: "(optional) the maximum value in msat that " + "can be pending within the channel at any given time", }, + cli.StringFlag{ + Name: "channel_type", + Usage: fmt.Sprintf("(optional) the type of channel to "+ + "propose to the remote peer (%q, %q)", + channelTypeTweakless, channelTypeAnchors), + }, }, Action: actionDecorator(openChannel), } @@ -307,6 +316,19 @@ func openChannel(ctx *cli.Context) error { req.Private = ctx.Bool("private") + // Parse the channel type and map it to its RPC representation. + channelType := ctx.String("channel_type") + switch channelType { + case "": + break + case channelTypeTweakless: + req.CommitmentType = lnrpc.CommitmentType_STATIC_REMOTE_KEY + case channelTypeAnchors: + req.CommitmentType = lnrpc.CommitmentType_ANCHORS + default: + return fmt.Errorf("unsupported channel type %v", channelType) + } + // PSBT funding is a more involved, interactive process that is too // large to also fit into this already long function. if ctx.Bool("psbt") { From 0c56b0725b05f900c11daaafd2e2ced8457a3434 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Fri, 30 Jul 2021 14:50:19 -0700 Subject: [PATCH 11/29] docs: add explicit channel negotiation text to release notes --- docs/release-notes/release-notes-0.14.0.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/release-notes/release-notes-0.14.0.md b/docs/release-notes/release-notes-0.14.0.md index ae221939687..6a1400e12dc 100644 --- a/docs/release-notes/release-notes-0.14.0.md +++ b/docs/release-notes/release-notes-0.14.0.md @@ -1,5 +1,16 @@ # Release Notes +## Protocol Extensions + +### Explicit Channel Negotiation + +[A new protocol extension has been added known as explicit channel negotiation] +(https://github.com/lightningnetwork/lnd/pull/5373). This allows a channel +initiator to signal their desired channel type to use with the remote peer. If +the remote peer supports said channel type and agrees, the previous implicit +negotiation based on the shared set of feature bits is bypassed, and the +proposed channel type is used. + ## RPC Server * [Return payment address and add index from @@ -83,4 +94,5 @@ to make LNDs payment throughput (and latency) with better when using etcd. * Martin Habovstiak * Zero-1729 * Oliver Gugger +* Wilmer Paulino * Yong Yu From 20f3b54c54acd094e419dfe083648cd82081197f Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Tue, 13 Jul 2021 15:11:14 -0700 Subject: [PATCH 12/29] lncfg: add protocol config option for script enforced lease support --- lncfg/protocol.go | 11 +++++++++++ lncfg/protocol_rpctest.go | 12 ++++++++++++ sample-lnd.conf | 6 ++++++ 3 files changed, 29 insertions(+) diff --git a/lncfg/protocol.go b/lncfg/protocol.go index afc129680fc..23e3d38cf18 100644 --- a/lncfg/protocol.go +++ b/lncfg/protocol.go @@ -23,6 +23,11 @@ type ProtocolOptions struct { // NoAnchors should be set if we don't want to support opening or accepting // channels having the anchor commitment type. NoAnchors bool `long:"no-anchors" description:"disable support for anchor commitments"` + + // NoScriptEnforcedLease should be set if we don't want to support + // opening or accepting channels having the script enforced commitment + // type for leased channel. + NoScriptEnforcedLease bool `long:"no-script-enforced-lease" description:"disable support for script enforced lease commitments"` } // Wumbo returns true if lnd should permit the creation and acceptance of wumbo @@ -36,3 +41,9 @@ func (l *ProtocolOptions) Wumbo() bool { func (l *ProtocolOptions) NoAnchorCommitments() bool { return l.NoAnchors } + +// NoScriptEnforcementLease returns true if we have disabled support for the +// script enforcement commitment type for leased channels. +func (l *ProtocolOptions) NoScriptEnforcementLease() bool { + return l.NoScriptEnforcedLease +} diff --git a/lncfg/protocol_rpctest.go b/lncfg/protocol_rpctest.go index 037aec7775e..fb12fd6866d 100644 --- a/lncfg/protocol_rpctest.go +++ b/lncfg/protocol_rpctest.go @@ -23,6 +23,12 @@ type ProtocolOptions struct { // Anchors enables anchor commitments. // TODO(halseth): transition itests to anchors instead! Anchors bool `long:"anchors" description:"enable support for anchor commitments"` + + // ScriptEnforcedLease enables script enforced commitments for channel + // leases. + // + // TODO: Move to experimental? + ScriptEnforcedLease bool `long:"script-enforced-lease" description:"enable support for script enforced lease commitments"` } // Wumbo returns true if lnd should permit the creation and acceptance of wumbo @@ -36,3 +42,9 @@ func (l *ProtocolOptions) Wumbo() bool { func (l *ProtocolOptions) NoAnchorCommitments() bool { return !l.Anchors } + +// NoScriptEnforcementLease returns true if we have disabled support for the +// script enforcement commitment type for leased channels. +func (l *ProtocolOptions) NoScriptEnforcementLease() bool { + return !l.ScriptEnforcedLease +} diff --git a/sample-lnd.conf b/sample-lnd.conf index 56fba9d672d..3fe713070b5 100644 --- a/sample-lnd.conf +++ b/sample-lnd.conf @@ -1070,6 +1070,12 @@ litecoin.node=ltcd ; (Deprecates the previous "protocol.anchors" setting.) ; protocol.no-anchors=true +; Set to disable support for script enforced lease channel commitments. If not +; set, lnd will accept these channels by default if the remote channel party +; proposes them. Note that lnd will require 1 UTXO to be reserved for this +; channel type if it is enabled. +; protocol.no-script-enforced-lease=true + [db] From dc1dd6e1cc0a6dac871c242c76f220f00a23594a Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Tue, 13 Jul 2021 15:20:46 -0700 Subject: [PATCH 13/29] lnwire+feature: add feature bit for script enforced lease support --- feature/default_sets.go | 4 ++++ feature/deps.go | 4 ++++ feature/manager.go | 8 ++++++++ lnwire/features.go | 20 ++++++++++++++++++++ server.go | 9 +++++---- 5 files changed, 41 insertions(+), 4 deletions(-) diff --git a/feature/default_sets.go b/feature/default_sets.go index 5ee98792a36..d345c90df94 100644 --- a/feature/default_sets.go +++ b/feature/default_sets.go @@ -64,4 +64,8 @@ var defaultSetDesc = setDesc{ SetInit: {}, // I SetNodeAnn: {}, // N }, + lnwire.ScriptEnforcedLeaseOptional: { + SetInit: {}, // I + SetNodeAnn: {}, // N + }, } diff --git a/feature/deps.go b/feature/deps.go index d6f57cb901c..92b0c03d59b 100644 --- a/feature/deps.go +++ b/feature/deps.go @@ -65,6 +65,10 @@ var deps = depDesc{ lnwire.PaymentAddrOptional: {}, }, lnwire.ExplicitChannelTypeOptional: {}, + lnwire.ScriptEnforcedLeaseOptional: { + lnwire.ExplicitChannelTypeOptional: {}, + lnwire.AnchorsZeroFeeHtlcTxOptional: {}, + }, } // ValidateDeps asserts that a feature vector sets all features and their diff --git a/feature/manager.go b/feature/manager.go index 9891807151e..50a54d62516 100644 --- a/feature/manager.go +++ b/feature/manager.go @@ -23,6 +23,10 @@ type Config struct { // NoWumbo unsets any bits signalling support for wumbo channels. NoWumbo bool + + // NoScriptEnforcementLease unsets any bits signaling support for script + // enforced leases. + NoScriptEnforcementLease bool } // Manager is responsible for generating feature vectors for different requested @@ -92,6 +96,10 @@ func newManager(cfg Config, desc setDesc) (*Manager, error) { raw.Unset(lnwire.WumboChannelsOptional) raw.Unset(lnwire.WumboChannelsRequired) } + if cfg.NoScriptEnforcementLease { + raw.Unset(lnwire.ScriptEnforcedLeaseOptional) + raw.Unset(lnwire.ScriptEnforcedLeaseRequired) + } // Ensure that all of our feature sets properly set any // dependent features. diff --git a/lnwire/features.go b/lnwire/features.go index d2ef0a6237a..c800563c1e6 100644 --- a/lnwire/features.go +++ b/lnwire/features.go @@ -159,6 +159,24 @@ const ( // TODO: Decide on actual feature bit value. ExplicitChannelTypeOptional = 2021 + // ScriptEnforcedLeaseOptional is an optional feature bit that signals + // that the node requires channels having zero-fee second-level HTLC + // transactions, which also imply anchor commitments, along with an + // additional CLTV constraint of a channel lease's expiration height + // applied to all outputs that pay directly to the channel initiator. + // + // TODO: Decide on actual feature bit value. + ScriptEnforcedLeaseRequired FeatureBit = 2022 + + // ScriptEnforcedLeaseOptional is a required feature bit that signals + // that the node requires channels having zero-fee second-level HTLC + // transactions, which also imply anchor commitments, along with an + // additional CLTV constraint of a channel lease's expiration height + // applied to all outputs that pay directly to the channel initiator. + // + // TODO: Decide on actual feature bit value. + ScriptEnforcedLeaseOptional FeatureBit = 2023 + // maxAllowedSize is a maximum allowed size of feature vector. // // NOTE: Within the protocol, the maximum allowed message size is 65535 @@ -206,6 +224,8 @@ var Features = map[FeatureBit]string{ AMPOptional: "amp", ExplicitChannelTypeOptional: "explicit-commitment-type", ExplicitChannelTypeRequired: "explicit-commitment-type", + ScriptEnforcedLeaseRequired: "script-enforced-lease", + ScriptEnforcedLeaseOptional: "script-enforced-lease", } // RawFeatureVector represents a set of feature bits as defined in BOLT-09. A diff --git a/server.go b/server.go index 2b914b90a4c..963ae64bc4f 100644 --- a/server.go +++ b/server.go @@ -413,10 +413,11 @@ func newServer(cfg *Config, listenAddrs []net.Addr, ) featureMgr, err := feature.NewManager(feature.Config{ - NoTLVOnion: cfg.ProtocolOptions.LegacyOnion(), - NoStaticRemoteKey: cfg.ProtocolOptions.NoStaticRemoteKey(), - NoAnchors: cfg.ProtocolOptions.NoAnchorCommitments(), - NoWumbo: !cfg.ProtocolOptions.Wumbo(), + NoTLVOnion: cfg.ProtocolOptions.LegacyOnion(), + NoStaticRemoteKey: cfg.ProtocolOptions.NoStaticRemoteKey(), + NoAnchors: cfg.ProtocolOptions.NoAnchorCommitments(), + NoWumbo: !cfg.ProtocolOptions.Wumbo(), + NoScriptEnforcementLease: cfg.ProtocolOptions.NoScriptEnforcementLease(), }) if err != nil { return nil, err From 067f335e11ddfc8ea79e738c5b12660363ce1b46 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 28 Jul 2021 15:15:42 -0700 Subject: [PATCH 14/29] lnwire: add LeaseExpiry custom record for Open+AcceptChannel --- lnwire/accept_channel.go | 19 +++++++++-- lnwire/lnwire_test.go | 10 ++++-- lnwire/open_channel.go | 19 +++++++++-- lnwire/typed_lease_expiry.go | 52 +++++++++++++++++++++++++++++++ lnwire/typed_lease_expiry_test.go | 25 +++++++++++++++ 5 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 lnwire/typed_lease_expiry.go create mode 100644 lnwire/typed_lease_expiry_test.go diff --git a/lnwire/accept_channel.go b/lnwire/accept_channel.go index 3cac6ca9e25..ac8f447b524 100644 --- a/lnwire/accept_channel.go +++ b/lnwire/accept_channel.go @@ -98,6 +98,12 @@ type AcceptChannel struct { // open. ChannelType *ChannelType + // LeaseExpiry represents the absolute expiration height of a channel + // lease. This is a custom TLV record that will only apply when a leased + // channel is being opened using the script enforced lease commitment + // type. + LeaseExpiry *LeaseExpiry + // ExtraData is the set of data that was appended to this message to // fill out the full maximum transport message size. These fields can // be used to specify optional data such as custom TLV fields. @@ -124,6 +130,9 @@ func (a *AcceptChannel) Encode(w io.Writer, pver uint32) error { if a.ChannelType != nil { recordProducers = append(recordProducers, a.ChannelType) } + if a.LeaseExpiry != nil { + recordProducers = append(recordProducers, a.LeaseExpiry) + } err := EncodeMessageExtraData(&a.ExtraData, recordProducers...) if err != nil { return err @@ -185,9 +194,12 @@ func (a *AcceptChannel) Decode(r io.Reader, pver uint32) error { // Next we'll parse out the set of known records, keeping the raw tlv // bytes untouched to ensure we don't drop any bytes erroneously. - var chanType ChannelType + var ( + chanType ChannelType + leaseExpiry LeaseExpiry + ) typeMap, err := tlvRecords.ExtractRecords( - &a.UpfrontShutdownScript, &chanType, + &a.UpfrontShutdownScript, &chanType, &leaseExpiry, ) if err != nil { return err @@ -197,6 +209,9 @@ func (a *AcceptChannel) Decode(r io.Reader, pver uint32) error { if val, ok := typeMap[ChannelTypeRecordType]; ok && val == nil { a.ChannelType = &chanType } + if val, ok := typeMap[LeaseExpiryRecordType]; ok && val == nil { + a.LeaseExpiry = &leaseExpiry + } a.ExtraData = tlvRecords diff --git a/lnwire/lnwire_test.go b/lnwire/lnwire_test.go index e54afe8072c..43cfe5e1eb7 100644 --- a/lnwire/lnwire_test.go +++ b/lnwire/lnwire_test.go @@ -360,7 +360,7 @@ func TestLightningWireProtocol(t *testing.T) { return } - // 1/2 chance empty upfront shutdown script. + // 1/2 chance empty TLV records. if r.Intn(2) == 0 { req.UpfrontShutdownScript, err = randDeliveryAddress(r) if err != nil { @@ -370,6 +370,9 @@ func TestLightningWireProtocol(t *testing.T) { req.ChannelType = new(ChannelType) *req.ChannelType = ChannelType(*randRawFeatureVector(r)) + + req.LeaseExpiry = new(LeaseExpiry) + *req.LeaseExpiry = LeaseExpiry(1337) } else { req.UpfrontShutdownScript = []byte{} } @@ -429,7 +432,7 @@ func TestLightningWireProtocol(t *testing.T) { return } - // 1/2 chance empty upfront shutdown script. + // 1/2 chance empty TLV records. if r.Intn(2) == 0 { req.UpfrontShutdownScript, err = randDeliveryAddress(r) if err != nil { @@ -439,6 +442,9 @@ func TestLightningWireProtocol(t *testing.T) { req.ChannelType = new(ChannelType) *req.ChannelType = ChannelType(*randRawFeatureVector(r)) + + req.LeaseExpiry = new(LeaseExpiry) + *req.LeaseExpiry = LeaseExpiry(1337) } else { req.UpfrontShutdownScript = []byte{} } diff --git a/lnwire/open_channel.go b/lnwire/open_channel.go index dca6a8b1c05..d237584167c 100644 --- a/lnwire/open_channel.go +++ b/lnwire/open_channel.go @@ -134,6 +134,12 @@ type OpenChannel struct { // open. ChannelType *ChannelType + // LeaseExpiry represents the absolute expiration height of a channel + // lease. This is a custom TLV record that will only apply when a leased + // channel is being opened using the script enforced lease commitment + // type. + LeaseExpiry *LeaseExpiry + // ExtraData is the set of data that was appended to this message to // fill out the full maximum transport message size. These fields can // be used to specify optional data such as custom TLV fields. @@ -160,6 +166,9 @@ func (o *OpenChannel) Encode(w io.Writer, pver uint32) error { if o.ChannelType != nil { recordProducers = append(recordProducers, o.ChannelType) } + if o.LeaseExpiry != nil { + recordProducers = append(recordProducers, o.LeaseExpiry) + } err := EncodeMessageExtraData(&o.ExtraData, recordProducers...) if err != nil { return err @@ -229,9 +238,12 @@ func (o *OpenChannel) Decode(r io.Reader, pver uint32) error { // Next we'll parse out the set of known records, keeping the raw tlv // bytes untouched to ensure we don't drop any bytes erroneously. - var chanType ChannelType + var ( + chanType ChannelType + leaseExpiry LeaseExpiry + ) typeMap, err := tlvRecords.ExtractRecords( - &o.UpfrontShutdownScript, &chanType, + &o.UpfrontShutdownScript, &chanType, &leaseExpiry, ) if err != nil { return err @@ -241,6 +253,9 @@ func (o *OpenChannel) Decode(r io.Reader, pver uint32) error { if val, ok := typeMap[ChannelTypeRecordType]; ok && val == nil { o.ChannelType = &chanType } + if val, ok := typeMap[LeaseExpiryRecordType]; ok && val == nil { + o.LeaseExpiry = &leaseExpiry + } o.ExtraData = tlvRecords diff --git a/lnwire/typed_lease_expiry.go b/lnwire/typed_lease_expiry.go new file mode 100644 index 00000000000..d1a5609c088 --- /dev/null +++ b/lnwire/typed_lease_expiry.go @@ -0,0 +1,52 @@ +package lnwire + +import ( + "io" + + "github.com/lightningnetwork/lnd/tlv" +) + +const ( + // LeaseExpiryType is the type of the experimental record used to + // communicate the expiration of a channel lease throughout the channel + // funding process. + // + // TODO: Decide on actual TLV type. Custom records start at 2^16. + LeaseExpiryRecordType tlv.Type = 1 << 16 +) + +// LeaseExpiry represents the absolute expiration height of a channel lease. All +// outputs that pay directly to the channel initiator are locked until this +// height is reached. +type LeaseExpiry uint32 + +// Record returns a TLV record that can be used to encode/decode the LeaseExpiry +// type from a given TLV stream. +func (l *LeaseExpiry) Record() tlv.Record { + return tlv.MakeStaticRecord( + LeaseExpiryRecordType, l, 4, leaseExpiryEncoder, leaseExpiryDecoder, + ) +} + +// leaseExpiryEncoder is a custom TLV encoder for the LeaseExpiry record. +func leaseExpiryEncoder(w io.Writer, val interface{}, buf *[8]byte) error { + if v, ok := val.(*LeaseExpiry); ok { + return tlv.EUint32T(w, uint32(*v), buf) + } + + return tlv.NewTypeForEncodingErr(val, "lnwire.LeaseExpiry") +} + +// leaseExpiryDecoder is a custom TLV decoder for the LeaseExpiry record. +func leaseExpiryDecoder(r io.Reader, val interface{}, buf *[8]byte, l uint64) error { + if v, ok := val.(*LeaseExpiry); ok { + var leaseExpiry uint32 + if err := tlv.DUint32(r, &leaseExpiry, buf, l); err != nil { + return err + } + *v = LeaseExpiry(leaseExpiry) + return nil + } + + return tlv.NewTypeForEncodingErr(val, "lnwire.LeaseExpiry") +} diff --git a/lnwire/typed_lease_expiry_test.go b/lnwire/typed_lease_expiry_test.go new file mode 100644 index 00000000000..d5f797b200b --- /dev/null +++ b/lnwire/typed_lease_expiry_test.go @@ -0,0 +1,25 @@ +package lnwire + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +// TestChannelTypeEncodeDecode tests that we're able to properly encode and +// decode channel types within TLV streams. +func TestLeaseExpiryEncodeDecode(t *testing.T) { + t.Parallel() + + leaseExpiry := LeaseExpiry(1337) + + var extraData ExtraOpaqueData + require.NoError(t, extraData.PackRecords(&leaseExpiry)) + + var leaseExpiry2 LeaseExpiry + tlvs, err := extraData.ExtractRecords(&leaseExpiry2) + require.NoError(t, err) + + require.Contains(t, tlvs, LeaseExpiryRecordType) + require.Equal(t, leaseExpiry, leaseExpiry2) +} From 9b05627158907b06b0596d81912a2529e777f537 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 14 Jul 2021 16:30:19 -0700 Subject: [PATCH 15/29] channeldb: add new ChannelType bit for script enforced leased channels --- channeldb/channel.go | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/channeldb/channel.go b/channeldb/channel.go index 7414c59273d..f85dafd5b00 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -257,6 +257,11 @@ const ( // ZeroHtlcTxFeeBit indicates that the channel should use zero-fee // second-level HTLC transactions. ZeroHtlcTxFeeBit ChannelType = 1 << 5 + + // LeaseExpirationBit indicates that the channel has been leased for a + // period of time, constraining every output that pays to the channel + // initiator with an additional CLTV of the lease maturity. + LeaseExpirationBit ChannelType = 1 << 6 ) // IsSingleFunder returns true if the channel type if one of the known single @@ -301,6 +306,11 @@ func (c ChannelType) IsFrozen() bool { return c&FrozenBit == FrozenBit } +// HasLeaseExpiration returns true if the channel originated from a lease. +func (c ChannelType) HasLeaseExpiration() bool { + return c&LeaseExpirationBit == LeaseExpirationBit +} + // ChannelConstraints represents a set of constraints meant to allow a node to // limit their exposure, enact flow control and ensure that all HTLCs are // economically relevant. This struct will be mirrored for both sides of the @@ -1363,7 +1373,7 @@ func putOpenChannel(chanBucket kvdb.RwBucket, channel *OpenChannel) error { // Next, if this is a frozen channel, we'll add in the axillary // information we need to store. - if channel.ChanType.IsFrozen() { + if channel.ChanType.IsFrozen() || channel.ChanType.HasLeaseExpiration() { err := storeThawHeight( chanBucket, channel.ThawHeight, ) @@ -1404,7 +1414,7 @@ func fetchOpenChannel(chanBucket kvdb.RBucket, // Next, if this is a frozen channel, we'll add in the axillary // information we need to store. - if channel.ChanType.IsFrozen() { + if channel.ChanType.IsFrozen() || channel.ChanType.HasLeaseExpiration() { thawHeight, err := fetchThawHeight(chanBucket) if err != nil { return nil, fmt.Errorf("unable to store thaw "+ @@ -2871,7 +2881,7 @@ func (c *OpenChannel) CloseChannel(summary *ChannelCloseSummary, // We'll also remove the channel from the frozen channel bucket // if we need to. - if c.ChanType.IsFrozen() { + if c.ChanType.IsFrozen() || c.ChanType.HasLeaseExpiration() { err := deleteThawHeight(chanBucket) if err != nil { return err @@ -3071,13 +3081,14 @@ func (c *OpenChannel) RemoteRevocationStore() (shachain.Store, error) { // channel is not frozen, then 0 is returned. func (c *OpenChannel) AbsoluteThawHeight() (uint32, error) { // Only frozen channels have a thaw height. - if !c.ChanType.IsFrozen() { + if !c.ChanType.IsFrozen() && !c.ChanType.HasLeaseExpiration() { return 0, nil } - // If the channel's thaw height is below the absolute threshold, then - // it's interpreted as a relative height to the chain's current height. - if c.ThawHeight < AbsoluteThawHeightThreshold { + // If the channel has the frozen bit set and it's thaw height is below + // the absolute threshold, then it's interpreted as a relative height to + // the chain's current height. + if c.ChanType.IsFrozen() && c.ThawHeight < AbsoluteThawHeightThreshold { // We'll only known of the channel's short ID once it's // confirmed. if c.IsPending { @@ -3086,6 +3097,7 @@ func (c *OpenChannel) AbsoluteThawHeight() (uint32, error) { } return c.ShortChannelID.BlockHeight + c.ThawHeight, nil } + return c.ThawHeight, nil } From 5c46a9fc6512d378655d8bdb34ceea7530c2c94a Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 14 Jul 2021 16:29:29 -0700 Subject: [PATCH 16/29] funding+lnwallet: support funding new script enforced leased channels --- funding/commitment_type_negotiation.go | 17 +++++++ funding/manager.go | 55 +++++++++++++++++++-- lnwallet/reservation.go | 68 ++++++++++++++++++++++---- lnwallet/wallet.go | 2 +- 4 files changed, 128 insertions(+), 14 deletions(-) diff --git a/funding/commitment_type_negotiation.go b/funding/commitment_type_negotiation.go index e66dc78b290..091c6fcbb63 100644 --- a/funding/commitment_type_negotiation.go +++ b/funding/commitment_type_negotiation.go @@ -50,6 +50,23 @@ func explicitNegotiateCommitmentType(channelType lnwire.ChannelType, channelFeatures := lnwire.RawFeatureVector(channelType) switch { + // Lease script enforcement + anchors zero fee + static remote key + // features only. + case channelFeatures.OnlyContains( + lnwire.ScriptEnforcedLeaseRequired, + lnwire.AnchorsZeroFeeHtlcTxRequired, + lnwire.StaticRemoteKeyRequired, + ): + if !hasFeatures( + local, remote, + lnwire.ScriptEnforcedLeaseOptional, + lnwire.AnchorsZeroFeeHtlcTxOptional, + lnwire.StaticRemoteKeyOptional, + ) { + return 0, errUnsupportedChannelType + } + return lnwallet.CommitmentTypeScriptEnforcedLease, nil + // Anchors zero fee + static remote key features only. case channelFeatures.OnlyContains( lnwire.AnchorsZeroFeeHtlcTxRequired, diff --git a/funding/manager.go b/funding/manager.go index f600390440d..4eda6ae5436 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -1374,6 +1374,28 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer, } reservation.SetOurUpfrontShutdown(shutdown) + // If a script enforced channel lease is being proposed, we'll need to + // validate its custom TLV records. + if commitType == lnwallet.CommitmentTypeScriptEnforcedLease { + if msg.LeaseExpiry == nil { + err := errors.New("missing lease expiry") + f.failFundingFlow(peer, msg.PendingChannelID, err) + return + } + + // If we had a shim registered for this channel prior to + // receiving its corresponding OpenChannel message, then we'll + // validate the proposed LeaseExpiry against what was registered + // in our shim. + if reservation.LeaseExpiry() != 0 { + if uint32(*msg.LeaseExpiry) != reservation.LeaseExpiry() { + err := errors.New("lease expiry mismatch") + f.failFundingFlow(peer, msg.PendingChannelID, err) + return + } + } + } + log.Infof("Requiring %v confirmations for pendingChan(%x): "+ "amt=%v, push_amt=%v, committype=%v, upfrontShutdown=%x", numConfsReq, msg.PendingChannelID, amt, msg.PushAmount, @@ -1497,6 +1519,7 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer, FirstCommitmentPoint: ourContribution.FirstCommitmentPoint, UpfrontShutdownScript: ourContribution.UpfrontShutdown, ChannelType: msg.ChannelType, + LeaseExpiry: msg.LeaseExpiry, } if err := peer.SendMessage(true, &fundingAccept); err != nil { @@ -1528,11 +1551,12 @@ func (f *Manager) handleFundingAccept(peer lnpeer.Peer, log.Infof("Recv'd fundingResponse for pending_id(%x)", pendingChanID[:]) - // We'll want to quickly check that ChannelType echoed by the channel - // request recipient matches what we proposed. + // Perform some basic validation of any custom TLV records included. // // TODO: Return errors as funding.Error to give context to remote peer? if resCtx.channelType != nil { + // We'll want to quickly check that the ChannelType echoed by + // the channel request recipient matches what we proposed. if msg.ChannelType == nil { err := errors.New("explicit channel type not echoed back") f.failFundingFlow(peer, msg.PendingChannelID, err) @@ -1545,6 +1569,21 @@ func (f *Manager) handleFundingAccept(peer lnpeer.Peer, f.failFundingFlow(peer, msg.PendingChannelID, err) return } + + // We'll want to do the same with the LeaseExpiry if one should + // be set. + if resCtx.reservation.LeaseExpiry() != 0 { + if msg.LeaseExpiry == nil { + err := errors.New("lease expiry not echoed back") + f.failFundingFlow(peer, msg.PendingChannelID, err) + return + } + if uint32(*msg.LeaseExpiry) != resCtx.reservation.LeaseExpiry() { + err := errors.New("lease expiry mismatch") + f.failFundingFlow(peer, msg.PendingChannelID, err) + return + } + } } else if msg.ChannelType != nil { err := errors.New("received unexpected channel type") f.failFundingFlow(peer, msg.PendingChannelID, err) @@ -3206,9 +3245,8 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) { // For anchor channels cap the initial commit fee rate at our defined // maximum. - if commitType == lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx && + if commitType.HasAnchors() && commitFeePerKw > f.cfg.MaxAnchorsCommitFeeRate { - commitFeePerKw = f.cfg.MaxAnchorsCommitFeeRate } @@ -3305,6 +3343,14 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) { // remote party. chanReserve := f.cfg.RequiredRemoteChanReserve(capacity, ourDustLimit) + // When opening a script enforced channel lease, include the required + // expiry TLV record in our proposal. + var leaseExpiry *lnwire.LeaseExpiry + if commitType == lnwallet.CommitmentTypeScriptEnforcedLease { + leaseExpiry = new(lnwire.LeaseExpiry) + *leaseExpiry = lnwire.LeaseExpiry(reservation.LeaseExpiry()) + } + log.Infof("Starting funding workflow with %v for pending_id(%x), "+ "committype=%v", msg.Peer.Address(), chanID, commitType) @@ -3329,6 +3375,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) { ChannelFlags: channelFlags, UpfrontShutdownScript: shutdown, ChannelType: msg.ChannelType, + LeaseExpiry: leaseExpiry, } if err := msg.Peer.SendMessage(true, &fundingOpen); err != nil { e := fmt.Errorf("unable to send funding request message: %v", diff --git a/lnwallet/reservation.go b/lnwallet/reservation.go index 2b24178c44d..8ea4be4955e 100644 --- a/lnwallet/reservation.go +++ b/lnwallet/reservation.go @@ -1,6 +1,7 @@ package lnwallet import ( + "errors" "net" "sync" @@ -34,8 +35,40 @@ const ( // requires second-level HTLC transactions to be signed using a // zero-fee. CommitmentTypeAnchorsZeroFeeHtlcTx + + // CommitmentTypeScriptEnforcedLease is a commitment type that builds + // upon CommitmentTypeTweakless and CommitmentTypeAnchorsZeroFeeHtlcTx, + // which in addition requires a CLTV clause to spend outputs paying to + // the channel initiator. This is intended for use on leased channels to + // guarantee that the channel initiator has no incentives to close a + // leased channel before its maturity date. + CommitmentTypeScriptEnforcedLease ) +// HasStaticRemoteKey returns whether the commitment type supports remote +// outputs backed by static keys. +func (c CommitmentType) HasStaticRemoteKey() bool { + switch c { + case CommitmentTypeTweakless, + CommitmentTypeAnchorsZeroFeeHtlcTx, + CommitmentTypeScriptEnforcedLease: + return true + default: + return false + } +} + +// HasAnchors returns whether the commitment type supports anchor outputs. +func (c CommitmentType) HasAnchors() bool { + switch c { + case CommitmentTypeAnchorsZeroFeeHtlcTx, + CommitmentTypeScriptEnforcedLease: + return true + default: + return false + } +} + // String returns the name of the CommitmentType. func (c CommitmentType) String() string { switch c { @@ -45,6 +78,8 @@ func (c CommitmentType) String() string { return "tweakless" case CommitmentTypeAnchorsZeroFeeHtlcTx: return "anchors-zero-fee-second-level" + case CommitmentTypeScriptEnforcedLease: + return "script-enforced-lease" default: return "invalid" } @@ -188,8 +223,8 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, // Based on the channel type, we determine the initial commit weight // and fee. commitWeight := int64(input.CommitWeight) - if commitType == CommitmentTypeAnchorsZeroFeeHtlcTx { - commitWeight = input.AnchorCommitWeight + if commitType.HasAnchors() { + commitWeight = int64(input.AnchorCommitWeight) } commitFee := commitFeePerKw.FeeForWeight(commitWeight) @@ -201,7 +236,7 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, // The total fee paid by the initiator will be the commitment fee in // addition to the two anchor outputs. feeMSat := lnwire.NewMSatFromSatoshis(commitFee) - if commitType == CommitmentTypeAnchorsZeroFeeHtlcTx { + if commitType.HasAnchors() { feeMSat += 2 * lnwire.NewMSatFromSatoshis(anchorSize) } @@ -285,8 +320,7 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, if ourBalance == 0 || theirBalance == 0 || pushMSat != 0 { // Both the tweakless type and the anchor type is tweakless, // hence set the bit. - if commitType == CommitmentTypeTweakless || - commitType == CommitmentTypeAnchorsZeroFeeHtlcTx { + if commitType.HasStaticRemoteKey() { chanType |= channeldb.SingleFunderTweaklessBit } else { chanType |= channeldb.SingleFunderBit @@ -322,14 +356,20 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, // We are adding anchor outputs to our commitment. We only support this // in combination with zero-fee second-levels HTLCs. - if commitType == CommitmentTypeAnchorsZeroFeeHtlcTx { + if commitType.HasAnchors() { chanType |= channeldb.AnchorOutputsBit chanType |= channeldb.ZeroHtlcTxFeeBit } - // If the channel is meant to be frozen, then we'll set the frozen bit - // now so once the channel is open, it can be interpreted properly. - if thawHeight != 0 { + // Set the appropriate LeaseExpiration/Frozen bit based on the + // reservation parameters. + if commitType == CommitmentTypeScriptEnforcedLease { + if thawHeight == 0 { + return nil, errors.New("missing absolute expiration " + + "for script enforced lease commitment type") + } + chanType |= channeldb.LeaseExpirationBit + } else if thawHeight > 0 { chanType |= channeldb.FrozenBit } @@ -684,6 +724,16 @@ func (r *ChannelReservation) Capacity() btcutil.Amount { return r.partialState.Capacity } +// LeaseExpiry returns the absolute expiration height for a leased channel using +// the script enforced commitment type. A zero value is returned when the +// channel is not using a script enforced lease commitment type. +func (r *ChannelReservation) LeaseExpiry() uint32 { + if !r.partialState.ChanType.HasLeaseExpiration() { + return 0 + } + return r.partialState.ThawHeight +} + // Cancel abandons this channel reservation. This method should be called in // the scenario that communications with the counterparty break down. Upon // cancellation, all resources previously reserved for this pending payment diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index 1b1b40b6d77..820bc83cfb3 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -794,7 +794,7 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg // funding tx ready, so this will always pass. We'll do another check // when the PSBT has been verified. isPublic := req.Flags&lnwire.FFAnnounceChannel != 0 - hasAnchors := req.CommitType == CommitmentTypeAnchorsZeroFeeHtlcTx + hasAnchors := req.CommitType.HasAnchors() err = l.enforceNewReservedValue(fundingIntent, isPublic, hasAnchors) if err != nil { fundingIntent.Cancel() From aa58449867dea62c2ff8ace1867054c073210046 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Tue, 13 Jul 2021 16:20:24 -0700 Subject: [PATCH 17/29] input: add scripts for new script enforced lease commitment type The new commitment type consists of adding an additional CLTV requirement to guarantee a leased channel's expiration on any commitment and HTLC outputs that pay directly to the channel initiator. --- input/script_utils.go | 166 +++++++++++ input/script_utils_test.go | 589 +++++++++++++++++++++++++++++++++++++ 2 files changed, 755 insertions(+) diff --git a/input/script_utils.go b/input/script_utils.go index 7ce6fff53ee..f94af5f8340 100644 --- a/input/script_utils.go +++ b/input/script_utils.go @@ -726,6 +726,78 @@ func SecondLevelHtlcScript(revocationKey, delayKey *btcec.PublicKey, return builder.Script() } +// LeaseSecondLevelHtlcScript is the uniform script that's used as the output for +// the second-level HTLC transactions. The second level transaction acts as a +// sort of covenant, ensuring that a 2-of-2 multi-sig output can only be +// spent in a particular way, and to a particular output. +// +// Possible Input Scripts: +// * To revoke an HTLC output that has been transitioned to the claim+delay +// state: +// * 1 +// +// * To claim an HTLC output, either with a pre-image or due to a timeout: +// * 0 +// +// OP_IF +// +// OP_ELSE +// +// OP_CHECKLOCKTIMEVERIFY +// OP_DROP +// +// OP_CHECKSEQUENCEVERIFY +// OP_DROP +// +// OP_ENDIF +// OP_CHECKSIG +func LeaseSecondLevelHtlcScript(revocationKey, delayKey *btcec.PublicKey, + csvDelay, cltvExpiry uint32) ([]byte, error) { + + builder := txscript.NewScriptBuilder() + + // If this is the revocation clause for this script is to be executed, + // the spender will push a 1, forcing us to hit the true clause of this + // if statement. + builder.AddOp(txscript.OP_IF) + + // If this this is the revocation case, then we'll push the revocation + // public key on the stack. + builder.AddData(revocationKey.SerializeCompressed()) + + // Otherwise, this is either the sender or receiver of the HTLC + // attempting to claim the HTLC output. + builder.AddOp(txscript.OP_ELSE) + + // The channel initiator always has the additional channel lease + // expiration constraint for outputs that pay to them which must be + // satisfied. + builder.AddInt64(int64(cltvExpiry)) + builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY) + builder.AddOp(txscript.OP_DROP) + + // In order to give the other party time to execute the revocation + // clause above, we require a relative timeout to pass before the + // output can be spent. + builder.AddInt64(int64(csvDelay)) + builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY) + builder.AddOp(txscript.OP_DROP) + + // If the relative timelock passes, then we'll add the delay key to the + // stack to ensure that we properly authenticate the spending party. + builder.AddData(delayKey.SerializeCompressed()) + + // Close out the if statement. + builder.AddOp(txscript.OP_ENDIF) + + // In either case, we'll ensure that only either the party possessing + // the revocation private key, or the delay private key is able to + // spend this output. + builder.AddOp(txscript.OP_CHECKSIG) + + return builder.Script() +} + // HtlcSpendSuccess spends a second-level HTLC output. This function is to be // used by the sender of an HTLC to claim the output after a relative timeout // or the receiver of the HTLC to claim on-chain with the pre-image. @@ -889,6 +961,66 @@ func CommitScriptToSelf(csvTimeout uint32, selfKey, revokeKey *btcec.PublicKey) return builder.Script() } +// LeaseCommitScriptToSelf constructs the public key script for the output on the +// commitment transaction paying to the "owner" of said commitment transaction. +// If the other party learns of the preimage to the revocation hash, then they +// can claim all the settled funds in the channel, plus the unsettled funds. +// +// Possible Input Scripts: +// REVOKE: 1 +// SENDRSWEEP: +// +// Output Script: +// OP_IF +// +// OP_ELSE +// OP_CHECKLOCKTIMEVERIFY OP_DROP +// OP_CHECKSEQUENCEVERIFY OP_DROP +// +// OP_ENDIF +// OP_CHECKSIG +func LeaseCommitScriptToSelf(selfKey, revokeKey *btcec.PublicKey, + csvTimeout, leaseExpiry uint32) ([]byte, error) { + + // This script is spendable under two conditions: either the + // 'csvTimeout' has passed and we can redeem our funds, or they can + // produce a valid signature with the revocation public key. The + // revocation public key will *only* be known to the other party if we + // have divulged the revocation hash, allowing them to homomorphically + // derive the proper private key which corresponds to the revoke public + // key. + builder := txscript.NewScriptBuilder() + + builder.AddOp(txscript.OP_IF) + + // If a valid signature using the revocation key is presented, then + // allow an immediate spend provided the proper signature. + builder.AddData(revokeKey.SerializeCompressed()) + + builder.AddOp(txscript.OP_ELSE) + + // Otherwise, we can re-claim our funds after once the CLTV lease + // maturity has been met, along with the CSV delay of 'csvTimeout' + // timeout blocks, and a valid signature. + builder.AddInt64(int64(leaseExpiry)) + builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY) + builder.AddOp(txscript.OP_DROP) + + builder.AddInt64(int64(csvTimeout)) + builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY) + builder.AddOp(txscript.OP_DROP) + + builder.AddData(selfKey.SerializeCompressed()) + + builder.AddOp(txscript.OP_ENDIF) + + // Finally, we'll validate the signature against the public key that's + // left on the top of the stack. + builder.AddOp(txscript.OP_CHECKSIG) + + return builder.Script() +} + // CommitSpendTimeout constructs a valid witness allowing the owner of a // particular commitment transaction to spend the output returning settled // funds back to themselves after a relative block timeout. In order to @@ -1033,6 +1165,40 @@ func CommitScriptToRemoteConfirmed(key *btcec.PublicKey) ([]byte, error) { return builder.Script() } +// LeaseCommitScriptToRemoteConfirmed constructs the script for the output on +// the commitment transaction paying to the remote party of said commitment +// transaction. The money can only be spend after one confirmation. +// +// Possible Input Scripts: +// SWEEP: +// +// Output Script: +// OP_CHECKSIGVERIFY +// OP_CHECKLOCKTIMEVERIFY OP_DROP +// 1 OP_CHECKSEQUENCEVERIFY +func LeaseCommitScriptToRemoteConfirmed(key *btcec.PublicKey, + leaseExpiry uint32) ([]byte, error) { + + builder := txscript.NewScriptBuilder() + + // Only the given key can spend the output. + builder.AddData(key.SerializeCompressed()) + builder.AddOp(txscript.OP_CHECKSIGVERIFY) + + // The channel initiator always has the additional channel lease + // expiration constraint for outputs that pay to them which must be + // satisfied. + builder.AddInt64(int64(leaseExpiry)) + builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY) + builder.AddOp(txscript.OP_DROP) + + // Check that it has one confirmation. + builder.AddOp(txscript.OP_1) + builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY) + + return builder.Script() +} + // CommitSpendToRemoteConfirmed constructs a valid witness allowing a node to // spend their settled output on the counterparty's commitment transaction when // it has one confirmetion. This is used for the anchor channel type. The diff --git a/input/script_utils_test.go b/input/script_utils_test.go index 5978d3eec18..e72c8c68c6f 100644 --- a/input/script_utils_test.go +++ b/input/script_utils_test.go @@ -13,6 +13,7 @@ import ( "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" "github.com/lightningnetwork/lnd/keychain" + "github.com/stretchr/testify/require" ) // assertEngineExecution executes the VM returned by the newEngine closure, @@ -1184,6 +1185,452 @@ func TestSecondLevelHtlcSpends(t *testing.T) { } } +// TestLeaseSecondLevelHtlcSpends tests all the possible redemption clauses from +// the HTLC success and timeout covenant transactions in script enforced lease +// commitments. +func TestLeaseSecondLevelHtlcSpends(t *testing.T) { + t.Parallel() + + // We'll start be creating a creating a 2BTC HTLC. + const htlcAmt = btcutil.Amount(2 * 10e8) + + // In all of our scenarios, the CSV timeout to claim a self output will + // be 5 blocks. + const claimDelay = 5 + + // In all of our scenarios, the CLTV timelock will expire at height + // 1337. + const leaseExpiry = 1337 + + // First we'll set up some initial key state for Alice and Bob that + // will be used in the scripts we created below. + aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes( + btcec.S256(), testWalletPrivKey, + ) + bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes( + btcec.S256(), bobsPrivKey, + ) + + revokePreimage := testHdSeed.CloneBytes() + commitSecret, commitPoint := btcec.PrivKeyFromBytes( + btcec.S256(), revokePreimage, + ) + + // As we're modeling this as Bob sweeping the HTLC on-chain from his + // commitment transaction after a period of time, we'll be using a + // revocation key derived from Alice's base point and his secret. + revocationKey := DeriveRevocationPubkey(aliceKeyPub, commitPoint) + + // Next, craft a fake HTLC outpoint that we'll use to generate the + // sweeping transaction using. + txid, err := chainhash.NewHash(testHdSeed.CloneBytes()) + require.NoError(t, err) + htlcOutPoint := &wire.OutPoint{ + Hash: *txid, + Index: 0, + } + sweepTx := wire.NewMsgTx(2) + sweepTx.AddTxIn(wire.NewTxIn(htlcOutPoint, nil, nil)) + sweepTx.AddTxOut( + &wire.TxOut{ + PkScript: []byte("doesn't matter"), + Value: 1 * 10e8, + }, + ) + sweepTxSigHashes := txscript.NewTxSigHashes(sweepTx) + + // The delay key will be crafted using Bob's public key as the output + // we created will be spending from Alice's commitment transaction. + delayKey := TweakPubKey(bobKeyPub, commitPoint) + + // The commit tweak will be required in order for Bob to derive the + // proper key need to spend the output. + commitTweak := SingleTweakBytes(commitPoint, bobKeyPub) + + // Finally we'll generate the HTLC script itself that we'll be spending + // from. The revocation clause can be claimed by Alice, while Bob can + // sweep the output after a particular delay. + htlcWitnessScript, err := LeaseSecondLevelHtlcScript( + revocationKey, delayKey, claimDelay, leaseExpiry, + ) + require.NoError(t, err) + htlcPkScript, err := WitnessScriptHash(htlcWitnessScript) + require.NoError(t, err) + + htlcOutput := &wire.TxOut{ + PkScript: htlcPkScript, + Value: int64(htlcAmt), + } + + // Finally, we'll create mock signers for both of them based on their + // private keys. This test simplifies a bit and uses the same key as + // the base point for all scripts and derivations. + bobSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{bobKeyPriv}} + aliceSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{aliceKeyPriv}} + + testCases := []struct { + witness func() wire.TxWitness + valid bool + }{ + { + // Sender of the HTLC attempts to activate the + // revocation clause, but uses the wrong key (fails to + // use the double tweak in this case). + makeWitnessTestCase(t, func() (wire.TxWitness, error) { + signDesc := &SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + PubKey: aliceKeyPub, + }, + WitnessScript: htlcWitnessScript, + Output: htlcOutput, + HashType: txscript.SigHashAll, + SigHashes: sweepTxSigHashes, + InputIndex: 0, + } + + return HtlcSpendRevoke( + aliceSigner, signDesc, sweepTx, + ) + }), + false, + }, + { + // Sender of HTLC activates the revocation clause. + makeWitnessTestCase(t, func() (wire.TxWitness, error) { + signDesc := &SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + PubKey: aliceKeyPub, + }, + DoubleTweak: commitSecret, + WitnessScript: htlcWitnessScript, + Output: htlcOutput, + HashType: txscript.SigHashAll, + SigHashes: sweepTxSigHashes, + InputIndex: 0, + } + + return HtlcSpendRevoke( + aliceSigner, signDesc, sweepTx, + ) + }), + true, + }, + { + // Receiver of the HTLC attempts to sweep, but tries to + // do so pre-maturely with a smaller CSV delay (2 + // blocks instead of 5 blocks), even after the CLTV + // timelock expires. + makeWitnessTestCase(t, func() (wire.TxWitness, error) { + sweepTx.LockTime = leaseExpiry + signDesc := &SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + PubKey: bobKeyPub, + }, + SingleTweak: commitTweak, + WitnessScript: htlcWitnessScript, + Output: htlcOutput, + HashType: txscript.SigHashAll, + SigHashes: sweepTxSigHashes, + InputIndex: 0, + } + + return HtlcSpendSuccess( + bobSigner, signDesc, sweepTx, claimDelay-3, + ) + }), + false, + }, + { + // Receiver of the HTLC sweeps with the proper CSV delay + // and after the CLTV timelock expires, but uses the + // wrong key (leaves off the single tweak). + makeWitnessTestCase(t, func() (wire.TxWitness, error) { + sweepTx.LockTime = leaseExpiry + signDesc := &SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + PubKey: bobKeyPub, + }, + WitnessScript: htlcWitnessScript, + Output: htlcOutput, + HashType: txscript.SigHashAll, + SigHashes: sweepTxSigHashes, + InputIndex: 0, + } + + return HtlcSpendSuccess( + bobSigner, signDesc, sweepTx, claimDelay, + ) + }), + false, + }, + { + // Receiver of the HTLC sweeps with the proper CSV + // delay, and the correct key, but before the CTLV + // timelock expires. + makeWitnessTestCase(t, func() (wire.TxWitness, error) { + sweepTx.LockTime = 0 + signDesc := &SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + PubKey: bobKeyPub, + }, + SingleTweak: commitTweak, + WitnessScript: htlcWitnessScript, + Output: htlcOutput, + HashType: txscript.SigHashAll, + SigHashes: sweepTxSigHashes, + InputIndex: 0, + } + + return HtlcSpendSuccess( + bobSigner, signDesc, sweepTx, claimDelay, + ) + }), + false, + }, + { + // Receiver of the HTLC sweeps with the proper CSV + // delay, and the correct key after the CTLV timelock + // expires. + makeWitnessTestCase(t, func() (wire.TxWitness, error) { + sweepTx.LockTime = leaseExpiry + signDesc := &SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + PubKey: bobKeyPub, + }, + SingleTweak: commitTweak, + WitnessScript: htlcWitnessScript, + Output: htlcOutput, + HashType: txscript.SigHashAll, + SigHashes: sweepTxSigHashes, + InputIndex: 0, + } + + return HtlcSpendSuccess( + bobSigner, signDesc, sweepTx, claimDelay, + ) + }), + true, + }, + } + + for i, testCase := range testCases { + sweepTx.TxIn[0].Witness = testCase.witness() + + newEngine := func() (*txscript.Engine, error) { + return txscript.NewEngine(htlcPkScript, + sweepTx, 0, txscript.StandardVerifyFlags, nil, + nil, int64(htlcAmt)) + } + + assertEngineExecution(t, i, testCase.valid, newEngine) + } +} + +// TestLeaseCommmitSpendToSelf tests all the possible redemption clauses from +// the to_self output in a script enforced lease commitment transaction. +func TestLeaseCommmitSpendToSelf(t *testing.T) { + t.Parallel() + + const ( + outputVal = btcutil.Amount(2 * 10e8) + csvDelay = 5 + leaseExpiry = 1337 + ) + + // Set up some initial key state for Alice and Bob that will be used in + // the scripts we created below. + aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes( + btcec.S256(), testWalletPrivKey, + ) + bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes( + btcec.S256(), bobsPrivKey, + ) + + // We'll have Bob take the revocation path in some cases. + revokePreimage := testHdSeed.CloneBytes() + commitSecret, commitPoint := btcec.PrivKeyFromBytes( + btcec.S256(), revokePreimage, + ) + revocationKey := DeriveRevocationPubkey(bobKeyPub, commitPoint) + + // Construct the script enforced lease to_self commitment transaction + // output. + txid, err := chainhash.NewHash(testHdSeed.CloneBytes()) + require.NoError(t, err) + commitOut := &wire.OutPoint{ + Hash: *txid, + Index: 0, + } + commitScript, err := LeaseCommitScriptToSelf( + aliceKeyPub, revocationKey, csvDelay, leaseExpiry, + ) + require.NoError(t, err) + commitPkScript, err := WitnessScriptHash(commitScript) + require.NoError(t, err) + + commitOutput := &wire.TxOut{ + PkScript: commitPkScript, + Value: int64(outputVal), + } + + sweepTx := wire.NewMsgTx(2) + sweepTx.AddTxIn(wire.NewTxIn(commitOut, nil, nil)) + sweepTx.AddTxOut( + &wire.TxOut{ + PkScript: []byte("doesn't matter"), + Value: 1 * 10e8, + }, + ) + + // Create mock signers for both parties to ensure signatures are + // produced and verified correctly. + aliceSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{aliceKeyPriv}} + bobSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{bobKeyPriv}} + + testCases := []struct { + witness func() wire.TxWitness + valid bool + }{ + { + // Bob can spend with his revocation key, but not + // without the proper tweak. + makeWitnessTestCase(t, func() (wire.TxWitness, error) { + sweepTxSigHashes := txscript.NewTxSigHashes(sweepTx) + signDesc := &SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + PubKey: bobKeyPub, + }, + WitnessScript: commitScript, + Output: commitOutput, + HashType: txscript.SigHashAll, + SigHashes: sweepTxSigHashes, + InputIndex: 0, + } + + return CommitSpendRevoke( + bobSigner, signDesc, sweepTx, + ) + }), + false, + }, + { + // Bob can spend with his revocation key with the proper + // tweak. + makeWitnessTestCase(t, func() (wire.TxWitness, error) { + sweepTxSigHashes := txscript.NewTxSigHashes(sweepTx) + signDesc := &SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + PubKey: bobKeyPub, + }, + DoubleTweak: commitSecret, + WitnessScript: commitScript, + Output: commitOutput, + HashType: txscript.SigHashAll, + SigHashes: sweepTxSigHashes, + InputIndex: 0, + } + + return CommitSpendRevoke( + bobSigner, signDesc, sweepTx, + ) + }), + true, + }, + { + // Alice cannot spend with the proper key before the CSV + // delay and after the CLTV timelock has expired. + makeWitnessTestCase(t, func() (wire.TxWitness, error) { + sweepTx.LockTime = leaseExpiry + sweepTx.TxIn[0].Sequence = LockTimeToSequence( + false, csvDelay/2, + ) + sweepTxSigHashes := txscript.NewTxSigHashes(sweepTx) + signDesc := &SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + PubKey: aliceKeyPub, + }, + DoubleTweak: commitSecret, + WitnessScript: commitScript, + Output: commitOutput, + HashType: txscript.SigHashAll, + SigHashes: sweepTxSigHashes, + InputIndex: 0, + } + + return CommitSpendTimeout( + aliceSigner, signDesc, sweepTx, + ) + }), + false, + }, + { + // Alice cannot spend with the proper key after the CSV + // delay and before the CLTV timelock has expired. + makeWitnessTestCase(t, func() (wire.TxWitness, error) { + sweepTx.LockTime = 0 + sweepTx.TxIn[0].Sequence = LockTimeToSequence( + false, csvDelay, + ) + sweepTxSigHashes := txscript.NewTxSigHashes(sweepTx) + signDesc := &SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + PubKey: aliceKeyPub, + }, + DoubleTweak: commitSecret, + WitnessScript: commitScript, + Output: commitOutput, + HashType: txscript.SigHashAll, + SigHashes: sweepTxSigHashes, + InputIndex: 0, + } + + return CommitSpendTimeout( + aliceSigner, signDesc, sweepTx, + ) + }), + false, + }, + { + // Alice can spend with the proper key after the CSV + // delay and CLTV timelock have expired. + makeWitnessTestCase(t, func() (wire.TxWitness, error) { + sweepTx.LockTime = leaseExpiry + sweepTx.TxIn[0].Sequence = LockTimeToSequence( + false, csvDelay, + ) + sweepTxSigHashes := txscript.NewTxSigHashes(sweepTx) + signDesc := &SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + PubKey: aliceKeyPub, + }, + WitnessScript: commitScript, + Output: commitOutput, + HashType: txscript.SigHashAll, + SigHashes: sweepTxSigHashes, + InputIndex: 0, + } + + return CommitSpendTimeout( + aliceSigner, signDesc, sweepTx, + ) + }), + true, + }, + } + + for i, testCase := range testCases { + sweepTx.TxIn[0].Witness = testCase.witness() + + newEngine := func() (*txscript.Engine, error) { + return txscript.NewEngine(commitPkScript, + sweepTx, 0, txscript.StandardVerifyFlags, nil, + nil, int64(outputVal)) + } + + assertEngineExecution(t, i, testCase.valid, newEngine) + } +} + // TestCommitSpendToRemoteConfirmed checks that the delayed version of the // to_remote version can only be spent by the owner, and after one // confirmation. @@ -1291,6 +1738,148 @@ func TestCommitSpendToRemoteConfirmed(t *testing.T) { } } +// TestLeaseCommitSpendToRemoteConfirmed checks that the delayed version of the +// to_remote version can only be spent by the owner, after one confirmation, and +// after the lease expiration has been met. +func TestLeaseCommitSpendToRemoteConfirmed(t *testing.T) { + t.Parallel() + + const ( + outputVal = btcutil.Amount(2 * 10e8) + leaseExpiry = 1337 + ) + + aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes( + btcec.S256(), testWalletPrivKey, + ) + + txid, err := chainhash.NewHash(testHdSeed.CloneBytes()) + require.NoError(t, err) + commitOut := &wire.OutPoint{ + Hash: *txid, + Index: 0, + } + commitScript, err := LeaseCommitScriptToRemoteConfirmed( + aliceKeyPub, leaseExpiry, + ) + require.NoError(t, err) + commitPkScript, err := WitnessScriptHash(commitScript) + require.NoError(t, err) + + commitOutput := &wire.TxOut{ + PkScript: commitPkScript, + Value: int64(outputVal), + } + + sweepTx := wire.NewMsgTx(2) + sweepTx.AddTxIn(wire.NewTxIn(commitOut, nil, nil)) + sweepTx.AddTxOut( + &wire.TxOut{ + PkScript: []byte("doesn't matter"), + Value: 1 * 10e8, + }, + ) + + aliceSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{aliceKeyPriv}} + + testCases := []struct { + witness func() wire.TxWitness + valid bool + }{ + { + // Alice can spend after the CSV delay and CLTV timelock + // has passed. + makeWitnessTestCase(t, func() (wire.TxWitness, error) { + sweepTx.LockTime = leaseExpiry + sweepTx.TxIn[0].Sequence = LockTimeToSequence( + false, 1, + ) + sweepTxSigHashes := txscript.NewTxSigHashes(sweepTx) + + signDesc := &SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + PubKey: aliceKeyPub, + }, + WitnessScript: commitScript, + Output: commitOutput, + HashType: txscript.SigHashAll, + SigHashes: sweepTxSigHashes, + InputIndex: 0, + } + + return CommitSpendToRemoteConfirmed( + aliceSigner, signDesc, sweepTx, + ) + }), + true, + }, + { + // Alice cannot spend output without sequence set, even + // once the CLTV timelock has expired. + makeWitnessTestCase(t, func() (wire.TxWitness, error) { + sweepTx.LockTime = leaseExpiry + sweepTx.TxIn[0].Sequence = wire.MaxTxInSequenceNum + sweepTxSigHashes := txscript.NewTxSigHashes(sweepTx) + + signDesc := &SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + PubKey: aliceKeyPub, + }, + WitnessScript: commitScript, + Output: commitOutput, + HashType: txscript.SigHashAll, + SigHashes: sweepTxSigHashes, + InputIndex: 0, + } + + return CommitSpendToRemoteConfirmed( + aliceSigner, signDesc, sweepTx, + ) + }), + false, + }, + { + // Alice cannot spend output without sequence or + // locktime set. + makeWitnessTestCase(t, func() (wire.TxWitness, error) { + sweepTx.LockTime = 0 + sweepTx.TxIn[0].Sequence = wire.MaxTxInSequenceNum + sweepTxSigHashes := txscript.NewTxSigHashes(sweepTx) + + signDesc := &SignDescriptor{ + KeyDesc: keychain.KeyDescriptor{ + PubKey: aliceKeyPub, + }, + WitnessScript: commitScript, + Output: commitOutput, + HashType: txscript.SigHashAll, + SigHashes: sweepTxSigHashes, + InputIndex: 0, + } + + return CommitSpendToRemoteConfirmed( + aliceSigner, signDesc, sweepTx, + ) + }), + false, + }, + } + + for i, testCase := range testCases { + sweepTx.TxIn[0].Witness = testCase.witness() + + newEngine := func() (*txscript.Engine, error) { + return txscript.NewEngine( + commitPkScript, sweepTx, 0, + txscript.StandardVerifyFlags, nil, nil, + int64(outputVal), + ) + } + + assertEngineExecution(t, i, testCase.valid, newEngine) + } +} + // TestSpendAnchor checks that we can spend the anchors using the various spend // paths. func TestSpendAnchor(t *testing.T) { From 5d4d6ce4d8cbe8df5171b110b42a3f02e46c2f90 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Tue, 13 Jul 2021 16:40:23 -0700 Subject: [PATCH 18/29] input: add witness gen and weight estimates for new commitment type This witness generators and weight estimates added only apply for the new script-enforced leased channel commitment type. --- input/size.go | 11 +++++++ input/witnessgen.go | 76 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/input/size.go b/input/size.go index 6ad55d87a5c..b923f815b8b 100644 --- a/input/size.go +++ b/input/size.go @@ -258,6 +258,17 @@ const ( // - OP_CHECKSIG: 1 byte ToLocalScriptSize = 1 + 1 + 33 + 1 + 1 + 4 + 1 + 1 + 1 + 33 + 1 + 1 + // LeaseWitnessScriptSizeOverhead represents the size overhead in bytes + // of the witness scripts used within script enforced lease commitments. + // This overhead results from the additional CLTV clause required to + // spend. + // + // - OP_DATA: 1 byte + // - lease_expiry: 4 bytes + // - OP_CHECKLOCKTIMEVERIFY: 1 byte + // - OP_DROP: 1 byte + LeaseWitnessScriptSizeOverhead = 1 + 4 + 1 + 1 + // ToLocalTimeoutWitnessSize 156 bytes // - number_of_witness_elements: 1 byte // - local_delay_sig_length: 1 byte diff --git a/input/witnessgen.go b/input/witnessgen.go index f5017083c8f..7d0f7fa7313 100644 --- a/input/witnessgen.go +++ b/input/witnessgen.go @@ -145,6 +145,36 @@ const ( // CommitmentAnchor is a witness that allows us to spend our anchor on // the commitment transaction. CommitmentAnchor StandardWitnessType = 14 + + // LeaseCommitmentTimeLock is a witness that allows us to spend our + // output on our local commitment transaction after a relative and + // absolute lock-time lockout as part of the script enforced lease + // commitment type. + LeaseCommitmentTimeLock StandardWitnessType = 17 + + // LeaseCommitmentToRemoteConfirmed is a witness that allows us to spend + // our output on the counterparty's commitment transaction after a + // confirmation and absolute locktime as part of the script enforced + // lease commitment type. + LeaseCommitmentToRemoteConfirmed StandardWitnessType = 18 + + // LeaseHtlcOfferedTimeoutSecondLevel is a witness that allows us to + // sweep an HTLC output that we extended to a party, but was never + // fulfilled. This HTLC output isn't directly on the commitment + // transaction, but is the result of a confirmed second-level HTLC + // transaction. As a result, we can only spend this after a CSV delay + // and CLTV locktime as part of the script enforced lease commitment + // type. + LeaseHtlcOfferedTimeoutSecondLevel StandardWitnessType = 19 + + // LeaseHtlcAcceptedSuccessSecondLevel is a witness that allows us to + // sweep an HTLC output that was offered to us, and for which we have a + // payment preimage. This HTLC output isn't directly on our commitment + // transaction, but is the result of confirmed second-level HTLC + // transaction. As a result, we can only spend this after a CSV delay + // and CLTV locktime as part of the script enforced lease commitment + // type. + LeaseHtlcAcceptedSuccessSecondLevel StandardWitnessType = 20 ) // String returns a human readable version of the target WitnessType. @@ -203,6 +233,18 @@ func (wt StandardWitnessType) String() string { case NestedWitnessKeyHash: return "NestedWitnessKeyHash" + case LeaseCommitmentTimeLock: + return "LeaseCommitmentTimeLock" + + case LeaseCommitmentToRemoteConfirmed: + return "LeaseCommitmentToRemoteConfirmed" + + case LeaseHtlcOfferedTimeoutSecondLevel: + return "LeaseHtlcOfferedTimeoutSecondLevel" + + case LeaseHtlcAcceptedSuccessSecondLevel: + return "LeaseHtlcAcceptedSuccessSecondLevel" + default: return fmt.Sprintf("Unknown WitnessType: %v", uint32(wt)) } @@ -225,7 +267,7 @@ func (wt StandardWitnessType) WitnessGenerator(signer Signer, desc.InputIndex = inputIndex switch wt { - case CommitmentTimeLock: + case CommitmentTimeLock, LeaseCommitmentTimeLock: witness, err := CommitSpendTimeout(signer, desc, tx) if err != nil { return nil, err @@ -235,7 +277,7 @@ func (wt StandardWitnessType) WitnessGenerator(signer Signer, Witness: witness, }, nil - case CommitmentToRemoteConfirmed: + case CommitmentToRemoteConfirmed, LeaseCommitmentToRemoteConfirmed: witness, err := CommitSpendToRemoteConfirmed( signer, desc, tx, ) @@ -307,17 +349,11 @@ func (wt StandardWitnessType) WitnessGenerator(signer Signer, Witness: witness, }, nil - case HtlcOfferedTimeoutSecondLevel: - witness, err := HtlcSecondLevelSpend(signer, desc, tx) - if err != nil { - return nil, err - } - - return &Script{ - Witness: witness, - }, nil + case HtlcOfferedTimeoutSecondLevel, + LeaseHtlcOfferedTimeoutSecondLevel, + HtlcAcceptedSuccessSecondLevel, + LeaseHtlcAcceptedSuccessSecondLevel: - case HtlcAcceptedSuccessSecondLevel: witness, err := HtlcSecondLevelSpend(signer, desc, tx) if err != nil { return nil, err @@ -382,10 +418,18 @@ func (wt StandardWitnessType) SizeUpperBound() (int, bool, error) { // to us. case CommitmentTimeLock: return ToLocalTimeoutWitnessSize, false, nil + case LeaseCommitmentTimeLock: + size := ToLocalTimeoutWitnessSize + + LeaseWitnessScriptSizeOverhead + return size, false, nil // 1 CSV time locked output to us on remote commitment. case CommitmentToRemoteConfirmed: return ToRemoteConfirmedWitnessSize, false, nil + case LeaseCommitmentToRemoteConfirmed: + size := ToRemoteConfirmedWitnessSize + + LeaseWitnessScriptSizeOverhead + return size, false, nil // Anchor output on the commitment transaction. case CommitmentAnchor: @@ -396,6 +440,10 @@ func (wt StandardWitnessType) SizeUpperBound() (int, bool, error) { // sweep. case HtlcOfferedTimeoutSecondLevel: return ToLocalTimeoutWitnessSize, false, nil + case LeaseHtlcOfferedTimeoutSecondLevel: + size := ToLocalTimeoutWitnessSize + + LeaseWitnessScriptSizeOverhead + return size, false, nil // Input to the outgoing HTLC second layer timeout transaction. case HtlcOfferedTimeoutSecondLevelInputConfirmed: @@ -406,6 +454,10 @@ func (wt StandardWitnessType) SizeUpperBound() (int, bool, error) { // sweep. case HtlcAcceptedSuccessSecondLevel: return ToLocalTimeoutWitnessSize, false, nil + case LeaseHtlcAcceptedSuccessSecondLevel: + size := ToLocalTimeoutWitnessSize + + LeaseWitnessScriptSizeOverhead + return size, false, nil // Input to the incoming second-layer HTLC success transaction. case HtlcAcceptedSuccessSecondLevelInputConfirmed: From 4e2d599b095b2fb7b83a6ab807e95e1e5b00921b Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 14 Jul 2021 17:06:13 -0700 Subject: [PATCH 19/29] lnwallet: coalesce different supported output scripts into single method --- contractcourt/chain_watcher.go | 11 ++---- lnwallet/channel.go | 50 ++++++++--------------- lnwallet/commitment.go | 72 +++++++++++++++++++++++++++------- lnwallet/transactions.go | 25 +++++------- 4 files changed, 88 insertions(+), 70 deletions(-) diff --git a/contractcourt/chain_watcher.go b/contractcourt/chain_watcher.go index ebe7e5fd98a..2bf8990ebc2 100644 --- a/contractcourt/chain_watcher.go +++ b/contractcourt/chain_watcher.go @@ -372,19 +372,14 @@ func (c *chainWatcher) handleUnknownLocalState( // Next, we'll derive our script that includes the revocation base for // the remote party allowing them to claim this output before the CSV // delay if we breach. - localScript, err := input.CommitScriptToSelf( - uint32(c.cfg.chanState.LocalChanCfg.CsvDelay), + localScript, err := lnwallet.CommitScriptToSelf( commitKeyRing.ToLocalKey, commitKeyRing.RevocationKey, + uint32(c.cfg.chanState.LocalChanCfg.CsvDelay), ) if err != nil { return false, err } - localPkScript, err := input.WitnessScriptHash(localScript) - if err != nil { - return false, err - } - // With all our scripts assembled, we'll examine the outputs of the // commitment transaction to determine if this is a local force close // or not. @@ -393,7 +388,7 @@ func (c *chainWatcher) handleUnknownLocalState( pkScript := output.PkScript switch { - case bytes.Equal(localPkScript, pkScript): + case bytes.Equal(localScript.PkScript, pkScript): ourCommit = true case bytes.Equal(remoteScript.PkScript, pkScript): diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 56991bd3f04..d533a169564 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -2315,16 +2315,12 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, // number so we can have the proper witness script to sign and include // within the final witness. theirDelay := uint32(chanState.RemoteChanCfg.CsvDelay) - theirPkScript, err := input.CommitScriptToSelf( - theirDelay, keyRing.ToLocalKey, keyRing.RevocationKey, + theirScript, err := CommitScriptToSelf( + keyRing.ToLocalKey, keyRing.RevocationKey, theirDelay, ) if err != nil { return nil, err } - theirWitnessHash, err := input.WitnessScriptHash(theirPkScript) - if err != nil { - return nil, err - } // Since it is the remote breach we are reconstructing, the output going // to us will be a to-remote script with our local params. @@ -2347,7 +2343,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, switch { case bytes.Equal(txOut.PkScript, ourScript.PkScript): ourOutpoint.Index = uint32(i) - case bytes.Equal(txOut.PkScript, theirWitnessHash): + case bytes.Equal(txOut.PkScript, theirScript.PkScript): theirOutpoint.Index = uint32(i) } } @@ -2385,9 +2381,9 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, theirSignDesc = &input.SignDescriptor{ KeyDesc: chanState.LocalChanCfg.RevocationBasePoint, DoubleTweak: commitmentSecret, - WitnessScript: theirPkScript, + WitnessScript: theirScript.WitnessScript, Output: &wire.TxOut{ - PkScript: theirWitnessHash, + PkScript: theirScript.PkScript, Value: int64(theirAmt), }, HashType: txscript.SigHashAll, @@ -2413,7 +2409,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, // as we'll need it if we're revoking an HTLC output on the // remote commitment transaction, and *they* go to the second // level. - secondLevelWitnessScript, err := input.SecondLevelHtlcScript( + secondLevelScript, err := SecondLevelHtlcScript( keyRing.RevocationKey, keyRing.ToLocalKey, theirDelay, ) if err != nil { @@ -2448,7 +2444,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, Hash: commitHash, Index: uint32(htlc.OutputIndex), }, - SecondLevelWitnessScript: secondLevelWitnessScript, + SecondLevelWitnessScript: secondLevelScript.WitnessScript, IsIncoming: htlc.Incoming, }) } @@ -5789,16 +5785,12 @@ func newOutgoingHtlcResolution(signer input.Signer, // Finally, we'll generate the script output that the timeout // transaction creates so we can generate the signDesc required to // complete the claim process after a delay period. - htlcSweepScript, err := input.SecondLevelHtlcScript( + htlcSweepScript, err := SecondLevelHtlcScript( keyRing.RevocationKey, keyRing.ToLocalKey, csvDelay, ) if err != nil { return nil, err } - htlcSweepScriptHash, err := input.WitnessScriptHash(htlcSweepScript) - if err != nil { - return nil, err - } localDelayTweak := input.SingleTweakBytes( keyRing.CommitPoint, localChanCfg.DelayBasePoint.PubKey, @@ -5815,9 +5807,9 @@ func newOutgoingHtlcResolution(signer input.Signer, SweepSignDesc: input.SignDescriptor{ KeyDesc: localChanCfg.DelayBasePoint, SingleTweak: localDelayTweak, - WitnessScript: htlcSweepScript, + WitnessScript: htlcSweepScript.WitnessScript, Output: &wire.TxOut{ - PkScript: htlcSweepScriptHash, + PkScript: htlcSweepScript.PkScript, Value: int64(secondLevelOutputAmt), }, HashType: txscript.SigHashAll, @@ -5928,16 +5920,12 @@ func newIncomingHtlcResolution(signer input.Signer, // Finally, we'll generate the script that the second-level transaction // creates so we can generate the proper signDesc to sweep it after the // CSV delay has passed. - htlcSweepScript, err := input.SecondLevelHtlcScript( + htlcSweepScript, err := SecondLevelHtlcScript( keyRing.RevocationKey, keyRing.ToLocalKey, csvDelay, ) if err != nil { return nil, err } - htlcSweepScriptHash, err := input.WitnessScriptHash(htlcSweepScript) - if err != nil { - return nil, err - } localDelayTweak := input.SingleTweakBytes( keyRing.CommitPoint, localChanCfg.DelayBasePoint.PubKey, @@ -5953,9 +5941,9 @@ func newIncomingHtlcResolution(signer input.Signer, SweepSignDesc: input.SignDescriptor{ KeyDesc: localChanCfg.DelayBasePoint, SingleTweak: localDelayTweak, - WitnessScript: htlcSweepScript, + WitnessScript: htlcSweepScript.WitnessScript, Output: &wire.TxOut{ - PkScript: htlcSweepScriptHash, + PkScript: htlcSweepScript.PkScript, Value: int64(secondLevelOutputAmt), }, HashType: txscript.SigHashAll, @@ -6178,16 +6166,12 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, &chanState.LocalChanCfg, &chanState.RemoteChanCfg, ) - selfScript, err := input.CommitScriptToSelf( - csvTimeout, keyRing.ToLocalKey, keyRing.RevocationKey, + toLocalScript, err := CommitScriptToSelf( + keyRing.ToLocalKey, keyRing.RevocationKey, csvTimeout, ) if err != nil { return nil, err } - payToUsScriptHash, err := input.WitnessScriptHash(selfScript) - if err != nil { - return nil, err - } // Locate the output index of the delayed commitment output back to us. // We'll return the details of this output to the caller so they can @@ -6197,7 +6181,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, delayOut *wire.TxOut ) for i, txOut := range commitTx.TxOut { - if !bytes.Equal(payToUsScriptHash, txOut.PkScript) { + if !bytes.Equal(toLocalScript.PkScript, txOut.PkScript) { continue } @@ -6223,7 +6207,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, SelfOutputSignDesc: input.SignDescriptor{ KeyDesc: chanState.LocalChanCfg.DelayBasePoint, SingleTweak: keyRing.LocalCommitKeyTweak, - WitnessScript: selfScript, + WitnessScript: toLocalScript.WitnessScript, Output: &wire.TxOut{ PkScript: delayOut.PkScript, Value: localBalance, diff --git a/lnwallet/commitment.go b/lnwallet/commitment.go index 96960f9dd11..379bfbdf5a6 100644 --- a/lnwallet/commitment.go +++ b/lnwallet/commitment.go @@ -190,10 +190,34 @@ type ScriptInfo struct { WitnessScript []byte } -// CommitScriptToRemote creates the script that will pay to the non-owner of -// the commitment transaction, adding a delay to the script based on the -// channel type. The second return value is the CSV deleay of the output -// script, what must be satisfied in order to spend the output. +// CommitScriptToSelf constructs the public key script for the output on the +// commitment transaction paying to the "owner" of said commitment transaction. +// If the other party learns of the preimage to the revocation hash, then they +// can claim all the settled funds in the channel, plus the unsettled funds. +func CommitScriptToSelf(selfKey, revokeKey *btcec.PublicKey, csvDelay uint32) ( + *ScriptInfo, error) { + + toLocalRedeemScript, err := input.CommitScriptToSelf( + csvDelay, selfKey, revokeKey, + ) + if err != nil { + return nil, err + } + + toLocalScriptHash, err := input.WitnessScriptHash(toLocalRedeemScript) + if err != nil { + return nil, err + } + + return &ScriptInfo{ + PkScript: toLocalScriptHash, + WitnessScript: toLocalRedeemScript, + }, nil +} + +// CommitScriptToRemote derives the appropriate to_remote script based on the +// channel's commitment type. The second return value is the CSV delay of the +// output script, what must be satisfied in order to spend the output. func CommitScriptToRemote(chanType channeldb.ChannelType, key *btcec.PublicKey) (*ScriptInfo, uint32, error) { @@ -268,6 +292,32 @@ func HtlcSecondLevelInputSequence(chanType channeldb.ChannelType) uint32 { return 0 } +// SecondLevelHtlcScript derives the appropriate second level HTLC script based +// on the channel's commitment type. It is the uniform script that's used as the +// output for the second-level HTLC transactions. The second level transaction +// act as a sort of covenant, ensuring that a 2-of-2 multi-sig output can only +// be spent in a particular way, and to a particular output. +func SecondLevelHtlcScript(revocationKey, delayKey *btcec.PublicKey, + csvDelay uint32) (*ScriptInfo, error) { + + witnessScript, err := input.SecondLevelHtlcScript( + revocationKey, delayKey, csvDelay, + ) + if err != nil { + return nil, err + } + + pkScript, err := input.WitnessScriptHash(witnessScript) + if err != nil { + return nil, err + } + + return &ScriptInfo{ + PkScript: pkScript, + WitnessScript: witnessScript, + }, nil +} + // CommitWeight returns the base commitment weight before adding HTLCs. func CommitWeight(chanType channeldb.ChannelType) int64 { // If this commitment has anchors, it will be slightly heavier. @@ -622,15 +672,9 @@ func CreateCommitTx(chanType channeldb.ChannelType, // output after a relative block delay, or the remote node can claim // the funds with the revocation key if we broadcast a revoked // commitment transaction. - toLocalRedeemScript, err := input.CommitScriptToSelf( - uint32(localChanCfg.CsvDelay), keyRing.ToLocalKey, - keyRing.RevocationKey, - ) - if err != nil { - return nil, err - } - toLocalScriptHash, err := input.WitnessScriptHash( - toLocalRedeemScript, + toLocalScript, err := CommitScriptToSelf( + keyRing.ToLocalKey, keyRing.RevocationKey, + uint32(localChanCfg.CsvDelay), ) if err != nil { return nil, err @@ -654,7 +698,7 @@ func CreateCommitTx(chanType channeldb.ChannelType, localOutput := amountToLocal >= localChanCfg.DustLimit if localOutput { commitTx.AddTxOut(&wire.TxOut{ - PkScript: toLocalScriptHash, + PkScript: toLocalScript.PkScript, Value: int64(amountToLocal), }) } diff --git a/lnwallet/transactions.go b/lnwallet/transactions.go index 861fdebcea1..2072deb6a60 100644 --- a/lnwallet/transactions.go +++ b/lnwallet/transactions.go @@ -8,7 +8,6 @@ import ( "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" "github.com/lightningnetwork/lnd/channeldb" - "github.com/lightningnetwork/lnd/input" ) const ( @@ -65,12 +64,9 @@ func CreateHtlcSuccessTx(chanType channeldb.ChannelType, // Next, we'll generate the script used as the output for all second // level HTLC which forces a covenant w.r.t what can be done with all // HTLC outputs. - witnessScript, err := input.SecondLevelHtlcScript(revocationKey, delayKey, - csvDelay) - if err != nil { - return nil, err - } - pkScript, err := input.WitnessScriptHash(witnessScript) + script, err := SecondLevelHtlcScript( + revocationKey, delayKey, csvDelay, + ) if err != nil { return nil, err } @@ -79,7 +75,7 @@ func CreateHtlcSuccessTx(chanType channeldb.ChannelType, // required fees), paying to the timeout script. successTx.AddTxOut(&wire.TxOut{ Value: int64(htlcAmt), - PkScript: pkScript, + PkScript: script.PkScript, }) return successTx, nil @@ -117,6 +113,8 @@ func CreateHtlcTimeoutTx(chanType channeldb.ChannelType, // sequence number based on the channel type. txin := &wire.TxIn{ PreviousOutPoint: htlcOutput, + SignatureScript: []byte{}, + Witness: [][]byte{}, Sequence: HtlcSecondLevelInputSequence(chanType), } timeoutTx.AddTxIn(txin) @@ -124,12 +122,9 @@ func CreateHtlcTimeoutTx(chanType channeldb.ChannelType, // Next, we'll generate the script used as the output for all second // level HTLC which forces a covenant w.r.t what can be done with all // HTLC outputs. - witnessScript, err := input.SecondLevelHtlcScript(revocationKey, delayKey, - csvDelay) - if err != nil { - return nil, err - } - pkScript, err := input.WitnessScriptHash(witnessScript) + script, err := SecondLevelHtlcScript( + revocationKey, delayKey, csvDelay, + ) if err != nil { return nil, err } @@ -138,7 +133,7 @@ func CreateHtlcTimeoutTx(chanType channeldb.ChannelType, // required fees), paying to the regular second level HTLC script. timeoutTx.AddTxOut(&wire.TxOut{ Value: int64(htlcAmt), - PkScript: pkScript, + PkScript: script.PkScript, }) return timeoutTx, nil From b9aed844fffed6a6d5f28d17f8fe6bf7d3ed1880 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 14 Jul 2021 17:16:13 -0700 Subject: [PATCH 20/29] lnwallet: support transactions and scripts for new commitment type This commit modifies the channel state machine to be able to derive the proper commitment and second-level HTLC output scripts required by the new script-enforced leased channel commitment type. --- breacharbiter_test.go | 1 + contractcourt/chain_watcher.go | 10 ++- htlcswitch/test_utils.go | 6 +- input/size_test.go | 6 +- lnwallet/channel.go | 118 +++++++++++++++++++---------- lnwallet/commitment.go | 133 ++++++++++++++++++++++++--------- lnwallet/test_utils.go | 7 +- lnwallet/transactions.go | 17 +++-- lnwallet/transactions_test.go | 4 +- lnwallet/wallet.go | 20 ++++- peer/test_utils.go | 6 +- 11 files changed, 230 insertions(+), 98 deletions(-) diff --git a/breacharbiter_test.go b/breacharbiter_test.go index 422e6be7e29..57612626c57 100644 --- a/breacharbiter_test.go +++ b/breacharbiter_test.go @@ -2296,6 +2296,7 @@ func createInitChannels(revocationWindow int) (*lnwallet.LightningChannel, *lnwa aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns( channelBal, channelBal, &aliceCfg, &bobCfg, aliceCommitPoint, bobCommitPoint, *fundingTxIn, channeldb.SingleFunderTweaklessBit, + false, 0, ) if err != nil { return nil, nil, nil, err diff --git a/contractcourt/chain_watcher.go b/contractcourt/chain_watcher.go index 2bf8990ebc2..973a0ca73ff 100644 --- a/contractcourt/chain_watcher.go +++ b/contractcourt/chain_watcher.go @@ -362,8 +362,13 @@ func (c *chainWatcher) handleUnknownLocalState( // With the keys derived, we'll construct the remote script that'll be // present if they have a non-dust balance on the commitment. + var leaseExpiry uint32 + if c.cfg.chanState.ChanType.HasLeaseExpiration() { + leaseExpiry = c.cfg.chanState.ThawHeight + } remoteScript, _, err := lnwallet.CommitScriptToRemote( - c.cfg.chanState.ChanType, commitKeyRing.ToRemoteKey, + c.cfg.chanState.ChanType, c.cfg.chanState.IsInitiator, + commitKeyRing.ToRemoteKey, leaseExpiry, ) if err != nil { return false, err @@ -373,8 +378,9 @@ func (c *chainWatcher) handleUnknownLocalState( // the remote party allowing them to claim this output before the CSV // delay if we breach. localScript, err := lnwallet.CommitScriptToSelf( + c.cfg.chanState.ChanType, c.cfg.chanState.IsInitiator, commitKeyRing.ToLocalKey, commitKeyRing.RevocationKey, - uint32(c.cfg.chanState.LocalChanCfg.CsvDelay), + uint32(c.cfg.chanState.LocalChanCfg.CsvDelay), leaseExpiry, ) if err != nil { return false, err diff --git a/htlcswitch/test_utils.go b/htlcswitch/test_utils.go index cfdadd969ef..10b13324e97 100644 --- a/htlcswitch/test_utils.go +++ b/htlcswitch/test_utils.go @@ -134,6 +134,7 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte, channelCapacity := aliceAmount + bobAmount csvTimeoutAlice := uint32(5) csvTimeoutBob := uint32(4) + isAliceInitiator := true aliceConstraints := &channeldb.ChannelConstraints{ DustLimit: btcutil.Amount(200), @@ -230,6 +231,7 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte, aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns( aliceAmount, bobAmount, &aliceCfg, &bobCfg, aliceCommitPoint, bobCommitPoint, *fundingTxIn, channeldb.SingleFunderTweaklessBit, + isAliceInitiator, 0, ) if err != nil { return nil, nil, nil, err @@ -298,7 +300,7 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte, IdentityPub: aliceKeyPub, FundingOutpoint: *prevOut, ChanType: channeldb.SingleFunderTweaklessBit, - IsInitiator: true, + IsInitiator: isAliceInitiator, Capacity: channelCapacity, RemoteCurrentRevocation: bobCommitPoint, RevocationProducer: alicePreimageProducer, @@ -317,7 +319,7 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte, IdentityPub: bobKeyPub, FundingOutpoint: *prevOut, ChanType: channeldb.SingleFunderTweaklessBit, - IsInitiator: false, + IsInitiator: !isAliceInitiator, Capacity: channelCapacity, RemoteCurrentRevocation: aliceCommitPoint, RevocationProducer: bobPreimageProducer, diff --git a/input/size_test.go b/input/size_test.go index 8008ac854aa..b2d1e2bee62 100644 --- a/input/size_test.go +++ b/input/size_test.go @@ -861,8 +861,8 @@ func TestWitnessSizes(t *testing.T) { func genTimeoutTx(chanType channeldb.ChannelType) (*wire.MsgTx, error) { // Create the unsigned timeout tx. timeoutTx, err := lnwallet.CreateHtlcTimeoutTx( - chanType, testOutPoint, testAmt, testCLTVExpiry, - testCSVDelay, testPubkey, testPubkey, + chanType, false, testOutPoint, testAmt, testCLTVExpiry, + testCSVDelay, 0, testPubkey, testPubkey, ) if err != nil { return nil, err @@ -903,7 +903,7 @@ func genTimeoutTx(chanType channeldb.ChannelType) (*wire.MsgTx, error) { func genSuccessTx(chanType channeldb.ChannelType) (*wire.MsgTx, error) { // Create the unisgned success tx. successTx, err := lnwallet.CreateHtlcSuccessTx( - chanType, testOutPoint, testAmt, testCSVDelay, + chanType, false, testOutPoint, testAmt, testCSVDelay, 0, testPubkey, testPubkey, ) if err != nil { diff --git a/lnwallet/channel.go b/lnwallet/channel.go index d533a169564..8283c4d55c6 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -2315,8 +2315,14 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, // number so we can have the proper witness script to sign and include // within the final witness. theirDelay := uint32(chanState.RemoteChanCfg.CsvDelay) + isRemoteInitiator := !chanState.IsInitiator + var leaseExpiry uint32 + if chanState.ChanType.HasLeaseExpiration() { + leaseExpiry = chanState.ThawHeight + } theirScript, err := CommitScriptToSelf( - keyRing.ToLocalKey, keyRing.RevocationKey, theirDelay, + chanState.ChanType, isRemoteInitiator, keyRing.ToLocalKey, + keyRing.RevocationKey, theirDelay, leaseExpiry, ) if err != nil { return nil, err @@ -2325,7 +2331,8 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, // Since it is the remote breach we are reconstructing, the output going // to us will be a to-remote script with our local params. ourScript, ourDelay, err := CommitScriptToRemote( - chanState.ChanType, keyRing.ToRemoteKey, + chanState.ChanType, isRemoteInitiator, keyRing.ToRemoteKey, + leaseExpiry, ) if err != nil { return nil, err @@ -2410,7 +2417,9 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, // remote commitment transaction, and *they* go to the second // level. secondLevelScript, err := SecondLevelHtlcScript( + chanState.ChanType, isRemoteInitiator, keyRing.RevocationKey, keyRing.ToLocalKey, theirDelay, + leaseExpiry, ) if err != nil { return nil, err @@ -2968,8 +2977,8 @@ func processFeeUpdate(feeUpdate *PaymentDescriptor, nextHeight uint64, // signature can be submitted to the sigPool to generate all the signatures // asynchronously and in parallel. func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing, - chanType channeldb.ChannelType, - localChanCfg, remoteChanCfg *channeldb.ChannelConfig, + chanType channeldb.ChannelType, isRemoteInitiator bool, + leaseExpiry uint32, localChanCfg, remoteChanCfg *channeldb.ChannelConfig, remoteCommitView *commitment) ([]SignJob, chan struct{}, error) { txHash := remoteCommitView.txn.TxHash() @@ -3019,9 +3028,9 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing, Index: uint32(htlc.remoteOutputIndex), } sigJob.Tx, err = CreateHtlcTimeoutTx( - chanType, op, outputAmt, htlc.Timeout, - uint32(remoteChanCfg.CsvDelay), - keyRing.RevocationKey, keyRing.ToLocalKey, + chanType, isRemoteInitiator, op, outputAmt, + htlc.Timeout, uint32(remoteChanCfg.CsvDelay), + leaseExpiry, keyRing.RevocationKey, keyRing.ToLocalKey, ) if err != nil { return nil, nil, err @@ -3072,7 +3081,8 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing, Index: uint32(htlc.remoteOutputIndex), } sigJob.Tx, err = CreateHtlcSuccessTx( - chanType, op, outputAmt, uint32(remoteChanCfg.CsvDelay), + chanType, isRemoteInitiator, op, outputAmt, + uint32(remoteChanCfg.CsvDelay), leaseExpiry, keyRing.RevocationKey, keyRing.ToLocalKey, ) if err != nil { @@ -3581,10 +3591,14 @@ func (lc *LightningChannel) SignNextCommitment() (lnwire.Sig, []lnwire.Sig, []ch // need to generate signatures of each of them for the remote party's // commitment state. We do so in two phases: first we generate and // submit the set of signature jobs to the worker pool. + var leaseExpiry uint32 + if lc.channelState.ChanType.HasLeaseExpiration() { + leaseExpiry = lc.channelState.ThawHeight + } sigBatch, cancelChan, err := genRemoteHtlcSigJobs( - keyRing, lc.channelState.ChanType, - &lc.channelState.LocalChanCfg, &lc.channelState.RemoteChanCfg, - newCommitView, + keyRing, lc.channelState.ChanType, !lc.channelState.IsInitiator, + leaseExpiry, &lc.channelState.LocalChanCfg, + &lc.channelState.RemoteChanCfg, newCommitView, ) if err != nil { return sig, htlcSigs, nil, err @@ -4067,7 +4081,7 @@ func (lc *LightningChannel) computeView(view *htlcView, remoteChain bool, // directly into the pool of workers. func genHtlcSigValidationJobs(localCommitmentView *commitment, keyRing *CommitmentKeyRing, htlcSigs []lnwire.Sig, - chanType channeldb.ChannelType, + chanType channeldb.ChannelType, isLocalInitiator bool, leaseExpiry uint32, localChanCfg, remoteChanCfg *channeldb.ChannelConfig) ([]VerifyJob, error) { txHash := localCommitmentView.txn.TxHash() @@ -4116,9 +4130,10 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment, outputAmt := htlc.Amount.ToSatoshis() - htlcFee successTx, err := CreateHtlcSuccessTx( - chanType, op, outputAmt, - uint32(localChanCfg.CsvDelay), - keyRing.RevocationKey, keyRing.ToLocalKey, + chanType, isLocalInitiator, op, + outputAmt, uint32(localChanCfg.CsvDelay), + leaseExpiry, keyRing.RevocationKey, + keyRing.ToLocalKey, ) if err != nil { return nil, err @@ -4170,8 +4185,9 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment, outputAmt := htlc.Amount.ToSatoshis() - htlcFee timeoutTx, err := CreateHtlcTimeoutTx( - chanType, op, outputAmt, htlc.Timeout, - uint32(localChanCfg.CsvDelay), + chanType, isLocalInitiator, op, + outputAmt, htlc.Timeout, + uint32(localChanCfg.CsvDelay), leaseExpiry, keyRing.RevocationKey, keyRing.ToLocalKey, ) if err != nil { @@ -4385,9 +4401,14 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSig lnwire.Sig, // As an optimization, we'll generate a series of jobs for the worker // pool to verify each of the HTLc signatures presented. Once // generated, we'll submit these jobs to the worker pool. + var leaseExpiry uint32 + if lc.channelState.ChanType.HasLeaseExpiration() { + leaseExpiry = lc.channelState.ThawHeight + } verifyJobs, err := genHtlcSigValidationJobs( localCommitmentView, keyRing, htlcSigs, - lc.channelState.ChanType, &lc.channelState.LocalChanCfg, + lc.channelState.ChanType, lc.channelState.IsInitiator, + leaseExpiry, &lc.channelState.LocalChanCfg, &lc.channelState.RemoteChanCfg, ) if err != nil { @@ -5455,18 +5476,24 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si // First, we'll generate the commitment point and the revocation point // so we can re-construct the HTLC state and also our payment key. + isOurCommit := false keyRing := DeriveCommitmentKeys( - commitPoint, false, chanState.ChanType, + commitPoint, isOurCommit, chanState.ChanType, &chanState.LocalChanCfg, &chanState.RemoteChanCfg, ) // Next, we'll obtain HTLC resolutions for all the outgoing HTLC's we // had on their commitment transaction. + var leaseExpiry uint32 + if chanState.ChanType.HasLeaseExpiration() { + leaseExpiry = chanState.ThawHeight + } + isRemoteInitiator := !chanState.IsInitiator htlcResolutions, err := extractHtlcResolutions( - chainfee.SatPerKWeight(remoteCommit.FeePerKw), false, signer, - remoteCommit.Htlcs, keyRing, &chanState.LocalChanCfg, + chainfee.SatPerKWeight(remoteCommit.FeePerKw), isOurCommit, + signer, remoteCommit.Htlcs, keyRing, &chanState.LocalChanCfg, &chanState.RemoteChanCfg, commitSpend.SpendingTx, - chanState.ChanType, + chanState.ChanType, isRemoteInitiator, leaseExpiry, ) if err != nil { return nil, fmt.Errorf("unable to create htlc "+ @@ -5479,7 +5506,8 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si // locate the output index of our non-delayed output on the commitment // transaction. selfScript, maturityDelay, err := CommitScriptToRemote( - chanState.ChanType, keyRing.ToRemoteKey, + chanState.ChanType, isRemoteInitiator, keyRing.ToRemoteKey, + leaseExpiry, ) if err != nil { return nil, fmt.Errorf("unable to create self commit "+ @@ -5686,8 +5714,9 @@ type HtlcResolutions struct { func newOutgoingHtlcResolution(signer input.Signer, localChanCfg *channeldb.ChannelConfig, commitTx *wire.MsgTx, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing, - feePerKw chainfee.SatPerKWeight, csvDelay uint32, - localCommit bool, chanType channeldb.ChannelType) (*OutgoingHtlcResolution, error) { + feePerKw chainfee.SatPerKWeight, csvDelay, leaseExpiry uint32, + localCommit, isCommitFromInitiator bool, + chanType channeldb.ChannelType) (*OutgoingHtlcResolution, error) { op := wire.OutPoint{ Hash: commitTx.TxHash(), @@ -5739,8 +5768,9 @@ func newOutgoingHtlcResolution(signer input.Signer, // With the fee calculated, re-construct the second level timeout // transaction. timeoutTx, err := CreateHtlcTimeoutTx( - chanType, op, secondLevelOutputAmt, htlc.RefundTimeout, - csvDelay, keyRing.RevocationKey, keyRing.ToLocalKey, + chanType, isCommitFromInitiator, op, secondLevelOutputAmt, + htlc.RefundTimeout, csvDelay, leaseExpiry, keyRing.RevocationKey, + keyRing.ToLocalKey, ) if err != nil { return nil, err @@ -5786,7 +5816,8 @@ func newOutgoingHtlcResolution(signer input.Signer, // transaction creates so we can generate the signDesc required to // complete the claim process after a delay period. htlcSweepScript, err := SecondLevelHtlcScript( - keyRing.RevocationKey, keyRing.ToLocalKey, csvDelay, + chanType, isCommitFromInitiator, keyRing.RevocationKey, + keyRing.ToLocalKey, csvDelay, leaseExpiry, ) if err != nil { return nil, err @@ -5827,8 +5858,9 @@ func newOutgoingHtlcResolution(signer input.Signer, func newIncomingHtlcResolution(signer input.Signer, localChanCfg *channeldb.ChannelConfig, commitTx *wire.MsgTx, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing, - feePerKw chainfee.SatPerKWeight, csvDelay uint32, localCommit bool, - chanType channeldb.ChannelType) (*IncomingHtlcResolution, error) { + feePerKw chainfee.SatPerKWeight, csvDelay, leaseExpiry uint32, + localCommit, isCommitFromInitiator bool, chanType channeldb.ChannelType) ( + *IncomingHtlcResolution, error) { op := wire.OutPoint{ Hash: commitTx.TxHash(), @@ -5873,8 +5905,8 @@ func newIncomingHtlcResolution(signer input.Signer, htlcFee := HtlcSuccessFee(chanType, feePerKw) secondLevelOutputAmt := htlc.Amt.ToSatoshis() - htlcFee successTx, err := CreateHtlcSuccessTx( - chanType, op, secondLevelOutputAmt, csvDelay, - keyRing.RevocationKey, keyRing.ToLocalKey, + chanType, isCommitFromInitiator, op, secondLevelOutputAmt, + csvDelay, leaseExpiry, keyRing.RevocationKey, keyRing.ToLocalKey, ) if err != nil { return nil, err @@ -5921,7 +5953,8 @@ func newIncomingHtlcResolution(signer input.Signer, // creates so we can generate the proper signDesc to sweep it after the // CSV delay has passed. htlcSweepScript, err := SecondLevelHtlcScript( - keyRing.RevocationKey, keyRing.ToLocalKey, csvDelay, + chanType, isCommitFromInitiator, keyRing.RevocationKey, + keyRing.ToLocalKey, csvDelay, leaseExpiry, ) if err != nil { return nil, err @@ -5981,8 +6014,8 @@ func (r *OutgoingHtlcResolution) HtlcPoint() wire.OutPoint { func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, ourCommit bool, signer input.Signer, htlcs []channeldb.HTLC, keyRing *CommitmentKeyRing, localChanCfg, remoteChanCfg *channeldb.ChannelConfig, - commitTx *wire.MsgTx, chanType channeldb.ChannelType) ( - *HtlcResolutions, error) { + commitTx *wire.MsgTx, chanType channeldb.ChannelType, + isCommitFromInitiator bool, leaseExpiry uint32) (*HtlcResolutions, error) { // TODO(roasbeef): don't need to swap csv delay? dustLimit := remoteChanCfg.DustLimit @@ -6014,8 +6047,8 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, ourCommit bool, // as we can satisfy the contract. ihr, err := newIncomingHtlcResolution( signer, localChanCfg, commitTx, &htlc, - keyRing, feePerKw, uint32(csvDelay), ourCommit, - chanType, + keyRing, feePerKw, uint32(csvDelay), leaseExpiry, + ourCommit, isCommitFromInitiator, chanType, ) if err != nil { return nil, err @@ -6027,7 +6060,8 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, ourCommit bool, ohr, err := newOutgoingHtlcResolution( signer, localChanCfg, commitTx, &htlc, keyRing, - feePerKw, uint32(csvDelay), ourCommit, chanType, + feePerKw, uint32(csvDelay), leaseExpiry, ourCommit, + isCommitFromInitiator, chanType, ) if err != nil { return nil, err @@ -6166,8 +6200,13 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, &chanState.LocalChanCfg, &chanState.RemoteChanCfg, ) + var leaseExpiry uint32 + if chanState.ChanType.HasLeaseExpiration() { + leaseExpiry = chanState.ThawHeight + } toLocalScript, err := CommitScriptToSelf( - keyRing.ToLocalKey, keyRing.RevocationKey, csvTimeout, + chanState.ChanType, chanState.IsInitiator, keyRing.ToLocalKey, + keyRing.RevocationKey, csvTimeout, leaseExpiry, ) if err != nil { return nil, err @@ -6228,6 +6267,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, chainfee.SatPerKWeight(localCommit.FeePerKw), true, signer, localCommit.Htlcs, keyRing, &chanState.LocalChanCfg, &chanState.RemoteChanCfg, commitTx, chanState.ChanType, + chanState.IsInitiator, leaseExpiry, ) if err != nil { return nil, err diff --git a/lnwallet/commitment.go b/lnwallet/commitment.go index 379bfbdf5a6..03cfd224026 100644 --- a/lnwallet/commitment.go +++ b/lnwallet/commitment.go @@ -192,14 +192,31 @@ type ScriptInfo struct { // CommitScriptToSelf constructs the public key script for the output on the // commitment transaction paying to the "owner" of said commitment transaction. -// If the other party learns of the preimage to the revocation hash, then they -// can claim all the settled funds in the channel, plus the unsettled funds. -func CommitScriptToSelf(selfKey, revokeKey *btcec.PublicKey, csvDelay uint32) ( +// The `initiator` argument should correspond to the owner of the commitment +// tranasction which we are generating the to_local script for. If the other +// party learns of the preimage to the revocation hash, then they can claim all +// the settled funds in the channel, plus the unsettled funds. +func CommitScriptToSelf(chanType channeldb.ChannelType, initiator bool, + selfKey, revokeKey *btcec.PublicKey, csvDelay, leaseExpiry uint32) ( *ScriptInfo, error) { - toLocalRedeemScript, err := input.CommitScriptToSelf( - csvDelay, selfKey, revokeKey, + var ( + toLocalRedeemScript []byte + err error ) + switch { + // If we are the initiator of a leased channel, then we have an + // additional CLTV requirement in addition to the usual CSV requirement. + case initiator && chanType.HasLeaseExpiration(): + toLocalRedeemScript, err = input.LeaseCommitScriptToSelf( + selfKey, revokeKey, csvDelay, leaseExpiry, + ) + + default: + toLocalRedeemScript, err = input.CommitScriptToSelf( + csvDelay, selfKey, revokeKey, + ) + } if err != nil { return nil, err } @@ -216,14 +233,38 @@ func CommitScriptToSelf(selfKey, revokeKey *btcec.PublicKey, csvDelay uint32) ( } // CommitScriptToRemote derives the appropriate to_remote script based on the -// channel's commitment type. The second return value is the CSV delay of the -// output script, what must be satisfied in order to spend the output. -func CommitScriptToRemote(chanType channeldb.ChannelType, - key *btcec.PublicKey) (*ScriptInfo, uint32, error) { +// channel's commitment type. The `initiator` argument should correspond to the +// owner of the commitment tranasction which we are generating the to_remote +// script for. The second return value is the CSV delay of the output script, +// what must be satisfied in order to spend the output. +func CommitScriptToRemote(chanType channeldb.ChannelType, initiator bool, + key *btcec.PublicKey, leaseExpiry uint32) (*ScriptInfo, uint32, error) { + + switch { + // If we are not the initiator of a leased channel, then the remote + // party has an additional CLTV requirement in addition to the 1 block + // CSV requirement. + case chanType.HasLeaseExpiration() && !initiator: + script, err := input.LeaseCommitScriptToRemoteConfirmed( + key, leaseExpiry, + ) + if err != nil { + return nil, 0, err + } + + p2wsh, err := input.WitnessScriptHash(script) + if err != nil { + return nil, 0, err + } + + return &ScriptInfo{ + PkScript: p2wsh, + WitnessScript: script, + }, 1, nil // If this channel type has anchors, we derive the delayed to_remote // script. - if chanType.HasAnchors() { + case chanType.HasAnchors(): script, err := input.CommitScriptToRemoteConfirmed(key) if err != nil { return nil, 0, err @@ -238,20 +279,22 @@ func CommitScriptToRemote(chanType channeldb.ChannelType, PkScript: p2wsh, WitnessScript: script, }, 1, nil - } - // Otherwise the to_remote will be a simple p2wkh. - p2wkh, err := input.CommitScriptUnencumbered(key) - if err != nil { - return nil, 0, err - } + default: + // Otherwise the to_remote will be a simple p2wkh. + p2wkh, err := input.CommitScriptUnencumbered(key) + if err != nil { + return nil, 0, err + } - // Since this is a regular P2WKH, the WitnessScipt and PkScript should - // both be set to the script hash. - return &ScriptInfo{ - WitnessScript: p2wkh, - PkScript: p2wkh, - }, 0, nil + // Since this is a regular P2WKH, the WitnessScipt and PkScript + // should both be set to the script hash. + return &ScriptInfo{ + WitnessScript: p2wkh, + PkScript: p2wkh, + }, 0, nil + + } } // HtlcSigHashType returns the sighash type to use for HTLC success and timeout @@ -296,13 +339,30 @@ func HtlcSecondLevelInputSequence(chanType channeldb.ChannelType) uint32 { // on the channel's commitment type. It is the uniform script that's used as the // output for the second-level HTLC transactions. The second level transaction // act as a sort of covenant, ensuring that a 2-of-2 multi-sig output can only -// be spent in a particular way, and to a particular output. -func SecondLevelHtlcScript(revocationKey, delayKey *btcec.PublicKey, - csvDelay uint32) (*ScriptInfo, error) { +// be spent in a particular way, and to a particular output. The `initiator` +// argument should correspond to the owner of the commitment tranasction which +// we are generating the to_local script for. +func SecondLevelHtlcScript(chanType channeldb.ChannelType, initiator bool, + revocationKey, delayKey *btcec.PublicKey, + csvDelay, leaseExpiry uint32) (*ScriptInfo, error) { - witnessScript, err := input.SecondLevelHtlcScript( - revocationKey, delayKey, csvDelay, + var ( + witnessScript []byte + err error ) + switch { + // If we are the initiator of a leased channel, then we have an + // additional CLTV requirement in addition to the usual CSV requirement. + case initiator && chanType.HasLeaseExpiration(): + witnessScript, err = input.LeaseSecondLevelHtlcScript( + revocationKey, delayKey, csvDelay, leaseExpiry, + ) + + default: + witnessScript, err = input.SecondLevelHtlcScript( + revocationKey, delayKey, csvDelay, + ) + } if err != nil { return nil, err } @@ -549,19 +609,23 @@ func (cb *CommitmentBuilder) createUnsignedCommitmentTx(ourBalance, // CreateCommitTx with parameters matching the perspective, to generate // a new commitment transaction with all the latest unsettled/un-timed // out HTLCs. + var leaseExpiry uint32 + if cb.chanState.ChanType.HasLeaseExpiration() { + leaseExpiry = cb.chanState.ThawHeight + } if isOurs { commitTx, err = CreateCommitTx( cb.chanState.ChanType, fundingTxIn(cb.chanState), keyRing, &cb.chanState.LocalChanCfg, &cb.chanState.RemoteChanCfg, ourBalance.ToSatoshis(), theirBalance.ToSatoshis(), - numHTLCs, + numHTLCs, cb.chanState.IsInitiator, leaseExpiry, ) } else { commitTx, err = CreateCommitTx( cb.chanState.ChanType, fundingTxIn(cb.chanState), keyRing, &cb.chanState.RemoteChanCfg, &cb.chanState.LocalChanCfg, theirBalance.ToSatoshis(), ourBalance.ToSatoshis(), - numHTLCs, + numHTLCs, !cb.chanState.IsInitiator, leaseExpiry, ) } if err != nil { @@ -660,12 +724,13 @@ func (cb *CommitmentBuilder) createUnsignedCommitmentTx(ourBalance, // output paying to the "owner" of the commitment transaction which can be // spent after a relative block delay or revocation event, and a remote output // paying the counterparty within the channel, which can be spent immediately -// or after a delay depending on the commitment type.. +// or after a delay depending on the commitment type. The `initiator` argument +// should correspond to the owner of the commitment tranasction we are creating. func CreateCommitTx(chanType channeldb.ChannelType, fundingOutput wire.TxIn, keyRing *CommitmentKeyRing, localChanCfg, remoteChanCfg *channeldb.ChannelConfig, amountToLocal, amountToRemote btcutil.Amount, - numHTLCs int64) (*wire.MsgTx, error) { + numHTLCs int64, initiator bool, leaseExpiry uint32) (*wire.MsgTx, error) { // First, we create the script for the delayed "pay-to-self" output. // This output has 2 main redemption clauses: either we can redeem the @@ -673,8 +738,8 @@ func CreateCommitTx(chanType channeldb.ChannelType, // the funds with the revocation key if we broadcast a revoked // commitment transaction. toLocalScript, err := CommitScriptToSelf( - keyRing.ToLocalKey, keyRing.RevocationKey, - uint32(localChanCfg.CsvDelay), + chanType, initiator, keyRing.ToLocalKey, keyRing.RevocationKey, + uint32(localChanCfg.CsvDelay), leaseExpiry, ) if err != nil { return nil, err @@ -682,7 +747,7 @@ func CreateCommitTx(chanType channeldb.ChannelType, // Next, we create the script paying to the remote. toRemoteScript, _, err := CommitScriptToRemote( - chanType, keyRing.ToRemoteKey, + chanType, initiator, keyRing.ToRemoteKey, leaseExpiry, ) if err != nil { return nil, err diff --git a/lnwallet/test_utils.go b/lnwallet/test_utils.go index bd048b2c0ff..af7f538ac8c 100644 --- a/lnwallet/test_utils.go +++ b/lnwallet/test_utils.go @@ -116,6 +116,7 @@ func CreateTestChannels(chanType channeldb.ChannelType) ( bobDustLimit := btcutil.Amount(1300) csvTimeoutAlice := uint32(5) csvTimeoutBob := uint32(4) + isAliceInitiator := true prevOut := &wire.OutPoint{ Hash: chainhash.Hash(testHdSeed), @@ -220,7 +221,7 @@ func CreateTestChannels(chanType channeldb.ChannelType) ( aliceCommitTx, bobCommitTx, err := CreateCommitmentTxns( channelBal, channelBal, &aliceCfg, &bobCfg, aliceCommitPoint, - bobCommitPoint, *fundingTxIn, chanType, + bobCommitPoint, *fundingTxIn, chanType, isAliceInitiator, 0, ) if err != nil { return nil, nil, nil, err @@ -315,7 +316,7 @@ func CreateTestChannels(chanType channeldb.ChannelType) ( FundingOutpoint: *prevOut, ShortChannelID: shortChanID, ChanType: chanType, - IsInitiator: true, + IsInitiator: isAliceInitiator, Capacity: channelCapacity, RemoteCurrentRevocation: bobCommitPoint, RevocationProducer: alicePreimageProducer, @@ -333,7 +334,7 @@ func CreateTestChannels(chanType channeldb.ChannelType) ( FundingOutpoint: *prevOut, ShortChannelID: shortChanID, ChanType: chanType, - IsInitiator: false, + IsInitiator: !isAliceInitiator, Capacity: channelCapacity, RemoteCurrentRevocation: aliceCommitPoint, RevocationProducer: bobPreimageProducer, diff --git a/lnwallet/transactions.go b/lnwallet/transactions.go index 2072deb6a60..ce2eb9e80d3 100644 --- a/lnwallet/transactions.go +++ b/lnwallet/transactions.go @@ -44,9 +44,10 @@ var ( // In order to spend the HTLC output, the witness for the passed transaction // should be: // * <0> -func CreateHtlcSuccessTx(chanType channeldb.ChannelType, - htlcOutput wire.OutPoint, htlcAmt btcutil.Amount, csvDelay uint32, - revocationKey, delayKey *btcec.PublicKey) (*wire.MsgTx, error) { +func CreateHtlcSuccessTx(chanType channeldb.ChannelType, initiator bool, + htlcOutput wire.OutPoint, htlcAmt btcutil.Amount, csvDelay, + leaseExpiry uint32, revocationKey, delayKey *btcec.PublicKey) ( + *wire.MsgTx, error) { // Create a version two transaction (as the success version of this // spends an output with a CSV timeout). @@ -65,7 +66,8 @@ func CreateHtlcSuccessTx(chanType channeldb.ChannelType, // level HTLC which forces a covenant w.r.t what can be done with all // HTLC outputs. script, err := SecondLevelHtlcScript( - revocationKey, delayKey, csvDelay, + chanType, initiator, revocationKey, delayKey, csvDelay, + leaseExpiry, ) if err != nil { return nil, err @@ -97,9 +99,9 @@ func CreateHtlcSuccessTx(chanType channeldb.ChannelType, // NOTE: The passed amount for the HTLC should take into account the required // fee rate at the time the HTLC was created. The fee should be able to // entirely pay for this (tiny: 1-in 1-out) transaction. -func CreateHtlcTimeoutTx(chanType channeldb.ChannelType, +func CreateHtlcTimeoutTx(chanType channeldb.ChannelType, initiator bool, htlcOutput wire.OutPoint, htlcAmt btcutil.Amount, - cltvExpiry, csvDelay uint32, + cltvExpiry, csvDelay, leaseExpiry uint32, revocationKey, delayKey *btcec.PublicKey) (*wire.MsgTx, error) { // Create a version two transaction (as the success version of this @@ -123,7 +125,8 @@ func CreateHtlcTimeoutTx(chanType channeldb.ChannelType, // level HTLC which forces a covenant w.r.t what can be done with all // HTLC outputs. script, err := SecondLevelHtlcScript( - revocationKey, delayKey, csvDelay, + chanType, initiator, revocationKey, delayKey, csvDelay, + leaseExpiry, ) if err != nil { return nil, err diff --git a/lnwallet/transactions_test.go b/lnwallet/transactions_test.go index 696328cdb2e..d923169360b 100644 --- a/lnwallet/transactions_test.go +++ b/lnwallet/transactions_test.go @@ -570,7 +570,7 @@ func testSpendValidation(t *testing.T, tweakless bool) { } commitmentTx, err := CreateCommitTx( channelType, *fakeFundingTxIn, keyRing, aliceChanCfg, - bobChanCfg, channelBalance, channelBalance, 0, + bobChanCfg, channelBalance, channelBalance, 0, true, 0, ) if err != nil { t.Fatalf("unable to create commitment transaction: %v", nil) @@ -886,7 +886,7 @@ func createTestChannelsForVectors(tc *testContext, chanType channeldb.ChannelTyp remoteCommitTx, localCommitTx, err := CreateCommitmentTxns( remoteBalance, localBalance-commitFee, &remoteCfg, &localCfg, remoteCommitPoint, - localCommitPoint, *fundingTxIn, chanType, + localCommitPoint, *fundingTxIn, chanType, true, 0, ) require.NoError(t, err) diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index 820bc83cfb3..39a41455990 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -1189,8 +1189,8 @@ func (l *LightningWallet) handleFundingCancelRequest(req *fundingReserveCancelMs func CreateCommitmentTxns(localBalance, remoteBalance btcutil.Amount, ourChanCfg, theirChanCfg *channeldb.ChannelConfig, localCommitPoint, remoteCommitPoint *btcec.PublicKey, - fundingTxIn wire.TxIn, chanType channeldb.ChannelType) ( - *wire.MsgTx, *wire.MsgTx, error) { + fundingTxIn wire.TxIn, chanType channeldb.ChannelType, initiator bool, + leaseExpiry uint32) (*wire.MsgTx, *wire.MsgTx, error) { localCommitmentKeys := DeriveCommitmentKeys( localCommitPoint, true, chanType, ourChanCfg, theirChanCfg, @@ -1201,7 +1201,8 @@ func CreateCommitmentTxns(localBalance, remoteBalance btcutil.Amount, ourCommitTx, err := CreateCommitTx( chanType, fundingTxIn, localCommitmentKeys, ourChanCfg, - theirChanCfg, localBalance, remoteBalance, 0, + theirChanCfg, localBalance, remoteBalance, 0, initiator, + leaseExpiry, ) if err != nil { return nil, nil, err @@ -1214,7 +1215,8 @@ func CreateCommitmentTxns(localBalance, remoteBalance btcutil.Amount, theirCommitTx, err := CreateCommitTx( chanType, fundingTxIn, remoteCommitmentKeys, theirChanCfg, - ourChanCfg, remoteBalance, localBalance, 0, + ourChanCfg, remoteBalance, localBalance, 0, !initiator, + leaseExpiry, ) if err != nil { return nil, nil, err @@ -1453,12 +1455,17 @@ func (l *LightningWallet) handleChanPointReady(req *continueContributionMsg) { // With the funding tx complete, create both commitment transactions. localBalance := pendingReservation.partialState.LocalCommitment.LocalBalance.ToSatoshis() remoteBalance := pendingReservation.partialState.LocalCommitment.RemoteBalance.ToSatoshis() + var leaseExpiry uint32 + if pendingReservation.partialState.ChanType.HasLeaseExpiration() { + leaseExpiry = pendingReservation.partialState.ThawHeight + } ourCommitTx, theirCommitTx, err := CreateCommitmentTxns( localBalance, remoteBalance, ourContribution.ChannelConfig, theirContribution.ChannelConfig, ourContribution.FirstCommitmentPoint, theirContribution.FirstCommitmentPoint, fundingTxIn, pendingReservation.partialState.ChanType, + pendingReservation.partialState.IsInitiator, leaseExpiry, ) if err != nil { req.err <- err @@ -1820,6 +1827,10 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) { // remote node's commitment transactions. localBalance := pendingReservation.partialState.LocalCommitment.LocalBalance.ToSatoshis() remoteBalance := pendingReservation.partialState.LocalCommitment.RemoteBalance.ToSatoshis() + var leaseExpiry uint32 + if pendingReservation.partialState.ChanType.HasLeaseExpiration() { + leaseExpiry = pendingReservation.partialState.ThawHeight + } ourCommitTx, theirCommitTx, err := CreateCommitmentTxns( localBalance, remoteBalance, pendingReservation.ourContribution.ChannelConfig, @@ -1827,6 +1838,7 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) { pendingReservation.ourContribution.FirstCommitmentPoint, pendingReservation.theirContribution.FirstCommitmentPoint, *fundingTxIn, pendingReservation.partialState.ChanType, + pendingReservation.partialState.IsInitiator, leaseExpiry, ) if err != nil { req.err <- err diff --git a/peer/test_utils.go b/peer/test_utils.go index e2534c1cd8b..5b5f35c6e86 100644 --- a/peer/test_utils.go +++ b/peer/test_utils.go @@ -72,6 +72,7 @@ func createTestPeer(notifier chainntnfs.ChainNotifier, bobDustLimit := btcutil.Amount(1300) csvTimeoutAlice := uint32(5) csvTimeoutBob := uint32(4) + isAliceInitiator := true prevOut := &wire.OutPoint{ Hash: channels.TestHdSeed, @@ -155,6 +156,7 @@ func createTestPeer(notifier chainntnfs.ChainNotifier, aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns( channelBal, channelBal, &aliceCfg, &bobCfg, aliceCommitPoint, bobCommitPoint, *fundingTxIn, channeldb.SingleFunderTweaklessBit, + isAliceInitiator, 0, ) if err != nil { return nil, nil, nil, err @@ -222,7 +224,7 @@ func createTestPeer(notifier chainntnfs.ChainNotifier, FundingOutpoint: *prevOut, ShortChannelID: shortChanID, ChanType: channeldb.SingleFunderTweaklessBit, - IsInitiator: true, + IsInitiator: isAliceInitiator, Capacity: channelCapacity, RemoteCurrentRevocation: bobCommitPoint, RevocationProducer: alicePreimageProducer, @@ -239,7 +241,7 @@ func createTestPeer(notifier chainntnfs.ChainNotifier, IdentityPub: bobKeyPub, FundingOutpoint: *prevOut, ChanType: channeldb.SingleFunderTweaklessBit, - IsInitiator: false, + IsInitiator: !isAliceInitiator, Capacity: channelCapacity, RemoteCurrentRevocation: aliceCommitPoint, RevocationProducer: bobPreimageProducer, From 425242af7f90b73e7e5122ead00a569c99db15e9 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Tue, 13 Jul 2021 16:19:26 -0700 Subject: [PATCH 21/29] input: add new constructor to support CSV and CLTV locked inputs --- input/input.go | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/input/input.go b/input/input.go index 87a6339eed8..87d4b9fcd4d 100644 --- a/input/input.go +++ b/input/input.go @@ -90,6 +90,7 @@ type inputKit struct { signDesc SignDescriptor heightHint uint32 blockToMaturity uint32 + cltvExpiry uint32 // unconfParent contains information about a potential unconfirmed // parent transaction. @@ -111,7 +112,7 @@ func (i *inputKit) RequiredTxOut() *wire.TxOut { // must be used in the transaction including it. This will be false for the // base input type since we can re-sign for any lock time. func (i *inputKit) RequiredLockTime() (uint32, bool) { - return 0, false + return i.cltvExpiry, i.cltvExpiry > 0 } // WitnessType returns the type of witness that must be generated to spend the @@ -196,6 +197,25 @@ func NewCsvInput(outpoint *wire.OutPoint, witnessType WitnessType, } } +// NewCsvInputWithCltv assembles a new csv and cltv locked input that can be +// used to construct a sweep transaction. +func NewCsvInputWithCltv(outpoint *wire.OutPoint, witnessType WitnessType, + signDescriptor *SignDescriptor, heightHint uint32, + csvDelay uint32, cltvExpiry uint32) *BaseInput { + + return &BaseInput{ + inputKit{ + outpoint: *outpoint, + witnessType: witnessType, + signDesc: *signDescriptor, + heightHint: heightHint, + blockToMaturity: csvDelay, + cltvExpiry: cltvExpiry, + unconfParent: nil, + }, + } +} + // CraftInputScript returns a valid set of input scripts allowing this output // to be spent. The returned input scripts should target the input at location // txIndex within the passed transaction. The input scripts generated by this From 4550a1cc8093a69db0680c836b7b2c818a93ee3d Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 14 Jul 2021 16:07:36 -0700 Subject: [PATCH 22/29] contractcourt: handle sweeping script-enforced leased channel outputs In order to sweep the commitment and HTLC outputs belonging to a script-enforced leased channel, each resolver must know whether the additional CLTV clause on the channel initiator applies to them. To do so, we retrieve the historical channel state stored within the database and supplement it to the resolvers to provide them with what's needed in order to sweep the necessary outputs and resolve their respective contracts. --- contractcourt/anchor_resolver.go | 7 ++ contractcourt/chain_arbitrator.go | 6 + contractcourt/channel_arbitrator.go | 30 ++++- contractcourt/channel_arbitrator_test.go | 3 + contractcourt/commit_sweep_resolver.go | 108 +++++++++++++++--- contractcourt/contract_resolvers.go | 4 + .../htlc_incoming_contest_resolver.go | 7 ++ .../htlc_outgoing_contest_resolver.go | 8 ++ contractcourt/htlc_success_resolver.go | 7 ++ contractcourt/htlc_timeout_resolver.go | 82 ++++++++++--- 10 files changed, 230 insertions(+), 32 deletions(-) diff --git a/contractcourt/anchor_resolver.go b/contractcourt/anchor_resolver.go index 98a4fccae6a..fe2adc8b144 100644 --- a/contractcourt/anchor_resolver.go +++ b/contractcourt/anchor_resolver.go @@ -192,6 +192,13 @@ func (c *anchorResolver) IsResolved() bool { return c.resolved } +// SupplementState allows the user of a ContractResolver to supplement it with +// state required for the proper resolution of a contract. +// +// NOTE: Part of the ContractResolver interface. +func (c *anchorResolver) SupplementState(_ *channeldb.OpenChannel) { +} + // report returns a report on the resolution state of the contract. func (c *anchorResolver) report() *ContractReport { c.reportLock.Lock() diff --git a/contractcourt/chain_arbitrator.go b/contractcourt/chain_arbitrator.go index 453f292b662..55e2d2ea1b3 100644 --- a/contractcourt/chain_arbitrator.go +++ b/contractcourt/chain_arbitrator.go @@ -350,6 +350,9 @@ func newActiveChannelArbitrator(channel *channeldb.OpenChannel, report, ) }, + FetchHistoricalChannel: func() (*channeldb.OpenChannel, error) { + return c.chanSource.FetchHistoricalChannel(&chanPoint) + }, } // The final component needed is an arbitrator log that the arbitrator @@ -558,6 +561,9 @@ func (c *ChainArbitrator) Start() error { tx, c.cfg.ChainHash, &chanPoint, report, ) }, + FetchHistoricalChannel: func() (*channeldb.OpenChannel, error) { + return c.chanSource.FetchHistoricalChannel(&chanPoint) + }, } chanLog, err := newBoltArbitratorLog( c.chanSource.Backend, arbCfg, c.cfg.ChainHash, chanPoint, diff --git a/contractcourt/channel_arbitrator.go b/contractcourt/channel_arbitrator.go index 5f4cb31d567..34d806dc5c3 100644 --- a/contractcourt/channel_arbitrator.go +++ b/contractcourt/channel_arbitrator.go @@ -158,6 +158,11 @@ type ChannelArbitratorConfig struct { PutResolverReport func(tx kvdb.RwTx, report *channeldb.ResolverReport) error + // FetchHistoricalChannel retrieves the historical state of a channel. + // This is mostly used to supplement the ContractResolvers with + // additional information required for proper contract resolution. + FetchHistoricalChannel func() (*channeldb.OpenChannel, error) + ChainArbitratorConfig } @@ -604,10 +609,20 @@ func (c *ChannelArbitrator) relaunchResolvers(commitSet *CommitSet, htlcMap[outpoint] = &htlc } + // We'll also fetch the historical state of this channel, as it should + // have been marked as closed by now, and supplement it to each resolver + // such that we can properly resolve our pending contracts. + chanState, err := c.cfg.FetchHistoricalChannel() + if err != nil { + return err + } + log.Infof("ChannelArbitrator(%v): relaunching %v contract "+ "resolvers", c.cfg.ChanPoint, len(unresolvedContracts)) for _, resolver := range unresolvedContracts { + resolver.SupplementState(chanState) + htlcResolver, ok := resolver.(htlcContractResolver) if !ok { continue @@ -1907,6 +1922,14 @@ func (c *ChannelArbitrator) prepContractResolutions( return nil, nil, err } + // We'll also fetch the historical state of this channel, as it should + // have been marked as closed by now, and supplement it to each resolver + // such that we can properly resolve our pending contracts. + chanState, err := c.cfg.FetchHistoricalChannel() + if err != nil { + return nil, nil, err + } + // There may be a class of HTLC's which we can fail back immediately, // for those we'll prepare a slice of packets to add to our outbox. Any // packets we need to send, will be cancels. @@ -2012,6 +2035,7 @@ func (c *ChannelArbitrator) prepContractResolutions( resolver := newTimeoutResolver( resolution, height, htlc, resolverCfg, ) + resolver.SupplementState(chanState) htlcResolvers = append(htlcResolvers, resolver) } @@ -2068,6 +2092,7 @@ func (c *ChannelArbitrator) prepContractResolutions( resolver := newOutgoingContestResolver( resolution, height, htlc, resolverCfg, ) + resolver.SupplementState(chanState) htlcResolvers = append(htlcResolvers, resolver) } } @@ -2078,9 +2103,10 @@ func (c *ChannelArbitrator) prepContractResolutions( // trimmed). if contractResolutions.CommitResolution != nil { resolver := newCommitSweepResolver( - *contractResolutions.CommitResolution, - height, c.cfg.ChanPoint, resolverCfg, + *contractResolutions.CommitResolution, height, + c.cfg.ChanPoint, resolverCfg, ) + resolver.SupplementState(chanState) htlcResolvers = append(htlcResolvers, resolver) } diff --git a/contractcourt/channel_arbitrator_test.go b/contractcourt/channel_arbitrator_test.go index 34eab1e31bf..c2bf055fb53 100644 --- a/contractcourt/channel_arbitrator_test.go +++ b/contractcourt/channel_arbitrator_test.go @@ -381,6 +381,9 @@ func createTestChannelArbitrator(t *testing.T, log ArbitratorLog, return nil }, + FetchHistoricalChannel: func() (*channeldb.OpenChannel, error) { + return &channeldb.OpenChannel{}, nil + }, } // Apply all custom options to the config struct. diff --git a/contractcourt/commit_sweep_resolver.go b/contractcourt/commit_sweep_resolver.go index 1ce3f3229f1..6b365735f58 100644 --- a/contractcourt/commit_sweep_resolver.go +++ b/contractcourt/commit_sweep_resolver.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "fmt" "io" + "math" "sync" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -43,6 +44,19 @@ type commitSweepResolver struct { // chanPoint is the channel point of the original contract. chanPoint wire.OutPoint + // channelInitiator denotes whether the party responsible for resolving + // the contract initiated the channel. + channelInitiator bool + + // leaseExpiry denotes the additional waiting period the contract must + // hold until it can be resolved. This waiting period is known as the + // expiration of a script-enforced leased channel and only applies to + // the channel initiator. + // + // NOTE: This value should only be set when the contract belongs to a + // leased channel. + leaseExpiry uint32 + // currentReport stores the current state of the resolver for reporting // over the rpc interface. currentReport ContractReport @@ -55,8 +69,8 @@ type commitSweepResolver struct { // newCommitSweepResolver instantiates a new direct commit output resolver. func newCommitSweepResolver(res lnwallet.CommitOutputResolution, - broadcastHeight uint32, - chanPoint wire.OutPoint, resCfg ResolverConfig) *commitSweepResolver { + broadcastHeight uint32, chanPoint wire.OutPoint, + resCfg ResolverConfig) *commitSweepResolver { r := &commitSweepResolver{ contractResolverKit: *newContractResolverKit(resCfg), @@ -181,7 +195,14 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) { return nil, err } + // Wait up until the CSV expires, unless we also have a CLTV that + // expires after. unlockHeight := confHeight + c.commitResolution.MaturityDelay + if c.hasCLTV() { + unlockHeight = uint32(math.Max( + float64(unlockHeight), float64(c.leaseExpiry), + )) + } c.log.Debugf("commit conf_height=%v, unlock_height=%v", confHeight, unlockHeight) @@ -191,14 +212,34 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) { c.currentReport.MaturityHeight = unlockHeight c.reportLock.Unlock() - // If there is a csv delay, we'll wait for that. - if c.commitResolution.MaturityDelay > 0 { - c.log.Debugf("waiting for csv lock to expire at height %v", - unlockHeight) + // If there is a csv/cltv lock, we'll wait for that. + if c.commitResolution.MaturityDelay > 0 || c.hasCLTV() { + // Determine what height we should wait until for the locks to + // expire. + var waitHeight uint32 + switch { + // If we have both a csv and cltv lock, we'll need to look at + // both and see which expires later. + case c.commitResolution.MaturityDelay > 0 && c.hasCLTV(): + c.log.Debugf("waiting for CSV and CLTV lock to expire "+ + "at height %v", unlockHeight) + // If the CSV expires after the CLTV, or there is no + // CLTV, then we can broadcast a sweep a block before. + // Otherwise, we need to broadcast at our expected + // unlock height. + waitHeight = uint32(math.Max( + float64(unlockHeight-1), float64(c.leaseExpiry), + )) + + // If we only have a csv lock, wait for the height before the + // lock expires as the spend path should be unlocked by then. + case c.commitResolution.MaturityDelay > 0: + c.log.Debugf("waiting for CSV lock to expire at "+ + "height %v", unlockHeight) + waitHeight = unlockHeight - 1 + } - // We only need to wait for the block before the block that - // unlocks the spend path. - err := waitForHeight(unlockHeight-1, c.Notifier, c.quit) + err := waitForHeight(waitHeight, c.Notifier, c.quit) if err != nil { return nil, err } @@ -222,10 +263,20 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) { var witnessType input.WitnessType switch { + // Delayed output to us on our local commitment for a channel lease in + // which we are the initiator. + case isLocalCommitTx && c.hasCLTV(): + witnessType = input.LeaseCommitmentTimeLock + // Delayed output to us on our local commitment. case isLocalCommitTx: witnessType = input.CommitmentTimeLock + // A confirmed output to us on the remote commitment for a channel lease + // in which we are the initiator. + case isDelayedOutput && c.hasCLTV(): + witnessType = input.LeaseCommitmentToRemoteConfirmed + // A confirmed output to us on the remote commitment. case isDelayedOutput: witnessType = input.CommitmentToRemoteConfirmed @@ -246,13 +297,21 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) { // We'll craft an input with all the information required for // the sweeper to create a fully valid sweeping transaction to // recover these coins. - inp := input.NewCsvInput( - &c.commitResolution.SelfOutPoint, - witnessType, - &c.commitResolution.SelfOutputSignDesc, - c.broadcastHeight, - c.commitResolution.MaturityDelay, - ) + var inp *input.BaseInput + if c.hasCLTV() { + inp = input.NewCsvInputWithCltv( + &c.commitResolution.SelfOutPoint, witnessType, + &c.commitResolution.SelfOutputSignDesc, + c.broadcastHeight, c.commitResolution.MaturityDelay, + c.leaseExpiry, + ) + } else { + inp = input.NewCsvInput( + &c.commitResolution.SelfOutPoint, witnessType, + &c.commitResolution.SelfOutputSignDesc, + c.broadcastHeight, c.commitResolution.MaturityDelay, + ) + } // With our input constructed, we'll now offer it to the // sweeper. @@ -337,6 +396,23 @@ func (c *commitSweepResolver) IsResolved() bool { return c.resolved } +// SupplementState allows the user of a ContractResolver to supplement it with +// state required for the proper resolution of a contract. +// +// NOTE: Part of the ContractResolver interface. +func (c *commitSweepResolver) SupplementState(state *channeldb.OpenChannel) { + if state.ChanType.HasLeaseExpiration() { + c.leaseExpiry = state.ThawHeight + } + c.channelInitiator = state.IsInitiator +} + +// hasCLTV denotes whether the resolver must wait for an additional CLTV to +// expire before resolving the contract. +func (c *commitSweepResolver) hasCLTV() bool { + return c.channelInitiator && c.leaseExpiry > 0 +} + // Encode writes an encoded version of the ContractResolver into the passed // Writer. // diff --git a/contractcourt/contract_resolvers.go b/contractcourt/contract_resolvers.go index ef391ff939e..b12c4815c47 100644 --- a/contractcourt/contract_resolvers.go +++ b/contractcourt/contract_resolvers.go @@ -48,6 +48,10 @@ type ContractResolver interface { // NOTE: This function MUST be run as a goroutine. Resolve() (ContractResolver, error) + // SupplementState allows the user of a ContractResolver to supplement + // it with state required for the proper resolution of a contract. + SupplementState(*channeldb.OpenChannel) + // IsResolved returns true if the stored state in the resolve is fully // resolved. In this case the target output can be forgotten. IsResolved() bool diff --git a/contractcourt/htlc_incoming_contest_resolver.go b/contractcourt/htlc_incoming_contest_resolver.go index 59f5d9fdb56..ca4e05ddf53 100644 --- a/contractcourt/htlc_incoming_contest_resolver.go +++ b/contractcourt/htlc_incoming_contest_resolver.go @@ -433,6 +433,13 @@ func (h *htlcIncomingContestResolver) Supplement(htlc channeldb.HTLC) { h.htlc = htlc } +// SupplementState allows the user of a ContractResolver to supplement it with +// state required for the proper resolution of a contract. +// +// NOTE: Part of the ContractResolver interface. +func (h *htlcIncomingContestResolver) SupplementState(_ *channeldb.OpenChannel) { +} + // decodePayload (re)decodes the hop payload of a received htlc. func (h *htlcIncomingContestResolver) decodePayload() (*hop.Payload, error) { diff --git a/contractcourt/htlc_outgoing_contest_resolver.go b/contractcourt/htlc_outgoing_contest_resolver.go index d2813c955bd..14398e1a761 100644 --- a/contractcourt/htlc_outgoing_contest_resolver.go +++ b/contractcourt/htlc_outgoing_contest_resolver.go @@ -190,6 +190,14 @@ func (h *htlcOutgoingContestResolver) IsResolved() bool { return h.resolved } +// SupplementState allows the user of a ContractResolver to supplement it with +// state required for the proper resolution of a contract. +// +// NOTE: Part of the ContractResolver interface. +func (h *htlcOutgoingContestResolver) SupplementState(state *channeldb.OpenChannel) { + h.htlcTimeoutResolver.SupplementState(state) +} + // Encode writes an encoded version of the ContractResolver into the passed // Writer. // diff --git a/contractcourt/htlc_success_resolver.go b/contractcourt/htlc_success_resolver.go index 37b4d42b66c..c81fffcc8b3 100644 --- a/contractcourt/htlc_success_resolver.go +++ b/contractcourt/htlc_success_resolver.go @@ -626,6 +626,13 @@ func (h *htlcSuccessResolver) Supplement(htlc channeldb.HTLC) { h.htlc = htlc } +// SupplementState allows the user of a ContractResolver to supplement it with +// state required for the proper resolution of a contract. +// +// NOTE: Part of the ContractResolver interface. +func (h *htlcSuccessResolver) SupplementState(_ *channeldb.OpenChannel) { +} + // HtlcPoint returns the htlc's outpoint on the commitment tx. // // NOTE: Part of the htlcContractResolver interface. diff --git a/contractcourt/htlc_timeout_resolver.go b/contractcourt/htlc_timeout_resolver.go index 44be1643340..b20f10ca9e7 100644 --- a/contractcourt/htlc_timeout_resolver.go +++ b/contractcourt/htlc_timeout_resolver.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "fmt" "io" + "math" "sync" "github.com/btcsuite/btcd/wire" @@ -47,6 +48,19 @@ type htlcTimeoutResolver struct { // htlc contains information on the htlc that we are resolving on-chain. htlc channeldb.HTLC + // channelInitiator denotes whether the party responsible for resolving + // the contract initiated the channel. + channelInitiator bool + + // leaseExpiry denotes the additional waiting period the contract must + // hold until it can be resolved. This waiting period is known as the + // expiration of a script-enforced leased channel and only applies to + // the channel initiator. + // + // NOTE: This value should only be set when the contract belongs to a + // leased channel. + leaseExpiry uint32 + // currentReport stores the current state of the resolver for reporting // over the rpc interface. This should only be reported in case we have // a non-nil SignDetails on the htlcResolution, otherwise the nursery @@ -429,19 +443,30 @@ func (h *htlcTimeoutResolver) handleCommitSpend( switch { // If the sweeper is handling the second level transaction, wait for - // the CSV lock to expire, before sweeping the output on the - // second-level. + // the CSV and possible CLTV lock to expire, before sweeping the output + // on the second-level. case h.htlcResolution.SignDetails != nil: waitHeight := uint32(commitSpend.SpendingHeight) + h.htlcResolution.CsvDelay - 1 + if h.hasCLTV() { + waitHeight = uint32(math.Max( + float64(waitHeight), float64(h.leaseExpiry), + )) + } h.reportLock.Lock() h.currentReport.Stage = 2 h.currentReport.MaturityHeight = waitHeight h.reportLock.Unlock() - log.Infof("%T(%x): waiting for CSV lock to expire at height %v", - h, h.htlc.RHash[:], waitHeight) + if h.hasCLTV() { + log.Infof("%T(%x): waiting for CSV and CLTV lock to "+ + "expire at height %v", h, h.htlc.RHash[:], + waitHeight) + } else { + log.Infof("%T(%x): waiting for CSV lock to expire at "+ + "height %v", h, h.htlc.RHash[:], waitHeight) + } err := waitForHeight(waitHeight, h.Notifier, h.quit) if err != nil { @@ -459,16 +484,28 @@ func (h *htlcTimeoutResolver) handleCommitSpend( } // Let the sweeper sweep the second-level output now that the - // CSV delay has passed. - log.Infof("%T(%x): CSV lock expired, offering second-layer "+ - "output to sweeper: %v", h, h.htlc.RHash[:], op) - - inp := input.NewCsvInput( - op, input.HtlcOfferedTimeoutSecondLevel, - &h.htlcResolution.SweepSignDesc, - h.broadcastHeight, - h.htlcResolution.CsvDelay, - ) + // CSV/CLTV locks have expired. + var inp *input.BaseInput + if h.hasCLTV() { + log.Infof("%T(%x): CSV and CLTV locks expired, offering "+ + "second-layer output to sweeper: %v", h, + h.htlc.RHash[:], op) + inp = input.NewCsvInputWithCltv( + op, input.LeaseHtlcOfferedTimeoutSecondLevel, + &h.htlcResolution.SweepSignDesc, + h.broadcastHeight, h.htlcResolution.CsvDelay, + h.leaseExpiry, + ) + } else { + log.Infof("%T(%x): CSV lock expired, offering "+ + "second-layer output to sweeper: %v", h, + h.htlc.RHash[:], op) + inp = input.NewCsvInput( + op, input.HtlcOfferedTimeoutSecondLevel, + &h.htlcResolution.SweepSignDesc, + h.broadcastHeight, h.htlcResolution.CsvDelay, + ) + } _, err = h.Sweeper.SweepInput( inp, sweep.Params{ @@ -681,6 +718,23 @@ func (h *htlcTimeoutResolver) Supplement(htlc channeldb.HTLC) { h.htlc = htlc } +// SupplementState allows the user of a ContractResolver to supplement it with +// state required for the proper resolution of a contract. +// +// NOTE: Part of the ContractResolver interface. +func (h *htlcTimeoutResolver) SupplementState(state *channeldb.OpenChannel) { + if state.ChanType.HasLeaseExpiration() { + h.leaseExpiry = state.ThawHeight + } + h.channelInitiator = state.IsInitiator +} + +// hasCLTV denotes whether the resolver must wait for an additional CLTV to +// expire before resolving the contract. +func (h *htlcTimeoutResolver) hasCLTV() bool { + return h.channelInitiator && h.leaseExpiry > 0 +} + // HtlcPoint returns the htlc's outpoint on the commitment tx. // // NOTE: Part of the htlcContractResolver interface. From c34d0745b012d09ce1ec9e932e5f619aa8d35b12 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 14 Jul 2021 17:19:22 -0700 Subject: [PATCH 23/29] sweep: remove previous exclusive group upon re-offered inputs This aims to cover an edge case and also serves as an optimization of what happens when an input that was offered to the Sweeper with an exclusive group is re-offered without one. This happens every time we attempt to sweep the different possible anchors of a channel at the time of broadcast, as we don't know which commitment transaction will end up confirming in the chain. Once the commitment transaction confirms however, we know which anchor output to act upon and re-offer it to the Sweeper without an exclusive group. At this point, the Sweeper will continue to attempt sweeping the other anchor output versions even know we know they are not valid. --- sweep/sweeper.go | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/sweep/sweeper.go b/sweep/sweeper.go index 5869e45644c..fd048428fe1 100644 --- a/sweep/sweeper.go +++ b/sweep/sweeper.go @@ -459,9 +459,11 @@ func (s *UtxoSweeper) SweepInput(input input.Input, return nil, err } + absoluteTimeLock, _ := input.RequiredLockTime() log.Infof("Sweep request received: out_point=%v, witness_type=%v, "+ - "time_lock=%v, amount=%v, params=(%v)", - input.OutPoint(), input.WitnessType(), input.BlocksToMaturity(), + "relative_time_lock=%v, absolute_time_lock=%v, amount=%v, "+ + "params=(%v)", input.OutPoint(), input.WitnessType(), + input.BlocksToMaturity(), absoluteTimeLock, btcutil.Amount(input.SignDesc().Output.Value), params) sweeperInput := &sweepInputMessage{ @@ -534,6 +536,17 @@ func (s *UtxoSweeper) collector(blockEpochs <-chan *chainntnfs.BlockEpoch) { log.Debugf("Already pending input %v received", outpoint) + // Before updating the input details, check if + // an exclusive group was set, and if so, assume + // this input as finalized and remove all other + // inputs belonging to the same exclusive group. + var prevExclGroup *uint64 + if pendInput.params.ExclusiveGroup != nil && + input.params.ExclusiveGroup == nil { + prevExclGroup = new(uint64) + *prevExclGroup = *pendInput.params.ExclusiveGroup + } + // Update input details and sweep parameters. // The re-offered input details may contain a // change to the unconfirmed parent tx info. @@ -545,6 +558,11 @@ func (s *UtxoSweeper) collector(blockEpochs <-chan *chainntnfs.BlockEpoch) { pendInput.listeners = append( pendInput.listeners, input.resultChan, ) + + if prevExclGroup != nil { + s.removeExclusiveGroup(*prevExclGroup) + } + continue } From 4ab815509b290aecd5ad722f5e3597fde2e76e5a Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 14 Jul 2021 17:21:04 -0700 Subject: [PATCH 24/29] lnrpc: add new CommitmentType for script enforced leased channels --- lnrpc/lightning.pb.go | 705 ++++++++++++++++++----------------- lnrpc/lightning.proto | 9 + lnrpc/lightning.swagger.json | 5 +- rpcserver.go | 12 + 4 files changed, 382 insertions(+), 349 deletions(-) diff --git a/lnrpc/lightning.pb.go b/lnrpc/lightning.pb.go index 81beed880b6..2877d1bacb7 100644 --- a/lnrpc/lightning.pb.go +++ b/lnrpc/lightning.pb.go @@ -98,6 +98,13 @@ const ( //commitments, allowing fee bumping after a force close transaction has //been broadcast. CommitmentType_ANCHORS CommitmentType = 3 + // + //A channel that uses a commitment type that builds upon the anchors + //commitment format, but in addition requires a CLTV clause to spend outputs + //paying to the channel initiator. This is intended for use on leased channels + //to guarantee that the channel initiator has no incentives to close a leased + //channel before its maturity date. + CommitmentType_SCRIPT_ENFORCED_LEASE CommitmentType = 4 ) // Enum value maps for CommitmentType. @@ -107,12 +114,14 @@ var ( 1: "LEGACY", 2: "STATIC_REMOTE_KEY", 3: "ANCHORS", + 4: "SCRIPT_ENFORCED_LEASE", } CommitmentType_value = map[string]int32{ "UNKNOWN_COMMITMENT_TYPE": 0, "LEGACY": 1, "STATIC_REMOTE_KEY": 2, "ANCHORS": 3, + "SCRIPT_ENFORCED_LEASE": 4, } ) @@ -16863,362 +16872,364 @@ var file_lightning_proto_rawDesc = []byte{ 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x02, 0x12, 0x1d, 0x0a, 0x19, 0x55, 0x4e, 0x55, 0x53, 0x45, 0x44, 0x5f, 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, - 0x03, 0x2a, 0x5d, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x54, + 0x03, 0x2a, 0x78, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x45, 0x47, 0x41, 0x43, 0x59, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x54, 0x41, 0x54, 0x49, 0x43, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x10, 0x03, - 0x2a, 0x61, 0x0a, 0x09, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x15, 0x0a, - 0x11, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, - 0x57, 0x4e, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, - 0x52, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x49, - 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x10, 0x02, 0x12, - 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x42, 0x4f, 0x54, - 0x48, 0x10, 0x03, 0x2a, 0x60, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, - 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4e, 0x43, 0x48, 0x4f, - 0x52, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x49, 0x4e, 0x47, 0x5f, - 0x48, 0x54, 0x4c, 0x43, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4f, 0x55, 0x54, 0x47, 0x4f, 0x49, - 0x4e, 0x47, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4d, - 0x4d, 0x49, 0x54, 0x10, 0x04, 0x2a, 0x71, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, - 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x63, 0x6f, 0x6d, 0x65, 0x12, 0x13, 0x0a, 0x0f, 0x4f, 0x55, - 0x54, 0x43, 0x4f, 0x4d, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, - 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, - 0x55, 0x4e, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x41, - 0x42, 0x41, 0x4e, 0x44, 0x4f, 0x4e, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x46, 0x49, - 0x52, 0x53, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x10, 0x04, 0x12, 0x0b, 0x0a, 0x07, 0x54, - 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x05, 0x2a, 0x39, 0x0a, 0x0e, 0x4e, 0x6f, 0x64, 0x65, - 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, - 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x42, 0x45, 0x54, 0x57, 0x45, - 0x45, 0x4e, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x52, 0x41, 0x4c, 0x49, 0x54, - 0x59, 0x10, 0x01, 0x2a, 0x3b, 0x0a, 0x10, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x48, 0x54, - 0x4c, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x43, 0x43, 0x45, 0x50, - 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, 0x44, - 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x02, - 0x2a, 0xd9, 0x01, 0x0a, 0x14, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x46, 0x61, 0x69, 0x6c, - 0x75, 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x13, 0x46, 0x41, 0x49, - 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, - 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, - 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x1b, - 0x0a, 0x17, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, - 0x5f, 0x4e, 0x4f, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x46, - 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x45, 0x52, - 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x2c, 0x0a, 0x28, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, - 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, - 0x54, 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, - 0x53, 0x10, 0x04, 0x12, 0x27, 0x0a, 0x23, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, - 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, - 0x4e, 0x54, 0x5f, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x05, 0x2a, 0xcf, 0x04, 0x0a, - 0x0a, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x69, 0x74, 0x12, 0x18, 0x0a, 0x14, 0x44, - 0x41, 0x54, 0x41, 0x4c, 0x4f, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x45, 0x43, 0x54, 0x5f, - 0x52, 0x45, 0x51, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x44, 0x41, 0x54, 0x41, 0x4c, 0x4f, 0x53, - 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x45, 0x43, 0x54, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x01, 0x12, - 0x17, 0x0a, 0x13, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x5f, 0x52, 0x4f, 0x55, 0x49, 0x4e, - 0x47, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x03, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x46, 0x52, - 0x4f, 0x4e, 0x54, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x5f, 0x53, 0x43, 0x52, - 0x49, 0x50, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x04, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x46, - 0x52, 0x4f, 0x4e, 0x54, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x5f, 0x53, 0x43, - 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x47, 0x4f, - 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x52, 0x45, 0x51, - 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, - 0x52, 0x49, 0x45, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x07, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x4c, - 0x56, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x08, 0x12, 0x11, 0x0a, - 0x0d, 0x54, 0x4c, 0x56, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x09, - 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x54, 0x5f, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, - 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x0a, 0x12, 0x1a, 0x0a, 0x16, - 0x45, 0x58, 0x54, 0x5f, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, - 0x45, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0b, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x54, 0x41, 0x54, - 0x49, 0x43, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x52, 0x45, - 0x51, 0x10, 0x0c, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x54, 0x41, 0x54, 0x49, 0x43, 0x5f, 0x52, 0x45, - 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0d, 0x12, 0x14, - 0x0a, 0x10, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x52, - 0x45, 0x51, 0x10, 0x0e, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, - 0x41, 0x44, 0x44, 0x52, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0f, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x50, - 0x50, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x10, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x50, 0x50, 0x5f, 0x4f, - 0x50, 0x54, 0x10, 0x11, 0x12, 0x16, 0x0a, 0x12, 0x57, 0x55, 0x4d, 0x42, 0x4f, 0x5f, 0x43, 0x48, - 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x12, 0x12, 0x16, 0x0a, 0x12, - 0x57, 0x55, 0x4d, 0x42, 0x4f, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x53, 0x5f, 0x4f, - 0x50, 0x54, 0x10, 0x13, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, - 0x52, 0x45, 0x51, 0x10, 0x14, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, - 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x15, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, - 0x53, 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, - 0x52, 0x45, 0x51, 0x10, 0x16, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, - 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4f, - 0x50, 0x54, 0x10, 0x17, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f, 0x52, 0x45, 0x51, 0x10, - 0x1e, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x1f, 0x32, 0xc9, - 0x21, 0x0a, 0x09, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x4a, 0x0a, 0x0d, - 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, - 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x74, - 0x61, 0x69, 0x6c, 0x73, 0x12, 0x44, 0x0a, 0x0b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, - 0x46, 0x65, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, - 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, + 0x12, 0x19, 0x0a, 0x15, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x45, 0x4e, 0x46, 0x4f, 0x52, + 0x43, 0x45, 0x44, 0x5f, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x10, 0x04, 0x2a, 0x61, 0x0a, 0x09, 0x49, + 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x15, 0x0a, 0x11, 0x49, 0x4e, 0x49, 0x54, + 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, + 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x4c, 0x4f, 0x43, + 0x41, 0x4c, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, + 0x52, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, + 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x42, 0x4f, 0x54, 0x48, 0x10, 0x03, 0x2a, 0x60, + 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, + 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x10, 0x01, 0x12, 0x11, + 0x0a, 0x0d, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x10, + 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4f, 0x55, 0x54, 0x47, 0x4f, 0x49, 0x4e, 0x47, 0x5f, 0x48, 0x54, + 0x4c, 0x43, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x04, + 0x2a, 0x71, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, + 0x74, 0x63, 0x6f, 0x6d, 0x65, 0x12, 0x13, 0x0a, 0x0f, 0x4f, 0x55, 0x54, 0x43, 0x4f, 0x4d, 0x45, + 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, + 0x41, 0x49, 0x4d, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x43, 0x4c, 0x41, + 0x49, 0x4d, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x41, 0x42, 0x41, 0x4e, 0x44, 0x4f, + 0x4e, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x46, 0x49, 0x52, 0x53, 0x54, 0x5f, 0x53, + 0x54, 0x41, 0x47, 0x45, 0x10, 0x04, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, + 0x54, 0x10, 0x05, 0x2a, 0x39, 0x0a, 0x0e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, + 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x42, 0x45, 0x54, 0x57, 0x45, 0x45, 0x4e, 0x4e, 0x45, 0x53, + 0x53, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x52, 0x41, 0x4c, 0x49, 0x54, 0x59, 0x10, 0x01, 0x2a, 0x3b, + 0x0a, 0x10, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x48, 0x54, 0x4c, 0x43, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, + 0x08, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x2a, 0xd9, 0x01, 0x0a, 0x14, + 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, 0x65, + 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x13, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, + 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1a, 0x0a, + 0x16, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, + 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x41, 0x49, + 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x5f, 0x52, + 0x4f, 0x55, 0x54, 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, + 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, + 0x12, 0x2c, 0x0a, 0x28, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, + 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, 0x5f, 0x50, 0x41, 0x59, + 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, 0x53, 0x10, 0x04, 0x12, 0x27, + 0x0a, 0x23, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, + 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x42, 0x41, + 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x05, 0x2a, 0xcf, 0x04, 0x0a, 0x0a, 0x46, 0x65, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x42, 0x69, 0x74, 0x12, 0x18, 0x0a, 0x14, 0x44, 0x41, 0x54, 0x41, 0x4c, 0x4f, + 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x45, 0x43, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x00, + 0x12, 0x18, 0x0a, 0x14, 0x44, 0x41, 0x54, 0x41, 0x4c, 0x4f, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, + 0x54, 0x45, 0x43, 0x54, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x49, 0x4e, + 0x49, 0x54, 0x49, 0x41, 0x4c, 0x5f, 0x52, 0x4f, 0x55, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x59, 0x4e, + 0x43, 0x10, 0x03, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x46, 0x52, 0x4f, 0x4e, 0x54, 0x5f, 0x53, + 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x52, + 0x45, 0x51, 0x10, 0x04, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x46, 0x52, 0x4f, 0x4e, 0x54, 0x5f, + 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, + 0x4f, 0x50, 0x54, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, + 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x06, 0x12, 0x16, 0x0a, + 0x12, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, + 0x4f, 0x50, 0x54, 0x10, 0x07, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x4c, 0x56, 0x5f, 0x4f, 0x4e, 0x49, + 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x08, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x4c, 0x56, 0x5f, + 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x09, 0x12, 0x1a, 0x0a, 0x16, 0x45, + 0x58, 0x54, 0x5f, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, + 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x0a, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x54, 0x5f, 0x47, + 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x4f, 0x50, + 0x54, 0x10, 0x0b, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x54, 0x41, 0x54, 0x49, 0x43, 0x5f, 0x52, 0x45, + 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x0c, 0x12, 0x19, + 0x0a, 0x15, 0x53, 0x54, 0x41, 0x54, 0x49, 0x43, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, + 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0d, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x41, 0x59, + 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x0e, 0x12, + 0x14, 0x0a, 0x10, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x5f, + 0x4f, 0x50, 0x54, 0x10, 0x0f, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x50, 0x50, 0x5f, 0x52, 0x45, 0x51, + 0x10, 0x10, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x50, 0x50, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x11, 0x12, + 0x16, 0x0a, 0x12, 0x57, 0x55, 0x4d, 0x42, 0x4f, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, + 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x12, 0x12, 0x16, 0x0a, 0x12, 0x57, 0x55, 0x4d, 0x42, 0x4f, + 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x13, 0x12, + 0x0f, 0x0a, 0x0b, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x14, + 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, + 0x15, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x5a, 0x45, 0x52, + 0x4f, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x16, + 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x5a, 0x45, 0x52, 0x4f, + 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x17, 0x12, + 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x1e, 0x12, 0x0b, 0x0a, 0x07, + 0x41, 0x4d, 0x50, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x1f, 0x32, 0xc9, 0x21, 0x0a, 0x09, 0x4c, 0x69, + 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x4a, 0x0a, 0x0d, 0x57, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, + 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, + 0x44, 0x0a, 0x0b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, - 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x53, 0x65, - 0x6e, 0x64, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x53, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x69, - 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x4c, 0x69, - 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x4c, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x01, 0x12, 0x3b, - 0x0a, 0x08, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x6e, 0x79, 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, - 0x61, 0x6e, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0a, 0x4e, - 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, - 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, - 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, - 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x44, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x12, - 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, - 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, + 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x69, + 0x6e, 0x73, 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, + 0x6f, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, + 0x70, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x15, 0x53, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x01, 0x12, 0x3b, 0x0a, 0x08, 0x53, 0x65, 0x6e, + 0x64, 0x4d, 0x61, 0x6e, 0x79, 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, + 0x6e, 0x64, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0a, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x53, 0x69, 0x67, + 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x4a, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, - 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, - 0x72, 0x73, 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, - 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x13, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1c, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x10, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x38, - 0x0a, 0x07, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, - 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x50, 0x65, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1d, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0c, - 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1a, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, - 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, - 0x0e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, - 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0f, - 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x79, 0x6e, 0x63, 0x12, - 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, - 0x43, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x19, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x30, 0x01, 0x12, 0x4c, 0x0a, 0x10, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x65, 0x70, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x4d, 0x73, 0x67, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x65, 0x70, 0x52, 0x65, - 0x73, 0x70, 0x12, 0x50, 0x0a, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x28, 0x01, 0x30, 0x01, 0x12, 0x46, 0x0a, 0x0c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, - 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x0e, - 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1c, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x53, - 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x4d, 0x0a, 0x0e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, + 0x65, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69, 0x73, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x3e, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x17, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x47, 0x0a, 0x13, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x50, 0x65, 0x65, + 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x10, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, + 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x38, 0x0a, 0x07, 0x47, 0x65, 0x74, + 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x15, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, + 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, + 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x56, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x0e, 0x43, 0x6c, 0x6f, 0x73, + 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0f, 0x4f, 0x70, 0x65, 0x6e, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x43, 0x0a, 0x0b, 0x4f, 0x70, + 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, + 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, + 0x4c, 0x0a, 0x10, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, + 0x74, 0x65, 0x70, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x67, + 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x65, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x50, 0x0a, + 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x6f, 0x72, + 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x1b, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, + 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x28, 0x01, 0x30, 0x01, 0x12, + 0x46, 0x0a, 0x0c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, + 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x0e, 0x41, 0x62, 0x61, 0x6e, 0x64, + 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, + 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, + 0x88, 0x02, 0x01, 0x28, 0x01, 0x30, 0x01, 0x12, 0x3a, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x28, 0x01, 0x30, 0x01, 0x12, 0x3a, 0x0a, 0x0f, - 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x12, - 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, - 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x28, 0x01, 0x30, 0x01, - 0x12, 0x41, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x53, - 0x79, 0x6e, 0x63, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, - 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, - 0x65, 0x12, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, - 0x65, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, - 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0c, - 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x0d, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x76, - 0x6f, 0x69, 0x63, 0x65, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, - 0x63, 0x72, 0x69, 0x62, 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x30, 0x01, 0x12, 0x32, 0x0a, 0x0c, 0x44, - 0x65, 0x63, 0x6f, 0x64, 0x65, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x13, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x1a, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, - 0x47, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, - 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, - 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x40, 0x0a, 0x0d, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x47, 0x72, 0x61, 0x70, - 0x68, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, - 0x70, 0x68, 0x12, 0x47, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, - 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0b, 0x47, - 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x45, 0x64, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, - 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, - 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x44, - 0x0a, 0x0b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x19, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x35, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x70, 0x44, 0x61, 0x65, - 0x6d, 0x6f, 0x6e, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x15, - 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x72, - 0x61, 0x70, 0x68, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x47, 0x72, 0x61, 0x70, 0x68, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x41, 0x0a, 0x0a, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, - 0x76, 0x65, 0x6c, 0x12, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x62, 0x75, - 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x46, 0x65, 0x65, 0x52, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, - 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, - 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x46, 0x6f, 0x72, 0x77, - 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1f, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, - 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, - 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x4e, 0x0a, 0x13, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x21, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x12, 0x54, 0x0a, 0x17, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x6c, 0x6c, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x1e, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x4e, 0x0a, 0x10, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, - 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, - 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, - 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x43, - 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, - 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x30, 0x01, 0x12, 0x47, 0x0a, 0x0c, 0x42, 0x61, 0x6b, 0x65, - 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x42, 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6b, - 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, - 0x6e, 0x49, 0x44, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, - 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, - 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, - 0x6e, 0x67, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, + 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x28, 0x01, 0x30, 0x01, 0x12, 0x41, 0x0a, 0x0f, 0x53, + 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x19, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, + 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x0e, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x1a, 0x19, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x49, + 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, + 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, + 0x0a, 0x0d, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, + 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, + 0x61, 0x73, 0x68, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, + 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, + 0x6f, 0x69, 0x63, 0x65, 0x30, 0x01, 0x12, 0x32, 0x0a, 0x0c, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, + 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, + 0x61, 0x79, 0x52, 0x65, 0x71, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x1a, 0x0d, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x47, 0x0a, 0x0c, 0x4c, 0x69, + 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, + 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0d, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x1a, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, + 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x47, 0x0a, + 0x0e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, + 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, + 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, + 0x61, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x64, 0x67, + 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x44, 0x0a, 0x0b, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x3f, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x35, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x70, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x12, 0x12, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, + 0x12, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x54, 0x6f, + 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, + 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, + 0x12, 0x41, 0x0a, 0x0a, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x18, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, + 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, + 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, + 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, + 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x13, 0x45, + 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x12, 0x21, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, + 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x54, 0x0a, 0x17, 0x45, + 0x78, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x6c, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, + 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, + 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, + 0x74, 0x12, 0x4e, 0x0a, 0x10, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x42, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, + 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, + 0x1a, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, + 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x56, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x17, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, + 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, + 0x74, 0x30, 0x01, 0x12, 0x47, 0x0a, 0x0c, 0x42, 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, + 0x6f, 0x6f, 0x6e, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6b, 0x65, + 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, + 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, + 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x12, + 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, + 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, + 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, + 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, + 0x49, 0x44, 0x12, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/lnrpc/lightning.proto b/lnrpc/lightning.proto index 93923c9148d..48cfa427ccb 100644 --- a/lnrpc/lightning.proto +++ b/lnrpc/lightning.proto @@ -1140,6 +1140,15 @@ enum CommitmentType { been broadcast. */ ANCHORS = 3; + + /* + A channel that uses a commitment type that builds upon the anchors + commitment format, but in addition requires a CLTV clause to spend outputs + paying to the channel initiator. This is intended for use on leased channels + to guarantee that the channel initiator has no incentives to close a leased + channel before its maturity date. + */ + SCRIPT_ENFORCED_LEASE = 4; } message ChannelConstraints { diff --git a/lnrpc/lightning.swagger.json b/lnrpc/lightning.swagger.json index 8be7b600ad4..9ce74d2b335 100644 --- a/lnrpc/lightning.swagger.json +++ b/lnrpc/lightning.swagger.json @@ -3501,10 +3501,11 @@ "UNKNOWN_COMMITMENT_TYPE", "LEGACY", "STATIC_REMOTE_KEY", - "ANCHORS" + "ANCHORS", + "SCRIPT_ENFORCED_LEASE" ], "default": "UNKNOWN_COMMITMENT_TYPE", - "description": " - UNKNOWN_COMMITMENT_TYPE: Returned when the commitment type isn't known or unavailable.\n - LEGACY: A channel using the legacy commitment format having tweaked to_remote\nkeys.\n - STATIC_REMOTE_KEY: A channel that uses the modern commitment format where the key in the\noutput of the remote party does not change each state. This makes back\nup and recovery easier as when the channel is closed, the funds go\ndirectly to that key.\n - ANCHORS: A channel that uses a commitment format that has anchor outputs on the\ncommitments, allowing fee bumping after a force close transaction has\nbeen broadcast." + "description": " - UNKNOWN_COMMITMENT_TYPE: Returned when the commitment type isn't known or unavailable.\n - LEGACY: A channel using the legacy commitment format having tweaked to_remote\nkeys.\n - STATIC_REMOTE_KEY: A channel that uses the modern commitment format where the key in the\noutput of the remote party does not change each state. This makes back\nup and recovery easier as when the channel is closed, the funds go\ndirectly to that key.\n - ANCHORS: A channel that uses a commitment format that has anchor outputs on the\ncommitments, allowing fee bumping after a force close transaction has\nbeen broadcast.\n - SCRIPT_ENFORCED_LEASE: A channel that uses a commitment type that builds upon the anchors\ncommitment format, but in addition requires a CLTV clause to spend outputs\npaying to the channel initiator. This is intended for use on leased channels\nto guarantee that the channel initiator has no incentives to close a leased\nchannel before its maturity date." }, "lnrpcConnectPeerRequest": { "type": "object", diff --git a/rpcserver.go b/rpcserver.go index fa25bf2b703..fe9c276f218 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -1935,6 +1935,14 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest, lnwire.AnchorsZeroFeeHtlcTxRequired, )) + case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: + channelType = new(lnwire.ChannelType) + *channelType = lnwire.ChannelType(*lnwire.NewRawFeatureVector( + lnwire.StaticRemoteKeyRequired, + lnwire.AnchorsZeroFeeHtlcTxRequired, + lnwire.ScriptEnforcedLeaseRequired, + )) + default: return nil, fmt.Errorf("unhandled request channel type %v", in.CommitmentType) @@ -3559,6 +3567,10 @@ func rpcCommitmentType(chanType channeldb.ChannelType) lnrpc.CommitmentType { // Extract the commitment type from the channel type flags. We must // first check whether it has anchors, since in that case it would also // be tweakless. + if chanType.HasLeaseExpiration() { + return lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE + } + if chanType.HasAnchors() { return lnrpc.CommitmentType_ANCHORS } From 863282068ebab5e107b56876f94fa17be5edf85f Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 14 Jul 2021 17:21:51 -0700 Subject: [PATCH 25/29] chanacceptor: include commitment type in channel acceptor requests --- chanacceptor/rpcacceptor.go | 37 +++ lnrpc/lightning.pb.go | 548 ++++++++++++++++++----------------- lnrpc/lightning.proto | 3 + lnrpc/lightning.swagger.json | 4 + 4 files changed, 325 insertions(+), 267 deletions(-) diff --git a/chanacceptor/rpcacceptor.go b/chanacceptor/rpcacceptor.go index 66d846b3038..bec91435599 100644 --- a/chanacceptor/rpcacceptor.go +++ b/chanacceptor/rpcacceptor.go @@ -256,6 +256,42 @@ func (r *RPCAcceptor) sendAcceptRequests(errChan chan error, req := newRequest.request pendingChanID := req.OpenChanMsg.PendingChannelID + // Map the channel commitment type to its RPC + // counterpart. + var commitmentType lnrpc.CommitmentType + if req.OpenChanMsg.ChannelType != nil { + channelFeatures := lnwire.RawFeatureVector( + *req.OpenChanMsg.ChannelType, + ) + switch { + case channelFeatures.OnlyContains( + lnwire.ScriptEnforcedLeaseRequired, + lnwire.AnchorsZeroFeeHtlcTxRequired, + lnwire.StaticRemoteKeyRequired, + ): + commitmentType = lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE + + case channelFeatures.OnlyContains( + lnwire.AnchorsZeroFeeHtlcTxRequired, + lnwire.StaticRemoteKeyRequired, + ): + commitmentType = lnrpc.CommitmentType_ANCHORS + + case channelFeatures.OnlyContains( + lnwire.StaticRemoteKeyRequired, + ): + commitmentType = lnrpc.CommitmentType_STATIC_REMOTE_KEY + + case channelFeatures.OnlyContains(): + commitmentType = lnrpc.CommitmentType_LEGACY + + default: + log.Warnf("Unhandled commitment type "+ + "in channel acceptor request: %v", + req.OpenChanMsg.ChannelType) + } + } + acceptRequests[pendingChanID] = newRequest // A ChannelAcceptRequest has been received, send it to the client. @@ -273,6 +309,7 @@ func (r *RPCAcceptor) sendAcceptRequests(errChan chan error, CsvDelay: uint32(req.OpenChanMsg.CsvDelay), MaxAcceptedHtlcs: uint32(req.OpenChanMsg.MaxAcceptedHTLCs), ChannelFlags: uint32(req.OpenChanMsg.ChannelFlags), + CommitmentType: commitmentType, } if err := r.send(chanAcceptReq); err != nil { diff --git a/lnrpc/lightning.pb.go b/lnrpc/lightning.pb.go index 2877d1bacb7..31819c19233 100644 --- a/lnrpc/lightning.pb.go +++ b/lnrpc/lightning.pb.go @@ -2035,6 +2035,8 @@ type ChannelAcceptRequest struct { // A bit-field which the initiator uses to specify proposed channel // behavior. ChannelFlags uint32 `protobuf:"varint,13,opt,name=channel_flags,json=channelFlags,proto3" json:"channel_flags,omitempty"` + // The commitment type the initiator wishes to use for the proposed channel. + CommitmentType CommitmentType `protobuf:"varint,14,opt,name=commitment_type,json=commitmentType,proto3,enum=lnrpc.CommitmentType" json:"commitment_type,omitempty"` } func (x *ChannelAcceptRequest) Reset() { @@ -2160,6 +2162,13 @@ func (x *ChannelAcceptRequest) GetChannelFlags() uint32 { return 0 } +func (x *ChannelAcceptRequest) GetCommitmentType() CommitmentType { + if x != nil { + return x.CommitmentType + } + return CommitmentType_UNKNOWN_COMMITMENT_TYPE +} + type ChannelAcceptResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -14938,7 +14947,7 @@ var file_lightning_proto_rawDesc = []byte{ 0x48, 0x61, 0x73, 0x68, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x22, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x4a, 0x04, - 0x08, 0x03, 0x10, 0x04, 0x22, 0xda, 0x03, 0x0a, 0x14, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x08, 0x03, 0x10, 0x04, 0x22, 0x9a, 0x04, 0x0a, 0x14, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6e, 0x6f, 0x64, 0x65, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x1d, @@ -14968,7 +14977,11 @@ var file_lightning_proto_rawDesc = []byte{ 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x48, 0x74, 0x6c, 0x63, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x46, 0x6c, 0x61, 0x67, - 0x73, 0x22, 0xf3, 0x02, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, + 0x73, 0x12, 0x3e, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x22, 0xf3, 0x02, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, @@ -17461,271 +17474,272 @@ var file_lightning_proto_depIdxs = []int32{ 8, // 5: lnrpc.SendRequest.dest_features:type_name -> lnrpc.FeatureBit 106, // 6: lnrpc.SendResponse.payment_route:type_name -> lnrpc.Route 106, // 7: lnrpc.SendToRouteRequest.route:type_name -> lnrpc.Route - 184, // 8: lnrpc.EstimateFeeRequest.AddrToAmount:type_name -> lnrpc.EstimateFeeRequest.AddrToAmountEntry - 185, // 9: lnrpc.SendManyRequest.AddrToAmount:type_name -> lnrpc.SendManyRequest.AddrToAmountEntry - 18, // 10: lnrpc.ListUnspentResponse.utxos:type_name -> lnrpc.Utxo - 0, // 11: lnrpc.NewAddressRequest.type:type_name -> lnrpc.AddressType - 30, // 12: lnrpc.ConnectPeerRequest.addr:type_name -> lnrpc.LightningAddress - 49, // 13: lnrpc.Channel.pending_htlcs:type_name -> lnrpc.HTLC - 1, // 14: lnrpc.Channel.commitment_type:type_name -> lnrpc.CommitmentType - 50, // 15: lnrpc.Channel.local_constraints:type_name -> lnrpc.ChannelConstraints - 50, // 16: lnrpc.Channel.remote_constraints:type_name -> lnrpc.ChannelConstraints - 51, // 17: lnrpc.ListChannelsResponse.channels:type_name -> lnrpc.Channel - 9, // 18: lnrpc.ChannelCloseSummary.close_type:type_name -> lnrpc.ChannelCloseSummary.ClosureType - 2, // 19: lnrpc.ChannelCloseSummary.open_initiator:type_name -> lnrpc.Initiator - 2, // 20: lnrpc.ChannelCloseSummary.close_initiator:type_name -> lnrpc.Initiator - 55, // 21: lnrpc.ChannelCloseSummary.resolutions:type_name -> lnrpc.Resolution - 3, // 22: lnrpc.Resolution.resolution_type:type_name -> lnrpc.ResolutionType - 4, // 23: lnrpc.Resolution.outcome:type_name -> lnrpc.ResolutionOutcome - 29, // 24: lnrpc.Resolution.outpoint:type_name -> lnrpc.OutPoint - 54, // 25: lnrpc.ClosedChannelsResponse.channels:type_name -> lnrpc.ChannelCloseSummary - 10, // 26: lnrpc.Peer.sync_type:type_name -> lnrpc.Peer.SyncType - 186, // 27: lnrpc.Peer.features:type_name -> lnrpc.Peer.FeaturesEntry - 59, // 28: lnrpc.Peer.errors:type_name -> lnrpc.TimestampedError - 58, // 29: lnrpc.ListPeersResponse.peers:type_name -> lnrpc.Peer - 11, // 30: lnrpc.PeerEvent.type:type_name -> lnrpc.PeerEvent.EventType - 68, // 31: lnrpc.GetInfoResponse.chains:type_name -> lnrpc.Chain - 187, // 32: lnrpc.GetInfoResponse.features:type_name -> lnrpc.GetInfoResponse.FeaturesEntry - 28, // 33: lnrpc.ChannelOpenUpdate.channel_point:type_name -> lnrpc.ChannelPoint - 28, // 34: lnrpc.CloseChannelRequest.channel_point:type_name -> lnrpc.ChannelPoint - 74, // 35: lnrpc.CloseStatusUpdate.close_pending:type_name -> lnrpc.PendingUpdate - 71, // 36: lnrpc.CloseStatusUpdate.chan_close:type_name -> lnrpc.ChannelCloseUpdate - 82, // 37: lnrpc.OpenChannelRequest.funding_shim:type_name -> lnrpc.FundingShim - 1, // 38: lnrpc.OpenChannelRequest.commitment_type:type_name -> lnrpc.CommitmentType - 74, // 39: lnrpc.OpenStatusUpdate.chan_pending:type_name -> lnrpc.PendingUpdate - 70, // 40: lnrpc.OpenStatusUpdate.chan_open:type_name -> lnrpc.ChannelOpenUpdate - 75, // 41: lnrpc.OpenStatusUpdate.psbt_fund:type_name -> lnrpc.ReadyForPsbtFunding - 78, // 42: lnrpc.KeyDescriptor.key_loc:type_name -> lnrpc.KeyLocator - 28, // 43: lnrpc.ChanPointShim.chan_point:type_name -> lnrpc.ChannelPoint - 79, // 44: lnrpc.ChanPointShim.local_key:type_name -> lnrpc.KeyDescriptor - 80, // 45: lnrpc.FundingShim.chan_point_shim:type_name -> lnrpc.ChanPointShim - 81, // 46: lnrpc.FundingShim.psbt_shim:type_name -> lnrpc.PsbtShim - 82, // 47: lnrpc.FundingTransitionMsg.shim_register:type_name -> lnrpc.FundingShim - 83, // 48: lnrpc.FundingTransitionMsg.shim_cancel:type_name -> lnrpc.FundingShimCancel - 84, // 49: lnrpc.FundingTransitionMsg.psbt_verify:type_name -> lnrpc.FundingPsbtVerify - 85, // 50: lnrpc.FundingTransitionMsg.psbt_finalize:type_name -> lnrpc.FundingPsbtFinalize - 189, // 51: lnrpc.PendingChannelsResponse.pending_open_channels:type_name -> lnrpc.PendingChannelsResponse.PendingOpenChannel - 192, // 52: lnrpc.PendingChannelsResponse.pending_closing_channels:type_name -> lnrpc.PendingChannelsResponse.ClosedChannel - 193, // 53: lnrpc.PendingChannelsResponse.pending_force_closing_channels:type_name -> lnrpc.PendingChannelsResponse.ForceClosedChannel - 190, // 54: lnrpc.PendingChannelsResponse.waiting_close_channels:type_name -> lnrpc.PendingChannelsResponse.WaitingCloseChannel - 51, // 55: lnrpc.ChannelEventUpdate.open_channel:type_name -> lnrpc.Channel - 54, // 56: lnrpc.ChannelEventUpdate.closed_channel:type_name -> lnrpc.ChannelCloseSummary - 28, // 57: lnrpc.ChannelEventUpdate.active_channel:type_name -> lnrpc.ChannelPoint - 28, // 58: lnrpc.ChannelEventUpdate.inactive_channel:type_name -> lnrpc.ChannelPoint - 74, // 59: lnrpc.ChannelEventUpdate.pending_open_channel:type_name -> lnrpc.PendingUpdate - 13, // 60: lnrpc.ChannelEventUpdate.type:type_name -> lnrpc.ChannelEventUpdate.UpdateType - 194, // 61: lnrpc.WalletBalanceResponse.account_balance:type_name -> lnrpc.WalletBalanceResponse.AccountBalanceEntry - 96, // 62: lnrpc.ChannelBalanceResponse.local_balance:type_name -> lnrpc.Amount - 96, // 63: lnrpc.ChannelBalanceResponse.remote_balance:type_name -> lnrpc.Amount - 96, // 64: lnrpc.ChannelBalanceResponse.unsettled_local_balance:type_name -> lnrpc.Amount - 96, // 65: lnrpc.ChannelBalanceResponse.unsettled_remote_balance:type_name -> lnrpc.Amount - 96, // 66: lnrpc.ChannelBalanceResponse.pending_open_local_balance:type_name -> lnrpc.Amount - 96, // 67: lnrpc.ChannelBalanceResponse.pending_open_remote_balance:type_name -> lnrpc.Amount - 22, // 68: lnrpc.QueryRoutesRequest.fee_limit:type_name -> lnrpc.FeeLimit - 101, // 69: lnrpc.QueryRoutesRequest.ignored_edges:type_name -> lnrpc.EdgeLocator - 100, // 70: lnrpc.QueryRoutesRequest.ignored_pairs:type_name -> lnrpc.NodePair - 195, // 71: lnrpc.QueryRoutesRequest.dest_custom_records:type_name -> lnrpc.QueryRoutesRequest.DestCustomRecordsEntry - 129, // 72: lnrpc.QueryRoutesRequest.route_hints:type_name -> lnrpc.RouteHint - 8, // 73: lnrpc.QueryRoutesRequest.dest_features:type_name -> lnrpc.FeatureBit - 106, // 74: lnrpc.QueryRoutesResponse.routes:type_name -> lnrpc.Route - 104, // 75: lnrpc.Hop.mpp_record:type_name -> lnrpc.MPPRecord - 105, // 76: lnrpc.Hop.amp_record:type_name -> lnrpc.AMPRecord - 196, // 77: lnrpc.Hop.custom_records:type_name -> lnrpc.Hop.CustomRecordsEntry - 103, // 78: lnrpc.Route.hops:type_name -> lnrpc.Hop - 109, // 79: lnrpc.NodeInfo.node:type_name -> lnrpc.LightningNode - 112, // 80: lnrpc.NodeInfo.channels:type_name -> lnrpc.ChannelEdge - 110, // 81: lnrpc.LightningNode.addresses:type_name -> lnrpc.NodeAddress - 197, // 82: lnrpc.LightningNode.features:type_name -> lnrpc.LightningNode.FeaturesEntry - 111, // 83: lnrpc.ChannelEdge.node1_policy:type_name -> lnrpc.RoutingPolicy - 111, // 84: lnrpc.ChannelEdge.node2_policy:type_name -> lnrpc.RoutingPolicy - 109, // 85: lnrpc.ChannelGraph.nodes:type_name -> lnrpc.LightningNode - 112, // 86: lnrpc.ChannelGraph.edges:type_name -> lnrpc.ChannelEdge - 5, // 87: lnrpc.NodeMetricsRequest.types:type_name -> lnrpc.NodeMetricType - 198, // 88: lnrpc.NodeMetricsResponse.betweenness_centrality:type_name -> lnrpc.NodeMetricsResponse.BetweennessCentralityEntry - 125, // 89: lnrpc.GraphTopologyUpdate.node_updates:type_name -> lnrpc.NodeUpdate - 126, // 90: lnrpc.GraphTopologyUpdate.channel_updates:type_name -> lnrpc.ChannelEdgeUpdate - 127, // 91: lnrpc.GraphTopologyUpdate.closed_chans:type_name -> lnrpc.ClosedChannelUpdate - 110, // 92: lnrpc.NodeUpdate.node_addresses:type_name -> lnrpc.NodeAddress - 199, // 93: lnrpc.NodeUpdate.features:type_name -> lnrpc.NodeUpdate.FeaturesEntry - 28, // 94: lnrpc.ChannelEdgeUpdate.chan_point:type_name -> lnrpc.ChannelPoint - 111, // 95: lnrpc.ChannelEdgeUpdate.routing_policy:type_name -> lnrpc.RoutingPolicy - 28, // 96: lnrpc.ClosedChannelUpdate.chan_point:type_name -> lnrpc.ChannelPoint - 128, // 97: lnrpc.RouteHint.hop_hints:type_name -> lnrpc.HopHint - 129, // 98: lnrpc.Invoice.route_hints:type_name -> lnrpc.RouteHint - 14, // 99: lnrpc.Invoice.state:type_name -> lnrpc.Invoice.InvoiceState - 131, // 100: lnrpc.Invoice.htlcs:type_name -> lnrpc.InvoiceHTLC - 200, // 101: lnrpc.Invoice.features:type_name -> lnrpc.Invoice.FeaturesEntry - 6, // 102: lnrpc.InvoiceHTLC.state:type_name -> lnrpc.InvoiceHTLCState - 201, // 103: lnrpc.InvoiceHTLC.custom_records:type_name -> lnrpc.InvoiceHTLC.CustomRecordsEntry - 132, // 104: lnrpc.InvoiceHTLC.amp:type_name -> lnrpc.AMP - 130, // 105: lnrpc.ListInvoiceResponse.invoices:type_name -> lnrpc.Invoice - 15, // 106: lnrpc.Payment.status:type_name -> lnrpc.Payment.PaymentStatus - 139, // 107: lnrpc.Payment.htlcs:type_name -> lnrpc.HTLCAttempt - 7, // 108: lnrpc.Payment.failure_reason:type_name -> lnrpc.PaymentFailureReason - 16, // 109: lnrpc.HTLCAttempt.status:type_name -> lnrpc.HTLCAttempt.HTLCStatus - 106, // 110: lnrpc.HTLCAttempt.route:type_name -> lnrpc.Route - 179, // 111: lnrpc.HTLCAttempt.failure:type_name -> lnrpc.Failure - 138, // 112: lnrpc.ListPaymentsResponse.payments:type_name -> lnrpc.Payment - 28, // 113: lnrpc.AbandonChannelRequest.channel_point:type_name -> lnrpc.ChannelPoint - 129, // 114: lnrpc.PayReq.route_hints:type_name -> lnrpc.RouteHint - 202, // 115: lnrpc.PayReq.features:type_name -> lnrpc.PayReq.FeaturesEntry - 152, // 116: lnrpc.FeeReportResponse.channel_fees:type_name -> lnrpc.ChannelFeeReport - 28, // 117: lnrpc.PolicyUpdateRequest.chan_point:type_name -> lnrpc.ChannelPoint - 157, // 118: lnrpc.ForwardingHistoryResponse.forwarding_events:type_name -> lnrpc.ForwardingEvent - 28, // 119: lnrpc.ExportChannelBackupRequest.chan_point:type_name -> lnrpc.ChannelPoint - 28, // 120: lnrpc.ChannelBackup.chan_point:type_name -> lnrpc.ChannelPoint - 28, // 121: lnrpc.MultiChanBackup.chan_points:type_name -> lnrpc.ChannelPoint - 164, // 122: lnrpc.ChanBackupSnapshot.single_chan_backups:type_name -> lnrpc.ChannelBackups - 161, // 123: lnrpc.ChanBackupSnapshot.multi_chan_backup:type_name -> lnrpc.MultiChanBackup - 160, // 124: lnrpc.ChannelBackups.chan_backups:type_name -> lnrpc.ChannelBackup - 164, // 125: lnrpc.RestoreChanBackupRequest.chan_backups:type_name -> lnrpc.ChannelBackups - 169, // 126: lnrpc.BakeMacaroonRequest.permissions:type_name -> lnrpc.MacaroonPermission - 169, // 127: lnrpc.MacaroonPermissionList.permissions:type_name -> lnrpc.MacaroonPermission - 203, // 128: lnrpc.ListPermissionsResponse.method_permissions:type_name -> lnrpc.ListPermissionsResponse.MethodPermissionsEntry - 17, // 129: lnrpc.Failure.code:type_name -> lnrpc.Failure.FailureCode - 180, // 130: lnrpc.Failure.channel_update:type_name -> lnrpc.ChannelUpdate - 182, // 131: lnrpc.MacaroonId.ops:type_name -> lnrpc.Op - 150, // 132: lnrpc.Peer.FeaturesEntry.value:type_name -> lnrpc.Feature - 150, // 133: lnrpc.GetInfoResponse.FeaturesEntry.value:type_name -> lnrpc.Feature - 2, // 134: lnrpc.PendingChannelsResponse.PendingChannel.initiator:type_name -> lnrpc.Initiator - 1, // 135: lnrpc.PendingChannelsResponse.PendingChannel.commitment_type:type_name -> lnrpc.CommitmentType - 188, // 136: lnrpc.PendingChannelsResponse.PendingOpenChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel - 188, // 137: lnrpc.PendingChannelsResponse.WaitingCloseChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel - 191, // 138: lnrpc.PendingChannelsResponse.WaitingCloseChannel.commitments:type_name -> lnrpc.PendingChannelsResponse.Commitments - 188, // 139: lnrpc.PendingChannelsResponse.ClosedChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel - 188, // 140: lnrpc.PendingChannelsResponse.ForceClosedChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel - 88, // 141: lnrpc.PendingChannelsResponse.ForceClosedChannel.pending_htlcs:type_name -> lnrpc.PendingHTLC - 12, // 142: lnrpc.PendingChannelsResponse.ForceClosedChannel.anchor:type_name -> lnrpc.PendingChannelsResponse.ForceClosedChannel.AnchorState - 93, // 143: lnrpc.WalletBalanceResponse.AccountBalanceEntry.value:type_name -> lnrpc.WalletAccountBalance - 150, // 144: lnrpc.LightningNode.FeaturesEntry.value:type_name -> lnrpc.Feature - 117, // 145: lnrpc.NodeMetricsResponse.BetweennessCentralityEntry.value:type_name -> lnrpc.FloatMetric - 150, // 146: lnrpc.NodeUpdate.FeaturesEntry.value:type_name -> lnrpc.Feature - 150, // 147: lnrpc.Invoice.FeaturesEntry.value:type_name -> lnrpc.Feature - 150, // 148: lnrpc.PayReq.FeaturesEntry.value:type_name -> lnrpc.Feature - 176, // 149: lnrpc.ListPermissionsResponse.MethodPermissionsEntry.value:type_name -> lnrpc.MacaroonPermissionList - 94, // 150: lnrpc.Lightning.WalletBalance:input_type -> lnrpc.WalletBalanceRequest - 97, // 151: lnrpc.Lightning.ChannelBalance:input_type -> lnrpc.ChannelBalanceRequest - 20, // 152: lnrpc.Lightning.GetTransactions:input_type -> lnrpc.GetTransactionsRequest - 31, // 153: lnrpc.Lightning.EstimateFee:input_type -> lnrpc.EstimateFeeRequest - 35, // 154: lnrpc.Lightning.SendCoins:input_type -> lnrpc.SendCoinsRequest - 37, // 155: lnrpc.Lightning.ListUnspent:input_type -> lnrpc.ListUnspentRequest - 20, // 156: lnrpc.Lightning.SubscribeTransactions:input_type -> lnrpc.GetTransactionsRequest - 33, // 157: lnrpc.Lightning.SendMany:input_type -> lnrpc.SendManyRequest - 39, // 158: lnrpc.Lightning.NewAddress:input_type -> lnrpc.NewAddressRequest - 41, // 159: lnrpc.Lightning.SignMessage:input_type -> lnrpc.SignMessageRequest - 43, // 160: lnrpc.Lightning.VerifyMessage:input_type -> lnrpc.VerifyMessageRequest - 45, // 161: lnrpc.Lightning.ConnectPeer:input_type -> lnrpc.ConnectPeerRequest - 47, // 162: lnrpc.Lightning.DisconnectPeer:input_type -> lnrpc.DisconnectPeerRequest - 60, // 163: lnrpc.Lightning.ListPeers:input_type -> lnrpc.ListPeersRequest - 62, // 164: lnrpc.Lightning.SubscribePeerEvents:input_type -> lnrpc.PeerEventSubscription - 64, // 165: lnrpc.Lightning.GetInfo:input_type -> lnrpc.GetInfoRequest - 66, // 166: lnrpc.Lightning.GetRecoveryInfo:input_type -> lnrpc.GetRecoveryInfoRequest - 89, // 167: lnrpc.Lightning.PendingChannels:input_type -> lnrpc.PendingChannelsRequest - 52, // 168: lnrpc.Lightning.ListChannels:input_type -> lnrpc.ListChannelsRequest - 91, // 169: lnrpc.Lightning.SubscribeChannelEvents:input_type -> lnrpc.ChannelEventSubscription - 56, // 170: lnrpc.Lightning.ClosedChannels:input_type -> lnrpc.ClosedChannelsRequest - 76, // 171: lnrpc.Lightning.OpenChannelSync:input_type -> lnrpc.OpenChannelRequest - 76, // 172: lnrpc.Lightning.OpenChannel:input_type -> lnrpc.OpenChannelRequest - 86, // 173: lnrpc.Lightning.FundingStateStep:input_type -> lnrpc.FundingTransitionMsg - 27, // 174: lnrpc.Lightning.ChannelAcceptor:input_type -> lnrpc.ChannelAcceptResponse - 72, // 175: lnrpc.Lightning.CloseChannel:input_type -> lnrpc.CloseChannelRequest - 144, // 176: lnrpc.Lightning.AbandonChannel:input_type -> lnrpc.AbandonChannelRequest - 23, // 177: lnrpc.Lightning.SendPayment:input_type -> lnrpc.SendRequest - 23, // 178: lnrpc.Lightning.SendPaymentSync:input_type -> lnrpc.SendRequest - 25, // 179: lnrpc.Lightning.SendToRoute:input_type -> lnrpc.SendToRouteRequest - 25, // 180: lnrpc.Lightning.SendToRouteSync:input_type -> lnrpc.SendToRouteRequest - 130, // 181: lnrpc.Lightning.AddInvoice:input_type -> lnrpc.Invoice - 135, // 182: lnrpc.Lightning.ListInvoices:input_type -> lnrpc.ListInvoiceRequest - 134, // 183: lnrpc.Lightning.LookupInvoice:input_type -> lnrpc.PaymentHash - 137, // 184: lnrpc.Lightning.SubscribeInvoices:input_type -> lnrpc.InvoiceSubscription - 148, // 185: lnrpc.Lightning.DecodePayReq:input_type -> lnrpc.PayReqString - 140, // 186: lnrpc.Lightning.ListPayments:input_type -> lnrpc.ListPaymentsRequest - 142, // 187: lnrpc.Lightning.DeleteAllPayments:input_type -> lnrpc.DeleteAllPaymentsRequest - 113, // 188: lnrpc.Lightning.DescribeGraph:input_type -> lnrpc.ChannelGraphRequest - 115, // 189: lnrpc.Lightning.GetNodeMetrics:input_type -> lnrpc.NodeMetricsRequest - 118, // 190: lnrpc.Lightning.GetChanInfo:input_type -> lnrpc.ChanInfoRequest - 107, // 191: lnrpc.Lightning.GetNodeInfo:input_type -> lnrpc.NodeInfoRequest - 99, // 192: lnrpc.Lightning.QueryRoutes:input_type -> lnrpc.QueryRoutesRequest - 119, // 193: lnrpc.Lightning.GetNetworkInfo:input_type -> lnrpc.NetworkInfoRequest - 121, // 194: lnrpc.Lightning.StopDaemon:input_type -> lnrpc.StopRequest - 123, // 195: lnrpc.Lightning.SubscribeChannelGraph:input_type -> lnrpc.GraphTopologySubscription - 146, // 196: lnrpc.Lightning.DebugLevel:input_type -> lnrpc.DebugLevelRequest - 151, // 197: lnrpc.Lightning.FeeReport:input_type -> lnrpc.FeeReportRequest - 154, // 198: lnrpc.Lightning.UpdateChannelPolicy:input_type -> lnrpc.PolicyUpdateRequest - 156, // 199: lnrpc.Lightning.ForwardingHistory:input_type -> lnrpc.ForwardingHistoryRequest - 159, // 200: lnrpc.Lightning.ExportChannelBackup:input_type -> lnrpc.ExportChannelBackupRequest - 162, // 201: lnrpc.Lightning.ExportAllChannelBackups:input_type -> lnrpc.ChanBackupExportRequest - 163, // 202: lnrpc.Lightning.VerifyChanBackup:input_type -> lnrpc.ChanBackupSnapshot - 165, // 203: lnrpc.Lightning.RestoreChannelBackups:input_type -> lnrpc.RestoreChanBackupRequest - 167, // 204: lnrpc.Lightning.SubscribeChannelBackups:input_type -> lnrpc.ChannelBackupSubscription - 170, // 205: lnrpc.Lightning.BakeMacaroon:input_type -> lnrpc.BakeMacaroonRequest - 172, // 206: lnrpc.Lightning.ListMacaroonIDs:input_type -> lnrpc.ListMacaroonIDsRequest - 174, // 207: lnrpc.Lightning.DeleteMacaroonID:input_type -> lnrpc.DeleteMacaroonIDRequest - 177, // 208: lnrpc.Lightning.ListPermissions:input_type -> lnrpc.ListPermissionsRequest - 95, // 209: lnrpc.Lightning.WalletBalance:output_type -> lnrpc.WalletBalanceResponse - 98, // 210: lnrpc.Lightning.ChannelBalance:output_type -> lnrpc.ChannelBalanceResponse - 21, // 211: lnrpc.Lightning.GetTransactions:output_type -> lnrpc.TransactionDetails - 32, // 212: lnrpc.Lightning.EstimateFee:output_type -> lnrpc.EstimateFeeResponse - 36, // 213: lnrpc.Lightning.SendCoins:output_type -> lnrpc.SendCoinsResponse - 38, // 214: lnrpc.Lightning.ListUnspent:output_type -> lnrpc.ListUnspentResponse - 19, // 215: lnrpc.Lightning.SubscribeTransactions:output_type -> lnrpc.Transaction - 34, // 216: lnrpc.Lightning.SendMany:output_type -> lnrpc.SendManyResponse - 40, // 217: lnrpc.Lightning.NewAddress:output_type -> lnrpc.NewAddressResponse - 42, // 218: lnrpc.Lightning.SignMessage:output_type -> lnrpc.SignMessageResponse - 44, // 219: lnrpc.Lightning.VerifyMessage:output_type -> lnrpc.VerifyMessageResponse - 46, // 220: lnrpc.Lightning.ConnectPeer:output_type -> lnrpc.ConnectPeerResponse - 48, // 221: lnrpc.Lightning.DisconnectPeer:output_type -> lnrpc.DisconnectPeerResponse - 61, // 222: lnrpc.Lightning.ListPeers:output_type -> lnrpc.ListPeersResponse - 63, // 223: lnrpc.Lightning.SubscribePeerEvents:output_type -> lnrpc.PeerEvent - 65, // 224: lnrpc.Lightning.GetInfo:output_type -> lnrpc.GetInfoResponse - 67, // 225: lnrpc.Lightning.GetRecoveryInfo:output_type -> lnrpc.GetRecoveryInfoResponse - 90, // 226: lnrpc.Lightning.PendingChannels:output_type -> lnrpc.PendingChannelsResponse - 53, // 227: lnrpc.Lightning.ListChannels:output_type -> lnrpc.ListChannelsResponse - 92, // 228: lnrpc.Lightning.SubscribeChannelEvents:output_type -> lnrpc.ChannelEventUpdate - 57, // 229: lnrpc.Lightning.ClosedChannels:output_type -> lnrpc.ClosedChannelsResponse - 28, // 230: lnrpc.Lightning.OpenChannelSync:output_type -> lnrpc.ChannelPoint - 77, // 231: lnrpc.Lightning.OpenChannel:output_type -> lnrpc.OpenStatusUpdate - 87, // 232: lnrpc.Lightning.FundingStateStep:output_type -> lnrpc.FundingStateStepResp - 26, // 233: lnrpc.Lightning.ChannelAcceptor:output_type -> lnrpc.ChannelAcceptRequest - 73, // 234: lnrpc.Lightning.CloseChannel:output_type -> lnrpc.CloseStatusUpdate - 145, // 235: lnrpc.Lightning.AbandonChannel:output_type -> lnrpc.AbandonChannelResponse - 24, // 236: lnrpc.Lightning.SendPayment:output_type -> lnrpc.SendResponse - 24, // 237: lnrpc.Lightning.SendPaymentSync:output_type -> lnrpc.SendResponse - 24, // 238: lnrpc.Lightning.SendToRoute:output_type -> lnrpc.SendResponse - 24, // 239: lnrpc.Lightning.SendToRouteSync:output_type -> lnrpc.SendResponse - 133, // 240: lnrpc.Lightning.AddInvoice:output_type -> lnrpc.AddInvoiceResponse - 136, // 241: lnrpc.Lightning.ListInvoices:output_type -> lnrpc.ListInvoiceResponse - 130, // 242: lnrpc.Lightning.LookupInvoice:output_type -> lnrpc.Invoice - 130, // 243: lnrpc.Lightning.SubscribeInvoices:output_type -> lnrpc.Invoice - 149, // 244: lnrpc.Lightning.DecodePayReq:output_type -> lnrpc.PayReq - 141, // 245: lnrpc.Lightning.ListPayments:output_type -> lnrpc.ListPaymentsResponse - 143, // 246: lnrpc.Lightning.DeleteAllPayments:output_type -> lnrpc.DeleteAllPaymentsResponse - 114, // 247: lnrpc.Lightning.DescribeGraph:output_type -> lnrpc.ChannelGraph - 116, // 248: lnrpc.Lightning.GetNodeMetrics:output_type -> lnrpc.NodeMetricsResponse - 112, // 249: lnrpc.Lightning.GetChanInfo:output_type -> lnrpc.ChannelEdge - 108, // 250: lnrpc.Lightning.GetNodeInfo:output_type -> lnrpc.NodeInfo - 102, // 251: lnrpc.Lightning.QueryRoutes:output_type -> lnrpc.QueryRoutesResponse - 120, // 252: lnrpc.Lightning.GetNetworkInfo:output_type -> lnrpc.NetworkInfo - 122, // 253: lnrpc.Lightning.StopDaemon:output_type -> lnrpc.StopResponse - 124, // 254: lnrpc.Lightning.SubscribeChannelGraph:output_type -> lnrpc.GraphTopologyUpdate - 147, // 255: lnrpc.Lightning.DebugLevel:output_type -> lnrpc.DebugLevelResponse - 153, // 256: lnrpc.Lightning.FeeReport:output_type -> lnrpc.FeeReportResponse - 155, // 257: lnrpc.Lightning.UpdateChannelPolicy:output_type -> lnrpc.PolicyUpdateResponse - 158, // 258: lnrpc.Lightning.ForwardingHistory:output_type -> lnrpc.ForwardingHistoryResponse - 160, // 259: lnrpc.Lightning.ExportChannelBackup:output_type -> lnrpc.ChannelBackup - 163, // 260: lnrpc.Lightning.ExportAllChannelBackups:output_type -> lnrpc.ChanBackupSnapshot - 168, // 261: lnrpc.Lightning.VerifyChanBackup:output_type -> lnrpc.VerifyChanBackupResponse - 166, // 262: lnrpc.Lightning.RestoreChannelBackups:output_type -> lnrpc.RestoreBackupResponse - 163, // 263: lnrpc.Lightning.SubscribeChannelBackups:output_type -> lnrpc.ChanBackupSnapshot - 171, // 264: lnrpc.Lightning.BakeMacaroon:output_type -> lnrpc.BakeMacaroonResponse - 173, // 265: lnrpc.Lightning.ListMacaroonIDs:output_type -> lnrpc.ListMacaroonIDsResponse - 175, // 266: lnrpc.Lightning.DeleteMacaroonID:output_type -> lnrpc.DeleteMacaroonIDResponse - 178, // 267: lnrpc.Lightning.ListPermissions:output_type -> lnrpc.ListPermissionsResponse - 209, // [209:268] is the sub-list for method output_type - 150, // [150:209] is the sub-list for method input_type - 150, // [150:150] is the sub-list for extension type_name - 150, // [150:150] is the sub-list for extension extendee - 0, // [0:150] is the sub-list for field type_name + 1, // 8: lnrpc.ChannelAcceptRequest.commitment_type:type_name -> lnrpc.CommitmentType + 184, // 9: lnrpc.EstimateFeeRequest.AddrToAmount:type_name -> lnrpc.EstimateFeeRequest.AddrToAmountEntry + 185, // 10: lnrpc.SendManyRequest.AddrToAmount:type_name -> lnrpc.SendManyRequest.AddrToAmountEntry + 18, // 11: lnrpc.ListUnspentResponse.utxos:type_name -> lnrpc.Utxo + 0, // 12: lnrpc.NewAddressRequest.type:type_name -> lnrpc.AddressType + 30, // 13: lnrpc.ConnectPeerRequest.addr:type_name -> lnrpc.LightningAddress + 49, // 14: lnrpc.Channel.pending_htlcs:type_name -> lnrpc.HTLC + 1, // 15: lnrpc.Channel.commitment_type:type_name -> lnrpc.CommitmentType + 50, // 16: lnrpc.Channel.local_constraints:type_name -> lnrpc.ChannelConstraints + 50, // 17: lnrpc.Channel.remote_constraints:type_name -> lnrpc.ChannelConstraints + 51, // 18: lnrpc.ListChannelsResponse.channels:type_name -> lnrpc.Channel + 9, // 19: lnrpc.ChannelCloseSummary.close_type:type_name -> lnrpc.ChannelCloseSummary.ClosureType + 2, // 20: lnrpc.ChannelCloseSummary.open_initiator:type_name -> lnrpc.Initiator + 2, // 21: lnrpc.ChannelCloseSummary.close_initiator:type_name -> lnrpc.Initiator + 55, // 22: lnrpc.ChannelCloseSummary.resolutions:type_name -> lnrpc.Resolution + 3, // 23: lnrpc.Resolution.resolution_type:type_name -> lnrpc.ResolutionType + 4, // 24: lnrpc.Resolution.outcome:type_name -> lnrpc.ResolutionOutcome + 29, // 25: lnrpc.Resolution.outpoint:type_name -> lnrpc.OutPoint + 54, // 26: lnrpc.ClosedChannelsResponse.channels:type_name -> lnrpc.ChannelCloseSummary + 10, // 27: lnrpc.Peer.sync_type:type_name -> lnrpc.Peer.SyncType + 186, // 28: lnrpc.Peer.features:type_name -> lnrpc.Peer.FeaturesEntry + 59, // 29: lnrpc.Peer.errors:type_name -> lnrpc.TimestampedError + 58, // 30: lnrpc.ListPeersResponse.peers:type_name -> lnrpc.Peer + 11, // 31: lnrpc.PeerEvent.type:type_name -> lnrpc.PeerEvent.EventType + 68, // 32: lnrpc.GetInfoResponse.chains:type_name -> lnrpc.Chain + 187, // 33: lnrpc.GetInfoResponse.features:type_name -> lnrpc.GetInfoResponse.FeaturesEntry + 28, // 34: lnrpc.ChannelOpenUpdate.channel_point:type_name -> lnrpc.ChannelPoint + 28, // 35: lnrpc.CloseChannelRequest.channel_point:type_name -> lnrpc.ChannelPoint + 74, // 36: lnrpc.CloseStatusUpdate.close_pending:type_name -> lnrpc.PendingUpdate + 71, // 37: lnrpc.CloseStatusUpdate.chan_close:type_name -> lnrpc.ChannelCloseUpdate + 82, // 38: lnrpc.OpenChannelRequest.funding_shim:type_name -> lnrpc.FundingShim + 1, // 39: lnrpc.OpenChannelRequest.commitment_type:type_name -> lnrpc.CommitmentType + 74, // 40: lnrpc.OpenStatusUpdate.chan_pending:type_name -> lnrpc.PendingUpdate + 70, // 41: lnrpc.OpenStatusUpdate.chan_open:type_name -> lnrpc.ChannelOpenUpdate + 75, // 42: lnrpc.OpenStatusUpdate.psbt_fund:type_name -> lnrpc.ReadyForPsbtFunding + 78, // 43: lnrpc.KeyDescriptor.key_loc:type_name -> lnrpc.KeyLocator + 28, // 44: lnrpc.ChanPointShim.chan_point:type_name -> lnrpc.ChannelPoint + 79, // 45: lnrpc.ChanPointShim.local_key:type_name -> lnrpc.KeyDescriptor + 80, // 46: lnrpc.FundingShim.chan_point_shim:type_name -> lnrpc.ChanPointShim + 81, // 47: lnrpc.FundingShim.psbt_shim:type_name -> lnrpc.PsbtShim + 82, // 48: lnrpc.FundingTransitionMsg.shim_register:type_name -> lnrpc.FundingShim + 83, // 49: lnrpc.FundingTransitionMsg.shim_cancel:type_name -> lnrpc.FundingShimCancel + 84, // 50: lnrpc.FundingTransitionMsg.psbt_verify:type_name -> lnrpc.FundingPsbtVerify + 85, // 51: lnrpc.FundingTransitionMsg.psbt_finalize:type_name -> lnrpc.FundingPsbtFinalize + 189, // 52: lnrpc.PendingChannelsResponse.pending_open_channels:type_name -> lnrpc.PendingChannelsResponse.PendingOpenChannel + 192, // 53: lnrpc.PendingChannelsResponse.pending_closing_channels:type_name -> lnrpc.PendingChannelsResponse.ClosedChannel + 193, // 54: lnrpc.PendingChannelsResponse.pending_force_closing_channels:type_name -> lnrpc.PendingChannelsResponse.ForceClosedChannel + 190, // 55: lnrpc.PendingChannelsResponse.waiting_close_channels:type_name -> lnrpc.PendingChannelsResponse.WaitingCloseChannel + 51, // 56: lnrpc.ChannelEventUpdate.open_channel:type_name -> lnrpc.Channel + 54, // 57: lnrpc.ChannelEventUpdate.closed_channel:type_name -> lnrpc.ChannelCloseSummary + 28, // 58: lnrpc.ChannelEventUpdate.active_channel:type_name -> lnrpc.ChannelPoint + 28, // 59: lnrpc.ChannelEventUpdate.inactive_channel:type_name -> lnrpc.ChannelPoint + 74, // 60: lnrpc.ChannelEventUpdate.pending_open_channel:type_name -> lnrpc.PendingUpdate + 13, // 61: lnrpc.ChannelEventUpdate.type:type_name -> lnrpc.ChannelEventUpdate.UpdateType + 194, // 62: lnrpc.WalletBalanceResponse.account_balance:type_name -> lnrpc.WalletBalanceResponse.AccountBalanceEntry + 96, // 63: lnrpc.ChannelBalanceResponse.local_balance:type_name -> lnrpc.Amount + 96, // 64: lnrpc.ChannelBalanceResponse.remote_balance:type_name -> lnrpc.Amount + 96, // 65: lnrpc.ChannelBalanceResponse.unsettled_local_balance:type_name -> lnrpc.Amount + 96, // 66: lnrpc.ChannelBalanceResponse.unsettled_remote_balance:type_name -> lnrpc.Amount + 96, // 67: lnrpc.ChannelBalanceResponse.pending_open_local_balance:type_name -> lnrpc.Amount + 96, // 68: lnrpc.ChannelBalanceResponse.pending_open_remote_balance:type_name -> lnrpc.Amount + 22, // 69: lnrpc.QueryRoutesRequest.fee_limit:type_name -> lnrpc.FeeLimit + 101, // 70: lnrpc.QueryRoutesRequest.ignored_edges:type_name -> lnrpc.EdgeLocator + 100, // 71: lnrpc.QueryRoutesRequest.ignored_pairs:type_name -> lnrpc.NodePair + 195, // 72: lnrpc.QueryRoutesRequest.dest_custom_records:type_name -> lnrpc.QueryRoutesRequest.DestCustomRecordsEntry + 129, // 73: lnrpc.QueryRoutesRequest.route_hints:type_name -> lnrpc.RouteHint + 8, // 74: lnrpc.QueryRoutesRequest.dest_features:type_name -> lnrpc.FeatureBit + 106, // 75: lnrpc.QueryRoutesResponse.routes:type_name -> lnrpc.Route + 104, // 76: lnrpc.Hop.mpp_record:type_name -> lnrpc.MPPRecord + 105, // 77: lnrpc.Hop.amp_record:type_name -> lnrpc.AMPRecord + 196, // 78: lnrpc.Hop.custom_records:type_name -> lnrpc.Hop.CustomRecordsEntry + 103, // 79: lnrpc.Route.hops:type_name -> lnrpc.Hop + 109, // 80: lnrpc.NodeInfo.node:type_name -> lnrpc.LightningNode + 112, // 81: lnrpc.NodeInfo.channels:type_name -> lnrpc.ChannelEdge + 110, // 82: lnrpc.LightningNode.addresses:type_name -> lnrpc.NodeAddress + 197, // 83: lnrpc.LightningNode.features:type_name -> lnrpc.LightningNode.FeaturesEntry + 111, // 84: lnrpc.ChannelEdge.node1_policy:type_name -> lnrpc.RoutingPolicy + 111, // 85: lnrpc.ChannelEdge.node2_policy:type_name -> lnrpc.RoutingPolicy + 109, // 86: lnrpc.ChannelGraph.nodes:type_name -> lnrpc.LightningNode + 112, // 87: lnrpc.ChannelGraph.edges:type_name -> lnrpc.ChannelEdge + 5, // 88: lnrpc.NodeMetricsRequest.types:type_name -> lnrpc.NodeMetricType + 198, // 89: lnrpc.NodeMetricsResponse.betweenness_centrality:type_name -> lnrpc.NodeMetricsResponse.BetweennessCentralityEntry + 125, // 90: lnrpc.GraphTopologyUpdate.node_updates:type_name -> lnrpc.NodeUpdate + 126, // 91: lnrpc.GraphTopologyUpdate.channel_updates:type_name -> lnrpc.ChannelEdgeUpdate + 127, // 92: lnrpc.GraphTopologyUpdate.closed_chans:type_name -> lnrpc.ClosedChannelUpdate + 110, // 93: lnrpc.NodeUpdate.node_addresses:type_name -> lnrpc.NodeAddress + 199, // 94: lnrpc.NodeUpdate.features:type_name -> lnrpc.NodeUpdate.FeaturesEntry + 28, // 95: lnrpc.ChannelEdgeUpdate.chan_point:type_name -> lnrpc.ChannelPoint + 111, // 96: lnrpc.ChannelEdgeUpdate.routing_policy:type_name -> lnrpc.RoutingPolicy + 28, // 97: lnrpc.ClosedChannelUpdate.chan_point:type_name -> lnrpc.ChannelPoint + 128, // 98: lnrpc.RouteHint.hop_hints:type_name -> lnrpc.HopHint + 129, // 99: lnrpc.Invoice.route_hints:type_name -> lnrpc.RouteHint + 14, // 100: lnrpc.Invoice.state:type_name -> lnrpc.Invoice.InvoiceState + 131, // 101: lnrpc.Invoice.htlcs:type_name -> lnrpc.InvoiceHTLC + 200, // 102: lnrpc.Invoice.features:type_name -> lnrpc.Invoice.FeaturesEntry + 6, // 103: lnrpc.InvoiceHTLC.state:type_name -> lnrpc.InvoiceHTLCState + 201, // 104: lnrpc.InvoiceHTLC.custom_records:type_name -> lnrpc.InvoiceHTLC.CustomRecordsEntry + 132, // 105: lnrpc.InvoiceHTLC.amp:type_name -> lnrpc.AMP + 130, // 106: lnrpc.ListInvoiceResponse.invoices:type_name -> lnrpc.Invoice + 15, // 107: lnrpc.Payment.status:type_name -> lnrpc.Payment.PaymentStatus + 139, // 108: lnrpc.Payment.htlcs:type_name -> lnrpc.HTLCAttempt + 7, // 109: lnrpc.Payment.failure_reason:type_name -> lnrpc.PaymentFailureReason + 16, // 110: lnrpc.HTLCAttempt.status:type_name -> lnrpc.HTLCAttempt.HTLCStatus + 106, // 111: lnrpc.HTLCAttempt.route:type_name -> lnrpc.Route + 179, // 112: lnrpc.HTLCAttempt.failure:type_name -> lnrpc.Failure + 138, // 113: lnrpc.ListPaymentsResponse.payments:type_name -> lnrpc.Payment + 28, // 114: lnrpc.AbandonChannelRequest.channel_point:type_name -> lnrpc.ChannelPoint + 129, // 115: lnrpc.PayReq.route_hints:type_name -> lnrpc.RouteHint + 202, // 116: lnrpc.PayReq.features:type_name -> lnrpc.PayReq.FeaturesEntry + 152, // 117: lnrpc.FeeReportResponse.channel_fees:type_name -> lnrpc.ChannelFeeReport + 28, // 118: lnrpc.PolicyUpdateRequest.chan_point:type_name -> lnrpc.ChannelPoint + 157, // 119: lnrpc.ForwardingHistoryResponse.forwarding_events:type_name -> lnrpc.ForwardingEvent + 28, // 120: lnrpc.ExportChannelBackupRequest.chan_point:type_name -> lnrpc.ChannelPoint + 28, // 121: lnrpc.ChannelBackup.chan_point:type_name -> lnrpc.ChannelPoint + 28, // 122: lnrpc.MultiChanBackup.chan_points:type_name -> lnrpc.ChannelPoint + 164, // 123: lnrpc.ChanBackupSnapshot.single_chan_backups:type_name -> lnrpc.ChannelBackups + 161, // 124: lnrpc.ChanBackupSnapshot.multi_chan_backup:type_name -> lnrpc.MultiChanBackup + 160, // 125: lnrpc.ChannelBackups.chan_backups:type_name -> lnrpc.ChannelBackup + 164, // 126: lnrpc.RestoreChanBackupRequest.chan_backups:type_name -> lnrpc.ChannelBackups + 169, // 127: lnrpc.BakeMacaroonRequest.permissions:type_name -> lnrpc.MacaroonPermission + 169, // 128: lnrpc.MacaroonPermissionList.permissions:type_name -> lnrpc.MacaroonPermission + 203, // 129: lnrpc.ListPermissionsResponse.method_permissions:type_name -> lnrpc.ListPermissionsResponse.MethodPermissionsEntry + 17, // 130: lnrpc.Failure.code:type_name -> lnrpc.Failure.FailureCode + 180, // 131: lnrpc.Failure.channel_update:type_name -> lnrpc.ChannelUpdate + 182, // 132: lnrpc.MacaroonId.ops:type_name -> lnrpc.Op + 150, // 133: lnrpc.Peer.FeaturesEntry.value:type_name -> lnrpc.Feature + 150, // 134: lnrpc.GetInfoResponse.FeaturesEntry.value:type_name -> lnrpc.Feature + 2, // 135: lnrpc.PendingChannelsResponse.PendingChannel.initiator:type_name -> lnrpc.Initiator + 1, // 136: lnrpc.PendingChannelsResponse.PendingChannel.commitment_type:type_name -> lnrpc.CommitmentType + 188, // 137: lnrpc.PendingChannelsResponse.PendingOpenChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel + 188, // 138: lnrpc.PendingChannelsResponse.WaitingCloseChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel + 191, // 139: lnrpc.PendingChannelsResponse.WaitingCloseChannel.commitments:type_name -> lnrpc.PendingChannelsResponse.Commitments + 188, // 140: lnrpc.PendingChannelsResponse.ClosedChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel + 188, // 141: lnrpc.PendingChannelsResponse.ForceClosedChannel.channel:type_name -> lnrpc.PendingChannelsResponse.PendingChannel + 88, // 142: lnrpc.PendingChannelsResponse.ForceClosedChannel.pending_htlcs:type_name -> lnrpc.PendingHTLC + 12, // 143: lnrpc.PendingChannelsResponse.ForceClosedChannel.anchor:type_name -> lnrpc.PendingChannelsResponse.ForceClosedChannel.AnchorState + 93, // 144: lnrpc.WalletBalanceResponse.AccountBalanceEntry.value:type_name -> lnrpc.WalletAccountBalance + 150, // 145: lnrpc.LightningNode.FeaturesEntry.value:type_name -> lnrpc.Feature + 117, // 146: lnrpc.NodeMetricsResponse.BetweennessCentralityEntry.value:type_name -> lnrpc.FloatMetric + 150, // 147: lnrpc.NodeUpdate.FeaturesEntry.value:type_name -> lnrpc.Feature + 150, // 148: lnrpc.Invoice.FeaturesEntry.value:type_name -> lnrpc.Feature + 150, // 149: lnrpc.PayReq.FeaturesEntry.value:type_name -> lnrpc.Feature + 176, // 150: lnrpc.ListPermissionsResponse.MethodPermissionsEntry.value:type_name -> lnrpc.MacaroonPermissionList + 94, // 151: lnrpc.Lightning.WalletBalance:input_type -> lnrpc.WalletBalanceRequest + 97, // 152: lnrpc.Lightning.ChannelBalance:input_type -> lnrpc.ChannelBalanceRequest + 20, // 153: lnrpc.Lightning.GetTransactions:input_type -> lnrpc.GetTransactionsRequest + 31, // 154: lnrpc.Lightning.EstimateFee:input_type -> lnrpc.EstimateFeeRequest + 35, // 155: lnrpc.Lightning.SendCoins:input_type -> lnrpc.SendCoinsRequest + 37, // 156: lnrpc.Lightning.ListUnspent:input_type -> lnrpc.ListUnspentRequest + 20, // 157: lnrpc.Lightning.SubscribeTransactions:input_type -> lnrpc.GetTransactionsRequest + 33, // 158: lnrpc.Lightning.SendMany:input_type -> lnrpc.SendManyRequest + 39, // 159: lnrpc.Lightning.NewAddress:input_type -> lnrpc.NewAddressRequest + 41, // 160: lnrpc.Lightning.SignMessage:input_type -> lnrpc.SignMessageRequest + 43, // 161: lnrpc.Lightning.VerifyMessage:input_type -> lnrpc.VerifyMessageRequest + 45, // 162: lnrpc.Lightning.ConnectPeer:input_type -> lnrpc.ConnectPeerRequest + 47, // 163: lnrpc.Lightning.DisconnectPeer:input_type -> lnrpc.DisconnectPeerRequest + 60, // 164: lnrpc.Lightning.ListPeers:input_type -> lnrpc.ListPeersRequest + 62, // 165: lnrpc.Lightning.SubscribePeerEvents:input_type -> lnrpc.PeerEventSubscription + 64, // 166: lnrpc.Lightning.GetInfo:input_type -> lnrpc.GetInfoRequest + 66, // 167: lnrpc.Lightning.GetRecoveryInfo:input_type -> lnrpc.GetRecoveryInfoRequest + 89, // 168: lnrpc.Lightning.PendingChannels:input_type -> lnrpc.PendingChannelsRequest + 52, // 169: lnrpc.Lightning.ListChannels:input_type -> lnrpc.ListChannelsRequest + 91, // 170: lnrpc.Lightning.SubscribeChannelEvents:input_type -> lnrpc.ChannelEventSubscription + 56, // 171: lnrpc.Lightning.ClosedChannels:input_type -> lnrpc.ClosedChannelsRequest + 76, // 172: lnrpc.Lightning.OpenChannelSync:input_type -> lnrpc.OpenChannelRequest + 76, // 173: lnrpc.Lightning.OpenChannel:input_type -> lnrpc.OpenChannelRequest + 86, // 174: lnrpc.Lightning.FundingStateStep:input_type -> lnrpc.FundingTransitionMsg + 27, // 175: lnrpc.Lightning.ChannelAcceptor:input_type -> lnrpc.ChannelAcceptResponse + 72, // 176: lnrpc.Lightning.CloseChannel:input_type -> lnrpc.CloseChannelRequest + 144, // 177: lnrpc.Lightning.AbandonChannel:input_type -> lnrpc.AbandonChannelRequest + 23, // 178: lnrpc.Lightning.SendPayment:input_type -> lnrpc.SendRequest + 23, // 179: lnrpc.Lightning.SendPaymentSync:input_type -> lnrpc.SendRequest + 25, // 180: lnrpc.Lightning.SendToRoute:input_type -> lnrpc.SendToRouteRequest + 25, // 181: lnrpc.Lightning.SendToRouteSync:input_type -> lnrpc.SendToRouteRequest + 130, // 182: lnrpc.Lightning.AddInvoice:input_type -> lnrpc.Invoice + 135, // 183: lnrpc.Lightning.ListInvoices:input_type -> lnrpc.ListInvoiceRequest + 134, // 184: lnrpc.Lightning.LookupInvoice:input_type -> lnrpc.PaymentHash + 137, // 185: lnrpc.Lightning.SubscribeInvoices:input_type -> lnrpc.InvoiceSubscription + 148, // 186: lnrpc.Lightning.DecodePayReq:input_type -> lnrpc.PayReqString + 140, // 187: lnrpc.Lightning.ListPayments:input_type -> lnrpc.ListPaymentsRequest + 142, // 188: lnrpc.Lightning.DeleteAllPayments:input_type -> lnrpc.DeleteAllPaymentsRequest + 113, // 189: lnrpc.Lightning.DescribeGraph:input_type -> lnrpc.ChannelGraphRequest + 115, // 190: lnrpc.Lightning.GetNodeMetrics:input_type -> lnrpc.NodeMetricsRequest + 118, // 191: lnrpc.Lightning.GetChanInfo:input_type -> lnrpc.ChanInfoRequest + 107, // 192: lnrpc.Lightning.GetNodeInfo:input_type -> lnrpc.NodeInfoRequest + 99, // 193: lnrpc.Lightning.QueryRoutes:input_type -> lnrpc.QueryRoutesRequest + 119, // 194: lnrpc.Lightning.GetNetworkInfo:input_type -> lnrpc.NetworkInfoRequest + 121, // 195: lnrpc.Lightning.StopDaemon:input_type -> lnrpc.StopRequest + 123, // 196: lnrpc.Lightning.SubscribeChannelGraph:input_type -> lnrpc.GraphTopologySubscription + 146, // 197: lnrpc.Lightning.DebugLevel:input_type -> lnrpc.DebugLevelRequest + 151, // 198: lnrpc.Lightning.FeeReport:input_type -> lnrpc.FeeReportRequest + 154, // 199: lnrpc.Lightning.UpdateChannelPolicy:input_type -> lnrpc.PolicyUpdateRequest + 156, // 200: lnrpc.Lightning.ForwardingHistory:input_type -> lnrpc.ForwardingHistoryRequest + 159, // 201: lnrpc.Lightning.ExportChannelBackup:input_type -> lnrpc.ExportChannelBackupRequest + 162, // 202: lnrpc.Lightning.ExportAllChannelBackups:input_type -> lnrpc.ChanBackupExportRequest + 163, // 203: lnrpc.Lightning.VerifyChanBackup:input_type -> lnrpc.ChanBackupSnapshot + 165, // 204: lnrpc.Lightning.RestoreChannelBackups:input_type -> lnrpc.RestoreChanBackupRequest + 167, // 205: lnrpc.Lightning.SubscribeChannelBackups:input_type -> lnrpc.ChannelBackupSubscription + 170, // 206: lnrpc.Lightning.BakeMacaroon:input_type -> lnrpc.BakeMacaroonRequest + 172, // 207: lnrpc.Lightning.ListMacaroonIDs:input_type -> lnrpc.ListMacaroonIDsRequest + 174, // 208: lnrpc.Lightning.DeleteMacaroonID:input_type -> lnrpc.DeleteMacaroonIDRequest + 177, // 209: lnrpc.Lightning.ListPermissions:input_type -> lnrpc.ListPermissionsRequest + 95, // 210: lnrpc.Lightning.WalletBalance:output_type -> lnrpc.WalletBalanceResponse + 98, // 211: lnrpc.Lightning.ChannelBalance:output_type -> lnrpc.ChannelBalanceResponse + 21, // 212: lnrpc.Lightning.GetTransactions:output_type -> lnrpc.TransactionDetails + 32, // 213: lnrpc.Lightning.EstimateFee:output_type -> lnrpc.EstimateFeeResponse + 36, // 214: lnrpc.Lightning.SendCoins:output_type -> lnrpc.SendCoinsResponse + 38, // 215: lnrpc.Lightning.ListUnspent:output_type -> lnrpc.ListUnspentResponse + 19, // 216: lnrpc.Lightning.SubscribeTransactions:output_type -> lnrpc.Transaction + 34, // 217: lnrpc.Lightning.SendMany:output_type -> lnrpc.SendManyResponse + 40, // 218: lnrpc.Lightning.NewAddress:output_type -> lnrpc.NewAddressResponse + 42, // 219: lnrpc.Lightning.SignMessage:output_type -> lnrpc.SignMessageResponse + 44, // 220: lnrpc.Lightning.VerifyMessage:output_type -> lnrpc.VerifyMessageResponse + 46, // 221: lnrpc.Lightning.ConnectPeer:output_type -> lnrpc.ConnectPeerResponse + 48, // 222: lnrpc.Lightning.DisconnectPeer:output_type -> lnrpc.DisconnectPeerResponse + 61, // 223: lnrpc.Lightning.ListPeers:output_type -> lnrpc.ListPeersResponse + 63, // 224: lnrpc.Lightning.SubscribePeerEvents:output_type -> lnrpc.PeerEvent + 65, // 225: lnrpc.Lightning.GetInfo:output_type -> lnrpc.GetInfoResponse + 67, // 226: lnrpc.Lightning.GetRecoveryInfo:output_type -> lnrpc.GetRecoveryInfoResponse + 90, // 227: lnrpc.Lightning.PendingChannels:output_type -> lnrpc.PendingChannelsResponse + 53, // 228: lnrpc.Lightning.ListChannels:output_type -> lnrpc.ListChannelsResponse + 92, // 229: lnrpc.Lightning.SubscribeChannelEvents:output_type -> lnrpc.ChannelEventUpdate + 57, // 230: lnrpc.Lightning.ClosedChannels:output_type -> lnrpc.ClosedChannelsResponse + 28, // 231: lnrpc.Lightning.OpenChannelSync:output_type -> lnrpc.ChannelPoint + 77, // 232: lnrpc.Lightning.OpenChannel:output_type -> lnrpc.OpenStatusUpdate + 87, // 233: lnrpc.Lightning.FundingStateStep:output_type -> lnrpc.FundingStateStepResp + 26, // 234: lnrpc.Lightning.ChannelAcceptor:output_type -> lnrpc.ChannelAcceptRequest + 73, // 235: lnrpc.Lightning.CloseChannel:output_type -> lnrpc.CloseStatusUpdate + 145, // 236: lnrpc.Lightning.AbandonChannel:output_type -> lnrpc.AbandonChannelResponse + 24, // 237: lnrpc.Lightning.SendPayment:output_type -> lnrpc.SendResponse + 24, // 238: lnrpc.Lightning.SendPaymentSync:output_type -> lnrpc.SendResponse + 24, // 239: lnrpc.Lightning.SendToRoute:output_type -> lnrpc.SendResponse + 24, // 240: lnrpc.Lightning.SendToRouteSync:output_type -> lnrpc.SendResponse + 133, // 241: lnrpc.Lightning.AddInvoice:output_type -> lnrpc.AddInvoiceResponse + 136, // 242: lnrpc.Lightning.ListInvoices:output_type -> lnrpc.ListInvoiceResponse + 130, // 243: lnrpc.Lightning.LookupInvoice:output_type -> lnrpc.Invoice + 130, // 244: lnrpc.Lightning.SubscribeInvoices:output_type -> lnrpc.Invoice + 149, // 245: lnrpc.Lightning.DecodePayReq:output_type -> lnrpc.PayReq + 141, // 246: lnrpc.Lightning.ListPayments:output_type -> lnrpc.ListPaymentsResponse + 143, // 247: lnrpc.Lightning.DeleteAllPayments:output_type -> lnrpc.DeleteAllPaymentsResponse + 114, // 248: lnrpc.Lightning.DescribeGraph:output_type -> lnrpc.ChannelGraph + 116, // 249: lnrpc.Lightning.GetNodeMetrics:output_type -> lnrpc.NodeMetricsResponse + 112, // 250: lnrpc.Lightning.GetChanInfo:output_type -> lnrpc.ChannelEdge + 108, // 251: lnrpc.Lightning.GetNodeInfo:output_type -> lnrpc.NodeInfo + 102, // 252: lnrpc.Lightning.QueryRoutes:output_type -> lnrpc.QueryRoutesResponse + 120, // 253: lnrpc.Lightning.GetNetworkInfo:output_type -> lnrpc.NetworkInfo + 122, // 254: lnrpc.Lightning.StopDaemon:output_type -> lnrpc.StopResponse + 124, // 255: lnrpc.Lightning.SubscribeChannelGraph:output_type -> lnrpc.GraphTopologyUpdate + 147, // 256: lnrpc.Lightning.DebugLevel:output_type -> lnrpc.DebugLevelResponse + 153, // 257: lnrpc.Lightning.FeeReport:output_type -> lnrpc.FeeReportResponse + 155, // 258: lnrpc.Lightning.UpdateChannelPolicy:output_type -> lnrpc.PolicyUpdateResponse + 158, // 259: lnrpc.Lightning.ForwardingHistory:output_type -> lnrpc.ForwardingHistoryResponse + 160, // 260: lnrpc.Lightning.ExportChannelBackup:output_type -> lnrpc.ChannelBackup + 163, // 261: lnrpc.Lightning.ExportAllChannelBackups:output_type -> lnrpc.ChanBackupSnapshot + 168, // 262: lnrpc.Lightning.VerifyChanBackup:output_type -> lnrpc.VerifyChanBackupResponse + 166, // 263: lnrpc.Lightning.RestoreChannelBackups:output_type -> lnrpc.RestoreBackupResponse + 163, // 264: lnrpc.Lightning.SubscribeChannelBackups:output_type -> lnrpc.ChanBackupSnapshot + 171, // 265: lnrpc.Lightning.BakeMacaroon:output_type -> lnrpc.BakeMacaroonResponse + 173, // 266: lnrpc.Lightning.ListMacaroonIDs:output_type -> lnrpc.ListMacaroonIDsResponse + 175, // 267: lnrpc.Lightning.DeleteMacaroonID:output_type -> lnrpc.DeleteMacaroonIDResponse + 178, // 268: lnrpc.Lightning.ListPermissions:output_type -> lnrpc.ListPermissionsResponse + 210, // [210:269] is the sub-list for method output_type + 151, // [151:210] is the sub-list for method input_type + 151, // [151:151] is the sub-list for extension type_name + 151, // [151:151] is the sub-list for extension extendee + 0, // [0:151] is the sub-list for field type_name } func init() { file_lightning_proto_init() } diff --git a/lnrpc/lightning.proto b/lnrpc/lightning.proto index 48cfa427ccb..686722609c9 100644 --- a/lnrpc/lightning.proto +++ b/lnrpc/lightning.proto @@ -792,6 +792,9 @@ message ChannelAcceptRequest { // A bit-field which the initiator uses to specify proposed channel // behavior. uint32 channel_flags = 13; + + // The commitment type the initiator wishes to use for the proposed channel. + CommitmentType commitment_type = 14; } message ChannelAcceptResponse { diff --git a/lnrpc/lightning.swagger.json b/lnrpc/lightning.swagger.json index 9ce74d2b335..ec7d3277f71 100644 --- a/lnrpc/lightning.swagger.json +++ b/lnrpc/lightning.swagger.json @@ -2997,6 +2997,10 @@ "type": "integer", "format": "int64", "description": "A bit-field which the initiator uses to specify proposed channel\nbehavior." + }, + "commitment_type": { + "$ref": "#/definitions/lnrpcCommitmentType", + "description": "The commitment type the initiator wishes to use for the proposed channel." } } }, From ab96e20f5f4a83e48399b6fa7eca4ed70dee2286 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Tue, 13 Jul 2021 15:57:22 -0700 Subject: [PATCH 26/29] itest: update itests to use new script-enforced lease commitment type We update several of our integration tests that exercise different scenarios with regards to the broadcast of a channel commitment transaction with HTLCs in-flight to use the new commitment type for channel leases. We do this to ensure we have complete coverage of said channel commitment type. This required changing several assumptions throughout the tests based on when we should expect sweeps to happen. --- lntest/itest/assertions.go | 30 +++- lntest/itest/lnd_funding_test.go | 17 +- .../lnd_multi-hop_htlc_aggregation_test.go | 101 ++++++++---- ...d_multi-hop_htlc_local_chain_claim_test.go | 140 ++++++++++++---- .../lnd_multi-hop_htlc_local_timeout_test.go | 151 +++++++++--------- ...ulti-hop_htlc_receiver_chain_claim_test.go | 76 +++++++-- ..._multi-hop_htlc_remote_chain_claim_test.go | 146 +++++++++++++---- ..._force_close_on_chain_htlc_timeout_test.go | 92 +++++++---- ..._force_close_on_chain_htlc_timeout_test.go | 57 +++++-- lntest/itest/lnd_multi-hop_test.go | 20 +++ lntest/itest/utils.go | 18 ++- 11 files changed, 604 insertions(+), 244 deletions(-) diff --git a/lntest/itest/assertions.go b/lntest/itest/assertions.go index def13577d2a..5123d8be4d3 100644 --- a/lntest/itest/assertions.go +++ b/lntest/itest/assertions.go @@ -1576,17 +1576,18 @@ func assertNumActiveHtlcs(nodes []*lntest.HarnessNode, numHtlcs int) error { } func assertSpendingTxInMempool(t *harnessTest, miner *rpcclient.Client, - timeout time.Duration, chanPoint wire.OutPoint) chainhash.Hash { + timeout time.Duration, inputs ...wire.OutPoint) chainhash.Hash { - tx := getSpendingTxInMempool(t, miner, timeout, chanPoint) + tx := getSpendingTxInMempool(t, miner, timeout, inputs...) return tx.TxHash() } // getSpendingTxInMempool waits for a transaction spending the given outpoint to // appear in the mempool and returns that tx in full. func getSpendingTxInMempool(t *harnessTest, miner *rpcclient.Client, - timeout time.Duration, chanPoint wire.OutPoint) *wire.MsgTx { + timeout time.Duration, inputs ...wire.OutPoint) *wire.MsgTx { + inputSet := make(map[wire.OutPoint]struct{}, len(inputs)) breakTimeout := time.After(timeout) ticker := time.NewTicker(50 * time.Millisecond) defer ticker.Stop() @@ -1606,13 +1607,30 @@ func getSpendingTxInMempool(t *harnessTest, miner *rpcclient.Client, for _, txid := range mempool { tx, err := miner.GetRawTransaction(txid) require.NoError(t.t, err, "unable to fetch tx") - msgTx := tx.MsgTx() + + // Include the inputs again in case they were + // removed in a previous iteration. + for _, input := range inputs { + inputSet[input] = struct{}{} + } + for _, txIn := range msgTx.TxIn { - if txIn.PreviousOutPoint == chanPoint { - return msgTx + input := txIn.PreviousOutPoint + if _, ok := inputSet[input]; ok { + delete(inputSet, input) } } + + if len(inputSet) > 0 { + // Missing input, check next transaction + // or try again. + continue + } + + // Transaction spends all expected inputs, + // return. + return msgTx } } } diff --git a/lntest/itest/lnd_funding_test.go b/lntest/itest/lnd_funding_test.go index 320d0a4a589..4b6a941001f 100644 --- a/lntest/itest/lnd_funding_test.go +++ b/lntest/itest/lnd_funding_test.go @@ -14,7 +14,7 @@ import ( "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/labels" "github.com/lightningnetwork/lnd/lnrpc" - "github.com/lightningnetwork/lnd/lnrpc/signrpc" + "github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lnwire" "github.com/stretchr/testify/require" @@ -407,7 +407,7 @@ func testExternalFundingChanPoint(net *lntest.NetworkHarness, t *harnessTest) { const thawHeight uint32 = 10 const chanSize = funding.MaxBtcFundingAmount fundingShim1, chanPoint1, _ := deriveFundingShim( - net, t, carol, dave, chanSize, thawHeight, 1, false, + net, t, carol, dave, chanSize, thawHeight, false, ) _ = openChannelStream( ctxb, t, net, carol, dave, lntest.OpenChannelParams{ @@ -424,7 +424,7 @@ func testExternalFundingChanPoint(net *lntest.NetworkHarness, t *harnessTest) { // do exactly that now. For this one we publish the transaction so we // can mine it later. fundingShim2, chanPoint2, _ := deriveFundingShim( - net, t, carol, dave, chanSize, thawHeight, 2, true, + net, t, carol, dave, chanSize, thawHeight, true, ) // At this point, we'll now carry out the normal basic channel funding @@ -667,17 +667,14 @@ func testChannelFundingPersistence(net *lntest.NetworkHarness, t *harnessTest) { // keys on both sides. func deriveFundingShim(net *lntest.NetworkHarness, t *harnessTest, carol, dave *lntest.HarnessNode, chanSize btcutil.Amount, - thawHeight uint32, keyIndex int32, publish bool) (*lnrpc.FundingShim, + thawHeight uint32, publish bool) (*lnrpc.FundingShim, *lnrpc.ChannelPoint, *chainhash.Hash) { ctxb := context.Background() - keyLoc := &signrpc.KeyLocator{ - KeyFamily: 9999, - KeyIndex: keyIndex, - } - carolFundingKey, err := carol.WalletKitClient.DeriveKey(ctxb, keyLoc) + keyLoc := &walletrpc.KeyReq{KeyFamily: 9999} + carolFundingKey, err := carol.WalletKitClient.DeriveNextKey(ctxb, keyLoc) require.NoError(t.t, err) - daveFundingKey, err := dave.WalletKitClient.DeriveKey(ctxb, keyLoc) + daveFundingKey, err := dave.WalletKitClient.DeriveNextKey(ctxb, keyLoc) require.NoError(t.t, err) // Now that we have the multi-sig keys for each party, we can manually diff --git a/lntest/itest/lnd_multi-hop_htlc_aggregation_test.go b/lntest/itest/lnd_multi-hop_htlc_aggregation_test.go index 1bad6fc1d3a..9045be16ea0 100644 --- a/lntest/itest/lnd_multi-hop_htlc_aggregation_test.go +++ b/lntest/itest/lnd_multi-hop_htlc_aggregation_test.go @@ -187,8 +187,9 @@ func testMultiHopHtlcAggregation(net *lntest.NetworkHarness, t *harnessTest, // Bob's force close transaction should now be found in the mempool. If // there are anchors, we also expect Bob's anchor sweep. + hasAnchors := commitTypeHasAnchors(c) expectedTxes := 1 - if c == lnrpc.CommitmentType_ANCHORS { + if hasAnchors { expectedTxes = 2 } @@ -251,19 +252,25 @@ func testMultiHopHtlcAggregation(net *lntest.NetworkHarness, t *harnessTest, require.NoError(t.t, err) } + switch c { // With the closing transaction confirmed, we should expect Bob's HTLC // timeout transactions to be broadcast due to the expiry being reached. // We will also expect the success transactions, since he learnt the // preimages from Alice. We also expect Carol to sweep her commitment // output. - expectedTxes = 2*numInvoices + 1 + case lnrpc.CommitmentType_LEGACY: + expectedTxes = 2*numInvoices + 1 // In case of anchors, all success transactions will be aggregated into // one, the same is the case for the timeout transactions. In this case - // Carol will also sweep her anchor output in a separate tx (since it - // will be low fee). - if c == lnrpc.CommitmentType_ANCHORS { + // Carol will also sweep her commitment and anchor output as separate + // txs (since it will be low fee). + case lnrpc.CommitmentType_ANCHORS, + lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: expectedTxes = 4 + + default: + t.Fatalf("unhandled commitment type %v", c) } txes, err := getNTxsFromMempool( @@ -298,7 +305,7 @@ func testMultiHopHtlcAggregation(net *lntest.NetworkHarness, t *harnessTest, // In case of anchor we expect all the timeout and success second // levels to be aggregated into one tx. For earlier channel types, they // will be separate transactions. - if c == lnrpc.CommitmentType_ANCHORS { + if hasAnchors { require.Len(t.t, timeoutTxs, 1) require.Len(t.t, successTxs, 1) } else { @@ -341,47 +348,75 @@ func testMultiHopHtlcAggregation(net *lntest.NetworkHarness, t *harnessTest, ) require.NoError(t.t, err) - // If we then mine additional blocks, Bob can sweep his commitment - // output. - _, err = net.Miner.Client.Generate(defaultCSV - 2) - require.NoError(t.t, err) + if c != lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + // If we then mine additional blocks, Bob can sweep his commitment + // output. + _, err = net.Miner.Client.Generate(defaultCSV - 2) + require.NoError(t.t, err) - // Find the commitment sweep. - bobCommitSweepHash, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout) - require.NoError(t.t, err) - bobCommitSweep, err := net.Miner.Client.GetRawTransaction(bobCommitSweepHash) - require.NoError(t.t, err) + // Find the commitment sweep. + bobCommitSweepHash, err := waitForTxInMempool( + net.Miner.Client, minerMempoolTimeout, + ) + require.NoError(t.t, err) + bobCommitSweep, err := net.Miner.Client.GetRawTransaction( + bobCommitSweepHash, + ) + require.NoError(t.t, err) - require.Equal( - t.t, closeTxid, bobCommitSweep.MsgTx().TxIn[0].PreviousOutPoint.Hash, - ) + require.Equal( + t.t, closeTxid, + bobCommitSweep.MsgTx().TxIn[0].PreviousOutPoint.Hash, + ) - // Also ensure it is not spending from any of the HTLC output. - for _, txin := range bobCommitSweep.MsgTx().TxIn { - for _, timeoutTx := range timeoutTxs { - if *timeoutTx == txin.PreviousOutPoint.Hash { - t.Fatalf("found unexpected spend of timeout tx") + // Also ensure it is not spending from any of the HTLC output. + for _, txin := range bobCommitSweep.MsgTx().TxIn { + for _, timeoutTx := range timeoutTxs { + if *timeoutTx == txin.PreviousOutPoint.Hash { + t.Fatalf("found unexpected spend of " + + "timeout tx") + } } - } - for _, successTx := range successTxs { - if *successTx == txin.PreviousOutPoint.Hash { - t.Fatalf("found unexpected spend of success tx") + for _, successTx := range successTxs { + if *successTx == txin.PreviousOutPoint.Hash { + t.Fatalf("found unexpected spend of " + + "success tx") + } } } } - switch { + switch c { + // In case this is a non-anchor channel type, we must mine 2 blocks, as + // the nursery waits an extra block before sweeping. Before the blocks + // are mined, we should expect to see Bob's commit sweep in the mempool. + case lnrpc.CommitmentType_LEGACY: + _ = mineBlocks(t, net, 2, 1) // Mining one additional block, Bob's second level tx is mature, and he - // can sweep the output. - case c == lnrpc.CommitmentType_ANCHORS: + // can sweep the output. Before the blocks are mined, we should expect + // to see Bob's commit sweep in the mempool. + case lnrpc.CommitmentType_ANCHORS: _ = mineBlocks(t, net, 1, 1) - // In case this is a non-anchor channel type, we must mine 2 blocks, as - // the nursery waits an extra block before sweeping. + // Since Bob is the initiator of the Bob-Carol script-enforced leased + // channel, he incurs an additional CLTV when sweeping outputs back to + // his wallet. We'll need to mine enough blocks for the timelock to + // expire to prompt his broadcast. + case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: + ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) + resp, err := bob.PendingChannels( + ctxt, &lnrpc.PendingChannelsRequest{}, + ) + require.NoError(t.t, err) + require.Len(t.t, resp.PendingForceClosingChannels, 1) + forceCloseChan := resp.PendingForceClosingChannels[0] + require.Positive(t.t, forceCloseChan.BlocksTilMaturity) + _ = mineBlocks(t, net, uint32(forceCloseChan.BlocksTilMaturity), 0) + default: - _ = mineBlocks(t, net, 2, 1) + t.Fatalf("unhandled commitment type %v", c) } bobSweep, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout) diff --git a/lntest/itest/lnd_multi-hop_htlc_local_chain_claim_test.go b/lntest/itest/lnd_multi-hop_htlc_local_chain_claim_test.go index 6f4ffc08ac5..18c9eea4850 100644 --- a/lntest/itest/lnd_multi-hop_htlc_local_chain_claim_test.go +++ b/lntest/itest/lnd_multi-hop_htlc_local_chain_claim_test.go @@ -86,16 +86,29 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest, // At this point, Bob decides that he wants to exit the channel // immediately, so he force closes his commitment transaction. ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) + hasAnchors := commitTypeHasAnchors(c) bobForceClose := closeChannelAndAssertType( - ctxt, t, net, bob, aliceChanPoint, - c == lnrpc.CommitmentType_ANCHORS, true, + ctxt, t, net, bob, aliceChanPoint, hasAnchors, true, ) - // Alice will sweep her commitment output immediately. If there are - // anchors, Alice will also sweep hers. - expectedTxes := 1 - if c == lnrpc.CommitmentType_ANCHORS { + var expectedTxes int + switch c { + // Alice will sweep her commitment output immediately. + case lnrpc.CommitmentType_LEGACY: + expectedTxes = 1 + + // Alice will sweep her commitment and anchor output immediately. + case lnrpc.CommitmentType_ANCHORS: expectedTxes = 2 + + // Alice will sweep her anchor output immediately. Her commitment output + // cannot be swept yet as it has incurred an additional CLTV due to + // being the initiator of a script-enforced leased channel. + case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: + expectedTxes = 1 + + default: + t.Fatalf("unhandled commitment type %v", c) } _, err = waitForNTxsInMempool( net.Miner.Client, expectedTxes, minerMempoolTimeout, @@ -156,15 +169,28 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest, err = restartBob() require.NoError(t.t, err) - // After the force close transacion is mined, Carol should broadcast her - // second level HTLC transacion. Bob will broadcast a sweep tx to sweep - // his output in the channel with Carol. He can do this immediately, as - // the output is not timelocked since Carol was the one force closing. - // If there are anchors on the commitment, Bob will also sweep his - // anchor. - expectedTxes = 2 - if c == lnrpc.CommitmentType_ANCHORS { + // After the force close transacion is mined, transactions will be + // broadcast by both Bob and Carol. + switch c { + // Carol will broadcast her second level HTLC transaction and Bob will + // sweep his commitment output. + case lnrpc.CommitmentType_LEGACY: + expectedTxes = 2 + + // Carol will broadcast her second level HTLC transaction and Bob will + // sweep his commitment and anchor output. + case lnrpc.CommitmentType_ANCHORS: + expectedTxes = 3 + + // Carol will broadcast her second level HTLC transaction and anchor + // sweep, and Bob will sweep his anchor output. Bob can't sweep his + // commitment output yet as it has incurred an additional CLTV due to + // being the initiator of a script-enforced leased channel. + case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: expectedTxes = 3 + + default: + t.Fatalf("unhandled commitment type %v", c) } txes, err := getNTxsFromMempool( net.Miner.Client, expectedTxes, minerMempoolTimeout, @@ -180,24 +206,20 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest, restartAlice, err := net.SuspendNode(alice) require.NoError(t.t, err) - // Mine a block to confirm the two transactions (+ the coinbase). + // Mine a block to confirm the expected transactions (+ the coinbase). block = mineBlocks(t, net, 1, expectedTxes)[0] require.Len(t.t, block.Transactions, expectedTxes+1) - var secondLevelMaturity uint32 - switch c { - - // If this is a channel of the anchor type, we will subtract one block - // from the default CSV, as the Sweeper will handle the input, and the Sweeper - // sweeps the input as soon as the lock expires. - case lnrpc.CommitmentType_ANCHORS: - secondLevelMaturity = defaultCSV - 1 - // For non-anchor channel types, the nursery will handle sweeping the // second level output, and it will wait one extra block before // sweeping it. - default: - secondLevelMaturity = defaultCSV + secondLevelMaturity := uint32(defaultCSV) + + // If this is a channel of the anchor type, we will subtract one block + // from the default CSV, as the Sweeper will handle the input, and the + // Sweeper sweeps the input as soon as the lock expires. + if hasAnchors { + secondLevelMaturity = defaultCSV - 1 } // Keep track of the second level tx maturity. @@ -221,9 +243,13 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest, // At this point, Bob should have broadcast his second layer success // transaction, and should have sent it to the nursery for incubation. + numPendingChans := 1 + if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + numPendingChans++ + } ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) err = waitForNumChannelPendingForceClose( - ctxt, bob, 1, func(c *lnrpcForceCloseChannel) error { + ctxt, bob, numPendingChans, func(c *lnrpcForceCloseChannel) error { if c.Channel.LocalBalance != 0 { return nil } @@ -290,15 +316,59 @@ func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest, block = mineBlocks(t, net, 1, 1)[0] assertTxInBlock(t, block, bobSweep) - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - err = waitForNumChannelPendingForceClose(ctxt, bob, 0, nil) - require.NoError(t.t, err) - assertNodeNumChannels(t, bob, 0) + // With the script-enforced lease commitment type, Alice and Bob still + // haven't been able to sweep their respective commit outputs due to the + // additional CLTV. We'll need to mine enough blocks for the timelock to + // expire and prompt their sweep. + if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + for _, node := range []*lntest.HarnessNode{alice, bob} { + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = waitForNumChannelPendingForceClose(ctxt, node, 1, nil) + require.NoError(t.t, err) + } + + // Due to the way the test is set up, Alice and Bob share the + // same CLTV for their commit outputs even though it's enforced + // on different channels (Alice-Bob and Bob-Carol). + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + resp, err := alice.PendingChannels( + ctxt, &lnrpc.PendingChannelsRequest{}, + ) + require.NoError(t.t, err) + require.Len(t.t, resp.PendingForceClosingChannels, 1) + forceCloseChan := resp.PendingForceClosingChannels[0] + require.Positive(t.t, forceCloseChan.BlocksTilMaturity) + + // Mine enough blocks for the timelock to expire. + numBlocks := uint32(forceCloseChan.BlocksTilMaturity) + _, err = net.Miner.Client.Generate(numBlocks) + require.NoError(t.t, err) + + // Both Alice and Bob show broadcast their commit sweeps. + aliceCommitOutpoint := wire.OutPoint{Hash: *bobForceClose, Index: 3} + aliceCommitSweep := assertSpendingTxInMempool( + t, net.Miner.Client, minerMempoolTimeout, + aliceCommitOutpoint, + ) + bobCommitOutpoint := wire.OutPoint{Hash: closingTxid, Index: 3} + bobCommitSweep := assertSpendingTxInMempool( + t, net.Miner.Client, minerMempoolTimeout, + bobCommitOutpoint, + ) + + // Confirm their sweeps. + block := mineBlocks(t, net, 1, 2)[0] + assertTxInBlock(t, block, &aliceCommitSweep) + assertTxInBlock(t, block, &bobCommitSweep) + } - // Also Carol should have no channels left (open nor pending). - err = waitForNumChannelPendingForceClose(ctxt, carol, 0, nil) - require.NoError(t.t, err) - assertNodeNumChannels(t, carol, 0) + // All nodes should show zero pending and open channels. + for _, node := range []*lntest.HarnessNode{alice, bob, carol} { + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = waitForNumChannelPendingForceClose(ctxt, node, 0, nil) + require.NoError(t.t, err) + assertNodeNumChannels(t, node, 0) + } // Finally, check that the Alice's payment is correctly marked // succeeded. diff --git a/lntest/itest/lnd_multi-hop_htlc_local_timeout_test.go b/lntest/itest/lnd_multi-hop_htlc_local_timeout_test.go index a40a0c8d2e2..6bbcda93b65 100644 --- a/lntest/itest/lnd_multi-hop_htlc_local_timeout_test.go +++ b/lntest/itest/lnd_multi-hop_htlc_local_timeout_test.go @@ -4,7 +4,6 @@ import ( "context" "time" - "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" "github.com/lightningnetwork/lnd/lncfg" @@ -104,23 +103,24 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest, // Bob's force close transaction should now be found in the mempool. If // there are anchors, we also expect Bob's anchor sweep. expectedTxes := 1 - if c == lnrpc.CommitmentType_ANCHORS { + hasAnchors := commitTypeHasAnchors(c) + if hasAnchors { expectedTxes = 2 } - - bobFundingTxid, err := lnrpc.GetChanPointFundingTxid(bobChanPoint) - require.NoError(t.t, err) _, err = waitForNTxsInMempool( net.Miner.Client, expectedTxes, minerMempoolTimeout, ) require.NoError(t.t, err) - closeTx := getSpendingTxInMempool( - t, net.Miner.Client, minerMempoolTimeout, wire.OutPoint{ - Hash: *bobFundingTxid, - Index: bobChanPoint.OutputIndex, - }, + + bobFundingTxid, err := lnrpc.GetChanPointFundingTxid(bobChanPoint) + require.NoError(t.t, err) + bobChanOutpoint := wire.OutPoint{ + Hash: *bobFundingTxid, + Index: bobChanPoint.OutputIndex, + } + closeTxid := assertSpendingTxInMempool( + t, net.Miner.Client, minerMempoolTimeout, bobChanOutpoint, ) - closeTxid := closeTx.TxHash() // Mine a block to confirm the closing transaction. mineBlocks(t, net, 1, expectedTxes) @@ -137,87 +137,86 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest, // With the closing transaction confirmed, we should expect Bob's HTLC // timeout transaction to be broadcast due to the expiry being reached. // If there are anchors, we also expect Carol's anchor sweep now. - txes, err := getNTxsFromMempool( + _, err = getNTxsFromMempool( net.Miner.Client, expectedTxes, minerMempoolTimeout, ) require.NoError(t.t, err) - // Lookup the timeout transaction that is expected to spend from the - // closing tx. We distinguish it from a possibly anchor sweep by value. - var htlcTimeout *chainhash.Hash - for _, tx := range txes { - prevOp := tx.TxIn[0].PreviousOutPoint - require.Equal(t.t, closeTxid, prevOp.Hash) - - // Assume that the timeout tx doesn't spend an output of exactly - // the size of the anchor. - if closeTx.TxOut[prevOp.Index].Value != anchorSize { - hash := tx.TxHash() - htlcTimeout = &hash - } + // We'll also obtain the expected HTLC timeout transaction hash. + htlcOutpoint := wire.OutPoint{Hash: closeTxid, Index: 0} + commitOutpoint := wire.OutPoint{Hash: closeTxid, Index: 1} + if hasAnchors { + htlcOutpoint.Index = 2 + commitOutpoint.Index = 3 } - require.NotNil(t.t, htlcTimeout) + htlcTimeoutTxid := assertSpendingTxInMempool( + t, net.Miner.Client, minerMempoolTimeout, htlcOutpoint, + ) - // We'll mine the remaining blocks in order to generate the sweep - // transaction of Bob's commitment output. The commitment was just - // mined at the current tip and the sweep will be broadcast so it can - // be mined at the tip+defaultCSV'th block, so mine one less to be able - // to make mempool assertions. - mineBlocks(t, net, defaultCSV-1, expectedTxes) + // Mine a block to confirm the expected transactions. + _ = mineBlocks(t, net, 1, expectedTxes) - // Check that the sweep spends from the mined commitment. - txes, err = getNTxsFromMempool(net.Miner.Client, 1, minerMempoolTimeout) + // With Bob's HTLC timeout transaction confirmed, there should be no + // active HTLC's on the commitment transaction from Alice -> Bob. + err = wait.NoError(func() error { + return assertNumActiveHtlcs([]*lntest.HarnessNode{alice}, 0) + }, defaultTimeout) require.NoError(t.t, err) - assertAllTxesSpendFrom(t, txes, closeTxid) - // Bob's pending channel report should show that he has a commitment - // output awaiting sweeping, and also that there's an outgoing HTLC - // output pending. - pendingChansRequest := &lnrpc.PendingChannelsRequest{} + // At this point, Bob should show that the pending HTLC has advanced to + // the second stage and is ready to be swept once the timelock is up. ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) + pendingChansRequest := &lnrpc.PendingChannelsRequest{} pendingChanResp, err := bob.PendingChannels(ctxt, pendingChansRequest) require.NoError(t.t, err) - - require.NotZero(t.t, len(pendingChanResp.PendingForceClosingChannels)) + require.Equal(t.t, 1, len(pendingChanResp.PendingForceClosingChannels)) forceCloseChan := pendingChanResp.PendingForceClosingChannels[0] require.NotZero(t.t, forceCloseChan.LimboBalance) - require.NotZero(t.t, len(forceCloseChan.PendingHtlcs)) - - // Mine a block to confirm Bob's commit sweep tx and assert it was in - // fact mined. - block := mineBlocks(t, net, 1, 1)[0] - commitSweepTxid := txes[0].TxHash() - assertTxInBlock(t, block, &commitSweepTxid) - - // Mine an additional block to prompt Bob to broadcast their second - // layer sweep due to the CSV on the HTLC timeout output. - mineBlocks(t, net, 1, 0) - assertSpendingTxInMempool( - t, net.Miner.Client, minerMempoolTimeout, wire.OutPoint{ - Hash: *htlcTimeout, - Index: 0, - }, - ) - - // The block should have confirmed Bob's HTLC timeout transaction. - // Therefore, at this point, there should be no active HTLC's on the - // commitment transaction from Alice -> Bob. - nodes = []*lntest.HarnessNode{alice} - err = wait.NoError(func() error { - return assertNumActiveHtlcs(nodes, 0) - }, defaultTimeout) - require.NoError(t.t, err) - - // At this point, Bob should show that the pending HTLC has advanced to - // the second stage and is to be swept. - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - pendingChanResp, err = bob.PendingChannels(ctxt, pendingChansRequest) - require.NoError(t.t, err) - forceCloseChan = pendingChanResp.PendingForceClosingChannels[0] + require.Positive(t.t, forceCloseChan.BlocksTilMaturity) + require.Equal(t.t, 1, len(forceCloseChan.PendingHtlcs)) require.Equal(t.t, uint32(2), forceCloseChan.PendingHtlcs[0].Stage) - // Next, we'll mine a final block that should confirm the second-layer - // sweeping transaction. + htlcTimeoutOutpoint := wire.OutPoint{Hash: htlcTimeoutTxid, Index: 0} + if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + // Since Bob is the initiator of the script-enforced leased + // channel between him and Carol, he will incur an additional + // CLTV on top of the usual CSV delay on any outputs that he can + // sweep back to his wallet. + blocksTilMaturity := uint32(forceCloseChan.BlocksTilMaturity) + mineBlocks(t, net, blocksTilMaturity, 0) + + // Check that the sweep spends the expected inputs. + _ = assertSpendingTxInMempool( + t, net.Miner.Client, minerMempoolTimeout, + commitOutpoint, htlcTimeoutOutpoint, + ) + } else { + // Since Bob force closed the channel between him and Carol, he + // will incur the usual CSV delay on any outputs that he can + // sweep back to his wallet. We'll subtract one block from our + // current maturity period to assert on the mempool. + mineBlocks(t, net, uint32(forceCloseChan.BlocksTilMaturity-1), 0) + + // Check that the sweep spends from the mined commitment. + _ = assertSpendingTxInMempool( + t, net.Miner.Client, minerMempoolTimeout, commitOutpoint, + ) + + // Mine a block to confirm Bob's commit sweep tx and assert it + // was in fact mined. + _ = mineBlocks(t, net, 1, 1)[0] + + // Mine an additional block to prompt Bob to broadcast their + // second layer sweep due to the CSV on the HTLC timeout output. + mineBlocks(t, net, 1, 0) + _ = assertSpendingTxInMempool( + t, net.Miner.Client, minerMempoolTimeout, + htlcTimeoutOutpoint, + ) + } + + // Next, we'll mine a final block that should confirm the sweeping + // transactions left. _, err = net.Miner.Client.Generate(1) require.NoError(t.t, err) diff --git a/lntest/itest/lnd_multi-hop_htlc_receiver_chain_claim_test.go b/lntest/itest/lnd_multi-hop_htlc_receiver_chain_claim_test.go index ba264515308..11682d8e74d 100644 --- a/lntest/itest/lnd_multi-hop_htlc_receiver_chain_claim_test.go +++ b/lntest/itest/lnd_multi-hop_htlc_receiver_chain_claim_test.go @@ -113,7 +113,8 @@ func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest, // transaction in order to go to the chain and sweep her HTLC. If there // are anchors, Carol also sweeps hers. expectedTxes := 1 - if c == lnrpc.CommitmentType_ANCHORS { + hasAnchors := commitTypeHasAnchors(c) + if hasAnchors { expectedTxes = 2 } _, err = getNTxsFromMempool( @@ -143,15 +144,32 @@ func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest, err = restartBob() require.NoError(t.t, err) - // After the force close transaction is mined, Carol should broadcast - // her second level HTLC transaction. Bob will broadcast a sweep tx to - // sweep his output in the channel with Carol. When Bob notices Carol's - // second level transaction in the mempool, he will extract the preimage - // and settle the HTLC back off-chain. Bob will also sweep his anchor, - // if present. - expectedTxes = 2 - if c == lnrpc.CommitmentType_ANCHORS { + // After the force close transaction is mined, a series of transactions + // should be broadcast by Bob and Carol. When Bob notices Carol's second + // level transaction in the mempool, he will extract the preimage and + // settle the HTLC back off-chain. + switch c { + // Carol should broadcast her second level HTLC transaction and Bob + // should broadcast a sweep tx to sweep his output in the channel with + // Carol. + case lnrpc.CommitmentType_LEGACY: + expectedTxes = 2 + + // Carol should broadcast her second level HTLC transaction and Bob + // should broadcast a sweep tx to sweep his output in the channel with + // Carol, and another sweep tx to sweep his anchor output. + case lnrpc.CommitmentType_ANCHORS: expectedTxes = 3 + + // Carol should broadcast her second level HTLC transaction and Bob + // should broadcast a sweep tx to sweep his anchor output. Bob's commit + // output can't be swept yet as he's incurring an additional CLTV from + // being the channel initiator of a script-enforced leased channel. + case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: + expectedTxes = 2 + + default: + t.Fatalf("unhandled commitment type %v", c) } txes, err := getNTxsFromMempool( net.Miner.Client, expectedTxes, minerMempoolTimeout, @@ -195,8 +213,8 @@ func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest, }, defaultTimeout) require.NoError(t.t, err) - // If we mine 4 additional blocks, then both outputs should now be - // mature. + // If we mine 4 additional blocks, then Carol can sweep the second level + // HTLC output. _, err = net.Miner.Client.Generate(defaultCSV) require.NoError(t.t, err) @@ -231,6 +249,42 @@ func testMultiHopReceiverChainClaim(net *lntest.NetworkHarness, t *harnessTest, ) require.NoError(t.t, err) + if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + // Bob still has his commit output to sweep to since he incurred + // an additional CLTV from being the channel initiator of a + // script-enforced leased channel, regardless of whether he + // forced closed the channel or not. + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + pendingChanResp, err := bob.PendingChannels( + ctxt, &lnrpc.PendingChannelsRequest{}, + ) + require.NoError(t.t, err) + + require.Len(t.t, pendingChanResp.PendingForceClosingChannels, 1) + forceCloseChan := pendingChanResp.PendingForceClosingChannels[0] + require.Positive(t.t, forceCloseChan.LimboBalance) + require.Positive(t.t, forceCloseChan.BlocksTilMaturity) + + // TODO: Bob still shows a pending HTLC at this point when he + // shouldn't, as he already extracted the preimage from Carol's + // claim. + // require.Len(t.t, forceCloseChan.PendingHtlcs, 0) + + // Mine enough blocks for Bob's commit output's CLTV to expire + // and sweep it. + _ = mineBlocks(t, net, uint32(forceCloseChan.BlocksTilMaturity), 0) + commitOutpoint := wire.OutPoint{Hash: closingTxid, Index: 3} + assertSpendingTxInMempool( + t, net.Miner.Client, minerMempoolTimeout, commitOutpoint, + ) + _, err = net.Miner.Client.Generate(1) + require.NoError(t.t, err) + } + + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = waitForNumChannelPendingForceClose(ctxt, bob, 0, nil) + require.NoError(t.t, err) + // We'll close out the channel between Alice and Bob, then shutdown // carol to conclude the test. ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) diff --git a/lntest/itest/lnd_multi-hop_htlc_remote_chain_claim_test.go b/lntest/itest/lnd_multi-hop_htlc_remote_chain_claim_test.go index 77ac1373d9f..d0a52d7a774 100644 --- a/lntest/itest/lnd_multi-hop_htlc_remote_chain_claim_test.go +++ b/lntest/itest/lnd_multi-hop_htlc_remote_chain_claim_test.go @@ -86,9 +86,9 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest // immediately force close the channel by broadcast her commitment // transaction. ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) + hasAnchors := commitTypeHasAnchors(c) aliceForceClose := closeChannelAndAssertType( - ctxt, t, net, alice, aliceChanPoint, - c == lnrpc.CommitmentType_ANCHORS, true, + ctxt, t, net, alice, aliceChanPoint, hasAnchors, true, ) // Wait for the channel to be marked pending force close. @@ -99,29 +99,29 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest // After closeChannelAndAssertType returns, it has mined a block so now // bob will attempt to redeem his anchor commitment (if the channel // type is of that type). - if c == lnrpc.CommitmentType_ANCHORS { + if hasAnchors { _, err = waitForNTxsInMempool( net.Miner.Client, 1, minerMempoolTimeout, ) - if err != nil { - t.Fatalf("unable to find bob's anchor commit sweep: %v", - err) - } + require.NoError(t.t, err) } - // Mine enough blocks for Alice to sweep her funds from the force - // closed channel. closeChannelAndAssertType() already mined a block - // containing the commitment tx and the commit sweep tx will be - // broadcast immediately before it can be included in a block, so mine - // one less than defaultCSV in order to perform mempool assertions. - _, err = net.Miner.Client.Generate(defaultCSV - 1) - require.NoError(t.t, err) - - // Alice should now sweep her funds. - _, err = waitForNTxsInMempool( - net.Miner.Client, 1, minerMempoolTimeout, - ) - require.NoError(t.t, err) + if c != lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + // Mine enough blocks for Alice to sweep her funds from the + // force closed channel. closeChannelAndAssertType() already + // mined a block containing the commitment tx and the commit + // sweep tx will be broadcast immediately before it can be + // included in a block, so mine one less than defaultCSV in + // order to perform mempool assertions. + _, err = net.Miner.Client.Generate(defaultCSV - 1) + require.NoError(t.t, err) + + // Alice should now sweep her funds. + _, err = waitForNTxsInMempool( + net.Miner.Client, 1, minerMempoolTimeout, + ) + require.NoError(t.t, err) + } // Suspend bob, so Carol is forced to go on chain. restartBob, err := net.SuspendNode(bob) @@ -142,14 +142,17 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest // We'll now mine enough blocks so Carol decides that she needs to go // on-chain to claim the HTLC as Bob has been inactive. numBlocks := padCLTV(uint32( - invoiceReq.CltvExpiry-lncfg.DefaultIncomingBroadcastDelta, - ) - defaultCSV) + invoiceReq.CltvExpiry - lncfg.DefaultIncomingBroadcastDelta, + )) + if c != lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + numBlocks -= defaultCSV + } _, err = net.Miner.Client.Generate(numBlocks) require.NoError(t.t, err) expectedTxes := 1 - if c == lnrpc.CommitmentType_ANCHORS { + if hasAnchors { expectedTxes = 2 } @@ -183,14 +186,31 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest err = restartBob() require.NoError(t.t, err) - // After the force close transacion is mined, Carol should broadcast her - // second level HTLC transacion. Bob will broadcast a sweep tx to sweep - // his output in the channel with Carol. He can do this immediately, as - // the output is not timelocked since Carol was the one force closing. - // If there are anchors, Bob should also sweep his. - expectedTxes = 2 - if c == lnrpc.CommitmentType_ANCHORS { + // After the force close transacion is mined, we should expect Bob and + // Carol to broadcast some transactions depending on the channel + // commitment type. + switch c { + // Carol should broadcast her second level HTLC transaction and Bob + // should broadcast a transaction to sweep his commitment output. + case lnrpc.CommitmentType_LEGACY: + expectedTxes = 2 + + // Carol should broadcast her second level HTLC transaction and Bob + // should broadcast a transaction to sweep his commitment output and + // another to sweep his anchor output. + case lnrpc.CommitmentType_ANCHORS: expectedTxes = 3 + + // Carol should broadcast her second level HTLC transaction and Bob + // should broadcast a transaction to sweep his anchor output. Bob can't + // sweep his commitment output yet as he has incurred an additional CLTV + // due to being the channel initiator of a force closed script-enforced + // leased channel. + case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: + expectedTxes = 2 + + default: + t.Fatalf("unhandled commitment type %v", c) } txes, err := getNTxsFromMempool( net.Miner.Client, expectedTxes, minerMempoolTimeout, @@ -230,11 +250,19 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest carolSecondLevelCSV-- // Now that the sweeping transaction has been confirmed, Bob should now - // recognize that all contracts have been fully resolved, and show no - // pending close channels. - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - err = waitForNumChannelPendingForceClose(ctxt, bob, 0, nil) - require.NoError(t.t, err) + // recognize that all contracts for the Bob-Carol channel have been + // fully resolved + aliceBobPendingChansLeft := 0 + if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + aliceBobPendingChansLeft = 1 + } + for _, node := range []*lntest.HarnessNode{alice, bob} { + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = waitForNumChannelPendingForceClose( + ctxt, node, aliceBobPendingChansLeft, nil, + ) + require.NoError(t.t, err) + } // If we then mine 3 additional blocks, Carol's second level tx will // mature, and she should pull the funds. @@ -255,6 +283,54 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest err = waitForNumChannelPendingForceClose(ctxt, carol, 0, nil) require.NoError(t.t, err) + // With the script-enforced lease commitment type, Alice and Bob still + // haven't been able to sweep their respective commit outputs due to the + // additional CLTV. We'll need to mine enough blocks for the timelock to + // expire and prompt their sweep. + if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + // Due to the way the test is set up, Alice and Bob share the + // same CLTV for their commit outputs even though it's enforced + // on different channels (Alice-Bob and Bob-Carol). + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + resp, err := alice.PendingChannels( + ctxt, &lnrpc.PendingChannelsRequest{}, + ) + require.NoError(t.t, err) + require.Len(t.t, resp.PendingForceClosingChannels, 1) + forceCloseChan := resp.PendingForceClosingChannels[0] + require.Positive(t.t, forceCloseChan.BlocksTilMaturity) + + // Mine enough blocks for the timelock to expire. + numBlocks := uint32(forceCloseChan.BlocksTilMaturity) + _, err = net.Miner.Client.Generate(numBlocks) + require.NoError(t.t, err) + + // Both Alice and Bob show broadcast their commit sweeps. + aliceCommitOutpoint := wire.OutPoint{Hash: *aliceForceClose, Index: 3} + aliceCommitSweep := assertSpendingTxInMempool( + t, net.Miner.Client, minerMempoolTimeout, + aliceCommitOutpoint, + ) + bobCommitOutpoint := wire.OutPoint{Hash: closingTxid, Index: 3} + bobCommitSweep := assertSpendingTxInMempool( + t, net.Miner.Client, minerMempoolTimeout, + bobCommitOutpoint, + ) + + // Confirm their sweeps. + block := mineBlocks(t, net, 1, 2)[0] + assertTxInBlock(t, block, &aliceCommitSweep) + assertTxInBlock(t, block, &bobCommitSweep) + + // Alice and Bob should not show any pending channels anymore as + // they have been fully resolved. + for _, node := range []*lntest.HarnessNode{alice, bob} { + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = waitForNumChannelPendingForceClose(ctxt, node, 0, nil) + require.NoError(t.t, err) + } + } + // The invoice should show as settled for Carol, indicating that it was // swept on-chain. invoicesReq := &lnrpc.ListInvoiceRequest{} diff --git a/lntest/itest/lnd_multi-hop_local_force_close_on_chain_htlc_timeout_test.go b/lntest/itest/lnd_multi-hop_local_force_close_on_chain_htlc_timeout_test.go index d61278e0c7a..39dd7c57ebd 100644 --- a/lntest/itest/lnd_multi-hop_local_force_close_on_chain_htlc_timeout_test.go +++ b/lntest/itest/lnd_multi-hop_local_force_close_on_chain_htlc_timeout_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" @@ -73,9 +74,9 @@ func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness, // force close the Bob -> Carol channel. This should trigger contract // resolution mode for both of them. ctxt, _ := context.WithTimeout(ctxb, channelCloseTimeout) - closeChannelAndAssertType( - ctxt, t, net, bob, bobChanPoint, - c == lnrpc.CommitmentType_ANCHORS, true, + hasAnchors := commitTypeHasAnchors(c) + closeTx := closeChannelAndAssertType( + ctxt, t, net, bob, bobChanPoint, hasAnchors, true, ) // At this point, Bob should have a pending force close channel as he @@ -94,27 +95,45 @@ func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness, ) require.NoError(t.t, err) - // We'll mine defaultCSV blocks in order to generate the sweep - // transaction of Bob's funding output. If there are anchors, mine - // Carol's anchor sweep too. - if c == lnrpc.CommitmentType_ANCHORS { + // If the channel closed has anchors, we should expect to see a sweep + // transaction for Carol's anchor. + htlcOutpoint := wire.OutPoint{Hash: *closeTx, Index: 0} + bobCommitOutpoint := wire.OutPoint{Hash: *closeTx, Index: 1} + if hasAnchors { + htlcOutpoint.Index = 2 + bobCommitOutpoint.Index = 3 _, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout) require.NoError(t.t, err) } - // The sweep is broadcast on the block immediately before the CSV - // expires and the commitment was already mined inside - // closeChannelAndAssertType(), so mine one block less than defaultCSV - // in order to perform mempool assertions. - _, err = net.Miner.Client.Generate(defaultCSV - 1) - require.NoError(t.t, err) + // Before the HTLC times out, we'll need to assert that Bob broadcasts a + // sweep transaction for his commit output. Note that if the channel has + // a script-enforced lease, then Bob will have to wait for an additional + // CLTV before sweeping it. + if c != lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + // The sweep is broadcast on the block immediately before the + // CSV expires and the commitment was already mined inside + // closeChannelAndAssertType(), so mine one block less than + // defaultCSV in order to perform mempool assertions. + _, err = net.Miner.Client.Generate(defaultCSV - 1) + require.NoError(t.t, err) - _, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout) - require.NoError(t.t, err) + commitSweepTx := assertSpendingTxInMempool( + t, net.Miner.Client, minerMempoolTimeout, + bobCommitOutpoint, + ) + blocks := mineBlocks(t, net, 1, 1) + assertTxInBlock(t, blocks[0], &commitSweepTx) + } // We'll now mine enough blocks for the HTLC to expire. After this, Bob // should hand off the now expired HTLC output to the utxo nursery. - numBlocks := padCLTV(uint32(finalCltvDelta - defaultCSV)) + numBlocks := padCLTV(finalCltvDelta) + if c != lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + // Subtract the number of blocks already mined to confirm Bob's + // commit sweep. + numBlocks -= defaultCSV + } _, err = net.Miner.Client.Generate(numBlocks) require.NoError(t.t, err) @@ -140,13 +159,14 @@ func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness, // We should also now find a transaction in the mempool, as Bob should // have broadcast his second layer timeout transaction. - timeoutTx, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout) - require.NoError(t.t, err) + timeoutTx := assertSpendingTxInMempool( + t, net.Miner.Client, minerMempoolTimeout, htlcOutpoint, + ) // Next, we'll mine an additional block. This should serve to confirm // the second layer timeout transaction. block := mineBlocks(t, net, 1, 1)[0] - assertTxInBlock(t, block, timeoutTx) + assertTxInBlock(t, block, &timeoutTx) // With the second layer timeout transaction confirmed, Bob should have // canceled backwards the HTLC that carol sent. @@ -176,19 +196,37 @@ func testMultiHopLocalForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness, ) require.NoError(t.t, err) - // We'll now mine 4 additional blocks. This should be enough for Bob's - // CSV timelock to expire and the sweeping transaction of the HTLC to be - // broadcast. - _, err = net.Miner.Client.Generate(defaultCSV) + // Bob should now broadcast a transaction that sweeps certain inputs + // depending on the commitment type. We'll need to mine some blocks + // before the broadcast is possible. + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + resp, err := bob.PendingChannels(ctxt, &lnrpc.PendingChannelsRequest{}) require.NoError(t.t, err) - sweepTx, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout) + require.Len(t.t, resp.PendingForceClosingChannels, 1) + forceCloseChan := resp.PendingForceClosingChannels[0] + require.Len(t.t, forceCloseChan.PendingHtlcs, 1) + pendingHtlc := forceCloseChan.PendingHtlcs[0] + require.Positive(t.t, pendingHtlc.BlocksTilMaturity) + numBlocks = uint32(pendingHtlc.BlocksTilMaturity) + + _, err = net.Miner.Client.Generate(numBlocks) require.NoError(t.t, err) - // We'll then mine a final block which should confirm this second layer - // sweep transaction. + // Now that the CSV/CLTV timelock has expired, the transaction should + // either only sweep the HTLC timeout transaction, or sweep both the + // HTLC timeout transaction and Bob's commit output depending on the + // commitment type. + htlcTimeoutOutpoint := wire.OutPoint{Hash: timeoutTx, Index: 0} + expectedInputsSwept := []wire.OutPoint{htlcTimeoutOutpoint} + if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + expectedInputsSwept = append(expectedInputsSwept, bobCommitOutpoint) + } + sweepTx := assertSpendingTxInMempool( + t, net.Miner.Client, minerMempoolTimeout, expectedInputsSwept..., + ) block = mineBlocks(t, net, 1, 1)[0] - assertTxInBlock(t, block, sweepTx) + assertTxInBlock(t, block, &sweepTx) // At this point, Bob should no longer show any channels as pending // close. diff --git a/lntest/itest/lnd_multi-hop_remote_force_close_on_chain_htlc_timeout_test.go b/lntest/itest/lnd_multi-hop_remote_force_close_on_chain_htlc_timeout_test.go index a20466135b4..961b3165e6a 100644 --- a/lntest/itest/lnd_multi-hop_remote_force_close_on_chain_htlc_timeout_test.go +++ b/lntest/itest/lnd_multi-hop_remote_force_close_on_chain_htlc_timeout_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" @@ -84,9 +85,9 @@ func testMultiHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness, // expired HTLC on Carol's version of the commitment transaction. If // Carol has an anchor, it will be swept too. ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) - closeChannelAndAssertType( - ctxt, t, net, carol, bobChanPoint, - c == lnrpc.CommitmentType_ANCHORS, true, + hasAnchors := commitTypeHasAnchors(c) + closeTx := closeChannelAndAssertType( + ctxt, t, net, carol, bobChanPoint, hasAnchors, true, ) // At this point, Bob should have a pending force close channel as @@ -95,13 +96,25 @@ func testMultiHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness, err = waitForNumChannelPendingForceClose(ctxt, bob, 1, nil) require.NoError(t.t, err) - // Bob can sweep his output immediately. If there is an anchor, Bob will - // sweep that as well. - expectedTxes := 1 - if c == lnrpc.CommitmentType_ANCHORS { + var expectedTxes int + switch c { + // Bob can sweep his commit output immediately. + case lnrpc.CommitmentType_LEGACY: + expectedTxes = 1 + + // Bob can sweep his commit and anchor outputs immediately. + case lnrpc.CommitmentType_ANCHORS: expectedTxes = 2 - } + // Bob can't sweep his commit output yet as he was the initiator of a + // script-enforced leased channel, so he'll always incur the additional + // CLTV. He can still sweep his anchor output however. + case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: + expectedTxes = 1 + + default: + t.Fatalf("unhandled commitment type %v", c) + } _, err = waitForNTxsInMempool( net.Miner.Client, expectedTxes, minerMempoolTimeout, ) @@ -172,8 +185,32 @@ func testMultiHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness, require.NoError(t.t, err) // Now we'll check Bob's pending channel report. Since this was Carol's - // commitment, he doesn't have to wait for any CSV delays. As a result, - // he should show no additional pending transactions. + // commitment, he doesn't have to wait for any CSV delays, but he may + // still need to wait for a CLTV on his commit output to expire + // depending on the commitment type. + if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + resp, err := bob.PendingChannels( + ctxt, &lnrpc.PendingChannelsRequest{}, + ) + require.NoError(t.t, err) + + require.Len(t.t, resp.PendingForceClosingChannels, 1) + forceCloseChan := resp.PendingForceClosingChannels[0] + require.Positive(t.t, forceCloseChan.BlocksTilMaturity) + + numBlocks := uint32(forceCloseChan.BlocksTilMaturity) + _, err = net.Miner.Client.Generate(numBlocks) + require.NoError(t.t, err) + + bobCommitOutpoint := wire.OutPoint{Hash: *closeTx, Index: 3} + bobCommitSweep := assertSpendingTxInMempool( + t, net.Miner.Client, minerMempoolTimeout, + bobCommitOutpoint, + ) + block := mineBlocks(t, net, 1, 1)[0] + assertTxInBlock(t, block, &bobCommitSweep) + } ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) err = waitForNumChannelPendingForceClose(ctxt, bob, 0, nil) require.NoError(t.t, err) diff --git a/lntest/itest/lnd_multi-hop_test.go b/lntest/itest/lnd_multi-hop_test.go index 0001f7d0c10..f8af2e6de9e 100644 --- a/lntest/itest/lnd_multi-hop_test.go +++ b/lntest/itest/lnd_multi-hop_test.go @@ -12,6 +12,7 @@ import ( "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntypes" + "github.com/stretchr/testify/require" ) func testMultiHopHtlcClaims(net *lntest.NetworkHarness, t *harnessTest) { @@ -71,6 +72,7 @@ func testMultiHopHtlcClaims(net *lntest.NetworkHarness, t *harnessTest) { commitTypes := []lnrpc.CommitmentType{ lnrpc.CommitmentType_LEGACY, lnrpc.CommitmentType_ANCHORS, + lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE, } for _, commitType := range commitTypes { @@ -223,12 +225,23 @@ func createThreeHopNetwork(t *harnessTest, net *lntest.NetworkHarness, // We'll start the test by creating a channel between Alice and Bob, // which will act as the first leg for out multi-hop HTLC. const chanAmt = 1000000 + var aliceFundingShim *lnrpc.FundingShim + var thawHeight uint32 + if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + _, minerHeight, err := net.Miner.Client.GetBestBlock() + require.NoError(t.t, err) + thawHeight = uint32(minerHeight + 144) + aliceFundingShim, _, _ = deriveFundingShim( + net, t, alice, bob, chanAmt, thawHeight, true, + ) + } ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout) aliceChanPoint := openChannelAndAssert( ctxt, t, net, alice, bob, lntest.OpenChannelParams{ Amt: chanAmt, CommitmentType: c, + FundingShim: aliceFundingShim, }, ) @@ -267,12 +280,19 @@ func createThreeHopNetwork(t *harnessTest, net *lntest.NetworkHarness, // We'll then create a channel from Bob to Carol. After this channel is // open, our topology looks like: A -> B -> C. + var bobFundingShim *lnrpc.FundingShim + if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + bobFundingShim, _, _ = deriveFundingShim( + net, t, bob, carol, chanAmt, thawHeight, true, + ) + } ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout) bobChanPoint := openChannelAndAssert( ctxt, t, net, bob, carol, lntest.OpenChannelParams{ Amt: chanAmt, CommitmentType: c, + FundingShim: bobFundingShim, }, ) ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) diff --git a/lntest/itest/utils.go b/lntest/itest/utils.go index c6945096ec3..b4beecc1c2e 100644 --- a/lntest/itest/utils.go +++ b/lntest/itest/utils.go @@ -203,6 +203,17 @@ func getChanInfo(ctx context.Context, node *lntest.HarnessNode) ( return channelInfo.Channels[0], nil } +// commitTypeHasAnchors returns whether commitType uses anchor outputs. +func commitTypeHasAnchors(commitType lnrpc.CommitmentType) bool { + switch commitType { + case lnrpc.CommitmentType_ANCHORS, + lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: + return true + default: + return false + } +} + // nodeArgsForCommitType returns the command line flag to supply to enable this // commitment type. func nodeArgsForCommitType(commitType lnrpc.CommitmentType) []string { @@ -213,6 +224,11 @@ func nodeArgsForCommitType(commitType lnrpc.CommitmentType) []string { return []string{} case lnrpc.CommitmentType_ANCHORS: return []string{"--protocol.anchors"} + case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: + return []string{ + "--protocol.anchors", + "--protocol.script-enforced-lease", + } } return nil @@ -233,7 +249,7 @@ func calcStaticFee(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount { // the value of the two anchors to the resulting fee the initiator // pays. In addition the fee rate is capped at 10 sat/vbyte for anchor // channels. - if c == lnrpc.CommitmentType_ANCHORS { + if commitTypeHasAnchors(c) { feePerKw = chainfee.SatPerKVByte( lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte * 1000, ).FeePerKWeight() From ee40e8eba3b05cf6ecc02f05ed92d9d4446b1164 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Mon, 26 Jul 2021 13:03:00 -0700 Subject: [PATCH 27/29] chanbackup: support backup restore of script enforced leased channels --- chanbackup/single.go | 41 ++++++++++++++++++++++++++++++++++++++- chanbackup/single_test.go | 16 ++++++++++----- chanrestore.go | 7 +++++++ 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/chanbackup/single.go b/chanbackup/single.go index e51700c886d..d8a12525750 100644 --- a/chanbackup/single.go +++ b/chanbackup/single.go @@ -40,6 +40,13 @@ const ( // AnchorsZeroFeeHtlcTxCommitVersion is a version that denotes this // channel is using the zero-fee second-level anchor commitment format. AnchorsZeroFeeHtlcTxCommitVersion = 3 + + // ScriptEnforcedLeaseVersion is a version that denotes this channel is + // using the zero-fee second-level anchor commitment format along with + // an additional CLTV requirement of the channel lease maturity on any + // commitment and HTLC outputs that pay directly to the channel + // initiator. + ScriptEnforcedLeaseVersion = 4 ) // Single is a static description of an existing channel that can be used for @@ -116,6 +123,16 @@ type Single struct { // ShaChainRootDesc describes how to derive the private key that was // used as the shachain root for this channel. ShaChainRootDesc keychain.KeyDescriptor + + // LeaseExpiry represents the absolute expiration as a height of the + // chain of a channel lease that is applied to every output that pays + // directly to the channel initiator in addition to the usual CSV + // requirement. + // + // NOTE: This field will only be present for the following versions: + // + // - ScriptEnforcedLeaseVersion + LeaseExpiry uint32 } // NewSingle creates a new static channel backup based on an existing open @@ -177,6 +194,10 @@ func NewSingle(channel *channeldb.OpenChannel, } switch { + case channel.ChanType.HasLeaseExpiration(): + single.Version = ScriptEnforcedLeaseVersion + single.LeaseExpiry = channel.ThawHeight + case channel.ChanType.ZeroHtlcTxFee(): single.Version = AnchorsZeroFeeHtlcTxCommitVersion @@ -203,6 +224,7 @@ func (s *Single) Serialize(w io.Writer) error { case TweaklessCommitVersion: case AnchorsCommitVersion: case AnchorsZeroFeeHtlcTxCommitVersion: + case ScriptEnforcedLeaseVersion: default: return fmt.Errorf("unable to serialize w/ unknown "+ "version: %v", s.Version) @@ -264,6 +286,12 @@ func (s *Single) Serialize(w io.Writer) error { ); err != nil { return err } + if s.Version == ScriptEnforcedLeaseVersion { + err := lnwire.WriteElements(&singleBytes, s.LeaseExpiry) + if err != nil { + return err + } + } return lnwire.WriteElements( w, @@ -363,6 +391,7 @@ func (s *Single) Deserialize(r io.Reader) error { case TweaklessCommitVersion: case AnchorsCommitVersion: case AnchorsZeroFeeHtlcTxCommitVersion: + case ScriptEnforcedLeaseVersion: default: return fmt.Errorf("unable to de-serialize w/ unknown "+ "version: %v", s.Version) @@ -456,8 +485,18 @@ func (s *Single) Deserialize(r io.Reader) error { return err } s.ShaChainRootDesc.KeyLocator.Family = keychain.KeyFamily(shaKeyFam) + err = lnwire.ReadElements(r, &s.ShaChainRootDesc.KeyLocator.Index) + if err != nil { + return err + } + + if s.Version == ScriptEnforcedLeaseVersion { + if err := lnwire.ReadElement(r, &s.LeaseExpiry); err != nil { + return err + } + } - return lnwire.ReadElements(r, &s.ShaChainRootDesc.KeyLocator.Index) + return nil } // UnpackFromReader is similar to Deserialize method, but it expects the passed diff --git a/chanbackup/single_test.go b/chanbackup/single_test.go index ee20d892f6b..97141ec9f3d 100644 --- a/chanbackup/single_test.go +++ b/chanbackup/single_test.go @@ -124,10 +124,7 @@ func genRandomOpenChannelShell() (*channeldb.OpenChannel, error) { isInitiator = true } - chanType := channeldb.SingleFunderBit - if rand.Int63()%2 == 0 { - chanType = channeldb.SingleFunderTweaklessBit - } + chanType := channeldb.ChannelType(rand.Intn(8)) return &channeldb.OpenChannel{ ChainHash: chainHash, @@ -137,6 +134,7 @@ func genRandomOpenChannelShell() (*channeldb.OpenChannel, error) { ShortChannelID: lnwire.NewShortChanIDFromInt( uint64(rand.Int63()), ), + ThawHeight: rand.Uint32(), IdentityPub: pub, LocalChanCfg: channeldb.ChannelConfig{ ChannelConstraints: channeldb.ChannelConstraints{ @@ -243,6 +241,13 @@ func TestSinglePackUnpack(t *testing.T) { valid: true, }, + // The new script enforced channel lease version should + // pack/unpack with no problem. + { + version: ScriptEnforcedLeaseVersion, + valid: true, + }, + // A non-default version, atm this should result in a failure. { version: 99, @@ -293,8 +298,9 @@ func TestSinglePackUnpack(t *testing.T) { t.Fatalf("unable to serialize single: %v", err) } + // Mutate the version byte to an unknown version. rawBytes := rawSingle.Bytes() - rawBytes[0] ^= 5 + rawBytes[0] = ^uint8(0) newReader := bytes.NewReader(rawBytes) err = unpackedSingle.Deserialize(newReader) diff --git a/chanrestore.go b/chanrestore.go index 7527499cd3b..6013568875a 100644 --- a/chanrestore.go +++ b/chanrestore.go @@ -149,6 +149,12 @@ func (c *chanDBRestorer) openChannelShell(backup chanbackup.Single) ( chanType |= channeldb.AnchorOutputsBit chanType |= channeldb.SingleFunderTweaklessBit + case chanbackup.ScriptEnforcedLeaseVersion: + chanType = channeldb.LeaseExpirationBit + chanType |= channeldb.ZeroHtlcTxFeeBit + chanType |= channeldb.AnchorOutputsBit + chanType |= channeldb.SingleFunderTweaklessBit + default: return nil, fmt.Errorf("unknown Single version: %v", err) } @@ -172,6 +178,7 @@ func (c *chanDBRestorer) openChannelShell(backup chanbackup.Single) ( RemoteCurrentRevocation: backup.RemoteNodePub, RevocationStore: shachain.NewRevocationStore(), RevocationProducer: shaChainProducer, + ThawHeight: backup.LeaseExpiry, }, } From 19e01add460cac5d1e3b4d0c16898e0251834fcc Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Mon, 26 Jul 2021 13:03:41 -0700 Subject: [PATCH 28/29] itest: test backup restore of script enforced lease channel type --- lntest/itest/assertions.go | 118 ++++++++++++++++++------ lntest/itest/lnd_channel_backup_test.go | 69 ++++++++++---- lntest/itest/lnd_misc_test.go | 2 +- 3 files changed, 142 insertions(+), 47 deletions(-) diff --git a/lntest/itest/assertions.go b/lntest/itest/assertions.go index 5123d8be4d3..d06c54775a1 100644 --- a/lntest/itest/assertions.go +++ b/lntest/itest/assertions.go @@ -1260,7 +1260,7 @@ func assertNumPendingChannels(t *harnessTest, node *lntest.HarnessNode, func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest, carol *lntest.HarnessNode, carolStartingBalance int64, dave *lntest.HarnessNode, daveStartingBalance int64, - anchors bool) { + commitType lnrpc.CommitmentType) { // Increase the fee estimate so that the following force close tx will // be cpfp'ed. @@ -1275,7 +1275,7 @@ func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest, // Upon reconnection, the nodes should detect that Dave is out of sync. // Carol should force close the channel using her latest commitment. expectedTxes := 1 - if anchors { + if commitTypeHasAnchors(commitType) { expectedTxes = 2 } _, err := waitForNTxsInMempool( @@ -1302,14 +1302,6 @@ func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest, // Generate a single block, which should confirm the closing tx. _ = mineBlocks(t, net, 1, expectedTxes)[0] - // Dave should sweep his funds immediately, as they are not timelocked. - // We also expect Dave to sweep his anchor, if present. - - _, err = waitForNTxsInMempool( - net.Miner.Client, expectedTxes, minerMempoolTimeout, - ) - require.NoError(t.t, err, "unable to find Dave's sweep tx in mempool") - // Dave should consider the channel pending force close (since he is // waiting for his sweep to confirm). assertNumPendingChannels(t, dave, 0, 1) @@ -1318,11 +1310,93 @@ func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest, // before she can sweep her outputs. assertNumPendingChannels(t, carol, 0, 1) - // Mine the sweep tx. - _ = mineBlocks(t, net, 1, expectedTxes)[0] + if commitType == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + // Dave should sweep his anchor only, since he still has the + // lease CLTV constraint on his commitment output. + _, err = waitForNTxsInMempool( + net.Miner.Client, 1, minerMempoolTimeout, + ) + require.NoError(t.t, err, "unable to find Dave's anchor sweep "+ + "tx in mempool") + + // Mine Dave's anchor sweep tx. + _ = mineBlocks(t, net, 1, 1)[0] + + // After Carol's output matures, she should also reclaim her + // funds. + // + // The commit sweep resolver publishes the sweep tx at + // defaultCSV-1 and we already mined one block after the + // commitmment was published, so take that into account. + mineBlocks(t, net, defaultCSV-1-1, 0) + carolSweep, err := waitForTxInMempool( + net.Miner.Client, minerMempoolTimeout, + ) + require.NoError(t.t, err, "unable to find Carol's sweep tx in "+ + "mempool") + block := mineBlocks(t, net, 1, 1)[0] + assertTxInBlock(t, block, carolSweep) + + // Now the channel should be fully closed also from Carol's POV. + assertNumPendingChannels(t, carol, 0, 0) + + // We'll now mine the remaining blocks to prompt Dave to sweep + // his CLTV-constrained output. + ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) + defer cancel() + resp, err := dave.PendingChannels( + ctxt, &lnrpc.PendingChannelsRequest{}, + ) + require.NoError(t.t, err) + blocksTilMaturity := + resp.PendingForceClosingChannels[0].BlocksTilMaturity + require.Positive(t.t, blocksTilMaturity) - // Now Dave should consider the channel fully closed. - assertNumPendingChannels(t, dave, 0, 0) + mineBlocks(t, net, uint32(blocksTilMaturity), 0) + daveSweep, err := waitForTxInMempool( + net.Miner.Client, minerMempoolTimeout, + ) + require.NoError(t.t, err, "unable to find Dave's sweep tx in "+ + "mempool") + block = mineBlocks(t, net, 1, 1)[0] + assertTxInBlock(t, block, daveSweep) + + // Now Dave should consider the channel fully closed. + assertNumPendingChannels(t, dave, 0, 0) + } else { + // Dave should sweep his funds immediately, as they are not + // timelocked. We also expect Dave to sweep his anchor, if + // present. + _, err = waitForNTxsInMempool( + net.Miner.Client, expectedTxes, minerMempoolTimeout, + ) + require.NoError(t.t, err, "unable to find Dave's sweep tx in "+ + "mempool") + + // Mine the sweep tx. + _ = mineBlocks(t, net, 1, expectedTxes)[0] + + // Now Dave should consider the channel fully closed. + assertNumPendingChannels(t, dave, 0, 0) + + // After Carol's output matures, she should also reclaim her + // funds. + // + // The commit sweep resolver publishes the sweep tx at + // defaultCSV-1 and we already mined one block after the + // commitmment was published, so take that into account. + mineBlocks(t, net, defaultCSV-1-1, 0) + carolSweep, err := waitForTxInMempool( + net.Miner.Client, minerMempoolTimeout, + ) + require.NoError(t.t, err, "unable to find Carol's sweep tx in "+ + "mempool") + block := mineBlocks(t, net, 1, 1)[0] + assertTxInBlock(t, block, carolSweep) + + // Now the channel should be fully closed also from Carol's POV. + assertNumPendingChannels(t, carol, 0, 0) + } // We query Dave's balance to make sure it increased after the channel // closed. This checks that he was able to sweep the funds he had in @@ -1337,22 +1411,6 @@ func assertDLPExecuted(net *lntest.NetworkHarness, t *harnessTest, t.t, daveBalance, daveStartingBalance, "balance not increased", ) - // After the Carol's output matures, she should also reclaim her funds. - // - // The commit sweep resolver publishes the sweep tx at defaultCSV-1 and - // we already mined one block after the commitmment was published, so - // take that into account. - mineBlocks(t, net, defaultCSV-1-1, 0) - carolSweep, err := waitForTxInMempool( - net.Miner.Client, minerMempoolTimeout, - ) - require.NoError(t.t, err, "unable to find Carol's sweep tx in mempool") - block := mineBlocks(t, net, 1, 1)[0] - assertTxInBlock(t, block, carolSweep) - - // Now the channel should be fully closed also from Carol's POV. - assertNumPendingChannels(t, carol, 0, 0) - // Make sure Carol got her balance back. err = wait.NoError(func() error { ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) diff --git a/lntest/itest/lnd_channel_backup_test.go b/lntest/itest/lnd_channel_backup_test.go index 3dbbe1edf84..73ace1533af 100644 --- a/lntest/itest/lnd_channel_backup_test.go +++ b/lntest/itest/lnd_channel_backup_test.go @@ -336,10 +336,37 @@ func testChannelBackupRestore(net *lntest.NetworkHarness, t *harnessTest) { // Restore the backup from the on-disk file, using the RPC // interface, for anchor commitment channels. { - name: "restore from backup file anchors", - initiator: true, - private: false, - anchorCommit: true, + name: "restore from backup file anchors", + initiator: true, + private: false, + commitmentType: lnrpc.CommitmentType_ANCHORS, + restoreMethod: func(oldNode *lntest.HarnessNode, + backupFilePath string, + mnemonic []string) (nodeRestorer, error) { + + // Read the entire Multi backup stored within + // this node's channels.backup file. + multi, err := ioutil.ReadFile(backupFilePath) + if err != nil { + return nil, err + } + + // Now that we have Dave's backup file, we'll + // create a new nodeRestorer that will restore + // using the on-disk channels.backup. + return chanRestoreViaRPC( + net, password, mnemonic, multi, oldNode, + ) + }, + }, + + // Restore the backup from the on-disk file, using the RPC + // interface, for script-enforced leased channels. + { + name: "restore from backup file script enforced lease", + initiator: true, + private: false, + commitmentType: lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE, restoreMethod: func(oldNode *lntest.HarnessNode, backupFilePath string, mnemonic []string) (nodeRestorer, error) { @@ -785,9 +812,9 @@ type chanRestoreTestCase struct { // confirmed or not. unconfirmed bool - // anchorCommit is true, then the new anchor commitment type will be - // used for the channels created in the test. - anchorCommit bool + // commitmentType specifies the commitment type that should be used for + // the channel from Dave to Carol. + commitmentType lnrpc.CommitmentType // legacyRevocation signals if a channel with the legacy revocation // producer format should also be created before restoring. @@ -821,11 +848,9 @@ func testChanRestoreScenario(t *harnessTest, net *lntest.NetworkHarness, "--minbackoff=50ms", "--maxbackoff=1s", } - if testCase.anchorCommit { - anchorNodeArgs := nodeArgsForCommitType( - lnrpc.CommitmentType_ANCHORS, - ) - nodeArgs = append(nodeArgs, anchorNodeArgs...) + if testCase.commitmentType != lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE { + args := nodeArgsForCommitType(testCase.commitmentType) + nodeArgs = append(nodeArgs, args...) } // First, we'll create a brand new node we'll use within the test. If @@ -899,13 +924,25 @@ func testChanRestoreScenario(t *harnessTest, net *lntest.NetworkHarness, ) default: + var fundingShim *lnrpc.FundingShim + if testCase.commitmentType == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + _, minerHeight, err := net.Miner.Client.GetBestBlock() + require.NoError(t.t, err) + thawHeight := uint32(minerHeight + 144) + + fundingShim, _, _ = deriveFundingShim( + net, t, from, to, chanAmt, thawHeight, true, + ) + } ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout) chanPoint := openChannelAndAssert( ctxt, t, net, from, to, lntest.OpenChannelParams{ - Amt: chanAmt, - PushAmt: pushAmt, - Private: testCase.private, + Amt: chanAmt, + PushAmt: pushAmt, + Private: testCase.private, + FundingShim: fundingShim, + CommitmentType: testCase.commitmentType, }, ) @@ -1092,7 +1129,7 @@ func testChanRestoreScenario(t *harnessTest, net *lntest.NetworkHarness, // end of the protocol. assertDLPExecuted( net, t, carol, carolStartingBalance, dave, daveStartingBalance, - testCase.anchorCommit, + testCase.commitmentType, ) } diff --git a/lntest/itest/lnd_misc_test.go b/lntest/itest/lnd_misc_test.go index aa7bf25dabb..cd67dbe271c 100644 --- a/lntest/itest/lnd_misc_test.go +++ b/lntest/itest/lnd_misc_test.go @@ -1056,7 +1056,7 @@ func testDataLossProtection(net *lntest.NetworkHarness, t *harnessTest) { // on chain, and both of them properly carry out the DLP protocol. assertDLPExecuted( net, t, carol, carolStartingBalance, dave, daveStartingBalance, - false, + lnrpc.CommitmentType_STATIC_REMOTE_KEY, ) // As a second part of this test, we will test the scenario where a From debc95c66220f3d1fec006946402786261cf7866 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Fri, 30 Jul 2021 15:28:10 -0700 Subject: [PATCH 29/29] docs: add script enforced channel leases text to release notes --- docs/release-notes/release-notes-0.14.0.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/release-notes/release-notes-0.14.0.md b/docs/release-notes/release-notes-0.14.0.md index 6a1400e12dc..8364dd6226d 100644 --- a/docs/release-notes/release-notes-0.14.0.md +++ b/docs/release-notes/release-notes-0.14.0.md @@ -11,6 +11,18 @@ the remote peer supports said channel type and agrees, the previous implicit negotiation based on the shared set of feature bits is bypassed, and the proposed channel type is used. +### Script Enforced Channel Leases + +[A new channel commitment type that builds upon the recently introduced anchors +commitment format has been introduced to back channel leases resulting from +Lightning Pool](https://github.com/lightningnetwork/lnd/pull/5549). This new +channel commitment type features an additional spend requirement on any +commitment and HTLC outputs that pay directly to the channel initiator. The +channel initiator must now wait for the channel lease maturity, expressed as an +absolute height of the chain, to be met before being able to sweep their funds, +on top of the usual CSV delay requirement. See the linked pull request for more +details. + ## RPC Server * [Return payment address and add index from