diff --git a/channeldb/channel.go b/channeldb/channel.go index 42858948534..22e937db268 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -412,6 +412,11 @@ const ( // level tapscript commitment. This MUST be set along with the // SimpleTaprootFeatureBit. TapscriptRootBit ChannelType = 1 << 11 + + // TaprootFinalBit indicates that this is a MuSig2 channel using the + // final/production taproot scripts and feature bits 80/81. This MUST + // be set along with the SimpleTaprootFeatureBit. + TaprootFinalBit ChannelType = 1 << 12 ) // IsSingleFunder returns true if the channel type if one of the known single @@ -488,6 +493,12 @@ func (c ChannelType) HasTapscriptRoot() bool { return c&TapscriptRootBit == TapscriptRootBit } +// IsTaprootFinal returns true if the channel is using final/production taproot +// scripts and feature bits. +func (c ChannelType) IsTaprootFinal() bool { + return c&TaprootFinalBit == TaprootFinalBit +} + // ChannelStateBounds are the parameters from OpenChannel and AcceptChannel // that are responsible for providing bounds on the state space of the abstract // channel state. These values must be remembered for normal channel operation @@ -1741,6 +1752,26 @@ func NewMusigVerificationNonce(pubKey *btcec.PublicKey, targetHeight uint64, return musig2.GenNonces(pubKeyOpt, shaChainRand) } +// chanSyncCfg holds configuration options for ChanSyncMsg. +type chanSyncCfg struct { + // taprootNonceType specifies which nonce format to use when + // constructing the ChannelReestablish message for the peer. + taprootNonceType lnwire.TaprootNonceType +} + +// ChanSyncOpt is a functional option that can be used to modify the behavior of +// ChanSyncMsg. +type ChanSyncOpt func(*chanSyncCfg) + +// WithChanSyncNonceType specifies which nonce format to use when constructing +// the ChannelReestablish message. This is determined by the peer's advertised +// feature bits. +func WithChanSyncNonceType(nonceType lnwire.TaprootNonceType) ChanSyncOpt { + return func(cfg *chanSyncCfg) { + cfg.taprootNonceType = nonceType + } +} + // ChanSyncMsg returns the ChannelReestablish message that should be sent upon // reconnection with the remote peer that we're maintaining this channel with. // The information contained within this message is necessary to re-sync our @@ -1756,7 +1787,16 @@ func NewMusigVerificationNonce(pubKey *btcec.PublicKey, targetHeight uint64, // If this is a restored channel, having status ChanStatusRestored, then we'll // modify our typical chan sync message to ensure they force close even if // we're on the very first state. -func (c *OpenChannel) ChanSyncMsg() (*lnwire.ChannelReestablish, error) { +func (c *OpenChannel) ChanSyncMsg( + opts ...ChanSyncOpt) (*lnwire.ChannelReestablish, error) { + + cfg := &chanSyncCfg{ + taprootNonceType: lnwire.TaprootNonceTypeLegacy, + } + for _, opt := range opts { + opt(cfg) + } + c.Lock() defer c.Unlock() @@ -1836,17 +1876,24 @@ func (c *OpenChannel) ChanSyncMsg() (*lnwire.ChannelReestablish, error) { "nonce: %w", err) } - // Populate the legacy LocalNonce field for backwards compatibility. - nextTaprootNonce = lnwire.SomeMusig2Nonce(nextNonce.PubNonce) - - // Also populate the new LocalNonces field. For channel - // re-establishment, we'll key our nonce by the funding txid. fundingTxid := c.FundingOutpoint.Hash - noncesMap := make(map[chainhash.Hash]lnwire.Musig2Nonce) - noncesMap[fundingTxid] = nextNonce.PubNonce - nextLocalNonces = lnwire.SomeLocalNonces( - lnwire.LocalNoncesData{NoncesMap: noncesMap}, - ) + nonce := nextNonce.PubNonce + + // Set the appropriate nonce field based on the peer's feature + // bits. If they support the final taproot channel feature bits, + // we use the map-based LocalNonces field. Otherwise, we use + // the legacy single LocalNonce field. + switch cfg.taprootNonceType { + case lnwire.TaprootNonceTypeLegacy: + nextTaprootNonce = lnwire.SomeMusig2Nonce(nonce) + + case lnwire.TaprootNonceTypeMap: + noncesMap := make(map[chainhash.Hash]lnwire.Musig2Nonce) + noncesMap[fundingTxid] = nonce + nextLocalNonces = lnwire.SomeLocalNonces( + lnwire.LocalNoncesData{NoncesMap: noncesMap}, + ) + } } return &lnwire.ChannelReestablish{ diff --git a/cmd/commands/cmd_open_channel.go b/cmd/commands/cmd_open_channel.go index b4fe83f20b1..1405cc1256e 100644 --- a/cmd/commands/cmd_open_channel.go +++ b/cmd/commands/cmd_open_channel.go @@ -58,9 +58,10 @@ Signed base64 encoded PSBT or hex encoded raw wire TX (or path to file): ` // of memory issues or other weird errors. psbtMaxFileSize = 1024 * 1024 - channelTypeTweakless = "tweakless" - channelTypeAnchors = "anchors" - channelTypeSimpleTaproot = "taproot" + channelTypeTweakless = "tweakless" + channelTypeAnchors = "anchors" + channelTypeSimpleTaproot = "taproot" + channelTypeSimpleTaprootFinal = "taproot-final" ) // TODO(roasbeef): change default number of confirmations. @@ -253,9 +254,9 @@ var openChannelCommand = cli.Command{ cli.StringFlag{ Name: "channel_type", Usage: fmt.Sprintf("(optional) the type of channel to "+ - "propose to the remote peer (%q, %q, %q)", + "propose to the remote peer (%q, %q, %q, %q)", channelTypeTweakless, channelTypeAnchors, - channelTypeSimpleTaproot), + channelTypeSimpleTaproot, channelTypeSimpleTaprootFinal), }, cli.BoolFlag{ Name: "zero_conf", @@ -446,6 +447,8 @@ func openChannel(ctx *cli.Context) error { req.CommitmentType = lnrpc.CommitmentType_ANCHORS case channelTypeSimpleTaproot: req.CommitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT + case channelTypeSimpleTaprootFinal: + req.CommitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL default: return fmt.Errorf("unsupported channel type %v", channelType) } diff --git a/contractcourt/channel_arbitrator.go b/contractcourt/channel_arbitrator.go index feb4bf35f6b..91f7551aae3 100644 --- a/contractcourt/channel_arbitrator.go +++ b/contractcourt/channel_arbitrator.go @@ -2466,8 +2466,13 @@ func (c *ChannelArbitrator) prepContractResolutions( continue } + var chanType channeldb.ChannelType + if chanState != nil { + chanType = chanState.ChanType + } + resolver := newSuccessResolver( - resolution, height, htlc, resolverCfg, + resolution, height, htlc, chanType, resolverCfg, ) if chanState != nil { resolver.SupplementState(chanState) @@ -2494,8 +2499,13 @@ func (c *ChannelArbitrator) prepContractResolutions( continue } + var chanType channeldb.ChannelType + if chanState != nil { + chanType = chanState.ChanType + } + resolver := newTimeoutResolver( - resolution, height, htlc, resolverCfg, + resolution, height, htlc, chanType, resolverCfg, ) if chanState != nil { resolver.SupplementState(chanState) @@ -2534,8 +2544,13 @@ func (c *ChannelArbitrator) prepContractResolutions( continue } + var chanType channeldb.ChannelType + if chanState != nil { + chanType = chanState.ChanType + } + resolver := newIncomingContestResolver( - resolution, height, htlc, + resolution, height, htlc, chanType, resolverCfg, ) if chanState != nil { @@ -2566,8 +2581,12 @@ func (c *ChannelArbitrator) prepContractResolutions( continue } + var chanType channeldb.ChannelType + if chanState != nil { + chanType = chanState.ChanType + } resolver := newOutgoingContestResolver( - resolution, height, htlc, resolverCfg, + resolution, height, htlc, chanType, resolverCfg, ) if chanState != nil { resolver.SupplementState(chanState) diff --git a/contractcourt/commit_sweep_resolver.go b/contractcourt/commit_sweep_resolver.go index 0f2cb6b242e..0bb313a45c6 100644 --- a/contractcourt/commit_sweep_resolver.go +++ b/contractcourt/commit_sweep_resolver.go @@ -506,11 +506,19 @@ func (c *commitSweepResolver) decideWitnessType() (input.WitnessType, error) { // commitment tweak to discern which type of commitment this is. var witnessType input.WitnessType switch { - // The local delayed output for a taproot channel. + // The local delayed output for a final taproot channel. + case isLocalCommitTx && c.chanType.IsTaprootFinal(): + witnessType = input.TaprootLocalCommitSpendFinal + + // The local delayed output for a staging taproot channel. case isLocalCommitTx && c.chanType.IsTaproot(): witnessType = input.TaprootLocalCommitSpend - // The CSV 1 delayed output for a taproot channel. + // The CSV 1 delayed output for a final taproot channel. + case !isLocalCommitTx && c.chanType.IsTaprootFinal(): + witnessType = input.TaprootRemoteCommitSpendFinal + + // The CSV 1 delayed output for a staging taproot channel. case !isLocalCommitTx && c.chanType.IsTaproot(): witnessType = input.TaprootRemoteCommitSpend diff --git a/contractcourt/htlc_incoming_contest_resolver.go b/contractcourt/htlc_incoming_contest_resolver.go index 95d08c417f8..ad4747a7c55 100644 --- a/contractcourt/htlc_incoming_contest_resolver.go +++ b/contractcourt/htlc_incoming_contest_resolver.go @@ -42,10 +42,10 @@ type htlcIncomingContestResolver struct { // newIncomingContestResolver instantiates a new incoming htlc contest resolver. func newIncomingContestResolver( res lnwallet.IncomingHtlcResolution, broadcastHeight uint32, - htlc channeldb.HTLC, resCfg ResolverConfig) *htlcIncomingContestResolver { + htlc channeldb.HTLC, chanType channeldb.ChannelType, resCfg ResolverConfig) *htlcIncomingContestResolver { success := newSuccessResolver( - res, broadcastHeight, htlc, resCfg, + res, broadcastHeight, htlc, chanType, resCfg, ) return &htlcIncomingContestResolver{ diff --git a/contractcourt/htlc_outgoing_contest_resolver.go b/contractcourt/htlc_outgoing_contest_resolver.go index 9e94587cccb..241117cfc5f 100644 --- a/contractcourt/htlc_outgoing_contest_resolver.go +++ b/contractcourt/htlc_outgoing_contest_resolver.go @@ -24,10 +24,10 @@ type htlcOutgoingContestResolver struct { // resolver. func newOutgoingContestResolver(res lnwallet.OutgoingHtlcResolution, broadcastHeight uint32, htlc channeldb.HTLC, - resCfg ResolverConfig) *htlcOutgoingContestResolver { + chanType channeldb.ChannelType, resCfg ResolverConfig) *htlcOutgoingContestResolver { timeout := newTimeoutResolver( - res, broadcastHeight, htlc, resCfg, + res, broadcastHeight, htlc, chanType, resCfg, ) return &htlcOutgoingContestResolver{ diff --git a/contractcourt/htlc_success_resolver.go b/contractcourt/htlc_success_resolver.go index a4d27ba4e81..8bc7e986d8b 100644 --- a/contractcourt/htlc_success_resolver.go +++ b/contractcourt/htlc_success_resolver.go @@ -50,6 +50,9 @@ type htlcSuccessResolver struct { // htlc contains information on the htlc that we are resolving on-chain. htlc channeldb.HTLC + // chanType denotes the type of channel the HTLC belongs to. + chanType channeldb.ChannelType + // 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 @@ -67,13 +70,14 @@ type htlcSuccessResolver struct { // newSuccessResolver instanties a new htlc success resolver. func newSuccessResolver(res lnwallet.IncomingHtlcResolution, broadcastHeight uint32, htlc channeldb.HTLC, - resCfg ResolverConfig) *htlcSuccessResolver { + chanType channeldb.ChannelType, resCfg ResolverConfig) *htlcSuccessResolver { h := &htlcSuccessResolver{ contractResolverKit: *newContractResolverKit(resCfg), htlcResolution: res, broadcastHeight: broadcastHeight, htlc: htlc, + chanType: chanType, } h.initReport() @@ -409,6 +413,11 @@ func (h *htlcSuccessResolver) isTaproot() bool { ) } +// isTaprootFinal returns true if the htlc output is from a final taproot channel. +func (h *htlcSuccessResolver) isTaprootFinal() bool { + return h.chanType.IsTaprootFinal() +} + // sweepRemoteCommitOutput creates a sweep request to sweep the HTLC output on // the remote commitment via the direct preimage-spend. func (h *htlcSuccessResolver) sweepRemoteCommitOutput() error { @@ -417,7 +426,18 @@ func (h *htlcSuccessResolver) sweepRemoteCommitOutput() error { // sweeping transaction, and generate a witness. var inp input.Input - if h.isTaproot() { + if h.isTaprootFinal() { + inp = lnutils.Ptr(input.MakeTaprootHtlcSucceedInputFinal( + &h.htlcResolution.ClaimOutpoint, + &h.htlcResolution.SweepSignDesc, + h.htlcResolution.Preimage[:], + h.broadcastHeight, + h.htlcResolution.CsvDelay, + input.WithResolutionBlob( + h.htlcResolution.ResolutionBlob, + ), + )) + } else if h.isTaproot() { inp = lnutils.Ptr(input.MakeTaprootHtlcSucceedInput( &h.htlcResolution.ClaimOutpoint, &h.htlcResolution.SweepSignDesc, @@ -562,7 +582,9 @@ func (h *htlcSuccessResolver) sweepSuccessTxOutput() error { // Let the sweeper sweep the second-level output now that the // CSV/CLTV locks have expired. var witType input.StandardWitnessType - if h.isTaproot() { + if h.isTaprootFinal() { + witType = input.TaprootHtlcAcceptedSuccessSecondLevelFinal + } else if h.isTaproot() { witType = input.TaprootHtlcAcceptedSuccessSecondLevel } else { witType = input.HtlcAcceptedSuccessSecondLevel diff --git a/contractcourt/htlc_timeout_resolver.go b/contractcourt/htlc_timeout_resolver.go index 5b8536398f9..eff95c47b7b 100644 --- a/contractcourt/htlc_timeout_resolver.go +++ b/contractcourt/htlc_timeout_resolver.go @@ -48,6 +48,9 @@ type htlcTimeoutResolver struct { // htlc contains information on the htlc that we are resolving on-chain. htlc channeldb.HTLC + // chanType denotes the type of channel the HTLC belongs to. + chanType channeldb.ChannelType + // 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 @@ -70,13 +73,14 @@ type htlcTimeoutResolver struct { // newTimeoutResolver instantiates a new timeout htlc resolver. func newTimeoutResolver(res lnwallet.OutgoingHtlcResolution, broadcastHeight uint32, htlc channeldb.HTLC, - resCfg ResolverConfig) *htlcTimeoutResolver { + chanType channeldb.ChannelType, resCfg ResolverConfig) *htlcTimeoutResolver { h := &htlcTimeoutResolver{ contractResolverKit: *newContractResolverKit(resCfg), htlcResolution: res, broadcastHeight: broadcastHeight, htlc: htlc, + chanType: chanType, } h.initReport() @@ -92,6 +96,11 @@ func (h *htlcTimeoutResolver) isTaproot() bool { ) } +// isTaprootFinal returns true if the htlc output is from a final taproot channel. +func (h *htlcTimeoutResolver) isTaprootFinal() bool { + return h.chanType.IsTaprootFinal() +} + // outpoint returns the outpoint of the HTLC output we're attempting to sweep. func (h *htlcTimeoutResolver) outpoint() wire.OutPoint { // The primary key for this resolver will be the outpoint of the HTLC @@ -515,7 +524,9 @@ func (h *htlcTimeoutResolver) resolveSecondLevelTxLegacy() error { // are resolved via this path. func (h *htlcTimeoutResolver) sweepDirectHtlcOutput() error { var htlcWitnessType input.StandardWitnessType - if h.isTaproot() { + if h.isTaprootFinal() { + htlcWitnessType = input.TaprootHtlcOfferedRemoteTimeoutFinal + } else if h.isTaproot() { htlcWitnessType = input.TaprootHtlcOfferedRemoteTimeout } else { htlcWitnessType = input.HtlcOfferedRemoteTimeout @@ -1030,7 +1041,9 @@ func (h *htlcTimeoutResolver) sweepTimeoutTxOutput() error { } var witType input.StandardWitnessType - if h.isTaproot() { + if h.isTaprootFinal() { + witType = input.TaprootHtlcOfferedTimeoutSecondLevelFinal + } else if h.isTaproot() { witType = input.TaprootHtlcOfferedTimeoutSecondLevel } else { witType = input.HtlcOfferedTimeoutSecondLevel diff --git a/contractcourt/utxonursery.go b/contractcourt/utxonursery.go index f78be9fa494..1fd22eeff3e 100644 --- a/contractcourt/utxonursery.go +++ b/contractcourt/utxonursery.go @@ -384,7 +384,10 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint, ) var witType input.StandardWitnessType - if isTaproot { + isProdTaproot := isTaproot && u.isProdTaprootResolution(htlcRes.ResolutionBlob) + if isProdTaproot { + witType = input.TaprootHtlcAcceptedSuccessSecondLevelFinal + } else if isTaproot { witType = input.TaprootHtlcAcceptedSuccessSecondLevel } else { witType = input.HtlcAcceptedSuccessSecondLevel @@ -409,7 +412,7 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint, // a baby output as we need to go to the second level to sweep // it. if htlcRes.SignedTimeoutTx != nil { - htlcOutput := makeBabyOutput( + htlcOutput := u.makeBabyOutput( &chanPoint, &htlcRes, deadlineHeight, ) @@ -428,7 +431,10 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint, ) var witType input.StandardWitnessType - if isTaproot { + isProdTaproot := isTaproot && u.isProdTaprootResolution(htlcRes.ResolutionBlob) + if isProdTaproot { + witType = input.TaprootHtlcOfferedRemoteTimeoutFinal + } else if isTaproot { witType = input.TaprootHtlcOfferedRemoteTimeout } else { witType = input.HtlcOfferedRemoteTimeout @@ -504,6 +510,16 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint, return nil } +// isProdTaprootResolution determines if a resolution blob indicates production taproot. +// For now, we use a simple heuristic: if there's a resolution blob, it's likely production. +// This can be refined later to parse the actual blob structure. +func (u *UtxoNursery) isProdTaprootResolution(resolutionBlob fn.Option[tlv.Blob]) bool { + // For production taproot channels, there should be a resolution blob + // containing auxiliary channel information. If no blob is present, + // this is likely a staging taproot channel. + return resolutionBlob.IsSome() +} + // NurseryReport attempts to return a nursery report stored for the target // outpoint. A nursery report details the maturity/sweeping progress for a // contract that was previously force closed. If a report entry for the target @@ -556,6 +572,8 @@ func (u *UtxoNursery) NurseryReport( switch kid.WitnessType() { //nolint:ll + case input.TaprootHtlcAcceptedSuccessSecondLevelFinal: + fallthrough case input.TaprootHtlcAcceptedSuccessSecondLevel: fallthrough case input.HtlcAcceptedSuccessSecondLevel: @@ -566,6 +584,7 @@ func (u *UtxoNursery) NurseryReport( report.AddLimboStage1SuccessHtlc(&kid) case input.HtlcOfferedRemoteTimeout, + input.TaprootHtlcOfferedRemoteTimeoutFinal, input.TaprootHtlcOfferedRemoteTimeout: // This is an HTLC output on the // commitment transaction of the remote @@ -582,6 +601,7 @@ func (u *UtxoNursery) NurseryReport( switch kid.WitnessType() { case input.HtlcOfferedRemoteTimeout, + input.TaprootHtlcOfferedRemoteTimeoutFinal, input.TaprootHtlcOfferedRemoteTimeout: // This is an HTLC output on the // commitment transaction of the remote @@ -612,14 +632,20 @@ func (u *UtxoNursery) NurseryReport( switch kid.WitnessType() { //nolint:ll + case input.TaprootHtlcAcceptedSuccessSecondLevelFinal: + fallthrough case input.TaprootHtlcAcceptedSuccessSecondLevel: fallthrough + case input.TaprootHtlcOfferedTimeoutSecondLevelFinal: + fallthrough case input.TaprootHtlcOfferedTimeoutSecondLevel: fallthrough case input.HtlcAcceptedSuccessSecondLevel: fallthrough case input.HtlcOfferedTimeoutSecondLevel: fallthrough + case input.TaprootHtlcOfferedRemoteTimeoutFinal: + fallthrough case input.TaprootHtlcOfferedRemoteTimeout: fallthrough case input.HtlcOfferedRemoteTimeout: @@ -1303,7 +1329,7 @@ type babyOutput struct { // makeBabyOutput constructs a baby output that wraps a future kidOutput. The // provided sign descriptors and witness types will be used once the output // reaches the delay and claim stage. -func makeBabyOutput(chanPoint *wire.OutPoint, +func (u *UtxoNursery) makeBabyOutput(chanPoint *wire.OutPoint, htlcResolution *lnwallet.OutgoingHtlcResolution, deadlineHeight fn.Option[int32]) babyOutput { @@ -1315,7 +1341,10 @@ func makeBabyOutput(chanPoint *wire.OutPoint, ) var witnessType input.StandardWitnessType - if isTaproot { + isProdTaproot := isTaproot && u.isProdTaprootResolution(htlcResolution.ResolutionBlob) + if isProdTaproot { + witnessType = input.TaprootHtlcOfferedTimeoutSecondLevelFinal + } else if isTaproot { witnessType = input.TaprootHtlcOfferedTimeoutSecondLevel } else { witnessType = input.HtlcOfferedTimeoutSecondLevel diff --git a/feature/default_sets.go b/feature/default_sets.go index fcb53b6664e..425ce9bec8d 100644 --- a/feature/default_sets.go +++ b/feature/default_sets.go @@ -96,6 +96,10 @@ var defaultSetDesc = setDesc{ SetInit: {}, // I SetNodeAnn: {}, // N }, + lnwire.SimpleTaprootChannelsOptionalFinal: { + SetInit: {}, // I + SetNodeAnn: {}, // N + }, lnwire.SimpleTaprootOverlayChansOptional: { SetInit: {}, // I SetNodeAnn: {}, // N diff --git a/feature/deps.go b/feature/deps.go index 0a2701e451f..5b10f7c7c61 100644 --- a/feature/deps.go +++ b/feature/deps.go @@ -79,6 +79,10 @@ var deps = depDesc{ lnwire.AnchorsZeroFeeHtlcTxOptional: {}, lnwire.ExplicitChannelTypeOptional: {}, }, + lnwire.SimpleTaprootChannelsOptionalFinal: { + lnwire.AnchorsZeroFeeHtlcTxOptional: {}, + lnwire.ExplicitChannelTypeOptional: {}, + }, lnwire.SimpleTaprootOverlayChansOptional: { lnwire.SimpleTaprootChannelsOptionalStaging: {}, lnwire.TLVOnionPayloadOptional: {}, diff --git a/feature/manager.go b/feature/manager.go index 862880f3b22..5b66541b480 100644 --- a/feature/manager.go +++ b/feature/manager.go @@ -199,6 +199,8 @@ func newManager(cfg Config, desc setDesc) (*Manager, error) { if cfg.NoTaprootChans { raw.Unset(lnwire.SimpleTaprootChannelsOptionalStaging) raw.Unset(lnwire.SimpleTaprootChannelsRequiredStaging) + raw.Unset(lnwire.SimpleTaprootChannelsOptionalFinal) + raw.Unset(lnwire.SimpleTaprootChannelsRequiredFinal) } if cfg.NoRouteBlinding { raw.Unset(lnwire.RouteBlindingOptional) diff --git a/funding/commitment_type_negotiation.go b/funding/commitment_type_negotiation.go index 817709c73d7..4444b0edd78 100644 --- a/funding/commitment_type_negotiation.go +++ b/funding/commitment_type_negotiation.go @@ -240,7 +240,22 @@ func explicitNegotiateCommitmentType(channelType lnwire.ChannelType, local, } return lnwallet.CommitmentTypeTweakless, nil - // Simple taproot channels only. + // Simple taproot channels only (final feature bits). + case channelFeatures.OnlyContains( + lnwire.SimpleTaprootChannelsRequiredFinal, + ): + + if !hasFeatures( + local, remote, + lnwire.SimpleTaprootChannelsOptionalFinal, + ) { + + return 0, errUnsupportedChannelType + } + + return lnwallet.CommitmentTypeSimpleTaprootFinal, nil + + // Simple taproot channels only (staging feature bits). case channelFeatures.OnlyContains( lnwire.SimpleTaprootChannelsRequiredStaging, ): @@ -255,7 +270,24 @@ func explicitNegotiateCommitmentType(channelType lnwire.ChannelType, local, return lnwallet.CommitmentTypeSimpleTaproot, nil - // Simple taproot channels with scid only. + // Simple taproot channels with scid only (final feature bits). + case channelFeatures.OnlyContains( + lnwire.SimpleTaprootChannelsRequiredFinal, + lnwire.ScidAliasRequired, + ): + + if !hasFeatures( + local, remote, + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.ScidAliasOptional, + ) { + + return 0, errUnsupportedChannelType + } + + return lnwallet.CommitmentTypeSimpleTaprootFinal, nil + + // Simple taproot channels with scid only (staging feature bits). case channelFeatures.OnlyContains( lnwire.SimpleTaprootChannelsRequiredStaging, lnwire.ScidAliasRequired, @@ -272,7 +304,24 @@ func explicitNegotiateCommitmentType(channelType lnwire.ChannelType, local, return lnwallet.CommitmentTypeSimpleTaproot, nil - // Simple taproot channels with zero conf only. + // Simple taproot channels with zero conf only (final feature bits). + case channelFeatures.OnlyContains( + lnwire.SimpleTaprootChannelsRequiredFinal, + lnwire.ZeroConfRequired, + ): + + if !hasFeatures( + local, remote, + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.ZeroConfOptional, + ) { + + return 0, errUnsupportedChannelType + } + + return lnwallet.CommitmentTypeSimpleTaprootFinal, nil + + // Simple taproot channels with zero conf only (staging feature bits). case channelFeatures.OnlyContains( lnwire.SimpleTaprootChannelsRequiredStaging, lnwire.ZeroConfRequired, @@ -289,7 +338,26 @@ func explicitNegotiateCommitmentType(channelType lnwire.ChannelType, local, return lnwallet.CommitmentTypeSimpleTaproot, nil - // Simple taproot channels with scid and zero conf. + // Simple taproot channels with scid and zero conf (final feature bits). + case channelFeatures.OnlyContains( + lnwire.SimpleTaprootChannelsRequiredFinal, + lnwire.ZeroConfRequired, + lnwire.ScidAliasRequired, + ): + + if !hasFeatures( + local, remote, + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.ZeroConfOptional, + lnwire.ScidAliasOptional, + ) { + + return 0, errUnsupportedChannelType + } + + return lnwallet.CommitmentTypeSimpleTaprootFinal, nil + + // Simple taproot channels with scid and zero conf (staging feature bits). case channelFeatures.OnlyContains( lnwire.SimpleTaprootChannelsRequiredStaging, lnwire.ZeroConfRequired, @@ -300,6 +368,7 @@ func explicitNegotiateCommitmentType(channelType lnwire.ChannelType, local, local, remote, lnwire.SimpleTaprootChannelsOptionalStaging, lnwire.ZeroConfOptional, + lnwire.ScidAliasOptional, ) { return 0, errUnsupportedChannelType @@ -391,6 +460,26 @@ func implicitNegotiateCommitmentType(local, remote *lnwire.FeatureVector) (*lnwire.ChannelType, lnwallet.CommitmentType) { + // If both peers are signalling support for simple taproot channels with + // final feature bits, prefer that over staging bits. + if hasFeatures(local, remote, lnwire.SimpleTaprootChannelsOptionalFinal) { + chanType := lnwire.ChannelType(*lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsRequiredFinal, + )) + + return &chanType, lnwallet.CommitmentTypeSimpleTaprootFinal + } + + // If both peers are signalling support for simple taproot channels with + // staging feature bits, use those. + if hasFeatures(local, remote, lnwire.SimpleTaprootChannelsOptionalStaging) { + chanType := lnwire.ChannelType(*lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsRequiredStaging, + )) + + return &chanType, lnwallet.CommitmentTypeSimpleTaproot + } + // 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) { diff --git a/funding/commitment_type_negotiation_test.go b/funding/commitment_type_negotiation_test.go index b9e9f59f0f0..4f7432f27d8 100644 --- a/funding/commitment_type_negotiation_test.go +++ b/funding/commitment_type_negotiation_test.go @@ -307,6 +307,189 @@ func TestCommitmentTypeNegotiation(t *testing.T) { expectsChanType: nil, expectsErr: nil, }, + + // Test cases for final taproot channels with explicit negotiation. + { + name: "explicit simple taproot final only", + channelFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsRequiredFinal, + ), + localFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.ExplicitChannelTypeOptional, + ), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.ExplicitChannelTypeOptional, + ), + expectsCommitType: lnwallet.CommitmentTypeSimpleTaprootFinal, + expectsChanType: (*lnwire.ChannelType)( + lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsRequiredFinal, + ), + ), + expectsErr: nil, + }, + { + name: "explicit simple taproot final with scid alias", + channelFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsRequiredFinal, + lnwire.ScidAliasRequired, + ), + localFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.ScidAliasOptional, + lnwire.ExplicitChannelTypeOptional, + ), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.ScidAliasOptional, + lnwire.ExplicitChannelTypeOptional, + ), + expectsCommitType: lnwallet.CommitmentTypeSimpleTaprootFinal, + expectsChanType: (*lnwire.ChannelType)( + lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsRequiredFinal, + lnwire.ScidAliasRequired, + ), + ), + scidAlias: true, + expectsErr: nil, + }, + { + name: "explicit simple taproot final with zero conf", + channelFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsRequiredFinal, + lnwire.ZeroConfRequired, + ), + localFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.ZeroConfOptional, + lnwire.ExplicitChannelTypeOptional, + ), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.ZeroConfOptional, + lnwire.ExplicitChannelTypeOptional, + ), + expectsCommitType: lnwallet.CommitmentTypeSimpleTaprootFinal, + expectsChanType: (*lnwire.ChannelType)( + lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsRequiredFinal, + lnwire.ZeroConfRequired, + ), + ), + zeroConf: true, + expectsErr: nil, + }, + { + name: "explicit simple taproot final with scid alias and zero conf", + channelFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsRequiredFinal, + lnwire.ScidAliasRequired, + lnwire.ZeroConfRequired, + ), + localFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.ScidAliasOptional, + lnwire.ZeroConfOptional, + lnwire.ExplicitChannelTypeOptional, + ), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.ScidAliasOptional, + lnwire.ZeroConfOptional, + lnwire.ExplicitChannelTypeOptional, + ), + expectsCommitType: lnwallet.CommitmentTypeSimpleTaprootFinal, + expectsChanType: (*lnwire.ChannelType)( + lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsRequiredFinal, + lnwire.ScidAliasRequired, + lnwire.ZeroConfRequired, + ), + ), + scidAlias: true, + zeroConf: true, + expectsErr: nil, + }, + { + name: "explicit simple taproot final missing remote support", + channelFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsRequiredFinal, + ), + localFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.ExplicitChannelTypeOptional, + ), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalStaging, + lnwire.ExplicitChannelTypeOptional, + ), + expectsErr: errUnsupportedChannelType, + }, + + // Test cases for implicit negotiation preferring final over staging. + { + name: "implicit final taproot preferred over staging", + channelFeatures: nil, + localFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.SimpleTaprootChannelsOptionalStaging, + lnwire.ExplicitChannelTypeOptional, + ), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.SimpleTaprootChannelsOptionalStaging, + lnwire.ExplicitChannelTypeOptional, + ), + expectsCommitType: lnwallet.CommitmentTypeSimpleTaprootFinal, + expectsChanType: (*lnwire.ChannelType)( + lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsRequiredFinal, + ), + ), + expectsErr: nil, + }, + { + name: "implicit staging taproot when final not supported", + channelFeatures: nil, + localFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.SimpleTaprootChannelsOptionalStaging, + lnwire.ExplicitChannelTypeOptional, + ), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalStaging, + lnwire.ExplicitChannelTypeOptional, + ), + expectsCommitType: lnwallet.CommitmentTypeSimpleTaproot, + expectsChanType: (*lnwire.ChannelType)( + lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsRequiredStaging, + ), + ), + expectsErr: nil, + }, + { + name: "implicit final taproot only", + channelFeatures: nil, + localFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.ExplicitChannelTypeOptional, + ), + remoteFeatures: lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsOptionalFinal, + lnwire.ExplicitChannelTypeOptional, + ), + expectsCommitType: lnwallet.CommitmentTypeSimpleTaprootFinal, + expectsChanType: (*lnwire.ChannelType)( + lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsRequiredFinal, + ), + ), + expectsErr: nil, + }, } for _, testCase := range testCases { diff --git a/funding/manager_test.go b/funding/manager_test.go index 72a60e02ab0..fea5eab47e0 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -4680,6 +4680,7 @@ func TestCommitmentTypeFundmaxSanityCheck(t *testing.T) { "SCRIPT_ENFORCED_LEASE": 4, "SIMPLE_TAPROOT": 5, "SIMPLE_TAPROOT_OVERLAY": 6, + "SIMPLE_TAPROOT_FINAL": 7, } for commitmentType := range lnrpc.CommitmentType_value { diff --git a/htlcswitch/link.go b/htlcswitch/link.go index d2bc4f4bf02..0c00145fb2e 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -895,10 +895,17 @@ func (l *channelLink) syncChanStates(ctx context.Context) error { l.log.Infof("Attempting to re-synchronize channel: %v", chanState) - // First, we'll generate our ChanSync message to send to the other - // side. Based on this message, the remote party will decide if they - // need to retransmit any data or not. - localChanSyncMsg, err := chanState.ChanSyncMsg() + // First, we'll generate our ChanSync message to send to the other side. + // Based on this message, the remote party will decide if they need to + // retransmit any data or not. We pass the peer's feature bits so that + // we use the correct nonce format based on whether they support the + // final or staging taproot channel feature bits. + nonceType := lnwire.DetermineTaprootNonceType( + l.cfg.Peer.RemoteFeatures(), + ) + localChanSyncMsg, err := chanState.ChanSyncMsg( + channeldb.WithChanSyncNonceType(nonceType), + ) if err != nil { return fmt.Errorf("unable to generate chan sync message for "+ "ChannelPoint(%v)", l.channel.ChannelPoint()) diff --git a/input/input.go b/input/input.go index 4a9a4b55c07..176efebd329 100644 --- a/input/input.go +++ b/input/input.go @@ -339,6 +339,25 @@ func MakeTaprootHtlcSucceedInput(op *wire.OutPoint, signDesc *SignDescriptor, } } +// MakeTaprootHtlcSucceedInputFinal creates a new HtlcSucceedInput that can be used +// to spend an HTLC output for a production taproot channel on the remote party's +// commitment transaction. +func MakeTaprootHtlcSucceedInputFinal(op *wire.OutPoint, signDesc *SignDescriptor, + preimage []byte, heightHint, blocksToMaturity uint32, + opts ...InputOpt) HtlcSucceedInput { + + input := MakeBaseInput( + op, TaprootHtlcAcceptedRemoteSuccessFinal, signDesc, + heightHint, nil, opts..., + ) + input.blockToMaturity = blocksToMaturity + + return HtlcSucceedInput{ + inputKit: input.inputKit, + preimage: preimage, + } +} + // CraftInputScript returns a valid set of input scripts allowing this output // to be spent. The returns input scripts should target the input at location // txIndex within the passed transaction. The input scripts generated by this diff --git a/input/script_utils.go b/input/script_utils.go index c314bc69e3b..a7d419efd8b 100644 --- a/input/script_utils.go +++ b/input/script_utils.go @@ -766,8 +766,8 @@ func senderHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey, // unilaterally spend the created output. func SenderHTLCScriptTaproot(senderHtlcKey, receiverHtlcKey, revokeKey *btcec.PublicKey, payHash []byte, - whoseCommit lntypes.ChannelParty, auxLeaf AuxTapLeaf) (*HtlcScriptTree, - error) { + whoseCommit lntypes.ChannelParty, auxLeaf AuxTapLeaf, + opts ...TaprootScriptOpt) (*HtlcScriptTree, error) { var hType htlcType if whoseCommit.IsLocal() { @@ -781,7 +781,7 @@ func SenderHTLCScriptTaproot(senderHtlcKey, receiverHtlcKey, // tap leaf paths. return senderHtlcTapScriptTree( senderHtlcKey, receiverHtlcKey, revokeKey, payHash, hType, - auxLeaf, + auxLeaf, opts..., ) } @@ -1286,7 +1286,7 @@ func receiverHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey, func ReceiverHTLCScriptTaproot(cltvExpiry uint32, senderHtlcKey, receiverHtlcKey, revocationKey *btcec.PublicKey, payHash []byte, whoseCommit lntypes.ChannelParty, - auxLeaf AuxTapLeaf) (*HtlcScriptTree, error) { + auxLeaf AuxTapLeaf, opts ...TaprootScriptOpt) (*HtlcScriptTree, error) { var hType htlcType if whoseCommit.IsLocal() { @@ -1300,7 +1300,7 @@ func ReceiverHTLCScriptTaproot(cltvExpiry uint32, // tap leaf paths. return receiverHtlcTapScriptTree( senderHtlcKey, receiverHtlcKey, revocationKey, payHash, - cltvExpiry, hType, auxLeaf, + cltvExpiry, hType, auxLeaf, opts..., ) } @@ -1537,11 +1537,11 @@ func TaprootSecondLevelTapLeaf(delayKey *btcec.PublicKey, // SecondLevelHtlcTapscriptTree construct the indexed tapscript tree needed to // generate the tap tweak to create the final output and also control block. func SecondLevelHtlcTapscriptTree(delayKey *btcec.PublicKey, csvDelay uint32, - auxLeaf AuxTapLeaf) (*txscript.IndexedTapScriptTree, error) { + auxLeaf AuxTapLeaf, opts ...TaprootScriptOpt) (*txscript.IndexedTapScriptTree, error) { // First grab the second level leaf script we need to create the top // level output. - secondLevelTapLeaf, err := TaprootSecondLevelTapLeaf(delayKey, csvDelay) + secondLevelTapLeaf, err := TaprootSecondLevelTapLeaf(delayKey, csvDelay, opts...) if err != nil { return nil, err } @@ -1573,12 +1573,12 @@ func SecondLevelHtlcTapscriptTree(delayKey *btcec.PublicKey, csvDelay uint32, // // The keyspend path require knowledge of the top level revocation private key. func TaprootSecondLevelHtlcScript(revokeKey, delayKey *btcec.PublicKey, - csvDelay uint32, auxLeaf AuxTapLeaf) (*btcec.PublicKey, error) { + csvDelay uint32, auxLeaf AuxTapLeaf, opts ...TaprootScriptOpt) (*btcec.PublicKey, error) { // First, we'll make the tapscript tree that commits to the redemption // path. tapScriptTree, err := SecondLevelHtlcTapscriptTree( - delayKey, csvDelay, auxLeaf, + delayKey, csvDelay, auxLeaf, opts..., ) if err != nil { return nil, err @@ -1612,12 +1612,12 @@ type SecondLevelScriptTree struct { // TaprootSecondLevelScriptTree constructs the tapscript tree used to spend the // second level HTLC output. func TaprootSecondLevelScriptTree(revokeKey, delayKey *btcec.PublicKey, - csvDelay uint32, auxLeaf AuxTapLeaf) (*SecondLevelScriptTree, error) { + csvDelay uint32, auxLeaf AuxTapLeaf, opts ...TaprootScriptOpt) (*SecondLevelScriptTree, error) { // First, we'll make the tapscript tree that commits to the redemption // path. tapScriptTree, err := SecondLevelHtlcTapscriptTree( - delayKey, csvDelay, auxLeaf, + delayKey, csvDelay, auxLeaf, opts..., ) if err != nil { return nil, err diff --git a/input/script_utils_test.go b/input/script_utils_test.go index 92eb8069928..4b435a50cc3 100644 --- a/input/script_utils_test.go +++ b/input/script_utils_test.go @@ -14,6 +14,7 @@ import ( "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/keychain" + "github.com/lightningnetwork/lnd/lntypes" "github.com/stretchr/testify/require" ) @@ -2249,3 +2250,88 @@ func runScriptAllocTest(dummyData, randomPubBytes []byte, return nil } + +// TestTaprootHtlcScriptGeneration tests that taproot HTLC scripts can be +// generated with both staging and production script options. +func TestTaprootHtlcScriptGeneration(t *testing.T) { + t.Parallel() + + // Generate test keys. + senderKey, err := btcec.NewPrivateKey() + require.NoError(t, err) + senderPubKey := senderKey.PubKey() + + receiverKey, err := btcec.NewPrivateKey() + require.NoError(t, err) + receiverPubKey := receiverKey.PubKey() + + revokeKey, err := btcec.NewPrivateKey() + require.NoError(t, err) + revokePubKey := revokeKey.PubKey() + + // Test constants. + cltvExpiry := uint32(500000) + hashBytes := make([]byte, 32) + copy(hashBytes, []byte("test payment hash")) + + // Use empty auxiliary leaf and local commit. + auxLeaf := NoneTapLeaf() + whoseCommit := lntypes.Local + + // Test SenderHTLCScriptTaproot with staging vs production scripts. + stagingSenderScript, err := SenderHTLCScriptTaproot( + senderPubKey, receiverPubKey, revokePubKey, hashBytes, + whoseCommit, auxLeaf, + ) + require.NoError(t, err) + + prodSenderScript, err := SenderHTLCScriptTaproot( + senderPubKey, receiverPubKey, revokePubKey, hashBytes, + whoseCommit, auxLeaf, WithProdScripts(), + ) + require.NoError(t, err) + + // Verify that both script trees are generated successfully. + require.NotNil(t, stagingSenderScript, "staging sender script should be generated") + require.NotNil(t, prodSenderScript, "production sender script should be generated") + + // Test ReceiverHTLCScriptTaproot with staging vs production scripts. + stagingReceiverScript, err := ReceiverHTLCScriptTaproot( + cltvExpiry, senderPubKey, receiverPubKey, revokePubKey, hashBytes, + whoseCommit, auxLeaf, + ) + require.NoError(t, err) + + prodReceiverScript, err := ReceiverHTLCScriptTaproot( + cltvExpiry, senderPubKey, receiverPubKey, revokePubKey, hashBytes, + whoseCommit, auxLeaf, WithProdScripts(), + ) + require.NoError(t, err) + + // Verify that both script trees are generated successfully. + require.NotNil(t, stagingReceiverScript, "staging receiver script should be generated") + require.NotNil(t, prodReceiverScript, "production receiver script should be generated") + + // Scripts should be different between staging and production. + // Note: The sender success script (redeemed by receiver) should differ. + require.NotEqual(t, stagingSenderScript.SuccessTapLeaf.Script, + prodSenderScript.SuccessTapLeaf.Script, + "staging and production sender success scripts should differ") + require.NotEqual(t, stagingReceiverScript.TimeoutTapLeaf.Script, + prodReceiverScript.TimeoutTapLeaf.Script, + "staging and production receiver timeout scripts should differ") + + // Production scripts should be smaller due to OP_CHECKSIGVERIFY optimizations. + require.Less(t, len(prodSenderScript.SuccessTapLeaf.Script), + len(stagingSenderScript.SuccessTapLeaf.Script), + "production sender success script should be smaller than staging") + require.Less(t, len(prodReceiverScript.TimeoutTapLeaf.Script), + len(stagingReceiverScript.TimeoutTapLeaf.Script), + "production receiver timeout script should be smaller than staging") + + // Verify the script trees have the expected structure. + require.NotNil(t, stagingSenderScript.TimeoutTapLeaf, "staging sender should have timeout leaf") + require.NotNil(t, prodSenderScript.TimeoutTapLeaf, "production sender should have timeout leaf") + require.NotNil(t, stagingReceiverScript.SuccessTapLeaf, "staging receiver should have success leaf") + require.NotNil(t, prodReceiverScript.SuccessTapLeaf, "production receiver should have success leaf") +} diff --git a/input/size.go b/input/size.go index f1c56ff8263..afbf168f5ba 100644 --- a/input/size.go +++ b/input/size.go @@ -275,18 +275,28 @@ const ( HtlcTimeoutWeight = 663 // TaprootHtlcTimeoutWeight is the total weight of the taproot HTLC - // timeout transaction. + // timeout transaction (using staging scripts). TaprootHtlcTimeoutWeight = 645 + // TaprootHtlcTimeoutWeightFinal is the total weight of the taproot HTLC + // timeout transaction using production scripts (with OP_CHECKSIGVERIFY + // instead of OP_CHECKSIG + OP_DROP). + TaprootHtlcTimeoutWeightFinal = 641 + // HtlcSuccessWeight 703 weight // HtlcSuccessWeight is the weight of the HTLC success transaction // which will transition an incoming HTLC to the delay-and-claim state. HtlcSuccessWeight = 703 // TaprootHtlcSuccessWeight is the total weight of the taproot HTLC - // success transaction. + // success transaction (using staging scripts). TaprootHtlcSuccessWeight = 705 + // TaprootHtlcSuccessWeightFinal is the total weight of the taproot HTLC + // success transaction using production scripts (with OP_CHECKSIGVERIFY + // instead of OP_CHECKSIG + OP_DROP). + TaprootHtlcSuccessWeightFinal = 701 + // HtlcConfirmedScriptOverhead 3 bytes // HtlcConfirmedScriptOverhead is the extra length of an HTLC script // that requires confirmation before it can be spent. These extra bytes @@ -729,6 +739,12 @@ const ( TaprootHtlcOfferedRemoteTimeoutScriptSize = (1 + 32 + 1 + 1 + 1 + 1 + 1 + 4 + 1 + 1) + // TaprootHtlcOfferedRemoteTimeoutScriptSizeFinal: 40 bytes (production scripts) + // Same as staging but replaces OP_CHECKSIG + OP_DROP patterns with + // OP_CHECKSIGVERIFY and OP_CHECKLOCKTIMEVERIFY + OP_DROP with + // OP_CHECKLOCKTIMEVERIFY, saving 2 bytes total. + TaprootHtlcOfferedRemoteTimeoutScriptSizeFinal = TaprootHtlcOfferedRemoteTimeoutScriptSize - 2 + // TaprootHtlcOfferedRemoteTimeoutwitSize: 176 bytes // - number_of_witness_elements: 1 byte // - sig_len: 1 byte @@ -742,6 +758,11 @@ const ( TaprootHtlcOfferedRemoteTimeoutScriptSize + 1 + TaprootBaseControlBlockWitnessSize + 32 + // TaprootHtlcOfferedRemoteTimeoutWitnessSizeFinal: 174 bytes (production scripts) + TaprootHtlcOfferedRemoteTimeoutWitnessSizeFinal = 1 + 1 + 65 + 1 + + TaprootHtlcOfferedRemoteTimeoutScriptSizeFinal + 1 + + TaprootBaseControlBlockWitnessSize + 32 + // TaprootHtlcOfferedLocalTmeoutScriptSize: // - OP_DATA: 1 byte (pub key len) // - local_key: 32 bytes @@ -751,6 +772,11 @@ const ( // - OP_CHECKSIG: 1 byte TaprootHtlcOfferedLocalTimeoutScriptSize = 1 + 32 + 1 + 1 + 32 + 1 + // TaprootHtlcOfferedLocalTimeoutScriptSizeFinal: 66 bytes (production scripts) + // Same as staging but replaces OP_CHECKSIG + OP_DROP with OP_CHECKSIGVERIFY, + // saving 1 byte. + TaprootHtlcOfferedLocalTimeoutScriptSizeFinal = TaprootHtlcOfferedLocalTimeoutScriptSize - 1 + // TaprootOfferedLocalTimeoutWitnessSize // - number_of_witness_elements: 1 byte // - sig_len: 1 byte @@ -766,6 +792,11 @@ const ( TaprootHtlcOfferedLocalTimeoutScriptSize + 1 + TaprootBaseControlBlockWitnessSize + 32 + // TaprootOfferedLocalTimeoutWitnessSizeFinal: 235 bytes (production scripts) + TaprootOfferedLocalTimeoutWitnessSizeFinal = 1 + 1 + 65 + 1 + 65 + 1 + + TaprootHtlcOfferedLocalTimeoutScriptSizeFinal + 1 + + TaprootBaseControlBlockWitnessSize + 32 + // TaprootHtlcAcceptedRemoteSuccessScriptSize: // - OP_SIZE: 1 byte // - OP_DATA: 1 byte @@ -784,6 +815,11 @@ const ( TaprootHtlcAcceptedRemoteSuccessScriptSize = 1 + 1 + 1 + 1 + 1 + 1 + 1 + 20 + 1 + 32 + 1 + 1 + 1 + 1 + // TaprootHtlcAcceptedRemoteSuccessScriptSizeFinal: 42 bytes (production scripts) + // Same as staging but replaces OP_CHECKSIG + OP_DROP with OP_CHECKSIGVERIFY + // and OP_CSV + OP_DROP with OP_CSV, saving 2 bytes total. + TaprootHtlcAcceptedRemoteSuccessScriptSizeFinal = TaprootHtlcAcceptedRemoteSuccessScriptSize - 2 + // TaprootHtlcAcceptedRemoteSuccessScriptSize: // - number_of_witness_elements: 1 byte // - sig_len: 1 byte @@ -799,6 +835,11 @@ const ( TaprootHtlcAcceptedRemoteSuccessScriptSize + 1 + TaprootBaseControlBlockWitnessSize + 32 + // TaprootHtlcAcceptedRemoteSuccessWitnessSizeFinal: 166 bytes (production scripts) + TaprootHtlcAcceptedRemoteSuccessWitnessSizeFinal = 1 + 1 + 65 + 1 + 32 + 1 + + TaprootHtlcAcceptedRemoteSuccessScriptSizeFinal + 1 + + TaprootBaseControlBlockWitnessSize + 32 + // TaprootHtlcAcceptedLocalSuccessScriptSize: // - OP_SIZE: 1 byte // - OP_DATA: 1 byte @@ -817,6 +858,11 @@ const ( TaprootHtlcAcceptedLocalSuccessScriptSize = 1 + 1 + 1 + 1 + 1 + 1 + 20 + 1 + 1 + 32 + 1 + 1 + 32 + 1 + // TaprootHtlcAcceptedLocalSuccessScriptSizeFinal: 73 bytes (production scripts) + // Same as staging but replaces OP_CHECKSIG + OP_DROP patterns with + // OP_CHECKSIGVERIFY, saving 1 byte. + TaprootHtlcAcceptedLocalSuccessScriptSizeFinal = TaprootHtlcAcceptedLocalSuccessScriptSize - 1 + // TaprootHtlcAcceptedLocalSuccessWitnessSize: // - number_of_witness_elements: 1 byte // - sig_len: 1 byte @@ -833,6 +879,11 @@ const ( TaprootHtlcAcceptedLocalSuccessWitnessSize = 1 + 1 + 65 + 1 + 65 + 1 + 32 + 1 + TaprootHtlcAcceptedLocalSuccessScriptSize + 1 + TaprootBaseControlBlockWitnessSize + 32 + + // TaprootHtlcAcceptedLocalSuccessWitnessSizeFinal: 271 bytes (production scripts) + TaprootHtlcAcceptedLocalSuccessWitnessSizeFinal = 1 + 1 + 65 + 1 + 65 + 1 + + 32 + 1 + TaprootHtlcAcceptedLocalSuccessScriptSizeFinal + 1 + + TaprootBaseControlBlockWitnessSize + 32 ) // EstimateCommitTxWeight estimate commitment transaction weight depending on diff --git a/input/size_test.go b/input/size_test.go index 2fba2c7b2e8..2691b784279 100644 --- a/input/size_test.go +++ b/input/size_test.go @@ -1593,3 +1593,126 @@ func TestTxSizes(t *testing.T) { }) } } + +// TestTaprootScriptOptions tests that both staging and production taproot +// scripts can be generated successfully and that they produce different +// script trees. +func TestTaprootScriptOptions(t *testing.T) { + // Generate test keys. + senderKey, err := btcec.NewPrivateKey() + require.NoError(t, err) + receiverKey, err := btcec.NewPrivateKey() + require.NoError(t, err) + revokeKey, err := btcec.NewPrivateKey() + require.NoError(t, err) + + var payHash [32]byte + copy(payHash[:], "testhash") + + // Test SenderHTLCScriptTaproot with different options. + t.Run("SenderHTLC staging vs production", func(t *testing.T) { + // Generate staging script (default). + stagingScript, err := input.SenderHTLCScriptTaproot( + senderKey.PubKey(), receiverKey.PubKey(), + revokeKey.PubKey(), payHash[:], lntypes.Remote, + input.NoneTapLeaf(), + ) + require.NoError(t, err) + + // Generate production script. + prodScript, err := input.SenderHTLCScriptTaproot( + senderKey.PubKey(), receiverKey.PubKey(), + revokeKey.PubKey(), payHash[:], lntypes.Remote, + input.NoneTapLeaf(), input.WithProdScripts(), + ) + require.NoError(t, err) + + // For sender HTLC, only the success script (redeemed by receiver) differs. + require.NotEqual(t, stagingScript.SuccessTapLeaf.Script, + prodScript.SuccessTapLeaf.Script, + "staging and production sender success scripts should differ") + + // Production success script should be smaller due to OP_CHECKSIGVERIFY optimizations. + require.Less(t, len(prodScript.SuccessTapLeaf.Script), + len(stagingScript.SuccessTapLeaf.Script), + "production sender success script should be smaller than staging") + + // Both should have valid tapscript trees. + require.NotNil(t, stagingScript.TapscriptTree) + require.NotNil(t, prodScript.TapscriptTree) + }) + + // Test ReceiverHTLCScriptTaproot with different options. + t.Run("ReceiverHTLC staging vs production", func(t *testing.T) { + cltvExpiry := uint32(500000) + + // Generate staging script (default). + stagingScript, err := input.ReceiverHTLCScriptTaproot( + cltvExpiry, senderKey.PubKey(), receiverKey.PubKey(), + revokeKey.PubKey(), payHash[:], lntypes.Remote, + input.NoneTapLeaf(), + ) + require.NoError(t, err) + + // Generate production script. + prodScript, err := input.ReceiverHTLCScriptTaproot( + cltvExpiry, senderKey.PubKey(), receiverKey.PubKey(), + revokeKey.PubKey(), payHash[:], lntypes.Remote, + input.NoneTapLeaf(), input.WithProdScripts(), + ) + require.NoError(t, err) + + // For receiver HTLC, the timeout script (sender reclaims) should differ. + require.NotEqual(t, stagingScript.TimeoutTapLeaf.Script, + prodScript.TimeoutTapLeaf.Script, + "staging and production receiver timeout scripts should differ") + + // Production timeout script should be smaller due to OP_CHECKSIGVERIFY optimizations. + require.Less(t, len(prodScript.TimeoutTapLeaf.Script), + len(stagingScript.TimeoutTapLeaf.Script), + "production receiver timeout script should be smaller than staging") + + // Both should have valid tapscript trees. + require.NotNil(t, stagingScript.TapscriptTree) + require.NotNil(t, prodScript.TapscriptTree) + }) + + // Test commit scripts with different options. + t.Run("CommitScript staging vs production", func(t *testing.T) { + csvDelay := uint32(144) + + // Generate staging script (default). + stagingScript, err := input.NewLocalCommitScriptTree( + csvDelay, senderKey.PubKey(), revokeKey.PubKey(), + input.NoneTapLeaf(), + ) + require.NoError(t, err) + + // Generate production script. + prodScript, err := input.NewLocalCommitScriptTree( + csvDelay, senderKey.PubKey(), revokeKey.PubKey(), + input.NoneTapLeaf(), input.WithProdScripts(), + ) + require.NoError(t, err) + + // Only the settle script should differ between staging and production. + // The revocation script doesn't implement production optimizations. + require.NotEqual(t, stagingScript.SettleLeaf.Script, + prodScript.SettleLeaf.Script, + "staging and production settle scripts should differ") + + // Revocation scripts should be identical (no production optimization). + require.Equal(t, stagingScript.RevocationLeaf.Script, + prodScript.RevocationLeaf.Script, + "revocation scripts should be identical between staging and production") + + // Production settle script should be smaller due to OP_CHECKSIGVERIFY optimizations. + require.Less(t, len(prodScript.SettleLeaf.Script), + len(stagingScript.SettleLeaf.Script), + "production settle script should be smaller than staging") + + // Both should have valid tapscript trees. + require.NotNil(t, stagingScript.TapscriptTree) + require.NotNil(t, prodScript.TapscriptTree) + }) +} diff --git a/input/witnessgen.go b/input/witnessgen.go index c49328afc99..8a2c1e0c514 100644 --- a/input/witnessgen.go +++ b/input/witnessgen.go @@ -255,6 +255,41 @@ const ( // settled output of a malicious counterparty's who broadcasts a // revoked taproot commitment transaction. TaprootCommitmentRevoke StandardWitnessType = 34 + + // TaprootLocalCommitSpendFinal is a witness type that allows us to spend + // our settled local commitment after a CSV delay when we force close + // a final taproot channel (using production scripts). + TaprootLocalCommitSpendFinal StandardWitnessType = 35 + + // TaprootRemoteCommitSpendFinal is a witness type that allows us to spend + // our settled remote commitment after a CSV delay when the remote party + // has force closed a final taproot channel (using production scripts). + TaprootRemoteCommitSpendFinal StandardWitnessType = 36 + + // TaprootHtlcOfferedTimeoutSecondLevelFinal is a witness that allows us to + // timeout an HTLC we offered to the remote party on our commitment + // transaction for final taproot channels (using production scripts). + TaprootHtlcOfferedTimeoutSecondLevelFinal StandardWitnessType = 37 + + // TaprootHtlcAcceptedSuccessSecondLevelFinal is a witness that allows us to + // sweep an HTLC we accepted on our commitment transaction after we go + // to the second level on chain for final taproot channels (using production scripts). + TaprootHtlcAcceptedSuccessSecondLevelFinal StandardWitnessType = 38 + + // TaprootHtlcOfferedRemoteTimeoutFinal is a witness that allows us to sweep + // an HTLC we offered to the remote party that lies on the commitment + // transaction for the remote party for final taproot channels (using production scripts). + TaprootHtlcOfferedRemoteTimeoutFinal StandardWitnessType = 39 + + // TaprootHtlcAcceptedRemoteSuccessFinal is a witness that allows us to + // sweep an HTLC that was offered to us by the remote party for final + // taproot channels (using production scripts). + TaprootHtlcAcceptedRemoteSuccessFinal StandardWitnessType = 40 + + // TaprootCommitmentRevokeFinal is a witness that allows us to sweep the + // settled output of a malicious counterparty's who broadcasts a + // revoked final taproot commitment transaction (using production scripts). + TaprootCommitmentRevokeFinal StandardWitnessType = 41 ) // String returns a human readable version of the target WitnessType. @@ -367,6 +402,27 @@ func (wt StandardWitnessType) String() string { case TaprootCommitmentRevoke: return "TaprootCommitmentRevoke" + case TaprootLocalCommitSpendFinal: + return "TaprootLocalCommitSpendFinal" + + case TaprootRemoteCommitSpendFinal: + return "TaprootRemoteCommitSpendFinal" + + case TaprootHtlcOfferedTimeoutSecondLevelFinal: + return "TaprootHtlcOfferedTimeoutSecondLevelFinal" + + case TaprootHtlcAcceptedSuccessSecondLevelFinal: + return "TaprootHtlcAcceptedSuccessSecondLevelFinal" + + case TaprootHtlcOfferedRemoteTimeoutFinal: + return "TaprootHtlcOfferedRemoteTimeoutFinal" + + case TaprootHtlcAcceptedRemoteSuccessFinal: + return "TaprootHtlcAcceptedRemoteSuccessFinal" + + case TaprootCommitmentRevokeFinal: + return "TaprootCommitmentRevokeFinal" + default: return fmt.Sprintf("Unknown WitnessType: %v", uint32(wt)) } @@ -682,6 +738,9 @@ func (wt StandardWitnessType) WitnessGenerator(signer Signer, "must be set for taproot spend") } + // TODO: For production taproot channels, we need to pass + // script options to generate the correct scripts. This requires + // channel type context that's not available here. witness, err := ReceiverHTLCScriptTaprootTimeout( signer, desc, tx, -1, nil, nil, ) @@ -715,6 +774,130 @@ func (wt StandardWitnessType) WitnessGenerator(signer Signer, Witness: witness, }, nil + // Production taproot witness types - these use the same witness generation + // functions as their staging counterparts since the script options are + // applied when creating the script trees stored in the SignDescriptor. + case TaprootLocalCommitSpendFinal: + // Same witness generation as TaprootLocalCommitSpend + desc.SignMethod = TaprootScriptSpendSignMethod + + if desc.ControlBlock == nil { + return nil, fmt.Errorf("control block " + + "must be set for taproot spend") + } + + witness, err := TaprootCommitSpendSuccess( + signer, desc, tx, nil, + ) + if err != nil { + return nil, err + } + + return &Script{ + Witness: witness, + }, nil + + case TaprootRemoteCommitSpendFinal: + // Same witness generation as TaprootRemoteCommitSpend + desc.SignMethod = TaprootScriptSpendSignMethod + + if desc.ControlBlock == nil { + return nil, fmt.Errorf("control block " + + "must be set for taproot spend") + } + + witness, err := TaprootCommitSpendSuccess( + signer, desc, tx, nil, + ) + if err != nil { + return nil, err + } + + return &Script{ + Witness: witness, + }, nil + + case TaprootHtlcOfferedTimeoutSecondLevelFinal, + TaprootHtlcAcceptedSuccessSecondLevelFinal: + // Same witness generation as staging versions + desc.SignMethod = TaprootScriptSpendSignMethod + + if desc.ControlBlock == nil { + return nil, fmt.Errorf("control block must " + + "be set for taproot spend") + } + + witness, err := TaprootHtlcSpendSuccess( + signer, desc, tx, nil, nil, + ) + if err != nil { + return nil, err + } + + return &Script{ + Witness: witness, + }, nil + + case TaprootHtlcOfferedRemoteTimeoutFinal: + // Same witness generation as TaprootHtlcOfferedRemoteTimeout + desc.SignMethod = TaprootScriptSpendSignMethod + + if desc.ControlBlock == nil { + return nil, fmt.Errorf("control block " + + "must be set for taproot spend") + } + + witness, err := ReceiverHTLCScriptTaprootTimeout( + signer, desc, tx, -1, nil, nil, + ) + if err != nil { + return nil, err + } + + return &Script{ + Witness: witness, + }, nil + + case TaprootHtlcAcceptedRemoteSuccessFinal: + // Same witness generation as TaprootHtlcAcceptedRemoteSuccess + desc.SignMethod = TaprootScriptSpendSignMethod + + if desc.ControlBlock == nil { + return nil, fmt.Errorf("control block " + + "must be set for taproot spend") + } + + witness, err := SenderHTLCScriptTaprootRedeem( + signer, desc, tx, nil, nil, nil, + ) + if err != nil { + return nil, err + } + + return &Script{ + Witness: witness, + }, nil + + case TaprootCommitmentRevokeFinal: + // Same witness generation as TaprootCommitmentRevoke + desc.SignMethod = TaprootScriptSpendSignMethod + + if desc.ControlBlock == nil { + return nil, fmt.Errorf("control block " + + "must be set for taproot spend") + } + + witness, err := TaprootCommitSpendRevoke( + signer, desc, tx, nil, + ) + if err != nil { + return nil, err + } + + return &Script{ + Witness: witness, + }, nil + default: return nil, fmt.Errorf("unknown witness type: %v", wt) } @@ -869,6 +1052,26 @@ func (wt StandardWitnessType) SizeUpperBound() (lntypes.WeightUnit, case TaprootCommitmentRevoke: return TaprootToLocalRevokeWitnessSize, false, nil + + // Production taproot witness types have the same sizes as their staging counterparts + case TaprootLocalCommitSpendFinal: + return TaprootToLocalWitnessSize, false, nil + + case TaprootRemoteCommitSpendFinal: + return TaprootToRemoteWitnessSize, false, nil + + case TaprootHtlcOfferedTimeoutSecondLevelFinal, + TaprootHtlcAcceptedSuccessSecondLevelFinal: + return TaprootSecondLevelHtlcWitnessSize, false, nil + + case TaprootHtlcOfferedRemoteTimeoutFinal: + return TaprootHtlcOfferedRemoteTimeoutWitnessSize, false, nil + + case TaprootHtlcAcceptedRemoteSuccessFinal: + return TaprootHtlcAcceptedRemoteSuccessWitnessSize, false, nil + + case TaprootCommitmentRevokeFinal: + return TaprootToLocalRevokeWitnessSize, false, nil } return 0, false, fmt.Errorf("unexpected witness type: %v", wt) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index ec7f672e1ae..18f214336ec 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -487,6 +487,10 @@ var allTestCases = []*lntest.TestCase{ Name: "simple taproot channel activation", TestFunc: testSimpleTaprootChannelActivation, }, + { + Name: "simple taproot final channel activation", + TestFunc: testSimpleTaprootFinalChannelActivation, + }, { Name: "wallet import pubkey", TestFunc: testWalletImportPubKey, diff --git a/itest/lnd_channel_backup_test.go b/itest/lnd_channel_backup_test.go index d3daeb1df79..f4911a95f8b 100644 --- a/itest/lnd_channel_backup_test.go +++ b/itest/lnd_channel_backup_test.go @@ -193,7 +193,8 @@ func newChanRestoreScenario(ht *lntest.HarnessTest, ct lnrpc.CommitmentType, // If the commitment type is taproot, then the channel must also be // private. var privateChan bool - if ct == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if ct == lnrpc.CommitmentType_SIMPLE_TAPROOT || + ct == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { privateChan = true } @@ -639,7 +640,8 @@ func runChanRestoreScenarioCommitTypes(ht *lntest.HarnessTest, // If this was a zero conf taproot channel, then since it's private, // we'll need to mine an extra block (framework won't mine extra blocks // otherwise). - if ct == lnrpc.CommitmentType_SIMPLE_TAPROOT && zeroConf { + if (ct == lnrpc.CommitmentType_SIMPLE_TAPROOT || + ct == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL) && zeroConf { ht.MineBlocksAndAssertNumTxes(1, 1) } diff --git a/itest/lnd_channel_force_close_test.go b/itest/lnd_channel_force_close_test.go index c04036a7673..46f425532a5 100644 --- a/itest/lnd_channel_force_close_test.go +++ b/itest/lnd_channel_force_close_test.go @@ -26,6 +26,10 @@ var channelForceCloseTestCases = []*lntest.TestCase{ Name: "simple taproot", TestFunc: testChannelForceClosureSimpleTaproot, }, + { + Name: "simple taproot final", + TestFunc: testChannelForceClosureSimpleTaprootFinal, + }, { Name: "anchor restart", TestFunc: testChannelForceClosureAnchorRestart, @@ -34,6 +38,10 @@ var channelForceCloseTestCases = []*lntest.TestCase{ Name: "simple taproot restart", TestFunc: testChannelForceClosureSimpleTaprootRestart, }, + { + Name: "simple taproot final restart", + TestFunc: testChannelForceClosureSimpleTaprootFinalRestart, + }, { Name: "wrong preimage", @@ -87,6 +95,31 @@ func testChannelForceClosureSimpleTaproot(ht *lntest.HarnessTest) { runChannelForceClosureTest(ht, cfgs, openChannelParams) } +// testChannelForceClosureSimpleTaprootFinal runs `runChannelForceClosureTest` +// with production simple taproot channels. +func testChannelForceClosureSimpleTaprootFinal(ht *lntest.HarnessTest) { + // Create a simple network: Alice -> Carol, using production simple + // taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + PushAmt: pushAmt, + // If the channel is a taproot channel, then we'll need to + // create a private channel. + // + // TODO(roasbeef): lift after G175 + CommitmentType: lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfgCarol} + + runChannelForceClosureTest(ht, cfgs, openChannelParams) +} + // runChannelForceClosureTest performs a test to exercise the behavior of // "force" closing a channel or unilaterally broadcasting the latest local // commitment state on-chain. The test creates a new channel between Alice and @@ -675,6 +708,31 @@ func testChannelForceClosureSimpleTaprootRestart(ht *lntest.HarnessTest) { runChannelForceClosureTestRestart(ht, cfgs, openChannelParams) } +// testChannelForceClosureSimpleTaprootFinalRestart runs +// `runChannelForceClosureTestRestart` with production simple taproot channels. +func testChannelForceClosureSimpleTaprootFinalRestart(ht *lntest.HarnessTest) { + // Create a simple network: Alice -> Carol, using production simple + // taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + PushAmt: pushAmt, + // If the channel is a taproot channel, then we'll need to + // create a private channel. + // + // TODO(roasbeef): lift after G175 + CommitmentType: lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfgCarol} + + runChannelForceClosureTestRestart(ht, cfgs, openChannelParams) +} + // runChannelForceClosureTestRestart performs a test to exercise the behavior of // "force" closing a channel or unilaterally broadcasting the latest local // commitment state on-chain. The test creates a new channel between Alice and diff --git a/itest/lnd_funding_test.go b/itest/lnd_funding_test.go index 52f0f780513..2ecacbef7ca 100644 --- a/itest/lnd_funding_test.go +++ b/itest/lnd_funding_test.go @@ -34,6 +34,10 @@ var basicFundingTestCases = []*lntest.TestCase{ Name: "basic flow simple taproot", TestFunc: testBasicChannelFundingSimpleTaproot, }, + { + Name: "basic flow simple taproot final", + TestFunc: testBasicChannelFundingSimpleTaprootFinal, + }, } // allFundingTypes defines the channel types to test for the basic funding @@ -42,6 +46,7 @@ var allFundingTypes = []lnrpc.CommitmentType{ lnrpc.CommitmentType_STATIC_REMOTE_KEY, lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT, + lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, } // testBasicChannelFundingStaticRemote performs a test exercising expected @@ -131,6 +136,35 @@ func testBasicChannelFundingSimpleTaproot(ht *lntest.HarnessTest) { } } +// testBasicChannelFundingSimpleTaprootFinal performs a test exercising expected +// behavior from a basic funding workflow. The test creates a new channel +// between Carol and Dave, with Carol using the production simple taproot +// commitment type, and Dave using allFundingTypes. +func testBasicChannelFundingSimpleTaprootFinal(ht *lntest.HarnessTest) { + carolCommitType := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // We'll test all possible combinations of the feature bit presence + // that both nodes can signal for this new channel type. We'll make a + // new Carol+Dave for each test instance as well. + for _, daveCommitType := range allFundingTypes { + cc := carolCommitType + dc := daveCommitType + + testName := fmt.Sprintf( + "carol_commit=%v,dave_commit=%v", cc, dc, + ) + + success := ht.Run(testName, func(t *testing.T) { + st := ht.Subtest(t) + runBasicFundingTest(st, cc, dc) + }) + + if !success { + break + } + } +} + // runBasicFundingTest is a helper function that takes Carol and Dave's // commitment types and test the funding flow. func runBasicFundingTest(ht *lntest.HarnessTest, carolCommitType, @@ -159,14 +193,17 @@ func runBasicFundingTest(ht *lntest.HarnessTest, carolCommitType, // private, otherwise it'll be rejected by Dave. // // TODO(roasbeef): lift after gossip 1.75 - if carolCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if carolCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + carolCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { privateChan = true } - // If carol wants taproot, but dave wants something else, then we'll - // assert that the channel negotiation attempt fails. + // If carol wants taproot, but dave wants something else (excluding + // SIMPLE_TAPROOT_FINAL which is allowed via cross-type negotiation), + // then we'll assert that the channel negotiation attempt fails. if carolCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT && - daveCommitType != lnrpc.CommitmentType_SIMPLE_TAPROOT { + daveCommitType != lnrpc.CommitmentType_SIMPLE_TAPROOT && + daveCommitType != lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { expectedErr := fmt.Errorf("requested channel type " + "not supported") @@ -182,6 +219,33 @@ func runBasicFundingTest(ht *lntest.HarnessTest, carolCommitType, return } + // NOTE: With both staging and final feature bits advertised by default, + // cross-type negotiation (e.g., Carol wants FINAL, Dave prefers STAGING) + // will succeed because explicit channel_type takes precedence. The + // channel will be created with Carol's requested type (FINAL) since + // Dave advertises support for it. This is acceptable because explicit + // channel types allow the initiator to choose which variant to use. + // + // In production deployments where version compatibility matters, nodes + // should be configured to advertise only one variant or the other. + // + // Skip the incompatibility check for same-family types (both taproot) + // when explicit channel types are used. + crossTaprootNegotiation := (carolCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL && + daveCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT) || + (carolCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT && + daveCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL) + + // For cross-taproot negotiation, the channel will use Carol's explicit + // type, so update our expectation accordingly. + if crossTaprootNegotiation { + // Dave will use Carol's requested type since he advertises + // support for both. + // + // The channel will proceed with Carol's explicitly requested + // commitment type. + } + carolChan, daveChan := basicChannelFundingTest( ht, carol, dave, nil, privateChan, &carolCommitType, ) @@ -197,6 +261,9 @@ func runBasicFundingTest(ht *lntest.HarnessTest, carolCommitType, expType := carolCommitType switch daveCommitType { + // Dave supports production taproot, type will be what Carol supports. + case lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL: + // Dave supports taproot, type will be what Carol supports. case lnrpc.CommitmentType_SIMPLE_TAPROOT: @@ -207,6 +274,9 @@ func runBasicFundingTest(ht *lntest.HarnessTest, carolCommitType, if expType == lnrpc.CommitmentType_SIMPLE_TAPROOT { expType = lnrpc.CommitmentType_ANCHORS } + if expType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { + expType = lnrpc.CommitmentType_ANCHORS + } // Dave only supports tweakless, channel will be downgraded to this // type if Carol supports anchors. @@ -216,6 +286,8 @@ func runBasicFundingTest(ht *lntest.HarnessTest, carolCommitType, expType = lnrpc.CommitmentType_STATIC_REMOTE_KEY case lnrpc.CommitmentType_SIMPLE_TAPROOT: expType = lnrpc.CommitmentType_STATIC_REMOTE_KEY + case lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL: + expType = lnrpc.CommitmentType_STATIC_REMOTE_KEY } // Dave only supports legacy type, channel will be downgraded to this @@ -241,6 +313,9 @@ func runBasicFundingTest(ht *lntest.HarnessTest, carolCommitType, case expType == lnrpc.CommitmentType_SIMPLE_TAPROOT && chansCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT: + case expType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL && + chansCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL: + default: ht.Fatalf("expected nodes to signal commit type %v, instead "+ "got %v", expType, chansCommitType) diff --git a/itest/lnd_multi-hop_force_close_test.go b/itest/lnd_multi-hop_force_close_test.go index 034a5641bb1..6c19f1c7d5f 100644 --- a/itest/lnd_multi-hop_force_close_test.go +++ b/itest/lnd_multi-hop_force_close_test.go @@ -47,6 +47,14 @@ var multiHopForceCloseTestCases = []*lntest.TestCase{ Name: "local claim outgoing htlc simple taproot zero conf", TestFunc: testLocalClaimOutgoingHTLCSimpleTaprootZeroConf, }, + { + Name: "local claim outgoing htlc simple taproot final", + TestFunc: testLocalClaimOutgoingHTLCSimpleTaprootFinal, + }, + { + Name: "local claim outgoing htlc simple taproot final zero conf", + TestFunc: testLocalClaimOutgoingHTLCSimpleTaprootFinalZeroConf, + }, { Name: "local claim outgoing htlc leased", TestFunc: testLocalClaimOutgoingHTLCLeased, @@ -71,6 +79,14 @@ var multiHopForceCloseTestCases = []*lntest.TestCase{ Name: "receiver preimage claim simple taproot zero conf", TestFunc: testMultiHopReceiverPreimageClaimSimpleTaprootZeroConf, }, + { + Name: "receiver preimage claim simple taproot final", + TestFunc: testMultiHopReceiverPreimageClaimSimpleTaprootFinal, + }, + { + Name: "receiver preimage claim simple taproot final zero conf", + TestFunc: testMultiHopReceiverPreimageClaimSimpleTaprootFinalZeroConf, + }, { Name: "receiver preimage claim leased", TestFunc: testMultiHopReceiverPreimageClaimLeased, @@ -95,6 +111,14 @@ var multiHopForceCloseTestCases = []*lntest.TestCase{ Name: "local force close before timeout simple taproot zero conf", TestFunc: testLocalForceCloseBeforeTimeoutSimpleTaprootZeroConf, }, + { + Name: "local force close before timeout simple taproot final", + TestFunc: testLocalForceCloseBeforeTimeoutSimpleTaprootFinal, + }, + { + Name: "local force close before timeout simple taproot final zero conf", + TestFunc: testLocalForceCloseBeforeTimeoutSimpleTaprootFinalZeroConf, + }, { Name: "local force close before timeout leased", TestFunc: testLocalForceCloseBeforeTimeoutLeased, @@ -119,6 +143,14 @@ var multiHopForceCloseTestCases = []*lntest.TestCase{ Name: "remote force close before timeout simple taproot zero conf", TestFunc: testRemoteForceCloseBeforeTimeoutSimpleTaprootZeroConf, }, + { + Name: "remote force close before timeout simple taproot final", + TestFunc: testRemoteForceCloseBeforeTimeoutSimpleTaprootFinal, + }, + { + Name: "remote force close before timeout simple taproot final zero conf", + TestFunc: testRemoteForceCloseBeforeTimeoutSimpleTaprootFinalZeroConf, + }, { Name: "remote force close before timeout leased", TestFunc: testRemoteForceCloseBeforeTimeoutLeased, @@ -143,6 +175,14 @@ var multiHopForceCloseTestCases = []*lntest.TestCase{ Name: "local claim incoming htlc simple taproot zero conf", TestFunc: testLocalClaimIncomingHTLCSimpleTaprootZeroConf, }, + { + Name: "local claim incoming htlc simple taproot final", + TestFunc: testLocalClaimIncomingHTLCSimpleTaprootFinal, + }, + { + Name: "local claim incoming htlc simple taproot final zero conf", + TestFunc: testLocalClaimIncomingHTLCSimpleTaprootFinalZeroConf, + }, { Name: "local claim incoming htlc leased", TestFunc: testLocalClaimIncomingHTLCLeased, @@ -167,6 +207,14 @@ var multiHopForceCloseTestCases = []*lntest.TestCase{ Name: "local preimage claim simple taproot zero conf", TestFunc: testLocalPreimageClaimSimpleTaprootZeroConf, }, + { + Name: "local preimage claim simple taproot final", + TestFunc: testLocalPreimageClaimSimpleTaprootFinal, + }, + { + Name: "local preimage claim simple taproot final zero conf", + TestFunc: testLocalPreimageClaimSimpleTaprootFinalZeroConf, + }, { Name: "local preimage claim leased", TestFunc: testLocalPreimageClaimLeased, @@ -191,6 +239,14 @@ var multiHopForceCloseTestCases = []*lntest.TestCase{ Name: "htlc aggregation simple taproot zero conf", TestFunc: testHtlcAggregaitonSimpleTaprootZeroConf, }, + { + Name: "htlc aggregation simple taproot final", + TestFunc: testHtlcAggregaitonSimpleTaprootFinal, + }, + { + Name: "htlc aggregation simple taproot final zero conf", + TestFunc: testHtlcAggregaitonSimpleTaprootFinalZeroConf, + }, { Name: "htlc aggregation leased", TestFunc: testHtlcAggregaitonLeased, @@ -285,6 +341,53 @@ func testLocalClaimOutgoingHTLCSimpleTaprootZeroConf(ht *lntest.HarnessTest) { runLocalClaimOutgoingHTLC(ht, cfgs, openChannelParams) } +// testLocalClaimOutgoingHTLCSimpleTaprootFinal tests +// `runLocalClaimOutgoingHTLC` with production simple taproot channel. +func testLocalClaimOutgoingHTLCSimpleTaprootFinal(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using production + // simple taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} + + runLocalClaimOutgoingHTLC(ht, cfgs, openChannelParams) +} + +// testLocalClaimOutgoingHTLCSimpleTaprootFinalZeroConf tests +// `runLocalClaimOutgoingHTLC` with zero-conf production simple taproot channel. +func testLocalClaimOutgoingHTLCSimpleTaprootFinalZeroConf(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // production simple taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } + + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} + + runLocalClaimOutgoingHTLC(ht, cfgs, openChannelParams) +} + // testLocalClaimOutgoingHTLCLeased tests `runLocalClaimOutgoingHTLC` with // script enforced lease channel. func testLocalClaimOutgoingHTLCLeased(ht *lntest.HarnessTest) { @@ -361,7 +464,8 @@ func runLocalClaimOutgoingHTLC(ht *lntest.HarnessTest, // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. var routeHints []*lnrpc.RouteHint - if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { routeHints = makeRouteHints(bob, carol, params.ZeroConf) } @@ -617,6 +721,55 @@ func testMultiHopReceiverPreimageClaimSimpleTaprootZeroConf( runMultiHopReceiverPreimageClaim(ht, cfgs, openChannelParams) } +// testMultiHopReceiverPreimageClaimSimpleTaprootFinal tests +// `runMultiHopReceiverPreimageClaim` with production simple taproot channels. +func testMultiHopReceiverPreimageClaimSimpleTaprootFinal(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using production + // simple taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgs := [][]string{cfg, cfg, cfg} + + runMultiHopReceiverPreimageClaim(ht, cfgs, openChannelParams) +} + +// testMultiHopReceiverPreimageClaimSimpleTaprootFinalZeroConf tests +// `runMultiHopReceiverPreimageClaim` with zero-conf production simple taproot +// channels. +func testMultiHopReceiverPreimageClaimSimpleTaprootFinalZeroConf( + ht *lntest.HarnessTest) { + + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // production simple taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } + + // Prepare Carol's node config to enable zero-conf and leased + // channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} + + runMultiHopReceiverPreimageClaim(ht, cfgs, openChannelParams) +} + // testMultiHopReceiverPreimageClaimLeased tests // `runMultiHopReceiverPreimageClaim` with script enforce lease channels. func testMultiHopReceiverPreimageClaimLeased(ht *lntest.HarnessTest) { @@ -691,7 +844,8 @@ func runMultiHopReceiverPreimageClaim(ht *lntest.HarnessTest, // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. var routeHints []*lnrpc.RouteHint - if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { routeHints = makeRouteHints(bob, carol, params.ZeroConf) } @@ -972,6 +1126,56 @@ func testLocalForceCloseBeforeTimeoutSimpleTaprootZeroConf( runLocalForceCloseBeforeHtlcTimeout(ht, cfgs, params) } +// testLocalForceCloseBeforeTimeoutSimpleTaprootFinal tests +// `runLocalForceCloseBeforeHtlcTimeout` with production simple taproot channel. +func testLocalForceCloseBeforeTimeoutSimpleTaprootFinal(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using production + // simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} + + runLocalForceCloseBeforeHtlcTimeout(ht, cfgs, params) +} + +// testLocalForceCloseBeforeTimeoutSimpleTaprootFinalZeroConf tests +// `runLocalForceCloseBeforeHtlcTimeout` with zero-conf production simple +// taproot channel. +func testLocalForceCloseBeforeTimeoutSimpleTaprootFinalZeroConf( + ht *lntest.HarnessTest) { + + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // production simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } + + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} + + runLocalForceCloseBeforeHtlcTimeout(ht, cfgs, params) +} + // testLocalForceCloseBeforeTimeoutLeased tests // `runLocalForceCloseBeforeHtlcTimeout` with script enforced lease channel. func testLocalForceCloseBeforeTimeoutLeased(ht *lntest.HarnessTest) { @@ -1041,7 +1245,8 @@ func runLocalForceCloseBeforeHtlcTimeout(ht *lntest.HarnessTest, // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. var routeHints []*lnrpc.RouteHint - if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { routeHints = makeRouteHints(bob, carol, params.ZeroConf) } @@ -1311,6 +1516,56 @@ func testRemoteForceCloseBeforeTimeoutSimpleTaproot(ht *lntest.HarnessTest) { runRemoteForceCloseBeforeHtlcTimeout(ht, cfgs, params) } +// testRemoteForceCloseBeforeTimeoutSimpleTaprootFinal tests +// `runRemoteForceCloseBeforeHtlcTimeout` with production simple taproot channel. +func testRemoteForceCloseBeforeTimeoutSimpleTaprootFinal(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using production + // simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} + + runRemoteForceCloseBeforeHtlcTimeout(ht, cfgs, params) +} + +// testRemoteForceCloseBeforeTimeoutSimpleTaprootFinalZeroConf tests +// `runRemoteForceCloseBeforeHtlcTimeout` with zero-conf production simple +// taproot channel. +func testRemoteForceCloseBeforeTimeoutSimpleTaprootFinalZeroConf( + ht *lntest.HarnessTest) { + + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // production simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } + + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} + + runRemoteForceCloseBeforeHtlcTimeout(ht, cfgs, params) +} + // testRemoteForceCloseBeforeTimeoutLeasedZeroConf tests // `runRemoteForceCloseBeforeHtlcTimeout` with zero-conf script enforced lease // channel. @@ -1377,7 +1632,8 @@ func runRemoteForceCloseBeforeHtlcTimeout(ht *lntest.HarnessTest, // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. var routeHints []*lnrpc.RouteHint - if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { routeHints = makeRouteHints(bob, carol, params.ZeroConf) } @@ -1608,6 +1864,52 @@ func testLocalClaimIncomingHTLCSimpleTaproot(ht *lntest.HarnessTest) { runLocalClaimIncomingHTLC(ht, cfgs, params) } +// testLocalClaimIncomingHTLCSimpleTaprootFinal tests +// `runLocalClaimIncomingHTLC` with production simple taproot channel. +func testLocalClaimIncomingHTLCSimpleTaprootFinal(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using production + // simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgs := [][]string{cfg, cfg, cfg} + + runLocalClaimIncomingHTLC(ht, cfgs, params) +} + +// testLocalClaimIncomingHTLCSimpleTaprootFinalZeroConf tests +// `runLocalClaimIncomingHTLC` with zero-conf production simple taproot channel. +func testLocalClaimIncomingHTLCSimpleTaprootFinalZeroConf(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // production simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } + + // Prepare Carol's node config to enable zero-conf and simple taproot + // channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} + + runLocalClaimIncomingHTLC(ht, cfgs, params) +} + // runLocalClaimIncomingHTLC tests that in a multi-hop HTLC scenario, if we // force close a channel with an incoming HTLC, and later find out the preimage // via the witness beacon, we properly settle the HTLC on-chain using the HTLC @@ -1633,7 +1935,8 @@ func runLocalClaimIncomingHTLC(ht *lntest.HarnessTest, // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. var routeHints []*lnrpc.RouteHint - if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { routeHints = makeRouteHints(bob, carol, params.ZeroConf) } @@ -2236,6 +2539,51 @@ func testLocalPreimageClaimSimpleTaproot(ht *lntest.HarnessTest) { runLocalPreimageClaim(ht, cfgs, params) } +// testLocalPreimageClaimSimpleTaprootFinal tests `runLocalPreimageClaim` with +// production simple taproot channel. +func testLocalPreimageClaimSimpleTaprootFinal(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using production + // simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgs := [][]string{cfg, cfg, cfg} + + runLocalPreimageClaim(ht, cfgs, params) +} + +// testLocalPreimageClaimSimpleTaprootFinalZeroConf tests +// `runLocalPreimageClaim` with zero-conf production simple taproot channel. +func testLocalPreimageClaimSimpleTaprootFinalZeroConf(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // production simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } + + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} + + runLocalPreimageClaim(ht, cfgs, params) +} + // runLocalPreimageClaim tests that in the multi-hop HTLC scenario, if the // remote party goes to chain while we have an incoming HTLC, then when we // found out the preimage via the witness beacon, we properly settle the HTLC @@ -2262,7 +2610,8 @@ func runLocalPreimageClaim(ht *lntest.HarnessTest, // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. var routeHints []*lnrpc.RouteHint - if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { routeHints = makeRouteHints(bob, carol, params.ZeroConf) } @@ -2808,6 +3157,51 @@ func testHtlcAggregaitonSimpleTaproot(ht *lntest.HarnessTest) { runHtlcAggregation(ht, cfgs, params) } +// testHtlcAggregaitonSimpleTaprootFinal tests `runHtlcAggregation` with +// production simple taproot channel. +func testHtlcAggregaitonSimpleTaprootFinal(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using production + // simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgs := [][]string{cfg, cfg, cfg} + + runHtlcAggregation(ht, cfgs, params) +} + +// testHtlcAggregaitonSimpleTaprootFinalZeroConf tests `runHtlcAggregation` +// with zero-conf production simple taproot channel. +func testHtlcAggregaitonSimpleTaprootFinalZeroConf(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // production simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } + + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} + + runHtlcAggregation(ht, cfgs, params) +} + // testHtlcAggregaitonLeasedZeroConf tests `runHtlcAggregation` with zero-conf // script enforced lease channel. func testHtlcAggregaitonLeasedZeroConf(ht *lntest.HarnessTest) { @@ -2878,7 +3272,8 @@ func runHtlcAggregation(ht *lntest.HarnessTest, aliceRouteHints []*lnrpc.RouteHint ) - if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { carolRouteHints = makeRouteHints(bob, carol, params.ZeroConf) aliceRouteHints = makeRouteHints(bob, alice, params.ZeroConf) } diff --git a/itest/lnd_open_channel_test.go b/itest/lnd_open_channel_test.go index 9377fd4d80e..18877e6aa97 100644 --- a/itest/lnd_open_channel_test.go +++ b/itest/lnd_open_channel_test.go @@ -926,6 +926,66 @@ func testSimpleTaprootChannelActivation(ht *lntest.HarnessTest) { ht.AssertChannelActive(alice, chanPoint) } +// testSimpleTaprootFinalChannelActivation ensures that a simple taproot final +// channel (using production scripts) is active if the initiator disconnects +// and reconnects in between channel opening and channel confirmation. +func testSimpleTaprootFinalChannelActivation(ht *lntest.HarnessTest) { + simpleTaprootFinalChanArgs := lntest.NodeArgsForCommitType( + lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, + ) + + // Make the new set of participants. + alice := ht.NewNode("alice", simpleTaprootFinalChanArgs) + bob := ht.NewNode("bob", simpleTaprootFinalChanArgs) + + ht.FundCoins(btcutil.SatoshiPerBitcoin, alice) + + // Make sure Alice and Bob are connected. + ht.EnsureConnected(alice, bob) + + // Create simple taproot final channel opening parameters. + params := lntest.OpenChannelParams{ + FundMax: true, + CommitmentType: lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, + Private: true, + } + + // Alice opens the channel to Bob. + pendingChan := ht.OpenChannelAssertPending(alice, bob, params) + + // We'll create the channel point to be able to close the channel once + // our test is done. + chanPoint := &lnrpc.ChannelPoint{ + FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{ + FundingTxidBytes: pendingChan.Txid, + }, + OutputIndex: pendingChan.OutputIndex, + } + + // We disconnect and reconnect Alice and Bob before the channel is + // confirmed. Our expectation is that the channel is active once the + // channel is confirmed. + ht.DisconnectNodes(alice, bob) + ht.EnsureConnected(alice, bob) + + // Mine six blocks to confirm the channel funding transaction. + ht.MineBlocksAndAssertNumTxes(6, 1) + + // Verify that Alice sees an active channel to Bob. + ht.AssertChannelActive(alice, chanPoint) + + // Verify that the channel uses the final taproot commitment type. + aliceChannels := alice.RPC.ListChannels(&lnrpc.ListChannelsRequest{}) + require.Len(ht, aliceChannels.Channels, 1) + require.Equal(ht, lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, + aliceChannels.Channels[0].CommitmentType) + + bobChannels := bob.RPC.ListChannels(&lnrpc.ListChannelsRequest{}) + require.Len(ht, bobChannels.Channels, 1) + require.Equal(ht, lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, + bobChannels.Channels[0].CommitmentType) +} + // testOpenChannelLockedBalance tests that when a funding reservation is // made for opening a channel, the balance of the required outputs shows // up as locked balance in the WalletBalance response. diff --git a/itest/lnd_payment_test.go b/itest/lnd_payment_test.go index f9617c68ff3..b630b083af8 100644 --- a/itest/lnd_payment_test.go +++ b/itest/lnd_payment_test.go @@ -682,7 +682,8 @@ func runAsyncPayments(ht *lntest.HarnessTest, alice, bob *node.HarnessNode, if commitType != nil { chanArgs.CommitmentType = *commitType - if *commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if *commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + *commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { chanArgs.Private = true } } diff --git a/itest/lnd_psbt_test.go b/itest/lnd_psbt_test.go index 6090784a096..af79209dbae 100644 --- a/itest/lnd_psbt_test.go +++ b/itest/lnd_psbt_test.go @@ -145,7 +145,8 @@ func runPsbtChanFundingWithNodes(ht *lntest.HarnessTest, carol, // If this is a taproot channel, then we'll decode the PSBT to assert // that an internal key is included. - if commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { decodedPSBT, err := psbt.NewFromRawBytes( bytes.NewReader(tempPsbt), false, ) diff --git a/itest/lnd_remote_signer_test.go b/itest/lnd_remote_signer_test.go index fd48df64320..93a4f0a3547 100644 --- a/itest/lnd_remote_signer_test.go +++ b/itest/lnd_remote_signer_test.go @@ -150,7 +150,8 @@ func prepareRemoteSignerTest(ht *lntest.HarnessTest, tc remoteSignerTestCase) ( } var commitArgs []string - if tc.commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if tc.commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + tc.commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { commitArgs = lntest.NodeArgsForCommitType( tc.commitType, ) diff --git a/itest/lnd_revocation_test.go b/itest/lnd_revocation_test.go index c2508b885bb..be2d92a2a5f 100644 --- a/itest/lnd_revocation_test.go +++ b/itest/lnd_revocation_test.go @@ -52,7 +52,8 @@ func breachRetributionTestCase(ht *lntest.HarnessTest, // In order to test Carol's response to an uncooperative channel // closure by Bob, we'll first open up a channel between them with a // 0.5 BTC value. - privateChan := commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT + privateChan := commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL chanPoint := ht.OpenChannel( carol, bob, lntest.OpenChannelParams{ CommitmentType: commitType, @@ -198,6 +199,7 @@ func breachRetributionTestCase(ht *lntest.HarnessTest, func testRevokedCloseRetribution(ht *lntest.HarnessTest) { for _, commitType := range []lnrpc.CommitmentType{ lnrpc.CommitmentType_SIMPLE_TAPROOT, + lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, } { testName := fmt.Sprintf("%v", commitType.String()) ht.Run(testName, func(t *testing.T) { @@ -248,7 +250,8 @@ func revokedCloseRetributionZeroValueRemoteOutputCase(ht *lntest.HarnessTest, // In order to test Dave's response to an uncooperative channel // closure by Carol, we'll first open up a channel between them with a // 0.5 BTC value. - privateChan := commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT + privateChan := commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL chanPoint := ht.OpenChannel( dave, carol, lntest.OpenChannelParams{ CommitmentType: commitType, @@ -381,6 +384,7 @@ func revokedCloseRetributionZeroValueRemoteOutputCase(ht *lntest.HarnessTest, func testRevokedCloseRetributionZeroValueRemoteOutput(ht *lntest.HarnessTest) { for _, commitType := range []lnrpc.CommitmentType{ lnrpc.CommitmentType_SIMPLE_TAPROOT, + lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, } { testName := fmt.Sprintf("%v", commitType.String()) ht.Run(testName, func(t *testing.T) { @@ -435,7 +439,8 @@ func revokedCloseRetributionRemoteHodlCase(ht *lntest.HarnessTest, // In order to test Dave's response to an uncooperative channel closure // by Carol, we'll first open up a channel between them with a // funding.MaxBtcFundingAmount (2^24) satoshis value. - privateChan := commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT + privateChan := commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL chanPoint := ht.OpenChannel( dave, carol, lntest.OpenChannelParams{ Amt: chanAmt, @@ -704,6 +709,7 @@ func revokedCloseRetributionRemoteHodlCase(ht *lntest.HarnessTest, func testRevokedCloseRetributionRemoteHodl(ht *lntest.HarnessTest) { for _, commitType := range []lnrpc.CommitmentType{ lnrpc.CommitmentType_SIMPLE_TAPROOT, + lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, } { testName := fmt.Sprintf("%v", commitType.String()) ht.Run(testName, func(t *testing.T) { diff --git a/lnrpc/lightning.pb.go b/lnrpc/lightning.pb.go index 81ca7d3dd88..d53e89aea11 100644 --- a/lnrpc/lightning.pb.go +++ b/lnrpc/lightning.pb.go @@ -230,12 +230,17 @@ const ( // channel before its maturity date. CommitmentType_SCRIPT_ENFORCED_LEASE CommitmentType = 4 // A channel that uses musig2 for the funding output, and the new tapscript - // features where relevant. + // features where relevant. This is the staging version using development + // scripts. CommitmentType_SIMPLE_TAPROOT CommitmentType = 5 + // A channel that uses musig2 for the funding output, and the new tapscript + // features where relevant. This is the production version using final scripts + // and feature bits 80/81. + CommitmentType_SIMPLE_TAPROOT_FINAL CommitmentType = 6 // Identical to the SIMPLE_TAPROOT channel type, but with extra functionality. // This channel type also commits to additional meta data in the tapscript // leaves for the scripts in a channel. - CommitmentType_SIMPLE_TAPROOT_OVERLAY CommitmentType = 6 + CommitmentType_SIMPLE_TAPROOT_OVERLAY CommitmentType = 7 ) // Enum value maps for CommitmentType. @@ -247,7 +252,8 @@ var ( 3: "ANCHORS", 4: "SCRIPT_ENFORCED_LEASE", 5: "SIMPLE_TAPROOT", - 6: "SIMPLE_TAPROOT_OVERLAY", + 6: "SIMPLE_TAPROOT_FINAL", + 7: "SIMPLE_TAPROOT_OVERLAY", } CommitmentType_value = map[string]int32{ "UNKNOWN_COMMITMENT_TYPE": 0, @@ -256,7 +262,8 @@ var ( "ANCHORS": 3, "SCRIPT_ENFORCED_LEASE": 4, "SIMPLE_TAPROOT": 5, - "SIMPLE_TAPROOT_OVERLAY": 6, + "SIMPLE_TAPROOT_FINAL": 6, + "SIMPLE_TAPROOT_OVERLAY": 7, } ) @@ -21603,7 +21610,7 @@ var file_lightning_proto_rawDesc = []byte{ 0x53, 0x48, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x10, 0x04, 0x12, 0x19, 0x0a, 0x15, 0x55, 0x4e, 0x55, 0x53, 0x45, 0x44, 0x5f, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, - 0x59, 0x10, 0x05, 0x2a, 0xa8, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, + 0x59, 0x10, 0x05, 0x2a, 0xc2, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x45, 0x47, 0x41, 0x43, 0x59, 0x10, 0x01, 0x12, @@ -21612,422 +21619,424 @@ var file_lightning_proto_rawDesc = []byte{ 0x53, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x45, 0x4e, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x44, 0x5f, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x49, 0x4d, 0x50, 0x4c, 0x45, 0x5f, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, - 0x10, 0x05, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x49, 0x4d, 0x50, 0x4c, 0x45, 0x5f, 0x54, 0x41, 0x50, - 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4f, 0x56, 0x45, 0x52, 0x4c, 0x41, 0x59, 0x10, 0x06, 0x2a, 0x61, - 0x0a, 0x09, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x15, 0x0a, 0x11, 0x49, - 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, - 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x49, 0x4e, 0x49, 0x54, 0x49, - 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x10, 0x02, 0x12, 0x12, 0x0a, - 0x0e, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x42, 0x4f, 0x54, 0x48, 0x10, - 0x03, 0x2a, 0x60, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, - 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x10, - 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x48, 0x54, - 0x4c, 0x43, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4f, 0x55, 0x54, 0x47, 0x4f, 0x49, 0x4e, 0x47, - 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4d, 0x4d, 0x49, - 0x54, 0x10, 0x04, 0x2a, 0x71, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x4f, 0x75, 0x74, 0x63, 0x6f, 0x6d, 0x65, 0x12, 0x13, 0x0a, 0x0f, 0x4f, 0x55, 0x54, 0x43, - 0x4f, 0x4d, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, - 0x07, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, - 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x41, 0x42, 0x41, - 0x4e, 0x44, 0x4f, 0x4e, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x46, 0x49, 0x52, 0x53, - 0x54, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x10, 0x04, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x49, 0x4d, - 0x45, 0x4f, 0x55, 0x54, 0x10, 0x05, 0x2a, 0x39, 0x0a, 0x0e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, - 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x42, 0x45, 0x54, 0x57, 0x45, 0x45, 0x4e, - 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x52, 0x41, 0x4c, 0x49, 0x54, 0x59, 0x10, - 0x01, 0x2a, 0x3b, 0x0a, 0x10, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x48, 0x54, 0x4c, 0x43, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, - 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, 0x44, 0x10, 0x01, - 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x2a, 0xf6, - 0x01, 0x0a, 0x14, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, - 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x13, 0x46, 0x41, 0x49, 0x4c, 0x55, - 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, - 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, - 0x4f, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, - 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, - 0x4f, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x41, 0x49, - 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x45, 0x52, 0x52, 0x4f, - 0x52, 0x10, 0x03, 0x12, 0x2c, 0x0a, 0x28, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, - 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, 0x5f, - 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, 0x53, 0x10, - 0x04, 0x12, 0x27, 0x0a, 0x23, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, - 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, - 0x5f, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x05, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x41, - 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x43, 0x41, 0x4e, - 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x06, 0x2a, 0x89, 0x05, 0x0a, 0x0a, 0x46, 0x65, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x42, 0x69, 0x74, 0x12, 0x18, 0x0a, 0x14, 0x44, 0x41, 0x54, 0x41, 0x4c, 0x4f, - 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x45, 0x43, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x00, + 0x10, 0x05, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x49, 0x4d, 0x50, 0x4c, 0x45, 0x5f, 0x54, 0x41, 0x50, + 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x10, 0x06, 0x12, 0x1a, 0x0a, 0x16, + 0x53, 0x49, 0x4d, 0x50, 0x4c, 0x45, 0x5f, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4f, + 0x56, 0x45, 0x52, 0x4c, 0x41, 0x59, 0x10, 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, 0xf6, 0x01, 0x0a, 0x14, 0x50, 0x61, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x12, 0x17, 0x0a, 0x13, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, + 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x41, + 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x54, 0x49, 0x4d, + 0x45, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, + 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x5f, 0x52, 0x4f, 0x55, 0x54, + 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, + 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x2c, 0x0a, + 0x28, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, + 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, + 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, 0x53, 0x10, 0x04, 0x12, 0x27, 0x0a, 0x23, 0x46, + 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, + 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x42, 0x41, 0x4c, 0x41, 0x4e, + 0x43, 0x45, 0x10, 0x05, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, + 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, + 0x06, 0x2a, 0x89, 0x05, 0x0a, 0x0a, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x69, 0x74, 0x12, 0x18, 0x0a, 0x14, 0x44, 0x41, 0x54, 0x41, 0x4c, 0x4f, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, - 0x54, 0x45, 0x43, 0x54, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x49, 0x4e, - 0x49, 0x54, 0x49, 0x41, 0x4c, 0x5f, 0x52, 0x4f, 0x55, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x59, 0x4e, - 0x43, 0x10, 0x03, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x46, 0x52, 0x4f, 0x4e, 0x54, 0x5f, 0x53, - 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x52, - 0x45, 0x51, 0x10, 0x04, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x46, 0x52, 0x4f, 0x4e, 0x54, 0x5f, - 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, - 0x4f, 0x50, 0x54, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, - 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x06, 0x12, 0x16, 0x0a, - 0x12, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, - 0x4f, 0x50, 0x54, 0x10, 0x07, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x4c, 0x56, 0x5f, 0x4f, 0x4e, 0x49, - 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x08, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x4c, 0x56, 0x5f, - 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x09, 0x12, 0x1a, 0x0a, 0x16, 0x45, - 0x58, 0x54, 0x5f, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, - 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x0a, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x54, 0x5f, 0x47, - 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x4f, 0x50, - 0x54, 0x10, 0x0b, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x54, 0x41, 0x54, 0x49, 0x43, 0x5f, 0x52, 0x45, - 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x0c, 0x12, 0x19, - 0x0a, 0x15, 0x53, 0x54, 0x41, 0x54, 0x49, 0x43, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, - 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0d, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x41, 0x59, - 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x0e, 0x12, - 0x14, 0x0a, 0x10, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x5f, - 0x4f, 0x50, 0x54, 0x10, 0x0f, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x50, 0x50, 0x5f, 0x52, 0x45, 0x51, - 0x10, 0x10, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x50, 0x50, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x11, 0x12, - 0x16, 0x0a, 0x12, 0x57, 0x55, 0x4d, 0x42, 0x4f, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, - 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x12, 0x12, 0x16, 0x0a, 0x12, 0x57, 0x55, 0x4d, 0x42, 0x4f, - 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x13, 0x12, - 0x0f, 0x0a, 0x0b, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x14, - 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, - 0x15, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x5a, 0x45, 0x52, - 0x4f, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x16, - 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x5a, 0x45, 0x52, 0x4f, - 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x17, 0x12, - 0x1b, 0x0a, 0x17, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x42, 0x4c, 0x49, 0x4e, 0x44, 0x49, 0x4e, - 0x47, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x10, 0x18, 0x12, 0x1b, 0x0a, 0x17, - 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x42, 0x4c, 0x49, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x4f, - 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x41, 0x4c, 0x10, 0x19, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x50, - 0x5f, 0x52, 0x45, 0x51, 0x10, 0x1e, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f, 0x4f, 0x50, - 0x54, 0x10, 0x1f, 0x2a, 0xac, 0x01, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x46, 0x61, - 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, - 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, - 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, - 0x55, 0x52, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1c, 0x0a, - 0x18, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, - 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x02, 0x12, 0x1f, 0x0a, 0x1b, 0x55, - 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x49, 0x4e, - 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x5f, 0x45, 0x52, 0x52, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, - 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x49, - 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x45, 0x54, 0x45, 0x52, - 0x10, 0x04, 0x32, 0xc3, 0x27, 0x0a, 0x09, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, - 0x12, 0x4a, 0x0a, 0x0d, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, - 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, - 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0e, - 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1c, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, - 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, - 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0f, 0x47, - 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x44, 0x0a, 0x0b, 0x45, 0x73, 0x74, 0x69, - 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 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, + 0x54, 0x45, 0x43, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x44, 0x41, + 0x54, 0x41, 0x4c, 0x4f, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x45, 0x43, 0x54, 0x5f, 0x4f, + 0x50, 0x54, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x5f, + 0x52, 0x4f, 0x55, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x03, 0x12, 0x1f, 0x0a, + 0x1b, 0x55, 0x50, 0x46, 0x52, 0x4f, 0x4e, 0x54, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, + 0x4e, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x04, 0x12, 0x1f, + 0x0a, 0x1b, 0x55, 0x50, 0x46, 0x52, 0x4f, 0x4e, 0x54, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, + 0x57, 0x4e, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x05, 0x12, + 0x16, 0x0a, 0x12, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, + 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x47, 0x4f, 0x53, 0x53, 0x49, + 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x07, 0x12, + 0x11, 0x0a, 0x0d, 0x54, 0x4c, 0x56, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x51, + 0x10, 0x08, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x4c, 0x56, 0x5f, 0x4f, 0x4e, 0x49, 0x4f, 0x4e, 0x5f, + 0x4f, 0x50, 0x54, 0x10, 0x09, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x54, 0x5f, 0x47, 0x4f, 0x53, + 0x53, 0x49, 0x50, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, + 0x0a, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x54, 0x5f, 0x47, 0x4f, 0x53, 0x53, 0x49, 0x50, 0x5f, + 0x51, 0x55, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0b, 0x12, 0x19, 0x0a, + 0x15, 0x53, 0x54, 0x41, 0x54, 0x49, 0x43, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, + 0x45, 0x59, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x0c, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x54, 0x41, 0x54, + 0x49, 0x43, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x50, + 0x54, 0x10, 0x0d, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, + 0x44, 0x44, 0x52, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x0e, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x41, 0x59, + 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x0f, 0x12, + 0x0b, 0x0a, 0x07, 0x4d, 0x50, 0x50, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x10, 0x12, 0x0b, 0x0a, 0x07, + 0x4d, 0x50, 0x50, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x11, 0x12, 0x16, 0x0a, 0x12, 0x57, 0x55, 0x4d, + 0x42, 0x4f, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, + 0x12, 0x12, 0x16, 0x0a, 0x12, 0x57, 0x55, 0x4d, 0x42, 0x4f, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, + 0x45, 0x4c, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x13, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x4e, 0x43, + 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x14, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x4e, + 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x15, 0x12, 0x1d, 0x0a, 0x19, 0x41, + 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x5f, 0x46, 0x45, 0x45, 0x5f, + 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x16, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4e, + 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x48, + 0x54, 0x4c, 0x43, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x17, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x4f, 0x55, + 0x54, 0x45, 0x5f, 0x42, 0x4c, 0x49, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x52, 0x45, 0x51, 0x55, + 0x49, 0x52, 0x45, 0x44, 0x10, 0x18, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, + 0x42, 0x4c, 0x49, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x41, + 0x4c, 0x10, 0x19, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x1e, + 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x1f, 0x2a, 0xac, 0x01, + 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, + 0x1a, 0x0a, 0x16, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, + 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x55, + 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x50, 0x45, + 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x55, 0x50, 0x44, 0x41, 0x54, + 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, + 0x55, 0x4e, 0x44, 0x10, 0x02, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, + 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, + 0x5f, 0x45, 0x52, 0x52, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, + 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, + 0x5f, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x45, 0x54, 0x45, 0x52, 0x10, 0x04, 0x32, 0xc3, 0x27, 0x0a, + 0x09, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x4a, 0x0a, 0x0d, 0x57, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x69, - 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, - 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, - 0x65, 0x65, 0x72, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, - 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0e, 0x44, 0x69, - 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, - 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x50, 0x65, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x4c, 0x69, 0x73, - 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x13, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x10, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x30, 0x01, 0x12, 0x38, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x15, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0c, - 0x47, 0x65, 0x74, 0x44, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, - 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x50, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0c, 0x4c, 0x69, 0x73, - 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x56, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x19, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x0e, 0x43, 0x6c, - 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1c, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0f, 0x4f, 0x70, 0x65, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x19, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x43, 0x0a, 0x0b, - 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x19, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, - 0x70, 0x65, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, - 0x01, 0x12, 0x53, 0x0a, 0x10, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, - 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, - 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x10, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x65, 0x70, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, 0x67, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x65, 0x70, - 0x52, 0x65, 0x73, 0x70, 0x12, 0x50, 0x0a, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, - 0x63, 0x63, 0x65, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x28, 0x01, 0x30, 0x01, 0x12, 0x46, 0x0a, 0x0c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, - 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x4d, - 0x0a, 0x0e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, - 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, - 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x28, 0x01, 0x30, 0x01, 0x12, 0x3f, - 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, 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, 0x46, 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, 0x22, 0x03, 0x88, 0x02, 0x01, 0x12, - 0x37, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x0e, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x1a, 0x19, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, - 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x33, 0x0a, 0x0d, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, - 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x48, 0x61, 0x73, 0x68, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, - 0x6f, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, - 0x76, 0x6f, 0x69, 0x63, 0x65, 0x30, 0x01, 0x12, 0x32, 0x0a, 0x0c, 0x44, 0x65, 0x63, 0x6f, 0x64, - 0x65, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x1a, 0x0d, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x47, 0x0a, 0x0c, 0x4c, - 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x56, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0d, 0x44, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x47, 0x0a, 0x0e, 0x47, 0x65, - 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x19, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x6e, - 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x64, 0x67, 0x65, 0x12, 0x36, - 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, - 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x44, 0x0a, 0x0b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, - 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, - 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0e, - 0x47, 0x65, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x35, 0x0a, - 0x0a, 0x53, 0x74, 0x6f, 0x70, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x12, 0x12, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x20, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x54, 0x6f, 0x70, 0x6f, 0x6c, - 0x6f, 0x67, 0x79, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, - 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x54, 0x6f, 0x70, - 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x41, 0x0a, - 0x0a, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x18, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, - 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x3e, 0x0a, 0x09, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, - 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x4e, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x56, 0x0a, 0x11, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, - 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, - 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, - 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x13, 0x45, 0x78, 0x70, 0x6f, - 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, - 0x21, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x54, 0x0a, 0x17, 0x45, 0x78, 0x70, 0x6f, - 0x72, 0x74, 0x41, 0x6c, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x73, 0x12, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x4e, - 0x0a, 0x10, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x1a, 0x1f, 0x2e, - 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, - 0x0a, 0x15, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, - 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, - 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x30, 0x01, - 0x12, 0x47, 0x0a, 0x0c, 0x42, 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, - 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, - 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x4c, 0x69, 0x73, - 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x12, 0x1d, 0x2e, 0x6c, - 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, - 0x6e, 0x49, 0x44, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, - 0x49, 0x44, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x10, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x12, - 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, - 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, - 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x50, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, - 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x53, 0x0a, 0x18, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4d, 0x61, 0x63, 0x61, 0x72, - 0x6f, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4d, 0x61, 0x63, 0x50, - 0x65, 0x72, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4d, 0x61, 0x63, 0x50, 0x65, 0x72, 0x6d, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x52, 0x50, 0x43, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, - 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x69, 0x64, 0x64, - 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x1b, - 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, - 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x28, 0x01, 0x30, 0x01, 0x12, - 0x56, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, - 0x64, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, - 0x6e, 0x64, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x73, 0x12, 0x25, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x30, - 0x01, 0x12, 0x44, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, - 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, - 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, - 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x14, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, - 0x70, 0x48, 0x74, 0x6c, 0x63, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x22, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x48, 0x74, - 0x6c, 0x63, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, - 0x75, 0x70, 0x48, 0x74, 0x6c, 0x63, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, 0x72, 0x70, - 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 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, 0x47, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x44, 0x65, 0x62, + 0x75, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x65, 0x74, 0x44, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, + 0x62, 0x75, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x50, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, + 0x6f, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x16, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x0e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, + 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, + 0x73, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0f, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, + 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x43, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, + 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x53, 0x0a, 0x10, 0x42, + 0x61, 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, + 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, + 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4f, 0x70, 0x65, + 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x4c, 0x0a, 0x10, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x53, 0x74, 0x65, 0x70, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x73, + 0x67, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x65, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x50, + 0x0a, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x6f, + 0x72, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, + 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, + 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x28, 0x01, 0x30, 0x01, + 0x12, 0x46, 0x0a, 0x0c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x0e, 0x41, 0x62, 0x61, 0x6e, + 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x03, 0x88, 0x02, 0x01, 0x28, 0x01, 0x30, 0x01, 0x12, 0x3f, 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, 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, 0x46, 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, 0x22, 0x03, 0x88, 0x02, 0x01, 0x12, 0x37, 0x0a, 0x0a, 0x41, 0x64, 0x64, + 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, + 0x65, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, + 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x0d, 0x4c, 0x6f, 0x6f, + 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x1a, 0x0e, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x41, + 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, + 0x63, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, + 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, + 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x30, + 0x01, 0x12, 0x32, 0x0a, 0x0c, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x50, 0x61, 0x79, 0x52, 0x65, + 0x71, 0x12, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x1a, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, + 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x47, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, + 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, + 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, + 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, + 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, + 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0d, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x47, 0x72, + 0x61, 0x70, 0x68, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x47, + 0x72, 0x61, 0x70, 0x68, 0x12, 0x47, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x4d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, + 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, + 0x0b, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x64, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4e, + 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x44, 0x0a, 0x0b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, + 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x35, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x70, 0x44, + 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, + 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, + 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x47, 0x72, 0x61, 0x70, 0x68, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x30, 0x01, 0x12, 0x41, 0x0a, 0x0a, 0x44, 0x65, 0x62, 0x75, 0x67, + 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, + 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, + 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x46, 0x65, + 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x18, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x65, 0x52, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x13, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x46, 0x6f, + 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, + 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, + 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, + 0x69, 0x6e, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x13, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x21, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x12, 0x54, 0x0a, 0x17, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x6c, 0x6c, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x1e, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x4e, 0x0a, 0x10, 0x56, 0x65, 0x72, 0x69, + 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x19, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, + 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x58, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6e, + 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x19, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x30, 0x01, 0x12, 0x47, 0x0a, 0x0c, 0x42, 0x61, + 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x42, 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x42, + 0x61, 0x6b, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, + 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, + 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x1e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, + 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, + 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x4c, 0x69, + 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x18, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x50, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4d, 0x61, 0x63, 0x50, 0x65, 0x72, 0x6d, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x4d, 0x61, 0x63, 0x50, 0x65, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x56, 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x50, 0x43, + 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, + 0x2e, 0x52, 0x50, 0x43, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x28, 0x01, 0x30, 0x01, 0x12, 0x56, 0x0a, 0x11, 0x53, 0x65, 0x6e, + 0x64, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, + 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x75, 0x73, 0x74, 0x6f, + 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x75, 0x73, 0x74, + 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x58, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x25, 0x2e, 0x6c, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x75, 0x73, 0x74, + 0x6f, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x30, 0x01, 0x12, 0x44, 0x0a, 0x0b, 0x4c, + 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, + 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x5f, 0x0a, 0x14, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x48, 0x74, 0x6c, 0x63, 0x52, + 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x6c, 0x6e, 0x72, 0x70, + 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x48, 0x74, 0x6c, 0x63, 0x52, 0x65, 0x73, 0x6f, + 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, + 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x48, 0x74, 0x6c, 0x63, + 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( diff --git a/lnrpc/lightning.proto b/lnrpc/lightning.proto index a88e0bc6563..02e4e0fb288 100644 --- a/lnrpc/lightning.proto +++ b/lnrpc/lightning.proto @@ -1428,16 +1428,24 @@ enum CommitmentType { /* A channel that uses musig2 for the funding output, and the new tapscript - features where relevant. + features where relevant. This is the staging version using development + scripts. */ SIMPLE_TAPROOT = 5; + /* + A channel that uses musig2 for the funding output, and the new tapscript + features where relevant. This is the production version using final scripts + and feature bits 80/81. + */ + SIMPLE_TAPROOT_FINAL = 6; + /* Identical to the SIMPLE_TAPROOT channel type, but with extra functionality. This channel type also commits to additional meta data in the tapscript leaves for the scripts in a channel. */ - SIMPLE_TAPROOT_OVERLAY = 6; + SIMPLE_TAPROOT_OVERLAY = 7; } message ChannelConstraints { diff --git a/lnrpc/lightning.swagger.json b/lnrpc/lightning.swagger.json index 634b32c8887..eddc72802e8 100644 --- a/lnrpc/lightning.swagger.json +++ b/lnrpc/lightning.swagger.json @@ -4755,10 +4755,11 @@ "ANCHORS", "SCRIPT_ENFORCED_LEASE", "SIMPLE_TAPROOT", + "SIMPLE_TAPROOT_FINAL", "SIMPLE_TAPROOT_OVERLAY" ], "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.\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.\n - SIMPLE_TAPROOT: A channel that uses musig2 for the funding output, and the new tapscript\nfeatures where relevant.\n - SIMPLE_TAPROOT_OVERLAY: Identical to the SIMPLE_TAPROOT channel type, but with extra functionality.\nThis channel type also commits to additional meta data in the tapscript\nleaves for the scripts in a channel." + "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.\n - SIMPLE_TAPROOT: A channel that uses musig2 for the funding output, and the new tapscript\nfeatures where relevant. This is the staging version using development\nscripts.\n - SIMPLE_TAPROOT_FINAL: A channel that uses musig2 for the funding output, and the new tapscript\nfeatures where relevant. This is the production version using final scripts\nand feature bits 80/81.\n - SIMPLE_TAPROOT_OVERLAY: Identical to the SIMPLE_TAPROOT channel type, but with extra functionality.\nThis channel type also commits to additional meta data in the tapscript\nleaves for the scripts in a channel." }, "lnrpcConnectPeerRequest": { "type": "object", diff --git a/lnrpc/walletrpc/walletkit.pb.go b/lnrpc/walletrpc/walletkit.pb.go index d89f3861e4b..bfcc7cb814e 100644 --- a/lnrpc/walletrpc/walletkit.pb.go +++ b/lnrpc/walletrpc/walletkit.pb.go @@ -217,6 +217,31 @@ const ( // A witness that allows us to sweep the settled output of a malicious // counterparty's who broadcasts a revoked taproot commitment transaction. WitnessType_TAPROOT_COMMITMENT_REVOKE WitnessType = 35 + // A witness type that allows us to spend our settled local commitment after a + // CSV delay when we force close a production taproot channel. + WitnessType_TAPROOT_LOCAL_COMMIT_SPEND_FINAL WitnessType = 36 + // A witness type that allows us to spend our settled local commitment after + // a CSV delay when the remote party has force closed a production taproot + // channel. + WitnessType_TAPROOT_REMOTE_COMMIT_SPEND_FINAL WitnessType = 37 + // A witness that allows us to timeout an HTLC we offered to the remote party + // on our production taproot commitment transaction. We use this when we need + // to go on chain to time out an HTLC. + WitnessType_TAPROOT_HTLC_OFFERED_TIMEOUT_SECOND_LEVEL_FINAL WitnessType = 38 + // A witness type that allows us to sweep an HTLC we accepted on our + // production taproot commitment transaction after we go to the second level + // on chain. + WitnessType_TAPROOT_HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL_FINAL WitnessType = 39 + // A witness that allows us to sweep an HTLC we offered to the remote party + // that lies on the production taproot commitment transaction for the remote + // party. We can spend this output after the absolute CLTV timeout of the + // HTLC as passed. + WitnessType_TAPROOT_HTLC_OFFERED_REMOTE_TIMEOUT_FINAL WitnessType = 40 + // A witness that allows us to sweep an HTLC that was offered to us by the + // remote party for a production taproot channel. We use this witness in the + // case that the remote party goes to chain, and we know the pre-image to the + // HTLC. We can sweep this without any additional timeout. + WitnessType_TAPROOT_HTLC_ACCEPTED_REMOTE_SUCCESS_FINAL WitnessType = 41 ) // Enum value maps for WitnessType. @@ -258,6 +283,12 @@ var ( 33: "TAPROOT_HTLC_ACCEPTED_REMOTE_SUCCESS", 34: "TAPROOT_HTLC_ACCEPTED_LOCAL_SUCCESS", 35: "TAPROOT_COMMITMENT_REVOKE", + 36: "TAPROOT_LOCAL_COMMIT_SPEND_FINAL", + 37: "TAPROOT_REMOTE_COMMIT_SPEND_FINAL", + 38: "TAPROOT_HTLC_OFFERED_TIMEOUT_SECOND_LEVEL_FINAL", + 39: "TAPROOT_HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL_FINAL", + 40: "TAPROOT_HTLC_OFFERED_REMOTE_TIMEOUT_FINAL", + 41: "TAPROOT_HTLC_ACCEPTED_REMOTE_SUCCESS_FINAL", } WitnessType_value = map[string]int32{ "UNKNOWN_WITNESS": 0, @@ -296,6 +327,12 @@ var ( "TAPROOT_HTLC_ACCEPTED_REMOTE_SUCCESS": 33, "TAPROOT_HTLC_ACCEPTED_LOCAL_SUCCESS": 34, "TAPROOT_COMMITMENT_REVOKE": 35, + "TAPROOT_LOCAL_COMMIT_SPEND_FINAL": 36, + "TAPROOT_REMOTE_COMMIT_SPEND_FINAL": 37, + "TAPROOT_HTLC_OFFERED_TIMEOUT_SECOND_LEVEL_FINAL": 38, + "TAPROOT_HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL_FINAL": 39, + "TAPROOT_HTLC_OFFERED_REMOTE_TIMEOUT_FINAL": 40, + "TAPROOT_HTLC_ACCEPTED_REMOTE_SUCCESS_FINAL": 41, } ) @@ -5141,7 +5178,7 @@ var file_walletrpc_walletkit_proto_rawDesc = []byte{ 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, 0x5f, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x10, 0x04, - 0x2a, 0xfb, 0x09, 0x0a, 0x0b, 0x57, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, + 0x2a, 0x92, 0x0c, 0x0a, 0x0b, 0x57, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x13, 0x0a, 0x0f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x01, 0x12, @@ -5220,158 +5257,176 @@ var file_walletrpc_walletkit_proto_rawDesc = []byte{ 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x22, 0x12, 0x1d, 0x0a, 0x19, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, - 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x56, 0x4f, 0x4b, 0x45, 0x10, 0x23, 0x2a, 0x56, - 0x0a, 0x11, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x1f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x41, 0x44, - 0x44, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, - 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x43, 0x48, 0x41, 0x4e, - 0x47, 0x45, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x50, 0x32, 0x54, 0x52, 0x10, 0x01, 0x32, 0xd6, 0x11, 0x0a, 0x09, 0x57, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x4b, 0x69, 0x74, 0x12, 0x4c, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, - 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 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, 0x0b, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x12, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x65, - 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x65, 0x61, - 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x52, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x12, 0x1f, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, - 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x73, - 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x3a, 0x0a, 0x0d, 0x44, 0x65, 0x72, 0x69, 0x76, 0x65, 0x4e, 0x65, 0x78, 0x74, 0x4b, 0x65, 0x79, - 0x12, 0x11, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, - 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, - 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x38, 0x0a, 0x09, 0x44, - 0x65, 0x72, 0x69, 0x76, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x13, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, - 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x1a, 0x16, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x3b, 0x0a, 0x08, 0x4e, 0x65, 0x78, 0x74, 0x41, 0x64, 0x64, - 0x72, 0x12, 0x16, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, - 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x77, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x12, 0x4f, 0x0a, 0x0c, 0x4c, 0x69, - 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x1e, 0x2e, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x0f, 0x52, - 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x12, 0x21, - 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x69, - 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x22, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x13, 0x53, 0x69, 0x67, - 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, - 0x12, 0x25, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, - 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x56, 0x4f, 0x4b, 0x45, 0x10, 0x23, 0x12, 0x24, + 0x0a, 0x20, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f, + 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x5f, 0x53, 0x50, 0x45, 0x4e, 0x44, 0x5f, 0x46, 0x49, 0x4e, + 0x41, 0x4c, 0x10, 0x24, 0x12, 0x25, 0x0a, 0x21, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, + 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x5f, 0x53, 0x50, + 0x45, 0x4e, 0x44, 0x5f, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x10, 0x25, 0x12, 0x33, 0x0a, 0x2f, 0x54, + 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4f, 0x46, 0x46, 0x45, + 0x52, 0x45, 0x44, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x5f, 0x53, 0x45, 0x43, 0x4f, + 0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x46, 0x49, 0x4e, 0x41, 0x4c, 0x10, 0x26, + 0x12, 0x34, 0x0a, 0x30, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, + 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, + 0x53, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x46, + 0x49, 0x4e, 0x41, 0x4c, 0x10, 0x27, 0x12, 0x2d, 0x0a, 0x29, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, + 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x52, + 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x5f, 0x46, 0x49, + 0x4e, 0x41, 0x4c, 0x10, 0x28, 0x12, 0x2e, 0x0a, 0x2a, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, + 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x5f, 0x52, + 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x46, 0x49, + 0x4e, 0x41, 0x4c, 0x10, 0x29, 0x2a, 0x56, 0x0a, 0x11, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x1f, 0x43, 0x48, + 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, 0x50, + 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x1c, 0x0a, 0x18, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, + 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x32, 0x54, 0x52, 0x10, 0x01, 0x32, 0xd6, 0x11, + 0x0a, 0x09, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x4b, 0x69, 0x74, 0x12, 0x4c, 0x0a, 0x0b, 0x4c, + 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x2e, 0x77, 0x61, 0x6c, + 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 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, 0x0b, 0x4c, 0x65, 0x61, + 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x1f, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x0a, 0x4c, + 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x77, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x0d, 0x44, 0x65, 0x72, 0x69, 0x76, 0x65, + 0x4e, 0x65, 0x78, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x11, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x6f, 0x72, 0x12, 0x38, 0x0a, 0x09, 0x44, 0x65, 0x72, 0x69, 0x76, 0x65, 0x4b, 0x65, 0x79, 0x12, + 0x13, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x63, + 0x61, 0x74, 0x6f, 0x72, 0x1a, 0x16, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, + 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x3b, 0x0a, 0x08, + 0x4e, 0x65, 0x78, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x16, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x17, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0e, 0x47, 0x65, 0x74, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x2e, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x12, 0x4f, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x73, 0x12, 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1f, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x58, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x65, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x12, 0x21, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0d, + 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x1f, 0x2e, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, + 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x64, 0x0a, 0x13, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, + 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x12, 0x25, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, - 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x6a, 0x0a, 0x15, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x12, 0x27, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, + 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x15, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x12, + 0x27, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, + 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x28, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, - 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, - 0x64, 0x64, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x49, - 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x77, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x41, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, - 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x58, 0x0a, 0x0f, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, - 0x65, 0x79, 0x12, 0x21, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x49, - 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x0f, 0x49, 0x6d, 0x70, - 0x6f, 0x72, 0x74, 0x54, 0x61, 0x70, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x21, 0x2e, 0x77, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, - 0x61, 0x70, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x22, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, - 0x72, 0x74, 0x54, 0x61, 0x70, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x12, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e, 0x77, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x1a, 0x1a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, - 0x11, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, - 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x53, 0x65, - 0x6e, 0x64, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x45, 0x73, 0x74, 0x69, - 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x12, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x12, 0x1f, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x77, 0x65, 0x65, 0x70, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x77, 0x65, 0x65, - 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x07, 0x42, 0x75, - 0x6d, 0x70, 0x46, 0x65, 0x65, 0x12, 0x19, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x6d, - 0x70, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x11, - 0x42, 0x75, 0x6d, 0x70, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x46, 0x65, - 0x65, 0x12, 0x23, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, - 0x6d, 0x70, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x46, 0x65, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x43, 0x6c, 0x6f, 0x73, - 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x0a, - 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x12, 0x1c, 0x2e, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x65, 0x65, 0x70, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x10, 0x4c, 0x61, 0x62, 0x65, 0x6c, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x77, 0x61, - 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x23, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x61, 0x62, 0x65, - 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x08, 0x46, 0x75, 0x6e, 0x64, 0x50, 0x73, 0x62, 0x74, - 0x12, 0x1a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, - 0x64, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x77, - 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x50, 0x73, 0x62, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x08, 0x53, 0x69, 0x67, - 0x6e, 0x50, 0x73, 0x62, 0x74, 0x12, 0x1a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1b, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, - 0x67, 0x6e, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, - 0x0a, 0x0c, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x73, 0x62, 0x74, 0x12, 0x1e, - 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x69, 0x6e, 0x61, 0x6c, - 0x69, 0x7a, 0x65, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, - 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x69, 0x6e, 0x61, 0x6c, - 0x69, 0x7a, 0x65, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, - 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, - 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, - 0x6e, 0x64, 0x2f, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2f, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, - 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x0f, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, 0x77, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x58, 0x0a, 0x0f, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x70, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x12, 0x21, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x70, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x70, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x12, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x73, 0x68, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x16, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x11, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c, + 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, + 0x12, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, + 0x64, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, + 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x4c, 0x0a, 0x0b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x12, 0x1d, + 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, + 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, + 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, + 0x0d, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x12, 0x1f, + 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x40, 0x0a, 0x07, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x65, 0x65, 0x12, 0x19, 0x2e, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x65, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x11, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x6f, 0x72, 0x63, 0x65, + 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x46, 0x65, 0x65, 0x12, 0x23, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x43, 0x6c, + 0x6f, 0x73, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x6f, + 0x72, 0x63, 0x65, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x65, 0x65, 0x70, + 0x73, 0x12, 0x1c, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, + 0x0a, 0x10, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x08, 0x46, + 0x75, 0x6e, 0x64, 0x50, 0x73, 0x62, 0x74, 0x12, 0x1a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x46, 0x75, 0x6e, 0x64, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x43, 0x0a, 0x08, 0x53, 0x69, 0x67, 0x6e, 0x50, 0x73, 0x62, 0x74, 0x12, 0x1a, 0x2e, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x50, 0x73, 0x62, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x0c, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, + 0x65, 0x50, 0x73, 0x62, 0x74, 0x12, 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2f, + 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/lnrpc/walletrpc/walletkit.proto b/lnrpc/walletrpc/walletkit.proto index b50d2d67825..77c79ef9a8f 100644 --- a/lnrpc/walletrpc/walletkit.proto +++ b/lnrpc/walletrpc/walletkit.proto @@ -1098,6 +1098,49 @@ enum WitnessType { counterparty's who broadcasts a revoked taproot commitment transaction. */ TAPROOT_COMMITMENT_REVOKE = 35; + + /* + A witness type that allows us to spend our settled local commitment after a + CSV delay when we force close a production taproot channel. + */ + TAPROOT_LOCAL_COMMIT_SPEND_FINAL = 36; + + /* + A witness type that allows us to spend our settled local commitment after + a CSV delay when the remote party has force closed a production taproot + channel. + */ + TAPROOT_REMOTE_COMMIT_SPEND_FINAL = 37; + + /* + A witness that allows us to timeout an HTLC we offered to the remote party + on our production taproot commitment transaction. We use this when we need + to go on chain to time out an HTLC. + */ + TAPROOT_HTLC_OFFERED_TIMEOUT_SECOND_LEVEL_FINAL = 38; + + /* + A witness type that allows us to sweep an HTLC we accepted on our + production taproot commitment transaction after we go to the second level + on chain. + */ + TAPROOT_HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL_FINAL = 39; + + /* + A witness that allows us to sweep an HTLC we offered to the remote party + that lies on the production taproot commitment transaction for the remote + party. We can spend this output after the absolute CLTV timeout of the + HTLC as passed. + */ + TAPROOT_HTLC_OFFERED_REMOTE_TIMEOUT_FINAL = 40; + + /* + A witness that allows us to sweep an HTLC that was offered to us by the + remote party for a production taproot channel. We use this witness in the + case that the remote party goes to chain, and we know the pre-image to the + HTLC. We can sweep this without any additional timeout. + */ + TAPROOT_HTLC_ACCEPTED_REMOTE_SUCCESS_FINAL = 41; } message PendingSweep { diff --git a/lnrpc/walletrpc/walletkit.swagger.json b/lnrpc/walletrpc/walletkit.swagger.json index 1e8e0741fd8..8b1b3431885 100644 --- a/lnrpc/walletrpc/walletkit.swagger.json +++ b/lnrpc/walletrpc/walletkit.swagger.json @@ -2356,10 +2356,16 @@ "TAPROOT_HTLC_LOCAL_OFFERED_TIMEOUT", "TAPROOT_HTLC_ACCEPTED_REMOTE_SUCCESS", "TAPROOT_HTLC_ACCEPTED_LOCAL_SUCCESS", - "TAPROOT_COMMITMENT_REVOKE" + "TAPROOT_COMMITMENT_REVOKE", + "TAPROOT_LOCAL_COMMIT_SPEND_FINAL", + "TAPROOT_REMOTE_COMMIT_SPEND_FINAL", + "TAPROOT_HTLC_OFFERED_TIMEOUT_SECOND_LEVEL_FINAL", + "TAPROOT_HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL_FINAL", + "TAPROOT_HTLC_OFFERED_REMOTE_TIMEOUT_FINAL", + "TAPROOT_HTLC_ACCEPTED_REMOTE_SUCCESS_FINAL" ], "default": "UNKNOWN_WITNESS", - "description": " - COMMITMENT_TIME_LOCK: A witness that allows us to spend the output of a commitment transaction\nafter a relative lock-time lockout.\n - COMMITMENT_NO_DELAY: A witness that allows us to spend a settled no-delay output immediately on a\ncounterparty's commitment transaction.\n - COMMITMENT_REVOKE: A witness that allows us to sweep the settled output of a malicious\ncounterparty's who broadcasts a revoked commitment transaction.\n - HTLC_OFFERED_REVOKE: A witness that allows us to sweep an HTLC which we offered to the remote\nparty in the case that they broadcast a revoked commitment state.\n - HTLC_ACCEPTED_REVOKE: A witness that allows us to sweep an HTLC output sent to us in the case that\nthe remote party broadcasts a revoked commitment state.\n - HTLC_OFFERED_TIMEOUT_SECOND_LEVEL: A witness that allows us to sweep an HTLC output that we extended to a\nparty, but was never fulfilled. This HTLC output isn't directly on the\ncommitment transaction, but is the result of a confirmed second-level HTLC\ntransaction. As a result, we can only spend this after a CSV delay.\n - HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL: A witness that allows us to sweep an HTLC output that was offered to us, and\nfor which we have a payment preimage. This HTLC output isn't directly on our\ncommitment transaction, but is the result of confirmed second-level HTLC\ntransaction. As a result, we can only spend this after a CSV delay.\n - HTLC_OFFERED_REMOTE_TIMEOUT: A witness that allows us to sweep an HTLC that we offered to the remote\nparty which lies in the commitment transaction of the remote party. We can\nspend this output after the absolute CLTV timeout of the HTLC as passed.\n - HTLC_ACCEPTED_REMOTE_SUCCESS: A witness that allows us to sweep an HTLC that was offered to us by the\nremote party. We use this witness in the case that the remote party goes to\nchain, and we know the pre-image to the HTLC. We can sweep this without any\nadditional timeout.\n - HTLC_SECOND_LEVEL_REVOKE: A witness that allows us to sweep an HTLC from the remote party's commitment\ntransaction in the case that the broadcast a revoked commitment, but then\nalso immediately attempt to go to the second level to claim the HTLC.\n - WITNESS_KEY_HASH: A witness type that allows us to spend a regular p2wkh output that's sent to\nan output which is under complete control of the backing wallet.\n - NESTED_WITNESS_KEY_HASH: A witness type that allows us to sweep an output that sends to a nested P2SH\nscript that pays to a key solely under our control.\n - COMMITMENT_ANCHOR: A witness type that allows us to spend our anchor on the commitment\ntransaction.\n - COMMITMENT_NO_DELAY_TWEAKLESS: A witness type that is similar to the COMMITMENT_NO_DELAY type,\nbut it omits the tweak that randomizes the key we need to\nspend with a channel peer supplied set of randomness.\n - COMMITMENT_TO_REMOTE_CONFIRMED: A witness type that allows us to spend our output on the counterparty's\ncommitment transaction after a confirmation.\n - HTLC_OFFERED_TIMEOUT_SECOND_LEVEL_INPUT_CONFIRMED: A witness type that allows us to sweep an HTLC output that we extended\nto a party, but was never fulfilled. This _is_ the HTLC output directly\non our commitment transaction, and the input to the second-level HTLC\ntimeout transaction. It can only be spent after CLTV expiry, and\ncommitment confirmation.\n - HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL_INPUT_CONFIRMED: A witness type that allows us to sweep an HTLC output that was offered\nto us, and for which we have a payment preimage. This _is_ the HTLC\noutput directly on our commitment transaction, and the input to the\nsecond-level HTLC success transaction. It can only be spent after the\ncommitment has confirmed.\n - LEASE_COMMITMENT_TIME_LOCK: A witness type that allows us to spend our output on our local\ncommitment transaction after a relative and absolute lock-time lockout as\npart of the script enforced lease commitment type.\n - LEASE_COMMITMENT_TO_REMOTE_CONFIRMED: A witness type that allows us to spend our output on the counterparty's\ncommitment transaction after a confirmation and absolute locktime as part\nof the script enforced lease commitment type.\n - LEASE_HTLC_OFFERED_TIMEOUT_SECOND_LEVEL: A witness type that allows us to sweep an HTLC output that we extended\nto a party, but was never fulfilled. This HTLC output isn't directly on\nthe commitment transaction, but is the result of a confirmed second-level\nHTLC transaction. As a result, we can only spend this after a CSV delay\nand CLTV locktime as part of the script enforced lease commitment type.\n - LEASE_HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL: A witness type that allows us to sweep an HTLC output that was offered\nto us, and for which we have a payment preimage. This HTLC output isn't\ndirectly on our commitment transaction, but is the result of confirmed\nsecond-level HTLC transaction. As a result, we can only spend this after\na CSV delay and CLTV locktime as part of the script enforced lease\ncommitment type.\n - TAPROOT_PUB_KEY_SPEND: A witness type that allows us to spend a regular p2tr output that's sent\nto an output which is under complete control of the backing wallet.\n - TAPROOT_LOCAL_COMMIT_SPEND: A witness type that allows us to spend our settled local commitment after a\nCSV delay when we force close the channel.\n - TAPROOT_REMOTE_COMMIT_SPEND: A witness type that allows us to spend our settled local commitment after\na CSV delay when the remote party has force closed the channel.\n - TAPROOT_ANCHOR_SWEEP_SPEND: A witness type that we'll use for spending our own anchor output.\n - TAPROOT_HTLC_OFFERED_TIMEOUT_SECOND_LEVEL: A witness that allows us to timeout an HTLC we offered to the remote party\non our commitment transaction. We use this when we need to go on chain to\ntime out an HTLC.\n - TAPROOT_HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL: A witness type that allows us to sweep an HTLC we accepted on our commitment\ntransaction after we go to the second level on chain.\n - TAPROOT_HTLC_SECOND_LEVEL_REVOKE: A witness that allows us to sweep an HTLC on the revoked transaction of the\nremote party that goes to the second level.\n - TAPROOT_HTLC_ACCEPTED_REVOKE: A witness that allows us to sweep an HTLC sent to us by the remote party\nin the event that they broadcast a revoked state.\n - TAPROOT_HTLC_OFFERED_REVOKE: A witness that allows us to sweep an HTLC we offered to the remote party if\nthey broadcast a revoked commitment.\n - TAPROOT_HTLC_OFFERED_REMOTE_TIMEOUT: A witness that allows us to sweep an HTLC we offered to the remote party\nthat lies on the commitment transaction for the remote party. We can spend\nthis output after the absolute CLTV timeout of the HTLC as passed.\n - TAPROOT_HTLC_LOCAL_OFFERED_TIMEOUT: A witness type that allows us to sign the second level HTLC timeout\ntransaction when spending from an HTLC residing on our local commitment\ntransaction.\nThis is used by the sweeper to re-sign inputs if it needs to aggregate\nseveral second level HTLCs.\n - TAPROOT_HTLC_ACCEPTED_REMOTE_SUCCESS: A witness that allows us to sweep an HTLC that was offered to us by the\nremote party for a taproot channels. We use this witness in the case that\nthe remote party goes to chain, and we know the pre-image to the HTLC. We\ncan sweep this without any additional timeout.\n - TAPROOT_HTLC_ACCEPTED_LOCAL_SUCCESS: A witness type that allows us to sweep the HTLC offered to us on our local\ncommitment transaction. We'll use this when we need to go on chain to sweep\nthe HTLC. In this case, this is the second level HTLC success transaction.\n - TAPROOT_COMMITMENT_REVOKE: A witness that allows us to sweep the settled output of a malicious\ncounterparty's who broadcasts a revoked taproot commitment transaction." + "description": " - COMMITMENT_TIME_LOCK: A witness that allows us to spend the output of a commitment transaction\nafter a relative lock-time lockout.\n - COMMITMENT_NO_DELAY: A witness that allows us to spend a settled no-delay output immediately on a\ncounterparty's commitment transaction.\n - COMMITMENT_REVOKE: A witness that allows us to sweep the settled output of a malicious\ncounterparty's who broadcasts a revoked commitment transaction.\n - HTLC_OFFERED_REVOKE: A witness that allows us to sweep an HTLC which we offered to the remote\nparty in the case that they broadcast a revoked commitment state.\n - HTLC_ACCEPTED_REVOKE: A witness that allows us to sweep an HTLC output sent to us in the case that\nthe remote party broadcasts a revoked commitment state.\n - HTLC_OFFERED_TIMEOUT_SECOND_LEVEL: A witness that allows us to sweep an HTLC output that we extended to a\nparty, but was never fulfilled. This HTLC output isn't directly on the\ncommitment transaction, but is the result of a confirmed second-level HTLC\ntransaction. As a result, we can only spend this after a CSV delay.\n - HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL: A witness that allows us to sweep an HTLC output that was offered to us, and\nfor which we have a payment preimage. This HTLC output isn't directly on our\ncommitment transaction, but is the result of confirmed second-level HTLC\ntransaction. As a result, we can only spend this after a CSV delay.\n - HTLC_OFFERED_REMOTE_TIMEOUT: A witness that allows us to sweep an HTLC that we offered to the remote\nparty which lies in the commitment transaction of the remote party. We can\nspend this output after the absolute CLTV timeout of the HTLC as passed.\n - HTLC_ACCEPTED_REMOTE_SUCCESS: A witness that allows us to sweep an HTLC that was offered to us by the\nremote party. We use this witness in the case that the remote party goes to\nchain, and we know the pre-image to the HTLC. We can sweep this without any\nadditional timeout.\n - HTLC_SECOND_LEVEL_REVOKE: A witness that allows us to sweep an HTLC from the remote party's commitment\ntransaction in the case that the broadcast a revoked commitment, but then\nalso immediately attempt to go to the second level to claim the HTLC.\n - WITNESS_KEY_HASH: A witness type that allows us to spend a regular p2wkh output that's sent to\nan output which is under complete control of the backing wallet.\n - NESTED_WITNESS_KEY_HASH: A witness type that allows us to sweep an output that sends to a nested P2SH\nscript that pays to a key solely under our control.\n - COMMITMENT_ANCHOR: A witness type that allows us to spend our anchor on the commitment\ntransaction.\n - COMMITMENT_NO_DELAY_TWEAKLESS: A witness type that is similar to the COMMITMENT_NO_DELAY type,\nbut it omits the tweak that randomizes the key we need to\nspend with a channel peer supplied set of randomness.\n - COMMITMENT_TO_REMOTE_CONFIRMED: A witness type that allows us to spend our output on the counterparty's\ncommitment transaction after a confirmation.\n - HTLC_OFFERED_TIMEOUT_SECOND_LEVEL_INPUT_CONFIRMED: A witness type that allows us to sweep an HTLC output that we extended\nto a party, but was never fulfilled. This _is_ the HTLC output directly\non our commitment transaction, and the input to the second-level HTLC\ntimeout transaction. It can only be spent after CLTV expiry, and\ncommitment confirmation.\n - HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL_INPUT_CONFIRMED: A witness type that allows us to sweep an HTLC output that was offered\nto us, and for which we have a payment preimage. This _is_ the HTLC\noutput directly on our commitment transaction, and the input to the\nsecond-level HTLC success transaction. It can only be spent after the\ncommitment has confirmed.\n - LEASE_COMMITMENT_TIME_LOCK: A witness type that allows us to spend our output on our local\ncommitment transaction after a relative and absolute lock-time lockout as\npart of the script enforced lease commitment type.\n - LEASE_COMMITMENT_TO_REMOTE_CONFIRMED: A witness type that allows us to spend our output on the counterparty's\ncommitment transaction after a confirmation and absolute locktime as part\nof the script enforced lease commitment type.\n - LEASE_HTLC_OFFERED_TIMEOUT_SECOND_LEVEL: A witness type that allows us to sweep an HTLC output that we extended\nto a party, but was never fulfilled. This HTLC output isn't directly on\nthe commitment transaction, but is the result of a confirmed second-level\nHTLC transaction. As a result, we can only spend this after a CSV delay\nand CLTV locktime as part of the script enforced lease commitment type.\n - LEASE_HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL: A witness type that allows us to sweep an HTLC output that was offered\nto us, and for which we have a payment preimage. This HTLC output isn't\ndirectly on our commitment transaction, but is the result of confirmed\nsecond-level HTLC transaction. As a result, we can only spend this after\na CSV delay and CLTV locktime as part of the script enforced lease\ncommitment type.\n - TAPROOT_PUB_KEY_SPEND: A witness type that allows us to spend a regular p2tr output that's sent\nto an output which is under complete control of the backing wallet.\n - TAPROOT_LOCAL_COMMIT_SPEND: A witness type that allows us to spend our settled local commitment after a\nCSV delay when we force close the channel.\n - TAPROOT_REMOTE_COMMIT_SPEND: A witness type that allows us to spend our settled local commitment after\na CSV delay when the remote party has force closed the channel.\n - TAPROOT_ANCHOR_SWEEP_SPEND: A witness type that we'll use for spending our own anchor output.\n - TAPROOT_HTLC_OFFERED_TIMEOUT_SECOND_LEVEL: A witness that allows us to timeout an HTLC we offered to the remote party\non our commitment transaction. We use this when we need to go on chain to\ntime out an HTLC.\n - TAPROOT_HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL: A witness type that allows us to sweep an HTLC we accepted on our commitment\ntransaction after we go to the second level on chain.\n - TAPROOT_HTLC_SECOND_LEVEL_REVOKE: A witness that allows us to sweep an HTLC on the revoked transaction of the\nremote party that goes to the second level.\n - TAPROOT_HTLC_ACCEPTED_REVOKE: A witness that allows us to sweep an HTLC sent to us by the remote party\nin the event that they broadcast a revoked state.\n - TAPROOT_HTLC_OFFERED_REVOKE: A witness that allows us to sweep an HTLC we offered to the remote party if\nthey broadcast a revoked commitment.\n - TAPROOT_HTLC_OFFERED_REMOTE_TIMEOUT: A witness that allows us to sweep an HTLC we offered to the remote party\nthat lies on the commitment transaction for the remote party. We can spend\nthis output after the absolute CLTV timeout of the HTLC as passed.\n - TAPROOT_HTLC_LOCAL_OFFERED_TIMEOUT: A witness type that allows us to sign the second level HTLC timeout\ntransaction when spending from an HTLC residing on our local commitment\ntransaction.\nThis is used by the sweeper to re-sign inputs if it needs to aggregate\nseveral second level HTLCs.\n - TAPROOT_HTLC_ACCEPTED_REMOTE_SUCCESS: A witness that allows us to sweep an HTLC that was offered to us by the\nremote party for a taproot channels. We use this witness in the case that\nthe remote party goes to chain, and we know the pre-image to the HTLC. We\ncan sweep this without any additional timeout.\n - TAPROOT_HTLC_ACCEPTED_LOCAL_SUCCESS: A witness type that allows us to sweep the HTLC offered to us on our local\ncommitment transaction. We'll use this when we need to go on chain to sweep\nthe HTLC. In this case, this is the second level HTLC success transaction.\n - TAPROOT_COMMITMENT_REVOKE: A witness that allows us to sweep the settled output of a malicious\ncounterparty's who broadcasts a revoked taproot commitment transaction.\n - TAPROOT_LOCAL_COMMIT_SPEND_FINAL: A witness type that allows us to spend our settled local commitment after a\nCSV delay when we force close a production taproot channel.\n - TAPROOT_REMOTE_COMMIT_SPEND_FINAL: A witness type that allows us to spend our settled local commitment after\na CSV delay when the remote party has force closed a production taproot\nchannel.\n - TAPROOT_HTLC_OFFERED_TIMEOUT_SECOND_LEVEL_FINAL: A witness that allows us to timeout an HTLC we offered to the remote party\non our production taproot commitment transaction. We use this when we need\nto go on chain to time out an HTLC.\n - TAPROOT_HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL_FINAL: A witness type that allows us to sweep an HTLC we accepted on our\nproduction taproot commitment transaction after we go to the second level\non chain.\n - TAPROOT_HTLC_OFFERED_REMOTE_TIMEOUT_FINAL: A witness that allows us to sweep an HTLC we offered to the remote party\nthat lies on the production taproot commitment transaction for the remote\nparty. We can spend this output after the absolute CLTV timeout of the\nHTLC as passed.\n - TAPROOT_HTLC_ACCEPTED_REMOTE_SUCCESS_FINAL: A witness that allows us to sweep an HTLC that was offered to us by the\nremote party for a production taproot channel. We use this witness in the\ncase that the remote party goes to chain, and we know the pre-image to the\nHTLC. We can sweep this without any additional timeout." } } } diff --git a/lnrpc/walletrpc/walletkit_server.go b/lnrpc/walletrpc/walletkit_server.go index e8f0a79e536..1c4e58d2c99 100644 --- a/lnrpc/walletrpc/walletkit_server.go +++ b/lnrpc/walletrpc/walletkit_server.go @@ -237,6 +237,12 @@ var ( input.TaprootHtlcAcceptedRemoteSuccess: WitnessType_TAPROOT_HTLC_ACCEPTED_REMOTE_SUCCESS, input.TaprootHtlcAcceptedLocalSuccess: WitnessType_TAPROOT_HTLC_ACCEPTED_LOCAL_SUCCESS, input.TaprootCommitmentRevoke: WitnessType_TAPROOT_COMMITMENT_REVOKE, + input.TaprootLocalCommitSpendFinal: WitnessType_TAPROOT_LOCAL_COMMIT_SPEND_FINAL, + input.TaprootRemoteCommitSpendFinal: WitnessType_TAPROOT_REMOTE_COMMIT_SPEND_FINAL, + input.TaprootHtlcOfferedTimeoutSecondLevelFinal: WitnessType_TAPROOT_HTLC_OFFERED_TIMEOUT_SECOND_LEVEL_FINAL, + input.TaprootHtlcAcceptedSuccessSecondLevelFinal: WitnessType_TAPROOT_HTLC_ACCEPTED_SUCCESS_SECOND_LEVEL_FINAL, + input.TaprootHtlcOfferedRemoteTimeoutFinal: WitnessType_TAPROOT_HTLC_OFFERED_REMOTE_TIMEOUT_FINAL, + input.TaprootHtlcAcceptedRemoteSuccessFinal: WitnessType_TAPROOT_HTLC_ACCEPTED_REMOTE_SUCCESS_FINAL, } ) diff --git a/lntest/utils.go b/lntest/utils.go index a07b0643690..aaf2780c23d 100644 --- a/lntest/utils.go +++ b/lntest/utils.go @@ -133,7 +133,8 @@ func channelPointStr(chanPoint *lnrpc.ChannelPoint) string { // CommitTypeHasTaproot returns whether commitType is a taproot commitment. func CommitTypeHasTaproot(commitType lnrpc.CommitmentType) bool { switch commitType { - case lnrpc.CommitmentType_SIMPLE_TAPROOT: + case lnrpc.CommitmentType_SIMPLE_TAPROOT, + lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL: return true default: return false @@ -145,6 +146,7 @@ func CommitTypeHasAnchors(commitType lnrpc.CommitmentType) bool { switch commitType { case lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT, + lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE: return true default: @@ -167,7 +169,8 @@ func NodeArgsForCommitType(commitType lnrpc.CommitmentType) []string { "--protocol.anchors", "--protocol.script-enforced-lease", } - case lnrpc.CommitmentType_SIMPLE_TAPROOT: + case lnrpc.CommitmentType_SIMPLE_TAPROOT, + lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL: return []string{ "--protocol.anchors", "--protocol.simple-taproot-chans", diff --git a/lnwallet/channel.go b/lnwallet/channel.go index cac20ce363f..ae33e657766 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -7,6 +7,7 @@ import ( "crypto/sha256" "errors" "fmt" + "io" "slices" "sync" @@ -838,6 +839,16 @@ type channelOpts struct { auxResolver fn.Option[AuxContractResolver] skipNonceInit bool + + // taprootNonceType specifies which nonce format to use when + // constructing messages for the peer. This is determined by the peer's + // advertised feature bits. + taprootNonceType lnwire.TaprootNonceType + + // customSigningRand is an optional custom random source for generating + // deterministic JIT signing nonces in MuSig2 sessions. This should + // only be set in tests that need reproducible signatures. + customSigningRand fn.Option[io.Reader] } // WithLocalMusigNonces is used to bind an existing verification/local nonce to @@ -889,6 +900,25 @@ func WithAuxResolver(resolver AuxContractResolver) ChannelOpt { } } +// WithCustomSigningRand is used to provide a custom random source for +// generating deterministic JIT signing nonces in MuSig2 sessions. This should +// only be used in tests that need reproducible MuSig2 signatures. +func WithCustomSigningRand(rand io.Reader) ChannelOpt { + return func(o *channelOpts) { + o.customSigningRand = fn.Some[io.Reader](rand) + } +} + +// WithPeerFeatures determines the appropriate nonce type to use based on the +// peer's advertised feature bits. If the peer supports the final taproot +// channel feature bits (80/81), we use the map-based LocalNonces field. +// Otherwise, we fall back to the legacy single LocalNonce field. +func WithPeerFeatures(features *lnwire.FeatureVector) ChannelOpt { + return func(o *channelOpts) { + o.taprootNonceType = lnwire.DetermineTaprootNonceType(features) + } +} + // defaultChannelOpts returns the set of default options for a new channel. func defaultChannelOpts() *channelOpts { return &channelOpts{} @@ -5642,6 +5672,45 @@ func (lc *LightningChannel) RevokeCurrentCommitment() (*lnwire.RevokeAndAck, return revocationMsg, newCommitment.Htlcs, finalHtlcs, nil } +// extractRevokeAndAckNonce extracts the next verification nonce from a +// RevokeAndAck message. It prioritizes the new LocalNonces field over the +// legacy LocalNonce field for backwards compatibility. If neither field is +// present, an error is returned. +func extractRevokeAndAckNonce(revMsg *lnwire.RevokeAndAck, +) (lnwire.Musig2Nonce, error) { + + switch { + case revMsg.LocalNonces.IsSome(): + noncesData, err := revMsg.LocalNonces.UnwrapOrErr( + fmt.Errorf("invalid LocalNonces"), + ) + if err != nil { + return lnwire.Musig2Nonce{}, err + } + + // For revoke and ack, we expect the nonce for the main + // commitment. For now, we take the first nonce from the map. + for _, nonce := range noncesData.NoncesMap { + return nonce, nil + } + + return lnwire.Musig2Nonce{}, fmt.Errorf("remote " + + "verification nonce not sent") + + case revMsg.LocalNonce.IsSome(): + localNonce, err := revMsg.LocalNonce.UnwrapOrErrV(errNoNonce) + if err != nil { + return lnwire.Musig2Nonce{}, err + } + + return localNonce, nil + + default: + return lnwire.Musig2Nonce{}, fmt.Errorf("remote " + + "verification nonce not sent") + } +} + // ReceiveRevocation processes a revocation sent by the remote party for the // lowest unrevoked commitment within their commitment chain. We receive a // revocation either during the initial session negotiation wherein revocation @@ -5827,15 +5896,13 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( // Now that we have a new verification nonce from them, we can refresh // our remote musig2 session which allows us to create another state. if lc.channelState.ChanType.IsTaproot() { - localNonce, err := revMsg.LocalNonce.UnwrapOrErrV(errNoNonce) + localNonce, err := extractRevokeAndAckNonce(revMsg) if err != nil { return nil, nil, err } session, err := lc.musigSessions.RemoteSession.Refresh( - &musig2.Nonces{ - PubNonce: localNonce, - }, + &musig2.Nonces{PubNonce: localNonce}, ) if err != nil { return nil, nil, err @@ -6599,7 +6666,7 @@ func GetSignedCommitTx(inputs SignedCommitTxInputs, musigSession := NewPartialMusigSession( *localNonce, inputs.OurKey, inputs.TheirKey, signer, inputs.SignDesc.Output, LocalMusigCommit, - tapscriptTweak, + tapscriptTweak, fn.None[io.Reader](), ) var remoteSig lnwire.PartialSigWithNonce @@ -7336,10 +7403,16 @@ func newOutgoingHtlcResolution(signer input.Signer, return nil, err } } else { + // Determine script options based on channel type. + var scriptOpts []input.TaprootScriptOpt + if chanType.IsTaprootFinal() { + scriptOpts = append(scriptOpts, input.WithProdScripts()) + } + //nolint:ll secondLevelScriptTree, err := input.TaprootSecondLevelScriptTree( keyRing.RevocationKey, keyRing.ToLocalKey, csvDelay, - secondLevelAuxLeaf, + secondLevelAuxLeaf, scriptOpts..., ) if err != nil { return nil, err @@ -7696,10 +7769,16 @@ func newIncomingHtlcResolution(signer input.Signer, return nil, err } } else { + // Determine script options based on channel type. + var scriptOpts []input.TaprootScriptOpt + if chanType.IsTaprootFinal() { + scriptOpts = append(scriptOpts, input.WithProdScripts()) + } + //nolint:ll secondLevelScriptTree, err := input.TaprootSecondLevelScriptTree( keyRing.RevocationKey, keyRing.ToLocalKey, csvDelay, - secondLevelAuxLeaf, + secondLevelAuxLeaf, scriptOpts..., ) if err != nil { return nil, err @@ -9238,9 +9317,27 @@ func (lc *LightningChannel) generateRevocation(height uint64) (*lnwire.RevokeAnd if err != nil { return nil, err } - revocationMsg.LocalNonce = lnwire.SomeMusig2Nonce( - nextVerificationNonce.PubNonce, - ) + + fundingTxid := lc.channelState.FundingOutpoint.Hash + nonce := nextVerificationNonce.PubNonce + + // Set the appropriate nonce field based on the peer's feature + // bits. If they support the final taproot channel feature bits, + // we use the map-based LocalNonces field. Otherwise, we use the + // legacy single LocalNonce field. + switch lc.opts.taprootNonceType { + case lnwire.TaprootNonceTypeLegacy: + revocationMsg.LocalNonce = lnwire.SomeMusig2Nonce(nonce) + + case lnwire.TaprootNonceTypeMap: + noncesMap := make(map[chainhash.Hash]lnwire.Musig2Nonce) + noncesMap[fundingTxid] = nonce + revocationMsg.LocalNonces = lnwire.SomeLocalNonces( + lnwire.LocalNoncesData{ + NoncesMap: noncesMap, + }, + ) + } } return revocationMsg, nil @@ -9931,13 +10028,14 @@ func (lc *LightningChannel) InitRemoteMusigNonces(remoteNonce *musig2.Nonces, // TODO(roasbeef): propagate rename of signing and verification nonces sessionCfg := &MusigSessionCfg{ - LocalKey: localChanCfg.MultiSigKey, - RemoteKey: remoteChanCfg.MultiSigKey, - LocalNonce: *localNonce, - RemoteNonce: *remoteNonce, - Signer: lc.Signer, - InputTxOut: &lc.fundingOutput, - TapscriptTweak: lc.channelState.TapscriptRoot, + LocalKey: localChanCfg.MultiSigKey, + RemoteKey: remoteChanCfg.MultiSigKey, + LocalNonce: *localNonce, + RemoteNonce: *remoteNonce, + Signer: lc.Signer, + InputTxOut: &lc.fundingOutput, + TapscriptTweak: lc.channelState.TapscriptRoot, + CustomNonceRand: lc.opts.customSigningRand, } lc.musigSessions = NewMusigPairSession( sessionCfg, diff --git a/lnwallet/channel_revoke_nonces_test.go b/lnwallet/channel_revoke_nonces_test.go new file mode 100644 index 00000000000..9364130c27b --- /dev/null +++ b/lnwallet/channel_revoke_nonces_test.go @@ -0,0 +1,220 @@ +package lnwallet + +import ( + "testing" + + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/stretchr/testify/require" +) + +// extractRevocationNonce is a helper function to extract the nonce from a +// RevokeAndAck message, preferring LocalNonces over LocalNonce. +func extractRevocationNonce(t *testing.T, + msg *lnwire.RevokeAndAck) lnwire.Musig2Nonce { + + if msg.LocalNonces.IsSome() { + noncesData := msg.LocalNonces.UnwrapOrFail(t) + + for _, nonce := range noncesData.NoncesMap { + return nonce + } + + // If map is empty, fall back to LocalNonce. + } + + return msg.LocalNonce.UnwrapOrFailV(t) +} + +// revokeModifier is a functional option to modify a RevokeAndAck message. +type revokeModifier func(*lnwire.RevokeAndAck) + +// generateAndProcessRevocation creates fresh channels, performs a state +// transition to generate a RevokeAndAck message, optionally modifies it, and +// processes it. Returns the revocation message and channels for further +// testing. +func generateAndProcessRevocation(t *testing.T, chanType channeldb.ChannelType, + modifier revokeModifier) ( + *lnwire.RevokeAndAck, *LightningChannel, *LightningChannel, error) { + + aliceChannel, bobChannel, err := CreateTestChannels(t, chanType) + require.NoError(t, err) + + aliceNewCommit, err := aliceChannel.SignNextCommitment(ctxb) + if err != nil { + return nil, nil, nil, err + } + err = bobChannel.ReceiveNewCommitment(aliceNewCommit.CommitSigs) + if err != nil { + return nil, nil, nil, err + } + + bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment() + if err != nil { + return nil, nil, nil, err + } + + // Apply the modifier if provided, we'll use this to mutate things to + // test our logic. + if modifier != nil { + modifier(bobRevocation) + } + + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + + return bobRevocation, aliceChannel, bobChannel, err +} + +// TestRevokeAndAckTaprootLocalNonces tests that the RevokeAndAck message +// properly populates the nonce fields based on the peer's feature bits. +// With the default (legacy) nonce type, only LocalNonce is populated. +// With the map nonce type, only LocalNonces is populated. +// This ensures backwards compatibility while supporting production peers. +func TestRevokeAndAckTaprootLocalNonces(t *testing.T) { + t.Parallel() + + chanType := channeldb.SimpleTaprootFeatureBit + + t.Run("legacy nonce type only populates LocalNonce", func(t *testing.T) { + t.Parallel() + + // Default behavior uses TaprootNonceTypeLegacy which only + // populates the LocalNonce field. + revMsg, _, _, err := generateAndProcessRevocation( + t, chanType, nil, + ) + require.NoError(t, err) + + // Verify only LocalNonce is populated (legacy behavior). + require.True( + t, revMsg.LocalNonce.IsSome(), + "LocalNonce should be populated for legacy nonce type", + ) + require.True( + t, revMsg.LocalNonces.IsNone(), + "LocalNonces should NOT be populated for legacy nonce type", + ) + }) + + t.Run("extracted nonce from legacy field", func(t *testing.T) { + t.Parallel() + + revMsg, _, _, err := generateAndProcessRevocation( + t, chanType, nil, + ) + require.NoError(t, err) + + // Verify we can extract the nonce from the legacy field. + legacyNonce := revMsg.LocalNonce.UnwrapOrFailV(t) + extractedNonce := extractRevocationNonce(t, revMsg) + require.Equal( + t, legacyNonce, extractedNonce, + "Extracted nonce should match legacy nonce", + ) + }) + + t.Run("receive with only LocalNonces field", func(t *testing.T) { + t.Parallel() + + // Modify the message to move the nonce from LocalNonce to + // LocalNonces field, simulating a peer using the map-based + // nonce format. + moveToLocalNonces := func(rev *lnwire.RevokeAndAck) { + // Get the nonce from the legacy field. + legacyNonce := rev.LocalNonce.UnwrapOrFailV(t) + + // Move it to the LocalNonces map field. + noncesMap := make(map[chainhash.Hash]lnwire.Musig2Nonce) + // Use a dummy txid for the test. + noncesMap[chainhash.Hash{}] = legacyNonce + rev.LocalNonces = lnwire.SomeLocalNonces( + lnwire.LocalNoncesData{NoncesMap: noncesMap}, + ) + + // Clear the legacy field. + rev.LocalNonce = lnwire.OptMusig2NonceTLV{} + } + + // They should still work properly as the other nonce is + // available. + _, _, _, err := generateAndProcessRevocation( + t, chanType, moveToLocalNonces, + ) + require.NoError( + t, err, + "should successfully process revocation "+ + "with only LocalNonces", + ) + }) + + t.Run("receive with only LocalNonce field (legacy peer)", func(t *testing.T) { + t.Parallel() + + // Modify the message to clear the LocalNonces field. + clearLocalNonces := func(rev *lnwire.RevokeAndAck) { + rev.LocalNonces = lnwire.OptLocalNonces{} + } + + // This should should successfully process with only LocalNonce + // (backwards compat). + _, _, _, err := generateAndProcessRevocation( + t, chanType, clearLocalNonces, + ) + require.NoError( + t, err, + "should successfully process "+ + "revocation with only LocalNonce for "+ + "backwards compatibility", + ) + + }) + + t.Run("error when LocalNonces map is empty", func(t *testing.T) { + t.Parallel() + + // Modify the message to have empty LocalNonces map and no + // LocalNonce. + emptyMap := func(rev *lnwire.RevokeAndAck) { + rev.LocalNonce = lnwire.OptMusig2NonceTLV{} + rev.LocalNonces = lnwire.SomeLocalNonces( + lnwire.LocalNoncesData{ + NoncesMap: make( + map[chainhash.Hash]lnwire.Musig2Nonce, + ), + }, + ) + } + + // We should get an error when the LocalNonces map is empty. + _, _, _, err := generateAndProcessRevocation( + t, chanType, emptyMap, + ) + require.Error( + t, err, "Should error when LocalNonces map is empty", + ) + require.Contains( + t, err.Error(), "remote verification nonce not sent", + ) + }) + + t.Run("error when both fields missing", func(t *testing.T) { + t.Parallel() + + clearBoth := func(rev *lnwire.RevokeAndAck) { + rev.LocalNonce = lnwire.OptMusig2NonceTLV{} + rev.LocalNonces = lnwire.OptLocalNonces{} + } + + // If both fields are missing, we should get an error. + _, _, _, err := generateAndProcessRevocation( + t, chanType, clearBoth, + ) + require.Error( + t, err, "Should error when both fields are missing", + ) + require.Contains( + t, err.Error(), "remote verification nonce not sent", + ) + }) +} diff --git a/lnwallet/channel_test.go b/lnwallet/channel_test.go index 5c8237929bc..a72b8e62eb3 100644 --- a/lnwallet/channel_test.go +++ b/lnwallet/channel_test.go @@ -3559,7 +3559,9 @@ func testChanSyncOweCommitment(t *testing.T, chanType channeldb.ChannelType) { } // TestChanSyncTaprootLocalNonces tests the nonce synchronization behavior for -// taproot channels using both LocalNonce and LocalNonces fields. +// taproot channels. The nonce field populated depends on the nonce type: +// - TaprootNonceTypeLegacy (default): only LocalNonce is populated +// - TaprootNonceTypeMap: only LocalNonces is populated func TestChanSyncTaprootLocalNonces(t *testing.T) { t.Parallel() @@ -3567,54 +3569,54 @@ func TestChanSyncTaprootLocalNonces(t *testing.T) { aliceChannel, bobChannel, err := CreateTestChannels(t, chanType) require.NoError(t, err) - t.Run("both fields populated", func(t *testing.T) { + t.Run("legacy nonce type only populates LocalNonce", func(t *testing.T) { assertNoChanSyncNeeded(t, aliceChannel, bobChannel) + // Default uses TaprootNonceTypeLegacy. aliceChanSyncMsg, err := aliceChannel.channelState.ChanSyncMsg() require.NoError(t, err) bobChanSyncMsg, err := bobChannel.channelState.ChanSyncMsg() require.NoError(t, err) + // Only LocalNonce should be populated. require.True(t, aliceChanSyncMsg.LocalNonce.IsSome()) - require.True(t, aliceChanSyncMsg.LocalNonces.IsSome()) + require.True(t, aliceChanSyncMsg.LocalNonces.IsNone()) require.True(t, bobChanSyncMsg.LocalNonce.IsSome()) - require.True(t, bobChanSyncMsg.LocalNonces.IsSome()) + require.True(t, bobChanSyncMsg.LocalNonces.IsNone()) }) - t.Run("nonces match between fields", func(t *testing.T) { - aliceChanSyncMsg, err := aliceChannel.channelState.ChanSyncMsg() + t.Run("map nonce type only populates LocalNonces", func(t *testing.T) { + // Use TaprootNonceTypeMap. + aliceChanSyncMsg, err := aliceChannel.channelState.ChanSyncMsg( + channeldb.WithChanSyncNonceType(lnwire.TaprootNonceTypeMap), + ) require.NoError(t, err) - aliceLegacyNonce := aliceChanSyncMsg.LocalNonce.UnwrapOrFailV(t) - aliceNoncesData := aliceChanSyncMsg.LocalNonces.UnwrapOrFail(t) - require.Len(t, aliceNoncesData.NoncesMap, 1) - - var aliceMapNonce lnwire.Musig2Nonce - for _, nonce := range aliceNoncesData.NoncesMap { - aliceMapNonce = nonce - break - } - require.Equal(t, aliceLegacyNonce, aliceMapNonce) + // Only LocalNonces should be populated. + require.True(t, aliceChanSyncMsg.LocalNonce.IsNone()) + require.True(t, aliceChanSyncMsg.LocalNonces.IsSome()) - extractedNonce := extractCommitmentNonce(t, aliceChanSyncMsg) - require.Equal(t, aliceLegacyNonce, extractedNonce) + noncesData := aliceChanSyncMsg.LocalNonces.UnwrapOrFail(t) + require.Len(t, noncesData.NoncesMap, 1) }) t.Run("sync with only LocalNonces field", func(t *testing.T) { - aliceChanSyncMsg, err := aliceChannel.channelState.ChanSyncMsg() + // Alice uses map nonce type (sends LocalNonces). + aliceChanSyncMsg, err := aliceChannel.channelState.ChanSyncMsg( + channeldb.WithChanSyncNonceType(lnwire.TaprootNonceTypeMap), + ) require.NoError(t, err) bobChanSyncMsg, err := bobChannel.channelState.ChanSyncMsg() require.NoError(t, err) - aliceModifiedMsg := *aliceChanSyncMsg - aliceModifiedMsg.LocalNonce = lnwire.OptMusig2NonceTLV{} - bobChannel.pendingVerificationNonce = &musig2.Nonces{ PubNonce: extractCommitmentNonce(t, bobChanSyncMsg), } + // Bob should be able to process Alice's message with only + // LocalNonces. bobMsgsToSend, _, _, err := bobChannel.ProcessChanSyncMsg( - ctxb, &aliceModifiedMsg, + ctxb, aliceChanSyncMsg, ) require.NoError(t, err) require.Empty(t, bobMsgsToSend) diff --git a/lnwallet/commitment.go b/lnwallet/commitment.go index ab20d9afaaa..74348eed1a7 100644 --- a/lnwallet/commitment.go +++ b/lnwallet/commitment.go @@ -236,8 +236,14 @@ func CommitScriptToSelf(chanType channeldb.ChannelType, initiator bool, // // Our "redeem" script here is just the taproot witness program. case chanType.IsTaproot(): + // Determine script options based on channel type. + var scriptOpts []input.TaprootScriptOpt + if chanType.IsTaprootFinal() { + scriptOpts = append(scriptOpts, input.WithProdScripts()) + } + return input.NewLocalCommitScriptTree( - csvDelay, selfKey, revokeKey, auxLeaf, + csvDelay, selfKey, revokeKey, auxLeaf, scriptOpts..., ) // If we are the initiator of a leased channel, then we have an @@ -320,8 +326,14 @@ func CommitScriptToRemote(chanType channeldb.ChannelType, initiator bool, // we use a NUMS key to force the remote party to take a script path, // with the sole tap leaf enforcing the 1 CSV delay. case chanType.IsTaproot(): + // Determine script options based on channel type. + var scriptOpts []input.TaprootScriptOpt + if chanType.IsTaprootFinal() { + scriptOpts = append(scriptOpts, input.WithProdScripts()) + } + toRemoteScriptTree, err := input.NewRemoteCommitScriptTree( - remoteKey, auxLeaf, + remoteKey, auxLeaf, scriptOpts..., ) if err != nil { return nil, 0, err @@ -426,8 +438,14 @@ func SecondLevelHtlcScript(chanType channeldb.ChannelType, initiator bool, switch { // For taproot channels, the pkScript is a segwit v1 p2tr output. case chanType.IsTaproot(): + // Determine script options based on channel type. + var scriptOpts []input.TaprootScriptOpt + if chanType.IsTaprootFinal() { + scriptOpts = append(scriptOpts, input.WithProdScripts()) + } + return input.TaprootSecondLevelScriptTree( - revocationKey, delayKey, csvDelay, auxLeaf, + revocationKey, delayKey, csvDelay, auxLeaf, scriptOpts..., ) // If we are the initiator of a leased channel, then we have an @@ -1165,7 +1183,7 @@ func genSegwitV0HtlcScript(chanType channeldb.ChannelType, // channel. func GenTaprootHtlcScript(isIncoming bool, whoseCommit lntypes.ChannelParty, timeout uint32, rHash [32]byte, keyRing *CommitmentKeyRing, - auxLeaf input.AuxTapLeaf) (*input.HtlcScriptTree, error) { + auxLeaf input.AuxTapLeaf, opts ...input.TaprootScriptOpt) (*input.HtlcScriptTree, error) { var ( htlcScriptTree *input.HtlcScriptTree @@ -1182,7 +1200,7 @@ func GenTaprootHtlcScript(isIncoming bool, whoseCommit lntypes.ChannelParty, case isIncoming && whoseCommit.IsLocal(): htlcScriptTree, err = input.ReceiverHTLCScriptTaproot( timeout, keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey, - keyRing.RevocationKey, rHash[:], whoseCommit, auxLeaf, + keyRing.RevocationKey, rHash[:], whoseCommit, auxLeaf, opts..., ) // We're being paid via an HTLC by the remote party, and the HTLC is @@ -1191,7 +1209,7 @@ func GenTaprootHtlcScript(isIncoming bool, whoseCommit lntypes.ChannelParty, case isIncoming && whoseCommit.IsRemote(): htlcScriptTree, err = input.SenderHTLCScriptTaproot( keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey, - keyRing.RevocationKey, rHash[:], whoseCommit, auxLeaf, + keyRing.RevocationKey, rHash[:], whoseCommit, auxLeaf, opts..., ) // We're sending an HTLC which is being added to our commitment @@ -1200,7 +1218,7 @@ func GenTaprootHtlcScript(isIncoming bool, whoseCommit lntypes.ChannelParty, case !isIncoming && whoseCommit.IsLocal(): htlcScriptTree, err = input.SenderHTLCScriptTaproot( keyRing.LocalHtlcKey, keyRing.RemoteHtlcKey, - keyRing.RevocationKey, rHash[:], whoseCommit, auxLeaf, + keyRing.RevocationKey, rHash[:], whoseCommit, auxLeaf, opts..., ) // Finally, we're paying the remote party via an HTLC, which is being @@ -1209,7 +1227,7 @@ func GenTaprootHtlcScript(isIncoming bool, whoseCommit lntypes.ChannelParty, case !isIncoming && whoseCommit.IsRemote(): htlcScriptTree, err = input.ReceiverHTLCScriptTaproot( timeout, keyRing.LocalHtlcKey, keyRing.RemoteHtlcKey, - keyRing.RevocationKey, rHash[:], whoseCommit, auxLeaf, + keyRing.RevocationKey, rHash[:], whoseCommit, auxLeaf, opts..., ) } @@ -1234,8 +1252,14 @@ func genHtlcScript(chanType channeldb.ChannelType, isIncoming bool, ) } + // Determine script options based on channel type. + var scriptOpts []input.TaprootScriptOpt + if chanType.IsTaprootFinal() { + scriptOpts = append(scriptOpts, input.WithProdScripts()) + } + return GenTaprootHtlcScript( - isIncoming, whoseCommit, timeout, rHash, keyRing, auxLeaf, + isIncoming, whoseCommit, timeout, rHash, keyRing, auxLeaf, scriptOpts..., ) } diff --git a/lnwallet/musig_session.go b/lnwallet/musig_session.go index 748e5fa9586..4c4c1a079cf 100644 --- a/lnwallet/musig_session.go +++ b/lnwallet/musig_session.go @@ -237,6 +237,11 @@ type MusigSession struct { // instead of the normal BIP 86 tweak when creating the MuSig2 // aggregate key and session. tapscriptTweak fn.Option[input.MuSig2Tweaks] + + // customNonceRand is an optional custom random source used to generate + // deterministic JIT signing nonces. This should only be set in tests + // that need reproducible MuSig2 signatures. + customNonceRand fn.Option[io.Reader] } // NewPartialMusigSession creates a new musig2 session given only the @@ -245,7 +250,8 @@ type MusigSession struct { func NewPartialMusigSession(verificationNonce musig2.Nonces, localKey, remoteKey keychain.KeyDescriptor, signer input.MuSig2Signer, inputTxOut *wire.TxOut, commitType MusigCommitType, - tapscriptTweak fn.Option[input.MuSig2Tweaks]) *MusigSession { + tapscriptTweak fn.Option[input.MuSig2Tweaks], + customNonceRand fn.Option[io.Reader]) *MusigSession { signerKeys := []*btcec.PublicKey{localKey.PubKey, remoteKey.PubKey} @@ -254,14 +260,15 @@ func NewPartialMusigSession(verificationNonce musig2.Nonces, } return &MusigSession{ - nonces: nonces, - remoteKey: remoteKey, - localKey: localKey, - inputTxOut: inputTxOut, - signerKeys: signerKeys, - signer: signer, - commitType: commitType, - tapscriptTweak: tapscriptTweak, + nonces: nonces, + remoteKey: remoteKey, + localKey: localKey, + inputTxOut: inputTxOut, + signerKeys: signerKeys, + signer: signer, + commitType: commitType, + tapscriptTweak: tapscriptTweak, + customNonceRand: customNonceRand, } } @@ -351,10 +358,17 @@ func (m *MusigSession) SignCommit(tx *wire.MsgTx) (*MusigPartialSig, error) { // a fresh nonce that'll be sent along side our signature. With // the nonce in hand, we can finalize the session. txHash := tx.TxHash() - signingNonce, err := musig2.GenNonces( + nonceOpts := []musig2.NonceGenOption{ musig2.WithPublicKey(m.localKey.PubKey), musig2.WithNonceAuxInput(txHash[:]), - ) + } + m.customNonceRand.WhenSome(func(r io.Reader) { + nonceOpts = append( + nonceOpts, + musig2.WithCustomRand(r), + ) + }) + signingNonce, err := musig2.GenNonces(nonceOpts...) if err != nil { return nil, err } @@ -409,6 +423,7 @@ func (m *MusigSession) Refresh(verificationNonce *musig2.Nonces, return NewPartialMusigSession( *verificationNonce, m.localKey, m.remoteKey, m.signer, m.inputTxOut, m.commitType, m.tapscriptTweak, + m.customNonceRand, ), nil } @@ -587,6 +602,11 @@ type MusigSessionCfg struct { // TapscriptTweak is an optional tweak that can be used to modify the // MuSig2 public key used in the session. TapscriptTweak fn.Option[chainhash.Hash] + + // CustomNonceRand is an optional custom random source for generating + // deterministic JIT signing nonces. This should only be set in tests + // that need reproducible MuSig2 signatures. + CustomNonceRand fn.Option[io.Reader] } // MusigPairSession houses the two musig2 sessions needed to do funding and @@ -615,10 +635,12 @@ func NewMusigPairSession(cfg *MusigSessionCfg) *MusigPairSession { localSession := NewPartialMusigSession( cfg.LocalNonce, cfg.LocalKey, cfg.RemoteKey, cfg.Signer, cfg.InputTxOut, LocalMusigCommit, tapscriptTweak, + cfg.CustomNonceRand, ) remoteSession := NewPartialMusigSession( cfg.RemoteNonce, cfg.LocalKey, cfg.RemoteKey, cfg.Signer, cfg.InputTxOut, RemoteMusigCommit, tapscriptTweak, + cfg.CustomNonceRand, ) return &MusigPairSession{ diff --git a/lnwallet/reservation.go b/lnwallet/reservation.go index a8a0cacd4bf..908759b983a 100644 --- a/lnwallet/reservation.go +++ b/lnwallet/reservation.go @@ -49,9 +49,16 @@ const ( // CommitmentTypeSimpleTaproot is the base commitment type for the // channels that use a musig2 funding output and the tapscript tree - // where relevant for the commitment transaction pk scripts. + // where relevant for the commitment transaction pk scripts. This is + // the staging version using feature bits 180/181. CommitmentTypeSimpleTaproot + // CommitmentTypeSimpleTaprootFinal is the production commitment type for + // taproot channels that use a musig2 funding output and the tapscript tree + // where relevant for the commitment transaction pk scripts. This uses the + // final feature bits 80/81 and production scripts. + CommitmentTypeSimpleTaprootFinal + // CommitmentTypeSimpleTaprootOverlay builds on the existing // CommitmentTypeSimpleTaproot type but layers on a special overlay // protocol. @@ -66,6 +73,7 @@ func (c CommitmentType) HasStaticRemoteKey() bool { CommitmentTypeAnchorsZeroFeeHtlcTx, CommitmentTypeScriptEnforcedLease, CommitmentTypeSimpleTaproot, + CommitmentTypeSimpleTaprootFinal, CommitmentTypeSimpleTaprootOverlay: return true @@ -81,6 +89,7 @@ func (c CommitmentType) HasAnchors() bool { case CommitmentTypeAnchorsZeroFeeHtlcTx, CommitmentTypeScriptEnforcedLease, CommitmentTypeSimpleTaproot, + CommitmentTypeSimpleTaprootFinal, CommitmentTypeSimpleTaprootOverlay: return true @@ -93,6 +102,7 @@ func (c CommitmentType) HasAnchors() bool { // IsTaproot returns true if the channel type is a taproot channel. func (c CommitmentType) IsTaproot() bool { return c == CommitmentTypeSimpleTaproot || + c == CommitmentTypeSimpleTaprootFinal || c == CommitmentTypeSimpleTaprootOverlay } @@ -109,6 +119,8 @@ func (c CommitmentType) String() string { return "script-enforced-lease" case CommitmentTypeSimpleTaproot: return "simple-taproot" + case CommitmentTypeSimpleTaprootFinal: + return "simple-taproot-final" case CommitmentTypeSimpleTaprootOverlay: return "simple-taproot-overlay" default: @@ -441,6 +453,11 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, if req.CommitType.IsTaproot() { chanType |= channeldb.SimpleTaprootFeatureBit + + // Set the final bit if this is the production taproot version. + if req.CommitType == CommitmentTypeSimpleTaprootFinal { + chanType |= channeldb.TaprootFinalBit + } } if req.ZeroConf { diff --git a/lnwallet/taproot_test_vectors_test.go b/lnwallet/taproot_test_vectors_test.go new file mode 100644 index 00000000000..a6894ded057 --- /dev/null +++ b/lnwallet/taproot_test_vectors_test.go @@ -0,0 +1,1261 @@ +package lnwallet + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "flag" + "fmt" + "net" + "os" + "sort" + "testing" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcd/wire" + "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/fn/v2" + "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/keychain" + "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnwallet/chainfee" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/shachain" + "github.com/stretchr/testify/require" +) + +// generateTaprootVectors controls whether to generate test vectors and write +// them to disk, or to verify the stored vectors match regenerated values. +var generateTaprootVectors = flag.Bool( + "generate-taproot-vectors", false, + "generate taproot test vectors and write to "+taprootVectorFile, +) + +const ( + // taprootVectorSeedHex is the single deterministic seed from which all + // test vector keys are derived. + taprootVectorSeedHex = "000102030405060708090a0b0c0d0e0f" + + "101112131415161718191a1b1c1d1e1f" + + // taprootVectorFile is the JSON file where test vectors are stored. + taprootVectorFile = "test_vectors_taproot.json" +) + +// deriveKeyFromSeed derives a deterministic private key from a seed and a +// label string. The key is computed as SHA256(seed || label). +func deriveKeyFromSeed(seed []byte, label string) *btcec.PrivateKey { + h := sha256.New() + h.Write(seed) + h.Write([]byte(label)) + keyBytes := h.Sum(nil) + + privKey, _ := btcec.PrivKeyFromBytes(keyBytes) + return privKey +} + +// pubHex returns the compressed hex encoding of a public key. +func pubHex(pub *btcec.PublicKey) string { + return hex.EncodeToString(pub.SerializeCompressed()) +} + +// privHex returns the hex encoding of a private key scalar. +func privHex(priv *btcec.PrivateKey) string { + return hex.EncodeToString(priv.Serialize()) +} + +// scriptHex returns the hex encoding of a byte slice (script, hash, etc.). +func scriptHex(b []byte) string { + return hex.EncodeToString(b) +} + +// leafHash computes the TapHash of a tap leaf script. +func leafHash(script []byte) string { + leaf := txscript.NewBaseTapLeaf(script) + h := leaf.TapHash() + return hex.EncodeToString(h[:]) +} + +// taprootTestContext holds all deterministic keys and parameters for taproot +// test vector generation. +type taprootTestContext struct { + seed []byte + + localFundingPrivkey *btcec.PrivateKey + remoteFundingPrivkey *btcec.PrivateKey + localPaymentBasepointSecret *btcec.PrivateKey + remotePaymentBasepointSecret *btcec.PrivateKey + localDelayedPaymentBasepointSecret *btcec.PrivateKey + remoteRevocationBasepointSecret *btcec.PrivateKey + localHtlcBasepointSecret *btcec.PrivateKey + remoteHtlcBasepointSecret *btcec.PrivateKey + + localPerCommitSecret lntypes.Hash + + fundingAmount btcutil.Amount + dustLimit btcutil.Amount + localCsvDelay uint16 + commitHeight uint64 + + t *testing.T +} + +// newTaprootTestContext creates a new test context with all keys derived +// deterministically from the single seed. +func newTaprootTestContext(t *testing.T) *taprootTestContext { + seed, err := hex.DecodeString(taprootVectorSeedHex) + require.NoError(t, err) + + tc := &taprootTestContext{ + seed: seed, + fundingAmount: 10_000_000, + dustLimit: 354, + localCsvDelay: 144, + commitHeight: 42, + t: t, + } + + tc.localFundingPrivkey = deriveKeyFromSeed(seed, "local-funding") + tc.remoteFundingPrivkey = deriveKeyFromSeed(seed, "remote-funding") + tc.localPaymentBasepointSecret = deriveKeyFromSeed( + seed, "local-payment-basepoint", + ) + tc.remotePaymentBasepointSecret = deriveKeyFromSeed( + seed, "remote-payment-basepoint", + ) + tc.localDelayedPaymentBasepointSecret = deriveKeyFromSeed( + seed, "local-delayed-payment-basepoint", + ) + tc.remoteRevocationBasepointSecret = deriveKeyFromSeed( + seed, "remote-revocation-basepoint", + ) + tc.localHtlcBasepointSecret = deriveKeyFromSeed( + seed, "local-htlc-basepoint", + ) + tc.remoteHtlcBasepointSecret = deriveKeyFromSeed( + seed, "remote-htlc-basepoint", + ) + + // Derive per-commitment secret from the seed as well. + h := sha256.New() + h.Write(seed) + h.Write([]byte("local-per-commit-secret")) + copy(tc.localPerCommitSecret[:], h.Sum(nil)) + + return tc +} + +// commitPoint returns the per-commitment point derived from the secret. +func (tc *taprootTestContext) commitPoint() *btcec.PublicKey { + return input.ComputeCommitmentPoint(tc.localPerCommitSecret[:]) +} + +// --------------------------------------------------------------------------- +// JSON output types +// --------------------------------------------------------------------------- + +// TaprootTestVectors is the top-level JSON structure for taproot test vectors. +type TaprootTestVectors struct { + Params TestVectorParams `json:"params"` + Scripts ScriptVectors `json:"scripts"` + Transactions []TransactionTestCase `json:"transactions"` +} + +// TestVectorParams holds the seed, channel parameters, and all keys. +type TestVectorParams struct { + Seed string `json:"seed"` + FundingAmountSatoshis int64 `json:"funding_amount_satoshis"` + DustLimitSatoshis int64 `json:"dust_limit_satoshis"` + CsvDelay uint16 `json:"csv_delay"` + CommitHeight uint64 `json:"commit_height"` + NumsPoint string `json:"nums_point"` + Keys KeySet `json:"keys"` +} + +// KeySet contains all base point keys and derived per-commitment keys. +type KeySet struct { + LocalFundingPrivkey string `json:"local_funding_privkey"` + LocalFundingPubkey string `json:"local_funding_pubkey"` + RemoteFundingPrivkey string `json:"remote_funding_privkey"` + RemoteFundingPubkey string `json:"remote_funding_pubkey"` + + LocalPaymentBasepointSecret string `json:"local_payment_basepoint_secret"` + LocalPaymentBasepoint string `json:"local_payment_basepoint"` + RemotePaymentBasepointSecret string `json:"remote_payment_basepoint_secret"` + RemotePaymentBasepoint string `json:"remote_payment_basepoint"` + + LocalDelayedPaymentBasepointSecret string `json:"local_delayed_payment_basepoint_secret"` + LocalDelayedPaymentBasepoint string `json:"local_delayed_payment_basepoint"` + RemoteRevocationBasepointSecret string `json:"remote_revocation_basepoint_secret"` + RemoteRevocationBasepoint string `json:"remote_revocation_basepoint"` + + LocalHtlcBasepointSecret string `json:"local_htlc_basepoint_secret"` + LocalHtlcBasepoint string `json:"local_htlc_basepoint"` + RemoteHtlcBasepointSecret string `json:"remote_htlc_basepoint_secret"` + RemoteHtlcBasepoint string `json:"remote_htlc_basepoint"` + + LocalPerCommitSecret string `json:"local_per_commit_secret"` + LocalPerCommitPoint string `json:"local_per_commit_point"` + + // Derived per-commitment keys. + DerivedLocalDelayedPubkey string `json:"derived_local_delayed_pubkey"` + DerivedRevocationPubkey string `json:"derived_revocation_pubkey"` + DerivedLocalHtlcPubkey string `json:"derived_local_htlc_pubkey"` + DerivedRemoteHtlcPubkey string `json:"derived_remote_htlc_pubkey"` + DerivedRemotePaymentPubkey string `json:"derived_remote_payment_pubkey"` +} + +// ScriptVectorEntry represents a single tapscript tree decomposition. +type ScriptVectorEntry struct { + // For scripts with named leaves. + Scripts map[string]string `json:"scripts,omitempty"` + LeafHashes map[string]string `json:"leaf_hashes,omitempty"` + + TapscriptRoot string `json:"tapscript_root"` + InternalKey string `json:"internal_key"` + OutputKey string `json:"output_key"` + PkScript string `json:"pkscript"` +} + +// FundingScriptVector holds the funding output vector. +type FundingScriptVector struct { + FundingTxHex string `json:"funding_tx_hex"` + CombinedKey string `json:"combined_key"` + PkScript string `json:"pkscript"` +} + +// ScriptVectors holds all script test vectors. +type ScriptVectors struct { + Funding FundingScriptVector `json:"funding"` + ToLocal ScriptVectorEntry `json:"to_local"` + ToRemote ScriptVectorEntry `json:"to_remote"` + LocalAnchor ScriptVectorEntry `json:"local_anchor"` + RemoteAnchor ScriptVectorEntry `json:"remote_anchor"` + OfferedHtlcLocalCommit ScriptVectorEntry `json:"offered_htlc_local_commit"` + OfferedHtlcRemoteCommit ScriptVectorEntry `json:"offered_htlc_remote_commit"` + AcceptedHtlcLocalCommit ScriptVectorEntry `json:"accepted_htlc_local_commit"` + AcceptedHtlcRemoteCommit ScriptVectorEntry `json:"accepted_htlc_remote_commit"` + SecondLevelHtlcSuccess ScriptVectorEntry `json:"second_level_htlc_success"` + SecondLevelHtlcTimeout ScriptVectorEntry `json:"second_level_htlc_timeout"` +} + +// HtlcDesc describes an HTLC resolution in the transaction vectors. +type HtlcDesc struct { + RemotePartialSigHex string `json:"remote_partial_sig_hex"` + ResolutionTxHex string `json:"resolution_tx_hex"` +} + +// HtlcInput describes an HTLC added to the channel for a test case. +type HtlcInput struct { + Incoming bool `json:"incoming"` + AmountMsat uint64 `json:"amount_msat"` + Expiry uint32 `json:"expiry"` + Preimage string `json:"preimage"` +} + +// TransactionTestCase is one transaction test vector. +type TransactionTestCase struct { + Name string `json:"name"` + LocalBalanceMsat uint64 `json:"local_balance_msat"` + RemoteBalanceMsat uint64 `json:"remote_balance_msat"` + FeePerKw int64 `json:"fee_per_kw"` + DustLimitSatoshis int64 `json:"dust_limit_satoshis,omitempty"` + Htlcs []HtlcInput `json:"htlcs"` + RemotePartialSig string `json:"remote_partial_sig"` + ExpectedCommitmentTxHex string `json:"expected_commitment_tx_hex"` + HtlcDescs []HtlcDesc `json:"htlc_descs"` +} + +// --------------------------------------------------------------------------- +// Script vector generation (Section A) +// --------------------------------------------------------------------------- + +// generateParams populates the params section of the test vectors. +func (tc *taprootTestContext) generateParams() TestVectorParams { + commitPt := tc.commitPoint() + + // Derive per-commitment tweaked keys. + localDelayedPubkey := input.TweakPubKey( + tc.localDelayedPaymentBasepointSecret.PubKey(), commitPt, + ) + revocationPubkey := input.DeriveRevocationPubkey( + tc.remoteRevocationBasepointSecret.PubKey(), commitPt, + ) + localHtlcPubkey := input.TweakPubKey( + tc.localHtlcBasepointSecret.PubKey(), commitPt, + ) + remoteHtlcPubkey := input.TweakPubKey( + tc.remoteHtlcBasepointSecret.PubKey(), commitPt, + ) + // For tweakless channels, the remote payment key is untweaked. + remotePaymentPubkey := tc.remotePaymentBasepointSecret.PubKey() + + return TestVectorParams{ + Seed: taprootVectorSeedHex, + FundingAmountSatoshis: int64(tc.fundingAmount), + DustLimitSatoshis: int64(tc.dustLimit), + CsvDelay: tc.localCsvDelay, + CommitHeight: tc.commitHeight, + NumsPoint: input.TaprootNUMSHex, + Keys: KeySet{ + LocalFundingPrivkey: privHex(tc.localFundingPrivkey), + LocalFundingPubkey: pubHex(tc.localFundingPrivkey.PubKey()), + RemoteFundingPrivkey: privHex(tc.remoteFundingPrivkey), + RemoteFundingPubkey: pubHex(tc.remoteFundingPrivkey.PubKey()), + + LocalPaymentBasepointSecret: privHex(tc.localPaymentBasepointSecret), + LocalPaymentBasepoint: pubHex(tc.localPaymentBasepointSecret.PubKey()), + RemotePaymentBasepointSecret: privHex(tc.remotePaymentBasepointSecret), + RemotePaymentBasepoint: pubHex(tc.remotePaymentBasepointSecret.PubKey()), + + LocalDelayedPaymentBasepointSecret: privHex(tc.localDelayedPaymentBasepointSecret), + LocalDelayedPaymentBasepoint: pubHex(tc.localDelayedPaymentBasepointSecret.PubKey()), + RemoteRevocationBasepointSecret: privHex(tc.remoteRevocationBasepointSecret), + RemoteRevocationBasepoint: pubHex(tc.remoteRevocationBasepointSecret.PubKey()), + + LocalHtlcBasepointSecret: privHex(tc.localHtlcBasepointSecret), + LocalHtlcBasepoint: pubHex(tc.localHtlcBasepointSecret.PubKey()), + RemoteHtlcBasepointSecret: privHex(tc.remoteHtlcBasepointSecret), + RemoteHtlcBasepoint: pubHex(tc.remoteHtlcBasepointSecret.PubKey()), + + LocalPerCommitSecret: hex.EncodeToString(tc.localPerCommitSecret[:]), + LocalPerCommitPoint: pubHex(commitPt), + + DerivedLocalDelayedPubkey: pubHex(localDelayedPubkey), + DerivedRevocationPubkey: pubHex(revocationPubkey), + DerivedLocalHtlcPubkey: pubHex(localHtlcPubkey), + DerivedRemoteHtlcPubkey: pubHex(remoteHtlcPubkey), + DerivedRemotePaymentPubkey: pubHex(remotePaymentPubkey), + }, + } +} + +// generateFundingVector generates the funding output script vector. +func (tc *taprootTestContext) generateFundingVector() FundingScriptVector { + t := tc.t + + pkScript, _, err := input.GenTaprootFundingScript( + tc.localFundingPrivkey.PubKey(), + tc.remoteFundingPrivkey.PubKey(), + int64(tc.fundingAmount), + fn.None[chainhash.Hash](), + ) + require.NoError(t, err) + + // Build a minimal funding transaction with the P2TR output. + fundingTx := wire.NewMsgTx(2) + fundingTx.AddTxIn(&wire.TxIn{ + PreviousOutPoint: wire.OutPoint{ + Hash: chainhash.Hash{}, + Index: 0, + }, + }) + fundingTx.AddTxOut(&wire.TxOut{ + Value: int64(tc.fundingAmount), + PkScript: pkScript, + }) + + var txBuf bytes.Buffer + require.NoError(t, fundingTx.Serialize(&txBuf)) + + // Extract the combined key from the pkScript. For P2TR, the pkScript + // is OP_1 <32-byte-key>, so the key starts at byte 2. + combinedKeyBytes := pkScript[2:] + + return FundingScriptVector{ + FundingTxHex: hex.EncodeToString(txBuf.Bytes()), + CombinedKey: hex.EncodeToString(combinedKeyBytes), + PkScript: scriptHex(pkScript), + } +} + +// commitScriptTreeToEntry converts a CommitScriptTree into a ScriptVectorEntry. +func commitScriptTreeToEntry( + tree *input.CommitScriptTree) ScriptVectorEntry { + + scripts := make(map[string]string) + leafHashes := make(map[string]string) + + settleScript := tree.SettleLeaf.Script + scripts["settle"] = scriptHex(settleScript) + leafHashes["settle"] = leafHash(settleScript) + + if tree.RevocationLeaf.Script != nil { + revokeScript := tree.RevocationLeaf.Script + scripts["revocation"] = scriptHex(revokeScript) + leafHashes["revocation"] = leafHash(revokeScript) + } + + return ScriptVectorEntry{ + Scripts: scripts, + LeafHashes: leafHashes, + TapscriptRoot: scriptHex(tree.TapscriptRoot), + InternalKey: pubHex(tree.InternalKey), + OutputKey: pubHex(tree.TaprootKey), + PkScript: scriptHex(tree.PkScript()), + } +} + +// htlcScriptTreeToEntry converts an HtlcScriptTree into a ScriptVectorEntry. +func htlcScriptTreeToEntry(tree *input.HtlcScriptTree) ScriptVectorEntry { + scripts := make(map[string]string) + leafHashes := make(map[string]string) + + successScript := tree.SuccessTapLeaf.Script + scripts["success"] = scriptHex(successScript) + leafHashes["success"] = leafHash(successScript) + + timeoutScript := tree.TimeoutTapLeaf.Script + scripts["timeout"] = scriptHex(timeoutScript) + leafHashes["timeout"] = leafHash(timeoutScript) + + return ScriptVectorEntry{ + Scripts: scripts, + LeafHashes: leafHashes, + TapscriptRoot: scriptHex(tree.TapscriptRoot), + InternalKey: pubHex(tree.InternalKey), + OutputKey: pubHex(tree.TaprootKey), + PkScript: scriptHex(tree.PkScript()), + } +} + +// secondLevelScriptTreeToEntry converts a SecondLevelScriptTree into a +// ScriptVectorEntry. +func secondLevelScriptTreeToEntry( + tree *input.SecondLevelScriptTree) ScriptVectorEntry { + + scripts := make(map[string]string) + leafHashes := make(map[string]string) + + successScript := tree.SuccessTapLeaf.Script + scripts["success"] = scriptHex(successScript) + leafHashes["success"] = leafHash(successScript) + + return ScriptVectorEntry{ + Scripts: scripts, + LeafHashes: leafHashes, + TapscriptRoot: scriptHex(tree.TapscriptRoot), + InternalKey: pubHex(tree.InternalKey), + OutputKey: pubHex(tree.TaprootKey), + PkScript: scriptHex(tree.PkScript()), + } +} + +// anchorScriptTreeToEntry converts an AnchorScriptTree into a +// ScriptVectorEntry. +func anchorScriptTreeToEntry( + tree *input.AnchorScriptTree) ScriptVectorEntry { + + scripts := make(map[string]string) + leafHashes := make(map[string]string) + + sweepScript := tree.SweepLeaf.Script + scripts["sweep"] = scriptHex(sweepScript) + leafHashes["sweep"] = leafHash(sweepScript) + + return ScriptVectorEntry{ + Scripts: scripts, + LeafHashes: leafHashes, + TapscriptRoot: scriptHex(tree.TapscriptRoot), + InternalKey: pubHex(tree.InternalKey), + OutputKey: pubHex(tree.TaprootKey), + PkScript: scriptHex(tree.PkScript()), + } +} + +// generateScriptVectors generates all script-only test vectors. +func (tc *taprootTestContext) generateScriptVectors() ScriptVectors { + t := tc.t + commitPt := tc.commitPoint() + + // Derive per-commitment tweaked keys. + localDelayedPubkey := input.TweakPubKey( + tc.localDelayedPaymentBasepointSecret.PubKey(), commitPt, + ) + revocationPubkey := input.DeriveRevocationPubkey( + tc.remoteRevocationBasepointSecret.PubKey(), commitPt, + ) + localHtlcPubkey := input.TweakPubKey( + tc.localHtlcBasepointSecret.PubKey(), commitPt, + ) + remoteHtlcPubkey := input.TweakPubKey( + tc.remoteHtlcBasepointSecret.PubKey(), commitPt, + ) + remotePaymentPubkey := tc.remotePaymentBasepointSecret.PubKey() + + noAux := fn.None[txscript.TapLeaf]() + + // 1. to_local script tree. + toLocalTree, err := input.NewLocalCommitScriptTree( + uint32(tc.localCsvDelay), localDelayedPubkey, + revocationPubkey, noAux, input.WithProdScripts(), + ) + require.NoError(t, err) + + // 2. to_remote script tree. + toRemoteTree, err := input.NewRemoteCommitScriptTree( + remotePaymentPubkey, noAux, input.WithProdScripts(), + ) + require.NoError(t, err) + + // 3. Anchor script trees. + localAnchorTree, err := input.NewAnchorScriptTree( + localDelayedPubkey, + ) + require.NoError(t, err) + + remoteAnchorTree, err := input.NewAnchorScriptTree( + remotePaymentPubkey, + ) + require.NoError(t, err) + + // Use HTLC 0 for offered/accepted HTLC vectors. + preimage0, err := lntypes.MakePreimageFromStr( + "0000000000000000000000000000000000000000000000000000000000000000", + ) + require.NoError(t, err) + payHash0 := preimage0.Hash() + + // 4. Offered HTLC (local commit). + offeredLocalTree, err := input.SenderHTLCScriptTaproot( + localHtlcPubkey, remoteHtlcPubkey, revocationPubkey, + payHash0[:], lntypes.Local, noAux, + input.WithProdScripts(), + ) + require.NoError(t, err) + + // 5. Offered HTLC (remote commit). + offeredRemoteTree, err := input.SenderHTLCScriptTaproot( + localHtlcPubkey, remoteHtlcPubkey, revocationPubkey, + payHash0[:], lntypes.Remote, noAux, + input.WithProdScripts(), + ) + require.NoError(t, err) + + // 6. Accepted HTLC (local commit). + acceptedLocalTree, err := input.ReceiverHTLCScriptTaproot( + 500, localHtlcPubkey, remoteHtlcPubkey, revocationPubkey, + payHash0[:], lntypes.Local, noAux, + input.WithProdScripts(), + ) + require.NoError(t, err) + + // 7. Accepted HTLC (remote commit). + acceptedRemoteTree, err := input.ReceiverHTLCScriptTaproot( + 500, localHtlcPubkey, remoteHtlcPubkey, revocationPubkey, + payHash0[:], lntypes.Remote, noAux, + input.WithProdScripts(), + ) + require.NoError(t, err) + + // 8. Second-level HTLC success. + secondLevelSuccess, err := input.TaprootSecondLevelScriptTree( + revocationPubkey, localDelayedPubkey, + uint32(tc.localCsvDelay), noAux, + input.WithProdScripts(), + ) + require.NoError(t, err) + + // 9. Second-level HTLC timeout (same function, different keys in a + // real scenario, but for vectors we show the construction with the + // same delay key since second-level success and timeout share the + // same script tree structure). + secondLevelTimeout, err := input.TaprootSecondLevelScriptTree( + revocationPubkey, localDelayedPubkey, + uint32(tc.localCsvDelay), noAux, + input.WithProdScripts(), + ) + require.NoError(t, err) + + return ScriptVectors{ + Funding: tc.generateFundingVector(), + ToLocal: commitScriptTreeToEntry(toLocalTree), + ToRemote: commitScriptTreeToEntry(toRemoteTree), + LocalAnchor: anchorScriptTreeToEntry(localAnchorTree), + RemoteAnchor: anchorScriptTreeToEntry(remoteAnchorTree), + OfferedHtlcLocalCommit: htlcScriptTreeToEntry(offeredLocalTree), + OfferedHtlcRemoteCommit: htlcScriptTreeToEntry(offeredRemoteTree), + AcceptedHtlcLocalCommit: htlcScriptTreeToEntry(acceptedLocalTree), + AcceptedHtlcRemoteCommit: htlcScriptTreeToEntry(acceptedRemoteTree), + SecondLevelHtlcSuccess: secondLevelScriptTreeToEntry(secondLevelSuccess), + SecondLevelHtlcTimeout: secondLevelScriptTreeToEntry(secondLevelTimeout), + } +} + +// --------------------------------------------------------------------------- +// Transaction vector generation (Section B) +// --------------------------------------------------------------------------- + +// taprootChanType is the channel type used for taproot test vectors. +var taprootChanType = channeldb.SingleFunderTweaklessBit | + channeldb.AnchorOutputsBit | + channeldb.ZeroHtlcTxFeeBit | + channeldb.SimpleTaprootFeatureBit | + channeldb.TaprootFinalBit + +// createTaprootTestChannelsForVectors creates a pair of LightningChannel +// instances configured for taproot test vector generation. All keys are +// deterministic. +func createTaprootTestChannelsForVectors(tc *taprootTestContext, + feeRate btcutil.Amount, remoteBalance, + localBalance btcutil.Amount) (*LightningChannel, *LightningChannel) { + + t := tc.t + + // Build the funding transaction with a P2TR output. + pkScript, _, err := input.GenTaprootFundingScript( + tc.localFundingPrivkey.PubKey(), + tc.remoteFundingPrivkey.PubKey(), + int64(tc.fundingAmount), + fn.None[chainhash.Hash](), + ) + require.NoError(t, err) + + fundingTx := wire.NewMsgTx(2) + fundingTx.AddTxIn(&wire.TxIn{ + PreviousOutPoint: wire.OutPoint{ + Hash: chainhash.Hash{}, + Index: 0, + }, + }) + fundingTx.AddTxOut(&wire.TxOut{ + Value: int64(tc.fundingAmount), + PkScript: pkScript, + }) + btcFundingTx := btcutil.NewTx(fundingTx) + + prevOut := &wire.OutPoint{ + Hash: *btcFundingTx.Hash(), + Index: 0, + } + fundingTxIn := wire.NewTxIn(prevOut, nil, nil) + + chanType := taprootChanType + + // Channel configurations using all deterministic keys. + remoteCfg := channeldb.ChannelConfig{ + ChannelStateBounds: channeldb.ChannelStateBounds{ + MaxPendingAmount: lnwire.NewMSatFromSatoshis( + tc.fundingAmount, + ), + ChanReserve: 0, + MinHTLC: 0, + MaxAcceptedHtlcs: input.MaxHTLCNumber / 2, + }, + CommitmentParams: channeldb.CommitmentParams{ + DustLimit: tc.dustLimit, + CsvDelay: tc.localCsvDelay, + }, + MultiSigKey: keychain.KeyDescriptor{ + PubKey: tc.remoteFundingPrivkey.PubKey(), + }, + PaymentBasePoint: keychain.KeyDescriptor{ + PubKey: tc.remotePaymentBasepointSecret.PubKey(), + }, + HtlcBasePoint: keychain.KeyDescriptor{ + PubKey: tc.remoteHtlcBasepointSecret.PubKey(), + }, + DelayBasePoint: keychain.KeyDescriptor{ + PubKey: tc.remotePaymentBasepointSecret.PubKey(), + }, + RevocationBasePoint: keychain.KeyDescriptor{ + PubKey: tc.remoteRevocationBasepointSecret.PubKey(), + }, + } + localCfg := channeldb.ChannelConfig{ + ChannelStateBounds: channeldb.ChannelStateBounds{ + MaxPendingAmount: lnwire.NewMSatFromSatoshis( + tc.fundingAmount, + ), + ChanReserve: 0, + MinHTLC: 0, + MaxAcceptedHtlcs: input.MaxHTLCNumber / 2, + }, + CommitmentParams: channeldb.CommitmentParams{ + DustLimit: tc.dustLimit, + CsvDelay: tc.localCsvDelay, + }, + MultiSigKey: keychain.KeyDescriptor{ + PubKey: tc.localFundingPrivkey.PubKey(), + }, + PaymentBasePoint: keychain.KeyDescriptor{ + PubKey: tc.localPaymentBasepointSecret.PubKey(), + }, + HtlcBasePoint: keychain.KeyDescriptor{ + PubKey: tc.localHtlcBasepointSecret.PubKey(), + }, + DelayBasePoint: keychain.KeyDescriptor{ + PubKey: tc.localDelayedPaymentBasepointSecret.PubKey(), + }, + RevocationBasePoint: keychain.KeyDescriptor{ + PubKey: tc.localPaymentBasepointSecret.PubKey(), + }, + } + + // Create mock producers for deterministic revocation secrets. + remotePreimageProducer := &mockProducer{ + secret: chainhash.Hash(tc.localPerCommitSecret), + } + remoteCommitPoint := input.ComputeCommitmentPoint( + tc.localPerCommitSecret[:], + ) + + localPreimageProducer := &mockProducer{ + secret: chainhash.Hash(tc.localPerCommitSecret), + } + localCommitPoint := input.ComputeCommitmentPoint( + tc.localPerCommitSecret[:], + ) + + // Create temporary databases. + dbRemote := channeldb.OpenForTesting(t, t.TempDir()) + dbLocal := channeldb.OpenForTesting(t, t.TempDir()) + + // Create initial commitment transactions. + feePerKw := chainfee.SatPerKWeight(feeRate) + commitWeight := lntypes.WeightUnit(input.AnchorCommitWeight) + commitFee := feePerKw.FeeForWeight(commitWeight) + anchorAmt := btcutil.Amount(2 * AnchorSize) + + remoteCommitTx, localCommitTx, err := CreateCommitmentTxns( + remoteBalance, localBalance-commitFee, + &remoteCfg, &localCfg, remoteCommitPoint, + localCommitPoint, *fundingTxIn, chanType, true, 0, + ) + require.NoError(t, err) + + var commitHeight = tc.commitHeight - 1 + + remoteCommit := channeldb.ChannelCommitment{ + CommitHeight: commitHeight, + LocalBalance: lnwire.NewMSatFromSatoshis(remoteBalance), + RemoteBalance: lnwire.NewMSatFromSatoshis(localBalance - commitFee - anchorAmt), + CommitFee: commitFee, + FeePerKw: btcutil.Amount(feePerKw), + CommitTx: remoteCommitTx, + CommitSig: testSigBytes, + } + localCommit := channeldb.ChannelCommitment{ + CommitHeight: commitHeight, + LocalBalance: lnwire.NewMSatFromSatoshis(localBalance - commitFee - anchorAmt), + RemoteBalance: lnwire.NewMSatFromSatoshis(remoteBalance), + CommitFee: commitFee, + FeePerKw: btcutil.Amount(feePerKw), + CommitTx: localCommitTx, + CommitSig: testSigBytes, + } + + shortChanID := lnwire.NewShortChanIDFromInt(0xdeadbeef) + + remoteChannelState := &channeldb.OpenChannel{ + LocalChanCfg: remoteCfg, + RemoteChanCfg: localCfg, + IdentityPub: tc.remoteFundingPrivkey.PubKey(), + FundingOutpoint: *prevOut, + ShortChannelID: shortChanID, + ChanType: chanType, + IsInitiator: false, + Capacity: tc.fundingAmount, + RemoteCurrentRevocation: localCommitPoint, + RevocationProducer: remotePreimageProducer, + RevocationStore: shachain.NewRevocationStore(), + LocalCommitment: remoteCommit, + RemoteCommitment: remoteCommit, + Db: dbRemote.ChannelStateDB(), + Packager: channeldb.NewChannelPackager(shortChanID), + FundingTxn: fundingTx, + } + localChannelState := &channeldb.OpenChannel{ + LocalChanCfg: localCfg, + RemoteChanCfg: remoteCfg, + IdentityPub: tc.localFundingPrivkey.PubKey(), + FundingOutpoint: *prevOut, + ShortChannelID: shortChanID, + ChanType: chanType, + IsInitiator: true, + Capacity: tc.fundingAmount, + RemoteCurrentRevocation: remoteCommitPoint, + RevocationProducer: localPreimageProducer, + RevocationStore: shachain.NewRevocationStore(), + LocalCommitment: localCommit, + RemoteCommitment: localCommit, + Db: dbLocal.ChannelStateDB(), + Packager: channeldb.NewChannelPackager(shortChanID), + FundingTxn: fundingTx, + } + + // Create mock signers with all deterministic keys. The funding key must + // be at index 0 because the MusigSessionManager's key fetcher always + // returns Privkeys[0] as the MuSig2 signing key. + localSigner := input.NewMockSigner([]*btcec.PrivateKey{ + tc.localFundingPrivkey, + tc.localPaymentBasepointSecret, + tc.localDelayedPaymentBasepointSecret, + tc.localHtlcBasepointSecret, + }, nil) + + remoteSigner := input.NewMockSigner([]*btcec.PrivateKey{ + tc.remoteFundingPrivkey, + tc.remoteRevocationBasepointSecret, + tc.remotePaymentBasepointSecret, + tc.remoteHtlcBasepointSecret, + }, nil) + + // Derive deterministic signing rand for JIT nonces so MuSig2 + // signatures are reproducible across runs. + localRandHash := sha256.Sum256(append(tc.seed, []byte("local-signing-rand")...)) + remoteRandHash := sha256.Sum256(append(tc.seed, []byte("remote-signing-rand")...)) + + auxSigner := NewDefaultAuxSignerMock(t) + remotePool := NewSigPool(1, remoteSigner) + channelRemote, err := NewLightningChannel( + remoteSigner, remoteChannelState, remotePool, + WithLeafStore(&MockAuxLeafStore{}), + WithAuxSigner(auxSigner), + WithCustomSigningRand(bytes.NewReader(remoteRandHash[:])), + ) + require.NoError(t, err) + require.NoError(t, remotePool.Start()) + + localPool := NewSigPool(1, localSigner) + channelLocal, err := NewLightningChannel( + localSigner, localChannelState, localPool, + WithLeafStore(&MockAuxLeafStore{}), + WithAuxSigner(auxSigner), + WithCustomSigningRand(bytes.NewReader(localRandHash[:])), + ) + require.NoError(t, err) + require.NoError(t, localPool.Start()) + + // Create state hint obfuscator. + obfuscator := createStateHintObfuscator(remoteChannelState) + err = SetStateNumHint(remoteCommitTx, commitHeight, obfuscator) + require.NoError(t, err) + err = SetStateNumHint(localCommitTx, commitHeight, obfuscator) + require.NoError(t, err) + + // Initialize the databases. + addr := &net.TCPAddr{ + IP: net.ParseIP("127.0.0.1"), + Port: 18556, + } + require.NoError(t, channelRemote.channelState.SyncPending(addr, 101)) + + addr = &net.TCPAddr{ + IP: net.ParseIP("127.0.0.1"), + Port: 18555, + } + require.NoError(t, channelLocal.channelState.SyncPending(addr, 101)) + + // Initialize revocation windows and musig nonces. + err = initRevocationWindows(channelRemote, channelLocal) + require.NoError(t, err) + + t.Cleanup(func() { + dbLocal.Close() + dbRemote.Close() + + require.NoError(t, remotePool.Stop()) + require.NoError(t, localPool.Stop()) + }) + + return channelRemote, channelLocal +} + +// taprootTransactionTestCases defines the set of transaction test cases. +var taprootTransactionTestCases = []struct { + name string + localBalance lnwire.MilliSatoshi + remoteBalance lnwire.MilliSatoshi + feePerKw btcutil.Amount + dustLimit btcutil.Amount + useTestHtlcs bool +}{ + { + name: "simple commitment tx with no HTLCs", + localBalance: 7_000_000_000, + remoteBalance: 3_000_000_000, + feePerKw: 15_000, + useTestHtlcs: false, + }, + { + name: "commitment tx with five HTLCs untrimmed", + localBalance: 6_988_000_000, + remoteBalance: 3_000_000_000, + feePerKw: 644, + useTestHtlcs: true, + }, + { + name: "commitment tx with some HTLCs trimmed", + localBalance: 6_988_000_000, + remoteBalance: 3_000_000_000, + feePerKw: 100_000, + dustLimit: 546, + useTestHtlcs: true, + }, +} + +// generateTransactionVectors generates all transaction test vectors. +func (tc *taprootTestContext) generateTransactionVectors() []TransactionTestCase { + t := tc.t + var results []TransactionTestCase + + for _, testCase := range taprootTransactionTestCases { + // Override dust limit if specified in the test case. + origDust := tc.dustLimit + if testCase.dustLimit != 0 { + tc.dustLimit = testCase.dustLimit + } + + // Compute spendable balances by adding back in-flight HTLCs. + remoteBalance := testCase.remoteBalance + localBalance := testCase.localBalance + if testCase.useTestHtlcs { + for _, htlc := range testHtlcsSet1 { + if htlc.incoming { + remoteBalance += htlc.amount + } else { + localBalance += htlc.amount + } + } + } + + // Verify balances add up to channel capacity. + require.EqualValues(t, + lnwire.NewMSatFromSatoshis(tc.fundingAmount), + remoteBalance+localBalance, + ) + + remoteChannel, localChannel := createTaprootTestChannelsForVectors( + tc, testCase.feePerKw, + remoteBalance.ToSatoshis(), + localBalance.ToSatoshis(), + ) + + // Add HTLCs if needed. + var hash160map map[[20]byte]lntypes.Preimage + if testCase.useTestHtlcs { + hash160map = addTestHtlcs( + t, remoteChannel, localChannel, + testHtlcsSet1, + ) + } + + // Execute commit dance. + localNewCommit, err := localChannel.SignNextCommitment(ctxb) + require.NoError(t, err) + + err = remoteChannel.ReceiveNewCommitment( + localNewCommit.CommitSigs, + ) + require.NoError(t, err) + + revMsg, _, _, err := remoteChannel.RevokeCurrentCommitment() + require.NoError(t, err) + + _, _, err = localChannel.ReceiveRevocation(revMsg) + require.NoError(t, err) + + remoteNewCommit, err := remoteChannel.SignNextCommitment(ctxb) + require.NoError(t, err) + + // Capture remote partial signature. + remoteSigHex := hex.EncodeToString( + remoteNewCommit.CommitSig.ToSignatureBytes(), + ) + + err = localChannel.ReceiveNewCommitment( + remoteNewCommit.CommitSigs, + ) + require.NoError(t, err) + + _, _, _, err = localChannel.RevokeCurrentCommitment() + require.NoError(t, err) + + // Force close to get the commitment transaction. + forceCloseSum, err := localChannel.ForceClose() + require.NoError(t, err) + + var txBytes bytes.Buffer + require.NoError(t, forceCloseSum.CloseTx.Serialize(&txBytes)) + + // Collect HTLC resolution transactions. + var htlcDescs []HtlcDesc + if testCase.useTestHtlcs { + resolutions := forceCloseSum.ContractResolutions.UnwrapOrFail(t) + htlcResolutions := resolutions.HtlcResolutions + + secondLevelTxes := map[uint32]*wire.MsgTx{} + secondLevelSigs := map[uint32]string{} + storeTx := func( + index uint32, tx *wire.MsgTx, sig string, + ) { + secondLevelTxes[index] = tx + secondLevelSigs[index] = sig + } + + for i, r := range htlcResolutions.IncomingHTLCs { + successTx := r.SignedSuccessTx + // Complete the witness with the preimage. + witnessScript := successTx.TxIn[0].Witness[4] + var hash160 [20]byte + copy(hash160[:], witnessScript[69:69+20]) + preimage := hash160map[hash160] + successTx.TxIn[0].Witness[3] = preimage[:] + + sigHex := hex.EncodeToString( + remoteNewCommit.HtlcSigs[i].ToSignatureBytes(), + ) + storeTx( + r.HtlcPoint().Index, successTx, sigHex, + ) + } + for i, r := range htlcResolutions.OutgoingHTLCs { + sigIdx := len(htlcResolutions.IncomingHTLCs) + i + sigHex := hex.EncodeToString( + remoteNewCommit.HtlcSigs[sigIdx].ToSignatureBytes(), + ) + storeTx( + r.HtlcPoint().Index, + r.SignedTimeoutTx, sigHex, + ) + } + + var keys []uint32 + for k := range secondLevelTxes { + keys = append(keys, k) + } + sort.Slice(keys, func(a, b int) bool { + return keys[a] < keys[b] + }) + + for _, idx := range keys { + tx := secondLevelTxes[idx] + var b bytes.Buffer + err := tx.Serialize(&b) + require.NoError(t, err) + + htlcDescs = append(htlcDescs, HtlcDesc{ + RemotePartialSigHex: secondLevelSigs[idx], + ResolutionTxHex: hex.EncodeToString(b.Bytes()), + }) + } + } + + // Build the HTLC input list. + var htlcInputs []HtlcInput + if testCase.useTestHtlcs { + for _, h := range testHtlcsSet1 { + htlcInputs = append(htlcInputs, HtlcInput{ + Incoming: h.incoming, + AmountMsat: uint64(h.amount), + Expiry: h.expiry, + Preimage: h.preimage, + }) + } + } + + result := TransactionTestCase{ + Name: testCase.name, + LocalBalanceMsat: uint64(testCase.localBalance), + RemoteBalanceMsat: uint64(testCase.remoteBalance), + FeePerKw: int64(testCase.feePerKw), + Htlcs: htlcInputs, + RemotePartialSig: remoteSigHex, + ExpectedCommitmentTxHex: hex.EncodeToString(txBytes.Bytes()), + HtlcDescs: htlcDescs, + } + if testCase.dustLimit != 0 { + result.DustLimitSatoshis = int64(testCase.dustLimit) + } + + results = append(results, result) + + // Restore dust limit. + tc.dustLimit = origDust + } + + return results +} + +// --------------------------------------------------------------------------- +// Main test entry point +// --------------------------------------------------------------------------- + +// TestTaprootVectors either generates or verifies taproot test vectors +// depending on the -generate-taproot-vectors flag. +func TestTaprootVectors(t *testing.T) { + if *generateTaprootVectors { + t.Log("Generating taproot test vectors...") + generateAndWriteTaprootVectors(t) + return + } + + t.Log("Verifying taproot test vectors...") + verifyTaprootVectors(t) +} + +// generateAndWriteTaprootVectors generates all taproot test vectors and writes +// them to the JSON file. +func generateAndWriteTaprootVectors(t *testing.T) { + tc := newTaprootTestContext(t) + + vectors := TaprootTestVectors{ + Params: tc.generateParams(), + Scripts: tc.generateScriptVectors(), + Transactions: tc.generateTransactionVectors(), + } + + jsonData, err := json.MarshalIndent(vectors, "", " ") + require.NoError(t, err) + + err = os.WriteFile(taprootVectorFile, jsonData, 0644) + require.NoError(t, err) + + t.Logf("Wrote taproot test vectors to %s (%d bytes)", + taprootVectorFile, len(jsonData)) +} + +// verifyTaprootVectors reads the stored test vectors and verifies them by +// regenerating all values from the seed. +func verifyTaprootVectors(t *testing.T) { + jsonData, err := os.ReadFile(taprootVectorFile) + require.NoError(t, err, "test vectors file not found, run with "+ + "-generate-taproot-vectors first") + + var stored TaprootTestVectors + err = json.Unmarshal(jsonData, &stored) + require.NoError(t, err) + + tc := newTaprootTestContext(t) + + // Verify params. + t.Run("params", func(t *testing.T) { + params := tc.generateParams() + require.Equal(t, stored.Params, params) + }) + + // Verify script vectors. + t.Run("scripts", func(t *testing.T) { + scripts := tc.generateScriptVectors() + + t.Run("funding", func(t *testing.T) { + require.Equal(t, + stored.Scripts.Funding.CombinedKey, + scripts.Funding.CombinedKey, + ) + require.Equal(t, + stored.Scripts.Funding.PkScript, + scripts.Funding.PkScript, + ) + }) + + t.Run("to_local", func(t *testing.T) { + require.Equal(t, + stored.Scripts.ToLocal, scripts.ToLocal, + ) + }) + + t.Run("to_remote", func(t *testing.T) { + require.Equal(t, + stored.Scripts.ToRemote, scripts.ToRemote, + ) + }) + + t.Run("local_anchor", func(t *testing.T) { + require.Equal(t, + stored.Scripts.LocalAnchor, + scripts.LocalAnchor, + ) + }) + + t.Run("remote_anchor", func(t *testing.T) { + require.Equal(t, + stored.Scripts.RemoteAnchor, + scripts.RemoteAnchor, + ) + }) + + t.Run("offered_htlc_local_commit", func(t *testing.T) { + require.Equal(t, + stored.Scripts.OfferedHtlcLocalCommit, + scripts.OfferedHtlcLocalCommit, + ) + }) + + t.Run("offered_htlc_remote_commit", func(t *testing.T) { + require.Equal(t, + stored.Scripts.OfferedHtlcRemoteCommit, + scripts.OfferedHtlcRemoteCommit, + ) + }) + + t.Run("accepted_htlc_local_commit", func(t *testing.T) { + require.Equal(t, + stored.Scripts.AcceptedHtlcLocalCommit, + scripts.AcceptedHtlcLocalCommit, + ) + }) + + t.Run("accepted_htlc_remote_commit", func(t *testing.T) { + require.Equal(t, + stored.Scripts.AcceptedHtlcRemoteCommit, + scripts.AcceptedHtlcRemoteCommit, + ) + }) + + t.Run("second_level_htlc_success", func(t *testing.T) { + require.Equal(t, + stored.Scripts.SecondLevelHtlcSuccess, + scripts.SecondLevelHtlcSuccess, + ) + }) + + t.Run("second_level_htlc_timeout", func(t *testing.T) { + require.Equal(t, + stored.Scripts.SecondLevelHtlcTimeout, + scripts.SecondLevelHtlcTimeout, + ) + }) + }) + + // Verify transaction vectors. + t.Run("transactions", func(t *testing.T) { + txVectors := tc.generateTransactionVectors() + require.Equal(t, len(stored.Transactions), len(txVectors)) + + for i, storedTx := range stored.Transactions { + genTx := txVectors[i] + t.Run(storedTx.Name, func(t *testing.T) { + require.Equal(t, + storedTx.ExpectedCommitmentTxHex, + genTx.ExpectedCommitmentTxHex, + "commitment tx mismatch", + ) + require.Equal(t, + storedTx.RemotePartialSig, + genTx.RemotePartialSig, + "remote partial sig mismatch", + ) + require.Equal(t, + len(storedTx.HtlcDescs), + len(genTx.HtlcDescs), + "htlc desc count mismatch", + ) + for j, storedHtlc := range storedTx.HtlcDescs { + require.Equal(t, + storedHtlc.ResolutionTxHex, + genTx.HtlcDescs[j].ResolutionTxHex, + fmt.Sprintf( + "htlc %d resolution tx mismatch", j, + ), + ) + } + }) + } + }) +} + diff --git a/lnwallet/test_vectors_taproot.json b/lnwallet/test_vectors_taproot.json new file mode 100644 index 00000000000..6de7141396b --- /dev/null +++ b/lnwallet/test_vectors_taproot.json @@ -0,0 +1,309 @@ +{ + "params": { + "seed": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "funding_amount_satoshis": 10000000, + "dust_limit_satoshis": 354, + "csv_delay": 144, + "commit_height": 42, + "nums_point": "02dca094751109d0bd055d03565874e8276dd53e926b44e3bd1bb6bf4bc130a279", + "keys": { + "local_funding_privkey": "20ae2d254ab29afd3dcbf8744a5b88d06070f55a4bd5532483a093ac4db91277", + "local_funding_pubkey": "03b7203dec7c13896b6ff1f58b24f84458c441720a12b5a57426397e22f0a8c78b", + "remote_funding_privkey": "f0c5500a9dbd7cdcd46ced7bdeb937d4dcbf90f9b9357626e7ee54ab024c3df0", + "remote_funding_pubkey": "02956e6845a6f346f97c5e028c0f8ab38a76b0124fd7184deab60f682b3e657fdb", + "local_payment_basepoint_secret": "277975b5b081a9cbc4834e066d7bb494e4fde4f7637257dd3d312a0ae7cb7754", + "local_payment_basepoint": "03955b6085296cbd2447a1dde0f7e273e19b83e83de1814993b1517aaf193b7f33", + "remote_payment_basepoint_secret": "f1cd3a5ca44b52baf4eacb849fbf06e75aace97477b8bfe31d2b814dbbb562b1", + "remote_payment_basepoint": "03595f2ef2a51d2250a21077dbea4a7fc3ce550f10676996bf63719e2a71d1f4c9", + "local_delayed_payment_basepoint_secret": "83ccf0b638c514db5ebefdc6cbf901505e2bb20edb2bb7248ce1a51523325f9b", + "local_delayed_payment_basepoint": "02ae68d8ff4c59864c03a42bbff6c07f9ae18047e0daa9bc40d07c410f9a0f7899", + "remote_revocation_basepoint_secret": "36c4175b91cff9731a63d1472b5b1c4cf3e7b688e87d5fb806b2e8350484e68d", + "remote_revocation_basepoint": "02c354121ef71922b5cb32fa685c08ac0014b558f96e28f383c45eb28b7da264c3", + "local_htlc_basepoint_secret": "786eb5024e4851bea3ddc6e40036c81b1efcf50eeed440eedefe5245bde6fc14", + "local_htlc_basepoint": "033ce88bf3c8333e242996964ac91ee7cd945bfe4c49668ea10f3211f3d418fbc8", + "remote_htlc_basepoint_secret": "51c9b6cf8279def85e3925bc8f16fc0ff100ee7b03ce7c954149ca29c834b684", + "remote_htlc_basepoint": "02932dfbf6737001e3c516696ae3dcd323fd91a01ce7898f7f91ab98eebacc323e", + "local_per_commit_secret": "037b507180b3985cea6396d6a70987cea11ccd05fde49e943a3ea0fe56ee33ed", + "local_per_commit_point": "02a0f5a09017c1dec2d30dd54a25dc4037fc5a2aa3832ee3c7b58f3a88a0836287", + "derived_local_delayed_pubkey": "0315ec0138eb42f1ab4603042123988d53c854e89d1d87aa4dbb97a57482029c05", + "derived_revocation_pubkey": "03d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0", + "derived_local_htlc_pubkey": "0271e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739e", + "derived_remote_htlc_pubkey": "032deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47d", + "derived_remote_payment_pubkey": "03595f2ef2a51d2250a21077dbea4a7fc3ce550f10676996bf63719e2a71d1f4c9" + } + }, + "scripts": { + "funding": { + "funding_tx_hex": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000018096980000000000225120d0ebb4909d563a7ae1213fddede4ae54132fba0ef0b97ee3f8469191fecd348e00000000", + "combined_key": "d0ebb4909d563a7ae1213fddede4ae54132fba0ef0b97ee3f8469191fecd348e", + "pkscript": "5120d0ebb4909d563a7ae1213fddede4ae54132fba0ef0b97ee3f8469191fecd348e" + }, + "to_local": { + "scripts": { + "revocation": "2015ec0138eb42f1ab4603042123988d53c854e89d1d87aa4dbb97a57482029c057520d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0ac", + "settle": "2015ec0138eb42f1ab4603042123988d53c854e89d1d87aa4dbb97a57482029c05ad029000b2" + }, + "leaf_hashes": { + "revocation": "8fcd64d212bbbf1bcec2360bbf229963240d05992fc2efb482fe6dca85b9469a", + "settle": "dbf0400e9c7c57f30b6ad0b0677e396b5a002cbf050d873c8925b966048e6a62" + }, + "tapscript_root": "b8b76c2e893ca785072f0d7393e35d5bd72adf8b7ff2a53538aa664378a38a36", + "internal_key": "02dca094751109d0bd055d03565874e8276dd53e926b44e3bd1bb6bf4bc130a279", + "output_key": "023e1fcbbd06c8a7414704612c72be9834a75d86ed85b29f0ef0c52e1950afaff3", + "pkscript": "51203e1fcbbd06c8a7414704612c72be9834a75d86ed85b29f0ef0c52e1950afaff3" + }, + "to_remote": { + "scripts": { + "settle": "20595f2ef2a51d2250a21077dbea4a7fc3ce550f10676996bf63719e2a71d1f4c9ad51b2" + }, + "leaf_hashes": { + "settle": "63ce35b16eb8f8687293d5a88c1d8ada3236843b79ca315fe9dd7c47f30f2bc9" + }, + "tapscript_root": "63ce35b16eb8f8687293d5a88c1d8ada3236843b79ca315fe9dd7c47f30f2bc9", + "internal_key": "02dca094751109d0bd055d03565874e8276dd53e926b44e3bd1bb6bf4bc130a279", + "output_key": "023609bb705034e5629aa6ec05c5ca906ac89ac08b34c4583c259521ec30174408", + "pkscript": "51203609bb705034e5629aa6ec05c5ca906ac89ac08b34c4583c259521ec30174408" + }, + "local_anchor": { + "scripts": { + "sweep": "60b2" + }, + "leaf_hashes": { + "sweep": "2b88a8f3f52386d61d5b3f2d822df659c35214d7360ed05352ad7ddc1ab03912" + }, + "tapscript_root": "2b88a8f3f52386d61d5b3f2d822df659c35214d7360ed05352ad7ddc1ab03912", + "internal_key": "0315ec0138eb42f1ab4603042123988d53c854e89d1d87aa4dbb97a57482029c05", + "output_key": "02f67ab012701705f3203d132f909a6810ef18c5da4c11d986cb50818803b8344e", + "pkscript": "5120f67ab012701705f3203d132f909a6810ef18c5da4c11d986cb50818803b8344e" + }, + "remote_anchor": { + "scripts": { + "sweep": "60b2" + }, + "leaf_hashes": { + "sweep": "2b88a8f3f52386d61d5b3f2d822df659c35214d7360ed05352ad7ddc1ab03912" + }, + "tapscript_root": "2b88a8f3f52386d61d5b3f2d822df659c35214d7360ed05352ad7ddc1ab03912", + "internal_key": "03595f2ef2a51d2250a21077dbea4a7fc3ce550f10676996bf63719e2a71d1f4c9", + "output_key": "021249c50576fdf914caa14f9221370b986df520bdbc73f57d5056a86ee03e5ac4", + "pkscript": "51201249c50576fdf914caa14f9221370b986df520bdbc73f57d5056a86ee03e5ac4" + }, + "offered_htlc_local_commit": { + "scripts": { + "success": "82012088a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dad51b2", + "timeout": "2071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dac" + }, + "leaf_hashes": { + "success": "cd4b7ba74d132998f2bcea85f76082f5018e614c86f27f2631b6569c4914320f", + "timeout": "dd0bd08b3df902c399f5493a682f6c50c476c89e233ba454e89a234d2d16ffe3" + }, + "tapscript_root": "f36c8bd45002c5264cfce9944211e7bc6ea974a6b90cf99a87812d18acf28a2a", + "internal_key": "03d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0", + "output_key": "033e5c3be9f4ce7ae07c28ad5e0eb0ab617c06eeb82b8d6ef10a5bf561848df5f0", + "pkscript": "51203e5c3be9f4ce7ae07c28ad5e0eb0ab617c06eeb82b8d6ef10a5bf561848df5f0" + }, + "offered_htlc_remote_commit": { + "scripts": { + "success": "82012088a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dad51b2", + "timeout": "2071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dac" + }, + "leaf_hashes": { + "success": "cd4b7ba74d132998f2bcea85f76082f5018e614c86f27f2631b6569c4914320f", + "timeout": "dd0bd08b3df902c399f5493a682f6c50c476c89e233ba454e89a234d2d16ffe3" + }, + "tapscript_root": "f36c8bd45002c5264cfce9944211e7bc6ea974a6b90cf99a87812d18acf28a2a", + "internal_key": "03d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0", + "output_key": "033e5c3be9f4ce7ae07c28ad5e0eb0ab617c06eeb82b8d6ef10a5bf561848df5f0", + "pkscript": "51203e5c3be9f4ce7ae07c28ad5e0eb0ab617c06eeb82b8d6ef10a5bf561848df5f0" + }, + "accepted_htlc_local_commit": { + "scripts": { + "success": "82012088a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dad2071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739eac", + "timeout": "2071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead51b26902f401b1" + }, + "leaf_hashes": { + "success": "69192ca730d4480044ade8741b8bd0845a32880aebaf58bc6f9186f8d2be8cbf", + "timeout": "4da43c795365bf757ed1e9656d12ea744b4cf52b01719a3ea94e6569115623f0" + }, + "tapscript_root": "1a990caa4bb0ed41ceb19e7466fcea5d9b31e3da968f348f6223201c5831d0a3", + "internal_key": "03d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0", + "output_key": "029aadbdd9aff986e5ea086cf53ae062972d33d0a5c7f5fb986dafec7fa6d7e6ea", + "pkscript": "51209aadbdd9aff986e5ea086cf53ae062972d33d0a5c7f5fb986dafec7fa6d7e6ea" + }, + "accepted_htlc_remote_commit": { + "scripts": { + "success": "82012088a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dad2071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739eac", + "timeout": "2071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead51b26902f401b1" + }, + "leaf_hashes": { + "success": "69192ca730d4480044ade8741b8bd0845a32880aebaf58bc6f9186f8d2be8cbf", + "timeout": "4da43c795365bf757ed1e9656d12ea744b4cf52b01719a3ea94e6569115623f0" + }, + "tapscript_root": "1a990caa4bb0ed41ceb19e7466fcea5d9b31e3da968f348f6223201c5831d0a3", + "internal_key": "03d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0", + "output_key": "029aadbdd9aff986e5ea086cf53ae062972d33d0a5c7f5fb986dafec7fa6d7e6ea", + "pkscript": "51209aadbdd9aff986e5ea086cf53ae062972d33d0a5c7f5fb986dafec7fa6d7e6ea" + }, + "second_level_htlc_success": { + "scripts": { + "success": "2015ec0138eb42f1ab4603042123988d53c854e89d1d87aa4dbb97a57482029c05ad029000b2" + }, + "leaf_hashes": { + "success": "dbf0400e9c7c57f30b6ad0b0677e396b5a002cbf050d873c8925b966048e6a62" + }, + "tapscript_root": "dbf0400e9c7c57f30b6ad0b0677e396b5a002cbf050d873c8925b966048e6a62", + "internal_key": "03d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0", + "output_key": "02df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba0", + "pkscript": "5120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba0" + }, + "second_level_htlc_timeout": { + "scripts": { + "success": "2015ec0138eb42f1ab4603042123988d53c854e89d1d87aa4dbb97a57482029c05ad029000b2" + }, + "leaf_hashes": { + "success": "dbf0400e9c7c57f30b6ad0b0677e396b5a002cbf050d873c8925b966048e6a62" + }, + "tapscript_root": "dbf0400e9c7c57f30b6ad0b0677e396b5a002cbf050d873c8925b966048e6a62", + "internal_key": "03d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0", + "output_key": "02df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba0", + "pkscript": "5120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba0" + } + }, + "transactions": [ + { + "name": "simple commitment tx with no HTLCs", + "local_balance_msat": 7000000000, + "remote_balance_msat": 3000000000, + "fee_per_kw": 15000, + "htlcs": null, + "remote_partial_sig": "3006020100020100", + "expected_commitment_tx_hex": "020000000001015474cba49124ab0c4327c244bb2907059585c4af3fa5f3469701534120fec0170000000000c5fe1780044a010000000000002251201249c50576fdf914caa14f9221370b986df520bdbc73f57d5056a86ee03e5ac44a01000000000000225120f67ab012701705f3203d132f909a6810ef18c5da4c11d986cb50818803b8344ec0c62d00000000002251203609bb705034e5629aa6ec05c5ca906ac89ac08b34c4583c259521ec3017440874946a00000000002251203e1fcbbd06c8a7414704612c72be9834a75d86ed85b29f0ef0c52e1950afaff30140a4a9eb512a2f4094efdd2c566f1f20cc8a6e2c307a4a44cc3f9fea7fa147dd7038f1b048aa43fa0b4009175c1c37c37b96c01058541f9e1b61110fce4e831d9f55dc1920", + "htlc_descs": null + }, + { + "name": "commitment tx with five HTLCs untrimmed", + "local_balance_msat": 6988000000, + "remote_balance_msat": 3000000000, + "fee_per_kw": 644, + "htlcs": [ + { + "incoming": true, + "amount_msat": 1000000, + "expiry": 500, + "preimage": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "incoming": true, + "amount_msat": 2000000, + "expiry": 501, + "preimage": "0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "incoming": false, + "amount_msat": 2000000, + "expiry": 502, + "preimage": "0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "incoming": false, + "amount_msat": 3000000, + "expiry": 503, + "preimage": "0303030303030303030303030303030303030303030303030303030303030303" + }, + { + "incoming": true, + "amount_msat": 4000000, + "expiry": 504, + "preimage": "0404040404040404040404040404040404040404040404040404040404040404" + } + ], + "remote_partial_sig": "3006020100020100", + "expected_commitment_tx_hex": "020000000001015474cba49124ab0c4327c244bb2907059585c4af3fa5f3469701534120fec0170000000000c5fe1780094a010000000000002251201249c50576fdf914caa14f9221370b986df520bdbc73f57d5056a86ee03e5ac44a01000000000000225120f67ab012701705f3203d132f909a6810ef18c5da4c11d986cb50818803b8344ee8030000000000002251209ce82cd1b1f6f975049d58019a7145a3ec9680079969cf929d7d2c4bc9b30637d0070000000000002251208937f8afbc80cf4ba773f1adc3d63ea26259f80f5a3ba622211906d2e7e6e23dd007000000000000225120bf9ae94dda9b5b88485cc67a966ec946b237d19626916dee034b789ebd7fd5fcb80b0000000000002251208fe2e1306e414e896dfd879475b5c1a6a01d4e79b32c0544aa185ccb73c392aaa00f000000000000225120d93389ba5cdde8570d3ba73487ff7fc9f8c3816645009e42110fe5239f5a3e62c0c62d00000000002251203609bb705034e5629aa6ec05c5ca906ac89ac08b34c4583c259521ec30174408b3996a00000000002251203e1fcbbd06c8a7414704612c72be9834a75d86ed85b29f0ef0c52e1950afaff301409dfe3b178022d975e4b86bd1f04bccfc7576363dbaf58f2ac682136ad89cbeb1a1d07eca1e0bc547b5c5c1133214565e5dfdc230bc7d4736aa7e1be3fb8269d355dc1920", + "htlc_descs": [ + { + "remote_partial_sig_hex": "ba244e80d7043172804bd1b8c8fc26328b4ca0379611892c9d311ac97802af6849541cac18f51071d9aa57dceb7bdfa72544cbab6527e7a47bf1e9507dc51683", + "resolution_tx_hex": "02000000000101ec4c0a34c981864f9badcb8383bbe42ec6b32e68c2aa1a7c7c2e8422adde673f02000000000100000001e803000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba00541ba244e80d7043172804bd1b8c8fc26328b4ca0379611892c9d311ac97802af6849541cac18f51071d9aa57dceb7bdfa72544cbab6527e7a47bf1e9507dc516838340f75d8a3d94db2d5aaefc4949b3c10fe2163ebd953b636b6488cc2fe9a988bd6b966fc0904557044510b6650bc624bdfa0298e3bb18c4f403996e0a46bdf37b720020000000000000000000000000000000000000000000000000000000000000000041c0d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0e5e8fd071b9ade6367122afbd8acacc1a6727ddb6d478612af30827590027e0300000000" + }, + { + "remote_partial_sig_hex": "790f2e9c117c83c3a0c207dfa9cbfe8a955717854e96e966f428dbce816a408c3434839e522031064f0cb3ebb15c8c030d20dc5859a0c99a78a5f795d32b693f", + "resolution_tx_hex": "02000000000101ec4c0a34c981864f9badcb8383bbe42ec6b32e68c2aa1a7c7c2e8422adde673f03000000000100000001d007000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba00541790f2e9c117c83c3a0c207dfa9cbfe8a955717854e96e966f428dbce816a408c3434839e522031064f0cb3ebb15c8c030d20dc5859a0c99a78a5f795d32b693f8340f417b7b78b52f00a2c76586c3555b66cc87207fdf2995db255d232d9bfdad33bc1e8ee80898c4c2e6c9856158999abe762bfd6d17933dec9b6d522dc3b9fec3b0020000000000000000000000000000000000000000000000000000000000000000041c0d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0127d1790461eff920f14ba7cff2093c44b8a83e6f0a959fa60e04cf8c435cf4b00000000" + }, + { + "remote_partial_sig_hex": "aa6d10a611d9d34fb22e02aa9d1cce2b85cd10f16651fa67e415a787e0a9d2f14eb5845c4e1990af4dac7d4d865d3da7afd049cbded334f46f174e8474a16e12", + "resolution_tx_hex": "02000000000101ec4c0a34c981864f9badcb8383bbe42ec6b32e68c2aa1a7c7c2e8422adde673f04000000000100000001d007000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba004410967aa040669318987029fba55410f9a43c4dd57da9e3a60e74b83a35abea76e813fbbdaa8baae38e096a6b7718d75838cb33e264814678823f55ee6fb9cdd0f8340c52f017d42f140311c33a8bb94329f77f40245880b6ecc736735056c581fc7ceaad686deb2fe4359f257defa175fc4ce07558825500c1ef8d25ead5ac495d5b0442071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dac41c1d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a040b30263c4d7cd1fa6544e8bc8cd9efe857d7b5fd691c958936c3a2e0df2232ef6010000" + }, + { + "remote_partial_sig_hex": "81dd0918b0e01f4c1f701a5689f3c5c076bf71d4f365f21b67707527c9e71fe40e0c6fee2f3e46ee297d542e883f5ba5004b53b04cda060b6f99d3a8b2c3f488", + "resolution_tx_hex": "02000000000101ec4c0a34c981864f9badcb8383bbe42ec6b32e68c2aa1a7c7c2e8422adde673f05000000000100000001b80b000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba00441aa6d10a611d9d34fb22e02aa9d1cce2b85cd10f16651fa67e415a787e0a9d2f14eb5845c4e1990af4dac7d4d865d3da7afd049cbded334f46f174e8474a16e1283403c03b026ef105fe37ec3710fe2b81844531cfb080ad3b7290c7045c6ffa29e3d60a680ce9f539e4b89b37e5818545efbf2a94cb0c1b893c4a4a6b65703b137b9442071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dac41c0d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a064c44563d1bd58fa25c5c3ca7303c75849b6b3d91bf2e28f27068db4319b4c2ff7010000" + }, + { + "remote_partial_sig_hex": "0967aa040669318987029fba55410f9a43c4dd57da9e3a60e74b83a35abea76e813fbbdaa8baae38e096a6b7718d75838cb33e264814678823f55ee6fb9cdd0f", + "resolution_tx_hex": "02000000000101ec4c0a34c981864f9badcb8383bbe42ec6b32e68c2aa1a7c7c2e8422adde673f06000000000100000001a00f000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba0054181dd0918b0e01f4c1f701a5689f3c5c076bf71d4f365f21b67707527c9e71fe40e0c6fee2f3e46ee297d542e883f5ba5004b53b04cda060b6f99d3a8b2c3f48883409c3edb75f915ab9573cd44d9500e630fb6c2388c21733be54bce3824e66df526bf73df2206ccb8fbd125a4f0025e5bae8ecd7ea586d62ff341cead78c0e2528b0020000000000000000000000000000000000000000000000000000000000000000041c1d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a06c3390c812b2596986592f02c7f22e4f857fb553805ff9ac1c2bda361c47c3fb00000000" + } + ] + }, + { + "name": "commitment tx with some HTLCs trimmed", + "local_balance_msat": 6988000000, + "remote_balance_msat": 3000000000, + "fee_per_kw": 100000, + "dust_limit_satoshis": 546, + "htlcs": [ + { + "incoming": true, + "amount_msat": 1000000, + "expiry": 500, + "preimage": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "incoming": true, + "amount_msat": 2000000, + "expiry": 501, + "preimage": "0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "incoming": false, + "amount_msat": 2000000, + "expiry": 502, + "preimage": "0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "incoming": false, + "amount_msat": 3000000, + "expiry": 503, + "preimage": "0303030303030303030303030303030303030303030303030303030303030303" + }, + { + "incoming": true, + "amount_msat": 4000000, + "expiry": 504, + "preimage": "0404040404040404040404040404040404040404040404040404040404040404" + } + ], + "remote_partial_sig": "3006020100020100", + "expected_commitment_tx_hex": "020000000001015474cba49124ab0c4327c244bb2907059585c4af3fa5f3469701534120fec0170000000000c5fe1780094a010000000000002251201249c50576fdf914caa14f9221370b986df520bdbc73f57d5056a86ee03e5ac44a01000000000000225120f67ab012701705f3203d132f909a6810ef18c5da4c11d986cb50818803b8344ee8030000000000002251209ce82cd1b1f6f975049d58019a7145a3ec9680079969cf929d7d2c4bc9b30637d0070000000000002251208937f8afbc80cf4ba773f1adc3d63ea26259f80f5a3ba622211906d2e7e6e23dd007000000000000225120bf9ae94dda9b5b88485cc67a966ec946b237d19626916dee034b789ebd7fd5fcb80b0000000000002251208fe2e1306e414e896dfd879475b5c1a6a01d4e79b32c0544aa185ccb73c392aaa00f000000000000225120d93389ba5cdde8570d3ba73487ff7fc9f8c3816645009e42110fe5239f5a3e62c0c62d00000000002251203609bb705034e5629aa6ec05c5ca906ac89ac08b34c4583c259521ec301744083cd46700000000002251203e1fcbbd06c8a7414704612c72be9834a75d86ed85b29f0ef0c52e1950afaff30140c06828b729b180dc98cefecaa42f05215016a0b5a3232ce86773b5fc08bedc1112ff1ceddb9fa7dd0740f1641d80114630017badc95f32480a15e435ed569d6555dc1920", + "htlc_descs": [ + { + "remote_partial_sig_hex": "f96a7376f50c3a2ee763bbeec232798458c50a8a6fab0333275c169f113d6ae8a5b37b61a9fc2eecbd0a0493418a1a8dd48fd5d161a410a57970f72a97fcee6f", + "resolution_tx_hex": "0200000000010171d9133e6692c6a995317b4d388f613d84c99195362ad8742e8f0c3bc7dda51502000000000100000001e803000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba00541f96a7376f50c3a2ee763bbeec232798458c50a8a6fab0333275c169f113d6ae8a5b37b61a9fc2eecbd0a0493418a1a8dd48fd5d161a410a57970f72a97fcee6f834036b2363b0f0f478a564a88052a9a7df89d00d18a449bb9f17c527a4049f6abd4f7e851b7294360613a01d1480726617cf754b3f26a28d45c44ea1abe7b317aa20020000000000000000000000000000000000000000000000000000000000000000041c0d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0e5e8fd071b9ade6367122afbd8acacc1a6727ddb6d478612af30827590027e0300000000" + }, + { + "remote_partial_sig_hex": "1e82f5cfb5d2a87418d1ca3cc3abf9f18198692aba1a31ced763a8a9ed0ecd4252fd2996b89089aa69958cf2f41dda83d04d8d5644443de32b6e614105e833fc", + "resolution_tx_hex": "0200000000010171d9133e6692c6a995317b4d388f613d84c99195362ad8742e8f0c3bc7dda51503000000000100000001d007000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba005411e82f5cfb5d2a87418d1ca3cc3abf9f18198692aba1a31ced763a8a9ed0ecd4252fd2996b89089aa69958cf2f41dda83d04d8d5644443de32b6e614105e833fc83402ff61ab8f640fe9f9ef159b0e2a9fc17d0b4d15da59eed6b44fdff55e80d3b3d45aea7362cae2dfb2ae1c92a7d87790fce1e8cc157edadb9882823bfe299bca90020000000000000000000000000000000000000000000000000000000000000000041c0d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a0127d1790461eff920f14ba7cff2093c44b8a83e6f0a959fa60e04cf8c435cf4b00000000" + }, + { + "remote_partial_sig_hex": "d1fc7f73da9f09780568db36b9d1d5b0555be656ac2913beeffc1a48105a9e7aefe36d83cfeba66df106f65e81a5d5bae078d3f103da7e855b9f244d3a9df538", + "resolution_tx_hex": "0200000000010171d9133e6692c6a995317b4d388f613d84c99195362ad8742e8f0c3bc7dda51504000000000100000001d007000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba004417fe6ed9d80a0d3e7c315ac36c6ec234f510515bd2b1812b54da0e93a75a5ce4fce67839dfebca8746d94d343e2610bc92c22c9f4bcf637de461dd6fa0acb768f83407635f668f41362106a98c94ff0cdf66f9a8a57a141240096a1d5bb5a8531e91381a24b48c2c86010cb68891a17aca616e6e476dab53890ef63374e2cfa0929d9442071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dac41c1d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a040b30263c4d7cd1fa6544e8bc8cd9efe857d7b5fd691c958936c3a2e0df2232ef6010000" + }, + { + "remote_partial_sig_hex": "754bcd14983ecb5a864ce03f1f1a6f986e7d23bd0fa92505929a5595cf56199a3a520cd56bd15f6b28f78f148e3eff5df7a3336a9f05396b5f4a67ac3e2ed747", + "resolution_tx_hex": "0200000000010171d9133e6692c6a995317b4d388f613d84c99195362ad8742e8f0c3bc7dda51505000000000100000001b80b000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba00441d1fc7f73da9f09780568db36b9d1d5b0555be656ac2913beeffc1a48105a9e7aefe36d83cfeba66df106f65e81a5d5bae078d3f103da7e855b9f244d3a9df53883407f6bd7945f87d3a6a6f3700d756757e2cd03a897d8e01145fa2217d2741f3422776ef1f8b337e9f3f78a29060bedea63a29e574764a49a25acef1d8fe0b50370442071e82ef65d5c667159036bfcf662cac2f6c41e38323d148bbbd00fdcd923739ead202deba21cf03c42362c9f912094f62ba045a040a2060882ba1ed3abf1f664a47dac41c0d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a064c44563d1bd58fa25c5c3ca7303c75849b6b3d91bf2e28f27068db4319b4c2ff7010000" + }, + { + "remote_partial_sig_hex": "7fe6ed9d80a0d3e7c315ac36c6ec234f510515bd2b1812b54da0e93a75a5ce4fce67839dfebca8746d94d343e2610bc92c22c9f4bcf637de461dd6fa0acb768f", + "resolution_tx_hex": "0200000000010171d9133e6692c6a995317b4d388f613d84c99195362ad8742e8f0c3bc7dda51506000000000100000001a00f000000000000225120df20bcec43daa75161f7d013254e401812e0fee8bc3369220b6a33672fc18ba00541754bcd14983ecb5a864ce03f1f1a6f986e7d23bd0fa92505929a5595cf56199a3a520cd56bd15f6b28f78f148e3eff5df7a3336a9f05396b5f4a67ac3e2ed747834016f15c4e15363903022afa572110909661a5b6da439507d49980585a7a2c4a23c91cae4a9c20ebc5a4051d47ed7e9a5c087f31f981652b5bc4e4018bb58e1f9f0020000000000000000000000000000000000000000000000000000000000000000041c1d4c77088d346bce67c13bbbf82ca112588f4b1c9595a1f8af3be9b2f95a109a06c3390c812b2596986592f02c7f22e4f857fb553805ff9ac1c2bda361c47c3fb00000000" + } + ] + } + ] +} \ No newline at end of file diff --git a/lnwire/musig2.go b/lnwire/musig2.go index cfc753f820b..c29d80ee0ea 100644 --- a/lnwire/musig2.go +++ b/lnwire/musig2.go @@ -67,3 +67,37 @@ func SomeMusig2Nonce(nonce Musig2Nonce) OptMusig2NonceTLV { tlv.NewRecordT[NonceRecordTypeT, Musig2Nonce](nonce), ) } + +// TaprootNonceType indicates which nonce format to use for taproot channel +// messages like revoke_and_ack and channel_reestablish. +type TaprootNonceType uint8 + +const ( + // TaprootNonceTypeLegacy indicates that only the single LocalNonce + // field should be populated. This is used for peers that support the + // staging taproot channel feature bits (180/181). + TaprootNonceTypeLegacy TaprootNonceType = iota + + // TaprootNonceTypeMap indicates that only the LocalNonces map-based + // field should be populated. This is used for peers that support the + // final taproot channel feature bits (80/81). + TaprootNonceTypeMap +) + +// DetermineTaprootNonceType returns the appropriate nonce type based on the +// peer's advertised feature bits. If the peer supports the final taproot +// channel feature bits (80/81), we use the map-based LocalNonces field. +// Otherwise, we fall back to the legacy single LocalNonce field. +func DetermineTaprootNonceType(features *FeatureVector) TaprootNonceType { + if features == nil { + return TaprootNonceTypeLegacy + } + + if features.HasFeature(SimpleTaprootChannelsOptionalFinal) || + features.HasFeature(SimpleTaprootChannelsRequiredFinal) { + + return TaprootNonceTypeMap + } + + return TaprootNonceTypeLegacy +} diff --git a/lnwire/revoke_and_ack.go b/lnwire/revoke_and_ack.go index 3c9775c99ed..676ac01abb6 100644 --- a/lnwire/revoke_and_ack.go +++ b/lnwire/revoke_and_ack.go @@ -38,6 +38,10 @@ type RevokeAndAck struct { // remote nonce and the sender's local nonce. LocalNonce OptMusig2NonceTLV + // LocalNonces is an optional field that stores a map of local musig2 + // nonces, keyed by TXID. This is used for splice nonce coordination. + LocalNonces OptLocalNonces + // 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. @@ -78,8 +82,14 @@ func (c *RevokeAndAck) Decode(r io.Reader, pver uint32) error { return err } - localNonce := c.LocalNonce.Zero() - typeMap, err := tlvRecords.ExtractRecords(&localNonce) + var ( + localNonce = c.LocalNonce.Zero() + localNoncesData LocalNoncesData + ) + + typeMap, err := tlvRecords.ExtractRecords( + &localNonce, &localNoncesData, + ) if err != nil { return err } @@ -88,6 +98,9 @@ func (c *RevokeAndAck) Decode(r io.Reader, pver uint32) error { if val, ok := typeMap[c.LocalNonce.TlvType()]; ok && val == nil { c.LocalNonce = tlv.SomeRecordT(localNonce) } + if val, ok := typeMap[(LocalNoncesRecordTypeDef)(nil).TypeVal()]; ok && val == nil { + c.LocalNonces = SomeLocalNonces(localNoncesData) + } if len(tlvRecords) != 0 { c.ExtraData = tlvRecords @@ -101,10 +114,13 @@ func (c *RevokeAndAck) Decode(r io.Reader, pver uint32) error { // // This is part of the lnwire.Message interface. func (c *RevokeAndAck) Encode(w *bytes.Buffer, pver uint32) error { - recordProducers := make([]tlv.RecordProducer, 0, 1) + recordProducers := make([]tlv.RecordProducer, 0, 2) c.LocalNonce.WhenSome(func(localNonce Musig2NonceTLV) { recordProducers = append(recordProducers, &localNonce) }) + c.LocalNonces.WhenSome(func(ln LocalNoncesData) { + recordProducers = append(recordProducers, &ln) + }) err := EncodeMessageExtraData(&c.ExtraData, recordProducers...) if err != nil { return err diff --git a/lnwire/test_message.go b/lnwire/test_message.go index 213918836f1..fc959b5268a 100644 --- a/lnwire/test_message.go +++ b/lnwire/test_message.go @@ -1463,6 +1463,27 @@ func (c *RevokeAndAck) RandTestMessage(t *rapid.T) Message { ) } + if rapid.Bool().Draw(t, "includeLocalNonces") { + numNonces := rapid.IntRange(0, 3).Draw(t, "numLocalNonces") + nonces := make(map[chainhash.Hash]Musig2Nonce) + for i := 0; i < numNonces; i++ { + txid := RandChainHash(t) + + // Ensure unique txids for the map. + for { + _, ok := nonces[txid] + if !ok { + break + } + txid = RandChainHash(t) + } + + nonces[txid] = RandMusig2Nonce(t) + } + + msg.LocalNonces = SomeLocalNonces(LocalNoncesData{NoncesMap: nonces}) + } + return msg } diff --git a/peer/brontide.go b/peer/brontide.go index 5d00e14ab9e..5f404d8454e 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -1107,6 +1107,12 @@ func (p *Brontide) loadActiveChannels(chans []*channeldb.OpenChannel) ( }, ) + // Pass remote peer's feature bits so the channel uses the + // correct nonce format (type 4 for staging, type 22 for final). + chanOpts = append( + chanOpts, lnwallet.WithPeerFeatures(p.remoteFeatures), + ) + lnChan, err := lnwallet.NewLightningChannel( p.cfg.Signer, dbChan, p.cfg.SigPool, chanOpts..., ) @@ -5155,6 +5161,10 @@ func (p *Brontide) addActiveChannel(c *lnpeer.NewChannel) error { chanOpts = append(chanOpts, lnwallet.WithAuxResolver(s)) }) + // Pass remote peer's feature bits so the channel uses the correct + // nonce format (type 4 for staging, type 22 for final). + chanOpts = append(chanOpts, lnwallet.WithPeerFeatures(p.remoteFeatures)) + // If not already active, we'll add this channel to the set of active // channels, so we can look it up later easily according to its channel // ID. diff --git a/peer/musig_chan_closer.go b/peer/musig_chan_closer.go index 149ebcfa0cc..e69f58536b2 100644 --- a/peer/musig_chan_closer.go +++ b/peer/musig_chan_closer.go @@ -2,6 +2,7 @@ package peer import ( "fmt" + "io" "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" "github.com/lightningnetwork/lnd/fn/v2" @@ -53,6 +54,7 @@ func (m *MusigChanCloser) ProposalClosingOpts() ( *m.remoteNonce, localKey, remoteKey, m.channel.Signer, m.channel.FundingTxOut(), lnwallet.RemoteMusigCommit, tapscriptTweak, + fn.None[io.Reader](), ) err := m.musigSession.FinalizeSession(*m.localNonce) diff --git a/rpcserver.go b/rpcserver.go index 124f7e9dd75..0e9e49c5830 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -2322,6 +2322,29 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest, *channelType = lnwire.ChannelType(*fv) + case lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL: + // If the final taproot channel type is being set, then the channel + // MUST be private (unadvertised) for now. + if !in.Private { + return nil, fmt.Errorf("taproot channels must be " + + "private") + } + + channelType = new(lnwire.ChannelType) + fv := lnwire.NewRawFeatureVector( + lnwire.SimpleTaprootChannelsRequiredFinal, + ) + + if in.ZeroConf { + fv.Set(lnwire.ZeroConfRequired) + } + + if in.ScidAlias { + fv.Set(lnwire.ScidAliasRequired) + } + + *channelType = lnwire.ChannelType(*fv) + case lnrpc.CommitmentType_SIMPLE_TAPROOT_OVERLAY: // If the taproot overlay channel type is being set, then the // channel MUST be private. @@ -4690,6 +4713,9 @@ func rpcCommitmentType(chanType channeldb.ChannelType) lnrpc.CommitmentType { case chanType.HasTapscriptRoot(): return lnrpc.CommitmentType_SIMPLE_TAPROOT_OVERLAY + case chanType.IsTaproot() && chanType.IsTaprootFinal(): + return lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + case chanType.IsTaproot(): return lnrpc.CommitmentType_SIMPLE_TAPROOT diff --git a/watchtower/blob/justice_kit.go b/watchtower/blob/justice_kit.go index 9dc1af6258b..61dcbe31720 100644 --- a/watchtower/blob/justice_kit.go +++ b/watchtower/blob/justice_kit.go @@ -310,9 +310,17 @@ func newTaprootJusticeKit(sweepScript []byte, // TODO(roasbeef): aux leaf tower updates needed + // TODO: Add channel type info to BreachRetribution to determine + // whether to use production scripts for final taproot channels. + // For now, we default to staging scripts. + var scriptOpts []input.TaprootScriptOpt + // if chanType.IsTaprootFinal() { + // scriptOpts = append(scriptOpts, input.WithProdScripts()) + // } + tree, err := input.NewLocalCommitScriptTree( breachInfo.RemoteDelay, keyRing.ToLocalKey, - keyRing.RevocationKey, fn.None[txscript.TapLeaf](), + keyRing.RevocationKey, fn.None[txscript.TapLeaf](), scriptOpts..., ) if err != nil { return nil, err @@ -352,8 +360,15 @@ func (t *taprootJusticeKit) ToLocalOutputSpendInfo() (*txscript.PkScript, return nil, nil, err } + // TODO: Add channel type info to determine whether to use production + // scripts for final taproot channels. For now, we default to staging scripts. + var scriptOpts []input.TaprootScriptOpt + // if chanType.IsTaprootFinal() { + // scriptOpts = append(scriptOpts, input.WithProdScripts()) + // } + revokeScript, err := input.TaprootLocalCommitRevokeScript( - localDelayedPubKey, revocationPubKey, + localDelayedPubKey, revocationPubKey, scriptOpts..., ) if err != nil { return nil, nil, err @@ -419,8 +434,15 @@ func (t *taprootJusticeKit) ToRemoteOutputSpendInfo() (*txscript.PkScript, return nil, nil, 0, err } + // TODO: Add channel type info to determine whether to use production + // scripts for final taproot channels. For now, we default to staging scripts. + var scriptOpts []input.TaprootScriptOpt + // if chanType.IsTaprootFinal() { + // scriptOpts = append(scriptOpts, input.WithProdScripts()) + // } + scriptTree, err := input.NewRemoteCommitScriptTree( - toRemotePk, fn.None[txscript.TapLeaf](), + toRemotePk, fn.None[txscript.TapLeaf](), scriptOpts..., ) if err != nil { return nil, nil, 0, err