Repository: lightningnetwork/lnd
Pull request #8485 (2024-02-17 23:28:27)

[3/3]: Blinded Route Error Handling
This PR is the third and final in the route blinding forwarding series, including:
* Conversion of errors in a blinded route to `INVALID_ONION_BLINDING`
* Itest coverage for error handling. 
* Advertizing of optional blinding feature bit.

Depends on #8160

Update: Writing up a summary of my understanding of error handling in LND / how this relates to route blinding because I got this conceptually wrong on my first attempt. 

## Description 

TL;DR for route blinding errors:
* Introduction node should always return an `UpdateFailHTLC` with `invalid_onion_blinding`
* Relaying node should always return an `UpdateFailMalformedHTLC` with `invalid_onion_blinding`

In LND, there are a few places where a HTLC can fail: 
1. Incoming Add: `processRemoteAdds` fails to add the incoming HLTC -> `sendHTLCError`
3. Switch: `handlePacketForward` fails to transmit the incoming HTLC to the outgoing link -> `failAddPacket`
4. Outgoing Add: `handleDownstreamUpdateAddHtlc` fails to add the outgoing HTLC -> `FailAdd`
5. Downstream Failure: `handleUpstreamMsg` receives a failure from peer, propagated to incoming link -> `FailHTLC`

Following review from @bitromortac, approach has been updated to handle all of these errors on the *incoming link* so that we don't have to scatter handling all over the codebase (see below for previous approach). 

Something that's key for this PR is that we need to know when we're in a blinded route when we're handling the error on the incoming link so that we send back the correct message. We could do this with a bool propagated through the switch, but there are some pesky [edge cases](https://github.com/carlaKC/lnd/commit/d2ff1d621b10342e74f4470db4bd474c361309c5) around restarts/ on-chain resolutions where we don't have this information on hand (started with this approach - full branch [here](https://github.com/carlaKC/lnd/tree/7298-3-propagatebool)).

This PR takes the approach of using the existing `ErrorEncrypterType` to store a "marker" struct (which just wraps our existing implementation) so that we have the information available to us when we're resolving the HTLC across restarts. We're already storing the type for mock vs real encryptor, so this persistence costs us nothing extra. This trick is very helpful because we can just restore the circuit on the packet on re-forwrad through the switch and we'll have full information about the type of forward this was available. 

<details>
  <summary>Previous Approach</summary>
There are a few subtleties about this error handling that are important: 
* There are *a lot* of different paths that errors can take, so we have to account for the switch required in route blinding in a few places
* With the exception of (1) where we've just handled the onion, we only handle error encryption (when we're the source of the error) _in the switch_, so we can't just handle errors on the incoming link because we don't have our encrypted available (and surfacing it is a bad layering violation)
* Malformed errors are handled on the outgoing link, and converted into regular failures


With all this in mind, the following approach is taken: 
* For (1/2), simply switch out the error on the spot since we have what we need (and it's a unique path)
* For (3/4) convert *all* blinded errors to `UpdateFailHTLC` on the outgoing link, errors will be appropriately encrypted in the switch as required
* When the error reaches the original incoming link, switch it out for a `UpdateMalformedHTLC` if we are a relaying node, leave as-is otherwise (which will appropriately transmit both introduction node errors and regular unblinded errors)

This does lead to an admittedly odd flow for relaying nodes that get an error from their peer: receive malformed -> convert to failure -> convert back to malformed, _but_ we don't transmit malformed errors across the switch (and I don't think that we should). And while we're sending this message to the peer, we handle everything else exactly like a failure so I think it's worth leaving flow as as .
</details>

coderabbitai[bot]: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: skip review by coderabbit.ai -->

> [!IMPORTANT]
> ## Auto Review Skipped
> 
> Draft detected.
> 
> Please check the settings in the CodeRabbit UI or the `.coderabbit.yaml` file in this repository.
> 
> To trigger a single review, invoke the `@coderabbitai review` command.
> 

<!-- end of auto-generated comment: skip review by coderabbit.ai --><!-- tweet_start -->

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

<details>
<summary>Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<!-- tweet_end --><!-- tips_start -->

---

<details>
<summary>Tips</summary>

### Chat

There are 3 ways to chat with CodeRabbit:

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
	- `I pushed a fix in commit <commit_id>.`
	- `Generate unit-tests for this file.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
	- `@coderabbitai generate unit tests for this file.`
	-	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
	- `@coderabbitai generate interesting stats about this repository from git and render them as a table.`
	- `@coderabbitai show all the console.log statements in this repository.`
	- `@coderabbitai read src/utils.ts and generate unit tests.`
	- `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (invoked as PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger a review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai help` to get help.


Additionally, you can add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.

### CodeRabbit Configration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- The JSON schema for the configuration file is available [here](https://coderabbit.ai/integrations/coderabbit-overrides.v2.json).
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json`

### CodeRabbit Discord Community

Join our [Discord Community](https://discord.com/invite/GsXnASn26c) to get help, request features, and share feedback.

</details>

<!-- tips_end -->
carlaKC: Opening this as a draft because I still want to test this against other implementations, but basic functionality is in place. 
carlaKC: Hold off on review here - ran into an impl issue while testing :(
carlaKC: Re-confirming interop w/ CLN v24.02.1 @ 42c2fac29 since we've had quite a few changes! With the small exception of the max cltv height check because I'm getting the [wrong value](https://github.com/ElementsProject/lightning/issues/7161), so I just commented that check out to test.

Tested LND1 as introduction point for the following topology, using the same offer-fetching trick as before to get a blinded path: `Sender LND --> LND1 --(private)--> CLN`. 

Working on testing relaying (non-introduction) as well, but need to find a way to create a multi-hop path (looking into testing w/ ldk), seems like CLN just does one hop rn. 
carlaKC: @orbitalturtle confirmed interop w/ Eclair (via LNDK) when LND is an intermediate forwarding node (ie, not introduction) because they have multi-hop blinded - setup writeup [here](https://github.com/orbitalturtle/offer-testing-tools/tree/master/polar/lnd-eclair-lnd-eclair)!
Roasbeef: Needs a rebase! 
carlaKC: Will do! Working on some of the suggestions from @ellemouton + @bitromortac's review, think they'll clean this up really nicely 🥇 Aiming to push later today, latest tomorrow.
carlaKC: Updated PR description with overview of approach, but tl;dr: 
* Isolated blinded error handling in the incoming link as suggested, much cleaner!
* Using an `ErrorEncrytor` type to store whether we were part of a blinded route (over an `isBlinding` bool) because we don't always have this information on hand otherwise (see description for full details)

This could use some unit tests, but wanted to get an ACK on the approach with the `ErrorEncryptor` before going all in (perhaps I've missed something and we don't need this / other suggestions ?).
carlaKC: Ready for a look 🙏  @ellemouton @bitromortac 
carlaKC: Pushed to address comments so far!

> I'm not sure yet if the type wrapping method is the best approach 

Thinking about alternatives, we could add a type enum to `SphinxErrorEncryper` to get rid of the wrappers? So when we decode and we get type = `Sphinx` or `Intro` or `Relaying` we always create a `SphinxErrorEncrypter` but then just set a `Type` field in that encrypter to the variant we're using. That would cut down on boilerplate a little, but we'd need to be a more careful with handling the various types. 

carlaKC: taking a look at that itest failure - restriction on mining  > 100 blocks at a time now (just rebased on master)?
```
=== RUN   TestLightningNetworkDaemon/tranche00/35-of-152/bitcoind/multi_hop_local_force_close_on-chain_htlc_timeout/zeroconf=false/committype=SCRIPT_ENFORCED_LEASE
    harness.go:1708: 
        	Error Trace:	/home/runner/work/lnd/lnd/lntest/harness.go:1708
        	            				/home/runner/work/lnd/lnd/itest/lnd_route_blinding_test.go:997
        	            				/home/runner/work/lnd/lnd/lntest/harness.go:358
        	            				/home/runner/work/lnd/lnd/itest/lnd_test.go:139
        	Error:      	"129" is not less than "100"
        	Test:       	TestLightningNetworkDaemon/tranche03/143-of-152/bitcoind/on_chain_to_blinded
        	Messages:   	too many blocks to mine
    harness.go:411: finished test: on_chain_to_blinded, start height=1526, end height=1546, mined blocks=20
    harness.go:417: test failed, skipped cleanup
=== NAME  TestLightningNetworkDaemon
    harness_rpc.go:97: 
        	Error Trace:	/home/runner/work/lnd/lnd/lntest/rpc/harness_rpc.go:97
        	            				/home/runner/work/lnd/lnd/lntest/rpc/router.go:122
        	            				/home/runner/work/lnd/lnd/itest/lnd_route_blinding_test.go:464
        	            				/home/runner/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.21.4.linux-amd64/src/runtime/asm_amd64.s:1650
        	Error:      	Received unexpected error:
        	            	rpc error: code = Canceled desc = context canceled
        	Messages:   	Alice: failed to call SendToRouteV2
```
carlaKC: Removed critical log + addressed itest issue. 

Ran into an issue where the second level HTLC claim wasn't going through because the amount was too small to be feasible, so the test got stuck - @ziggie1984 very graciously helped me debug + is going to open up an issue. 

Patch:
diff --git a/config.go b/config.go
index 7084500b4..6c8df62dd 100644
--- a/config.go
+++ b/config.go
@@ -627,9 +627,8 @@ func DefaultConfig() Config {
 			RejectCacheSize:  channeldb.DefaultRejectCacheSize,
 			ChannelCacheSize: channeldb.DefaultChannelCacheSize,
 		},
-		Prometheus:      lncfg.DefaultPrometheus(),
-		Watchtower:      lncfg.DefaultWatchtowerCfg(defaultTowerDir),
-		ProtocolOptions: lncfg.DefaultProtocol(),
+		Prometheus: lncfg.DefaultPrometheus(),
+		Watchtower: lncfg.DefaultWatchtowerCfg(defaultTowerDir),
 		HealthChecks: &lncfg.HealthCheckConfig{
 			ChainCheck: &lncfg.CheckConfig{
 				Interval: defaultChainInterval,
diff --git a/docs/release-notes/release-notes-0.18.0.md b/docs/release-notes/release-notes-0.18.0.md
index 01a821db6..3135764ff 100644
--- a/docs/release-notes/release-notes-0.18.0.md
+++ b/docs/release-notes/release-notes-0.18.0.md
@@ -129,10 +129,6 @@
 
 * [Fixed](https://github.com/lightningnetwork/lnd/pull/8685) lncli "bumpfee"
   parsing of the immediate/force flag.
-  
-* [Fixed](https://github.com/lightningnetwork/lnd/pull/8621) the behaviour of
-  neutrino LND nodes which would loose sync in case they had very unstable
-  peer connection.
 
 # New Features
 ## Functional Enhancements
@@ -215,8 +211,11 @@ bitcoin peers' feefilter values into account](https://github.com/lightningnetwor
 
 * [Preparatory work](https://github.com/lightningnetwork/lnd/pull/8159) for 
   forwarding of blinded routes was added, along with [support](https://github.com/lightningnetwork/lnd/pull/8160)
-  for forwarding blinded payments. Forwarding of blinded payments is disabled 
-  by default, and the feature is not yet advertised to the network.
+  for forwarding blinded payments and [error handling](https://github.com/lightningnetwork/lnd/pull/8485).
+  With this change, LND is now eligible to be selected as part of a blinded 
+  route and can forward payments on behalf of nodes that have support for 
+  receiving to blinded paths. This upgrade provides a meaningful improvement 
+  to the anonymity set and usability of blinded paths in the Lightning Network.
 
 * Introduced [fee bumper](https://github.com/lightningnetwork/lnd/pull/8424) to
   handle bumping the fees of sweeping transactions properly. A
@@ -368,10 +367,6 @@ bitcoin peers' feefilter values into account](https://github.com/lightningnetwor
   whether through gRPC or the REST API, due to the destructive nature of the
   operation.
 
-* When paying an AMP payment request, [the `--amp` flag is now
-  required](https://github.com/lightningnetwork/lnd/pull/8681) to be consistent
-  w/ the flow when a payment request isn't used. 
-
 ## lncli Updates
 
 * [Documented all available `lncli`
@@ -536,7 +531,6 @@ bitcoin peers' feefilter values into account](https://github.com/lightningnetwor
 * Marcos Fernandez Perez
 * Matt Morehouse
 * Mohamed Awnallah
-* Olaoluwa Osuntokun
 * Ononiwu Maureen Chiamaka
 * Slyghtning
 * Tee8z
diff --git a/feature/default_sets.go b/feature/default_sets.go
index 3b7e0f7ea..cc802fe85 100644
--- a/feature/default_sets.go
+++ b/feature/default_sets.go
@@ -79,6 +79,11 @@ var defaultSetDesc = setDesc{
 		SetInit:    {}, // I
 		SetNodeAnn: {}, // N
 	},
+	lnwire.RouteBlindingOptional: {
+		SetInit:    {}, // I
+		SetNodeAnn: {}, // N
+		SetInvoice: {}, // 9
+	},
 	lnwire.ShutdownAnySegwitOptional: {
 		SetInit:    {}, // I
 		SetNodeAnn: {}, // N
diff --git a/feature/deps.go b/feature/deps.go
index b9fec2da0..350d49acf 100644
--- a/feature/deps.go
+++ b/feature/deps.go
@@ -79,6 +79,12 @@ var deps = depDesc{
 		lnwire.AnchorsZeroFeeHtlcTxOptional: {},
 		lnwire.ExplicitChannelTypeOptional:  {},
 	},
+	lnwire.RouteBlindingOptional: {
+		lnwire.TLVOnionPayloadOptional: {},
+	},
+	lnwire.RouteBlindingRequired: {
+		lnwire.TLVOnionPayloadRequired: {},
+	},
 }
 
 // ValidateDeps asserts that a feature vector sets all features and their
diff --git a/feature/manager.go b/feature/manager.go
index 98317eb8f..c7029e893 100644
--- a/feature/manager.go
+++ b/feature/manager.go
@@ -60,6 +60,9 @@ type Config struct {
 	// segwit witness versions for co-op closes.
 	NoAnySegwit bool
 
+	// NoRouteBlinding unsets route blinding feature bits.
+	NoRouteBlinding bool
+
 	// CustomFeatures is a set of custom features to advertise in each
 	// set.
 	CustomFeatures map[Set][]lnwire.FeatureBit
@@ -123,6 +126,8 @@ func newManager(cfg Config, desc setDesc) (*Manager, error) {
 			raw.Unset(lnwire.PaymentAddrRequired)
 			raw.Unset(lnwire.MPPOptional)
 			raw.Unset(lnwire.MPPRequired)
+			raw.Unset(lnwire.RouteBlindingOptional)
+			raw.Unset(lnwire.RouteBlindingRequired)
 			raw.Unset(lnwire.AMPOptional)
 			raw.Unset(lnwire.AMPRequired)
 			raw.Unset(lnwire.KeysendOptional)
@@ -179,7 +184,10 @@ func newManager(cfg Config, desc setDesc) (*Manager, error) {
 			raw.Unset(lnwire.SimpleTaprootChannelsOptionalStaging)
 			raw.Unset(lnwire.SimpleTaprootChannelsRequiredStaging)
 		}
-
+		if cfg.NoRouteBlinding {
+			raw.Unset(lnwire.RouteBlindingOptional)
+			raw.Unset(lnwire.RouteBlindingRequired)
+		}
 		for _, custom := range cfg.CustomFeatures[set] {
 			if custom > set.Maximum() {
 				return nil, fmt.Errorf("feature bit: %v "+
diff --git a/go.mod b/go.mod
index 5dd778818..54827142b 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ require (
 	github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344
 	github.com/andybalholm/brotli v1.0.4
 	github.com/btcsuite/btcd v0.24.2-beta.rc1.0.20240403021926-ae5533602c46
-	github.com/btcsuite/btcd/btcec/v2 v2.3.3
+	github.com/btcsuite/btcd/btcec/v2 v2.3.2
 	github.com/btcsuite/btcd/btcutil v1.1.5
 	github.com/btcsuite/btcd/btcutil/psbt v1.1.8
 	github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0
@@ -17,7 +17,7 @@ require (
 	github.com/btcsuite/btcwallet/wtxmgr v1.5.3
 	github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f
 	github.com/davecgh/go-spew v1.1.1
-	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0
+	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1
 	github.com/go-errors/errors v1.0.1
 	github.com/gorilla/websocket v1.5.0
 	github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
@@ -30,7 +30,7 @@ require (
 	github.com/jessevdk/go-flags v1.4.0
 	github.com/jrick/logrotate v1.0.0
 	github.com/kkdai/bstream v1.0.0
-	github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd
+	github.com/lightninglabs/neutrino v0.16.0
 	github.com/lightninglabs/neutrino/cache v1.1.2
 	github.com/lightningnetwork/lightning-onion v1.2.1-0.20230823005744-06182b1d7d2f
 	github.com/lightningnetwork/lnd/cert v1.2.2
@@ -51,12 +51,12 @@ require (
 	github.com/urfave/cli v1.22.9
 	go.etcd.io/etcd/client/pkg/v3 v3.5.7
 	go.etcd.io/etcd/client/v3 v3.5.7
-	golang.org/x/crypto v0.22.0
+	golang.org/x/crypto v0.21.0
 	golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8
 	golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028
 	golang.org/x/net v0.22.0
 	golang.org/x/sync v0.6.0
-	golang.org/x/term v0.19.0
+	golang.org/x/term v0.18.0
 	golang.org/x/time v0.3.0
 	google.golang.org/grpc v1.59.0
 	google.golang.org/protobuf v1.33.0
@@ -82,8 +82,8 @@ require (
 	github.com/coreos/go-semver v0.3.0 // indirect
 	github.com/coreos/go-systemd/v22 v22.3.2 // indirect
 	github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
-	github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect
-	github.com/decred/dcrd/lru v1.1.2 // indirect
+	github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect
+	github.com/decred/dcrd/lru v1.0.0 // indirect
 	github.com/docker/cli v20.10.17+incompatible // indirect
 	github.com/docker/docker v24.0.7+incompatible // indirect
 	github.com/docker/go-connections v0.4.0 // indirect
@@ -172,7 +172,7 @@ require (
 	go.uber.org/multierr v1.6.0 // indirect
 	go.uber.org/zap v1.17.0 // indirect
 	golang.org/x/mod v0.16.0 // indirect
-	golang.org/x/sys v0.19.0 // indirect
+	golang.org/x/sys v0.18.0 // indirect
 	golang.org/x/text v0.14.0 // indirect
 	golang.org/x/tools v0.19.0 // indirect
 	google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
diff --git a/go.sum b/go.sum
index e6f6245ff..e5e56d2c1 100644
--- a/go.sum
+++ b/go.sum
@@ -77,8 +77,8 @@ github.com/btcsuite/btcd v0.24.2-beta.rc1.0.20240403021926-ae5533602c46 h1:tjpNT
 github.com/btcsuite/btcd v0.24.2-beta.rc1.0.20240403021926-ae5533602c46/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg=
 github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA=
 github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
-github.com/btcsuite/btcd/btcec/v2 v2.3.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0=
-github.com/btcsuite/btcd/btcec/v2 v2.3.3/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
+github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
+github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
 github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A=
 github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE=
 github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8=
@@ -162,15 +162,12 @@ github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
 github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
-github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
-github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
+github.com/decred/dcrd/lru v1.0.0 h1:Kbsb1SFDsIlaupWPwsPp+dkxiBY1frcS07PCPgotKz8=
 github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
-github.com/decred/dcrd/lru v1.1.2 h1:KdCzlkxppuoIDGEvCGah1fZRicrDH36IipvlB1ROkFY=
-github.com/decred/dcrd/lru v1.1.2/go.mod h1:gEdCVgXs1/YoBvFWt7Scgknbhwik3FgVSzlnCcXL2N8=
 github.com/dhui/dktest v0.4.0 h1:z05UmuXZHO/bgj/ds2bGMBu8FI4WA+Ag/m3ghL+om7M=
 github.com/dhui/dktest v0.4.0/go.mod h1:v/Dbz1LgCBOi2Uki2nUqLBGa83hWBGFMu5MrgMDCc78=
 github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M=
@@ -436,8 +433,8 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
 github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc=
 github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk=
-github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd h1:D8aRocHpoCv43hL8egXEMYyPmyOiefFHZ66338KQB2s=
-github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd/go.mod h1:x3OmY2wsA18+Kc3TSV2QpSUewOCiscw2mKpXgZv2kZk=
+github.com/lightninglabs/neutrino v0.16.0 h1:YNTQG32fPR/Zg0vvJVI65OBH8l3U18LSXXtX91hx0q0=
+github.com/lightninglabs/neutrino v0.16.0/go.mod h1:x3OmY2wsA18+Kc3TSV2QpSUewOCiscw2mKpXgZv2kZk=
 github.com/lightninglabs/neutrino/cache v1.1.2 h1:C9DY/DAPaPxbFC+xNNEI/z1SJY9GS3shmlu5hIQ798g=
 github.com/lightninglabs/neutrino/cache v1.1.2/go.mod h1:XJNcgdOw1LQnanGjw8Vj44CvguYA25IMKjWFZczwZuo=
 github.com/lightninglabs/protobuf-go-hex-display v1.30.0-hex-display h1:pRdza2wleRN1L2fJXd6ZoQ9ZegVFTAb2bOQfruJPKcY=
@@ -687,8 +684,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
-golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
+golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
+golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -843,12 +840,12 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
-golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
-golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
+golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
+golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/htlcswitch/circuit.go b/htlcswitch/circuit.go
index efb2a4779..700b087f5 100644
--- a/htlcswitch/circuit.go
+++ b/htlcswitch/circuit.go
@@ -205,6 +205,12 @@ func (c *PaymentCircuit) Decode(r io.Reader) error {
 		// Test encrypter.
 		c.ErrorEncrypter = NewMockObfuscator()
 
+	case hop.EncrypterTypeIntroduction:
+		c.ErrorEncrypter = hop.NewIntroductionErrorEncrypter()
+
+	case hop.EncrypterTypeRelaying:
+		c.ErrorEncrypter = hop.NewRelayingErrorEncrypter()
+
 	default:
 		return UnknownEncrypterType(encrypterType)
 	}
diff --git a/htlcswitch/hop/error_encryptor.go b/htlcswitch/hop/error_encryptor.go
index 7b6a3dd1a..23272ec00 100644
--- a/htlcswitch/hop/error_encryptor.go
+++ b/htlcswitch/hop/error_encryptor.go
@@ -25,8 +25,26 @@ const (
 
 	// EncrypterTypeMock is used to identify a mock obfuscator instance.
 	EncrypterTypeMock = 2
+
+	// EncrypterTypeIntroduction is used to identify a sphinx onion error
+	// encrypter where we are the introduction node in a blinded route. It
+	// has the same functionality as EncrypterTypeSphinx, but is used to
+	// mark our special-case error handling.
+	EncrypterTypeIntroduction = 3
+
+	// EncrypterTypeRelaying is used to identify a sphinx onion error
+	// encryper where we are a relaying node in a blinded route. It has
+	// the same functionality as a EncrypterTypeSphinx, but is used to mark
+	// our special-case error handling.
+	EncrypterTypeRelaying = 4
 )
 
+// IsBlinded returns a boolean indicating whether the error encrypter belongs
+// to a blinded route.
+func (e EncrypterType) IsBlinded() bool {
+	return e == EncrypterTypeIntroduction || e == EncrypterTypeRelaying
+}
+
 // ErrorEncrypterExtracter defines a function signature that extracts an
 // ErrorEncrypter from an sphinx OnionPacket.
 type ErrorEncrypterExtracter func(*btcec.PublicKey) (ErrorEncrypter,
@@ -197,9 +215,72 @@ func (s *SphinxErrorEncrypter) Reextract(
 	s.OnionErrorEncrypter = sphinxEncrypter.OnionErrorEncrypter
 
 	return nil
-
 }
 
 // A compile time check to ensure SphinxErrorEncrypter implements the
 // ErrorEncrypter interface.
 var _ ErrorEncrypter = (*SphinxErrorEncrypter)(nil)
+
+// A compile time check to ensure that IntroductionErrorEncrypter implements
+// the ErrorEncrypter interface.
+var _ ErrorEncrypter = (*IntroductionErrorEncrypter)(nil)
+
+// IntroductionErrorEncrypter is a wrapper type on SphinxErrorEncrypter which
+// is used to signal that we have special HTLC error handling for this hop.
+type IntroductionErrorEncrypter struct {
+	// ErrorEncrypter is the underlying error encrypter, embedded
+	// directly in the struct so that we don't have to re-implement the
+	// ErrorEncrypter interface.
+	ErrorEncrypter
+}
+
+// NewIntroductionErrorEncrypter returns a blank IntroductionErrorEncrypter.
+func NewIntroductionErrorEncrypter() *IntroductionErrorEncrypter {
+	return &IntroductionErrorEncrypter{
+		ErrorEncrypter: NewSphinxErrorEncrypter(),
+	}
+}
+
+// Type returns the identifier for an introduction error encrypter.
+func (i *IntroductionErrorEncrypter) Type() EncrypterType {
+	return EncrypterTypeIntroduction
+}
+
+// Reextract rederives the error encrypter from the currently held EphemeralKey,
+// relying on the logic in the underlying SphinxErrorEncrypter.
+func (i *IntroductionErrorEncrypter) Reextract(
+	extract ErrorEncrypterExtracter) error {
+
+	return i.ErrorEncrypter.Reextract(extract)
+}
+
+// A compile time check to ensure that RelayingErrorEncrypte implements
+// the ErrorEncrypter interface.
+var _ ErrorEncrypter = (*RelayingErrorEncrypter)(nil)
+
+// RelayingErrorEncrypter is a wrapper type on SphinxErrorEncrypter which
+// is used to signal that we have special HTLC error handling for this hop.
+type RelayingErrorEncrypter struct {
+	ErrorEncrypter
+}
+
+// NewRelayingErrorEncrypter returns a blank RelayingErrorEncrypter with
+// an underlying SphinxErrorEncrypter.
+func NewRelayingErrorEncrypter() *RelayingErrorEncrypter {
+	return &RelayingErrorEncrypter{
+		ErrorEncrypter: NewSphinxErrorEncrypter(),
+	}
+}
+
+// Type returns the identifier for a relaying error encrypter.
+func (r *RelayingErrorEncrypter) Type() EncrypterType {
+	return EncrypterTypeRelaying
+}
+
+// Reextract rederives the error encrypter from the currently held EphemeralKey,
+// relying on the logic in the underlying SphinxErrorEncrypter.
+func (r *RelayingErrorEncrypter) Reextract(
+	extract ErrorEncrypterExtracter) error {
+
+	return r.ErrorEncrypter.Reextract(extract)
+}
diff --git a/htlcswitch/hop/iterator.go b/htlcswitch/hop/iterator.go
index df6f5aac7..a89f1b734 100644
--- a/htlcswitch/hop/iterator.go
+++ b/htlcswitch/hop/iterator.go
@@ -17,8 +17,69 @@ import (
 var (
 	// ErrDecodeFailed is returned when we can't decode blinded data.
 	ErrDecodeFailed = errors.New("could not decode blinded data")
+
+	// ErrNoBlindingPoint is returned when we have not provided a blinding
+	// point for a validated payload with encrypted data set.
+	ErrNoBlindingPoint = errors.New("no blinding point set for validated " +
+		"blinded hop")
+)
+
+// RouteRole represents the different types of roles a node can have as a
+// recipient of a HTLC.
+type RouteRole uint8
+
+const (
+	// RouteRoleCleartext represents a regular route hop.
+	RouteRoleCleartext RouteRole = iota
+
+	// RouteRoleIntroduction represents an introduction node in a blinded
+	// path, characterized by a blinding point in the onion payload.
+	RouteRoleIntroduction
+
+	// RouteRoleRelaying represents a relaying node in a blinded path,
+	// characterized by a blinding point in update_add_htlc.
+	RouteRoleRelaying
 )
 
+// String representation of a role in a route.
+func (h RouteRole) String() string {
+	switch h {
+	case RouteRoleCleartext:
+		return "cleartext"
+
+	case RouteRoleRelaying:
+		return "blinded relay"
+
+	case RouteRoleIntroduction:
+		return "introduction node"
+
+	default:
+		return fmt.Sprintf("unknown route role: %d", h)
+	}
+}
+
+// NewRouteRole returns the role we're playing in a route depending on the
+// blinding points set (or not). If we are in the situation where we received
+// blinding points in both the update add message and the payload:
+//   - We must have had a valid update add blinding point, because we were able
+//     to decrypt our onion to get the payload blinding point.
+//   - We return a relaying node role, because an introduction node (by
+//     definition) does not receive a blinding point in update add.
+//   - We assume the sending node to be buggy (including a payload blinding
+//     where it shouldn't), and rely on validation elsewhere to handle this.
+func NewRouteRole(updateAddBlinding, payloadBlinding bool) RouteRole {
+	switch {
+	case updateAddBlinding:
+		return RouteRoleRelaying
+
+	case payloadBlinding:
+		return RouteRoleIntroduction
+
+	default:
+		return RouteRoleCleartext
+	}
+}
+
 // Iterator is an interface that abstracts away the routing information
 // included in HTLC's which includes the entirety of the payment path of an
 // HTLC. This interface provides two basic method which carry out: how to
@@ -30,8 +91,11 @@ type Iterator interface {
 	// information encoded within the returned ForwardingInfo is to be used
 	// by each hop to authenticate the information given to it by the prior
 	// hop. The payload will also contain any additional TLV fields provided
-	// by the sender.
-	HopPayload() (*Payload, error)
+	// by the sender. The role that this hop plays in the context of
+	// route blinding (regular, introduction or relaying) is returned
+	// whenever the payload is successfully parsed, even if we subsequently
+	// face a validation error.
+	HopPayload() (*Payload, RouteRole, error)
 
 	// EncodeNextHop encodes the onion packet destined for the next hop
 	// into the passed io.Writer.
@@ -39,8 +103,8 @@ type Iterator interface {
 
 	// ExtractErrorEncrypter returns the ErrorEncrypter needed for this hop,
 	// along with a failure code to signal if the decoding was successful.
-	ExtractErrorEncrypter(ErrorEncrypterExtracter) (ErrorEncrypter,
-		lnwire.FailCode)
+	ExtractErrorEncrypter(extractor ErrorEncrypterExtracter,
+		introductionNode bool) (ErrorEncrypter, lnwire.FailCode)
 }
 
 // sphinxHopIterator is the Sphinx implementation of hop iterator which uses
@@ -90,29 +154,56 @@ func (r *sphinxHopIterator) EncodeNextHop(w io.Writer) error {
 // HopPayload returns the set of fields that detail exactly _how_ this hop
 // should forward the HTLC to the next hop.  Additionally, the information
 // encoded within the returned ForwardingInfo is to be used by each hop to
-// authenticate the information given to it by the prior hop. The payload will
-// also contain any additional TLV fields provided by the sender.
+// authenticate the information given to it by the prior hop. The role that
+// this hop plays in the context of route blinding (regular, introduction or
+// relaying) is returned whenever the payload is successfully parsed, even if
+// we subsequently face a validation error. The payload will also contain any
+// additional TLV fields provided by the sender.
 //
 // NOTE: Part of the HopIterator interface.
-func (r *sphinxHopIterator) HopPayload() (*Payload, error) {
+func (r *sphinxHopIterator) HopPayload() (*Payload, RouteRole, error) {
 	switch r.processedPacket.Payload.Type {
 
 	// If this is the legacy payload, then we'll extract the information
 	// directly from the pre-populated ForwardingInstructions field.
 	case sphinx.PayloadLegacy:
 		fwdInst := r.processedPacket.ForwardingInstructions
-		return NewLegacyPayload(fwdInst), nil
+		return NewLegacyPayload(fwdInst), RouteRoleCleartext, nil
 
 	// Otherwise, if this is the TLV payload, then we'll make a new stream
 	// to decode only what we need to make routing decisions.
 	case sphinx.PayloadTLV:
 		isFinal := r.processedPacket.Action == sphinx.ExitNode
-		payload, parsed, err := NewPayloadFromReader(
+		payload, parsed, err := ParseTLVPayload(
 			bytes.NewReader(r.processedPacket.Payload.Payload),
-			isFinal,
 		)
 		if err != nil {
-			return nil, err
+			// If we couldn't even parse our payload then we do
+			// a best-effort of determining our role in a blinded
+			// route, accepting that we can't know whether we
+			// were the introduction node (as the payload
+			// is not parseable).
+			routeRole := RouteRoleCleartext
+			if r.blindingKit.UpdateAddBlinding.IsSome() {
+				routeRole = RouteRoleRelaying
+			}
+
+			return nil, routeRole, err
+		}
+
+		// Now that we've parsed our payload we can determine which
+		// role we're playing in the route.
+		_, payloadBlinding := parsed[record.BlindingPointOnionType]
+		routeRole := NewRouteRole(
+			r.blindingKit.UpdateAddBlinding.IsSome(),
+			payloadBlinding,
+		)
+
+		if err := ValidateTLVPayload(
+			parsed, isFinal,
+			r.blindingKit.UpdateAddBlinding.IsSome(),
+		); err != nil {
+			return nil, routeRole, err
 		}
 
 		// If we had an encrypted data payload present, pull out our
@@ -122,17 +213,18 @@ func (r *sphinxHopIterator) HopPayload() (*Payload, error) {
 				payload, isFinal, parsed,
 			)
 			if err != nil {
-				return nil, err
+				return nil, routeRole, err
 			}
 
 			payload.FwdInfo = *fwdInfo
 		}
 
-		return payload, err
+		return payload, routeRole, nil
 
 	default:
-		return nil, fmt.Errorf("unknown sphinx payload type: %v",
-			r.processedPacket.Payload.Type)
+		return nil, RouteRoleCleartext,
+			fmt.Errorf("unknown sphinx payload type: %v",
+				r.processedPacket.Payload.Type)
 	}
 }
 
@@ -143,9 +235,31 @@ func (r *sphinxHopIterator) HopPayload() (*Payload, error) {
 //
 // NOTE: Part of the HopIterator interface.
 func (r *sphinxHopIterator) ExtractErrorEncrypter(
-	extracter ErrorEncrypterExtracter) (ErrorEncrypter, lnwire.FailCode) {
+	extracter ErrorEncrypterExtracter, introductionNode bool) (
+	ErrorEncrypter, lnwire.FailCode) {
+
+	encrypter, errCode := extracter(r.ogPacket.EphemeralKey)
+	if errCode != lnwire.CodeNone {
+		return nil, errCode
+	}
+
+	// If we're in a blinded path, wrap the error encrypter that we just
+	// derived in a "marker" type which we'll use to know what type of
+	// error we're handling.
+	switch {
+	case introductionNode:
+		return &IntroductionErrorEncrypter{
+			ErrorEncrypter: encrypter,
+		}, errCode
+
+	case r.blindingKit.UpdateAddBlinding.IsSome():
+		return &RelayingErrorEncrypter{
+			ErrorEncrypter: encrypter,
+		}, errCode
 
-	return extracter(r.ogPacket.EphemeralKey)
+	default:
+		return encrypter, errCode
+	}
 }
 
 // BlindingProcessor is an interface that provides the cryptographic operations
@@ -182,35 +296,16 @@ type BlindingKit struct {
 	IncomingAmount lnwire.MilliSatoshi
 }
 
-// validateBlindingPoint validates that only one blinding point is present for
-// the hop and returns the relevant one.
-func (b *BlindingKit) validateBlindingPoint(payloadBlinding *btcec.PublicKey,
-	isFinalHop bool) (*btcec.PublicKey, error) {
-
-	// Bolt 04: if encrypted_recipient_data is present:
-	// - if blinding_point (in update add) is set:
-	//   - MUST error if current_blinding_point is set (in payload)
-	// - otherwise:
-	//   - MUST return an error if current_blinding_point is not present
-	//     (in payload)
+// getBlindingPoint returns either the payload or updateAddHtlc blinding point,
+// assuming that validation that these values are appropriately set has already
+// been handled elsewhere.
+func (b *BlindingKit) getBlindingPoint(payloadBlinding *btcec.PublicKey) (
+	*btcec.PublicKey, error) {
+
 	payloadBlindingSet := payloadBlinding != nil
 	updateBlindingSet := b.UpdateAddBlinding.IsSome()
 
 	switch {
-	case !(payloadBlindingSet || updateBlindingSet):
-		return nil, ErrInvalidPayload{
-			Type:      record.BlindingPointOnionType,
-			Violation: OmittedViolation,
-			FinalHop:  isFinalHop,
-		}
-
-	case payloadBlindingSet && updateBlindingSet:
-		return nil, ErrInvalidPayload{
-			Type:      record.BlindingPointOnionType,
-			Violation: IncludedViolation,
-			FinalHop:  isFinalHop,
-		}
-
 	case payloadBlindingSet:
 		return payloadBlinding, nil
 
@@ -223,9 +318,10 @@ func (b *BlindingKit) validateBlindingPoint(payloadBlinding *btcec.PublicKey,
 		}
 
 		return pk.Val, nil
-	}
 
-	return nil, fmt.Errorf("expected blinded point set")
+	default:
+		return nil, ErrNoBlindingPoint
+	}
 }
 
 // DecryptAndValidateFwdInfo performs all operations required to decrypt and
@@ -235,11 +331,10 @@ func (b *BlindingKit) DecryptAndValidateFwdInfo(payload *Payload,
 	*ForwardingInfo, error) {
 
 	// We expect this function to be called when we have encrypted data
-	// present, and a blinding key is set either in the payload or the
+	// present, and expect validation to already have ensured that a
+	// blinding key is set either in the payload or the
 	// update_add_htlc message.
-	blindingPoint, err := b.validateBlindingPoint(
-		payload.blindingPoint, isFinalHop,
-	)
+	blindingPoint, err := b.getBlindingPoint(payload.blindingPoint)
 	if err != nil {
 		return nil, err
 	}
diff --git a/htlcswitch/hop/payload.go b/htlcswitch/hop/payload.go
index 70fdb1403..9e717bbd2 100644
--- a/htlcswitch/hop/payload.go
+++ b/htlcswitch/hop/payload.go
@@ -133,14 +133,10 @@ func NewLegacyPayload(f *sphinx.HopData) *Payload {
 	}
 }
 
-// NewPayloadFromReader builds a new Hop from the passed io.Reader and returns
-// a map of all the types that were found in the payload. The reader
-// should correspond to the bytes encapsulated in a TLV onion payload. The
-// final hop bool signals that this payload was the final packet parsed by
-// sphinx.
-func NewPayloadFromReader(r io.Reader, finalHop bool) (*Payload,
-	map[tlv.Type][]byte, error) {
-
+// ParseTLVPayload builds a new Hop from the passed io.Reader and returns
+// a map of all the types that were found in the payload. This function
+// does not perform validation of TLV types included in the payload.
+func ParseTLVPayload(r io.Reader) (*Payload, map[tlv.Type][]byte, error) {
 	var (
 		cid           uint64
 		amt           uint64
@@ -175,23 +171,6 @@ func NewPayloadFromReader(r io.Reader, finalHop bool) (*Payload,
 		return nil, nil, err
 	}
 
-	// Validate whether the sender properly included or omitted tlv records
-	// in accordance with BOLT 04.
-	err = ValidateParsedPayloadTypes(parsedTypes, finalHop)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	// Check for violation of the rules for mandatory fields.
-	violatingType := getMinRequiredViolation(parsedTypes)
-	if violatingType != nil {
-		return nil, nil, ErrInvalidPayload{
-			Type:      *violatingType,
-			Violation: RequiredViolation,
-			FinalHop:  finalHop,
-		}
-	}
-
 	// If no MPP field was parsed, set the MPP field on the resulting
 	// payload to nil.
 	if _, ok := parsedTypes[record.MPPOnionType]; !ok {
@@ -232,7 +211,34 @@ func NewPayloadFromReader(r io.Reader, finalHop bool) (*Payload,
 		blindingPoint: blindingPoint,
 		customRecords: customRecords,
 		totalAmtMsat:  lnwire.MilliSatoshi(totalAmtMsat),
-	}, nil, nil
+	}, parsedTypes, nil
+}
+
+// ValidateTLVPayload validates the TLV fields that were included in a TLV
+// payload.
+func ValidateTLVPayload(parsedTypes map[tlv.Type][]byte,
+	finalHop bool, updateAddBlinding bool) error {
+
+	// Validate whether the sender properly included or omitted tlv records
+	// in accordance with BOLT 04.
+	err := ValidateParsedPayloadTypes(
+		parsedTypes, finalHop, updateAddBlinding,
+	)
+	if err != nil {
+		return err
+	}
+
+	// Check for violation of the rules for mandatory fields.
+	violatingType := getMinRequiredViolation(parsedTypes)
+	if violatingType != nil {
+		return ErrInvalidPayload{
+			Type:      *violatingType,
+			Violation: RequiredViolation,
+			FinalHop:  finalHop,
+		}
+	}
+
+	return nil
 }
 
 // ForwardingInfo returns the basic parameters required for HTLC forwarding,
@@ -259,7 +265,7 @@ func NewCustomRecords(parsedTypes tlv.TypeMap) record.CustomSet {
 // boolean should be true if the payload was parsed for an exit hop. The
 // requirements for this method are described in BOLT 04.
 func ValidateParsedPayloadTypes(parsedTypes tlv.TypeMap,
-	isFinalHop bool) error {
+	isFinalHop, updateAddBlinding bool) error {
 
 	_, hasAmt := parsedTypes[record.AmtOnionType]
 	_, hasLockTime := parsedTypes[record.LockTimeOnionType]
@@ -267,6 +273,7 @@ func ValidateParsedPayloadTypes(parsedTypes tlv.TypeMap,
 	_, hasMPP := parsedTypes[record.MPPOnionType]
 	_, hasAMP := parsedTypes[record.AMPOnionType]
 	_, hasEncryptedData := parsedTypes[record.EncryptedDataOnionType]
+	_, hasBlinding := parsedTypes[record.BlindingPointOnionType]
 
 	// All cleartext hops (including final hop) and the final hop in a
 	// blinded path require the forwading amount and expiry TLVs to be set.
@@ -277,6 +284,32 @@ func ValidateParsedPayloadTypes(parsedTypes tlv.TypeMap,
 	needNextHop := !(hasEncryptedData || isFinalHop)
 
 	switch {
+	// Both blinding point being set is invalid.
+	case hasBlinding && updateAddBlinding:
+		return ErrInvalidPayload{
+			Type:      record.BlindingPointOnionType,
+			Violation: IncludedViolation,
+			FinalHop:  isFinalHop,
+		}
+
+	// If encrypted data is not provided, blinding points should not be
+	// set.
+	case !hasEncryptedData && (hasBlinding || updateAddBlinding):
+		return ErrInvalidPayload{
+			Type:      record.EncryptedDataOnionType,
+			Violation: OmittedViolation,
+			FinalHop:  isFinalHop,
+		}
+
+	// If encrypted data is present, we require that one blinding point
+	// is set.
+	case hasEncryptedData && !(hasBlinding || updateAddBlinding):
+		return ErrInvalidPayload{
+			Type:      record.EncryptedDataOnionType,
+			Violation: IncludedViolation,
+			FinalHop:  isFinalHop,
+		}
+
 	// Hops that need forwarding info must include an amount to forward.
 	case needFwdInfo && !hasAmt:
 		return ErrInvalidPayload{
diff --git a/htlcswitch/link.go b/htlcswitch/link.go
index 778e78d70..ed3151728 100644
--- a/htlcswitch/link.go
+++ b/htlcswitch/link.go
@@ -1793,8 +1793,20 @@ func (l *channelLink) handleDownstreamPkt(pkt *htlcPacket) {
 		htlc.ID = pkt.incomingHTLCID
 
 		// We send the HTLC message to the peer which initially created
-		// the HTLC.
-		l.cfg.Peer.SendMessage(false, htlc)
+		// the HTLC. If the incoming blinding point is non-nil, we
+		// know that we are a relaying node in a blinded path.
+		// Otherwise, we're either an introduction node or not part of
+		// a blinded path at all.
+		if err := l.sendIncomingHTLCFailureMsg(
+			htlc.ID,
+			pkt.obfuscator,
+			htlc.Reason,
+		); err != nil {
+			l.log.Errorf("unable to send HTLC failure: %v",
+				err)
+
+			return
+		}
 
 		// If the packet does not have a link failure set, it failed
 		// further down the route so we notify a forwarding failure.
@@ -2030,6 +2042,19 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) {
 			failure = &lnwire.FailInvalidOnionKey{
 				OnionSHA256: msg.ShaOnionBlob,
 			}
+
+		// Handle malformed errors that are part of a blinded route.
+		// This case is slightly different, because we expect every
+		// relaying node in the blinded portion of the route to send
+		// malformed errors. If we're also a relaying node, we're
+		// likely going to switch this error out anyway for our own
+		// malformed error, but we handle the case here for
+		// completeness.
+		case lnwire.CodeInvalidBlinding:
+			failure = &lnwire.FailInvalidBlinding{
+				OnionSHA256: msg.ShaOnionBlob,
+			}
+
 		default:
 			l.log.Warnf("unexpected failure code received in "+
 				"UpdateFailMailformedHTLC: %v", msg.FailureCode)
@@ -3249,7 +3274,7 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
 		// DecodeHopIterator function which process the Sphinx packet.
 		chanIterator, failureCode := decodeResps[i].Result()
 		if failureCode != lnwire.CodeNone {
-			// If we're unable to process the onion blob than we
+			// If we're unable to process the onion blob then we
 			// should send the malformed htlc error to payment
 			// sender.
 			l.sendMalformedHTLCError(pd.HtlcIndex, failureCode,
@@ -3260,37 +3285,50 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
 			continue
 		}
 
-		// Retrieve onion obfuscator from onion blob in order to
-		// produce initial obfuscation of the onion failureCode.
-		obfuscator, failureCode := chanIterator.ExtractErrorEncrypter(
-			l.cfg.ExtractErrorEncrypter,
-		)
-		if failureCode != lnwire.CodeNone {
-			// If we're unable to process the onion blob than we
-			// should send the malformed htlc error to payment
-			// sender.
-			l.sendMalformedHTLCError(
-				pd.HtlcIndex, failureCode, onionBlob[:], pd.SourceRef,
-			)
-
-			l.log.Errorf("unable to decode onion "+
-				"obfuscator: %v", failureCode)
-			continue
-		}
-
 		heightNow := l.cfg.BestHeight()
 
-		pld, err := chanIterator.HopPayload()
-		if err != nil {
+		pld, routeRole, pldErr := chanIterator.HopPayload()
+		if pldErr != nil {
 			// If we're unable to process the onion payload, or we
 			// received invalid onion payload failure, then we
 			// should send an error back to the caller so the HTLC
 			// can be canceled.
 			var failedType uint64
-			if e, ok := err.(hop.ErrInvalidPayload); ok {
+
+			// We need to get the underlying error value, so we
+			// can't use errors.As as suggested by the linter.
+			//nolint:errorlint
+			if e, ok := pldErr.(hop.ErrInvalidPayload); ok {
 				failedType = uint64(e.Type)
 			}
 
+			// If we couldn't parse the payload, make our best
+			// effort at creating an error encrypter that knows
+			// what blinding type we were, but if we couldn't
+			// parse the payload we have no way of knowing whether
+			// we were the introduction node or not.
+			//
+			//nolint:lll
+			obfuscator, failCode := chanIterator.ExtractErrorEncrypter(
+				l.cfg.ExtractErrorEncrypter,
+				// We need our route role here because we
+				// couldn't parse or validate the payload.
+				routeRole == hop.RouteRoleIntroduction,
+			)
+			if failCode != lnwire.CodeNone {
+				l.log.Errorf("could not extract error "+
+					"encrypter: %v", pldErr)
+
+				// We can't process this htlc, send back
+				// malformed.
+				l.sendMalformedHTLCError(
+					pd.HtlcIndex, failureCode,
+					onionBlob[:], pd.SourceRef,
+				)
+
+				continue
+			}
+
 			// TODO: currently none of the test unit infrastructure
 			// is setup to handle TLV payloads, so testing this
 			// would require implementing a separate mock iterator
@@ -3303,7 +3341,29 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
 			)
 
 			l.log.Errorf("unable to decode forwarding "+
-				"instructions: %v", err)
+				"instructions: %v", pldErr)
+
+			continue
+		}
+
+		// Retrieve onion obfuscator from onion blob in order to
+		// produce initial obfuscation of the onion failureCode.
+		obfuscator, failureCode := chanIterator.ExtractErrorEncrypter(
+			l.cfg.ExtractErrorEncrypter,
+			routeRole == hop.RouteRoleIntroduction,
+		)
+		if failureCode != lnwire.CodeNone {
+			// If we're unable to process the onion blob than we
+			// should send the malformed htlc error to payment
+			// sender.
+			l.sendMalformedHTLCError(
+				pd.HtlcIndex, failureCode, onionBlob[:],
+				pd.SourceRef,
+			)
+
+			l.log.Errorf("unable to decode onion "+
+				"obfuscator: %v", failureCode)
+
 			continue
 		}
 
@@ -3672,11 +3732,14 @@ func (l *channelLink) sendHTLCError(pd *lnwallet.PaymentDescriptor,
 		return
 	}
 
-	l.cfg.Peer.SendMessage(false, &lnwire.UpdateFailHTLC{
-		ChanID: l.ChanID(),
-		ID:     pd.HtlcIndex,
-		Reason: reason,
-	})
+	// Send the appropriate failure message depending on whether we're
+	// in a blinded route or not.
+	if err := l.sendIncomingHTLCFailureMsg(
+		pd.HtlcIndex, e, reason,
+	); err != nil {
+		l.log.Errorf("unable to send HTLC failure: %v", err)
+		return
+	}
 
 	// Notify a link failure on our incoming link. Outgoing htlc information
 	// is not available at this point, because we have not decrypted the
@@ -3705,6 +3768,95 @@ func (l *channelLink) sendHTLCError(pd *lnwallet.PaymentDescriptor,
 	)
 }
 
+// sendPeerHTLCFailure handles sending a HTLC failure message back to the
+// peer from which the HTLC was received. This function is primarily used to
+// handle the special requirements of route blinding, specifically:
+// - Forwarding nodes must switch out any errors with MalformedFailHTLC
+// - Introduction nodes should return regular HTLC failure messages.
+//
+// It accepts the original opaque failure, which will be used in the case
+// that we're not part of a blinded route and an error encrypter that'll be
+// used if we are the introduction node and need to present an error as if
+// we're the failing party.
+//
+// Note: this function does not yet handle special error cases for receiving
+// nodes in blinded paths, as LND does not support blinded receives.
+func (l *channelLink) sendIncomingHTLCFailureMsg(htlcIndex uint64,
+	e hop.ErrorEncrypter,
+	originalFailure lnwire.OpaqueReason) error {
+
+	var msg lnwire.Message
+	switch {
+	// Our circuit's error encrypter will be nil if this was a locally
+	// initiated payment. We can only hit a blinded error for a locally
+	// initiated payment if we allow ourselves to be picked as the
+	// introduction node for our own payments and in that case we
+	// shouldn't reach this code. To prevent the HTLC getting stuck,
+	// we fail it back and log an error.
+	// code.
+	case e == nil:
+		msg = &lnwire.UpdateFailHTLC{
+			ChanID: l.ChanID(),
+			ID:     htlcIndex,
+			Reason: originalFailure,
+		}
+
+		l.log.Errorf("Unexpected blinded failure when "+
+			"we are the sending node, incoming htlc: %v(%v)",
+			l.ShortChanID(), htlcIndex)
+
+	// For cleartext hops (ie, non-blinded/normal) we don't need any
+	// transformation on the error message and can just send the original.
+	case !e.Type().IsBlinded():
+		msg = &lnwire.UpdateFailHTLC{
+			ChanID: l.ChanID(),
+			ID:     htlcIndex,
+			Reason: originalFailure,
+		}
+
+	// When we're the introduction node, we need to convert the error to
+	// a UpdateFailHTLC.
+	case e.Type() == hop.EncrypterTypeIntroduction:
+		l.log.Debugf("Introduction blinded node switching out failure "+
+			"error: %v", htlcIndex)
+
+		// The specification does not require that we set the onion
+		// blob.
+		failureMsg := lnwire.NewInvalidBlinding(nil)
+		reason, err := e.EncryptFirstHop(failureMsg)
+		if err != nil {
+			return err
+		}
+
+		msg = &lnwire.UpdateFailHTLC{
+			ChanID: l.ChanID(),
+			ID:     htlcIndex,
+			Reason: reason,
+		}
+
+	// If we are a relaying node, we need to switch out any error that
+	// we've received to a malformed HTLC error.
+	case e.Type() == hop.EncrypterTypeRelaying:
+		l.log.Debugf("Relaying blinded node switching out malformed "+
+			"error: %v", htlcIndex)
+
+		msg = &lnwire.UpdateFailMalformedHTLC{
+			ChanID:      l.ChanID(),
+			ID:          htlcIndex,
+			FailureCode: lnwire.CodeInvalidBlinding,
+		}
+
+	default:
+		return fmt.Errorf("unexpected encrypter: %d", e)
+	}
+
+	if err := l.cfg.Peer.SendMessage(false, msg); err != nil {
+		l.log.Warnf("Send update fail failed: %v", err)
+	}
+
+	return nil
+}
+
 // sendMalformedHTLCError helper function which sends the malformed HTLC update
 // to the payment sender.
 func (l *channelLink) sendMalformedHTLCError(htlcIndex uint64,
diff --git a/htlcswitch/mailbox.go b/htlcswitch/mailbox.go
index 99066497c..a729e3ba5 100644
--- a/htlcswitch/mailbox.go
+++ b/htlcswitch/mailbox.go
@@ -738,6 +738,7 @@ func (m *memoryMailBox) FailAdd(pkt *htlcPacket) {
 		sourceRef:      pkt.sourceRef,
 		hasSource:      true,
 		localFailure:   localFailure,
+		obfuscator:     pkt.obfuscator,
 		linkFailure:    linkError,
 		htlc: &lnwire.UpdateFailHTLC{
 			Reason: reason,
diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go
index dfa834c58..cd3e5026b 100644
--- a/htlcswitch/mock.go
+++ b/htlcswitch/mock.go
@@ -330,10 +330,10 @@ func newMockHopIterator(hops ...*hop.Payload) hop.Iterator {
 	return &mockHopIterator{hops: hops}
 }
 
-func (r *mockHopIterator) HopPayload() (*hop.Payload, error) {
+func (r *mockHopIterator) HopPayload() (*hop.Payload, hop.RouteRole, error) {
 	h := r.hops[0]
 	r.hops = r.hops[1:]
-	return h, nil
+	return h, hop.RouteRoleCleartext, nil
 }
 
 func (r *mockHopIterator) ExtraOnionBlob() []byte {
@@ -341,7 +341,7 @@ func (r *mockHopIterator) ExtraOnionBlob() []byte {
 }
 
 func (r *mockHopIterator) ExtractErrorEncrypter(
-	extracter hop.ErrorEncrypterExtracter) (hop.ErrorEncrypter,
+	extracter hop.ErrorEncrypterExtracter, _ bool) (hop.ErrorEncrypter,
 	lnwire.FailCode) {
 
 	return extracter(nil)
diff --git a/htlcswitch/switch.go b/htlcswitch/switch.go
index 70b819b1e..d473d8422 100644
--- a/htlcswitch/switch.go
+++ b/htlcswitch/switch.go
@@ -1297,6 +1297,11 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
 
 		fail, isFail := htlc.(*lnwire.UpdateFailHTLC)
 		if isFail && !packet.hasSource {
+			// HTLC resolutions and messages restored from disk
+			// don't have the obfuscator set from the original htlc
+			// add packet - set it here for use in blinded errors.
+			packet.obfuscator = circuit.ErrorEncrypter
+
 			switch {
 			// No message to encrypt, locally sourced payment.
 			case circuit.ErrorEncrypter == nil:
@@ -1485,6 +1490,7 @@ func (s *Switch) failAddPacket(packet *htlcPacket, failure *LinkError) error {
 		incomingTimeout: packet.incomingTimeout,
 		outgoingTimeout: packet.outgoingTimeout,
 		circuit:         packet.circuit,
+		obfuscator:      packet.obfuscator,
 		linkFailure:     failure,
 		htlc: &lnwire.UpdateFailHTLC{
 			Reason: reason,
@@ -1841,6 +1847,10 @@ out:
 			// resolution message on restart.
 			resolutionMsg.errChan <- nil
 
+			// Create a htlc packet for this resolution. We do
+			// not have some of the information that we'll need
+			// for blinded error handling here , so we'll rely on
+			// our forwarding logic to fill it in later.
 			pkt := &htlcPacket{
 				outgoingChanID: resolutionMsg.SourceChan,
 				outgoingHTLCID: resolutionMsg.HtlcIndex,
@@ -2065,6 +2075,8 @@ func (s *Switch) reforwardResolutions() error {
 
 		// The circuit is still open, so we can assume that the link or
 		// switch (if we are the source) hasn't cleaned it up yet.
+		// We rely on our forwarding logic to fill in details that
+		// are not currently available to us.
 		resPkt := &htlcPacket{
 			outgoingChanID: resMsg.SourceChan,
 			outgoingHTLCID: resMsg.HtlcIndex,
@@ -2214,7 +2226,8 @@ func (s *Switch) reforwardSettleFails(fwdPkgs []*channeldb.FwdPkg) {
 				// we can continue to propagate it. This
 				// failure originated from another node, so
 				// the linkFailure field is not set on this
-				// packet.
+				// packet. We rely on the link to fill in
+				// additional circuit information for us.
 				failPacket := &htlcPacket{
 					outgoingChanID: fwdPkg.Source,
 					outgoingHTLCID: pd.ParentIndex,
diff --git a/lncfg/protocol.go b/lncfg/protocol.go
index 59027a09b..e98b4dcf8 100644
--- a/lncfg/protocol.go
+++ b/lncfg/protocol.go
@@ -59,14 +59,6 @@ type ProtocolOptions struct {
 	NoRouteBlindingOption bool `long:"no-route-blinding" description:"do not forward payments that are a part of a blinded route"`
 }
 
-// DefaultProtocol returns a protocol config with route blinding turned off,
-// temporarily in place until full handling of blinded route errors is merged.
-func DefaultProtocol() *ProtocolOptions {
-	return &ProtocolOptions{
-		NoRouteBlindingOption: true,
-	}
-}
-
 // Wumbo returns true if lnd should permit the creation and acceptance of wumbo
 // channels.
 func (l *ProtocolOptions) Wumbo() bool {
diff --git a/lncfg/protocol_integration.go b/lncfg/protocol_integration.go
index f44aa1246..841f8e9eb 100644
--- a/lncfg/protocol_integration.go
+++ b/lncfg/protocol_integration.go
@@ -62,13 +62,6 @@ type ProtocolOptions struct {
 	NoRouteBlindingOption bool `long:"no-route-blinding" description:"do not forward payments that are a part of a blinded route"`
 }
 
-// DefaultProtocol returns a protocol config with route blinding turned on,
-// so that itests can run against route blinding features even while we've
-// got it turned off for the daemon (pending completion of error handling).
-func DefaultProtocol() *ProtocolOptions {
-	return &ProtocolOptions{}
-}
-
 // Wumbo returns true if lnd should permit the creation and acceptance of wumbo
 // channels.
 func (l *ProtocolOptions) Wumbo() bool {
diff --git a/lnrpc/lightning.pb.go b/lnrpc/lightning.pb.go
index b2bc8034c..161fd2f11 100644
--- a/lnrpc/lightning.pb.go
+++ b/lnrpc/lightning.pb.go
@@ -651,6 +651,8 @@ const (
 	FeatureBit_ANCHORS_OPT                 FeatureBit = 21
 	FeatureBit_ANCHORS_ZERO_FEE_HTLC_REQ   FeatureBit = 22
 	FeatureBit_ANCHORS_ZERO_FEE_HTLC_OPT   FeatureBit = 23
+	FeatureBit_ROUTE_BLINDING_REQUIRED     FeatureBit = 24
+	FeatureBit_ROUTE_BLINDING_OPTIONAL     FeatureBit = 25
 	FeatureBit_AMP_REQ                     FeatureBit = 30
 	FeatureBit_AMP_OPT                     FeatureBit = 31
 )
@@ -681,6 +683,8 @@ var (
 		21: "ANCHORS_OPT",
 		22: "ANCHORS_ZERO_FEE_HTLC_REQ",
 		23: "ANCHORS_ZERO_FEE_HTLC_OPT",
+		24: "ROUTE_BLINDING_REQUIRED",
+		25: "ROUTE_BLINDING_OPTIONAL",
 		30: "AMP_REQ",
 		31: "AMP_OPT",
 	}
@@ -708,6 +712,8 @@ var (
 		"ANCHORS_OPT":                 21,
 		"ANCHORS_ZERO_FEE_HTLC_REQ":   22,
 		"ANCHORS_ZERO_FEE_HTLC_OPT":   23,
+		"ROUTE_BLINDING_REQUIRED":     24,
+		"ROUTE_BLINDING_OPTIONAL":     25,
 		"AMP_REQ":                     30,
 		"AMP_OPT":                     31,
 	}
@@ -20669,7 +20675,7 @@ var file_lightning_proto_rawDesc = []byte{
 	0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, 0x53, 0x10, 0x04,
 	0x12, 0x27, 0x0a, 0x23, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53,
 	0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f,
-	0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x05, 0x2a, 0xcf, 0x04, 0x0a, 0x0a, 0x46, 0x65,
+	0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x05, 0x2a, 0x89, 0x05, 0x0a, 0x0a, 0x46, 0x65,
 	0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x69, 0x74, 0x12, 0x18, 0x0a, 0x14, 0x44, 0x41, 0x54, 0x41,
 	0x4c, 0x4f, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x45, 0x43, 0x54, 0x5f, 0x52, 0x45, 0x51,
 	0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x44, 0x41, 0x54, 0x41, 0x4c, 0x4f, 0x53, 0x53, 0x5f, 0x50,
@@ -20705,338 +20711,342 @@ var file_lightning_proto_rawDesc = []byte{
 	0x45, 0x52, 0x4f, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x52, 0x45, 0x51,
 	0x10, 0x16, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x53, 0x5f, 0x5a, 0x45,
 	0x52, 0x4f, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4f, 0x50, 0x54, 0x10,
-	0x17, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x1e, 0x12, 0x0b,
-	0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f, 0x4f, 0x50, 0x54, 0x10, 0x1f, 0x2a, 0xac, 0x01, 0x0a, 0x0d,
-	0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x1a, 0x0a,
-	0x16, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f,
-	0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x55, 0x50, 0x44,
-	0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44,
-	0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f,
-	0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e,
-	0x44, 0x10, 0x02, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41,
-	0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x5f, 0x45,
-	0x52, 0x52, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46,
-	0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x50,
-	0x41, 0x52, 0x41, 0x4d, 0x45, 0x54, 0x45, 0x52, 0x10, 0x04, 0x32, 0xb9, 0x27, 0x0a, 0x09, 0x4c,
-	0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x4a, 0x0a, 0x0d, 0x57, 0x61, 0x6c, 0x6c,
-	0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70,
-	0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52,
-	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x57,
-	0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42,
-	0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43,
-	0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61,
-	0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61,
-	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47,
-	0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72,
-	0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73,
-	0x12, 0x44, 0x0a, 0x0b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x12,
-	0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65,
-	0x46, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 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, 0x3a, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61,
-	0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70,
-	0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e,
-	0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74,
-	0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f,
-	0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c,
-	0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x28, 0x01, 0x30, 0x01, 0x12, 0x41, 0x0a, 0x0f, 0x53, 0x65,
-	0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x19, 0x2e,
-	0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74,
-	0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63,
-	0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a,
-	0x0a, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x0e, 0x2e, 0x6c, 0x6e,
-	0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x1a, 0x19, 0x2e, 0x6c, 0x6e,
-	0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65,
-	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e,
-	0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c,
-	0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
-	0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e,
-	0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a,
-	0x0d, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x12,
-	0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61,
-	0x73, 0x68, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69,
-	0x63, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x49,
-	0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e,
-	0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
-	0x69, 0x6f, 0x6e, 0x1a, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f,
-	0x69, 0x63, 0x65, 0x30, 0x01, 0x12, 0x32, 0x0a, 0x0c, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x50,
-	0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61,
-	0x79, 0x52, 0x65, 0x71, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x1a, 0x0d, 0x2e, 0x6c, 0x6e, 0x72,
-	0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x47, 0x0a, 0x0c, 0x4c, 0x69, 0x73,
-	0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70,
-	0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69,
-	0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x12, 0x4a, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d,
-	0x65, 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65,
-	0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50,
-	0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56,
-	0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65,
-	0x6e, 0x74, 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65,
-	0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 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,
+	0x17, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x42, 0x4c, 0x49, 0x4e, 0x44,
+	0x49, 0x4e, 0x47, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x10, 0x18, 0x12, 0x1b,
+	0x0a, 0x17, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x42, 0x4c, 0x49, 0x4e, 0x44, 0x49, 0x4e, 0x47,
+	0x5f, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x41, 0x4c, 0x10, 0x19, 0x12, 0x0b, 0x0a, 0x07, 0x41,
+	0x4d, 0x50, 0x5f, 0x52, 0x45, 0x51, 0x10, 0x1e, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x4d, 0x50, 0x5f,
+	0x4f, 0x50, 0x54, 0x10, 0x1f, 0x2a, 0xac, 0x01, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
+	0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x55, 0x50, 0x44, 0x41, 0x54,
+	0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57,
+	0x4e, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41,
+	0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12,
+	0x1c, 0x0a, 0x18, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52,
+	0x45, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x02, 0x12, 0x1f, 0x0a,
+	0x1b, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f,
+	0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x5f, 0x45, 0x52, 0x52, 0x10, 0x03, 0x12, 0x24,
+	0x0a, 0x20, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45,
+	0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x45, 0x54,
+	0x45, 0x52, 0x10, 0x04, 0x32, 0xb9, 0x27, 0x0a, 0x09, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69,
+	0x6e, 0x67, 0x12, 0x4a, 0x0a, 0x0d, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61,
+	0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c,
+	0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x42,
+	0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d,
+	0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65,
+	0x12, 0x1c, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
+	0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d,
+	0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x61,
+	0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a,
+	0x0f, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+	0x12, 0x1d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e,
+	0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
+	0x69, 0x6f, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x44, 0x0a, 0x0b, 0x45, 0x73,
+	0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70,
+	0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 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, 0x3a, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53,
+	0x79, 0x6e, 0x63, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e,
+	0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b,
+	0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x6c, 0x6e,
+	0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53,
+	0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01,
+	0x28, 0x01, 0x30, 0x01, 0x12, 0x41, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f,
+	0x75, 0x74, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e,
+	0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x49, 0x6e,
+	0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x0e, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e,
+	0x76, 0x6f, 0x69, 0x63, 0x65, 0x1a, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64,
+	0x64, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x12, 0x45, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73,
+	0x12, 0x19, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76,
+	0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6e,
+	0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x0d, 0x4c, 0x6f, 0x6f, 0x6b, 0x75,
+	0x70, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63,
+	0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x1a, 0x0e, 0x2e, 0x6c,
+	0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x11,
+	0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65,
+	0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63,
+	0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0e, 0x2e,
+	0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x30, 0x01, 0x12,
+	0x32, 0x0a, 0x0c, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12,
+	0x13, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79, 0x52, 0x65, 0x71, 0x53, 0x74,
+	0x72, 0x69, 0x6e, 0x67, 0x1a, 0x0d, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x79,
+	0x52, 0x65, 0x71, 0x12, 0x47, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65,
+	0x6e, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74,
+	0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x1b, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x79, 0x6d,
+	0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x0d,
+	0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x2e,
+	0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d,
+	0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6e, 0x72,
+	0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65,
+	0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x2e,
+	0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x6c, 0x50,
+	0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20,
+	0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x44, 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,
-	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,
+	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 162dc35f9..2ad22e089 100644
--- a/lnrpc/lightning.proto
+++ b/lnrpc/lightning.proto
@@ -4311,6 +4311,8 @@ enum FeatureBit {
     ANCHORS_OPT = 21;
     ANCHORS_ZERO_FEE_HTLC_REQ = 22;
     ANCHORS_ZERO_FEE_HTLC_OPT = 23;
+    ROUTE_BLINDING_REQUIRED = 24;
+    ROUTE_BLINDING_OPTIONAL = 25;
     AMP_REQ = 30;
     AMP_OPT = 31;
 }
diff --git a/lnrpc/lightning.swagger.json b/lnrpc/lightning.swagger.json
index c0ea92d82..3a7132fc0 100644
--- a/lnrpc/lightning.swagger.json
+++ b/lnrpc/lightning.swagger.json
@@ -1470,6 +1470,8 @@
                 "ANCHORS_OPT",
                 "ANCHORS_ZERO_FEE_HTLC_REQ",
                 "ANCHORS_ZERO_FEE_HTLC_OPT",
+                "ROUTE_BLINDING_REQUIRED",
+                "ROUTE_BLINDING_OPTIONAL",
                 "AMP_REQ",
                 "AMP_OPT"
               ]
@@ -4694,6 +4696,8 @@
         "ANCHORS_OPT",
         "ANCHORS_ZERO_FEE_HTLC_REQ",
         "ANCHORS_ZERO_FEE_HTLC_OPT",
+        "ROUTE_BLINDING_REQUIRED",
+        "ROUTE_BLINDING_OPTIONAL",
         "AMP_REQ",
         "AMP_OPT"
       ],
diff --git a/lnrpc/peersrpc/peers.swagger.json b/lnrpc/peersrpc/peers.swagger.json
index c7b9970cf..b667994a4 100644
--- a/lnrpc/peersrpc/peers.swagger.json
+++ b/lnrpc/peersrpc/peers.swagger.json
@@ -77,6 +77,8 @@
         "ANCHORS_OPT",
         "ANCHORS_ZERO_FEE_HTLC_REQ",
         "ANCHORS_ZERO_FEE_HTLC_OPT",
+        "ROUTE_BLINDING_REQUIRED",
+        "ROUTE_BLINDING_OPTIONAL",
         "AMP_REQ",
         "AMP_OPT"
       ],
diff --git a/lnrpc/routerrpc/router.swagger.json b/lnrpc/routerrpc/router.swagger.json
index 8e1c646c1..1d948d3f8 100644
--- a/lnrpc/routerrpc/router.swagger.json
+++ b/lnrpc/routerrpc/router.swagger.json
@@ -772,6 +772,8 @@
         "ANCHORS_OPT",
         "ANCHORS_ZERO_FEE_HTLC_REQ",
         "ANCHORS_ZERO_FEE_HTLC_OPT",
+        "ROUTE_BLINDING_REQUIRED",
+        "ROUTE_BLINDING_OPTIONAL",
         "AMP_REQ",
         "AMP_OPT"
       ],
diff --git a/lnrpc/routerrpc/router_backend.go b/lnrpc/routerrpc/router_backend.go
index 9fde63411..18233991d 100644
--- a/lnrpc/routerrpc/router_backend.go
+++ b/lnrpc/routerrpc/router_backend.go
@@ -940,14 +940,6 @@ func (r *RouterBackend) extractIntentFromSendRequest(
 
 		payAddr := payReq.PaymentAddr
 		if payReq.Features.HasFeature(lnwire.AMPOptional) {
-			// The opt-in AMP flag is required to pay an AMP
-			// invoice.
-			if !rpcPayReq.Amp {
-				return nil, fmt.Errorf("the AMP flag (--amp " +
-					"or SendPaymentRequest.Amp) must be " +
-					"set to pay an AMP invoice")
-			}
-
 			// Generate random SetID and root share.
 			var setID [32]byte
 			_, err = rand.Read(setID[:])
diff --git a/lnwire/features.go b/lnwire/features.go
index ab6facc75..e4dd7f4f8 100644
--- a/lnwire/features.go
+++ b/lnwire/features.go
@@ -141,6 +141,14 @@ const (
 	// transactions, which also imply anchor commitments.
 	AnchorsZeroFeeHtlcTxOptional FeatureBit = 23
 
+	// RouteBlindingRequired is a required feature bit that signals that
+	// the node supports blinded payments.
+	RouteBlindingRequired FeatureBit = 24
+
+	// RouteBlindingOptional is an optional feature bit that signals that
+	// the node supports blinded payments.
+	RouteBlindingOptional FeatureBit = 25
+
 	// ShutdownAnySegwitRequired is an required feature bit that signals
 	// that the sender is able to properly handle/parse segwit witness
 	// programs up to version 16. This enables utilization of Taproot
@@ -315,6 +323,8 @@ var Features = map[FeatureBit]string{
 	ScidAliasOptional:                    "scid-alias",
 	ZeroConfRequired:                     "zero-conf",
 	ZeroConfOptional:                     "zero-conf",
+	RouteBlindingRequired:                "route-blinding",
+	RouteBlindingOptional:                "route-blinding",
 	ShutdownAnySegwitRequired:            "shutdown-any-segwit",
 	ShutdownAnySegwitOptional:            "shutdown-any-segwit",
 	SimpleTaprootChannelsRequiredFinal:   "simple-taproot-chans",
diff --git a/server.go b/server.go
index 2979880a2..43390ca57 100644
--- a/server.go
+++ b/server.go
@@ -549,6 +549,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
 		NoAnySegwit:              cfg.ProtocolOptions.NoAnySegwit(),
 		CustomFeatures:           cfg.ProtocolOptions.ExperimentalProtocol.CustomFeatures(),
 		NoTaprootChans:           !cfg.ProtocolOptions.TaprootChans,
+		NoRouteBlinding:          cfg.ProtocolOptions.NoRouteBlinding(),
 	})
 	if err != nil {
 		return nil, err


Test patch:
diff --git a/contractcourt/htlc_incoming_contest_resolver.go b/contractcourt/htlc_incoming_contest_resolver.go
index e73e3e45b..b104f8d70 100644
--- a/contractcourt/htlc_incoming_contest_resolver.go
+++ b/contractcourt/htlc_incoming_contest_resolver.go
@@ -543,7 +543,7 @@ func (h *htlcIncomingContestResolver) decodePayload() (*hop.Payload,
 		return nil, nil, err
 	}
 
-	payload, err := iterator.HopPayload()
+	payload, _, err := iterator.HopPayload()
 	if err != nil {
 		return nil, nil, err
 	}
diff --git a/contractcourt/htlc_incoming_contest_resolver_test.go b/contractcourt/htlc_incoming_contest_resolver_test.go
index 6c4ba6bc4..55d93a6fb 100644
--- a/contractcourt/htlc_incoming_contest_resolver_test.go
+++ b/contractcourt/htlc_incoming_contest_resolver_test.go
@@ -263,7 +263,7 @@ type mockHopIterator struct {
 	hop.Iterator
 }
 
-func (h *mockHopIterator) HopPayload() (*hop.Payload, error) {
+func (h *mockHopIterator) HopPayload() (*hop.Payload, hop.RouteRole, error) {
 	var nextAddress [8]byte
 	if !h.isExit {
 		nextAddress = [8]byte{0x01}
@@ -275,7 +275,7 @@ func (h *mockHopIterator) HopPayload() (*hop.Payload, error) {
 		ForwardAmount: 100,
 		OutgoingCltv:  40,
 		ExtraBytes:    [12]byte{},
-	}), nil
+	}), hop.RouteRoleCleartext, nil
 }
 
 func (h *mockHopIterator) EncodeNextHop(w io.Writer) error {
diff --git a/htlcswitch/hop/fuzz_test.go b/htlcswitch/hop/fuzz_test.go
index cbbe88260..e5c00b525 100644
--- a/htlcswitch/hop/fuzz_test.go
+++ b/htlcswitch/hop/fuzz_test.go
@@ -97,19 +97,37 @@ func hopFromPayload(p *Payload) (*route.Hop, uint64) {
 
 // FuzzPayloadFinal fuzzes final hop payloads, providing the additional context
 // that the hop should be final (which is usually obtained by the structure
-// of the sphinx packet).
-func FuzzPayloadFinal(f *testing.F) {
-	fuzzPayload(f, true)
+// of the sphinx packet) for the case where a blinding point was provided in
+// UpdateAddHtlc.
+func FuzzPayloadFinalBlinding(f *testing.F) {
+	fuzzPayload(f, true, true)
+}
+
+// FuzzPayloadFinal fuzzes final hop payloads, providing the additional context
+// that the hop should be final (which is usually obtained by the structure
+// of the sphinx packet) for the case where no blinding point was provided in
+// UpdateAddHtlc.
+func FuzzPayloadFinalNoBlinding(f *testing.F) {
+	fuzzPayload(f, true, false)
 }
 
 // FuzzPayloadIntermediate fuzzes intermediate hop payloads, providing the
 // additional context that a hop should be intermediate (which is usually
-// obtained by the structure of the sphinx packet).
-func FuzzPayloadIntermediate(f *testing.F) {
-	fuzzPayload(f, false)
+// obtained by the structure of the sphinx packet) for the case where a
+// blinding point was provided in UpdateAddHtlc.
+func FuzzPayloadIntermediateBlinding(f *testing.F) {
+	fuzzPayload(f, false, true)
 }
 
-func fuzzPayload(f *testing.F, finalPayload bool) {
+// FuzzPayloadIntermediate fuzzes intermediate hop payloads, providing the
+// additional context that a hop should be intermediate (which is usually
+// obtained by the structure of the sphinx packet) for the case where no
+// blinding point was provided in UpdateAddHtlc.
+func FuzzPayloadIntermediateNoBlinding(f *testing.F) {
+	fuzzPayload(f, false, false)
+}
+
+func fuzzPayload(f *testing.F, finalPayload, updateAddBlinded bool) {
 	f.Fuzz(func(t *testing.T, data []byte) {
 		if len(data) > sphinx.MaxPayloadSize {
 			return
@@ -117,17 +135,23 @@ func fuzzPayload(f *testing.F, finalPayload bool) {
 
 		r := bytes.NewReader(data)
 
-		payload1, _, err := NewPayloadFromReader(r, finalPayload)
+		payload1, parsed, err := ParseTLVPayload(r)
 		if err != nil {
 			return
 		}
 
+		if err = ValidateParsedPayloadTypes(
+			parsed, finalPayload, updateAddBlinded,
+		); err != nil {
+			return
+		}
+
 		var b bytes.Buffer
 		hop, nextChanID := hopFromPayload(payload1)
 		err = hop.PackHopPayload(&b, nextChanID, finalPayload)
 		switch {
 		// PackHopPayload refuses to encode an AMP record
-		// without an MPP record. However, NewPayloadFromReader
+		// without an MPP record. However, ValidateParsedPayloadTypes
 		// does allow decoding an AMP record without an MPP
 		// record, since validation is done at a later stage. Do
 		// not report a bug for this case.
@@ -136,9 +160,9 @@ func fuzzPayload(f *testing.F, finalPayload bool) {
 
 		// PackHopPayload will not encode regular payloads or final
 		// hops in blinded routes that do not have an amount or expiry
-		// TLV set. However, NewPayloadFromReader will allow creation
-		// of payloads where these TLVs are present, but they have
-		// zero values because validation is done at a later stage.
+		// TLV set. However, ValidateParsedPayloadTypes will allow
+		// creation of payloads where these TLVs are present, but they
+		// have zero values because validation is done at a later stage.
 		case errors.Is(err, route.ErrMissingField):
 			return
 
@@ -146,7 +170,12 @@ func fuzzPayload(f *testing.F, finalPayload bool) {
 			require.NoError(t, err)
 		}
 
-		payload2, _, err := NewPayloadFromReader(&b, finalPayload)
+		payload2, parsed, err := ParseTLVPayload(&b)
+		require.NoError(t, err)
+
+		err = ValidateParsedPayloadTypes(
+			parsed, finalPayload, updateAddBlinded,
+		)
 		require.NoError(t, err)
 
 		require.Equal(t, payload1, payload2)
diff --git a/htlcswitch/hop/iterator_test.go b/htlcswitch/hop/iterator_test.go
index 60919333b..e69361b0a 100644
--- a/htlcswitch/hop/iterator_test.go
+++ b/htlcswitch/hop/iterator_test.go
@@ -88,10 +88,10 @@ func TestSphinxHopIteratorForwardingInstructions(t *testing.T) {
 	for i, testCase := range testCases {
 		iterator.processedPacket = testCase.sphinxPacket
 
-		pld, err := iterator.HopPayload()
-		if err != nil {
+		pld, _, pldErr := iterator.HopPayload()
+		if pldErr != nil {
 			t.Fatalf("#%v: unable to extract forwarding "+
-				"instructions: %v", i, err)
+				"instructions: %v", i, pldErr)
 		}
 
 		fwdInfo := pld.ForwardingInfo()
@@ -216,24 +216,10 @@ func TestDecryptAndValidateFwdInfo(t *testing.T) {
 		expectedErr       error
 	}{
 		{
-			name:      "no blinding point",
-			data:      validData,
-			processor: &mockProcessor{},
-			expectedErr: ErrInvalidPayload{
-				Type:      record.BlindingPointOnionType,
-				Violation: OmittedViolation,
-			},
-		},
-		{
-			name:              "both blinding points",
-			data:              validData,
-			updateAddBlinding: &btcec.PublicKey{},
-			payloadBlinding:   &btcec.PublicKey{},
-			processor:         &mockProcessor{},
-			expectedErr: ErrInvalidPayload{
-				Type:      record.BlindingPointOnionType,
-				Violation: IncludedViolation,
-			},
+			name:        "no blinding point",
+			data:        validData,
+			processor:   &mockProcessor{},
+			expectedErr: ErrNoBlindingPoint,
 		},
 		{
 			name:              "decryption failed",
@@ -265,12 +251,19 @@ func TestDecryptAndValidateFwdInfo(t *testing.T) {
 			},
 		},
 		{
-			name:              "valid",
+			name:              "valid using update add",
 			updateAddBlinding: &btcec.PublicKey{},
 			data:              validData,
 			processor:         &mockProcessor{},
 			expectedErr:       nil,
 		},
+		{
+			name:            "valid using payload",
+			payloadBlinding: &btcec.PublicKey{},
+			data:            validData,
+			processor:       &mockProcessor{},
+			expectedErr:     nil,
+		},
 	}
 
 	for _, testCase := range tests {
diff --git a/htlcswitch/hop/payload_test.go b/htlcswitch/hop/payload_test.go
index 301e57716..c22144d7b 100644
--- a/htlcswitch/hop/payload_test.go
+++ b/htlcswitch/hop/payload_test.go
@@ -26,6 +26,7 @@ type decodePayloadTest struct {
 	name               string
 	payload            []byte
 	isFinalHop         bool
+	updateAddBlinded   bool
 	expErr             error
 	expCustomRecords   map[uint64][]byte
 	shouldHaveMPP      bool
@@ -271,8 +272,9 @@ var decodePayloadTests = []decodePayloadTest{
 		},
 	},
 	{
-		name:       "intermediate hop with encrypted data",
-		isFinalHop: false,
+		name:             "intermediate hop with encrypted data",
+		isFinalHop:       false,
+		updateAddBlinded: true,
 		payload: []byte{
 			// encrypted data
 			0x0a, 0x03, 0x03, 0x02, 0x01,
@@ -365,8 +367,9 @@ var decodePayloadTests = []decodePayloadTest{
 		shouldHaveTotalAmt: true,
 	},
 	{
-		name:       "final blinded hop with total amount",
-		isFinalHop: true,
+		name:             "final blinded hop with total amount",
+		isFinalHop:       true,
+		updateAddBlinded: true,
 		payload: []byte{
 			// amount
 			0x02, 0x00,
@@ -378,8 +381,9 @@ var decodePayloadTests = []decodePayloadTest{
 		shouldHaveEncData: true,
 	},
 	{
-		name:       "final blinded missing amt",
-		isFinalHop: true,
+		name:             "final blinded missing amt",
+		isFinalHop:       true,
+		updateAddBlinded: true,
 		payload: []byte{
 			// cltv
 			0x04, 0x00,
@@ -394,8 +398,9 @@ var decodePayloadTests = []decodePayloadTest{
 		},
 	},
 	{
-		name:       "final blinded missing cltv",
-		isFinalHop: true,
+		name:             "final blinded missing cltv",
+		isFinalHop:       true,
+		updateAddBlinded: true,
 		payload: []byte{
 			// amount
 			0x02, 0x00,
@@ -410,8 +415,9 @@ var decodePayloadTests = []decodePayloadTest{
 		},
 	},
 	{
-		name:       "intermediate blinded has amount",
-		isFinalHop: false,
+		name:             "intermediate blinded has amount",
+		isFinalHop:       false,
+		updateAddBlinded: true,
 		payload: []byte{
 			// amount
 			0x02, 0x00,
@@ -425,8 +431,9 @@ var decodePayloadTests = []decodePayloadTest{
 		},
 	},
 	{
-		name:       "intermediate blinded has expiry",
-		isFinalHop: false,
+		name:             "intermediate blinded has expiry",
+		isFinalHop:       false,
+		updateAddBlinded: true,
 		payload: []byte{
 			// cltv
 			0x04, 0x00,
@@ -439,6 +446,67 @@ var decodePayloadTests = []decodePayloadTest{
 			FinalHop:  false,
 		},
 	},
+	{
+		name:       "update add blinding no data",
+		isFinalHop: false,
+		payload: []byte{
+			// cltv
+			0x04, 0x00,
+		},
+		updateAddBlinded: true,
+		expErr: hop.ErrInvalidPayload{
+			Type:      record.EncryptedDataOnionType,
+			Violation: hop.OmittedViolation,
+			FinalHop:  false,
+		},
+	},
+	{
+		name:       "onion blinding point no data",
+		isFinalHop: false,
+		payload: append([]byte{
+			// blinding point (type / length)
+			0x0c, 0x21,
+		},
+			// blinding point (value)
+			testPubKey.SerializeCompressed()...,
+		),
+		expErr: hop.ErrInvalidPayload{
+			Type:      record.EncryptedDataOnionType,
+			Violation: hop.OmittedViolation,
+			FinalHop:  false,
+		},
+	},
+	{
+		name:       "encrypted data no blinding",
+		isFinalHop: false,
+		payload: []byte{
+			// encrypted data
+			0x0a, 0x03, 0x03, 0x02, 0x01,
+		},
+		expErr: hop.ErrInvalidPayload{
+			Type:      record.EncryptedDataOnionType,
+			Violation: hop.IncludedViolation,
+		},
+	},
+	{
+		name:             "both blinding points",
+		isFinalHop:       false,
+		updateAddBlinded: true,
+		payload: append([]byte{
+			// encrypted data
+			0x0a, 0x03, 0x03, 0x02, 0x01,
+			// blinding point (type / length)
+			0x0c, 0x21,
+		},
+			// blinding point (value)
+			testPubKey.SerializeCompressed()...,
+		),
+		expErr: hop.ErrInvalidPayload{
+			Type:      record.BlindingPointOnionType,
+			Violation: hop.IncludedViolation,
+			FinalHop:  false,
+		},
+	},
 }
 
 // TestDecodeHopPayloadRecordValidation asserts that parsing the payloads in the
@@ -479,8 +547,13 @@ func testDecodeHopPayloadValidation(t *testing.T, test decodePayloadTest) {
 		testChildIndex = uint32(9)
 	)
 
-	p, _, err := hop.NewPayloadFromReader(
-		bytes.NewReader(test.payload), test.isFinalHop,
+	p, parsedTypes, err := hop.ParseTLVPayload(
+		bytes.NewReader(test.payload),
+	)
+	require.NoError(t, err)
+
+	err = hop.ValidateTLVPayload(
+		parsedTypes, test.isFinalHop, test.updateAddBlinded,
 	)
 	if !reflect.DeepEqual(test.expErr, err) {
 		t.Fatalf("expected error mismatch, want: %v, got: %v",
diff --git a/itest/list_on_test.go b/itest/list_on_test.go
index 4696fc80e..2434ee92d 100644
--- a/itest/list_on_test.go
+++ b/itest/list_on_test.go
@@ -566,6 +566,26 @@ var allTestCases = []*lntest.TestCase{
 		Name:     "forward blinded",
 		TestFunc: testForwardBlindedRoute,
 	},
+	{
+		Name:     "receiver blinded error",
+		TestFunc: testReceiverBlindedError,
+	},
+	{
+		Name:     "relayer blinded error",
+		TestFunc: testRelayingBlindedError,
+	},
+	{
+		Name:     "introduction blinded error",
+		TestFunc: testIntroductionNodeError,
+	},
+	{
+		Name:     "disable introduction node",
+		TestFunc: testDisableIntroductionNode,
+	},
+	{
+		Name:     "on chain to blinded",
+		TestFunc: testErrorHandlingOnChainFailure,
+	},
 	{
 		Name:     "removetx",
 		TestFunc: testRemoveTx,
diff --git a/itest/lnd_amp_test.go b/itest/lnd_amp_test.go
index 23bfd8654..a96911319 100644
--- a/itest/lnd_amp_test.go
+++ b/itest/lnd_amp_test.go
@@ -129,7 +129,6 @@ func testSendPaymentAMPInvoiceCase(ht *lntest.HarnessTest,
 		PaymentAddr:    externalPayAddr,
 		TimeoutSeconds: 60,
 		FeeLimitMsat:   noFeeLimitMsat,
-		Amp:            true,
 	}
 	payment := ht.SendPaymentAssertSettled(mts.alice, sendReq)
 
@@ -253,7 +252,6 @@ func testSendPaymentAMPInvoiceRepeat(ht *lntest.HarnessTest) {
 	// Now we'll use Carol to pay the invoice that Dave created.
 	ht.CompletePaymentRequests(
 		carol, []string{addInvoiceResp.PaymentRequest},
-		lntest.WithAMP(),
 	)
 
 	// Dave should get a notification that the invoice has been settled.
@@ -276,7 +274,6 @@ func testSendPaymentAMPInvoiceRepeat(ht *lntest.HarnessTest) {
 	// has received another payment.
 	ht.CompletePaymentRequests(
 		carol, []string{addInvoiceResp.PaymentRequest},
-		lntest.WithAMP(),
 	)
 
 	// Dave should get another notification.
diff --git a/itest/lnd_psbt_test.go b/itest/lnd_psbt_test.go
index cd93fa0c0..a6f15fd35 100644
--- a/itest/lnd_psbt_test.go
+++ b/itest/lnd_psbt_test.go
@@ -1010,7 +1010,7 @@ func runFundAndSignPsbt(ht *lntest.HarnessTest, alice *node.HarnessNode) {
 
 	for _, addrType := range spendAddrTypes {
 		for _, changeType := range changeAddrTypes {
-			ht.Logf("testing with address type %s and "+
+			ht.Logf("testing with address type %s and"+
 				"change address type %s", addrType, changeType)
 
 			// First, spend all the coins in the wallet to an
diff --git a/itest/lnd_route_blinding_test.go b/itest/lnd_route_blinding_test.go
index e2d1ec033..1cae46a0c 100644
--- a/itest/lnd_route_blinding_test.go
+++ b/itest/lnd_route_blinding_test.go
@@ -355,14 +355,16 @@ func (b *blindedForwardTest) setup(
 	ctx context.Context) *routing.BlindedPayment {
 
 	b.carol = b.ht.NewNode("Carol", []string{
-		"requireinterceptor",
+		"--requireinterceptor", "--bitcoin.timelockdelta=18",
 	})
 
 	var err error
 	b.carolInterceptor, err = b.carol.RPC.Router.HtlcInterceptor(ctx)
 	require.NoError(b.ht, err, "interceptor")
 
-	b.dave = b.ht.NewNode("Dave", nil)
+	b.dave = b.ht.NewNode("Dave", []string{
+		"--bitcoin.timelockdelta=18",
+	})
 
 	b.channels = setupFourHopNetwork(b.ht, b.carol, b.dave)
 
@@ -448,9 +450,11 @@ func (b *blindedForwardTest) createRouteToBlinded(paymentAmt int64,
 	return resp.Routes[0]
 }
 
-// sendBlindedPayment dispatches a payment to the route provided.
+// sendBlindedPayment dispatches a payment to the route provided, returning a
+// cancel function for the payment. Timeout is set for very long to allow
+// time for on-chain resolution.
 func (b *blindedForwardTest) sendBlindedPayment(ctx context.Context,
-	route *lnrpc.Route) {
+	route *lnrpc.Route) func() {
 
 	hash := sha256.Sum256(b.preimage[:])
 	sendReq := &routerrpc.SendToRouteRequest{
@@ -458,11 +462,13 @@ func (b *blindedForwardTest) sendBlindedPayment(ctx context.Context,
 		Route:       route,
 	}
 
-	// Dispatch in a goroutine because this call is blocking - we assume
-	// that we'll have assertions that this payment is sent by the caller.
+	ctx, cancel := context.WithTimeout(ctx, time.Hour)
 	go func() {
-		b.ht.Alice.RPC.SendToRouteV2(sendReq)
+		_, err := b.ht.Alice.RPC.Router.SendToRouteV2(ctx, sendReq)
+		require.NoError(b.ht, err)
 	}()
+
+	return cancel
 }
 
 // interceptFinalHop launches a goroutine to intercept Carol's htlcs and
@@ -524,6 +530,43 @@ func (b *blindedForwardTest) interceptFinalHop() func(routerrpc.ResolveHoldForwa
 	return resolve
 }
 
+// drainCarolLiquidity will drain all of the liquidity in Carol's channel in
+// the direction requested:
+// - incoming: Carol has no incoming liquidity from Bob
+// - outgoing: Carol has no outgoing liquidity to Dave.
+func (b *blindedForwardTest) drainCarolLiquidity(incoming bool) {
+	sendingNode := b.carol
+	receivingNode := b.dave
+
+	if incoming {
+		sendingNode = b.ht.Bob
+		receivingNode = b.carol
+	}
+
+	resp := sendingNode.RPC.ListChannels(&lnrpc.ListChannelsRequest{
+		Peer: receivingNode.PubKey[:],
+	})
+	require.Len(b.ht, resp.Channels, 1)
+
+	// We can't send our channel reserve, and leave some buffer for fees.
+	paymentAmt := resp.Channels[0].LocalBalance -
+		int64(resp.Channels[0].RemoteConstraints.ChanReserveSat) - 25000
+
+	invoice := receivingNode.RPC.AddInvoice(&lnrpc.Invoice{
+		// Leave some leeway for fees for the HTLC.
+		Value: paymentAmt,
+	})
+
+	pmtClient := sendingNode.RPC.SendPayment(
+		&routerrpc.SendPaymentRequest{
+			PaymentRequest: invoice.PaymentRequest,
+			TimeoutSeconds: 60,
+		},
+	)
+
+	b.ht.AssertPaymentStatusFromStream(pmtClient, lnrpc.Payment_SUCCEEDED)
+}
+
 // setupFourHopNetwork creates a network with the following topology and
 // liquidity:
 // Alice (100k)----- Bob (100k) ----- Carol (100k) ----- Dave
@@ -768,7 +811,8 @@ func testForwardBlindedRoute(ht *lntest.HarnessTest) {
 	resolveHTLC := testCase.interceptFinalHop()
 
 	// Once our interceptor is set up, we can send the blinded payment.
-	testCase.sendBlindedPayment(ctx, blindedRoute)
+	cancelPmt := testCase.sendBlindedPayment(ctx, blindedRoute)
+	defer cancelPmt()
 
 	// Wait for the HTLC to be active on Alice's channel.
 	hash := sha256.Sum256(testCase.preimage[:])
@@ -788,3 +832,227 @@ func testForwardBlindedRoute(ht *lntest.HarnessTest) {
 	ht.AssertHTLCNotActive(ht.Bob, testCase.channels[1], hash[:])
 	ht.AssertHTLCNotActive(ht.Alice, testCase.channels[0], hash[:])
 }
+
+// Tests handling of errors from the receiving node in a blinded route, testing
+// a payment over: Alice -- Bob -- Carol -- Dave, where Bob is the introduction
+// node.
+//
+// Note that at present the payment fails at Dave because we do not yet support
+// receiving to blinded routes. In future, we can substitute this test out to
+// trigger an IncorrectPaymentDetails failure. In the meantime, this test
+// provides valuable coverage for the case where a node in the route is not
+// spec compliant (ie, does not return the blinded failure and just uses a
+// normal one) because Dave will not appropriately convert the error.
+func testReceiverBlindedError(ht *lntest.HarnessTest) {
+	ctx, testCase := newBlindedForwardTest(ht)
+	defer testCase.cleanup()
+	route := testCase.setup(ctx)
+
+	sendAndResumeBlindedPayment(ctx, ht, testCase, route, true)
+}
+
+// testRelayingBlindedError tests handling of errors from relaying nodes in a
+// blinded route, testing a failure over on Carol's outgoing link in the
+// following topology: Alice -- Bob -- Carol -- Dave, where Bob is the
+// introduction node.
+func testRelayingBlindedError(ht *lntest.HarnessTest) {
+	ctx, testCase := newBlindedForwardTest(ht)
+	defer testCase.cleanup()
+	route := testCase.setup(ctx)
+
+	// Before we send our payment, drain all of Carol's liquidity
+	// so that she can't forward the payment to Dave.
+	testCase.drainCarolLiquidity(false)
+
+	// Then dispatch the payment through Carol which will fail due to
+	// a lack of liquidity. This check only happens _after_ the interceptor
+	// has given the instruction to resume so we can use test
+	// infrastructure that will go ahead and intercept the payment.
+	sendAndResumeBlindedPayment(ctx, ht, testCase, route, true)
+}
+
+// sendAndResumeBlindedPayment sends a blinded payment through the test
+// network provided, intercepting the payment at Carol and allowing it to
+// resume. This utility function allows us to ensure that payments at least
+// reach Carol and asserts that all errors appear to originate from the
+// introduction node.
+func sendAndResumeBlindedPayment(ctx context.Context, ht *lntest.HarnessTest,
+	testCase *blindedForwardTest, route *routing.BlindedPayment,
+	interceptAtCarol bool) {
+
+	blindedRoute := testCase.createRouteToBlinded(10_000_000, route)
+
+	// Before we dispatch the payment, spin up a goroutine that will
+	// intercept the HTLC on Carol's forward. This allows us to ensure
+	// that the HTLC actually reaches the location we expect it to.
+	var resolveHTLC func(routerrpc.ResolveHoldForwardAction)
+	if interceptAtCarol {
+		resolveHTLC = testCase.interceptFinalHop()
+	}
+
+	// First, test sending the payment all the way through to Dave. We
+	// expect this payment to fail, because he does not know how to
+	// process payments to a blinded route (not yet supported).
+	cancelPmt := testCase.sendBlindedPayment(ctx, blindedRoute)
+	defer cancelPmt()
+
+	// When Carol intercepts the HTLC, instruct her to resume the payment
+	// so that it'll reach Dave and fail.
+	if interceptAtCarol {
+		resolveHTLC(routerrpc.ResolveHoldForwardAction_RESUME)
+	}
+
+	// Wait for the HTLC to reflect as failed for Alice.
+	preimage, err := lntypes.MakePreimage(testCase.preimage[:])
+	require.NoError(ht, err)
+	pmt := ht.AssertPaymentStatus(ht.Alice, preimage, lnrpc.Payment_FAILED)
+	require.Len(ht, pmt.Htlcs, 1)
+	require.EqualValues(
+		ht, 1, pmt.Htlcs[0].Failure.FailureSourceIndex,
+	)
+	require.Equal(
+		ht, lnrpc.Failure_INVALID_ONION_BLINDING,
+		pmt.Htlcs[0].Failure.Code,
+	)
+}
+
+// testIntroductionNodeError tests handling of errors in a blinded route when
+// the introduction node is the source of the error. This test sends a payment
+// over Alice -- Bob -- Carol -- Dave, where Bob is the introduction node and
+// has insufficient outgoing liquidity to forward on to carol.
+func testIntroductionNodeError(ht *lntest.HarnessTest) {
+	ctx, testCase := newBlindedForwardTest(ht)
+	defer testCase.cleanup()
+	route := testCase.setup(ctx)
+
+	// Before we send our payment, drain all of Carol's incoming liquidity
+	// so that she can't receive the forward from Bob, causing a failure
+	// at the introduction node.
+	testCase.drainCarolLiquidity(true)
+
+	// Send the payment, but do not expect it to reach Carol at all.
+	sendAndResumeBlindedPayment(ctx, ht, testCase, route, false)
+}
+
+// testDisableIntroductionNode tests disabling of blinded forwards for the
+// introduction node.
+func testDisableIntroductionNode(ht *lntest.HarnessTest) {
+	// Disable route blinding for Bob, then re-connect to Alice.
+	ht.RestartNodeWithExtraArgs(ht.Bob, []string{
+		"--protocol.no-route-blinding",
+	})
+	ht.EnsureConnected(ht.Alice, ht.Bob)
+
+	ctx, testCase := newBlindedForwardTest(ht)
+	defer testCase.cleanup()
+	route := testCase.setup(ctx)
+	// We always expect failures to look like they originated at Bob
+	// because blinded errors are converted. However, our tests intercepts
+	// all of Carol's forwards and we're not providing it any interceptor
+	// instructions. This means that the test will hang/timeout at Carol
+	// if Bob _doesn't_ fail the HTLC back as expected.
+	sendAndResumeBlindedPayment(ctx, ht, testCase, route, false)
+}
+
+// testErrorHandlingOnChainFailure tests handling of blinded errors when we're
+// resolving from an on-chain resolution. This test also tests that we're able
+// to resolve blinded HTLCs on chain between restarts, as we've got all the
+// infrastructure in place already for error testing.
+func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) {
+	// Setup a test case, note that we don't use its built in clean up
+	// because we're going to close a channel so we'll close out the
+	// rest manually.
+	ctx, testCase := newBlindedForwardTest(ht)
+
+	// Note that we send a larger amount here do it'll be worthwhile for
+	// the sweeper to claim.
+	route := testCase.setup(ctx)
+	blindedRoute := testCase.createRouteToBlinded(50_000_000, route)
+
+	// Once our interceptor is set up, we can send the blinded payment.
+	cancelPmt := testCase.sendBlindedPayment(ctx, blindedRoute)
+	defer cancelPmt()
+
+	// Wait for the HTLC to be active on Alice and Bob's channels.
+	hash := sha256.Sum256(testCase.preimage[:])
+	ht.AssertOutgoingHTLCActive(ht.Alice, testCase.channels[0], hash[:])
+	ht.AssertOutgoingHTLCActive(ht.Bob, testCase.channels[1], hash[:])
+
+	// Intercept the forward on Carol's link, but do not take any action
+	// so that we have the chance to force close with this HTLC in flight.
+	carolHTLC, err := testCase.carolInterceptor.Recv()
+	require.NoError(ht, err)
+
+	// Force close Bob <-> Carol.
+	closeStream, _ := ht.CloseChannelAssertPending(
+		ht.Bob, testCase.channels[1], true,
+	)
+
+	ht.AssertStreamChannelForceClosed(
+		ht.Bob, testCase.channels[1], false, closeStream,
+	)
+
+	// SuspendCarol so that she can't interfere with the resolution of the
+	// HTLC from now on.
+	restartCarol := ht.SuspendNode(testCase.carol)
+
+	// Mine blocks so that Bob will claim his CSV delayed local commitment,
+	// we've already mined 1 block so we need one less than our CSV.
+	ht.MineBlocks(node.DefaultCSV - 1)
+	ht.AssertNumPendingSweeps(ht.Bob, 1)
+	ht.MineEmptyBlocks(1)
+	ht.Miner.MineBlocksAndAssertNumTxes(1, 1)
+
+	// Restart bob so that we can test that he's able to recover everything
+	// he needs to claim a blinded HTLC.
+	ht.RestartNode(ht.Bob)
+
+	// Mine enough blocks for Bob to trigger timeout of his outgoing HTLC.
+	// Carol's incoming expiry height is Bob's outgoing so we can use this
+	// value.
+	info := ht.Bob.RPC.GetInfo()
+	target := carolHTLC.IncomingExpiry - info.BlockHeight
+	ht.MineBlocks(target)
+
+	// Wait for Bob's timeout transaction in the mempool, since we've
+	// suspended Carol we don't need to account for her commitment output
+	// claim.
+	ht.Miner.MineBlocksAndAssertNumTxes(1, 1)
+
+	// Assert that the HTLC has cleared.
+	ht.AssertHTLCNotActive(ht.Alice, testCase.channels[0], hash[:])
+	ht.AssertHTLCNotActive(ht.Bob, testCase.channels[0], hash[:])
+
+	// Wait for the HTLC to reflect as failed for Alice.
+	paymentStream := ht.Alice.RPC.TrackPaymentV2(hash[:])
+	htlcs := ht.ReceiveTrackPayment(paymentStream).Htlcs
+	require.Len(ht, htlcs, 1)
+	require.NotNil(ht, htlcs[0].Failure)
+	require.Equal(
+		ht, htlcs[0].Failure.Code,
+		lnrpc.Failure_INVALID_ONION_BLINDING,
+	)
+
+	// Clean up the rest of our force close: mine blocks so that Bob's CSV
+	// expires plus one block to trigger his sweep and then mine it.
+	ht.MineBlocks(node.DefaultCSV + 1)
+	ht.Miner.MineBlocksAndAssertNumTxes(1, 1)
+
+	// Bring carol back up so that we can close out the rest of our
+	// channels cooperatively. She requires an interceptor to start up
+	// so we just re-register our interceptor.
+	require.NoError(ht, restartCarol())
+	_, err = testCase.carol.RPC.Router.HtlcInterceptor(ctx)
+	require.NoError(ht, err, "interceptor")
+
+	// Assert that Carol has started up and reconnected to dave so that
+	// we can close out channels cooperatively.
+	ht.EnsureConnected(testCase.carol, testCase.dave)
+
+	// Manually close out the rest of our channels and cancel (don't use
+	// built in cleanup which will try close the already-force-closed
+	// channel).
+	ht.CloseChannel(ht.Alice, testCase.channels[0])
+	ht.CloseChannel(testCase.carol, testCase.channels[2])
+	testCase.cancel()
+}
diff --git a/lntest/harness.go b/lntest/harness.go
index 889bb156e..5c2bef488 100644
--- a/lntest/harness.go
+++ b/lntest/harness.go
@@ -105,32 +105,6 @@ type HarnessTest struct {
 	cleaned bool
 }
 
-// harnessOpts contains functional option to modify the behavior of the various
-// harness calls.
-type harnessOpts struct {
-	useAMP bool
-}
-
-// defaultHarnessOpts returns a new instance of the harnessOpts with default
-// values specified.
-func defaultHarnessOpts() harnessOpts {
-	return harnessOpts{
-		useAMP: false,
-	}
-}
-
-// HarnessOpt is a functional option that can be used to modify the behavior of
-// harness functionality.
-type HarnessOpt func(*harnessOpts)
-
-// WithAMP is a functional option that can be used to enable the AMP feature
-// for sending payments.
-func WithAMP() HarnessOpt {
-	return func(h *harnessOpts) {
-		h.useAMP = true
-	}
-}
-
 // NewHarnessTest creates a new instance of a harnessTest from a regular
 // testing.T instance.
 func NewHarnessTest(t *testing.T, lndBinary string, feeService WebFeeService,
@@ -1464,13 +1438,7 @@ func (h *HarnessTest) FundCoinsP2TR(amt btcutil.Amount,
 // all payment requests. This function does not return until all payments
 // have reached the specified status.
 func (h *HarnessTest) completePaymentRequestsAssertStatus(hn *node.HarnessNode,
-	paymentRequests []string, status lnrpc.Payment_PaymentStatus,
-	opts ...HarnessOpt) {
-
-	payOpts := defaultHarnessOpts()
-	for _, opt := range opts {
-		opt(&payOpts)
-	}
+	paymentRequests []string, status lnrpc.Payment_PaymentStatus) {
 
 	// Create a buffered chan to signal the results.
 	results := make(chan rpc.PaymentClient, len(paymentRequests))
@@ -1481,7 +1449,6 @@ func (h *HarnessTest) completePaymentRequestsAssertStatus(hn *node.HarnessNode,
 			PaymentRequest: payReq,
 			TimeoutSeconds: int32(wait.PaymentTimeout.Seconds()),
 			FeeLimitMsat:   noFeeLimitMsat,
-			Amp:            payOpts.useAMP,
 		}
 		stream := hn.RPC.SendPayment(req)
 
@@ -1510,10 +1477,10 @@ func (h *HarnessTest) completePaymentRequestsAssertStatus(hn *node.HarnessNode,
 // requests. This function does not return until all payments successfully
 // complete without errors.
 func (h *HarnessTest) CompletePaymentRequests(hn *node.HarnessNode,
-	paymentRequests []string, opts ...HarnessOpt) {
+	paymentRequests []string) {
 
 	h.completePaymentRequestsAssertStatus(
-		hn, paymentRequests, lnrpc.Payment_SUCCEEDED, opts...,
+		hn, paymentRequests, lnrpc.Payment_SUCCEEDED,
 	)
 }