Repository: lightningnetwork/lnd
Pull request #8985 (2024-08-06 22:49:13)

fn: more fn goodies
## Change Description
We add `fn` equivalents of the following Haskell functions:
- [`sequenceA`](https://hackage.haskell.org/package/base-4.20.0.1/docs/Prelude.html#v:sequenceA) renamed to `Collect`, both the Option and Result variants
- [`traverse`](https://hackage.haskell.org/package/base-4.20.0.1/docs/Prelude.html#v:traverse), both Option and Result variants
- [`mapMaybe`](https://hackage.haskell.org/package/base-4.20.0.1/docs/Data-Maybe.html#v:mapMaybe), renamed to FilterMap
- [`catMaybes`](https://hackage.haskell.org/package/base-4.20.0.1/docs/Data-Maybe.html#v:catMaybes), renamed to TrimNones
- [`note`](https://hackage.haskell.org/package/errors-2.3.0/docs/Control-Error-Util.html#v:note)
- [`hush`](https://hackage.haskell.org/package/errors-2.3.0/docs/Control-Error-Util.html#v:hush)

These are additions to the API that I discovered were missing when trying to do a refactor.

## Steps to Test
I can add tests if need be but for the most part I think the functions themselves are mostly checked by the type system. Thoughts appreciated.

## Pull Request Checklist
### Testing
- [x] Your PR passes all CI checks.
- [x] Tests covering the positive and negative (error paths) are included.
- [x] Bug fixes contain tests triggering the bug to prevent regressions.

### Code Style and Documentation
- [x] The change obeys the [Code Documentation and Commenting](https://github.com/lightningnetwork/lnd/blob/master/docs/code_contribution_guidelines.md#CodeDocumentation) guidelines, and lines wrap at 80.
- [x] Commits follow the [Ideal Git Commit Structure](https://github.com/lightningnetwork/lnd/blob/master/docs/code_contribution_guidelines.md#IdealGitCommitStructure).
- [x] Any new logging statements use an appropriate subsystem and logging level.
- [x] Any new lncli commands have appropriate tags in the comments for the rpc in the proto file.
- [x] [There is a change description in the release notes](https://github.com/lightningnetwork/lnd/tree/master/docs/release-notes), or `[skip ci]` in the commit message for small changes.

📝 Please see our [Contribution Guidelines](https://github.com/lightningnetwork/lnd/blob/master/docs/code_contribution_guidelines.md) for further guidance.


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

> [!IMPORTANT]
> ## Review skipped
> 
> Auto reviews are limited to specific labels.
> 
> <details>
> <summary>Labels to auto review (1)</summary>
> 
> * llm-review
> 
> </details>
> 
> 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.
> 
> You can disable this status message by setting the `reviews.review_status` to `false` in the CodeRabbit configuration file.

<!-- end of auto-generated comment: skip review by coderabbit.ai --><!-- tips_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>

<details>
<summary>Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
	- `I pushed a fix in commit <commit_id>.`
	- `Generate unit testing code for this file.`
	- `Open a follow-up GitHub issue for this discussion.`
- 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 testing code 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 and render them as a table.`
	- `@coderabbitai show all the console.log statements in this repository.`
	- `@coderabbitai read src/utils.ts and generate unit testing code.`
	- `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
	- `@coderabbitai help me debug CodeRabbit configuration file.`

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 an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.


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

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

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- 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/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://coderabbit.ai/docs) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](https://discord.com/invite/GsXnASn26c) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
ProofOfKeags: This PR has transformed into the breaking change PR we have been planning for some time. Micro label has been stripped. Merging this means we must push a tag for fn v2.0.0
lightninglabs-deploy: @carlakc: review reminder
lightninglabs-deploy: @roasbeef: review reminder
@yyforyongyu: review reminder
@carlakc: review reminder
ProofOfKeags: > I lean towards the approach of adding functionality as we need it (rather than wholesale PRs to extend the fn package)

The tools I include have all been directly motivated by code I witnessed in LND that would benefit from their inclusion, AND they all have direct corollaries in haskell's *standard* library. These aren't just toys I thought up from nowhere.

Adding functionality "as we need" is, in practice, just "continue to do the Sysiphean boulder push" since it is rare for people to notice and re-derive functional patterns, however, when they already exist, people will use them without issue.

The curse of truly general code is that it's generality makes it simultaneously more useful AND *less obviously* useful.
carlaKC: > since it is rare for people to notice and re-derive functional patterns, however, when they already exist, people will use them without issue.

Totally valid point / approach 👍 

My comment was just to note that I defer to the best judgement of the author/second reviewer here because I haven't done the work of taking a look at LND / common patterns that could use these tools, not that they aren't going to be useful! 
lightninglabs-deploy: @roasbeef: review reminder
@yyforyongyu: review reminder
@proofofkeags, remember to re-request review from reviewers when ready
lightninglabs-deploy: @roasbeef: review reminder
@yyforyongyu: review reminder
@proofofkeags, remember to re-request review from reviewers when ready
lightninglabs-deploy: @roasbeef: review reminder
@yyforyongyu: review reminder
@proofofkeags, remember to re-request review from reviewers when ready
lightninglabs-deploy: @roasbeef: review reminder
@yyforyongyu: review reminder
@proofofkeags, remember to re-request review from reviewers when ready
lightninglabs-deploy: @proofofkeags, remember to re-request review from reviewers when ready
lightninglabs-deploy: @roasbeef: review reminder
@yyforyongyu: review reminder
@proofofkeags, remember to re-request review from reviewers when ready
lightninglabs-deploy: @roasbeef: review reminder
@yyforyongyu: review reminder
@proofofkeags, remember to re-request review from reviewers when ready
lightninglabs-deploy: @roasbeef: review reminder
@yyforyongyu: review reminder
@proofofkeags, remember to re-request review from reviewers when ready

Patch:
diff --git a/build/config.go b/build/config.go
index fd3b01a94..66a0b3144 100644
--- a/build/config.go
+++ b/build/config.go
@@ -1,42 +1,34 @@
-package build
+//go:build !dev
+// +build !dev
 
-import (
-	"fmt"
+package build
 
-	"github.com/btcsuite/btclog/v2"
-)
+import "github.com/btcsuite/btclog/v2"
 
 const (
 	callSiteOff   = "off"
 	callSiteShort = "short"
 	callSiteLong  = "long"
-
-	defaultLogCompressor = Gzip
-
-	// DefaultMaxLogFiles is the default maximum number of log files to
-	// keep.
-	DefaultMaxLogFiles = 10
-
-	// DefaultMaxLogFileSize is the default maximum log file size in MB.
-	DefaultMaxLogFileSize = 20
 )
 
 // LogConfig holds logging configuration options.
 //
 //nolint:lll
 type LogConfig struct {
-	Console *consoleLoggerCfg `group:"console" namespace:"console" description:"The logger writing to stdout and stderr."`
-	File    *FileLoggerConfig `group:"file" namespace:"file" description:"The logger writing to LND's standard log file."`
+	Console *LoggerConfig `group:"console" namespace:"console" description:"The logger writing to stdout and stderr."`
+	File    *LoggerConfig `group:"file" namespace:"file" description:"The logger writing to LND's standard log file."`
 }
 
-// Validate validates the LogConfig struct values.
-func (c *LogConfig) Validate() error {
-	if !SupportedLogCompressor(c.File.Compressor) {
-		return fmt.Errorf("invalid log compressor: %v",
-			c.File.Compressor)
+// DefaultLogConfig returns the default logging config options.
+func DefaultLogConfig() *LogConfig {
+	return &LogConfig{
+		Console: &LoggerConfig{
+			CallSite: callSiteOff,
+		},
+		File: &LoggerConfig{
+			CallSite: callSiteOff,
+		},
 	}
-
-	return nil
 }
 
 // LoggerConfig holds options for a particular logger.
@@ -48,21 +40,6 @@ type LoggerConfig struct {
 	CallSite     string `long:"call-site" description:"Include the call-site of each log line." choice:"off" choice:"short" choice:"long"`
 }
 
-// DefaultLogConfig returns the default logging config options.
-func DefaultLogConfig() *LogConfig {
-	return &LogConfig{
-		Console: defaultConsoleLoggerCfg(),
-		File: &FileLoggerConfig{
-			Compressor:     defaultLogCompressor,
-			MaxLogFiles:    DefaultMaxLogFiles,
-			MaxLogFileSize: DefaultMaxLogFileSize,
-			LoggerConfig: LoggerConfig{
-				CallSite: callSiteOff,
-			},
-		},
-	}
-}
-
 // HandlerOptions returns the set of btclog.HandlerOptions that the state of the
 // config struct translates to.
 func (cfg *LoggerConfig) HandlerOptions() []btclog.HandlerOption {
@@ -73,7 +50,6 @@ func (cfg *LoggerConfig) HandlerOptions() []btclog.HandlerOption {
 		// to 7 here.
 		btclog.WithCallSiteSkipDepth(7),
 	}
-
 	if cfg.NoTimestamps {
 		opts = append(opts, btclog.WithNoTimestamp())
 	}
@@ -87,13 +63,3 @@ func (cfg *LoggerConfig) HandlerOptions() []btclog.HandlerOption {
 
 	return opts
 }
-
-// FileLoggerConfig extends LoggerConfig with specific log file options.
-//
-//nolint:lll
-type FileLoggerConfig struct {
-	LoggerConfig
-	Compressor     string `long:"compressor" description:"Compression algorithm to use when rotating logs." choice:"gzip" choice:"zstd"`
-	MaxLogFiles    int    `long:"max-files" description:"Maximum logfiles to keep (0 for no rotation)"`
-	MaxLogFileSize int    `long:"max-file-size" description:"Maximum logfile size in MB"`
-}
diff --git a/build/config_dev.go b/build/config_dev.go
index 09df7d618..daa5b1fde 100644
--- a/build/config_dev.go
+++ b/build/config_dev.go
@@ -17,8 +17,68 @@ const (
 	faintSeq = "2"
 	esc      = '\x1b'
 	csi      = string(esc) + "["
+
+	callSiteOff   = "off"
+	callSiteShort = "short"
+	callSiteLong  = "long"
 )
 
+// LogConfig holds logging configuration options.
+//
+//nolint:lll
+type LogConfig struct {
+	Console *consoleLoggerCfg `group:"console" namespace:"console" description:"The logger writing to stdout and stderr."`
+	File    *LoggerConfig     `group:"file" namespace:"file" description:"The logger writing to LND's standard log file."`
+}
+
+// DefaultLogConfig returns the default logging config options.
+func DefaultLogConfig() *LogConfig {
+	return &LogConfig{
+		Console: &consoleLoggerCfg{
+			LoggerConfig: LoggerConfig{
+				CallSite: callSiteShort,
+			},
+		},
+		File: &LoggerConfig{
+			CallSite: callSiteOff,
+		},
+	}
+}
+
+// LoggerConfig holds options for a particular logger.
+//
+//nolint:lll
+type LoggerConfig struct {
+	Disable      bool   `long:"disable" description:"Disable this logger."`
+	NoTimestamps bool   `long:"no-timestamps" description:"Omit timestamps from log lines."`
+	CallSite     string `long:"call-site" description:"Include the call-site of each log line." choice:"off" choice:"short" choice:"long"`
+}
+
+// HandlerOptions returns the set of btclog.HandlerOptions that the state of the
+// config struct translates to.
+func (cfg *LoggerConfig) HandlerOptions() []btclog.HandlerOption {
+	opts := []btclog.HandlerOption{
+		// The default skip depth used by the logging library is 6 but
+		// since we wrap the logging handlers with another level of
+		// abstraction with the handlerSet, we increase the skip depth
+		// to 7 here.
+		btclog.WithCallSiteSkipDepth(7),
+	}
+
+	if cfg.NoTimestamps {
+		opts = append(opts, btclog.WithNoTimestamp())
+	}
+
+	switch cfg.CallSite {
+	case callSiteShort:
+		opts = append(opts, btclog.WithCallerFlags(btclog.Lshortfile))
+	case callSiteLong:
+		opts = append(opts, btclog.WithCallerFlags(btclog.Llongfile))
+	}
+
+	return opts
+}
+
 // consoleLoggerCfg extends the LoggerConfig struct by adding a Color option
 // which is only available for a console logger.
 //
@@ -28,16 +88,6 @@ type consoleLoggerCfg struct {
 	Style bool `long:"style" description:"If set, the output will be styled with color and fonts"`
 }
 
-// defaultConsoleLoggerCfg returns the default consoleLoggerCfg for the dev
-// console logger.
-func defaultConsoleLoggerCfg() *consoleLoggerCfg {
-	return &consoleLoggerCfg{
-		LoggerConfig: LoggerConfig{
-			CallSite: callSiteShort,
-		},
-	}
-}
-
 // HandlerOptions returns the set of btclog.HandlerOptions that the state of the
 // config struct translates to.
 func (cfg *consoleLoggerCfg) HandlerOptions() []btclog.HandlerOption {
diff --git a/build/config_prod.go b/build/config_prod.go
deleted file mode 100644
index 67a43f8ac..000000000
--- a/build/config_prod.go
+++ /dev/null
@@ -1,22 +0,0 @@
-//go:build !dev
-// +build !dev
-
-package build
-
-// consoleLoggerCfg embeds the LoggerConfig struct along with any extensions
-// specific to a production deployment.
-//
-//nolint:lll
-type consoleLoggerCfg struct {
-	LoggerConfig
-}
-
-// defaultConsoleLoggerCfg returns the default consoleLoggerCfg for the prod
-// console logger.
-func defaultConsoleLoggerCfg() *consoleLoggerCfg {
-	return &consoleLoggerCfg{
-		LoggerConfig: LoggerConfig{
-			CallSite: callSiteOff,
-		},
-	}
-}
diff --git a/build/log.go b/build/log.go
index 37751ab46..568f9f618 100644
--- a/build/log.go
+++ b/build/log.go
@@ -52,9 +52,9 @@ var logCompressors = map[string]string{
 	Zstd: "zst",
 }
 
-// SupportedLogCompressor returns whether or not logCompressor is a supported
+// SuportedLogCompressor returns whether or not logCompressor is a supported
 // compression algorithm for log files.
-func SupportedLogCompressor(logCompressor string) bool {
+func SuportedLogCompressor(logCompressor string) bool {
 	_, ok := logCompressors[logCompressor]
 
 	return ok
diff --git a/build/logrotator.go b/build/logrotator.go
index b9b16654c..2ae105fde 100644
--- a/build/logrotator.go
+++ b/build/logrotator.go
@@ -31,8 +31,8 @@ func NewRotatingLogWriter() *RotatingLogWriter {
 // InitLogRotator initializes the log file rotator to write logs to logFile and
 // create roll files in the same directory. It should be called as early on
 // startup and possible and must be closed on shutdown by calling `Close`.
-func (r *RotatingLogWriter) InitLogRotator(cfg *FileLoggerConfig,
-	logFile string) error {
+func (r *RotatingLogWriter) InitLogRotator(logFile, logCompressor string,
+	maxLogFileSize int, maxLogFiles int) error {
 
 	logDir, _ := filepath.Split(logFile)
 	err := os.MkdirAll(logDir, 0700)
@@ -41,19 +41,19 @@ func (r *RotatingLogWriter) InitLogRotator(cfg *FileLoggerConfig,
 	}
 
 	r.rotator, err = rotator.New(
-		logFile, int64(cfg.MaxLogFileSize*1024), false, cfg.MaxLogFiles,
+		logFile, int64(maxLogFileSize*1024), false, maxLogFiles,
 	)
 	if err != nil {
 		return fmt.Errorf("failed to create file rotator: %w", err)
 	}
 
 	// Reject unknown compressors.
-	if !SupportedLogCompressor(cfg.Compressor) {
-		return fmt.Errorf("unknown log compressor: %v", cfg.Compressor)
+	if !SuportedLogCompressor(logCompressor) {
+		return fmt.Errorf("unknown log compressor: %v", logCompressor)
 	}
 
 	var c rotator.Compressor
-	switch cfg.Compressor {
+	switch logCompressor {
 	case Gzip:
 		c = gzip.NewWriter(nil)
 
@@ -66,7 +66,7 @@ func (r *RotatingLogWriter) InitLogRotator(cfg *FileLoggerConfig,
 	}
 
 	// Apply the compressor and its file suffix to the log rotator.
-	r.rotator.SetCompressor(c, logCompressors[cfg.Compressor])
+	r.rotator.SetCompressor(c, logCompressors[logCompressor])
 
 	// Run rotator as a goroutine now but make sure we catch any errors
 	// that happen in case something with the rotation goes wrong during
diff --git a/chainntnfs/btcdnotify/btcd.go b/chainntnfs/btcdnotify/btcd.go
index 1bf63f1e6..e865426e9 100644
--- a/chainntnfs/btcdnotify/btcd.go
+++ b/chainntnfs/btcdnotify/btcd.go
@@ -129,6 +129,11 @@ func New(config *rpcclient.ConnConfig, chainParams *chaincfg.Params,
 		quit: make(chan struct{}),
 	}
 
+	// Disable connecting to btcd within the rpcclient.New method. We
+	// defer establishing the connection to our .Start() method.
+	config.DisableConnectOnNew = true
+	config.DisableAutoReconnect = false
+
 	ntfnCallbacks := &rpcclient.NotificationHandlers{
 		OnBlockConnected:    notifier.onBlockConnected,
 		OnBlockDisconnected: notifier.onBlockDisconnected,
diff --git a/channeldb/migration/lnwire21/msat.go b/channeldb/migration/lnwire21/msat.go
index 47c676285..7473d72c8 100644
--- a/channeldb/migration/lnwire21/msat.go
+++ b/channeldb/migration/lnwire21/msat.go
@@ -2,10 +2,8 @@ package lnwire
 
 import (
 	"fmt"
-	"io"
 
 	"github.com/btcsuite/btcd/btcutil"
-	"github.com/lightningnetwork/lnd/tlv"
 )
 
 const (
@@ -51,39 +49,3 @@ func (m MilliSatoshi) String() string {
 }
 
 // TODO(roasbeef): extend with arithmetic operations?
-
-// Record returns a TLV record that can be used to encode/decode a MilliSatoshi
-// to/from a TLV stream.
-func (m *MilliSatoshi) Record() tlv.Record {
-	return tlv.MakeDynamicRecord(
-		0, m, tlv.SizeBigSize(m), encodeMilliSatoshis,
-		decodeMilliSatoshis,
-	)
-}
-func encodeMilliSatoshis(w io.Writer, val interface{}, buf *[8]byte) error {
-	if v, ok := val.(*MilliSatoshi); ok {
-		bigSize := uint64(*v)
-
-		return tlv.EBigSize(w, &bigSize, buf)
-	}
-
-	return tlv.NewTypeForEncodingErr(val, "lnwire.MilliSatoshi")
-}
-
-func decodeMilliSatoshis(r io.Reader, val interface{}, buf *[8]byte,
-	l uint64) error {
-
-	if v, ok := val.(*MilliSatoshi); ok {
-		var bigSize uint64
-		err := tlv.DBigSize(r, &bigSize, buf, l)
-		if err != nil {
-			return err
-		}
-
-		*v = MilliSatoshi(bigSize)
-
-		return nil
-	}
-
-	return tlv.NewTypeForDecodingErr(val, "lnwire.MilliSatoshi", l, l)
-}
diff --git a/channeldb/migration/lnwire21/true_boolean.go b/channeldb/migration/lnwire21/true_boolean.go
deleted file mode 100644
index 3cde34263..000000000
--- a/channeldb/migration/lnwire21/true_boolean.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package lnwire
-
-import (
-	"io"
-
-	"github.com/lightningnetwork/lnd/tlv"
-)
-
-// TrueBoolean is a record that indicates true or false using the presence of
-// the record. If the record is absent, it indicates false. If it is present,
-// it indicates true.
-type TrueBoolean struct{}
-
-// Record returns the tlv record for the boolean entry.
-func (b *TrueBoolean) Record() tlv.Record {
-	return tlv.MakeStaticRecord(
-		0, b, 0, booleanEncoder, booleanDecoder,
-	)
-}
-
-func booleanEncoder(_ io.Writer, val interface{}, _ *[8]byte) error {
-	if _, ok := val.(*TrueBoolean); ok {
-		return nil
-	}
-
-	return tlv.NewTypeForEncodingErr(val, "TrueBoolean")
-}
-
-func booleanDecoder(_ io.Reader, val interface{}, _ *[8]byte,
-	l uint64) error {
-
-	if _, ok := val.(*TrueBoolean); ok && (l == 0 || l == 1) {
-		return nil
-	}
-
-	return tlv.NewTypeForEncodingErr(val, "TrueBoolean")
-}
diff --git a/channeldb/migration32/mission_control_store.go b/channeldb/migration32/mission_control_store.go
index 3ac9d6114..3953cd1f2 100644
--- a/channeldb/migration32/mission_control_store.go
+++ b/channeldb/migration32/mission_control_store.go
@@ -8,8 +8,6 @@ import (
 
 	"github.com/btcsuite/btcd/wire"
 	lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
-	"github.com/lightningnetwork/lnd/fn"
-	"github.com/lightningnetwork/lnd/tlv"
 )
 
 const (
@@ -24,22 +22,30 @@ var (
 	resultsKey = []byte("missioncontrol-results")
 )
 
-// paymentResultOld is the information that becomes available when a payment
-// attempt completes.
-type paymentResultOld struct {
+// paymentResultCommon holds the fields that are shared by the old and new
+// payment result encoding.
+type paymentResultCommon struct {
 	id                 uint64
 	timeFwd, timeReply time.Time
-	route              *Route
 	success            bool
 	failureSourceIdx   *int
 	failure            lnwire.FailureMessage
 }
 
+// paymentResultOld is the information that becomes available when a payment
+// attempt completes.
+type paymentResultOld struct {
+	paymentResultCommon
+	route *Route
+}
+
 // deserializeOldResult deserializes a payment result using the old encoding.
 func deserializeOldResult(k, v []byte) (*paymentResultOld, error) {
 	// Parse payment id.
 	result := paymentResultOld{
-		id: byteOrder.Uint64(k[8:]),
+		paymentResultCommon: paymentResultCommon{
+			id: byteOrder.Uint64(k[8:]),
+		},
 	}
 
 	r := bytes.NewReader(v)
@@ -93,563 +99,67 @@ func deserializeOldResult(k, v []byte) (*paymentResultOld, error) {
 
 // convertPaymentResult converts a paymentResultOld to a paymentResultNew.
 func convertPaymentResult(old *paymentResultOld) *paymentResultNew {
-	var failure *paymentFailure
-	if !old.success {
-		failure = newPaymentFailure(old.failureSourceIdx, old.failure)
+	return &paymentResultNew{
+		paymentResultCommon: old.paymentResultCommon,
+		route:               extractMCRoute(old.route),
 	}
-
-	return newPaymentResult(
-		old.id, extractMCRoute(old.route), old.timeFwd, old.timeReply,
-		failure,
-	)
-}
-
-// newPaymentResult constructs a new paymentResult.
-func newPaymentResult(id uint64, rt *mcRoute, timeFwd, timeReply time.Time,
-	failure *paymentFailure) *paymentResultNew {
-
-	result := &paymentResultNew{
-		id: id,
-		timeFwd: tlv.NewPrimitiveRecord[tlv.TlvType0](
-			uint64(timeFwd.UnixNano()),
-		),
-		timeReply: tlv.NewPrimitiveRecord[tlv.TlvType1](
-			uint64(timeReply.UnixNano()),
-		),
-		route: tlv.NewRecordT[tlv.TlvType2](*rt),
-	}
-
-	if failure != nil {
-		result.failure = tlv.SomeRecordT(
-			tlv.NewRecordT[tlv.TlvType3](*failure),
-		)
-	}
-
-	return result
 }
 
 // paymentResultNew is the information that becomes available when a payment
 // attempt completes.
 type paymentResultNew struct {
-	id        uint64
-	timeFwd   tlv.RecordT[tlv.TlvType0, uint64]
-	timeReply tlv.RecordT[tlv.TlvType1, uint64]
-	route     tlv.RecordT[tlv.TlvType2, mcRoute]
-
-	// failure holds information related to the failure of a payment. The
-	// presence of this record indicates a payment failure. The absence of
-	// this record indicates a successful payment.
-	failure tlv.OptionalRecordT[tlv.TlvType3, paymentFailure]
-}
-
-// paymentFailure represents the presence of a payment failure. It may or may
-// not include additional information about said failure.
-type paymentFailure struct {
-	info tlv.OptionalRecordT[tlv.TlvType0, paymentFailureInfo]
-}
-
-// newPaymentFailure constructs a new paymentFailure struct. If the source
-// index is nil, then an empty paymentFailure is returned. This represents a
-// failure with unknown details. Otherwise, the index and failure message are
-// used to populate the info field of the paymentFailure.
-func newPaymentFailure(sourceIdx *int,
-	failureMsg lnwire.FailureMessage) *paymentFailure {
-
-	if sourceIdx == nil {
-		return &paymentFailure{}
-	}
-
-	info := paymentFailureInfo{
-		sourceIdx: tlv.NewPrimitiveRecord[tlv.TlvType0](
-			uint8(*sourceIdx),
-		),
-		msg: tlv.NewRecordT[tlv.TlvType1](failureMessage{failureMsg}),
-	}
-
-	return &paymentFailure{
-		info: tlv.SomeRecordT(tlv.NewRecordT[tlv.TlvType0](info)),
-	}
-}
-
-// Record returns a TLV record that can be used to encode/decode a
-// paymentFailure to/from a TLV stream.
-func (r *paymentFailure) Record() tlv.Record {
-	recordSize := func() uint64 {
-		var (
-			b   bytes.Buffer
-			buf [8]byte
-		)
-		if err := encodePaymentFailure(&b, r, &buf); err != nil {
-			panic(err)
-		}
-
-		return uint64(len(b.Bytes()))
-	}
-
-	return tlv.MakeDynamicRecord(
-		0, r, recordSize, encodePaymentFailure, decodePaymentFailure,
-	)
-}
-
-func encodePaymentFailure(w io.Writer, val interface{}, _ *[8]byte) error {
-	if v, ok := val.(*paymentFailure); ok {
-		var recordProducers []tlv.RecordProducer
-		v.info.WhenSome(
-			func(r tlv.RecordT[tlv.TlvType0, paymentFailureInfo]) {
-				recordProducers = append(recordProducers, &r)
-			},
-		)
-
-		return lnwire.EncodeRecordsTo(
-			w, lnwire.ProduceRecordsSorted(recordProducers...),
-		)
-	}
-
-	return tlv.NewTypeForEncodingErr(val, "routing.paymentFailure")
-}
-
-func decodePaymentFailure(r io.Reader, val interface{}, _ *[8]byte,
-	l uint64) error {
-
-	if v, ok := val.(*paymentFailure); ok {
-		var h paymentFailure
-
-		info := tlv.ZeroRecordT[tlv.TlvType0, paymentFailureInfo]()
-		typeMap, err := lnwire.DecodeRecords(
-			r, lnwire.ProduceRecordsSorted(&info)...,
-		)
-		if err != nil {
-			return err
-		}
-
-		if _, ok := typeMap[h.info.TlvType()]; ok {
-			h.info = tlv.SomeRecordT(info)
-		}
-
-		*v = h
-
-		return nil
-	}
-
-	return tlv.NewTypeForDecodingErr(val, "routing.paymentFailure", l, l)
-}
-
-// paymentFailureInfo holds additional information about a payment failure.
-type paymentFailureInfo struct {
-	sourceIdx tlv.RecordT[tlv.TlvType0, uint8]
-	msg       tlv.RecordT[tlv.TlvType1, failureMessage]
-}
-
-// Record returns a TLV record that can be used to encode/decode a
-// paymentFailureInfo to/from a TLV stream.
-func (r *paymentFailureInfo) Record() tlv.Record {
-	recordSize := func() uint64 {
-		var (
-			b   bytes.Buffer
-			buf [8]byte
-		)
-		if err := encodePaymentFailureInfo(&b, r, &buf); err != nil {
-			panic(err)
-		}
-
-		return uint64(len(b.Bytes()))
-	}
-
-	return tlv.MakeDynamicRecord(
-		0, r, recordSize, encodePaymentFailureInfo,
-		decodePaymentFailureInfo,
-	)
-}
-
-func encodePaymentFailureInfo(w io.Writer, val interface{}, _ *[8]byte) error {
-	if v, ok := val.(*paymentFailureInfo); ok {
-		return lnwire.EncodeRecordsTo(
-			w, lnwire.ProduceRecordsSorted(
-				&v.sourceIdx, &v.msg,
-			),
-		)
-	}
-
-	return tlv.NewTypeForEncodingErr(val, "routing.paymentFailureInfo")
-}
-
-func decodePaymentFailureInfo(r io.Reader, val interface{}, _ *[8]byte,
-	l uint64) error {
-
-	if v, ok := val.(*paymentFailureInfo); ok {
-		var h paymentFailureInfo
-
-		_, err := lnwire.DecodeRecords(
-			r,
-			lnwire.ProduceRecordsSorted(&h.sourceIdx, &h.msg)...,
-		)
-		if err != nil {
-			return err
-		}
-
-		*v = h
-
-		return nil
-	}
-
-	return tlv.NewTypeForDecodingErr(
-		val, "routing.paymentFailureInfo", l, l,
-	)
-}
-
-type failureMessage struct {
-	lnwire.FailureMessage
-}
-
-// Record returns a TLV record that can be used to encode/decode a list of
-// failureMessage to/from a TLV stream.
-func (r *failureMessage) Record() tlv.Record {
-	recordSize := func() uint64 {
-		var (
-			b   bytes.Buffer
-			buf [8]byte
-		)
-		if err := encodeFailureMessage(&b, r, &buf); err != nil {
-			panic(err)
-		}
-
-		return uint64(len(b.Bytes()))
-	}
-
-	return tlv.MakeDynamicRecord(
-		0, r, recordSize, encodeFailureMessage, decodeFailureMessage,
-	)
-}
-
-func encodeFailureMessage(w io.Writer, val interface{}, _ *[8]byte) error {
-	if v, ok := val.(*failureMessage); ok {
-		var b bytes.Buffer
-		err := lnwire.EncodeFailureMessage(&b, v.FailureMessage, 0)
-		if err != nil {
-			return err
-		}
-
-		_, err = w.Write(b.Bytes())
-
-		return err
-	}
-
-	return tlv.NewTypeForEncodingErr(val, "routing.failureMessage")
-}
-
-func decodeFailureMessage(r io.Reader, val interface{}, _ *[8]byte,
-	l uint64) error {
-
-	if v, ok := val.(*failureMessage); ok {
-		msg, err := lnwire.DecodeFailureMessage(r, 0)
-		if err != nil {
-			return err
-		}
-
-		*v = failureMessage{
-			FailureMessage: msg,
-		}
-
-		return nil
-	}
-
-	return tlv.NewTypeForDecodingErr(val, "routing.failureMessage", l, l)
+	paymentResultCommon
+	route *mcRoute
 }
 
 // extractMCRoute extracts the fields required by MC from the Route struct to
 // create the more minimal mcRoute struct.
-func extractMCRoute(r *Route) *mcRoute {
+func extractMCRoute(route *Route) *mcRoute {
 	return &mcRoute{
-		sourcePubKey: tlv.NewRecordT[tlv.TlvType0](r.SourcePubKey),
-		totalAmount:  tlv.NewRecordT[tlv.TlvType1](r.TotalAmount),
-		hops: tlv.NewRecordT[tlv.TlvType2](
-			extractMCHops(r.Hops),
-		),
+		sourcePubKey: route.SourcePubKey,
+		totalAmount:  route.TotalAmount,
+		hops:         extractMCHops(route.Hops),
 	}
 }
 
 // extractMCHops extracts the Hop fields that MC actually uses from a slice of
 // Hops.
-func extractMCHops(hops []*Hop) mcHops {
-	return fn.Map(extractMCHop, hops)
+func extractMCHops(hops []*Hop) []*mcHop {
+	mcHops := make([]*mcHop, len(hops))
+	for i, hop := range hops {
+		mcHops[i] = extractMCHop(hop)
+	}
+
+	return mcHops
 }
 
 // extractMCHop extracts the Hop fields that MC actually uses from a Hop.
 func extractMCHop(hop *Hop) *mcHop {
-	h := mcHop{
-		channelID: tlv.NewPrimitiveRecord[tlv.TlvType0, uint64](
-			hop.ChannelID,
-		),
-		pubKeyBytes: tlv.NewRecordT[tlv.TlvType1, Vertex](
-			hop.PubKeyBytes,
-		),
-		amtToFwd: tlv.NewRecordT[tlv.TlvType2, lnwire.MilliSatoshi](
-			hop.AmtToForward,
-		),
-	}
-
-	if hop.BlindingPoint != nil {
-		h.hasBlindingPoint = tlv.SomeRecordT(
-			tlv.NewRecordT[tlv.TlvType3, lnwire.TrueBoolean](
-				lnwire.TrueBoolean{},
-			),
-		)
-	}
-
-	if len(hop.CustomRecords) != 0 {
-		h.hasCustomRecords = tlv.SomeRecordT(
-			tlv.NewRecordT[tlv.TlvType4, lnwire.TrueBoolean](
-				lnwire.TrueBoolean{},
-			),
-		)
+	return &mcHop{
+		channelID:        hop.ChannelID,
+		pubKeyBytes:      hop.PubKeyBytes,
+		amtToFwd:         hop.AmtToForward,
+		hasBlindingPoint: hop.BlindingPoint != nil,
+		hasCustomRecords: len(hop.CustomRecords) > 0,
 	}
-
-	return &h
 }
 
 // mcRoute holds the bare minimum info about a payment attempt route that MC
 // requires.
 type mcRoute struct {
-	sourcePubKey tlv.RecordT[tlv.TlvType0, Vertex]
-	totalAmount  tlv.RecordT[tlv.TlvType1, lnwire.MilliSatoshi]
-	hops         tlv.RecordT[tlv.TlvType2, mcHops]
-}
-
-// Record returns a TLV record that can be used to encode/decode an mcRoute
-// to/from a TLV stream.
-func (r *mcRoute) Record() tlv.Record {
-	recordSize := func() uint64 {
-		var (
-			b   bytes.Buffer
-			buf [8]byte
-		)
-		if err := encodeMCRoute(&b, r, &buf); err != nil {
-			panic(err)
-		}
-
-		return uint64(len(b.Bytes()))
-	}
-
-	return tlv.MakeDynamicRecord(
-		0, r, recordSize, encodeMCRoute, decodeMCRoute,
-	)
-}
-
-func encodeMCRoute(w io.Writer, val interface{}, _ *[8]byte) error {
-	if v, ok := val.(*mcRoute); ok {
-		return serializeRoute(w, v)
-	}
-
-	return tlv.NewTypeForEncodingErr(val, "routing.mcRoute")
-}
-
-func decodeMCRoute(r io.Reader, val interface{}, _ *[8]byte, l uint64) error {
-	if v, ok := val.(*mcRoute); ok {
-		route, err := deserializeRoute(io.LimitReader(r, int64(l)))
-		if err != nil {
-			return err
-		}
-
-		*v = *route
-
-		return nil
-	}
-
-	return tlv.NewTypeForDecodingErr(val, "routing.mcRoute", l, l)
-}
-
-// mcHops is a list of mcHop records.
-type mcHops []*mcHop
-
-// Record returns a TLV record that can be used to encode/decode a list of
-// mcHop to/from a TLV stream.
-func (h *mcHops) Record() tlv.Record {
-	recordSize := func() uint64 {
-		var (
-			b   bytes.Buffer
-			buf [8]byte
-		)
-		if err := encodeMCHops(&b, h, &buf); err != nil {
-			panic(err)
-		}
-
-		return uint64(len(b.Bytes()))
-	}
-
-	return tlv.MakeDynamicRecord(
-		0, h, recordSize, encodeMCHops, decodeMCHops,
-	)
-}
-
-func encodeMCHops(w io.Writer, val interface{}, buf *[8]byte) error {
-	if v, ok := val.(*mcHops); ok {
-		// Encode the number of hops as a var int.
-		if err := tlv.WriteVarInt(w, uint64(len(*v)), buf); err != nil {
-			return err
-		}
-
-		// With that written out, we'll now encode the entries
-		// themselves as a sub-TLV record, which includes its _own_
-		// inner length prefix.
-		for _, hop := range *v {
-			var hopBytes bytes.Buffer
-			if err := serializeNewHop(&hopBytes, hop); err != nil {
-				return err
-			}
-
-			// We encode the record with a varint length followed by
-			// the _raw_ TLV bytes.
-			tlvLen := uint64(len(hopBytes.Bytes()))
-			if err := tlv.WriteVarInt(w, tlvLen, buf); err != nil {
-				return err
-			}
-
-			if _, err := w.Write(hopBytes.Bytes()); err != nil {
-				return err
-			}
-		}
-
-		return nil
-	}
-
-	return tlv.NewTypeForEncodingErr(val, "routing.mcHops")
-}
-
-func decodeMCHops(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
-	if v, ok := val.(*mcHops); ok {
-		// First, we'll decode the varint that encodes how many hops
-		// are encoded in the stream.
-		numHops, err := tlv.ReadVarInt(r, buf)
-		if err != nil {
-			return err
-		}
-
-		// Now that we know how many records we'll need to read, we can
-		// iterate and read them all out in series.
-		for i := uint64(0); i < numHops; i++ {
-			// Read out the varint that encodes the size of this
-			// inner TLV record.
-			hopSize, err := tlv.ReadVarInt(r, buf)
-			if err != nil {
-				return err
-			}
-
-			// Using this information, we'll create a new limited
-			// reader that'll return an EOF once the end has been
-			// reached so the stream stops consuming bytes.
-			innerTlvReader := &io.LimitedReader{
-				R: r,
-				N: int64(hopSize),
-			}
-
-			hop, err := deserializeNewHop(innerTlvReader)
-			if err != nil {
-				return err
-			}
-
-			*v = append(*v, hop)
-		}
-
-		return nil
-	}
-
-	return tlv.NewTypeForDecodingErr(val, "routing.mcHops", l, l)
-}
-
-// serializeRoute serializes a mcRoute and writes the resulting bytes to the
-// given io.Writer.
-func serializeRoute(w io.Writer, r *mcRoute) error {
-	records := lnwire.ProduceRecordsSorted(
-		&r.sourcePubKey,
-		&r.totalAmount,
-		&r.hops,
-	)
-
-	return lnwire.EncodeRecordsTo(w, records)
-}
-
-// deserializeRoute deserializes the mcRoute from the given io.Reader.
-func deserializeRoute(r io.Reader) (*mcRoute, error) {
-	var rt mcRoute
-	records := lnwire.ProduceRecordsSorted(
-		&rt.sourcePubKey,
-		&rt.totalAmount,
-		&rt.hops,
-	)
-
-	_, err := lnwire.DecodeRecords(r, records...)
-	if err != nil {
-		return nil, err
-	}
-
-	return &rt, nil
-}
-
-// deserializeNewHop deserializes the mcHop from the given io.Reader.
-func deserializeNewHop(r io.Reader) (*mcHop, error) {
-	var (
-		h        mcHop
-		blinding = tlv.ZeroRecordT[tlv.TlvType3, lnwire.TrueBoolean]()
-		custom   = tlv.ZeroRecordT[tlv.TlvType4, lnwire.TrueBoolean]()
-	)
-	records := lnwire.ProduceRecordsSorted(
-		&h.channelID,
-		&h.pubKeyBytes,
-		&h.amtToFwd,
-		&blinding,
-		&custom,
-	)
-
-	typeMap, err := lnwire.DecodeRecords(r, records...)
-	if err != nil {
-		return nil, err
-	}
-
-	if _, ok := typeMap[h.hasBlindingPoint.TlvType()]; ok {
-		h.hasBlindingPoint = tlv.SomeRecordT(blinding)
-	}
-
-	if _, ok := typeMap[h.hasCustomRecords.TlvType()]; ok {
-		h.hasCustomRecords = tlv.SomeRecordT(custom)
-	}
-
-	return &h, nil
-}
-
-// serializeNewHop serializes a mcHop and writes the resulting bytes to the
-// given io.Writer.
-func serializeNewHop(w io.Writer, h *mcHop) error {
-	recordProducers := []tlv.RecordProducer{
-		&h.channelID,
-		&h.pubKeyBytes,
-		&h.amtToFwd,
-	}
-
-	h.hasBlindingPoint.WhenSome(func(
-		hasBlinding tlv.RecordT[tlv.TlvType3, lnwire.TrueBoolean]) {
-
-		recordProducers = append(recordProducers, &hasBlinding)
-	})
-
-	h.hasCustomRecords.WhenSome(func(
-		hasCustom tlv.RecordT[tlv.TlvType4, lnwire.TrueBoolean]) {
-
-		recordProducers = append(recordProducers, &hasCustom)
-	})
-
-	return lnwire.EncodeRecordsTo(
-		w, lnwire.ProduceRecordsSorted(recordProducers...),
-	)
+	sourcePubKey Vertex
+	totalAmount  lnwire.MilliSatoshi
+	hops         []*mcHop
 }
 
 // mcHop holds the bare minimum info about a payment attempt route hop that MC
 // requires.
 type mcHop struct {
-	channelID        tlv.RecordT[tlv.TlvType0, uint64]
-	pubKeyBytes      tlv.RecordT[tlv.TlvType1, Vertex]
-	amtToFwd         tlv.RecordT[tlv.TlvType2, lnwire.MilliSatoshi]
-	hasBlindingPoint tlv.OptionalRecordT[tlv.TlvType3, lnwire.TrueBoolean]
-	hasCustomRecords tlv.OptionalRecordT[tlv.TlvType4, lnwire.TrueBoolean]
+	channelID        uint64
+	pubKeyBytes      Vertex
+	amtToFwd         lnwire.MilliSatoshi
+	hasBlindingPoint bool
+	hasCustomRecords bool
 }
 
 // serializeOldResult serializes a payment result and returns a key and value
@@ -715,30 +225,48 @@ func getResultKeyOld(rp *paymentResultOld) []byte {
 // serializeNewResult serializes a payment result and returns a key and value
 // byte slice to insert into the bucket.
 func serializeNewResult(rp *paymentResultNew) ([]byte, []byte, error) {
-	recordProducers := []tlv.RecordProducer{
-		&rp.timeFwd,
-		&rp.timeReply,
-		&rp.route,
+	// Write timestamps, success status, failure source index and route.
+	var b bytes.Buffer
+
+	var dbFailureSourceIdx int32
+	if rp.failureSourceIdx == nil {
+		dbFailureSourceIdx = unknownFailureSourceIdx
+	} else {
+		dbFailureSourceIdx = int32(*rp.failureSourceIdx)
 	}
 
-	rp.failure.WhenSome(
-		func(failure tlv.RecordT[tlv.TlvType3, paymentFailure]) {
-			recordProducers = append(recordProducers, &failure)
-		},
+	err := WriteElements(
+		&b,
+		uint64(rp.timeFwd.UnixNano()),
+		uint64(rp.timeReply.UnixNano()),
+		rp.success, dbFailureSourceIdx,
 	)
+	if err != nil {
+		return nil, nil, err
+	}
 
-	// Compose key that identifies this result.
-	key := getResultKeyNew(rp)
+	if err := serializeMCRoute(&b, rp.route); err != nil {
+		return nil, nil, err
+	}
 
-	var buff bytes.Buffer
-	err := lnwire.EncodeRecordsTo(
-		&buff, lnwire.ProduceRecordsSorted(recordProducers...),
-	)
+	// Write failure. If there is no failure message, write an empty
+	// byte slice.
+	var failureBytes bytes.Buffer
+	if rp.failure != nil {
+		err := lnwire.EncodeFailureMessage(&failureBytes, rp.failure, 0)
+		if err != nil {
+			return nil, nil, err
+		}
+	}
+	err = wire.WriteVarBytes(&b, 0, failureBytes.Bytes())
 	if err != nil {
 		return nil, nil, err
 	}
 
-	return key, buff.Bytes(), err
+	// Compose key that identifies this result.
+	key := getResultKeyNew(rp)
+
+	return key, b.Bytes(), nil
 }
 
 // getResultKeyNew returns a byte slice representing a unique key for this
@@ -750,9 +278,43 @@ func getResultKeyNew(rp *paymentResultNew) []byte {
 	// key. This allows importing mission control data from an external
 	// source without key collisions and keeps the records sorted
 	// chronologically.
-	byteOrder.PutUint64(keyBytes[:], rp.timeReply.Val)
+	byteOrder.PutUint64(keyBytes[:], uint64(rp.timeReply.UnixNano()))
 	byteOrder.PutUint64(keyBytes[8:], rp.id)
-	copy(keyBytes[16:], rp.route.Val.sourcePubKey.Val[:])
+	copy(keyBytes[16:], rp.route.sourcePubKey[:])
 
 	return keyBytes[:]
 }
+
+// serializeMCRoute serializes an mcRoute and writes the bytes to the given
+// io.Writer.
+func serializeMCRoute(w io.Writer, r *mcRoute) error {
+	if err := WriteElements(
+		w, r.totalAmount, r.sourcePubKey[:],
+	); err != nil {
+		return err
+	}
+
+	if err := WriteElements(w, uint32(len(r.hops))); err != nil {
+		return err
+	}
+
+	for _, h := range r.hops {
+		if err := serializeNewHop(w, h); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// serializeMCRoute serializes an mcHop and writes the bytes to the given
+// io.Writer.
+func serializeNewHop(w io.Writer, h *mcHop) error {
+	return WriteElements(w,
+		h.pubKeyBytes[:],
+		h.channelID,
+		h.amtToFwd,
+		h.hasBlindingPoint,
+		h.hasCustomRecords,
+	)
+}
diff --git a/channeldb/migration32/route.go b/channeldb/migration32/route.go
index a35338e50..a4d40a45c 100644
--- a/channeldb/migration32/route.go
+++ b/channeldb/migration32/route.go
@@ -29,32 +29,6 @@ const VertexSize = 33
 // public key.
 type Vertex [VertexSize]byte
 
-// Record returns a TLV record that can be used to encode/decode a Vertex
-// to/from a TLV stream.
-func (v *Vertex) Record() tlv.Record {
-	return tlv.MakeStaticRecord(
-		0, v, VertexSize, encodeVertex, decodeVertex,
-	)
-}
-
-func encodeVertex(w io.Writer, val interface{}, _ *[8]byte) error {
-	if b, ok := val.(*Vertex); ok {
-		_, err := w.Write(b[:])
-		return err
-	}
-
-	return tlv.NewTypeForEncodingErr(val, "Vertex")
-}
-
-func decodeVertex(r io.Reader, val interface{}, _ *[8]byte, l uint64) error {
-	if b, ok := val.(*Vertex); ok {
-		_, err := io.ReadFull(r, b[:])
-		return err
-	}
-
-	return tlv.NewTypeForDecodingErr(val, "Vertex", l, VertexSize)
-}
-
 // Route represents a path through the channel graph which runs over one or
 // more channels in succession. This struct carries all the information
 // required to craft the Sphinx onion packet, and send the payment along the
diff --git a/cmd/commands/walletrpc_active.go b/cmd/commands/walletrpc_active.go
index bb5982c78..ff56adf4d 100644
--- a/cmd/commands/walletrpc_active.go
+++ b/cmd/commands/walletrpc_active.go
@@ -1160,8 +1160,7 @@ var fundPsbtCommand = cli.Command{
 	Name:  "fund",
 	Usage: "Fund a Partially Signed Bitcoin Transaction (PSBT).",
 	ArgsUsage: "[--template_psbt=T | [--outputs=O [--inputs=I]]] " +
-		"[--conf_target=C | --sat_per_vbyte=S | --sat_per_kw=K] " +
-		"[--change_type=A]",
+		"[--conf_target=C | --sat_per_vbyte=S] [--change_type=A]",
 	Description: `
 	The fund command creates a fully populated PSBT that contains enough
 	inputs to fund the outputs specified in either the PSBT or the
@@ -1223,11 +1222,6 @@ var fundPsbtCommand = cli.Command{
 			Usage: "a manual fee expressed in sat/vbyte that " +
 				"should be used when creating the transaction",
 		},
-		cli.Uint64Flag{
-			Name: "sat_per_kw",
-			Usage: "a manual fee expressed in sat/kw that " +
-				"should be used when creating the transaction",
-		},
 		cli.StringFlag{
 			Name: "account",
 			Usage: "(optional) the name of the account to use to " +
@@ -1252,12 +1246,6 @@ var fundPsbtCommand = cli.Command{
 			Value: defaultUtxoMinConf,
 		},
 		coinSelectionStrategyFlag,
-		cli.Float64Flag{
-			Name: "max_fee_ratio",
-			Usage: "the maximum fee to total output amount ratio " +
-				"that this psbt should adhere to",
-			Value: chanfunding.DefaultMaxFeeRatio,
-		},
 	},
 	Action: actionDecorator(fundPsbt),
 }
@@ -1314,11 +1302,10 @@ func fundPsbt(ctx *cli.Context) error {
 		)
 
 		if len(ctx.String("outputs")) > 0 {
-			// Parse the address to amount map as JSON now. At least
-			// one entry must be present.
+			// Parse the address to amount map as JSON now. At least one
+			// entry must be present.
 			jsonMap := []byte(ctx.String("outputs"))
-			err := json.Unmarshal(jsonMap, &amountToAddr)
-			if err != nil {
+			if err := json.Unmarshal(jsonMap, &amountToAddr); err != nil {
 				return fmt.Errorf("error parsing outputs "+
 					"JSON: %w", err)
 			}
@@ -1330,8 +1317,7 @@ func fundPsbt(ctx *cli.Context) error {
 			var inputs []string
 
 			jsonList := []byte(ctx.String("inputs"))
-			err := json.Unmarshal(jsonList, &inputs)
-			if err != nil {
+			if err := json.Unmarshal(jsonList, &inputs); err != nil {
 				return fmt.Errorf("error parsing inputs JSON: "+
 					"%v", err)
 			}
@@ -1358,23 +1344,15 @@ func fundPsbt(ctx *cli.Context) error {
 
 	// Parse fee flags.
 	switch {
-	case ctx.IsSet("conf_target") && ctx.IsSet("sat_per_vbyte") ||
-		ctx.IsSet("conf_target") && ctx.IsSet("sat_per_kw") ||
-		ctx.IsSet("sat_per_vbyte") && ctx.IsSet("sat_per_kw"):
-
-		return fmt.Errorf("only one of conf_target, sat_per_vbyte, " +
-			"or sat_per_kw can be set at the same time")
+	case ctx.IsSet("conf_target") && ctx.IsSet("sat_per_vbyte"):
+		return fmt.Errorf("cannot set conf_target and sat_per_vbyte " +
+			"at the same time")
 
 	case ctx.Uint64("sat_per_vbyte") > 0:
 		req.Fees = &walletrpc.FundPsbtRequest_SatPerVbyte{
 			SatPerVbyte: ctx.Uint64("sat_per_vbyte"),
 		}
 
-	case ctx.Uint64("sat_per_kw") > 0:
-		req.Fees = &walletrpc.FundPsbtRequest_SatPerKw{
-			SatPerKw: ctx.Uint64("sat_per_kw"),
-		}
-
 	// Check conf_target last because it has a default value.
 	case ctx.Uint64("conf_target") > 0:
 		req.Fees = &walletrpc.FundPsbtRequest_TargetConf{
@@ -1396,8 +1374,6 @@ func fundPsbt(ctx *cli.Context) error {
 		}
 	}
 
-	req.MaxFeeRatio = ctx.Float64("max_fee_ratio")
-
 	walletClient, cleanUp := getWalletClient(ctx)
 	defer cleanUp()
 
diff --git a/config.go b/config.go
index 5ac4dc307..c8991cf60 100644
--- a/config.go
+++ b/config.go
@@ -59,6 +59,7 @@ const (
 	defaultLogLevel           = "info"
 	defaultLogDirname         = "logs"
 	defaultLogFilename        = "lnd.log"
+	defaultLogCompressor      = build.Gzip
 	defaultRPCPort            = 10009
 	defaultRESTPort           = 8080
 	defaultPeerPort           = 9735
@@ -71,6 +72,8 @@ const (
 	defaultChanEnableTimeout             = 19 * time.Minute
 	defaultChanDisableTimeout            = 20 * time.Minute
 	defaultHeightHintCacheQueryDisable   = false
+	defaultMaxLogFiles                   = 3
+	defaultMaxLogFileSize                = 10
 	defaultMinBackoff                    = time.Second
 	defaultMaxBackoff                    = time.Hour
 	defaultLetsEncryptDirname            = "letsencrypt"
@@ -313,8 +316,9 @@ type Config struct {
 	ReadMacPath     string        `long:"readonlymacaroonpath" description:"Path to write the read-only macaroon for lnd's RPC and REST services if it doesn't exist"`
 	InvoiceMacPath  string        `long:"invoicemacaroonpath" description:"Path to the invoice-only macaroon for lnd's RPC and REST services if it doesn't exist"`
 	LogDir          string        `long:"logdir" description:"Directory to log output."`
-	MaxLogFiles     int           `long:"maxlogfiles" description:"Maximum logfiles to keep (0 for no rotation). DEPRECATED: use --logging.file.max-files instead" hidden:"true"`
-	MaxLogFileSize  int           `long:"maxlogfilesize" description:"Maximum logfile size in MB. DEPRECATED: use --logging.file.max-file-size instead" hidden:"true"`
+	LogCompressor   string        `long:"logcompressor" description:"Compression algorithm to use when rotating logs." choice:"gzip" choice:"zstd"`
+	MaxLogFiles     int           `long:"maxlogfiles" description:"Maximum logfiles to keep (0 for no rotation)"`
+	MaxLogFileSize  int           `long:"maxlogfilesize" description:"Maximum logfile size in MB"`
 	AcceptorTimeout time.Duration `long:"acceptortimeout" description:"Time after which an RPCAcceptor will time out and return false if it hasn't yet received a response"`
 
 	LetsEncryptDir    string `long:"letsencryptdir" description:"The directory to store Let's Encrypt certificates within"`
@@ -560,8 +564,9 @@ func DefaultConfig() Config {
 		LetsEncryptDir:    defaultLetsEncryptDir,
 		LetsEncryptListen: defaultLetsEncryptListen,
 		LogDir:            defaultLogDir,
-		MaxLogFiles:       build.DefaultMaxLogFiles,
-		MaxLogFileSize:    build.DefaultMaxLogFileSize,
+		LogCompressor:     defaultLogCompressor,
+		MaxLogFiles:       defaultMaxLogFiles,
+		MaxLogFileSize:    defaultMaxLogFileSize,
 		AcceptorTimeout:   defaultAcceptorTimeout,
 		WSPingInterval:    lnrpc.DefaultPingInterval,
 		WSPongWait:        lnrpc.DefaultPongWait,
@@ -1398,8 +1403,9 @@ func ValidateConfig(cfg Config, interceptor signal.Interceptor, fileParser,
 		lncfg.NormalizeNetwork(cfg.ActiveNetParams.Name),
 	)
 
-	if err := cfg.LogConfig.Validate(); err != nil {
-		return nil, mkErr("error validating logging config: %w", err)
+	if !build.SuportedLogCompressor(cfg.LogCompressor) {
+		return nil, mkErr("invalid log compressor: %v",
+			cfg.LogCompressor)
 	}
 
 	cfg.SubLogMgr = build.NewSubLoggerManager(build.NewDefaultLogHandlers(
@@ -1415,31 +1421,9 @@ func ValidateConfig(cfg Config, interceptor signal.Interceptor, fileParser,
 			cfg.SubLogMgr.SupportedSubsystems())
 		os.Exit(0)
 	}
-
-	if cfg.MaxLogFiles != build.DefaultMaxLogFiles {
-		if cfg.LogConfig.File.MaxLogFiles !=
-			build.DefaultMaxLogFiles {
-
-			return nil, mkErr("cannot set both maxlogfiles and "+
-				"logging.file.max-files", err)
-		}
-
-		cfg.LogConfig.File.MaxLogFiles = cfg.MaxLogFiles
-	}
-	if cfg.MaxLogFileSize != build.DefaultMaxLogFileSize {
-		if cfg.LogConfig.File.MaxLogFileSize !=
-			build.DefaultMaxLogFileSize {
-
-			return nil, mkErr("cannot set both maxlogfilesize and "+
-				"logging.file.max-file-size", err)
-		}
-
-		cfg.LogConfig.File.MaxLogFileSize = cfg.MaxLogFileSize
-	}
-
 	err = cfg.LogRotator.InitLogRotator(
-		cfg.LogConfig.File,
 		filepath.Join(cfg.LogDir, defaultLogFilename),
+		cfg.LogCompressor, cfg.MaxLogFileSize, cfg.MaxLogFiles,
 	)
 	if err != nil {
 		str := "log rotation setup failed: %v"
diff --git a/docs/release-notes/release-notes-0.19.0.md b/docs/release-notes/release-notes-0.19.0.md
index 2bbcc4d58..3b20a054e 100644
--- a/docs/release-notes/release-notes-0.19.0.md
+++ b/docs/release-notes/release-notes-0.19.0.md
@@ -48,32 +48,16 @@
   `BumpForceCloseFee` which moves the functionality soley available in the
   `lncli` to LND hence making it more universal.
 
-* [The `walletrpc.FundPsbt` RPC method now has an option to specify the fee as
-  `sat_per_kw` which allows for more precise
-  fees](https://github.com/lightningnetwork/lnd/pull/9013).
-
-* [The `walletrpc.FundPsbt` method now has a new option to specify the maximum
-  fee to output amounts ratio.](https://github.com/lightningnetwork/lnd/pull/8600)
-
 ## lncli Additions
 
 * [A pre-generated macaroon root key can now be specified in `lncli create` and
   `lncli createwatchonly`](https://github.com/lightningnetwork/lnd/pull/9172) to
   allow for deterministic macaroon generation.
 
-* [The `lncli wallet fundpsbt` sub command now has a `--sat_per_kw` flag to
-  specify more precise fee
-  rates](https://github.com/lightningnetwork/lnd/pull/9013).
-
-* The `lncli wallet fundpsbt` command now has a [`--max_fee_ratio` argument to
-  specify the max fees to output amounts ratio.](https://github.com/lightningnetwork/lnd/pull/8600)
-
 # Improvements
 ## Functional Updates
 
-* [Allow](https://github.com/lightningnetwork/lnd/pull/9017) the compression of 
-  logs during rotation with ZSTD via the `logging.file.compressor` startup 
-  argument.
+* [Allow](https://github.com/lightningnetwork/lnd/pull/9017) the compression of logs during rotation with ZSTD via the `logcompressor` startup argument.
 
 * The SCB file now [contains more data][https://github.com/lightningnetwork/lnd/pull/8183]
   that enable a last resort rescue for certain cases where the peer is no longer
@@ -87,10 +71,6 @@
 
 ## Code Health
 
-* [Add retry logic](https://github.com/lightningnetwork/lnd/pull/8381) for
-  watchtower block fetching with a max number of attempts and exponential
-  back-off.
-
 * [Moved](https://github.com/lightningnetwork/lnd/pull/9138) profile related
   config settings to its own dedicated group. The old ones still work but will
   be removed in a future release.
@@ -108,14 +88,6 @@
   Finally, the new `--logging.console.style` option can be used under the `dev` 
   build tag to add styling to console logging.
  
-* [Add max files and max file size](https://github.com/lightningnetwork/lnd/pull/9233) 
-  options to the `logging` config namespace under new `--logging.file.max-files` 
-  and `--logging.files.max-file-size` options. The old options (`--maxlogfiles` 
-  and `--maxlogfilesize`) will still work but deprecation notices have been 
-  added and they will be removed in a future release. The defaults values for 
-  these options have also been increased from max 3 log files to 10 and from 
-  max 10 MB to 20 MB. 
- 
 ## Breaking Changes
 ## Performance Improvements
 
@@ -136,8 +108,7 @@
 
 * [Migrate the mission control 
   store](https://github.com/lightningnetwork/lnd/pull/8911) to use a more 
-  minimal encoding for payment attempt routes as well as use [pure TLV 
-  encoding](https://github.com/lightningnetwork/lnd/pull/9167).
+  minimal encoding for payment attempt routes.
 
 * [Migrate the mission control 
   store](https://github.com/lightningnetwork/lnd/pull/9001) so that results are 
@@ -153,11 +124,9 @@
 
 # Contributors (Alphabetical Order)
 
-* Animesh Bilthare
 * Boris Nagaev
 * CharlieZKSmith
 * Elle Mouton
-* George Tsagkarelis
 * Pins
 * Viktor Tigerström
 * Ziggie
diff --git a/fn/either.go b/fn/either.go
index f85104385..19a7ec171 100644
--- a/fn/either.go
+++ b/fn/either.go
@@ -20,7 +20,7 @@ func NewRight[L any, R any](r R) Either[L, R] {
 // ElimEither is the universal Either eliminator. It can be used to safely
 // handle all possible values inside the Either by supplying two continuations,
 // one for each side of the Either.
-func ElimEither[L, R, O any](f func(L) O, g func(R) O, e Either[L, R]) O {
+func ElimEither[L, R, O any](e Either[L, R], f func(L) O, g func(R) O) O {
 	if !e.isRight {
 		return f(e.left)
 	}
@@ -52,9 +52,9 @@ func (e Either[L, R]) IsRight() bool {
 	return e.isRight
 }
 
-// LeftToOption converts a Left value to an Option, returning None if the inner
+// LeftToSome converts a Left value to an Option, returning None if the inner
 // Either value is a Right value.
-func (e Either[L, R]) LeftToOption() Option[L] {
+func (e Either[L, R]) LeftToSome() Option[L] {
 	if e.isRight {
 		return None[L]()
 	}
@@ -62,9 +62,9 @@ func (e Either[L, R]) LeftToOption() Option[L] {
 	return Some(e.left)
 }
 
-// RightToOption converts a Right value to an Option, returning None if the
+// RightToSome converts a Right value to an Option, returning None if the
 // inner Either value is a Left value.
-func (e Either[L, R]) RightToOption() Option[R] {
+func (e Either[L, R]) RightToSome() Option[R] {
 	if !e.isRight {
 		return None[R]()
 	}
diff --git a/fn/fn.go b/fn/fn.go
index 147bf7daf..ea9190b7f 100644
--- a/fn/fn.go
+++ b/fn/fn.go
@@ -23,7 +23,7 @@ func Iden[A any](a A) A {
 // Const is a function that accepts an argument and returns a function that
 // always returns that value irrespective of the returned function's argument.
 // This is also quite useful in conjunction with higher order functions.
-func Const[A, B any](a A) func(B) A {
+func Const[B, A any](a A) func(B) A {
 	return func(_ B) A {
 		return a
 	}
diff --git a/fn/option.go b/fn/option.go
index f1a6c858c..f02f82c8a 100644
--- a/fn/option.go
+++ b/fn/option.go
@@ -1,9 +1,14 @@
 package fn
 
-import "testing"
+import (
+	"fmt"
+	"testing"
 
-// Option represents a value which may or may not be there. This is very often
-// preferable to nil-able pointers.
+	"github.com/stretchr/testify/require"
+)
+
+// Option[A] represents a value which may or may not be there. This is very
+// often preferable to nil-able pointers.
 type Option[A any] struct {
 	isSome bool
 	some   A
@@ -26,17 +31,6 @@ func None[A any]() Option[A] {
 	return Option[A]{}
 }
 
-// OptionFromPtr constructs an option from a pointer.
-//
-// OptionFromPtr : *A -> Option[A].
-func OptionFromPtr[A any](a *A) Option[A] {
-	if a == nil {
-		return None[A]()
-	}
-
-	return Some[A](*a)
-}
-
 // ElimOption is the universal Option eliminator. It can be used to safely
 // handle all possible values inside the Option by supplying two continuations.
 //
@@ -72,14 +66,9 @@ func (o Option[A]) UnwrapOrFunc(f func() A) A {
 func (o Option[A]) UnwrapOrFail(t *testing.T) A {
 	t.Helper()
 
-	if o.isSome {
-		return o.some
-	}
-
-	t.Fatalf("Option[%T] was None()", o.some)
+	require.True(t, o.isSome, "Option[%T] was None()", o.some)
 
-	var zero A
-	return zero
+	return o.some
 }
 
 // UnwrapOrErr is used to extract a value from an option, if the option is
@@ -144,11 +133,11 @@ func FlattenOption[A any](oo Option[Option[A]]) Option[A] {
 	return oo.some
 }
 
-// ChainOption transforms a function A -> Option[B] into one that accepts an
+// FlatMapOption transforms a function A -> Option[B] into one that accepts an
 // Option[A] as an argument.
 //
-// ChainOption : (A -> Option[B]) -> Option[A] -> Option[B].
-func ChainOption[A, B any](f func(A) Option[B]) func(Option[A]) Option[B] {
+// FlatMapOption : (A -> Option[B]) -> Option[A] -> Option[B].
+func FlatMapOption[A, B any](f func(A) Option[B]) func(Option[A]) Option[B] {
 	return func(o Option[A]) Option[B] {
 		if o.isSome {
 			return f(o.some)
@@ -225,9 +214,9 @@ func (o Option[A]) UnsafeFromSome() A {
 	panic("Option was None()")
 }
 
-// OptionToLeft can be used to convert an Option value into an Either, by
+// SomeToLeft can be used to convert an Option value into an Either, by
 // providing the Right value that should be used if the Option value is None.
-func OptionToLeft[O, L, R any](o Option[O], r R) Either[O, R] {
+func SomeToLeft[O, R any](o Option[O], r R) Either[O, R] {
 	if o.IsSome() {
 		return NewLeft[O, R](o.some)
 	}
@@ -235,12 +224,42 @@ func OptionToLeft[O, L, R any](o Option[O], r R) Either[O, R] {
 	return NewRight[O, R](r)
 }
 
-// OptionToRight can be used to convert an Option value into an Either, by
+// SomeToRight can be used to convert an Option value into an Either, by
 // providing the Left value that should be used if the Option value is None.
-func OptionToRight[O, L, R any](o Option[O], l L) Either[L, O] {
+func SomeToRight[O, L any](o Option[O], l L) Either[L, O] {
 	if o.IsSome() {
 		return NewRight[L, O](o.some)
 	}
 
 	return NewLeft[L, O](l)
 }
+
+// SomeToOk allows you to convert an Option value to a Result with your own
+// error. If the Option contained a Some, then the supplied error is ignored
+// and Some is converted to Ok.
+func (o Option[A]) SomeToOk(err error) Result[A] {
+	return Result[A]{
+		SomeToLeft(o, err),
+	}
+}
+
+// SomeToOkf allows you to convert an Option value to a Result with your own
+// error message. If the Option contains a Some, then the supplied message is
+// ignored and Some is converted to Ok.
+func (o Option[A]) SomeToOkf(errString string, args ...interface{}) Result[A] {
+	return Result[A]{
+		SomeToLeft(o, fmt.Errorf(errString, args...)),
+	}
+}
+
+// TransposeOptRes transposes the Option[Result[A]] into a Result[Option[A]].
+// This has the effect of leaving an A value alone while inverting the Option
+// and Result layers. If there is no internal A value, it will convert the
+// non-success value to the proper one in the transposition.
+func TransposeOptRes[A any](o Option[Result[A]]) Result[Option[A]] {
+	if o.IsNone() {
+		return Ok(None[A]())
+	}
+
+	return Result[Option[A]]{MapLeft[A, error](Some[A])(o.some.Either)}
+}
diff --git a/fn/result.go b/fn/result.go
index 93d2dd7d6..37958f26c 100644
--- a/fn/result.go
+++ b/fn/result.go
@@ -3,6 +3,8 @@ package fn
 import (
 	"fmt"
 	"testing"
+
+	"github.com/stretchr/testify/require"
 )
 
 // Result represents a value that can either be a success (T) or an error.
@@ -62,27 +64,35 @@ func (r Result[T]) IsErr() bool {
 	return r.IsRight()
 }
 
-// Map applies a function to the success value if it exists.
-func (r Result[T]) Map(f func(T) T) Result[T] {
+// MapOk applies an endomorphic function to the success value if it exists.
+func (r Result[T]) MapOk(f func(T) T) Result[T] {
 	return Result[T]{
 		MapLeft[T, error](f)(r.Either),
 	}
 }
 
-// MapErr applies a function to the error value if it exists.
+// MapErr applies an endomorphic function to the error value if it exists.
 func (r Result[T]) MapErr(f func(error) error) Result[T] {
 	return Result[T]{
 		MapRight[T](f)(r.Either),
 	}
 }
 
-// Option returns the success value as an Option.
-func (r Result[T]) Option() Option[T] {
-	return r.Either.LeftToOption()
+// MapOk applies a non-endomorphic function to the success value if it exists
+// and returns a Result of the new type.
+func MapOk[A, B any](f func(A) B) func(Result[A]) Result[B] {
+	return func(r Result[A]) Result[B] {
+		return Result[B]{MapLeft[A, error](f)(r.Either)}
+	}
+}
+
+// OkToSome mutes the error value of the result.
+func (r Result[T]) OkToSome() Option[T] {
+	return r.Either.LeftToSome()
 }
 
-// WhenResult executes the given function if the Result is a success.
-func (r Result[T]) WhenResult(f func(T)) {
+// WhenOk executes the given function if the Result is a success.
+func (r Result[T]) WhenOk(f func(T)) {
 	r.WhenLeft(f)
 }
 
@@ -102,9 +112,9 @@ func (r Result[T]) UnwrapOr(defaultValue T) T {
 
 // UnwrapOrElse returns the success value or computes a value from a function
 // if it's an error.
-func (r Result[T]) UnwrapOrElse(f func() T) T {
+func (r Result[T]) UnwrapOrElse(f func(error) T) T {
 	if r.IsErr() {
-		return f()
+		return f(r.right)
 	}
 
 	return r.left
@@ -114,17 +124,29 @@ func (r Result[T]) UnwrapOrElse(f func() T) T {
 func (r Result[T]) UnwrapOrFail(t *testing.T) T {
 	t.Helper()
 
+	require.True(
+		t, r.IsOk(), "Result[%T] contained error: %v", r.left, r.right,
+	)
+
+	return r.left
+}
+
+// FlattenResult takes a nested Result and joins the two functor layers into
+// one.
+func FlattenResult[A any](r Result[Result[A]]) Result[A] {
 	if r.IsErr() {
-		t.Fatalf("Result[%T] contained error: %v", r.left, r.right)
+		return Err[A](r.right)
 	}
 
-	var zero T
+	if r.left.IsErr() {
+		return Err[A](r.left.right)
+	}
 
-	return zero
+	return r.left
 }
 
-// FlatMap applies a function that returns a Result to the success value if it
-// exists.
+// FlatMap applies a kleisli endomorphic function that returns a Result to the
+// success value if it exists.
 func (r Result[T]) FlatMap(f func(T) Result[T]) Result[T] {
 	if r.IsOk() {
 		return r
@@ -143,17 +165,17 @@ func (r Result[T]) AndThen(f func(T) Result[T]) Result[T] {
 // OrElse returns the original Result if it is a success, otherwise it returns
 // the provided alternative Result. This along with AndThen can be used to
 // Railway Oriented Programming (ROP).
-func (r Result[T]) OrElse(f func() Result[T]) Result[T] {
+func (r Result[T]) OrElse(f func(error) Result[T]) Result[T] {
 	if r.IsOk() {
 		return r
 	}
 
-	return f()
+	return f(r.right)
 }
 
-// FlatMap applies a function that returns a Result[B] to the success value if
-// it exists.
-func FlatMap[A, B any](r Result[A], f func(A) Result[B]) Result[B] {
+// FlatMapResult applies a function that returns a Result[B] to the success
+// value if it exists.
+func FlatMapResult[A, B any](r Result[A], f func(A) Result[B]) Result[B] {
 	if r.IsOk() {
 		return f(r.left)
 	}
@@ -164,17 +186,45 @@ func FlatMap[A, B any](r Result[A], f func(A) Result[B]) Result[B] {
 // AndThen is an alias for FlatMap. This along with OrElse can be used to
 // Railway Oriented Programming (ROP).
 func AndThen[A, B any](r Result[A], f func(A) Result[B]) Result[B] {
-	return FlatMap(r, f)
+	return FlatMapResult(r, f)
 }
 
-// AndThen2 applies a function that returns a Result[C] to the success values
-// of two Result types if both exist.
-func AndThen2[A, B, C any](ra Result[A], rb Result[B],
-	f func(A, B) Result[C]) Result[C] {
+// LiftA2Result lifts a two-argument function to a function that can operate
+// over results of its arguments.
+func LiftA2Result[A, B, C any](f func(A, B) C,
+) func(Result[A], Result[B]) Result[C] {
+
+	return func(ra Result[A], rb Result[B]) Result[C] {
+		if ra.IsErr() {
+			return Err[C](ra.right)
+		}
+
+		if rb.IsErr() {
+			return Err[C](rb.right)
+		}
+
+		return Ok(f(ra.left, rb.left))
+	}
+}
+
+// Sink consumes a Result, either propagating its error or processing its
+// success value with a function that can fail.
+func (r Result[A]) Sink(f func(A) error) error {
+	if r.IsErr() {
+		return r.right
+	}
+
+	return f(r.left)
+}
+
+// TransposeResOpt transposes the Result[Option[A]] into a Option[Result[A]].
+// This has the effect of leaving an A value alone while inverting the Result
+// and Option layers. If there is no internal A value, it will convert the
+// non-success value to the proper one in the transposition.
+func TransposeResOpt[A any](r Result[Option[A]]) Option[Result[A]] {
+	if r.IsErr() {
+		return Some(Err[A](r.right))
+	}
 
-	return AndThen(ra, func(a A) Result[C] {
-		return AndThen(rb, func(b B) Result[C] {
-			return f(a, b)
-		})
-	})
+	return MapOption(Ok[A])(r.left)
 }
diff --git a/fn/slice.go b/fn/slice.go
index 3b25b32a1..afd8e0f7f 100644
--- a/fn/slice.go
+++ b/fn/slice.go
@@ -17,7 +17,7 @@ type Number interface {
 
 // All returns true when the supplied predicate evaluates to true for all of
 // the values in the slice.
-func All[A any](pred func(A) bool, s []A) bool {
+func All[A any](s []A, pred Pred[A]) bool {
 	for _, val := range s {
 		if !pred(val) {
 			return false
@@ -29,7 +29,7 @@ func All[A any](pred func(A) bool, s []A) bool {
 
 // Any returns true when the supplied predicate evaluates to true for any of
 // the values in the slice.
-func Any[A any](pred func(A) bool, s []A) bool {
+func Any[A any](s []A, pred Pred[A]) bool {
 	for _, val := range s {
 		if pred(val) {
 			return true
@@ -41,7 +41,7 @@ func Any[A any](pred func(A) bool, s []A) bool {
 
 // Map applies the function argument to all members of the slice and returns a
 // slice of those return values.
-func Map[A, B any](f func(A) B, s []A) []B {
+func Map[A, B any](s []A, f func(A) B) []B {
 	res := make([]B, 0, len(s))
 
 	for _, val := range s {
@@ -53,7 +53,7 @@ func Map[A, B any](f func(A) B, s []A) []B {
 
 // Filter creates a new slice of values where all the members of the returned
 // slice pass the predicate that is supplied in the argument.
-func Filter[A any](pred Pred[A], s []A) []A {
+func Filter[A any](s []A, pred Pred[A]) []A {
 	res := make([]A, 0)
 
 	for _, val := range s {
@@ -65,10 +65,38 @@ func Filter[A any](pred Pred[A], s []A) []A {
 	return res
 }
 
+// FilterMap takes a function argument that optionally produces a value and
+// returns a slice of the 'Some' return values.
+func FilterMap[A, B any](as []A, f func(A) Option[B]) []B {
+	var bs []B
+
+	for _, a := range as {
+		f(a).WhenSome(func(b B) {
+			bs = append(bs, b)
+		})
+	}
+
+	return bs
+}
+
+// TrimNones takes a slice of Option values and returns a slice of the Some
+// values in it.
+func TrimNones[A any](as []Option[A]) []A {
+	var somes []A
+
+	for _, a := range as {
+		a.WhenSome(func(b A) {
+			somes = append(somes, b)
+		})
+	}
+
+	return somes
+}
+
 // Foldl iterates through all members of the slice left to right and reduces
 // them pairwise with an accumulator value that is seeded with the seed value in
 // the argument.
-func Foldl[A, B any](f func(B, A) B, seed B, s []A) B {
+func Foldl[A, B any](seed B, s []A, f func(B, A) B) B {
 	acc := seed
 
 	for _, val := range s {
@@ -80,7 +108,7 @@ func Foldl[A, B any](f func(B, A) B, seed B, s []A) B {
 
 // Foldr, is exactly like Foldl except that it iterates over the slice from
 // right to left.
-func Foldr[A, B any](f func(A, B) B, seed B, s []A) B {
+func Foldr[A, B any](seed B, s []A, f func(A, B) B) B {
 	acc := seed
 
 	for i := range s {
@@ -92,7 +120,7 @@ func Foldr[A, B any](f func(A, B) B, seed B, s []A) B {
 
 // Find returns the first value that passes the supplied predicate, or None if
 // the value wasn't found.
-func Find[A any](pred Pred[A], s []A) Option[A] {
+func Find[A any](s []A, pred Pred[A]) Option[A] {
 	for _, val := range s {
 		if pred(val) {
 			return Some(val)
@@ -104,7 +132,7 @@ func Find[A any](pred Pred[A], s []A) Option[A] {
 
 // FindIdx returns the first value that passes the supplied predicate along with
 // its index in the slice. If no satisfactory value is found, None is returned.
-func FindIdx[A any](pred Pred[A], s []A) Option[T2[int, A]] {
+func FindIdx[A any](s []A, pred Pred[A]) Option[T2[int, A]] {
 	for i, val := range s {
 		if pred(val) {
 			return Some(NewT2[int, A](i, val))
@@ -116,16 +144,14 @@ func FindIdx[A any](pred Pred[A], s []A) Option[T2[int, A]] {
 
 // Elem returns true if the element in the argument is found in the slice
 func Elem[A comparable](a A, s []A) bool {
-	return Any(Eq(a), s)
+	return Any(s, Eq(a))
 }
 
 // Flatten takes a slice of slices and returns a concatenation of those slices.
 func Flatten[A any](s [][]A) []A {
-	sz := Foldr(
-		func(l []A, acc uint64) uint64 {
-			return uint64(len(l)) + acc
-		}, 0, s,
-	)
+	sz := Foldr(0, s, func(l []A, acc uint64) uint64 {
+		return uint64(len(l)) + acc
+	})
 
 	res := make([]A, 0, sz)
 
@@ -150,7 +176,7 @@ func Replicate[A any](n uint, val A) []A {
 // Span, applied to a predicate and a slice, returns two slices where the first
 // element is the longest prefix (possibly empty) of slice elements that
 // satisfy the predicate and second element is the remainder of the slice.
-func Span[A any](pred func(A) bool, s []A) ([]A, []A) {
+func Span[A any](s []A, pred Pred[A]) ([]A, []A) {
 	for i := range s {
 		if !pred(s[i]) {
 			fst := make([]A, i)
@@ -183,7 +209,7 @@ func SplitAt[A any](n uint, s []A) ([]A, []A) {
 
 // ZipWith combines slice elements with the same index using the function
 // argument, returning a slice of the results.
-func ZipWith[A, B, C any](f func(A, B) C, a []A, b []B) []C {
+func ZipWith[A, B, C any](a []A, b []B, f func(A, B) C) []C {
 	var l uint
 
 	if la, lb := len(a), len(b); la < lb {
@@ -218,9 +244,9 @@ func SliceToMap[A any, K comparable, V any](s []A, keyFunc func(A) K,
 
 // Sum calculates the sum of a slice of numbers, `items`.
 func Sum[B Number](items []B) B {
-	return Foldl(func(a, b B) B {
+	return Foldl(0, items, func(a, b B) B {
 		return a + b
-	}, 0, items)
+	})
 }
 
 // HasDuplicates checks if the given slice contains any duplicate elements.
@@ -233,9 +259,7 @@ func HasDuplicates[A comparable](items []A) bool {
 // ForEachConc maps the argument function over the slice, spawning a new
 // goroutine for each element in the slice and then awaits all results before
 // returning them.
-func ForEachConc[A, B any](f func(A) B,
-	as []A) []B {
-
+func ForEachConc[A, B any](as []A, f func(A) B) []B {
 	var wait sync.WaitGroup
 	ctx := context.Background()
 
@@ -318,3 +342,69 @@ func Unsnoc[A any](items []A) Option[T2[[]A, A]] {
 func Len[A any](items []A) uint {
 	return uint(len(items))
 }
+
+// CollectOptions collects a list of Options into a single Option of the list of
+// Some values in it. If there are any Nones present it will return None.
+func CollectOptions[A any](options []Option[A]) Option[[]A] {
+	// We intentionally do a separate None checking pass here to avoid
+	// allocating a new slice for the values until we're sure we need to.
+	for _, r := range options {
+		if r.IsNone() {
+			return None[[]A]()
+		}
+	}
+
+	// Now that we're sure we have no Nones, we can just do an unchecked
+	// index into the some value of the option.
+	return Some(Map(options, func(o Option[A]) A { return o.some }))
+}
+
+// CollectResults collects a list of Results into a single Result of the list of
+// Ok values in it. If there are any errors present it will return the first
+// error encountered.
+func CollectResults[A any](results []Result[A]) Result[[]A] {
+	// We intentionally do a separate error checking pass here to avoid
+	// allocating a new slice for the results until we're sure we need to.
+	for _, r := range results {
+		if r.IsErr() {
+			return Err[[]A](r.right)
+		}
+	}
+
+	// Now that we're sure we have no errors, we can just do an unchecked
+	// index into the left side of the result.
+	return Ok(Map(results, func(r Result[A]) A { return r.left }))
+}
+
+// TraverseOption traverses a slice of A values, applying the provided
+// function to each, collecting the results into an Option of a slice of B
+// values. If any of the results are None, the entire result is None.
+func TraverseOption[A, B any](as []A, f func(A) Option[B]) Option[[]B] {
+	var bs []B
+	for _, a := range as {
+		b := f(a)
+		if b.IsNone() {
+			return None[[]B]()
+		}
+		bs = append(bs, b.some)
+	}
+
+	return Some(bs)
+}
+
+// TraverseResult traverses a slice of A values, applying the provided
+// function to each, collecting the results into a Result of a slice of B
+// values. If any of the results are Err, the entire result is the first
+// error encountered.
+func TraverseResult[A, B any](as []A, f func(A) Result[B]) Result[[]B] {
+	var bs []B
+	for _, a := range as {
+		b := f(a)
+		if b.IsErr() {
+			return Err[[]B](b.right)
+		}
+		bs = append(bs, b.left)
+	}
+
+	return Ok(bs)
+}
diff --git a/go.mod b/go.mod
index e0bda2c29..692e5ad75 100644
--- a/go.mod
+++ b/go.mod
@@ -37,13 +37,13 @@ require (
 	github.com/lightningnetwork/lnd/cert v1.2.2
 	github.com/lightningnetwork/lnd/clock v1.1.1
 	github.com/lightningnetwork/lnd/fn v1.2.3
-	github.com/lightningnetwork/lnd/healthcheck v1.2.6
-	github.com/lightningnetwork/lnd/kvdb v1.4.11
+	github.com/lightningnetwork/lnd/healthcheck v1.2.5
+	github.com/lightningnetwork/lnd/kvdb v1.4.10
 	github.com/lightningnetwork/lnd/queue v1.1.1
-	github.com/lightningnetwork/lnd/sqldb v1.0.5
+	github.com/lightningnetwork/lnd/sqldb v1.0.4
 	github.com/lightningnetwork/lnd/ticker v1.1.1
 	github.com/lightningnetwork/lnd/tlv v1.2.6
-	github.com/lightningnetwork/lnd/tor v1.1.4
+	github.com/lightningnetwork/lnd/tor v1.1.2
 	github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796
 	github.com/miekg/dns v1.1.43
 	github.com/pkg/errors v0.9.1
diff --git a/go.sum b/go.sum
index 0cf08569c..d0f1882f3 100644
--- a/go.sum
+++ b/go.sum
@@ -458,20 +458,20 @@ github.com/lightningnetwork/lnd/clock v1.1.1 h1:OfR3/zcJd2RhH0RU+zX/77c0ZiOnIMsD
 github.com/lightningnetwork/lnd/clock v1.1.1/go.mod h1:mGnAhPyjYZQJmebS7aevElXKTFDuO+uNFFfMXK1W8xQ=
 github.com/lightningnetwork/lnd/fn v1.2.3 h1:Q1OrgNSgQynVheBNa16CsKVov1JI5N2AR6G07x9Mles=
 github.com/lightningnetwork/lnd/fn v1.2.3/go.mod h1:SyFohpVrARPKH3XVAJZlXdVe+IwMYc4OMAvrDY32kw0=
-github.com/lightningnetwork/lnd/healthcheck v1.2.6 h1:1sWhqr93GdkWy4+6U7JxBfcyZIE78MhIHTJZfPx7qqI=
-github.com/lightningnetwork/lnd/healthcheck v1.2.6/go.mod h1:Mu02um4CWY/zdTOvFje7WJgJcHyX2zq/FG3MhOAiGaQ=
-github.com/lightningnetwork/lnd/kvdb v1.4.11 h1:fk1HMVFrsVK3xqU7q+JWHRgBltw/a2qIg1E3zazMb/8=
-github.com/lightningnetwork/lnd/kvdb v1.4.11/go.mod h1:a5cMDKMjbJA8dD06ZqqnYkmSh5DhEbbG8C1YHM3NN+k=
+github.com/lightningnetwork/lnd/healthcheck v1.2.5 h1:aTJy5xeBpcWgRtW/PGBDe+LMQEmNm/HQewlQx2jt7OA=
+github.com/lightningnetwork/lnd/healthcheck v1.2.5/go.mod h1:G7Tst2tVvWo7cx6mSBEToQC5L1XOGxzZTPB29g9Rv2I=
+github.com/lightningnetwork/lnd/kvdb v1.4.10 h1:vK89IVv1oVH9ubQWU+EmoCQFeVRaC8kfmOrqHbY5zoY=
+github.com/lightningnetwork/lnd/kvdb v1.4.10/go.mod h1:J2diNABOoII9UrMnxXS5w7vZwP7CA1CStrl8MnIrb3A=
 github.com/lightningnetwork/lnd/queue v1.1.1 h1:99ovBlpM9B0FRCGYJo6RSFDlt8/vOkQQZznVb18iNMI=
 github.com/lightningnetwork/lnd/queue v1.1.1/go.mod h1:7A6nC1Qrm32FHuhx/mi1cieAiBZo5O6l8IBIoQxvkz4=
-github.com/lightningnetwork/lnd/sqldb v1.0.5 h1:ax5vBPf44tN/uD6C5+hBPBjOJ7cRMrUL+sVOdzmLVt4=
-github.com/lightningnetwork/lnd/sqldb v1.0.5/go.mod h1:OG09zL/PHPaBJefp4HsPz2YLUJ+zIQHbpgCtLnOx8I4=
+github.com/lightningnetwork/lnd/sqldb v1.0.4 h1:9cMwPxcrLQG8UmyZO4q8SpR7NmxSwBMbj3AispdcwHg=
+github.com/lightningnetwork/lnd/sqldb v1.0.4/go.mod h1:4cQOkdymlZ1znnjuRNvMoatQGJkRneTj2CoPSPaQhWo=
 github.com/lightningnetwork/lnd/ticker v1.1.1 h1:J/b6N2hibFtC7JLV77ULQp++QLtCwT6ijJlbdiZFbSM=
 github.com/lightningnetwork/lnd/ticker v1.1.1/go.mod h1:waPTRAAcwtu7Ji3+3k+u/xH5GHovTsCoSVpho0KDvdA=
 github.com/lightningnetwork/lnd/tlv v1.2.6 h1:icvQG2yDr6k3ZuZzfRdG3EJp6pHurcuh3R6dg0gv/Mw=
 github.com/lightningnetwork/lnd/tlv v1.2.6/go.mod h1:/CmY4VbItpOldksocmGT4lxiJqRP9oLxwSZOda2kzNQ=
-github.com/lightningnetwork/lnd/tor v1.1.4 h1:TUW27EXqoZCcCAQPlD4aaDfh8jMbBS9CghNz50qqwtA=
-github.com/lightningnetwork/lnd/tor v1.1.4/go.mod h1:qSRB8llhAK+a6kaTPWOLLXSZc6Hg8ZC0mq1sUQ/8JfI=
+github.com/lightningnetwork/lnd/tor v1.1.2 h1:3zv9z/EivNFaMF89v3ciBjCS7kvCj4ZFG7XvD2Qq0/k=
+github.com/lightningnetwork/lnd/tor v1.1.2/go.mod h1:j7T9uJ2NLMaHwE7GiBGnpYLn4f7NRoTM6qj+ul6/ycA=
 github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw=
 github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY=
 github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA=
diff --git a/htlcswitch/link.go b/htlcswitch/link.go
index 383a28546..3532a2318 100644
--- a/htlcswitch/link.go
+++ b/htlcswitch/link.go
@@ -3793,8 +3793,7 @@ func (l *channelLink) processExitHop(add lnwire.UpdateAddHTLC,
 	// ADD, nor will we settle the corresponding invoice or respond with the
 	// preimage.
 	if l.cfg.HodlMask.Active(hodl.ExitSettle) {
-		l.log.Warnf("%s for htlc(rhash=%x,htlcIndex=%v)",
-			hodl.ExitSettle.Warning(), add.PaymentHash, add.ID)
+		l.log.Warnf(hodl.ExitSettle.Warning())
 
 		return nil
 	}
diff --git a/lnrpc/routerrpc/router.pb.go b/lnrpc/routerrpc/router.pb.go
index a8fa5b0d4..f74fb9d3f 100644
--- a/lnrpc/routerrpc/router.pb.go
+++ b/lnrpc/routerrpc/router.pb.go
@@ -3253,14 +3253,6 @@ type ForwardHtlcInterceptResponse struct {
 	// Any custom records that should be set on the p2p wire message message of
 	// the resumed HTLC. This field is ignored if the action is not
 	// RESUME_MODIFIED.
-	//
-	// If this map is populated, it will overwrite any of the wire custom
-	// records set by LND. It is the caller's responsibility to copy any desired
-	// records across. If the map is empty, no action will be taken and existing
-	// custom records will be propagated.
-	//
-	// The API does not currently support deleting custom records, unless they
-	// are overwritten by a new set.
 	OutWireCustomRecords map[uint64][]byte `protobuf:"bytes,8,rep,name=out_wire_custom_records,json=outWireCustomRecords,proto3" json:"out_wire_custom_records,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
 }
 
diff --git a/lnrpc/routerrpc/router.proto b/lnrpc/routerrpc/router.proto
index 6eb928e31..92da75192 100644
--- a/lnrpc/routerrpc/router.proto
+++ b/lnrpc/routerrpc/router.proto
@@ -1063,14 +1063,6 @@ message ForwardHtlcInterceptResponse {
     // Any custom records that should be set on the p2p wire message message of
     // the resumed HTLC. This field is ignored if the action is not
     // RESUME_MODIFIED.
-    //
-    // If this map is populated, it will overwrite any of the wire custom
-    // records set by LND. It is the caller's responsibility to copy any desired
-    // records across. If the map is empty, no action will be taken and existing
-    // custom records will be propagated.
-    //
-    // The API does not currently support deleting custom records, unless they
-    // are overwritten by a new set.
     map<uint64, bytes> out_wire_custom_records = 8;
 }
 
diff --git a/lnrpc/routerrpc/router.swagger.json b/lnrpc/routerrpc/router.swagger.json
index 157e2e7bb..b838f475d 100644
--- a/lnrpc/routerrpc/router.swagger.json
+++ b/lnrpc/routerrpc/router.swagger.json
@@ -1525,7 +1525,7 @@
             "type": "string",
             "format": "byte"
           },
-          "description": "Any custom records that should be set on the p2p wire message message of\nthe resumed HTLC. This field is ignored if the action is not\nRESUME_MODIFIED.\n\nIf this map is populated, it will overwrite any of the wire custom\nrecords set by LND. It is the caller's responsibility to copy any desired\nrecords across. If the map is empty, no action will be taken and existing\ncustom records will be propagated.\n\nThe API does not currently support deleting custom records, unless they\nare overwritten by a new set."
+          "description": "Any custom records that should be set on the p2p wire message message of\nthe resumed HTLC. This field is ignored if the action is not\nRESUME_MODIFIED."
         }
       },
       "description": "*\nForwardHtlcInterceptResponse enables the caller to resolve a previously hold\nforward. The caller can choose either to:\n- `Resume`: Execute the default behavior (usually forward).\n- `ResumeModified`: Execute the default behavior (usually forward) with HTLC\nfield modifications.\n- `Reject`: Fail the htlc backwards.\n- `Settle`: Settle this htlc with a given preimage."
diff --git a/lnrpc/walletrpc/walletkit.pb.go b/lnrpc/walletrpc/walletkit.pb.go
index dad0aac60..4976f2186 100644
--- a/lnrpc/walletrpc/walletkit.pb.go
+++ b/lnrpc/walletrpc/walletkit.pb.go
@@ -3645,7 +3645,6 @@ type FundPsbtRequest struct {
 	//
 	//	*FundPsbtRequest_TargetConf
 	//	*FundPsbtRequest_SatPerVbyte
-	//	*FundPsbtRequest_SatPerKw
 	Fees isFundPsbtRequest_Fees `protobuf_oneof:"fees"`
 	// The name of the account to fund the PSBT with. If empty, the default wallet
 	// account is used.
@@ -3662,8 +3661,6 @@ type FundPsbtRequest struct {
 	ChangeType ChangeAddressType `protobuf:"varint,8,opt,name=change_type,json=changeType,proto3,enum=walletrpc.ChangeAddressType" json:"change_type,omitempty"`
 	// The strategy to use for selecting coins during funding the PSBT.
 	CoinSelectionStrategy lnrpc.CoinSelectionStrategy `protobuf:"varint,10,opt,name=coin_selection_strategy,json=coinSelectionStrategy,proto3,enum=lnrpc.CoinSelectionStrategy" json:"coin_selection_strategy,omitempty"`
-	// The max fee to total output amount ratio that this psbt should adhere to.
-	MaxFeeRatio float64 `protobuf:"fixed64,12,opt,name=max_fee_ratio,json=maxFeeRatio,proto3" json:"max_fee_ratio,omitempty"`
 }
 
 func (x *FundPsbtRequest) Reset() {
@@ -3747,13 +3744,6 @@ func (x *FundPsbtRequest) GetSatPerVbyte() uint64 {
 	return 0
 }
 
-func (x *FundPsbtRequest) GetSatPerKw() uint64 {
-	if x, ok := x.GetFees().(*FundPsbtRequest_SatPerKw); ok {
-		return x.SatPerKw
-	}
-	return 0
-}
-
 func (x *FundPsbtRequest) GetAccount() string {
 	if x != nil {
 		return x.Account
@@ -3789,13 +3779,6 @@ func (x *FundPsbtRequest) GetCoinSelectionStrategy() lnrpc.CoinSelectionStrategy
 	return lnrpc.CoinSelectionStrategy(0)
 }
 
-func (x *FundPsbtRequest) GetMaxFeeRatio() float64 {
-	if x != nil {
-		return x.MaxFeeRatio
-	}
-	return 0
-}
-
 type isFundPsbtRequest_Template interface {
 	isFundPsbtRequest_Template()
 }
@@ -3858,18 +3841,10 @@ type FundPsbtRequest_SatPerVbyte struct {
 	SatPerVbyte uint64 `protobuf:"varint,4,opt,name=sat_per_vbyte,json=satPerVbyte,proto3,oneof"`
 }
 
-type FundPsbtRequest_SatPerKw struct {
-	// The fee rate, expressed in sat/kWU, that should be used to spend the
-	// input with.
-	SatPerKw uint64 `protobuf:"varint,11,opt,name=sat_per_kw,json=satPerKw,proto3,oneof"`
-}
-
 func (*FundPsbtRequest_TargetConf) isFundPsbtRequest_Fees() {}
 
 func (*FundPsbtRequest_SatPerVbyte) isFundPsbtRequest_Fees() {}
 
-func (*FundPsbtRequest_SatPerKw) isFundPsbtRequest_Fees() {}
-
 type FundPsbtResponse struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -4930,7 +4905,7 @@ var file_walletrpc_walletkit_proto_rawDesc = []byte{
 	0x65, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x76, 0x65, 0x72, 0x77, 0x72, 0x69, 0x74, 0x65, 0x18,
 	0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6f, 0x76, 0x65, 0x72, 0x77, 0x72, 0x69, 0x74, 0x65,
 	0x22, 0x1a, 0x0a, 0x18, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
-	0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xaa, 0x04, 0x0a,
+	0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe6, 0x03, 0x0a,
 	0x0f, 0x46, 0x75, 0x6e, 0x64, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
 	0x12, 0x14, 0x0a, 0x04, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00,
 	0x52, 0x04, 0x70, 0x73, 0x62, 0x74, 0x12, 0x29, 0x0a, 0x03, 0x72, 0x61, 0x77, 0x18, 0x02, 0x20,
@@ -4944,9 +4919,7 @@ var file_walletrpc_walletkit_proto_rawDesc = []byte{
 	0x20, 0x01, 0x28, 0x0d, 0x48, 0x01, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x6f,
 	0x6e, 0x66, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x76, 0x62,
 	0x79, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x48, 0x01, 0x52, 0x0b, 0x73, 0x61, 0x74,
-	0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x61, 0x74, 0x5f,
-	0x70, 0x65, 0x72, 0x5f, 0x6b, 0x77, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x48, 0x01, 0x52, 0x08,
-	0x73, 0x61, 0x74, 0x50, 0x65, 0x72, 0x4b, 0x77, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f,
+	0x50, 0x65, 0x72, 0x56, 0x62, 0x79, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f,
 	0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75,
 	0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x73, 0x18,
 	0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x73, 0x12,
@@ -4962,315 +4935,312 @@ var file_walletrpc_walletkit_proto_rawDesc = []byte{
 	0x6e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69,
 	0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x15, 0x63, 0x6f, 0x69, 0x6e,
 	0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
-	0x79, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74,
-	0x69, 0x6f, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x46, 0x65, 0x65,
-	0x52, 0x61, 0x74, 0x69, 0x6f, 0x42, 0x0a, 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74,
-	0x65, 0x42, 0x06, 0x0a, 0x04, 0x66, 0x65, 0x65, 0x73, 0x22, 0x9c, 0x01, 0x0a, 0x10, 0x46, 0x75,
-	0x6e, 0x64, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f,
-	0x0a, 0x0b, 0x66, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x0c, 0x52, 0x0a, 0x66, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x73, 0x62, 0x74, 0x12,
-	0x2e, 0x0a, 0x13, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74,
-	0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x63, 0x68,
-	0x61, 0x6e, 0x67, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12,
-	0x37, 0x0a, 0x0c, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x18,
-	0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70,
-	0x63, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x0b, 0x6c, 0x6f, 0x63,
-	0x6b, 0x65, 0x64, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x22, 0xaf, 0x01, 0x0a, 0x0a, 0x54, 0x78, 0x54,
-	0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74,
-	0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e,
-	0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73,
-	0x12, 0x3c, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
-	0x0b, 0x32, 0x22, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x78,
-	0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73,
-	0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x1a, 0x3a,
-	0x0a, 0x0c, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
-	0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
-	0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52,
-	0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x7f, 0x0a, 0x0e, 0x50, 0x73,
-	0x62, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04,
-	0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x70, 0x73, 0x62, 0x74,
-	0x12, 0x34, 0x0a, 0x15, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x75, 0x74,
-	0x70, 0x75, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x48,
-	0x00, 0x52, 0x13, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4f, 0x75, 0x74, 0x70, 0x75,
-	0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x12, 0x0a, 0x03, 0x61, 0x64, 0x64, 0x18, 0x03, 0x20,
-	0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x03, 0x61, 0x64, 0x64, 0x42, 0x0f, 0x0a, 0x0d, 0x63, 0x68,
-	0x61, 0x6e, 0x67, 0x65, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x9b, 0x01, 0x0a, 0x09,
-	0x55, 0x74, 0x78, 0x6f, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2b, 0x0a, 0x08, 0x6f, 0x75, 0x74,
-	0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6e,
-	0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75,
-	0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61,
-	0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x69,
-	0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6b, 0x5f, 0x73, 0x63, 0x72,
-	0x69, 0x70, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x70, 0x6b, 0x53, 0x63, 0x72,
-	0x69, 0x70, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01,
-	0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x32, 0x0a, 0x0f, 0x53, 0x69, 0x67,
-	0x6e, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b,
-	0x66, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x0c, 0x52, 0x0a, 0x66, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x73, 0x62, 0x74, 0x22, 0x58, 0x0a,
-	0x10, 0x53, 0x69, 0x67, 0x6e, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x73, 0x62, 0x74,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x73,
-	0x62, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x70,
-	0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65,
-	0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x22, 0x50, 0x0a, 0x13, 0x46, 0x69, 0x6e, 0x61, 0x6c,
-	0x69, 0x7a, 0x65, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f,
-	0x0a, 0x0b, 0x66, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x0c, 0x52, 0x0a, 0x66, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x73, 0x62, 0x74, 0x12,
-	0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x59, 0x0a, 0x14, 0x46, 0x69, 0x6e,
-	0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x73, 0x62, 0x74,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x73,
-	0x62, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x72, 0x61, 0x77, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x5f,
-	0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x61, 0x77, 0x46, 0x69, 0x6e,
-	0x61, 0x6c, 0x54, 0x78, 0x22, 0x13, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x73,
-	0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4d, 0x0a, 0x12, 0x4c, 0x69, 0x73,
-	0x74, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
-	0x37, 0x0a, 0x0c, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x18,
-	0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70,
-	0x63, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x0b, 0x6c, 0x6f, 0x63,
-	0x6b, 0x65, 0x64, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x2a, 0x8e, 0x01, 0x0a, 0x0b, 0x41, 0x64, 0x64,
-	0x72, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e,
-	0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53,
-	0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x01, 0x12, 0x1e,
-	0x0a, 0x1a, 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, 0x5f, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53,
-	0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x02, 0x12, 0x25,
-	0x0a, 0x21, 0x48, 0x59, 0x42, 0x52, 0x49, 0x44, 0x5f, 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, 0x5f,
-	0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48,
-	0x41, 0x53, 0x48, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54,
-	0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x10, 0x04, 0x2a, 0xfb, 0x09, 0x0a, 0x0b, 0x57, 0x69,
-	0x74, 0x6e, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x13, 0x0a, 0x0f, 0x55, 0x4e, 0x4b,
-	0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x18,
-	0x0a, 0x14, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x49, 0x4d,
-	0x45, 0x5f, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4d, 0x4d,
-	0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x4e, 0x4f, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x10,
-	0x02, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f,
-	0x52, 0x45, 0x56, 0x4f, 0x4b, 0x45, 0x10, 0x03, 0x12, 0x17, 0x0a, 0x13, 0x48, 0x54, 0x4c, 0x43,
-	0x5f, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x52, 0x45, 0x56, 0x4f, 0x4b, 0x45, 0x10,
-	0x04, 0x12, 0x18, 0x0a, 0x14, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54,
-	0x45, 0x44, 0x5f, 0x52, 0x45, 0x56, 0x4f, 0x4b, 0x45, 0x10, 0x05, 0x12, 0x25, 0x0a, 0x21, 0x48,
-	0x54, 0x4c, 0x43, 0x5f, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x54, 0x49, 0x4d, 0x45,
-	0x4f, 0x55, 0x54, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c,
-	0x10, 0x06, 0x12, 0x26, 0x0a, 0x22, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50,
-	0x54, 0x45, 0x44, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x45, 0x43, 0x4f,
-	0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x10, 0x07, 0x12, 0x1f, 0x0a, 0x1b, 0x48, 0x54,
-	0x4c, 0x43, 0x5f, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54,
-	0x45, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x08, 0x12, 0x20, 0x0a, 0x1c, 0x48,
-	0x54, 0x4c, 0x43, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x5f, 0x52, 0x45, 0x4d,
-	0x4f, 0x54, 0x45, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x09, 0x12, 0x1c, 0x0a,
-	0x18, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56,
-	0x45, 0x4c, 0x5f, 0x52, 0x45, 0x56, 0x4f, 0x4b, 0x45, 0x10, 0x0a, 0x12, 0x14, 0x0a, 0x10, 0x57,
-	0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10,
-	0x0b, 0x12, 0x1b, 0x0a, 0x17, 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, 0x5f, 0x57, 0x49, 0x54, 0x4e,
-	0x45, 0x53, 0x53, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x0c, 0x12, 0x15,
-	0x0a, 0x11, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x4e, 0x43,
-	0x48, 0x4f, 0x52, 0x10, 0x0d, 0x12, 0x21, 0x0a, 0x1d, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d,
-	0x45, 0x4e, 0x54, 0x5f, 0x4e, 0x4f, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x54, 0x57, 0x45,
-	0x41, 0x4b, 0x4c, 0x45, 0x53, 0x53, 0x10, 0x0e, 0x12, 0x22, 0x0a, 0x1e, 0x43, 0x4f, 0x4d, 0x4d,
-	0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45,
-	0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x0f, 0x12, 0x35, 0x0a, 0x31,
-	0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x54, 0x49, 0x4d,
-	0x45, 0x4f, 0x55, 0x54, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45,
-	0x4c, 0x5f, 0x49, 0x4e, 0x50, 0x55, 0x54, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45,
-	0x44, 0x10, 0x10, 0x12, 0x36, 0x0a, 0x32, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x43, 0x43, 0x45,
-	0x50, 0x54, 0x45, 0x44, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x45, 0x43,
-	0x4f, 0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x49, 0x4e, 0x50, 0x55, 0x54, 0x5f,
-	0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x11, 0x12, 0x1e, 0x0a, 0x1a, 0x4c,
-	0x45, 0x41, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f,
-	0x54, 0x49, 0x4d, 0x45, 0x5f, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x12, 0x12, 0x28, 0x0a, 0x24, 0x4c,
-	0x45, 0x41, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f,
-	0x54, 0x4f, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52,
-	0x4d, 0x45, 0x44, 0x10, 0x13, 0x12, 0x2b, 0x0a, 0x27, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x5f, 0x48,
-	0x54, 0x4c, 0x43, 0x5f, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x54, 0x49, 0x4d, 0x45,
-	0x4f, 0x55, 0x54, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c,
-	0x10, 0x14, 0x12, 0x2c, 0x0a, 0x28, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43,
-	0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53,
-	0x53, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x10, 0x15,
-	0x12, 0x19, 0x0a, 0x15, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x50, 0x55, 0x42, 0x5f,
-	0x4b, 0x45, 0x59, 0x5f, 0x53, 0x50, 0x45, 0x4e, 0x44, 0x10, 0x16, 0x12, 0x1e, 0x0a, 0x1a, 0x54,
-	0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f, 0x43, 0x4f, 0x4d,
-	0x4d, 0x49, 0x54, 0x5f, 0x53, 0x50, 0x45, 0x4e, 0x44, 0x10, 0x17, 0x12, 0x1f, 0x0a, 0x1b, 0x54,
-	0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x43, 0x4f,
-	0x4d, 0x4d, 0x49, 0x54, 0x5f, 0x53, 0x50, 0x45, 0x4e, 0x44, 0x10, 0x18, 0x12, 0x1e, 0x0a, 0x1a,
-	0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x5f, 0x53,
-	0x57, 0x45, 0x45, 0x50, 0x5f, 0x53, 0x50, 0x45, 0x4e, 0x44, 0x10, 0x19, 0x12, 0x2d, 0x0a, 0x29,
-	0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4f, 0x46, 0x46,
-	0x45, 0x52, 0x45, 0x44, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x5f, 0x53, 0x45, 0x43,
-	0x4f, 0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x10, 0x1a, 0x12, 0x2e, 0x0a, 0x2a, 0x54,
+	0x79, 0x42, 0x0a, 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x42, 0x06, 0x0a,
+	0x04, 0x66, 0x65, 0x65, 0x73, 0x22, 0x9c, 0x01, 0x0a, 0x10, 0x46, 0x75, 0x6e, 0x64, 0x50, 0x73,
+	0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x75,
+	0x6e, 0x64, 0x65, 0x64, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
+	0x0a, 0x66, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x73, 0x62, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x63,
+	0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x69, 0x6e, 0x64,
+	0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
+	0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x37, 0x0a, 0x0c, 0x6c,
+	0x6f, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x14, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x74,
+	0x78, 0x6f, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x0b, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x55,
+	0x74, 0x78, 0x6f, 0x73, 0x22, 0xaf, 0x01, 0x0a, 0x0a, 0x54, 0x78, 0x54, 0x65, 0x6d, 0x70, 0x6c,
+	0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x01, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x50,
+	0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x3c, 0x0a, 0x07,
+	0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e,
+	0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x78, 0x54, 0x65, 0x6d, 0x70,
+	0x6c, 0x61, 0x74, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72,
+	0x79, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x1a, 0x3a, 0x0a, 0x0c, 0x4f, 0x75,
+	0x74, 0x70, 0x75, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
+	0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c,
+	0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x7f, 0x0a, 0x0e, 0x50, 0x73, 0x62, 0x74, 0x43, 0x6f,
+	0x69, 0x6e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x73, 0x62, 0x74,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x70, 0x73, 0x62, 0x74, 0x12, 0x34, 0x0a, 0x15,
+	0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f,
+	0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x13, 0x65,
+	0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x49, 0x6e, 0x64,
+	0x65, 0x78, 0x12, 0x12, 0x0a, 0x03, 0x61, 0x64, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x48,
+	0x00, 0x52, 0x03, 0x61, 0x64, 0x64, 0x42, 0x0f, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
+	0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x9b, 0x01, 0x0a, 0x09, 0x55, 0x74, 0x78, 0x6f,
+	0x4c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2b, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e,
+	0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e,
+	0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69,
+	0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6b, 0x5f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18,
+	0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x70, 0x6b, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12,
+	0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x32, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x50, 0x73, 0x62,
+	0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x75, 0x6e, 0x64,
+	0x65, 0x64, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x66,
+	0x75, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x73, 0x62, 0x74, 0x22, 0x58, 0x0a, 0x10, 0x53, 0x69, 0x67,
+	0x6e, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a,
+	0x0b, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x73, 0x62, 0x74, 0x12, 0x23,
+	0x0a, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18,
+	0x02, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x49, 0x6e, 0x70,
+	0x75, 0x74, 0x73, 0x22, 0x50, 0x0a, 0x13, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50,
+	0x73, 0x62, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x75,
+	0x6e, 0x64, 0x65, 0x64, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
+	0x0a, 0x66, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x73, 0x62, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61,
+	0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63,
+	0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x59, 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a,
+	0x65, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a,
+	0x0b, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x73, 0x62, 0x74, 0x12, 0x20,
+	0x0a, 0x0c, 0x72, 0x61, 0x77, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x74, 0x78, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x61, 0x77, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x54, 0x78,
+	0x22, 0x13, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4d, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61,
+	0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0c, 0x6c,
+	0x6f, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x14, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x74,
+	0x78, 0x6f, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x0b, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x55,
+	0x74, 0x78, 0x6f, 0x73, 0x2a, 0x8e, 0x01, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
+	0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10,
+	0x00, 0x12, 0x17, 0x0a, 0x13, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x50, 0x55, 0x42,
+	0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x01, 0x12, 0x1e, 0x0a, 0x1a, 0x4e, 0x45,
+	0x53, 0x54, 0x45, 0x44, 0x5f, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x5f, 0x50, 0x55, 0x42,
+	0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x02, 0x12, 0x25, 0x0a, 0x21, 0x48, 0x59,
+	0x42, 0x52, 0x49, 0x44, 0x5f, 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, 0x5f, 0x57, 0x49, 0x54, 0x4e,
+	0x45, 0x53, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10,
+	0x03, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x50, 0x55, 0x42,
+	0x4b, 0x45, 0x59, 0x10, 0x04, 0x2a, 0xfb, 0x09, 0x0a, 0x0b, 0x57, 0x69, 0x74, 0x6e, 0x65, 0x73,
+	0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x13, 0x0a, 0x0f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e,
+	0x5f, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x4f,
+	0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x4c, 0x4f,
+	0x43, 0x4b, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45,
+	0x4e, 0x54, 0x5f, 0x4e, 0x4f, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x10, 0x02, 0x12, 0x15, 0x0a,
+	0x11, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x56, 0x4f,
+	0x4b, 0x45, 0x10, 0x03, 0x12, 0x17, 0x0a, 0x13, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4f, 0x46, 0x46,
+	0x45, 0x52, 0x45, 0x44, 0x5f, 0x52, 0x45, 0x56, 0x4f, 0x4b, 0x45, 0x10, 0x04, 0x12, 0x18, 0x0a,
+	0x14, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x5f, 0x52,
+	0x45, 0x56, 0x4f, 0x4b, 0x45, 0x10, 0x05, 0x12, 0x25, 0x0a, 0x21, 0x48, 0x54, 0x4c, 0x43, 0x5f,
+	0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x5f,
+	0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x10, 0x06, 0x12, 0x26,
+	0x0a, 0x22, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x5f,
+	0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x4c,
+	0x45, 0x56, 0x45, 0x4c, 0x10, 0x07, 0x12, 0x1f, 0x0a, 0x1b, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4f,
+	0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x54, 0x49,
+	0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x08, 0x12, 0x20, 0x0a, 0x1c, 0x48, 0x54, 0x4c, 0x43, 0x5f,
+	0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f,
+	0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x09, 0x12, 0x1c, 0x0a, 0x18, 0x48, 0x54, 0x4c,
+	0x43, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x52,
+	0x45, 0x56, 0x4f, 0x4b, 0x45, 0x10, 0x0a, 0x12, 0x14, 0x0a, 0x10, 0x57, 0x49, 0x54, 0x4e, 0x45,
+	0x53, 0x53, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x0b, 0x12, 0x1b, 0x0a,
+	0x17, 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, 0x5f, 0x57, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x5f,
+	0x4b, 0x45, 0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10, 0x0c, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x4f,
+	0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x10,
+	0x0d, 0x12, 0x21, 0x0a, 0x1d, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f,
+	0x4e, 0x4f, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x54, 0x57, 0x45, 0x41, 0x4b, 0x4c, 0x45,
+	0x53, 0x53, 0x10, 0x0e, 0x12, 0x22, 0x0a, 0x1e, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45,
+	0x4e, 0x54, 0x5f, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x43, 0x4f, 0x4e,
+	0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x0f, 0x12, 0x35, 0x0a, 0x31, 0x48, 0x54, 0x4c, 0x43,
+	0x5f, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54,
+	0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x49, 0x4e,
+	0x50, 0x55, 0x54, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x10, 0x12,
+	0x36, 0x0a, 0x32, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44,
+	0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f,
+	0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x49, 0x4e, 0x50, 0x55, 0x54, 0x5f, 0x43, 0x4f, 0x4e, 0x46,
+	0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x11, 0x12, 0x1e, 0x0a, 0x1a, 0x4c, 0x45, 0x41, 0x53, 0x45,
+	0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x49, 0x4d, 0x45,
+	0x5f, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x12, 0x12, 0x28, 0x0a, 0x24, 0x4c, 0x45, 0x41, 0x53, 0x45,
+	0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x4f, 0x5f, 0x52,
+	0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10,
+	0x13, 0x12, 0x2b, 0x0a, 0x27, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f,
+	0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x5f,
+	0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x10, 0x14, 0x12, 0x2c,
+	0x0a, 0x28, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x43, 0x43,
+	0x45, 0x50, 0x54, 0x45, 0x44, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x45,
+	0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x10, 0x15, 0x12, 0x19, 0x0a, 0x15,
+	0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x50, 0x55, 0x42, 0x5f, 0x4b, 0x45, 0x59, 0x5f,
+	0x53, 0x50, 0x45, 0x4e, 0x44, 0x10, 0x16, 0x12, 0x1e, 0x0a, 0x1a, 0x54, 0x41, 0x50, 0x52, 0x4f,
+	0x4f, 0x54, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x5f,
+	0x53, 0x50, 0x45, 0x4e, 0x44, 0x10, 0x17, 0x12, 0x1f, 0x0a, 0x1b, 0x54, 0x41, 0x50, 0x52, 0x4f,
+	0x4f, 0x54, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54,
+	0x5f, 0x53, 0x50, 0x45, 0x4e, 0x44, 0x10, 0x18, 0x12, 0x1e, 0x0a, 0x1a, 0x54, 0x41, 0x50, 0x52,
+	0x4f, 0x4f, 0x54, 0x5f, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x5f, 0x53, 0x57, 0x45, 0x45, 0x50,
+	0x5f, 0x53, 0x50, 0x45, 0x4e, 0x44, 0x10, 0x19, 0x12, 0x2d, 0x0a, 0x29, 0x54, 0x41, 0x50, 0x52,
+	0x4f, 0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44,
+	0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f,
+	0x4c, 0x45, 0x56, 0x45, 0x4c, 0x10, 0x1a, 0x12, 0x2e, 0x0a, 0x2a, 0x54, 0x41, 0x50, 0x52, 0x4f,
+	0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44,
+	0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f,
+	0x4c, 0x45, 0x56, 0x45, 0x4c, 0x10, 0x1b, 0x12, 0x24, 0x0a, 0x20, 0x54, 0x41, 0x50, 0x52, 0x4f,
+	0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x4c,
+	0x45, 0x56, 0x45, 0x4c, 0x5f, 0x52, 0x45, 0x56, 0x4f, 0x4b, 0x45, 0x10, 0x1c, 0x12, 0x20, 0x0a,
+	0x1c, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x43,
+	0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x5f, 0x52, 0x45, 0x56, 0x4f, 0x4b, 0x45, 0x10, 0x1d, 0x12,
+	0x1f, 0x0a, 0x1b, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f,
+	0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x52, 0x45, 0x56, 0x4f, 0x4b, 0x45, 0x10, 0x1e,
+	0x12, 0x27, 0x0a, 0x23, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43,
+	0x5f, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f,
+	0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x1f, 0x12, 0x26, 0x0a, 0x22, 0x54, 0x41, 0x50,
+	0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f,
+	0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10,
+	0x20, 0x12, 0x28, 0x0a, 0x24, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c,
+	0x43, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x54,
+	0x45, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x21, 0x12, 0x27, 0x0a, 0x23, 0x54,
 	0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x43, 0x43, 0x45,
-	0x50, 0x54, 0x45, 0x44, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x45, 0x43,
-	0x4f, 0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x10, 0x1b, 0x12, 0x24, 0x0a, 0x20, 0x54,
-	0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x53, 0x45, 0x43, 0x4f,
-	0x4e, 0x44, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x52, 0x45, 0x56, 0x4f, 0x4b, 0x45, 0x10,
-	0x1c, 0x12, 0x20, 0x0a, 0x1c, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c,
-	0x43, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x5f, 0x52, 0x45, 0x56, 0x4f, 0x4b,
-	0x45, 0x10, 0x1d, 0x12, 0x1f, 0x0a, 0x1b, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x48,
-	0x54, 0x4c, 0x43, 0x5f, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x52, 0x45, 0x56, 0x4f,
-	0x4b, 0x45, 0x10, 0x1e, 0x12, 0x27, 0x0a, 0x23, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f,
-	0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x52, 0x45, 0x4d,
-	0x4f, 0x54, 0x45, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x1f, 0x12, 0x26, 0x0a,
-	0x22, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x4c, 0x4f,
-	0x43, 0x41, 0x4c, 0x5f, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x54, 0x49, 0x4d, 0x45,
-	0x4f, 0x55, 0x54, 0x10, 0x20, 0x12, 0x28, 0x0a, 0x24, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54,
-	0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x5f, 0x52,
-	0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x21, 0x12,
-	0x27, 0x0a, 0x23, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f,
-	0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f, 0x53,
-	0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x22, 0x12, 0x1d, 0x0a, 0x19, 0x54, 0x41, 0x50, 0x52,
-	0x4f, 0x4f, 0x54, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x52,
-	0x45, 0x56, 0x4f, 0x4b, 0x45, 0x10, 0x23, 0x2a, 0x56, 0x0a, 0x11, 0x43, 0x68, 0x61, 0x6e, 0x67,
-	0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x1f,
-	0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x54,
-	0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10,
-	0x00, 0x12, 0x1c, 0x0a, 0x18, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x41, 0x44, 0x44, 0x52,
-	0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x32, 0x54, 0x52, 0x10, 0x01, 0x32,
-	0xd6, 0x11, 0x0a, 0x09, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x4b, 0x69, 0x74, 0x12, 0x4c, 0x0a,
-	0x0b, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x2e, 0x77,
-	0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73,
-	0x70, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x61,
-	0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70,
-	0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x4c,
-	0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x1d, 0x2e, 0x77, 0x61, 0x6c,
-	0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70,
-	0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c,
-	0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75,
-	0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x52, 0x65, 0x6c,
-	0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x1f, 0x2e, 0x77, 0x61, 0x6c,
-	0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75,
-	0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x61,
-	0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4f,
-	0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a,
-	0x0a, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x77, 0x61,
-	0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x73,
-	0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c,
-	0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x73,
-	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x0d, 0x44, 0x65, 0x72, 0x69,
-	0x76, 0x65, 0x4e, 0x65, 0x78, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x11, 0x2e, 0x77, 0x61, 0x6c, 0x6c,
-	0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x73,
-	0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69,
-	0x70, 0x74, 0x6f, 0x72, 0x12, 0x38, 0x0a, 0x09, 0x44, 0x65, 0x72, 0x69, 0x76, 0x65, 0x4b, 0x65,
-	0x79, 0x12, 0x13, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x4c,
-	0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x1a, 0x16, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63,
-	0x2e, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x3b,
-	0x0a, 0x08, 0x4e, 0x65, 0x78, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x16, 0x2e, 0x77, 0x61, 0x6c,
-	0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
-	0x73, 0x74, 0x1a, 0x17, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41,
-	0x64, 0x64, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0e, 0x47,
-	0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x2e,
-	0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61,
-	0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
-	0x12, 0x2e, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
-	0x69, 0x6f, 0x6e, 0x12, 0x4f, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75,
-	0x6e, 0x74, 0x73, 0x12, 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e,
-	0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75,
-	0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e,
-	0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64,
-	0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x12, 0x21, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74,
-	0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x65,
-	0x72, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x77, 0x61, 0x6c,
-	0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52,
-	0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52,
-	0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12,
+	0x50, 0x54, 0x45, 0x44, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45,
+	0x53, 0x53, 0x10, 0x22, 0x12, 0x1d, 0x0a, 0x19, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f,
+	0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x56, 0x4f, 0x4b,
+	0x45, 0x10, 0x23, 0x2a, 0x56, 0x0a, 0x11, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x64,
+	0x72, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x1f, 0x43, 0x48, 0x41, 0x4e,
+	0x47, 0x45, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f,
+	0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a,
+	0x18, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x5f,
+	0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x32, 0x54, 0x52, 0x10, 0x01, 0x32, 0xd6, 0x11, 0x0a, 0x09,
+	0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x4b, 0x69, 0x74, 0x12, 0x4c, 0x0a, 0x0b, 0x4c, 0x69, 0x73,
+	0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65,
+	0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74,
+	0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x4c, 0x65, 0x61, 0x73, 0x65,
+	0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72,
+	0x70, 0x63, 0x2e, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70,
+	0x63, 0x2e, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
+	0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x1f, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72,
+	0x70, 0x63, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74,
+	0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75,
+	0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x0a, 0x4c, 0x69, 0x73,
+	0x74, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74,
+	0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70,
+	0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x0d, 0x44, 0x65, 0x72, 0x69, 0x76, 0x65, 0x4e, 0x65,
+	0x78, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x11, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70,
+	0x63, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72,
+	0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72,
+	0x12, 0x38, 0x0a, 0x09, 0x44, 0x65, 0x72, 0x69, 0x76, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x13, 0x2e,
+	0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74,
+	0x6f, 0x72, 0x1a, 0x16, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79,
+	0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x3b, 0x0a, 0x08, 0x4e, 0x65,
+	0x78, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x16, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72,
+	0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17,
+	0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x54, 0x72,
+	0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c,
+	0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
+	0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6c, 0x6e,
+	0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12,
+	0x4f, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12,
+	0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74,
+	0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
 	0x1f, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74,
-	0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x1a, 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73,
-	0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x12, 0x64, 0x0a, 0x13, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
-	0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x12, 0x25, 0x2e, 0x77, 0x61, 0x6c, 0x6c,
-	0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
-	0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x1a, 0x26, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67,
-	0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72,
-	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x15, 0x56, 0x65, 0x72, 0x69,
-	0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64,
-	0x72, 0x12, 0x27, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65,
-	0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41,
-	0x64, 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x77, 0x61, 0x6c,
-	0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73,
+	0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x12, 0x58, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x65,
+	0x72, 0x76, 0x65, 0x12, 0x21, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e,
+	0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72,
+	0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x65, 0x72,
+	0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x4c, 0x69,
+	0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x77, 0x61,
+	0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72,
+	0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77,
+	0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x64,
+	0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64,
+	0x0a, 0x13, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74,
+	0x68, 0x41, 0x64, 0x64, 0x72, 0x12, 0x25, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70,
+	0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74,
+	0x68, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x77,
+	0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73,
 	0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x63,
-	0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70,
-	0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52,
-	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72,
-	0x70, 0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
-	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x0f, 0x49, 0x6d, 0x70, 0x6f,
-	0x72, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, 0x77, 0x61,
-	0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x75,
-	0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22,
-	0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72,
-	0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x12, 0x58, 0x0a, 0x0f, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x70, 0x73,
-	0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x21, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70,
-	0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x70, 0x73, 0x63, 0x72, 0x69, 0x70,
-	0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65,
-	0x74, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x70, 0x73, 0x63,
-	0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x12,
-	0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69,
-	0x6f, 0x6e, 0x12, 0x16, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54,
-	0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1a, 0x2e, 0x77, 0x61, 0x6c,
-	0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65,
-	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x11, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
-	0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x2e, 0x77, 0x61,
-	0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73,
-	0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e,
-	0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65,
-	0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x75, 0x74, 0x70, 0x75,
-	0x74, 0x73, 0x12, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53,
-	0x65, 0x6e, 0x64, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
-	0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65,
-	0x6e, 0x64, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65,
-	0x12, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74,
-	0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
-	0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69,
-	0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
-	0x52, 0x0a, 0x0d, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x77, 0x65, 0x65, 0x70, 0x73,
-	0x12, 0x1f, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e,
-	0x64, 0x69, 0x6e, 0x67, 0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
-	0x74, 0x1a, 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65,
-	0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x07, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x65, 0x65, 0x12, 0x19,
-	0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x46,
-	0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x77, 0x61, 0x6c, 0x6c,
-	0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73,
-	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x11, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x6f, 0x72,
-	0x63, 0x65, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x46, 0x65, 0x65, 0x12, 0x23, 0x2e, 0x77, 0x61, 0x6c,
-	0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x6f, 0x72, 0x63, 0x65,
-	0x43, 0x6c, 0x6f, 0x73, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
-	0x24, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x6d, 0x70,
-	0x46, 0x6f, 0x72, 0x63, 0x65, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73,
-	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x65,
-	0x65, 0x70, 0x73, 0x12, 0x1c, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e,
-	0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
-	0x74, 0x1a, 0x1d, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69,
-	0x73, 0x74, 0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
-	0x12, 0x5b, 0x0a, 0x10, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
-	0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x15, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65,
+	0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x12, 0x27, 0x2e,
+	0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79,
+	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72,
+	0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x57, 0x69, 0x74, 0x68, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x12, 0x52, 0x0a, 0x0d, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e,
+	0x74, 0x12, 0x1f, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6d,
+	0x70, 0x6f, 0x72, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x49,
+	0x6d, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x0f, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x75,
+	0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74,
+	0x72, 0x70, 0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,
+	0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x77, 0x61, 0x6c,
+	0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x75, 0x62,
+	0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58,
+	0x0a, 0x0f, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x70, 0x73, 0x63, 0x72, 0x69, 0x70,
+	0x74, 0x12, 0x21, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6d,
+	0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x70, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63,
+	0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x70, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x12, 0x50, 0x75, 0x62, 0x6c,
+	0x69, 0x73, 0x68, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16,
+	0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73,
+	0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72,
+	0x70, 0x63, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x12, 0x5b, 0x0a, 0x11, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e,
+	0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74,
+	0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69,
+	0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x77, 0x61, 0x6c, 0x6c,
+	0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e,
+	0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+	0x4c, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1d,
+	0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f,
+	0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e,
+	0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x75,
+	0x74, 0x70, 0x75, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a,
+	0x0b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x46, 0x65, 0x65, 0x12, 0x1d, 0x2e, 0x77,
+	0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74,
+	0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x61,
+	0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65,
+	0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x50,
+	0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x12, 0x1f, 0x2e, 0x77,
+	0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67,
+	0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e,
+	0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e,
+	0x67, 0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+	0x40, 0x0a, 0x07, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x65, 0x65, 0x12, 0x19, 0x2e, 0x77, 0x61, 0x6c,
+	0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x65, 0x65, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70,
+	0x63, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x12, 0x5e, 0x0a, 0x11, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x43, 0x6c,
+	0x6f, 0x73, 0x65, 0x46, 0x65, 0x65, 0x12, 0x23, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72,
+	0x70, 0x63, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x43, 0x6c, 0x6f, 0x73,
+	0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x77, 0x61,
+	0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x6d, 0x70, 0x46, 0x6f, 0x72, 0x63,
+	0x65, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x12, 0x49, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x12,
+	0x1c, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74,
+	0x53, 0x77, 0x65, 0x65, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e,
+	0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77,
+	0x65, 0x65, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x10,
+	0x4c, 0x61, 0x62, 0x65, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+	0x12, 0x22, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x61, 0x62,
+	0x65, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63,
 	0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
-	0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65,
-	0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61,
-	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a,
-	0x08, 0x46, 0x75, 0x6e, 0x64, 0x50, 0x73, 0x62, 0x74, 0x12, 0x1a, 0x2e, 0x77, 0x61, 0x6c, 0x6c,
-	0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70,
-	0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x12, 0x43, 0x0a, 0x08, 0x53, 0x69, 0x67, 0x6e, 0x50, 0x73, 0x62, 0x74, 0x12, 0x1a,
-	0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x50,
-	0x73, 0x62, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x77, 0x61, 0x6c,
+	0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x08, 0x46, 0x75, 0x6e,
+	0x64, 0x50, 0x73, 0x62, 0x74, 0x12, 0x1a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70,
+	0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x1a, 0x1b, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75,
+	0x6e, 0x64, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43,
+	0x0a, 0x08, 0x53, 0x69, 0x67, 0x6e, 0x50, 0x73, 0x62, 0x74, 0x12, 0x1a, 0x2e, 0x77, 0x61, 0x6c,
 	0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x50, 0x73, 0x62, 0x74, 0x52,
-	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x0c, 0x46, 0x69, 0x6e, 0x61, 0x6c,
-	0x69, 0x7a, 0x65, 0x50, 0x73, 0x62, 0x74, 0x12, 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74,
-	0x72, 0x70, 0x63, 0x2e, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x73, 0x62, 0x74,
-	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74,
-	0x72, 0x70, 0x63, 0x2e, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x73, 0x62, 0x74,
-	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68,
-	0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67,
-	0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, 0x72, 0x70,
-	0x63, 0x2f, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x33,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72,
+	0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x0c, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50,
+	0x73, 0x62, 0x74, 0x12, 0x1e, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e,
+	0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e,
+	0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
+	0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6e, 0x65, 0x74, 0x77,
+	0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2f, 0x77, 0x61,
+	0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -6230,7 +6200,6 @@ func file_walletrpc_walletkit_proto_init() {
 		(*FundPsbtRequest_CoinSelect)(nil),
 		(*FundPsbtRequest_TargetConf)(nil),
 		(*FundPsbtRequest_SatPerVbyte)(nil),
-		(*FundPsbtRequest_SatPerKw)(nil),
 	}
 	file_walletrpc_walletkit_proto_msgTypes[53].OneofWrappers = []interface{}{
 		(*PsbtCoinSelect_ExistingOutputIndex)(nil),
diff --git a/lnrpc/walletrpc/walletkit.proto b/lnrpc/walletrpc/walletkit.proto
index 7021bec0b..9a4ab4745 100644
--- a/lnrpc/walletrpc/walletkit.proto
+++ b/lnrpc/walletrpc/walletkit.proto
@@ -1388,12 +1388,6 @@ message FundPsbtRequest {
         input with.
         */
         uint64 sat_per_vbyte = 4;
-
-        /*
-        The fee rate, expressed in sat/kWU, that should be used to spend the
-        input with.
-        */
-        uint64 sat_per_kw = 11;
     }
 
     /*
@@ -1417,9 +1411,6 @@ message FundPsbtRequest {
 
     // The strategy to use for selecting coins during funding the PSBT.
     lnrpc.CoinSelectionStrategy coin_selection_strategy = 10;
-
-    // The max fee to total output amount ratio that this psbt should adhere to.
-    double max_fee_ratio = 12;
 }
 message FundPsbtResponse {
     /*
diff --git a/lnrpc/walletrpc/walletkit.swagger.json b/lnrpc/walletrpc/walletkit.swagger.json
index ab72f3a85..68c7daef0 100644
--- a/lnrpc/walletrpc/walletkit.swagger.json
+++ b/lnrpc/walletrpc/walletkit.swagger.json
@@ -1564,11 +1564,6 @@
           "format": "uint64",
           "description": "The fee rate, expressed in sat/vbyte, that should be used to spend the\ninput with."
         },
-        "sat_per_kw": {
-          "type": "string",
-          "format": "uint64",
-          "description": "The fee rate, expressed in sat/kWU, that should be used to spend the\ninput with."
-        },
         "account": {
           "type": "string",
           "description": "The name of the account to fund the PSBT with. If empty, the default wallet\naccount is used."
@@ -1589,11 +1584,6 @@
         "coin_selection_strategy": {
           "$ref": "#/definitions/lnrpcCoinSelectionStrategy",
           "description": "The strategy to use for selecting coins during funding the PSBT."
-        },
-        "max_fee_ratio": {
-          "type": "number",
-          "format": "double",
-          "description": "The max fee to total output amount ratio that this psbt should adhere to."
         }
       }
     },
diff --git a/lnrpc/walletrpc/walletkit_server.go b/lnrpc/walletrpc/walletkit_server.go
index 6be185ca3..2d577db68 100644
--- a/lnrpc/walletrpc/walletkit_server.go
+++ b/lnrpc/walletrpc/walletkit_server.go
@@ -1511,13 +1511,9 @@ func (w *WalletKit) FundPsbt(_ context.Context,
 			req.GetSatPerVbyte() * 1000,
 		).FeePerKWeight()
 
-	case req.GetSatPerKw() != 0:
-		feeSatPerKW = chainfee.SatPerKWeight(req.GetSatPerKw())
-
 	default:
 		return nil, fmt.Errorf("fee definition missing, need to " +
-			"specify either target_conf, sat_per_vbyte or " +
-			"sat_per_kw")
+			"specify either target_conf or sat_per_vbyte")
 	}
 
 	// Then, we'll extract the minimum number of confirmations that each
@@ -1626,17 +1622,11 @@ func (w *WalletKit) FundPsbt(_ context.Context,
 			return nil, fmt.Errorf("unknown change output type")
 		}
 
-		maxFeeRatio := chanfunding.DefaultMaxFeeRatio
-
-		if req.MaxFeeRatio != 0 {
-			maxFeeRatio = req.MaxFeeRatio
-		}
-
 		// Run the actual funding process now, using the channel funding
 		// coin selection algorithm.
 		return w.fundPsbtCoinSelect(
 			account, changeIndex, packet, minConfs, changeType,
-			feeSatPerKW, coinSelectionStrategy, maxFeeRatio,
+			feeSatPerKW, coinSelectionStrategy,
 		)
 
 	// The template is specified as a RPC message. We need to create a new
@@ -1839,8 +1829,8 @@ func (w *WalletKit) fundPsbtInternalWallet(account string,
 func (w *WalletKit) fundPsbtCoinSelect(account string, changeIndex int32,
 	packet *psbt.Packet, minConfs int32,
 	changeType chanfunding.ChangeAddressType,
-	feeRate chainfee.SatPerKWeight, strategy base.CoinSelectionStrategy,
-	maxFeeRatio float64) (*FundPsbtResponse, error) {
+	feeRate chainfee.SatPerKWeight, strategy base.CoinSelectionStrategy) (
+	*FundPsbtResponse, error) {
 
 	// We want to make sure we don't select any inputs that are already
 	// specified in the template. To do that, we require those inputs to
@@ -1928,7 +1918,6 @@ func (w *WalletKit) fundPsbtCoinSelect(account string, changeIndex int32,
 		changeAmt, needMore, err := chanfunding.CalculateChangeAmount(
 			inputSum, outputSum, packetFeeNoChange,
 			packetFeeWithChange, changeDustLimit, changeType,
-			maxFeeRatio,
 		)
 		if err != nil {
 			return nil, fmt.Errorf("error calculating change "+
@@ -1985,7 +1974,7 @@ func (w *WalletKit) fundPsbtCoinSelect(account string, changeIndex int32,
 
 		selectedCoins, changeAmount, err := chanfunding.CoinSelect(
 			feeRate, fundingAmount, changeDustLimit, coins,
-			strategy, estimator, changeType, maxFeeRatio,
+			strategy, estimator, changeType,
 		)
 		if err != nil {
 			return fmt.Errorf("error selecting coins: %w", err)
diff --git a/lnwallet/chanfunding/coin_select.go b/lnwallet/chanfunding/coin_select.go
index 26fe9b92b..e2c85c9d3 100644
--- a/lnwallet/chanfunding/coin_select.go
+++ b/lnwallet/chanfunding/coin_select.go
@@ -58,10 +58,6 @@ const (
 	// must assert that the output value of the selected existing output
 	// already is above dust when using this change address type.
 	ExistingChangeAddress ChangeAddressType = 2
-
-	// DefaultMaxFeeRatio is the default fee to total amount of outputs
-	// ratio that is used to sanity check the fees of a transaction.
-	DefaultMaxFeeRatio float64 = 0.2
 )
 
 // selectInputs selects a slice of inputs necessary to meet the specified
@@ -147,25 +143,16 @@ func calculateFees(utxos []wallet.Coin, feeRate chainfee.SatPerKWeight,
 	return requiredFeeNoChange, requiredFeeWithChange, nil
 }
 
-// sanityCheckFee checks if the specified fee amounts to what the provided ratio
-// allows.
-func sanityCheckFee(totalOut, fee btcutil.Amount, maxFeeRatio float64) error {
-	// Sanity check the maxFeeRatio itself.
-	if maxFeeRatio <= 0.00 || maxFeeRatio > 1.00 {
-		return fmt.Errorf("maxFeeRatio must be between 0.00 and 1.00 "+
-			"got %.2f", maxFeeRatio)
-	}
-
-	maxFee := btcutil.Amount(float64(totalOut) * maxFeeRatio)
-
-	// Check that the fees do not exceed the max allowed value.
-	if fee > maxFee {
-		return fmt.Errorf("fee %v exceeds max fee (%v) on total "+
-			"output value %v with max fee ratio of %.2f", fee,
-			maxFee, totalOut, maxFeeRatio)
+// sanityCheckFee checks if the specified fee amounts to over 20% of the total
+// output amount and raises an error.
+func sanityCheckFee(totalOut, fee btcutil.Amount) error {
+	// Fail if more than 20% goes to fees.
+	// TODO(halseth): smarter fee limit. Make configurable or dynamic wrt
+	// total funding size?
+	if fee > totalOut/5 {
+		return fmt.Errorf("fee (%v) exceeds 20%% of total output (%v)",
+			fee, totalOut)
 	}
-
-	// All checks passed, we return nil to signal that the fees are valid.
 	return nil
 }
 
@@ -176,8 +163,7 @@ func sanityCheckFee(totalOut, fee btcutil.Amount, maxFeeRatio float64) error {
 func CoinSelect(feeRate chainfee.SatPerKWeight, amt, dustLimit btcutil.Amount,
 	coins []wallet.Coin, strategy wallet.CoinSelectionStrategy,
 	existingWeight input.TxWeightEstimator,
-	changeType ChangeAddressType, maxFeeRatio float64) ([]wallet.Coin,
-	btcutil.Amount, error) {
+	changeType ChangeAddressType) ([]wallet.Coin, btcutil.Amount, error) {
 
 	amtNeeded := amt
 	for {
@@ -202,7 +188,6 @@ func CoinSelect(feeRate chainfee.SatPerKWeight, amt, dustLimit btcutil.Amount,
 		changeAmount, newAmtNeeded, err := CalculateChangeAmount(
 			totalSat, amt, requiredFeeNoChange,
 			requiredFeeWithChange, dustLimit, changeType,
-			maxFeeRatio,
 		)
 		if err != nil {
 			return nil, 0, err
@@ -231,8 +216,7 @@ func CoinSelect(feeRate chainfee.SatPerKWeight, amt, dustLimit btcutil.Amount,
 // fees and that more coins need to be selected.
 func CalculateChangeAmount(totalInputAmt, requiredAmt, requiredFeeNoChange,
 	requiredFeeWithChange, dustLimit btcutil.Amount,
-	changeType ChangeAddressType, maxFeeRatio float64) (btcutil.Amount,
-	btcutil.Amount, error) {
+	changeType ChangeAddressType) (btcutil.Amount, btcutil.Amount, error) {
 
 	// This is just a sanity check to make sure the function is used
 	// correctly.
@@ -282,8 +266,7 @@ func CalculateChangeAmount(totalInputAmt, requiredAmt, requiredFeeNoChange,
 	// Sanity check the resulting output values to make sure we
 	// don't burn a great part to fees.
 	totalOut := requiredAmt + changeAmt
-
-	err := sanityCheckFee(totalOut, totalInputAmt-totalOut, maxFeeRatio)
+	err := sanityCheckFee(totalOut, totalInputAmt-totalOut)
 	if err != nil {
 		return 0, 0, err
 	}
@@ -297,9 +280,9 @@ func CalculateChangeAmount(totalInputAmt, requiredAmt, requiredFeeNoChange,
 func CoinSelectSubtractFees(feeRate chainfee.SatPerKWeight, amt,
 	dustLimit btcutil.Amount, coins []wallet.Coin,
 	strategy wallet.CoinSelectionStrategy,
-	existingWeight input.TxWeightEstimator, changeType ChangeAddressType,
-	maxFeeRatio float64) ([]wallet.Coin, btcutil.Amount, btcutil.Amount,
-	error) {
+	existingWeight input.TxWeightEstimator,
+	changeType ChangeAddressType) ([]wallet.Coin, btcutil.Amount,
+	btcutil.Amount, error) {
 
 	// First perform an initial round of coin selection to estimate
 	// the required fee.
@@ -348,7 +331,7 @@ func CoinSelectSubtractFees(feeRate chainfee.SatPerKWeight, amt,
 	// Sanity check the resulting output values to make sure we
 	// don't burn a great part to fees.
 	totalOut := outputAmt + changeAmt
-	err = sanityCheckFee(totalOut, totalSat-totalOut, maxFeeRatio)
+	err = sanityCheckFee(totalOut, totalSat-totalOut)
 	if err != nil {
 		return nil, 0, 0, err
 	}
@@ -364,8 +347,8 @@ func CoinSelectUpToAmount(feeRate chainfee.SatPerKWeight, minAmount, maxAmount,
 	reserved, dustLimit btcutil.Amount, coins []wallet.Coin,
 	strategy wallet.CoinSelectionStrategy,
 	existingWeight input.TxWeightEstimator,
-	changeType ChangeAddressType, maxFeeRatio float64) ([]wallet.Coin,
-	btcutil.Amount, btcutil.Amount, error) {
+	changeType ChangeAddressType) ([]wallet.Coin, btcutil.Amount,
+	btcutil.Amount, error) {
 
 	var (
 		// selectSubtractFee is tracking if our coin selection was
@@ -386,7 +369,7 @@ func CoinSelectUpToAmount(feeRate chainfee.SatPerKWeight, minAmount, maxAmount,
 	// maxAmount with or without a change output that covers the miner fee.
 	selected, changeAmt, err := CoinSelect(
 		feeRate, maxAmount, dustLimit, coins, strategy, existingWeight,
-		changeType, maxFeeRatio,
+		changeType,
 	)
 
 	var errInsufficientFunds *ErrInsufficientFunds
@@ -429,7 +412,7 @@ func CoinSelectUpToAmount(feeRate chainfee.SatPerKWeight, minAmount, maxAmount,
 	if selectSubtractFee {
 		selected, outputAmount, changeAmt, err = CoinSelectSubtractFees(
 			feeRate, totalBalance-reserved, dustLimit, coins,
-			strategy, existingWeight, changeType, maxFeeRatio,
+			strategy, existingWeight, changeType,
 		)
 		if err != nil {
 			return nil, 0, 0, err
@@ -447,7 +430,7 @@ func CoinSelectUpToAmount(feeRate chainfee.SatPerKWeight, minAmount, maxAmount,
 
 		return sum
 	}
-	err = sanityCheckFee(totalOut, sum(selected)-totalOut, maxFeeRatio)
+	err = sanityCheckFee(totalOut, sum(selected)-totalOut)
 	if err != nil {
 		return nil, 0, 0, err
 	}
diff --git a/lnwallet/chanfunding/wallet_assembler.go b/lnwallet/chanfunding/wallet_assembler.go
index ce2b406c6..3d62649cb 100644
--- a/lnwallet/chanfunding/wallet_assembler.go
+++ b/lnwallet/chanfunding/wallet_assembler.go
@@ -436,7 +436,6 @@ func (w *WalletAssembler) ProvisionChannel(r *Request) (Intent, error) {
 				reserve, w.cfg.DustLimit, coins,
 				w.cfg.CoinSelectionStrategy,
 				fundingOutputWeight, changeType,
-				DefaultMaxFeeRatio,
 			)
 			if err != nil {
 				return err
@@ -472,7 +471,6 @@ func (w *WalletAssembler) ProvisionChannel(r *Request) (Intent, error) {
 				r.FeeRate, r.LocalAmt, dustLimit, coins,
 				w.cfg.CoinSelectionStrategy,
 				fundingOutputWeight, changeType,
-				DefaultMaxFeeRatio,
 			)
 			if err != nil {
 				return err
@@ -487,7 +485,6 @@ func (w *WalletAssembler) ProvisionChannel(r *Request) (Intent, error) {
 				r.FeeRate, r.LocalAmt, dustLimit, coins,
 				w.cfg.CoinSelectionStrategy,
 				fundingOutputWeight, changeType,
-				DefaultMaxFeeRatio,
 			)
 			if err != nil {
 				return err
diff --git a/lnwallet/interface.go b/lnwallet/interface.go
index e2e491c73..0ab18ef02 100644
--- a/lnwallet/interface.go
+++ b/lnwallet/interface.go
@@ -636,19 +636,6 @@ func InternalKeyForAddr(wallet WalletController, netParams *chaincfg.Params,
 
 	walletAddr, err := wallet.AddressInfo(addr)
 	if err != nil {
-		// If the error is that the address can't be found, it is not
-		// an error. This happens when any channel which is not a custom
-		// taproot channel is cooperatively closed to an external P2TR
-		// address. In this case there is no internal key associated
-		// with the address. Callers can use the .Option() method to get
-		// an option value.
-		var managerErr waddrmgr.ManagerError
-		if errors.As(err, &managerErr) &&
-			managerErr.ErrorCode == waddrmgr.ErrAddressNotFound {
-
-			return none, nil
-		}
-
 		return none, err
 	}
 
diff --git a/lnwire/channel_update_2.go b/lnwire/channel_update_2.go
index 5c6d24095..79a76aad6 100644
--- a/lnwire/channel_update_2.go
+++ b/lnwire/channel_update_2.go
@@ -411,7 +411,7 @@ func decodeDisableFlags(r io.Reader, val interface{}, buf *[8]byte,
 }
 
 // TrueBoolean is a record that indicates true or false using the presence of
-// the record. If the record is absent, it indicates false. If it is present,
+// the record. If the record is absent, it indicates false. If it is presence,
 // it indicates true.
 type TrueBoolean struct{}
 
diff --git a/log.go b/log.go
index c88208ef3..faa4f15f4 100644
--- a/log.go
+++ b/log.go
@@ -177,13 +177,13 @@ func SetupLoggers(root *build.SubLoggerManager, interceptor signal.Interceptor)
 	AddSubLogger(root, routerrpc.Subsystem, interceptor, routerrpc.UseLogger)
 	AddSubLogger(root, chanfitness.Subsystem, interceptor, chanfitness.UseLogger)
 	AddSubLogger(root, verrpc.Subsystem, interceptor, verrpc.UseLogger)
-	AddSubLogger(root, healthcheck.Subsystem, interceptor, healthcheck.UseLogger)
+	AddV1SubLogger(root, healthcheck.Subsystem, interceptor, healthcheck.UseLogger)
 	AddSubLogger(root, chainreg.Subsystem, interceptor, chainreg.UseLogger)
 	AddSubLogger(root, chanacceptor.Subsystem, interceptor, chanacceptor.UseLogger)
 	AddSubLogger(root, funding.Subsystem, interceptor, funding.UseLogger)
 	AddSubLogger(root, cluster.Subsystem, interceptor, cluster.UseLogger)
 	AddSubLogger(root, rpcperms.Subsystem, interceptor, rpcperms.UseLogger)
-	AddSubLogger(root, tor.Subsystem, interceptor, tor.UseLogger)
+	AddV1SubLogger(root, tor.Subsystem, interceptor, tor.UseLogger)
 	AddSubLogger(root, btcwallet.Subsystem, interceptor, btcwallet.UseLogger)
 	AddSubLogger(root, rpcwallet.Subsystem, interceptor, rpcwallet.UseLogger)
 	AddSubLogger(root, peersrpc.Subsystem, interceptor, peersrpc.UseLogger)
diff --git a/routing/missioncontrol.go b/routing/missioncontrol.go
index 20aa04907..be8ce7c9f 100644
--- a/routing/missioncontrol.go
+++ b/routing/missioncontrol.go
@@ -1,10 +1,8 @@
 package routing
 
 import (
-	"bytes"
 	"errors"
 	"fmt"
-	"io"
 	"sync"
 	"time"
 
@@ -18,7 +16,6 @@ import (
 	"github.com/lightningnetwork/lnd/kvdb"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/routing/route"
-	"github.com/lightningnetwork/lnd/tlv"
 )
 
 const (
@@ -264,39 +261,12 @@ type MissionControlPairSnapshot struct {
 // paymentResult is the information that becomes available when a payment
 // attempt completes.
 type paymentResult struct {
-	id        uint64
-	timeFwd   tlv.RecordT[tlv.TlvType0, uint64]
-	timeReply tlv.RecordT[tlv.TlvType1, uint64]
-	route     tlv.RecordT[tlv.TlvType2, mcRoute]
-
-	// failure holds information related to the failure of a payment. The
-	// presence of this record indicates a payment failure. The absence of
-	// this record indicates a successful payment.
-	failure tlv.OptionalRecordT[tlv.TlvType3, paymentFailure]
-}
-
-// newPaymentResult constructs a new paymentResult.
-func newPaymentResult(id uint64, rt *mcRoute, timeFwd, timeReply time.Time,
-	failure *paymentFailure) *paymentResult {
-
-	result := &paymentResult{
-		id: id,
-		timeFwd: tlv.NewPrimitiveRecord[tlv.TlvType0](
-			uint64(timeFwd.UnixNano()),
-		),
-		timeReply: tlv.NewPrimitiveRecord[tlv.TlvType1](
-			uint64(timeReply.UnixNano()),
-		),
-		route: tlv.NewRecordT[tlv.TlvType2](*rt),
-	}
-
-	if failure != nil {
-		result.failure = tlv.SomeRecordT(
-			tlv.NewRecordT[tlv.TlvType3](*failure),
-		)
-	}
-
-	return result
+	id                 uint64
+	timeFwd, timeReply time.Time
+	route              *mcRoute
+	success            bool
+	failureSourceIdx   *int
+	failure            lnwire.FailureMessage
 }
 
 // NewMissionController returns a new instance of MissionController.
@@ -620,10 +590,15 @@ func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route,
 
 	timestamp := m.cfg.clock.Now()
 
-	result := newPaymentResult(
-		paymentID, extractMCRoute(rt), timestamp, timestamp,
-		newPaymentFailure(failureSourceIdx, failure),
-	)
+	result := &paymentResult{
+		success:          false,
+		timeFwd:          timestamp,
+		timeReply:        timestamp,
+		id:               paymentID,
+		failureSourceIdx: failureSourceIdx,
+		failure:          failure,
+		route:            extractMCRoute(rt),
+	}
 
 	return m.processPaymentResult(result)
 }
@@ -635,12 +610,15 @@ func (m *MissionControl) ReportPaymentSuccess(paymentID uint64,
 
 	timestamp := m.cfg.clock.Now()
 
-	result := newPaymentResult(
-		paymentID, extractMCRoute(rt), timestamp, timestamp, nil,
-	)
+	result := &paymentResult{
+		timeFwd:   timestamp,
+		timeReply: timestamp,
+		id:        paymentID,
+		success:   true,
+		route:     extractMCRoute(rt),
+	}
 
 	_, err := m.processPaymentResult(result)
-
 	return err
 }
 
@@ -668,11 +646,14 @@ func (m *MissionControl) applyPaymentResult(
 	result *paymentResult) *channeldb.FailureReason {
 
 	// Interpret result.
-	i := interpretResult(&result.route.Val, result.failure.ValOpt())
+	i := interpretResult(
+		result.route, result.success, result.failureSourceIdx,
+		result.failure,
+	)
 
 	if i.policyFailure != nil {
 		if m.state.requestSecondChance(
-			time.Unix(0, int64(result.timeReply.Val)),
+			result.timeReply,
 			i.policyFailure.From, i.policyFailure.To,
 		) {
 			return nil
@@ -700,10 +681,7 @@ func (m *MissionControl) applyPaymentResult(
 		m.log.Debugf("Reporting node failure to Mission Control: "+
 			"node=%v", *i.nodeFailure)
 
-		m.state.setAllFail(
-			*i.nodeFailure,
-			time.Unix(0, int64(result.timeReply.Val)),
-		)
+		m.state.setAllFail(*i.nodeFailure, result.timeReply)
 	}
 
 	for pair, pairResult := range i.pairResults {
@@ -720,9 +698,7 @@ func (m *MissionControl) applyPaymentResult(
 		}
 
 		m.state.setLastPairResult(
-			pair.From, pair.To,
-			time.Unix(0, int64(result.timeReply.Val)), &pairResult,
-			false,
+			pair.From, pair.To, result.timeReply, &pairResult, false,
 		)
 	}
 
@@ -827,158 +803,3 @@ func (n *namespacedDB) purge() error {
 		return err
 	}, func() {})
 }
-
-// paymentFailure represents the presence of a payment failure. It may or may
-// not include additional information about said failure.
-type paymentFailure struct {
-	info tlv.OptionalRecordT[tlv.TlvType0, paymentFailureInfo]
-}
-
-// newPaymentFailure constructs a new paymentFailure struct. If the source
-// index is nil, then an empty paymentFailure is returned. This represents a
-// failure with unknown details. Otherwise, the index and failure message are
-// used to populate the info field of the paymentFailure.
-func newPaymentFailure(sourceIdx *int,
-	failureMsg lnwire.FailureMessage) *paymentFailure {
-
-	if sourceIdx == nil {
-		return &paymentFailure{}
-	}
-
-	info := paymentFailureInfo{
-		sourceIdx: tlv.NewPrimitiveRecord[tlv.TlvType0](
-			uint8(*sourceIdx),
-		),
-		msg: tlv.NewRecordT[tlv.TlvType1](failureMessage{failureMsg}),
-	}
-
-	return &paymentFailure{
-		info: tlv.SomeRecordT(tlv.NewRecordT[tlv.TlvType0](info)),
-	}
-}
-
-// Record returns a TLV record that can be used to encode/decode a
-// paymentFailure to/from a TLV stream.
-func (r *paymentFailure) Record() tlv.Record {
-	recordSize := func() uint64 {
-		var (
-			b   bytes.Buffer
-			buf [8]byte
-		)
-		if err := encodePaymentFailure(&b, r, &buf); err != nil {
-			panic(err)
-		}
-
-		return uint64(len(b.Bytes()))
-	}
-
-	return tlv.MakeDynamicRecord(
-		0, r, recordSize, encodePaymentFailure, decodePaymentFailure,
-	)
-}
-
-func encodePaymentFailure(w io.Writer, val interface{}, _ *[8]byte) error {
-	if v, ok := val.(*paymentFailure); ok {
-		var recordProducers []tlv.RecordProducer
-		v.info.WhenSome(
-			func(r tlv.RecordT[tlv.TlvType0, paymentFailureInfo]) {
-				recordProducers = append(recordProducers, &r)
-			},
-		)
-
-		return lnwire.EncodeRecordsTo(
-			w, lnwire.ProduceRecordsSorted(recordProducers...),
-		)
-	}
-
-	return tlv.NewTypeForEncodingErr(val, "routing.paymentFailure")
-}
-
-func decodePaymentFailure(r io.Reader, val interface{}, _ *[8]byte,
-	l uint64) error {
-
-	if v, ok := val.(*paymentFailure); ok {
-		var h paymentFailure
-
-		info := tlv.ZeroRecordT[tlv.TlvType0, paymentFailureInfo]()
-		typeMap, err := lnwire.DecodeRecords(
-			r, lnwire.ProduceRecordsSorted(&info)...,
-		)
-		if err != nil {
-			return err
-		}
-
-		if _, ok := typeMap[h.info.TlvType()]; ok {
-			h.info = tlv.SomeRecordT(info)
-		}
-
-		*v = h
-
-		return nil
-	}
-
-	return tlv.NewTypeForDecodingErr(val, "routing.paymentFailure", l, l)
-}
-
-// paymentFailureInfo holds additional information about a payment failure.
-type paymentFailureInfo struct {
-	sourceIdx tlv.RecordT[tlv.TlvType0, uint8]
-	msg       tlv.RecordT[tlv.TlvType1, failureMessage]
-}
-
-// Record returns a TLV record that can be used to encode/decode a
-// paymentFailureInfo to/from a TLV stream.
-func (r *paymentFailureInfo) Record() tlv.Record {
-	recordSize := func() uint64 {
-		var (
-			b   bytes.Buffer
-			buf [8]byte
-		)
-		if err := encodePaymentFailureInfo(&b, r, &buf); err != nil {
-			panic(err)
-		}
-
-		return uint64(len(b.Bytes()))
-	}
-
-	return tlv.MakeDynamicRecord(
-		0, r, recordSize, encodePaymentFailureInfo,
-		decodePaymentFailureInfo,
-	)
-}
-
-func encodePaymentFailureInfo(w io.Writer, val interface{}, _ *[8]byte) error {
-	if v, ok := val.(*paymentFailureInfo); ok {
-		return lnwire.EncodeRecordsTo(
-			w, lnwire.ProduceRecordsSorted(
-				&v.sourceIdx, &v.msg,
-			),
-		)
-	}
-
-	return tlv.NewTypeForEncodingErr(val, "routing.paymentFailureInfo")
-}
-
-func decodePaymentFailureInfo(r io.Reader, val interface{}, _ *[8]byte,
-	l uint64) error {
-
-	if v, ok := val.(*paymentFailureInfo); ok {
-		var h paymentFailureInfo
-
-		_, err := lnwire.DecodeRecords(
-			r,
-			lnwire.ProduceRecordsSorted(&h.sourceIdx, &h.msg)...,
-		)
-		if err != nil {
-			return err
-		}
-
-		*v = h
-
-		return nil
-	}
-
-	return tlv.NewTypeForDecodingErr(
-		val, "routing.paymentFailureInfo", l, l,
-	)
-}
diff --git a/routing/missioncontrol_store.go b/routing/missioncontrol_store.go
index ceb4740e4..c40f24697 100644
--- a/routing/missioncontrol_store.go
+++ b/routing/missioncontrol_store.go
@@ -6,12 +6,14 @@ import (
 	"encoding/binary"
 	"fmt"
 	"io"
+	"math"
 	"sync"
 	"time"
 
+	"github.com/btcsuite/btcd/wire"
+	"github.com/lightningnetwork/lnd/channeldb"
 	"github.com/lightningnetwork/lnd/kvdb"
 	"github.com/lightningnetwork/lnd/lnwire"
-	"github.com/lightningnetwork/lnd/tlv"
 )
 
 var (
@@ -24,6 +26,12 @@ var (
 	byteOrder = binary.BigEndian
 )
 
+const (
+	// unknownFailureSourceIdx is the database encoding of an unknown error
+	// source.
+	unknownFailureSourceIdx = -1
+)
+
 // missionControlDB is an interface that defines the database methods that a
 // single missionControlStore has access to. It allows the missionControlStore
 // to be unaware of the overall DB structure and restricts its access to the DB
@@ -160,146 +168,190 @@ func (b *missionControlStore) fetchAll() ([]*paymentResult, error) {
 // serializeResult serializes a payment result and returns a key and value byte
 // slice to insert into the bucket.
 func serializeResult(rp *paymentResult) ([]byte, []byte, error) {
-	recordProducers := []tlv.RecordProducer{
-		&rp.timeFwd,
-		&rp.timeReply,
-		&rp.route,
+	// Write timestamps, success status, failure source index and route.
+	var b bytes.Buffer
+
+	var dbFailureSourceIdx int32
+	if rp.failureSourceIdx == nil {
+		dbFailureSourceIdx = unknownFailureSourceIdx
+	} else {
+		dbFailureSourceIdx = int32(*rp.failureSourceIdx)
 	}
 
-	rp.failure.WhenSome(
-		func(failure tlv.RecordT[tlv.TlvType3, paymentFailure]) {
-			recordProducers = append(recordProducers, &failure)
-		},
-	)
-
-	// Compose key that identifies this result.
-	key := getResultKey(rp)
-
-	var buff bytes.Buffer
-	err := lnwire.EncodeRecordsTo(
-		&buff, lnwire.ProduceRecordsSorted(recordProducers...),
+	err := channeldb.WriteElements(
+		&b,
+		uint64(rp.timeFwd.UnixNano()),
+		uint64(rp.timeReply.UnixNano()),
+		rp.success, dbFailureSourceIdx,
 	)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	return key, buff.Bytes(), err
-}
-
-// deserializeResult deserializes a payment result.
-func deserializeResult(k, v []byte) (*paymentResult, error) {
-	// Parse payment id.
-	result := paymentResult{
-		id: byteOrder.Uint64(k[8:]),
+	if err := serializeRoute(&b, rp.route); err != nil {
+		return nil, nil, err
 	}
 
-	failure := tlv.ZeroRecordT[tlv.TlvType3, paymentFailure]()
-	recordProducers := []tlv.RecordProducer{
-		&result.timeFwd,
-		&result.timeReply,
-		&result.route,
-		&failure,
+	// Write failure. If there is no failure message, write an empty
+	// byte slice.
+	var failureBytes bytes.Buffer
+	if rp.failure != nil {
+		err := lnwire.EncodeFailureMessage(&failureBytes, rp.failure, 0)
+		if err != nil {
+			return nil, nil, err
+		}
 	}
-
-	r := bytes.NewReader(v)
-	typeMap, err := lnwire.DecodeRecords(
-		r, lnwire.ProduceRecordsSorted(recordProducers...)...,
-	)
+	err = wire.WriteVarBytes(&b, 0, failureBytes.Bytes())
 	if err != nil {
-		return nil, err
-	}
-
-	if _, ok := typeMap[result.failure.TlvType()]; ok {
-		result.failure = tlv.SomeRecordT(failure)
+		return nil, nil, err
 	}
 
-	return &result, nil
-}
-
-// serializeRoute serializes a mcRoute and writes the resulting bytes to the
-// given io.Writer.
-func serializeRoute(w io.Writer, r *mcRoute) error {
-	records := lnwire.ProduceRecordsSorted(
-		&r.sourcePubKey,
-		&r.totalAmount,
-		&r.hops,
-	)
+	// Compose key that identifies this result.
+	key := getResultKey(rp)
 
-	return lnwire.EncodeRecordsTo(w, records)
+	return key, b.Bytes(), nil
 }
 
 // deserializeRoute deserializes the mcRoute from the given io.Reader.
 func deserializeRoute(r io.Reader) (*mcRoute, error) {
 	var rt mcRoute
-	records := lnwire.ProduceRecordsSorted(
-		&rt.sourcePubKey,
-		&rt.totalAmount,
-		&rt.hops,
-	)
+	if err := channeldb.ReadElements(r, &rt.totalAmount); err != nil {
+		return nil, err
+	}
 
-	_, err := lnwire.DecodeRecords(r, records...)
-	if err != nil {
+	var pub []byte
+	if err := channeldb.ReadElements(r, &pub); err != nil {
 		return nil, err
 	}
+	copy(rt.sourcePubKey[:], pub)
+
+	var numHops uint32
+	if err := channeldb.ReadElements(r, &numHops); err != nil {
+		return nil, err
+	}
+
+	var hops []*mcHop
+	for i := uint32(0); i < numHops; i++ {
+		hop, err := deserializeHop(r)
+		if err != nil {
+			return nil, err
+		}
+		hops = append(hops, hop)
+	}
+	rt.hops = hops
 
 	return &rt, nil
 }
 
 // deserializeHop deserializes the mcHop from the given io.Reader.
 func deserializeHop(r io.Reader) (*mcHop, error) {
-	var (
-		h        mcHop
-		blinding = tlv.ZeroRecordT[tlv.TlvType3, lnwire.TrueBoolean]()
-		custom   = tlv.ZeroRecordT[tlv.TlvType4, lnwire.TrueBoolean]()
-	)
-	records := lnwire.ProduceRecordsSorted(
-		&h.channelID,
-		&h.pubKeyBytes,
-		&h.amtToFwd,
-		&blinding,
-		&custom,
-	)
+	var h mcHop
 
-	typeMap, err := lnwire.DecodeRecords(r, records...)
-	if err != nil {
+	var pub []byte
+	if err := channeldb.ReadElements(r, &pub); err != nil {
+		return nil, err
+	}
+	copy(h.pubKeyBytes[:], pub)
+
+	if err := channeldb.ReadElements(r,
+		&h.channelID, &h.amtToFwd, &h.hasBlindingPoint,
+		&h.hasCustomRecords,
+	); err != nil {
 		return nil, err
 	}
 
-	if _, ok := typeMap[h.hasBlindingPoint.TlvType()]; ok {
-		h.hasBlindingPoint = tlv.SomeRecordT(blinding)
+	return &h, nil
+}
+
+// serializeRoute serializes a mcRoute and writes the resulting bytes to the
+// given io.Writer.
+func serializeRoute(w io.Writer, r *mcRoute) error {
+	err := channeldb.WriteElements(w, r.totalAmount, r.sourcePubKey[:])
+	if err != nil {
+		return err
+	}
+
+	if err := channeldb.WriteElements(w, uint32(len(r.hops))); err != nil {
+		return err
 	}
 
-	if _, ok := typeMap[h.hasCustomRecords.TlvType()]; ok {
-		h.hasCustomRecords = tlv.SomeRecordT(custom)
+	for _, h := range r.hops {
+		if err := serializeHop(w, h); err != nil {
+			return err
+		}
 	}
 
-	return &h, nil
+	return nil
 }
 
 // serializeHop serializes a mcHop and writes the resulting bytes to the given
 // io.Writer.
 func serializeHop(w io.Writer, h *mcHop) error {
-	recordProducers := []tlv.RecordProducer{
-		&h.channelID,
-		&h.pubKeyBytes,
-		&h.amtToFwd,
+	return channeldb.WriteElements(w,
+		h.pubKeyBytes[:],
+		h.channelID,
+		h.amtToFwd,
+		h.hasBlindingPoint,
+		h.hasCustomRecords,
+	)
+}
+
+// deserializeResult deserializes a payment result.
+func deserializeResult(k, v []byte) (*paymentResult, error) {
+	// Parse payment id.
+	result := paymentResult{
+		id: byteOrder.Uint64(k[8:]),
 	}
 
-	h.hasBlindingPoint.WhenSome(func(
-		hasBlinding tlv.RecordT[tlv.TlvType3, lnwire.TrueBoolean]) {
+	r := bytes.NewReader(v)
 
-		recordProducers = append(recordProducers, &hasBlinding)
-	})
+	// Read timestamps, success status and failure source index.
+	var (
+		timeFwd, timeReply uint64
+		dbFailureSourceIdx int32
+	)
 
-	h.hasCustomRecords.WhenSome(func(
-		hasCustom tlv.RecordT[tlv.TlvType4, lnwire.TrueBoolean]) {
+	err := channeldb.ReadElements(
+		r, &timeFwd, &timeReply, &result.success, &dbFailureSourceIdx,
+	)
+	if err != nil {
+		return nil, err
+	}
 
-		recordProducers = append(recordProducers, &hasCustom)
-	})
+	// Convert time stamps to local time zone for consistent logging.
+	result.timeFwd = time.Unix(0, int64(timeFwd)).Local()
+	result.timeReply = time.Unix(0, int64(timeReply)).Local()
+
+	// Convert from unknown index magic number to nil value.
+	if dbFailureSourceIdx != unknownFailureSourceIdx {
+		failureSourceIdx := int(dbFailureSourceIdx)
+		result.failureSourceIdx = &failureSourceIdx
+	}
+
+	// Read route.
+	route, err := deserializeRoute(r)
+	if err != nil {
+		return nil, err
+	}
+	result.route = route
 
-	return lnwire.EncodeRecordsTo(
-		w, lnwire.ProduceRecordsSorted(recordProducers...),
+	// Read failure.
+	failureBytes, err := wire.ReadVarBytes(
+		r, 0, math.MaxUint16, "failure",
 	)
+	if err != nil {
+		return nil, err
+	}
+	if len(failureBytes) > 0 {
+		result.failure, err = lnwire.DecodeFailureMessage(
+			bytes.NewReader(failureBytes), 0,
+		)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return &result, nil
 }
 
 // AddResult adds a new result to the db.
@@ -528,70 +580,9 @@ func getResultKey(rp *paymentResult) []byte {
 	// key. This allows importing mission control data from an external
 	// source without key collisions and keeps the records sorted
 	// chronologically.
-	byteOrder.PutUint64(keyBytes[:], rp.timeReply.Val)
+	byteOrder.PutUint64(keyBytes[:], uint64(rp.timeReply.UnixNano()))
 	byteOrder.PutUint64(keyBytes[8:], rp.id)
-	copy(keyBytes[16:], rp.route.Val.sourcePubKey.Val[:])
+	copy(keyBytes[16:], rp.route.sourcePubKey[:])
 
 	return keyBytes[:]
 }
-
-// failureMessage wraps the lnwire.FailureMessage interface such that we can
-// apply a Record method and use the failureMessage in a TLV encoded type.
-type failureMessage struct {
-	lnwire.FailureMessage
-}
-
-// Record returns a TLV record that can be used to encode/decode a list of
-// failureMessage to/from a TLV stream.
-func (r *failureMessage) Record() tlv.Record {
-	recordSize := func() uint64 {
-		var (
-			b   bytes.Buffer
-			buf [8]byte
-		)
-		if err := encodeFailureMessage(&b, r, &buf); err != nil {
-			panic(err)
-		}
-
-		return uint64(len(b.Bytes()))
-	}
-
-	return tlv.MakeDynamicRecord(
-		0, r, recordSize, encodeFailureMessage, decodeFailureMessage,
-	)
-}
-
-func encodeFailureMessage(w io.Writer, val interface{}, _ *[8]byte) error {
-	if v, ok := val.(*failureMessage); ok {
-		var b bytes.Buffer
-		err := lnwire.EncodeFailureMessage(&b, v.FailureMessage, 0)
-		if err != nil {
-			return err
-		}
-
-		_, err = w.Write(b.Bytes())
-
-		return err
-	}
-
-	return tlv.NewTypeForEncodingErr(val, "routing.failureMessage")
-}
-
-func decodeFailureMessage(r io.Reader, val interface{}, _ *[8]byte,
-	l uint64) error {
-
-	if v, ok := val.(*failureMessage); ok {
-		msg, err := lnwire.DecodeFailureMessage(r, 0)
-		if err != nil {
-			return err
-		}
-
-		*v = failureMessage{
-			FailureMessage: msg,
-		}
-
-		return nil
-	}
-
-	return tlv.NewTypeForDecodingErr(val, "routing.failureMessage", l, l)
-}
diff --git a/routing/result_interpretation.go b/routing/result_interpretation.go
index 089213d65..4da413421 100644
--- a/routing/result_interpretation.go
+++ b/routing/result_interpretation.go
@@ -1,15 +1,11 @@
 package routing
 
 import (
-	"bytes"
 	"fmt"
-	"io"
 
 	"github.com/lightningnetwork/lnd/channeldb"
-	"github.com/lightningnetwork/lnd/fn"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/routing/route"
-	"github.com/lightningnetwork/lnd/tlv"
 )
 
 // Instantiate variables to allow taking a reference from the failure reason.
@@ -80,73 +76,63 @@ type interpretedResult struct {
 
 // interpretResult interprets a payment outcome and returns an object that
 // contains information required to update mission control.
-func interpretResult(rt *mcRoute,
-	failure fn.Option[paymentFailure]) *interpretedResult {
+func interpretResult(rt *mcRoute, success bool, failureSrcIdx *int,
+	failure lnwire.FailureMessage) *interpretedResult {
 
 	i := &interpretedResult{
 		pairResults: make(map[DirectedNodePair]pairResult),
 	}
 
-	return fn.ElimOption(failure, func() *interpretedResult {
+	if success {
 		i.processSuccess(rt)
-
-		return i
-	}, func(info paymentFailure) *interpretedResult {
-		i.processFail(rt, info)
-
-		return i
-	})
+	} else {
+		i.processFail(rt, failureSrcIdx, failure)
+	}
+	return i
 }
 
 // processSuccess processes a successful payment attempt.
 func (i *interpretedResult) processSuccess(route *mcRoute) {
 	// For successes, all nodes must have acted in the right way. Therefore
 	// we mark all of them with a success result.
-	i.successPairRange(route, 0, len(route.hops.Val)-1)
+	i.successPairRange(route, 0, len(route.hops)-1)
 }
 
 // processFail processes a failed payment attempt.
-func (i *interpretedResult) processFail(rt *mcRoute, failure paymentFailure) {
-	if failure.info.IsNone() {
+func (i *interpretedResult) processFail(rt *mcRoute, errSourceIdx *int,
+	failure lnwire.FailureMessage) {
+
+	if errSourceIdx == nil {
 		i.processPaymentOutcomeUnknown(rt)
 		return
 	}
 
-	var (
-		idx     int
-		failMsg lnwire.FailureMessage
-	)
-
-	failure.info.WhenSome(
-		func(r tlv.RecordT[tlv.TlvType0, paymentFailureInfo]) {
-			idx = int(r.Val.sourceIdx.Val)
-			failMsg = r.Val.msg.Val.FailureMessage
-		},
-	)
-
 	// If the payment was to a blinded route and we received an error from
 	// after the introduction point, handle this error separately - there
 	// has been a protocol violation from the introduction node. This
 	// penalty applies regardless of the error code that is returned.
 	introIdx, isBlinded := introductionPointIndex(rt)
-	if isBlinded && introIdx < idx {
-		i.processPaymentOutcomeBadIntro(rt, introIdx, idx)
+	if isBlinded && introIdx < *errSourceIdx {
+		i.processPaymentOutcomeBadIntro(rt, introIdx, *errSourceIdx)
 		return
 	}
 
-	switch idx {
+	switch *errSourceIdx {
+
 	// We are the source of the failure.
 	case 0:
-		i.processPaymentOutcomeSelf(rt, failMsg)
+		i.processPaymentOutcomeSelf(rt, failure)
 
 	// A failure from the final hop was received.
-	case len(rt.hops.Val):
-		i.processPaymentOutcomeFinal(rt, failMsg)
+	case len(rt.hops):
+		i.processPaymentOutcomeFinal(rt, failure)
 
 	// An intermediate hop failed. Interpret the outcome, update reputation
 	// and try again.
 	default:
-		i.processPaymentOutcomeIntermediate(rt, idx, failMsg)
+		i.processPaymentOutcomeIntermediate(
+			rt, *errSourceIdx, failure,
+		)
 	}
 }
 
@@ -172,7 +158,7 @@ func (i *interpretedResult) processPaymentOutcomeBadIntro(route *mcRoute,
 	// a final failure reason because the recipient can't process the
 	// payment (independent of the introduction failing to convert the
 	// error, we can't complete the payment if the last hop fails).
-	if errSourceIdx == len(route.hops.Val) {
+	if errSourceIdx == len(route.hops) {
 		i.finalFailureReason = &reasonError
 	}
 }
@@ -192,7 +178,7 @@ func (i *interpretedResult) processPaymentOutcomeSelf(rt *mcRoute,
 		i.failNode(rt, 1)
 
 		// If this was a payment to a direct peer, we can stop trying.
-		if len(rt.hops.Val) == 1 {
+		if len(rt.hops) == 1 {
 			i.finalFailureReason = &reasonError
 		}
 
@@ -202,7 +188,7 @@ func (i *interpretedResult) processPaymentOutcomeSelf(rt *mcRoute,
 	// available in the link has been updated.
 	default:
 		log.Warnf("Routing failure for local channel %v occurred",
-			rt.hops.Val[0].channelID)
+			rt.hops[0].channelID)
 	}
 }
 
@@ -210,7 +196,7 @@ func (i *interpretedResult) processPaymentOutcomeSelf(rt *mcRoute,
 func (i *interpretedResult) processPaymentOutcomeFinal(route *mcRoute,
 	failure lnwire.FailureMessage) {
 
-	n := len(route.hops.Val)
+	n := len(route.hops)
 
 	failNode := func() {
 		i.failNode(route, n)
@@ -410,8 +396,8 @@ func (i *interpretedResult) processPaymentOutcomeIntermediate(route *mcRoute,
 		// Set the node pair for which a channel update may be out of
 		// date. The second chance logic uses the policyFailure field.
 		i.policyFailure = &DirectedNodePair{
-			From: route.hops.Val[errorSourceIdx-1].pubKeyBytes.Val,
-			To:   route.hops.Val[errorSourceIdx].pubKeyBytes.Val,
+			From: route.hops[errorSourceIdx-1].pubKeyBytes,
+			To:   route.hops[errorSourceIdx].pubKeyBytes,
 		}
 
 		reportOutgoing()
@@ -439,8 +425,8 @@ func (i *interpretedResult) processPaymentOutcomeIntermediate(route *mcRoute,
 		// Set the node pair for which a channel update may be out of
 		// date. The second chance logic uses the policyFailure field.
 		i.policyFailure = &DirectedNodePair{
-			From: route.hops.Val[errorSourceIdx-1].pubKeyBytes.Val,
-			To:   route.hops.Val[errorSourceIdx].pubKeyBytes.Val,
+			From: route.hops[errorSourceIdx-1].pubKeyBytes,
+			To:   route.hops[errorSourceIdx].pubKeyBytes,
 		}
 
 		// We report incoming channel. If a second pair is granted in
@@ -514,14 +500,14 @@ func (i *interpretedResult) processPaymentOutcomeIntermediate(route *mcRoute,
 		// Note that if LND is extended to support multiple blinded
 		// routes, this will terminate the payment without re-trying
 		// the other routes.
-		if introIdx == len(route.hops.Val)-1 {
+		if introIdx == len(route.hops)-1 {
 			i.finalFailureReason = &reasonError
 		} else {
 			// If there are other hops between the recipient and
 			// introduction node, then we just penalize the last
 			// hop in the blinded route to minimize the storage of
 			// results for ephemeral keys.
-			i.failPairBalance(route, len(route.hops.Val)-1)
+			i.failPairBalance(route, len(route.hops)-1)
 		}
 
 	// In all other cases, we penalize the reporting node. These are all
@@ -536,8 +522,8 @@ func (i *interpretedResult) processPaymentOutcomeIntermediate(route *mcRoute,
 // (i.e., that we consider our own node to be at index zero). A boolean is
 // returned to indicate whether the route contains a blinded portion at all.
 func introductionPointIndex(route *mcRoute) (int, bool) {
-	for i, hop := range route.hops.Val {
-		if hop.hasBlindingPoint.IsSome() {
+	for i, hop := range route.hops {
+		if hop.hasBlindingPoint {
 			return i + 1, true
 		}
 	}
@@ -548,7 +534,7 @@ func introductionPointIndex(route *mcRoute) (int, bool) {
 // processPaymentOutcomeUnknown processes a payment outcome for which no failure
 // message or source is available.
 func (i *interpretedResult) processPaymentOutcomeUnknown(route *mcRoute) {
-	n := len(route.hops.Val)
+	n := len(route.hops)
 
 	// If this is a direct payment, the destination must be at fault.
 	if n == 1 {
@@ -565,204 +551,52 @@ func (i *interpretedResult) processPaymentOutcomeUnknown(route *mcRoute) {
 
 // extractMCRoute extracts the fields required by MC from the Route struct to
 // create the more minimal mcRoute struct.
-func extractMCRoute(r *route.Route) *mcRoute {
+func extractMCRoute(route *route.Route) *mcRoute {
 	return &mcRoute{
-		sourcePubKey: tlv.NewRecordT[tlv.TlvType0](r.SourcePubKey),
-		totalAmount:  tlv.NewRecordT[tlv.TlvType1](r.TotalAmount),
-		hops: tlv.NewRecordT[tlv.TlvType2](
-			extractMCHops(r.Hops),
-		),
+		sourcePubKey: route.SourcePubKey,
+		totalAmount:  route.TotalAmount,
+		hops:         extractMCHops(route.Hops),
 	}
 }
 
 // extractMCHops extracts the Hop fields that MC actually uses from a slice of
 // Hops.
-func extractMCHops(hops []*route.Hop) mcHops {
-	return fn.Map(extractMCHop, hops)
+func extractMCHops(hops []*route.Hop) []*mcHop {
+	mcHops := make([]*mcHop, len(hops))
+	for i, hop := range hops {
+		mcHops[i] = extractMCHop(hop)
+	}
+
+	return mcHops
 }
 
 // extractMCHop extracts the Hop fields that MC actually uses from a Hop.
 func extractMCHop(hop *route.Hop) *mcHop {
-	h := mcHop{
-		channelID: tlv.NewPrimitiveRecord[tlv.TlvType0](
-			hop.ChannelID,
-		),
-		pubKeyBytes: tlv.NewRecordT[tlv.TlvType1](hop.PubKeyBytes),
-		amtToFwd:    tlv.NewRecordT[tlv.TlvType2](hop.AmtToForward),
+	return &mcHop{
+		channelID:        hop.ChannelID,
+		pubKeyBytes:      hop.PubKeyBytes,
+		amtToFwd:         hop.AmtToForward,
+		hasBlindingPoint: hop.BlindingPoint != nil,
+		hasCustomRecords: len(hop.CustomRecords) > 0,
 	}
-
-	if hop.BlindingPoint != nil {
-		h.hasBlindingPoint = tlv.SomeRecordT(
-			tlv.NewRecordT[tlv.TlvType3](lnwire.TrueBoolean{}),
-		)
-	}
-
-	if hop.CustomRecords != nil {
-		h.hasCustomRecords = tlv.SomeRecordT(
-			tlv.NewRecordT[tlv.TlvType4](lnwire.TrueBoolean{}),
-		)
-	}
-
-	return &h
 }
 
 // mcRoute holds the bare minimum info about a payment attempt route that MC
 // requires.
 type mcRoute struct {
-	sourcePubKey tlv.RecordT[tlv.TlvType0, route.Vertex]
-	totalAmount  tlv.RecordT[tlv.TlvType1, lnwire.MilliSatoshi]
-	hops         tlv.RecordT[tlv.TlvType2, mcHops]
-}
-
-// Record returns a TLV record that can be used to encode/decode an mcRoute
-// to/from a TLV stream.
-func (r *mcRoute) Record() tlv.Record {
-	recordSize := func() uint64 {
-		var (
-			b   bytes.Buffer
-			buf [8]byte
-		)
-		if err := encodeMCRoute(&b, r, &buf); err != nil {
-			panic(err)
-		}
-
-		return uint64(len(b.Bytes()))
-	}
-
-	return tlv.MakeDynamicRecord(
-		0, r, recordSize, encodeMCRoute, decodeMCRoute,
-	)
-}
-
-func encodeMCRoute(w io.Writer, val interface{}, _ *[8]byte) error {
-	if v, ok := val.(*mcRoute); ok {
-		return serializeRoute(w, v)
-	}
-
-	return tlv.NewTypeForEncodingErr(val, "routing.mcRoute")
-}
-
-func decodeMCRoute(r io.Reader, val interface{}, _ *[8]byte, l uint64) error {
-	if v, ok := val.(*mcRoute); ok {
-		route, err := deserializeRoute(io.LimitReader(r, int64(l)))
-		if err != nil {
-			return err
-		}
-
-		*v = *route
-
-		return nil
-	}
-
-	return tlv.NewTypeForDecodingErr(val, "routing.mcRoute", l, l)
-}
-
-// mcHops is a list of mcHop records.
-type mcHops []*mcHop
-
-// Record returns a TLV record that can be used to encode/decode a list of
-// mcHop to/from a TLV stream.
-func (h *mcHops) Record() tlv.Record {
-	recordSize := func() uint64 {
-		var (
-			b   bytes.Buffer
-			buf [8]byte
-		)
-		if err := encodeMCHops(&b, h, &buf); err != nil {
-			panic(err)
-		}
-
-		return uint64(len(b.Bytes()))
-	}
-
-	return tlv.MakeDynamicRecord(
-		0, h, recordSize, encodeMCHops, decodeMCHops,
-	)
-}
-
-func encodeMCHops(w io.Writer, val interface{}, buf *[8]byte) error {
-	if v, ok := val.(*mcHops); ok {
-		// Encode the number of hops as a var int.
-		if err := tlv.WriteVarInt(w, uint64(len(*v)), buf); err != nil {
-			return err
-		}
-
-		// With that written out, we'll now encode the entries
-		// themselves as a sub-TLV record, which includes its _own_
-		// inner length prefix.
-		for _, hop := range *v {
-			var hopBytes bytes.Buffer
-			if err := serializeHop(&hopBytes, hop); err != nil {
-				return err
-			}
-
-			// We encode the record with a varint length followed by
-			// the _raw_ TLV bytes.
-			tlvLen := uint64(len(hopBytes.Bytes()))
-			if err := tlv.WriteVarInt(w, tlvLen, buf); err != nil {
-				return err
-			}
-
-			if _, err := w.Write(hopBytes.Bytes()); err != nil {
-				return err
-			}
-		}
-
-		return nil
-	}
-
-	return tlv.NewTypeForEncodingErr(val, "routing.mcHops")
-}
-
-func decodeMCHops(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
-	if v, ok := val.(*mcHops); ok {
-		// First, we'll decode the varint that encodes how many hops
-		// are encoded in the stream.
-		numHops, err := tlv.ReadVarInt(r, buf)
-		if err != nil {
-			return err
-		}
-
-		// Now that we know how many records we'll need to read, we can
-		// iterate and read them all out in series.
-		for i := uint64(0); i < numHops; i++ {
-			// Read out the varint that encodes the size of this
-			// inner TLV record.
-			hopSize, err := tlv.ReadVarInt(r, buf)
-			if err != nil {
-				return err
-			}
-
-			// Using this information, we'll create a new limited
-			// reader that'll return an EOF once the end has been
-			// reached so the stream stops consuming bytes.
-			innerTlvReader := &io.LimitedReader{
-				R: r,
-				N: int64(hopSize),
-			}
-
-			hop, err := deserializeHop(innerTlvReader)
-			if err != nil {
-				return err
-			}
-
-			*v = append(*v, hop)
-		}
-
-		return nil
-	}
-
-	return tlv.NewTypeForDecodingErr(val, "routing.mcHops", l, l)
+	sourcePubKey route.Vertex
+	totalAmount  lnwire.MilliSatoshi
+	hops         []*mcHop
 }
 
 // mcHop holds the bare minimum info about a payment attempt route hop that MC
 // requires.
 type mcHop struct {
-	channelID        tlv.RecordT[tlv.TlvType0, uint64]
-	pubKeyBytes      tlv.RecordT[tlv.TlvType1, route.Vertex]
-	amtToFwd         tlv.RecordT[tlv.TlvType2, lnwire.MilliSatoshi]
-	hasBlindingPoint tlv.OptionalRecordT[tlv.TlvType3, lnwire.TrueBoolean]
-	hasCustomRecords tlv.OptionalRecordT[tlv.TlvType4, lnwire.TrueBoolean]
+	channelID        uint64
+	pubKeyBytes      route.Vertex
+	amtToFwd         lnwire.MilliSatoshi
+	hasBlindingPoint bool
+	hasCustomRecords bool
 }
 
 // failNode marks the node indicated by idx in the route as failed. It also
@@ -770,7 +604,7 @@ type mcHop struct {
 // intentionally panics when the self node is failed.
 func (i *interpretedResult) failNode(rt *mcRoute, idx int) {
 	// Mark the node as failing.
-	i.nodeFailure = &rt.hops.Val[idx-1].pubKeyBytes.Val
+	i.nodeFailure = &rt.hops[idx-1].pubKeyBytes
 
 	// Mark the incoming connection as failed for the node. We intent to
 	// penalize as much as we can for a node level failure, including future
@@ -786,7 +620,7 @@ func (i *interpretedResult) failNode(rt *mcRoute, idx int) {
 
 	// If not the ultimate node, mark the outgoing connection as failed for
 	// the node.
-	if idx < len(rt.hops.Val) {
+	if idx < len(rt.hops) {
 		outgoingChannelIdx := idx
 		outPair, _ := getPair(rt, outgoingChannelIdx)
 		i.pairResults[outPair] = failPairResult(0)
@@ -833,18 +667,18 @@ func (i *interpretedResult) successPairRange(rt *mcRoute, fromIdx, toIdx int) {
 func getPair(rt *mcRoute, channelIdx int) (DirectedNodePair,
 	lnwire.MilliSatoshi) {
 
-	nodeTo := rt.hops.Val[channelIdx].pubKeyBytes.Val
+	nodeTo := rt.hops[channelIdx].pubKeyBytes
 	var (
 		nodeFrom route.Vertex
 		amt      lnwire.MilliSatoshi
 	)
 
 	if channelIdx == 0 {
-		nodeFrom = rt.sourcePubKey.Val
-		amt = rt.totalAmount.Val
+		nodeFrom = rt.sourcePubKey
+		amt = rt.totalAmount
 	} else {
-		nodeFrom = rt.hops.Val[channelIdx-1].pubKeyBytes.Val
-		amt = rt.hops.Val[channelIdx-1].amtToFwd.Val
+		nodeFrom = rt.hops[channelIdx-1].pubKeyBytes
+		amt = rt.hops[channelIdx-1].amtToFwd
 	}
 
 	pair := NewDirectedNodePair(nodeFrom, nodeTo)
diff --git a/routing/route/route.go b/routing/route/route.go
index 2d62af465..9aa28759b 100644
--- a/routing/route/route.go
+++ b/routing/route/route.go
@@ -94,32 +94,6 @@ func (v Vertex) String() string {
 	return fmt.Sprintf("%x", v[:])
 }
 
-// Record returns a TLV record that can be used to encode/decode a Vertex
-// to/from a TLV stream.
-func (v *Vertex) Record() tlv.Record {
-	return tlv.MakeStaticRecord(
-		0, v, VertexSize, encodeVertex, decodeVertex,
-	)
-}
-
-func encodeVertex(w io.Writer, val interface{}, _ *[8]byte) error {
-	if b, ok := val.(*Vertex); ok {
-		_, err := w.Write(b[:])
-		return err
-	}
-
-	return tlv.NewTypeForEncodingErr(val, "Vertex")
-}
-
-func decodeVertex(r io.Reader, val interface{}, _ *[8]byte, l uint64) error {
-	if b, ok := val.(*Vertex); ok {
-		_, err := io.ReadFull(r, b[:])
-		return err
-	}
-
-	return tlv.NewTypeForDecodingErr(val, "Vertex", l, VertexSize)
-}
-
 // Hop represents an intermediate or final node of the route. This naming
 // is in line with the definition given in BOLT #4: Onion Routing Protocol.
 // The struct houses the channel along which this hop can be reached and
diff --git a/sample-lnd.conf b/sample-lnd.conf
index 6d64603e8..eeb6a9d31 100644
--- a/sample-lnd.conf
+++ b/sample-lnd.conf
@@ -30,14 +30,14 @@
 ; Rotated logs are compressed in place.
 ; logdir=~/.lnd/logs
 
-; DEPRECATED: Use logging.file.max-files instead.
-; Number of logfiles that the log rotation should keep. Setting it to 0 disables
-; deletion of old log files.
-; maxlogfiles=10
+; Number of logfiles that the log rotation should keep. Setting it to 0 disables deletion of old log files.
+; maxlogfiles=3
 ;
-; DEPRECATED: Use logging.file.max-file-size instead.
 ; Max log file size in MB before it is rotated.
-; maxlogfilesize=20
+; maxlogfilesize=10
+
+; Compression algorithm to use when rotating logs.
+; logcompressor=gzip
 
 ; Time after which an RPCAcceptor will time out and return false if
 ; it hasn't yet received a response.
@@ -988,19 +988,6 @@
 ; Disable logging to the standard LND log file.
 ; logging.file.disable=false
 
-; Number of log files that the log rotation should keep. Setting
-; it to 0 disables deletion of old log files.
-; logging.file.max-files=10
-
-; Max log file size in MB before it is rotated.
-; logging.file.max-file-size=20
-
-; Compression algorithm to use when rotating logs.
-; Default:
-;   logging.file.compressor=gzip
-; Example:
-;   logging.file.compressor=zstd
-
 ; Don't add timestamps to logs written to the standard LND log file.
 ; logging.file.no-timestamps=false
 
diff --git a/watchtower/lookout/lookout.go b/watchtower/lookout/lookout.go
index b40911995..28f52cccd 100644
--- a/watchtower/lookout/lookout.go
+++ b/watchtower/lookout/lookout.go
@@ -1,22 +1,14 @@
 package lookout
 
 import (
-	"errors"
-	"fmt"
 	"sync"
 	"sync/atomic"
-	"time"
 
-	"github.com/btcsuite/btcd/chaincfg/chainhash"
 	"github.com/btcsuite/btcd/wire"
 	"github.com/lightningnetwork/lnd/chainntnfs"
 	"github.com/lightningnetwork/lnd/watchtower/blob"
 )
 
-// ErrLookoutExiting is an error that is returned when the lookout server is
-// in the process of shutting down.
-var ErrLookoutExiting = errors.New("lookout server is shutting down")
-
 // Config houses the Lookout's required resources to properly fulfill it's duty,
 // including block fetching, querying accepted state updates, and construction
 // and publication of justice transactions.
@@ -37,18 +29,6 @@ type Config struct {
 	// Punisher handles the responsibility of crafting and broadcasting
 	// justice transaction for any breached transactions.
 	Punisher Punisher
-
-	// MinBackoff is the minimum amount of time to back-off before
-	// re-attempting to fetch a block.
-	MinBackoff time.Duration
-
-	// MaxBackoff is the maximum amount of time to back-off before
-	// re-attempting to fetch a block.
-	MaxBackoff time.Duration
-
-	// MaxNumRetries is the maximum number of times that we should
-	// re-attempt fetching a block before moving on.
-	MaxNumRetries int
 }
 
 // Lookout will check any incoming blocks against the transactions found in the
@@ -122,49 +102,6 @@ func (l *Lookout) Stop() error {
 	return nil
 }
 
-// fetchBlockWithRetries attempts to fetch a block from the blockchain using
-// its hash. If it fails to fetch the block, it will back-off and retry up to
-// MaxNumRetries times.
-func (l *Lookout) fetchBlockWithRetries(hash *chainhash.Hash) (*wire.MsgBlock,
-	error) {
-
-	backoff := l.cfg.MinBackoff
-
-	updateBackoff := func() {
-		backoff *= 2
-		if backoff > l.cfg.MaxBackoff {
-			backoff = l.cfg.MaxBackoff
-		}
-	}
-
-	var attempt int
-	for {
-		attempt++
-
-		block, err := l.cfg.BlockFetcher.GetBlock(hash)
-		if err == nil {
-			return block, nil
-		}
-
-		if attempt > l.cfg.MaxNumRetries {
-			return nil, fmt.Errorf("failed to fetch block %s "+
-				"after %d attempts: %v", hash, attempt, err)
-		}
-
-		log.Errorf("Failed to fetch block %s (attempt %d): %v. "+
-			"Retrying in %v seconds", hash, attempt, err,
-			backoff.Seconds())
-
-		select {
-		case <-time.After(backoff):
-		case <-l.quit:
-			return nil, ErrLookoutExiting
-		}
-
-		updateBackoff()
-	}
-}
-
 // watchBlocks serially pulls incoming epochs from the epoch source and searches
 // our accepted state updates for any breached transactions. If any are found,
 // we will attempt to decrypt the state updates' encrypted blobs and exact
@@ -181,10 +118,11 @@ func (l *Lookout) watchBlocks(epochs *chainntnfs.BlockEpochEvent) {
 			log.Debugf("Fetching block for (height=%d, hash=%s)",
 				epoch.Height, epoch.Hash)
 
-			// Fetch the full block corresponding to the newly
-			// arriving epoch from the backend.
-			block, err := l.fetchBlockWithRetries(epoch.Hash)
+			// Fetch the full block from the backend corresponding
+			// to the newly arriving epoch.
+			block, err := l.cfg.BlockFetcher.GetBlock(epoch.Hash)
 			if err != nil {
+				// TODO(conner): add retry logic?
 				log.Errorf("Unable to fetch block for "+
 					"(height=%x, hash=%s): %v",
 					epoch.Height, epoch.Hash, err)
diff --git a/watchtower/standalone.go b/watchtower/standalone.go
index b973c9ce4..c652d9c76 100644
--- a/watchtower/standalone.go
+++ b/watchtower/standalone.go
@@ -3,7 +3,6 @@ package watchtower
 import (
 	"net"
 	"sync/atomic"
-	"time"
 
 	"github.com/btcsuite/btcd/btcec/v2"
 	"github.com/lightningnetwork/lnd/brontide"
@@ -66,9 +65,6 @@ func New(cfg *Config) (*Standalone, error) {
 		DB:             cfg.DB,
 		EpochRegistrar: cfg.EpochRegistrar,
 		Punisher:       punisher,
-		MinBackoff:     time.Second,
-		MaxBackoff:     time.Minute,
-		MaxNumRetries:  5,
 	})
 
 	// Create a brontide listener on each of the provided listening


Test patch:
diff --git a/channeldb/migration32/migration_test.go b/channeldb/migration32/migration_test.go
index 703c32a72..1ce6016ed 100644
--- a/channeldb/migration32/migration_test.go
+++ b/channeldb/migration32/migration_test.go
@@ -9,7 +9,6 @@ import (
 	lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
 	"github.com/lightningnetwork/lnd/channeldb/migtest"
 	"github.com/lightningnetwork/lnd/kvdb"
-	"github.com/lightningnetwork/lnd/tlv"
 )
 
 var (
@@ -25,197 +24,20 @@ var (
 	_       = pubKeyY.SetByteSlice(pubkeyBytes)
 	pubkey  = btcec.NewPublicKey(new(btcec.FieldVal).SetInt(4), pubKeyY)
 
-	customRecord = map[uint64][]byte{
-		65536: {4, 2, 2},
-	}
-
-	resultOld1 = paymentResultOld{
+	paymentResultCommon1 = paymentResultCommon{
 		id:               0,
 		timeFwd:          time.Unix(0, 1),
 		timeReply:        time.Unix(0, 2),
 		success:          false,
 		failureSourceIdx: &failureIndex,
 		failure:          &lnwire.FailFeeInsufficient{},
-		route: &Route{
-			TotalTimeLock: 100,
-			TotalAmount:   400,
-			SourcePubKey:  testPub,
-			Hops: []*Hop{
-				// A hop with MPP, AMP and custom
-				// records.
-				{
-					PubKeyBytes:      testPub,
-					ChannelID:        100,
-					OutgoingTimeLock: 300,
-					AmtToForward:     500,
-					MPP: &MPP{
-						paymentAddr: [32]byte{4, 5},
-						totalMsat:   900,
-					},
-					AMP: &AMP{
-						rootShare:  [32]byte{0, 0},
-						setID:      [32]byte{5, 5, 5},
-						childIndex: 90,
-					},
-					CustomRecords: customRecord,
-					Metadata:      []byte{6, 7, 7},
-				},
-				// A legacy hop.
-				{
-					PubKeyBytes:      testPub,
-					ChannelID:        800,
-					OutgoingTimeLock: 4,
-					AmtToForward:     4,
-					LegacyPayload:    true,
-				},
-				// A hop with a blinding key.
-				{
-					PubKeyBytes:      testPub,
-					ChannelID:        800,
-					OutgoingTimeLock: 4,
-					AmtToForward:     4,
-					BlindingPoint:    pubkey,
-					EncryptedData:    []byte{1, 2, 3},
-					TotalAmtMsat:     600,
-				},
-				// A hop with a blinding key and custom
-				// records.
-				{
-					PubKeyBytes:      testPub,
-					ChannelID:        800,
-					OutgoingTimeLock: 4,
-					AmtToForward:     4,
-					CustomRecords:    customRecord,
-					BlindingPoint:    pubkey,
-					EncryptedData:    []byte{1, 2, 3},
-					TotalAmtMsat:     600,
-				},
-			},
-		},
 	}
 
-	resultOld2 = paymentResultOld{
+	paymentResultCommon2 = paymentResultCommon{
 		id:        2,
 		timeFwd:   time.Unix(0, 4),
 		timeReply: time.Unix(0, 7),
 		success:   true,
-		route: &Route{
-			TotalTimeLock: 101,
-			TotalAmount:   401,
-			SourcePubKey:  testPub2,
-			Hops: []*Hop{
-				{
-					PubKeyBytes:      testPub,
-					ChannelID:        800,
-					OutgoingTimeLock: 4,
-					AmtToForward:     4,
-					BlindingPoint:    pubkey,
-					EncryptedData:    []byte{1, 2, 3},
-					CustomRecords:    customRecord,
-					TotalAmtMsat:     600,
-				},
-			},
-		},
-	}
-
-	//nolint:lll
-	resultNew1Hop1 = &mcHop{
-		channelID:   tlv.NewPrimitiveRecord[tlv.TlvType0, uint64](100),
-		pubKeyBytes: tlv.NewRecordT[tlv.TlvType1](testPub),
-		amtToFwd:    tlv.NewPrimitiveRecord[tlv.TlvType2, lnwire.MilliSatoshi](500),
-		hasCustomRecords: tlv.SomeRecordT(
-			tlv.ZeroRecordT[tlv.TlvType4, lnwire.TrueBoolean](),
-		),
-	}
-
-	//nolint:lll
-	resultNew1Hop2 = &mcHop{
-		channelID:   tlv.NewPrimitiveRecord[tlv.TlvType0, uint64](800),
-		pubKeyBytes: tlv.NewRecordT[tlv.TlvType1](testPub),
-		amtToFwd:    tlv.NewPrimitiveRecord[tlv.TlvType2, lnwire.MilliSatoshi](4),
-	}
-
-	//nolint:lll
-	resultNew1Hop3 = &mcHop{
-		channelID:   tlv.NewPrimitiveRecord[tlv.TlvType0, uint64](800),
-		pubKeyBytes: tlv.NewRecordT[tlv.TlvType1](testPub),
-		amtToFwd:    tlv.NewPrimitiveRecord[tlv.TlvType2, lnwire.MilliSatoshi](4),
-		hasBlindingPoint: tlv.SomeRecordT(
-			tlv.ZeroRecordT[tlv.TlvType3, lnwire.TrueBoolean](),
-		),
-	}
-
-	//nolint:lll
-	resultNew1Hop4 = &mcHop{
-		channelID:   tlv.NewPrimitiveRecord[tlv.TlvType0, uint64](800),
-		pubKeyBytes: tlv.NewRecordT[tlv.TlvType1](testPub),
-		amtToFwd:    tlv.NewPrimitiveRecord[tlv.TlvType2, lnwire.MilliSatoshi](4),
-		hasCustomRecords: tlv.SomeRecordT(
-			tlv.ZeroRecordT[tlv.TlvType4, lnwire.TrueBoolean](),
-		),
-		hasBlindingPoint: tlv.SomeRecordT(
-			tlv.ZeroRecordT[tlv.TlvType3, lnwire.TrueBoolean](),
-		),
-	}
-
-	//nolint:lll
-	resultNew2Hop1 = &mcHop{
-		channelID:   tlv.NewPrimitiveRecord[tlv.TlvType0, uint64](800),
-		pubKeyBytes: tlv.NewRecordT[tlv.TlvType1](testPub),
-		amtToFwd:    tlv.NewPrimitiveRecord[tlv.TlvType2, lnwire.MilliSatoshi](4),
-		hasCustomRecords: tlv.SomeRecordT(
-			tlv.ZeroRecordT[tlv.TlvType4, lnwire.TrueBoolean](),
-		),
-		hasBlindingPoint: tlv.SomeRecordT(
-			tlv.ZeroRecordT[tlv.TlvType3, lnwire.TrueBoolean](),
-		),
-	}
-
-	//nolint:lll
-	resultNew1 = paymentResultNew{
-		id: 0,
-		timeFwd: tlv.NewPrimitiveRecord[tlv.TlvType0](
-			uint64(time.Unix(0, 1).UnixNano()),
-		),
-		timeReply: tlv.NewPrimitiveRecord[tlv.TlvType1](
-			uint64(time.Unix(0, 2).UnixNano()),
-		),
-		failure: tlv.SomeRecordT(
-			tlv.NewRecordT[tlv.TlvType3](
-				*newPaymentFailure(
-					&failureIndex,
-					&lnwire.FailFeeInsufficient{},
-				),
-			),
-		),
-		route: tlv.NewRecordT[tlv.TlvType2](mcRoute{
-			sourcePubKey: tlv.NewRecordT[tlv.TlvType0](testPub),
-			totalAmount:  tlv.NewRecordT[tlv.TlvType1, lnwire.MilliSatoshi](400),
-			hops: tlv.NewRecordT[tlv.TlvType2, mcHops](mcHops{
-				resultNew1Hop1,
-				resultNew1Hop2,
-				resultNew1Hop3,
-				resultNew1Hop4,
-			}),
-		}),
-	}
-
-	//nolint:lll
-	resultNew2 = paymentResultNew{
-		id: 2,
-		timeFwd: tlv.NewPrimitiveRecord[tlv.TlvType0, uint64](
-			uint64(time.Unix(0, 4).UnixNano()),
-		),
-		timeReply: tlv.NewPrimitiveRecord[tlv.TlvType1, uint64](
-			uint64(time.Unix(0, 7).UnixNano()),
-		),
-		route: tlv.NewRecordT[tlv.TlvType2](mcRoute{
-			sourcePubKey: tlv.NewRecordT[tlv.TlvType0](testPub2),
-			totalAmount:  tlv.NewRecordT[tlv.TlvType1, lnwire.MilliSatoshi](401),
-			hops: tlv.NewRecordT[tlv.TlvType2](mcHops{
-				resultNew2Hop1,
-			}),
-		}),
 	}
 )
 
@@ -223,14 +45,153 @@ var (
 // migration function correctly migrates the MC store from using the old route
 // encoding to using the newer, more minimal route encoding.
 func TestMigrateMCRouteSerialisation(t *testing.T) {
-	var (
-		resultsOld = []*paymentResultOld{
-			&resultOld1, &resultOld2,
-		}
-		expectedResultsNew = []*paymentResultNew{
-			&resultNew1, &resultNew2,
-		}
-	)
+	customRecord := map[uint64][]byte{
+		65536: {4, 2, 2},
+	}
+
+	resultsOld := []*paymentResultOld{
+		{
+			paymentResultCommon: paymentResultCommon1,
+			route: &Route{
+				TotalTimeLock: 100,
+				TotalAmount:   400,
+				SourcePubKey:  testPub,
+				Hops: []*Hop{
+					// A hop with MPP, AMP and custom
+					// records.
+					{
+						PubKeyBytes:      testPub,
+						ChannelID:        100,
+						OutgoingTimeLock: 300,
+						AmtToForward:     500,
+						MPP: &MPP{
+							paymentAddr: [32]byte{
+								4, 5,
+							},
+							totalMsat: 900,
+						},
+						AMP: &AMP{
+							rootShare: [32]byte{
+								0, 0,
+							},
+							setID: [32]byte{
+								5, 5, 5,
+							},
+							childIndex: 90,
+						},
+						CustomRecords: customRecord,
+						Metadata:      []byte{6, 7, 7},
+					},
+					// A legacy hop.
+					{
+						PubKeyBytes:      testPub,
+						ChannelID:        800,
+						OutgoingTimeLock: 4,
+						AmtToForward:     4,
+						LegacyPayload:    true,
+					},
+					// A hop with a blinding key.
+					{
+						PubKeyBytes:      testPub,
+						ChannelID:        800,
+						OutgoingTimeLock: 4,
+						AmtToForward:     4,
+						BlindingPoint:    pubkey,
+						EncryptedData: []byte{
+							1, 2, 3,
+						},
+						TotalAmtMsat: 600,
+					},
+					// A hop with a blinding key and custom
+					// records.
+					{
+						PubKeyBytes:      testPub,
+						ChannelID:        800,
+						OutgoingTimeLock: 4,
+						AmtToForward:     4,
+						CustomRecords:    customRecord,
+						BlindingPoint:    pubkey,
+						EncryptedData: []byte{
+							1, 2, 3,
+						},
+						TotalAmtMsat: 600,
+					},
+				},
+			},
+		},
+		{
+			paymentResultCommon: paymentResultCommon2,
+			route: &Route{
+				TotalTimeLock: 101,
+				TotalAmount:   401,
+				SourcePubKey:  testPub2,
+				Hops: []*Hop{
+					{
+						PubKeyBytes:      testPub,
+						ChannelID:        800,
+						OutgoingTimeLock: 4,
+						AmtToForward:     4,
+						BlindingPoint:    pubkey,
+						EncryptedData: []byte{
+							1, 2, 3,
+						},
+						TotalAmtMsat: 600,
+					},
+				},
+			},
+		},
+	}
+
+	expectedResultsNew := []*paymentResultNew{
+		{
+			paymentResultCommon: paymentResultCommon1,
+			route: &mcRoute{
+				sourcePubKey: testPub,
+				totalAmount:  400,
+				hops: []*mcHop{
+					{
+						channelID:        100,
+						pubKeyBytes:      testPub,
+						amtToFwd:         500,
+						hasCustomRecords: true,
+					},
+					{
+						channelID:   800,
+						pubKeyBytes: testPub,
+						amtToFwd:    4,
+					},
+					{
+						channelID:        800,
+						pubKeyBytes:      testPub,
+						amtToFwd:         4,
+						hasBlindingPoint: true,
+					},
+					{
+						channelID:        800,
+						pubKeyBytes:      testPub,
+						amtToFwd:         4,
+						hasBlindingPoint: true,
+						hasCustomRecords: true,
+					},
+				},
+			},
+		},
+		{
+			paymentResultCommon: paymentResultCommon2,
+			route: &mcRoute{
+				sourcePubKey: testPub2,
+				totalAmount:  401,
+				hops: []*mcHop{
+					{
+						channelID:        800,
+						pubKeyBytes:      testPub,
+						amtToFwd:         4,
+						hasBlindingPoint: true,
+					},
+				},
+			},
+		},
+	}
 
 	// Prime the database with some mission control data that uses the
 	// old route encoding.
diff --git a/fn/either_test.go b/fn/either_test.go
index dca15f8d9..e00891b54 100644
--- a/fn/either_test.go
+++ b/fn/either_test.go
@@ -10,17 +10,17 @@ func TestPropConstructorEliminatorDuality(t *testing.T) {
 		Len := func(s string) int { return len(s) } // smh
 		if isRight {
 			v := ElimEither(
+				NewRight[int, string](s),
 				Iden[int],
 				Len,
-				NewRight[int, string](s),
 			)
 			return v == Len(s)
 		}
 
 		v := ElimEither(
+			NewLeft[int, string](i),
 			Iden[int],
 			Len,
-			NewLeft[int, string](i),
 		)
 		return v == i
 	}
@@ -99,18 +99,16 @@ func TestPropToOptionIdentities(t *testing.T) {
 		if isRight {
 			e = NewRight[int, string](s)
 
-			r2O := e.RightToOption() == Some(s)
-			o2R := e == OptionToRight[string, int, string](
-				Some(s), i,
-			)
-			l2O := e.LeftToOption() == None[int]()
+			r2O := e.RightToSome() == Some(s)
+			o2R := e == SomeToRight(Some(s), i)
+			l2O := e.LeftToSome() == None[int]()
 
 			return r2O && o2R && l2O
 		} else {
 			e = NewLeft[int, string](i)
-			l2O := e.LeftToOption() == Some(i)
-			o2L := e == OptionToLeft[int, int](Some(i), s)
-			r2O := e.RightToOption() == None[string]()
+			l2O := e.LeftToSome() == Some(i)
+			o2L := e == SomeToLeft(Some(i), s)
+			r2O := e.RightToSome() == None[string]()
 
 			return l2O && o2L && r2O
 		}
diff --git a/fn/list_test.go b/fn/list_test.go
index efe2c5a92..a2a1261a0 100644
--- a/fn/list_test.go
+++ b/fn/list_test.go
@@ -743,7 +743,7 @@ func TestFilterIdempotence(t *testing.T) {
 
 				filtered := l.Filter(pred)
 
-				filteredAgain := Filter(pred, filtered)
+				filteredAgain := Filter(filtered, pred)
 
 				return slices.Equal(filtered, filteredAgain)
 			},
diff --git a/fn/option_test.go b/fn/option_test.go
new file mode 100644
index 000000000..69f6608d3
--- /dev/null
+++ b/fn/option_test.go
@@ -0,0 +1,53 @@
+package fn
+
+import (
+	"errors"
+	"fmt"
+	"testing"
+	"testing/quick"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestOptionUnwrapOrFail(t *testing.T) {
+	require.Equal(t, Some(1).UnwrapOrFail(t), 1)
+}
+
+func TestSomeToOk(t *testing.T) {
+	err := errors.New("err")
+	require.Equal(t, Some(1).SomeToOk(err), Ok(1))
+	require.Equal(t, None[uint8]().SomeToOk(err), Err[uint8](err))
+}
+
+func TestSomeToOkf(t *testing.T) {
+	errStr := "err"
+	require.Equal(t, Some(1).SomeToOkf(errStr), Ok(1))
+	require.Equal(
+		t, None[uint8]().SomeToOkf(errStr),
+		Err[uint8](fmt.Errorf(errStr)),
+	)
+}
+
+func TestPropTransposeOptResInverts(t *testing.T) {
+	f := func(i uint) bool {
+		var o Option[Result[uint]]
+		switch i % 3 {
+		case 0:
+			o = Some(Ok(i))
+		case 1:
+			o = Some(Errf[uint]("error"))
+		case 2:
+			o = None[Result[uint]]()
+		default:
+			return false
+		}
+
+		odd := TransposeOptRes(o) ==
+			TransposeOptRes(TransposeResOpt(TransposeOptRes(o)))
+		even := TransposeResOpt(TransposeOptRes(o)) == o
+
+		return odd && even
+	}
+
+	require.NoError(t, quick.Check(f, nil))
+}
diff --git a/fn/result_test.go b/fn/result_test.go
new file mode 100644
index 000000000..2b5d942a4
--- /dev/null
+++ b/fn/result_test.go
@@ -0,0 +1,98 @@
+package fn
+
+import (
+	"errors"
+	"fmt"
+	"testing"
+	"testing/quick"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestResultUnwrapOrFail(t *testing.T) {
+	require.Equal(t, Ok(1).UnwrapOrFail(t), 1)
+}
+
+func TestOkToSome(t *testing.T) {
+	require.Equal(t, Ok(1).OkToSome(), Some(1))
+	require.Equal(
+		t, Err[uint8](errors.New("err")).OkToSome(), None[uint8](),
+	)
+}
+
+func TestMapOk(t *testing.T) {
+	inc := func(i int) int {
+		return i + 1
+	}
+	f := func(i int) bool {
+		ok := Ok(i)
+		return MapOk(inc)(ok) == Ok(inc(i))
+	}
+
+	require.NoError(t, quick.Check(f, nil))
+}
+
+func TestFlattenResult(t *testing.T) {
+	f := func(i int) bool {
+		e := fmt.Errorf("error")
+
+		x := FlattenResult(Ok(Ok(i))) == Ok(i)
+		y := FlattenResult(Ok(Err[int](e))) == Err[int](e)
+		z := FlattenResult(Err[Result[int]](e)) == Err[int](e)
+
+		return x && y && z
+	}
+
+	require.NoError(t, quick.Check(f, nil))
+}
+
+func TestPropTransposeResOptInverts(t *testing.T) {
+	f := func(i uint) bool {
+		var r Result[Option[uint]]
+		switch i % 3 {
+		case 0:
+			r = Ok(Some(i))
+		case 1:
+			r = Ok(None[uint]())
+		case 2:
+			r = Errf[Option[uint]]("error")
+		default:
+			return false
+		}
+
+		odd := TransposeResOpt(TransposeOptRes(TransposeResOpt(r))) ==
+			TransposeResOpt(r)
+
+		even := TransposeOptRes(TransposeResOpt(r)) == r
+
+		return odd && even
+	}
+
+	require.NoError(t, quick.Check(f, nil))
+}
+
+func TestSinkOnErrNoContinutationCall(t *testing.T) {
+	called := false
+	res := Err[uint8](errors.New("err")).Sink(
+		func(a uint8) error {
+			called = true
+			return nil
+		},
+	)
+
+	require.False(t, called)
+	require.NotNil(t, res)
+}
+
+func TestSinkOnOkContinuationCall(t *testing.T) {
+	called := false
+	res := Ok(uint8(1)).Sink(
+		func(a uint8) error {
+			called = true
+			return nil
+		},
+	)
+
+	require.True(t, called)
+	require.Nil(t, res)
+}
diff --git a/fn/slice_test.go b/fn/slice_test.go
index 86c870ff8..7269f801e 100644
--- a/fn/slice_test.go
+++ b/fn/slice_test.go
@@ -2,6 +2,7 @@ package fn
 
 import (
 	"fmt"
+	"math/rand"
 	"slices"
 	"testing"
 	"testing/quick"
@@ -15,30 +16,30 @@ func odd(a int) bool  { return a%2 != 0 }
 
 func TestAll(t *testing.T) {
 	x := []int{0, 2, 4, 6, 8}
-	require.True(t, All(even, x))
-	require.False(t, All(odd, x))
+	require.True(t, All(x, even))
+	require.False(t, All(x, odd))
 
 	y := []int{1, 3, 5, 7, 9}
-	require.False(t, All(even, y))
-	require.True(t, All(odd, y))
+	require.False(t, All(y, even))
+	require.True(t, All(y, odd))
 
 	z := []int{0, 2, 4, 6, 9}
-	require.False(t, All(even, z))
-	require.False(t, All(odd, z))
+	require.False(t, All(z, even))
+	require.False(t, All(z, odd))
 }
 
 func TestAny(t *testing.T) {
 	x := []int{1, 3, 5, 7, 9}
-	require.False(t, Any(even, x))
-	require.True(t, Any(odd, x))
+	require.False(t, Any(x, even))
+	require.True(t, Any(x, odd))
 
 	y := []int{0, 3, 5, 7, 9}
-	require.True(t, Any(even, y))
-	require.True(t, Any(odd, y))
+	require.True(t, Any(y, even))
+	require.True(t, Any(y, odd))
 
 	z := []int{0, 2, 4, 6, 8}
-	require.True(t, Any(even, z))
-	require.False(t, Any(odd, z))
+	require.True(t, Any(z, even))
+	require.False(t, Any(z, odd))
 }
 
 func TestMap(t *testing.T) {
@@ -46,7 +47,7 @@ func TestMap(t *testing.T) {
 
 	x := []int{0, 2, 4, 6, 8}
 
-	y := Map(inc, x)
+	y := Map(x, inc)
 
 	z := []int{1, 3, 5, 7, 9}
 
@@ -56,11 +57,11 @@ func TestMap(t *testing.T) {
 func TestFilter(t *testing.T) {
 	x := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
 
-	y := Filter(even, x)
+	y := Filter(x, even)
 
-	require.True(t, All(even, y))
+	require.True(t, All(y, even))
 
-	z := Filter(odd, y)
+	z := Filter(y, odd)
 
 	require.Zero(t, len(z))
 }
@@ -71,7 +72,7 @@ func TestFoldl(t *testing.T) {
 
 	x := []int{0, 1, 2, 3, 4}
 
-	r := Foldl(stupid, seed, x)
+	r := Foldl(seed, x, stupid)
 
 	require.True(t, slices.Equal(x, r))
 }
@@ -82,7 +83,7 @@ func TestFoldr(t *testing.T) {
 
 	x := []int{0, 1, 2, 3, 4}
 
-	z := Foldr(stupid, seed, x)
+	z := Foldr(seed, x, stupid)
 
 	slices.Reverse[[]int](x)
 
@@ -95,9 +96,9 @@ func TestFind(t *testing.T) {
 	div3 := func(a int) bool { return a%3 == 0 }
 	div8 := func(a int) bool { return a%8 == 0 }
 
-	require.Equal(t, Find(div3, x), Some(12))
+	require.Equal(t, Find(x, div3), Some(12))
 
-	require.Equal(t, Find(div8, x), None[int]())
+	require.Equal(t, Find(x, div8), None[int]())
 }
 
 func TestFlatten(t *testing.T) {
@@ -116,7 +117,7 @@ func TestSpan(t *testing.T) {
 	x := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
 	lt5 := func(a int) bool { return a < 5 }
 
-	low, high := Span(lt5, x)
+	low, high := Span(x, lt5)
 
 	require.True(t, slices.Equal(low, []int{0, 1, 2, 3, 4}))
 	require.True(t, slices.Equal(high, []int{5, 6, 7, 8, 9}))
@@ -134,7 +135,7 @@ func TestZipWith(t *testing.T) {
 	eq := func(a, b int) bool { return a == b }
 	x := []int{0, 1, 2, 3, 4}
 	y := Replicate(5, 1)
-	z := ZipWith(eq, x, y)
+	z := ZipWith(x, y, eq)
 	require.True(t, slices.Equal(
 		z, []bool{false, true, false, false, false},
 	))
@@ -289,8 +290,8 @@ func TestHasDuplicates(t *testing.T) {
 func TestPropForEachConcMapIsomorphism(t *testing.T) {
 	f := func(incSize int, s []int) bool {
 		inc := func(i int) int { return i + incSize }
-		mapped := Map(inc, s)
-		conc := ForEachConc(inc, s)
+		mapped := Map(s, inc)
+		conc := ForEachConc(s, inc)
 
 		return slices.Equal(mapped, conc)
 	}
@@ -318,7 +319,7 @@ func TestPropForEachConcOutperformsMapWhenExpensive(t *testing.T) {
 		c := make(chan bool, 1)
 
 		go func() {
-			Map(inc, s)
+			Map(s, inc)
 			select {
 			case c <- false:
 			default:
@@ -326,7 +327,7 @@ func TestPropForEachConcOutperformsMapWhenExpensive(t *testing.T) {
 		}()
 
 		go func() {
-			ForEachConc(inc, s)
+			ForEachConc(s, inc)
 			select {
 			case c <- true:
 			default:
@@ -351,14 +352,14 @@ func TestPropFindIdxFindIdentity(t *testing.T) {
 			return i%div == mod
 		}
 
-		foundIdx := FindIdx(pred, s)
+		foundIdx := FindIdx(s, pred)
 
 		// onlyVal :: Option[T2[A, B]] -> Option[B]
 		onlyVal := MapOption(func(t2 T2[int, uint8]) uint8 {
 			return t2.Second()
 		})
 
-		valuesEqual := Find(pred, s) == onlyVal(foundIdx)
+		valuesEqual := Find(s, pred) == onlyVal(foundIdx)
 
 		idxGetsVal := ElimOption(
 			foundIdx,
@@ -382,7 +383,7 @@ func TestPropLastTailIsLast(t *testing.T) {
 			return true
 		}
 
-		return Last(s) == ChainOption(Last[uint8])(Tail(s))
+		return Last(s) == FlatMapOption(Last[uint8])(Tail(s))
 	}
 
 	require.NoError(t, quick.Check(f, nil))
@@ -395,7 +396,7 @@ func TestPropHeadInitIsHead(t *testing.T) {
 			return true
 		}
 
-		return Head(s) == ChainOption(Head[uint8])(Init(s))
+		return Head(s) == FlatMapOption(Head[uint8])(Init(s))
 	}
 
 	require.NoError(t, quick.Check(f, nil))
@@ -413,6 +414,122 @@ func TestPropTailDecrementsLength(t *testing.T) {
 	require.NoError(t, quick.Check(f, nil))
 }
 
+func TestSingletonTailIsEmpty(t *testing.T) {
+	require.Equal(t, Tail([]int{1}), Some([]int{}))
+}
+
+func TestSingletonInitIsEmpty(t *testing.T) {
+	require.Equal(t, Init([]int{1}), Some([]int{}))
+}
+
+// TestPropAlwaysNoneEmptyFilterMap ensures the property that if we were to
+// always return none from our filter function then we would end up with an
+// empty slice.
+func TestPropAlwaysNoneEmptyFilterMap(t *testing.T) {
+	f := func(s []int) bool {
+		filtered := FilterMap(s, Const[int](None[int]()))
+		return len(filtered) == 0
+	}
+
+	require.NoError(t, quick.Check(f, nil))
+}
+
+// TestPropFilterMapSomeIdentity ensures that if the filter function is a
+// trivial lift into Option space, then we will get back the original slice.
+func TestPropFilterMapSomeIdentity(t *testing.T) {
+	f := func(s []int) bool {
+		filtered := FilterMap(s, Some[int])
+		return slices.Equal(s, filtered)
+	}
+
+	require.NoError(t, quick.Check(f, nil))
+}
+
+// TestPropFilterMapCantGrow ensures that regardless of the filter functions
+// return values, we will never end up with a slice larger than the original.
+func TestPropFilterMapCantGrow(t *testing.T) {
+	f := func(s []int) bool {
+		filterFunc := func(i int) Option[int] {
+			if rand.Int()%2 == 0 {
+				return None[int]()
+			}
+
+			return Some(i + rand.Int())
+		}
+
+		return len(FilterMap(s, filterFunc)) <= len(s)
+	}
+
+	require.NoError(t, quick.Check(f, nil))
+}
+
+// TestPropFilterMapBisectIdentity ensures that the concatenation of the
+// FilterMaps is the same as the FilterMap of the concatenation.
+func TestPropFilterMapBisectIdentity(t *testing.T) {
+	f := func(s []int) bool {
+		sz := len(s)
+		first := s[0 : sz/2]
+		second := s[sz/2 : sz]
+
+		filterFunc := func(i int) Option[int] {
+			if i%2 == 0 {
+				return None[int]()
+			}
+
+			return Some(i)
+		}
+
+		firstFiltered := FilterMap(first, filterFunc)
+		secondFiltered := FilterMap(second, filterFunc)
+		allFiltered := FilterMap(s, filterFunc)
+		reassembled := slices.Concat(firstFiltered, secondFiltered)
+
+		return slices.Equal(allFiltered, reassembled)
+	}
+
+	require.NoError(t, quick.Check(f, nil))
+}
+
+// TestTraverseOkIdentity ensures that trivially lifting the elements of a slice
+// via the Ok function during a Traverse is equivalent to just lifting the
+// entire slice via the Ok function.
+func TestPropTraverseOkIdentity(t *testing.T) {
+	f := func(s []int) bool {
+		traversed := TraverseResult(s, Ok[int])
+
+		traversedOk := traversed.UnwrapOrFail(t)
+
+		return slices.Equal(s, traversedOk)
+	}
+
+	require.NoError(t, quick.Check(f, nil))
+}
+
+// TestPropTraverseSingleErrEjection ensures that if the traverse function
+// returns even a single error, then the entire Traverse will error.
+func TestPropTraverseSingleErrEjection(t *testing.T) {
+	f := func(s []int, errIdx uint8) bool {
+		if len(s) == 0 {
+			return true
+		}
+
+		errIdxMut := int(errIdx) % len(s)
+		f := func(i int) Result[int] {
+			if errIdxMut == 0 {
+				return Errf[int]("err")
+			}
+
+			errIdxMut--
+
+			return Ok(i)
+		}
+
+		return TraverseResult(s, f).IsErr()
+	}
+
+	require.NoError(t, quick.Check(f, nil))
+}
+
 func TestPropInitDecrementsLength(t *testing.T) {
 	f := func(s []uint8) bool {
 		if len(s) == 0 {
@@ -425,10 +542,137 @@ func TestPropInitDecrementsLength(t *testing.T) {
 	require.NoError(t, quick.Check(f, nil))
 }
 
-func TestSingletonTailIsEmpty(t *testing.T) {
-	require.Equal(t, Tail([]int{1}), Some([]int{}))
+// TestPropTrimNonesEqualsFilterMapIden checks that if we use the Iden
+// function when calling FilterMap on a slice of Options that we get the same
+// result as we would if we called TrimNones on it.
+func TestPropTrimNonesEqualsFilterMapIden(t *testing.T) {
+	f := func(s []uint8) bool {
+		withNones := make([]Option[uint8], len(s))
+		for i, x := range s {
+			if x%3 == 0 {
+				withNones[i] = None[uint8]()
+			} else {
+				withNones[i] = Some(x)
+			}
+		}
+
+		return slices.Equal(
+			FilterMap(withNones, Iden[Option[uint8]]),
+			TrimNones(withNones),
+		)
+	}
+
+	require.NoError(t, quick.Check(f, nil))
 }
 
-func TestSingletonInitIsEmpty(t *testing.T) {
-	require.Equal(t, Init([]int{1}), Some([]int{}))
+// TestPropCollectResultsSingleErrEjection ensures that if there is even a
+// single error in the batch, then CollectResults will return an error.
+func TestPropCollectResultsSingleErrEjection(t *testing.T) {
+	f := func(s []int, errIdx uint8) bool {
+		if len(s) == 0 {
+			return true
+		}
+
+		errIdxMut := int(errIdx) % len(s)
+		f := func(i int) Result[int] {
+			if errIdxMut == 0 {
+				return Errf[int]("err")
+			}
+
+			errIdxMut--
+
+			return Ok(i)
+		}
+
+		return CollectResults(Map(s, f)).IsErr()
+	}
+
+	require.NoError(t, quick.Check(f, nil))
+}
+
+// TestPropCollectResultsNoErrUnwrap ensures that if there are no errors in the
+// results then we end up with unwrapping all of the Results in the slice.
+func TestPropCollectResultsNoErrUnwrap(t *testing.T) {
+	f := func(s []int) bool {
+		res := CollectResults(Map(s, Ok[int]))
+		return !res.isRight && slices.Equal(res.left, s)
+	}
+
+	require.NoError(t, quick.Check(f, nil))
+}
+
+// TestPropTraverseSomeIdentity ensures that trivially lifting the elements of a
+// slice via the Some function during a Traverse is equivalent to just lifting
+// the entire slice via the Some function.
+func TestPropTraverseSomeIdentity(t *testing.T) {
+	f := func(s []int) bool {
+		traversed := TraverseOption(s, Some[int])
+
+		traversedSome := traversed.UnwrapOrFail(t)
+
+		return slices.Equal(s, traversedSome)
+	}
+
+	require.NoError(t, quick.Check(f, nil))
+}
+
+// TestTraverseSingleNoneEjection ensures that if the traverse function returns
+// even a single None, then the entire Traverse will return None.
+func TestTraverseSingleNoneEjection(t *testing.T) {
+	f := func(s []int, errIdx uint8) bool {
+		if len(s) == 0 {
+			return true
+		}
+
+		errIdxMut := int(errIdx) % len(s)
+		f := func(i int) Option[int] {
+			if errIdxMut == 0 {
+				return None[int]()
+			}
+
+			errIdxMut--
+
+			return Some(i)
+		}
+
+		return TraverseOption(s, f).IsNone()
+	}
+
+	require.NoError(t, quick.Check(f, nil))
+}
+
+// TestPropCollectOptionsSingleNoneEjection ensures that if there is even a
+// single None in the batch, then CollectOptions will return a None.
+func TestPropCollectOptionsSingleNoneEjection(t *testing.T) {
+	f := func(s []int, errIdx uint8) bool {
+		if len(s) == 0 {
+			return true
+		}
+
+		errIdxMut := int(errIdx) % len(s)
+		f := func(i int) Option[int] {
+			if errIdxMut == 0 {
+				return None[int]()
+			}
+
+			errIdxMut--
+
+			return Some(i)
+		}
+
+		return CollectOptions(Map(s, f)).IsNone()
+	}
+
+	require.NoError(t, quick.Check(f, nil))
+}
+
+// TestPropCollectOptionsNoNoneUnwrap ensures that if there are no nones in the
+// options then we end up with unwrapping all of the Options in the slice.
+func TestPropCollectOptionsNoNoneUnwrap(t *testing.T) {
+	f := func(s []int) bool {
+		res := CollectOptions(Map(s, Some[int]))
+		return res.isSome && slices.Equal(res.some, s)
+	}
+
+	require.NoError(t, quick.Check(f, nil))
 }
diff --git a/htlcswitch/link_test.go b/htlcswitch/link_test.go
index 78bb99d04..5bfb79ee0 100644
--- a/htlcswitch/link_test.go
+++ b/htlcswitch/link_test.go
@@ -27,7 +27,6 @@ import (
 	"github.com/lightningnetwork/lnd/channeldb"
 	"github.com/lightningnetwork/lnd/channeldb/models"
 	"github.com/lightningnetwork/lnd/contractcourt"
-	"github.com/lightningnetwork/lnd/fn"
 	"github.com/lightningnetwork/lnd/htlcswitch/hodl"
 	"github.com/lightningnetwork/lnd/htlcswitch/hop"
 	"github.com/lightningnetwork/lnd/input"
@@ -865,7 +864,7 @@ func TestChannelLinkCancelFullCommitment(t *testing.T) {
 	)
 
 	// Fill up the commitment from Alice's side with 20 sat payments.
-	count := int(maxInflightHtlcs)
+	count := (input.MaxHTLCNumber / 2)
 	amt := lnwire.NewMSatFromSatoshis(20000)
 
 	htlcAmt, totalTimelock, hopsForwards := generateHops(amt,
@@ -903,17 +902,17 @@ func TestChannelLinkCancelFullCommitment(t *testing.T) {
 
 	// Now make an additional payment from Alice to Bob, this should be
 	// canceled because the commitment in this direction is full.
-	resp := makePayment(
+	err = <-makePayment(
 		n.aliceServer, n.bobServer, firstHop, hopsForwards, amt,
 		htlcAmt, totalTimelock,
-	)
-
-	paymentErr, timeoutErr := fn.RecvOrTimeout(resp.err, 30*time.Second)
-	require.NoError(t, timeoutErr, "timeout receiving payment resp")
-	require.Error(t, paymentErr, "overflow payment should have failed")
-
-	var lerr *LinkError
-	require.ErrorAs(t, paymentErr, &lerr)
+	).err
+	if err == nil {
+		t.Fatalf("overflow payment should have failed")
+	}
+	lerr, ok := err.(*LinkError)
+	if !ok {
+		t.Fatalf("expected LinkError, got: %T", err)
+	}
 
 	msg := lerr.WireMessage()
 	if _, ok := msg.(*lnwire.FailTemporaryChannelFailure); !ok {
@@ -939,9 +938,10 @@ func TestChannelLinkCancelFullCommitment(t *testing.T) {
 
 	// Ensure that all of the payments sent by alice eventually succeed.
 	for errChan := range aliceErrChan {
-		receivedErr, err := fn.RecvOrTimeout(errChan, 30*time.Second)
-		require.NoError(t, err, "payment timeout")
-		require.NoError(t, receivedErr, "alice payment failed")
+		err := <-errChan
+		if err != nil {
+			t.Fatalf("alice payment failed: %v", err)
+		}
 	}
 }
 
diff --git a/htlcswitch/switch_test.go b/htlcswitch/switch_test.go
index 5d24e2daa..825ee6c65 100644
--- a/htlcswitch/switch_test.go
+++ b/htlcswitch/switch_test.go
@@ -22,7 +22,6 @@ import (
 	"github.com/lightningnetwork/lnd/htlcswitch/hodl"
 	"github.com/lightningnetwork/lnd/htlcswitch/hop"
 	"github.com/lightningnetwork/lnd/lntest/mock"
-	"github.com/lightningnetwork/lnd/lntest/wait"
 	"github.com/lightningnetwork/lnd/lntypes"
 	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
@@ -4290,19 +4289,14 @@ func TestSwitchDustForwarding(t *testing.T) {
 
 	// We'll test that once the default threshold is exceeded on the
 	// Alice -> Bob channel, either side's calls to SendHTLC will fail.
-	numHTLCs := maxInflightHtlcs
+	//
+	// Alice will send 354 HTLC's of 700sats. Bob will also send 354 HTLC's
+	// of 700sats.
+	numHTLCs := 354
 	aliceAttemptID, bobAttemptID := numHTLCs, numHTLCs
 	amt := lnwire.NewMSatFromSatoshis(700)
 	aliceBobFirstHop := n.aliceChannelLink.ShortChanID()
 
-	// We decreased the max number of inflight HTLCs therefore we also need
-	// do decrease the max fee exposure.
-	maxFeeExposure := lnwire.NewMSatFromSatoshis(74500)
-	n.aliceChannelLink.cfg.MaxFeeExposure = maxFeeExposure
-	n.firstBobChannelLink.cfg.MaxFeeExposure = maxFeeExposure
-
-	// Alice will send 50 HTLC's of 700sats. Bob will also send 50 HTLC's
-	// of 700sats.
 	sendDustHtlcs(t, n, true, amt, aliceBobFirstHop, numHTLCs)
 	sendDustHtlcs(t, n, false, amt, aliceBobFirstHop, numHTLCs)
 
@@ -4324,13 +4318,22 @@ func TestSwitchDustForwarding(t *testing.T) {
 		OnionBlob:   blob,
 	}
 
-	// This is the expected dust without taking the commitfee into account.
-	expectedDust := maxInflightHtlcs * 2 * amt
+	checkAlmostDust := func(link *channelLink, mbox MailBox,
+		whoseCommit lntypes.ChannelParty) bool {
+
+		timeout := time.After(15 * time.Second)
+		pollInterval := 300 * time.Millisecond
+		expectedDust := 354 * 2 * amt
 
-	assertAlmostDust := func(link *channelLink, mbox MailBox,
-		whoseCommit lntypes.ChannelParty) {
+		for {
+			<-time.After(pollInterval)
+
+			select {
+			case <-timeout:
+				return false
+			default:
+			}
 
-		err := wait.NoError(func() error {
 			linkDust := link.getDustSum(
 				whoseCommit, fn.None[chainfee.SatPerKWeight](),
 			)
@@ -4344,13 +4347,11 @@ func TestSwitchDustForwarding(t *testing.T) {
 			}
 
 			if totalDust == expectedDust {
-				return nil
+				break
 			}
+		}
 
-			return fmt.Errorf("got totalDust=%v, expectedDust=%v",
-				totalDust, expectedDust)
-		}, 15*time.Second)
-		require.NoError(t, err, "timeout checking dust")
+		return true
 	}
 
 	// Wait until Bob is almost at the fee threshold.
@@ -4358,15 +4359,14 @@ func TestSwitchDustForwarding(t *testing.T) {
 		n.firstBobChannelLink.ChanID(),
 		n.firstBobChannelLink.ShortChanID(),
 	)
-	assertAlmostDust(n.firstBobChannelLink, bobMbox, lntypes.Local)
+	require.True(
+		t, checkAlmostDust(
+			n.firstBobChannelLink, bobMbox, lntypes.Local,
+		),
+	)
 
 	// Sending one more HTLC should fail. SendHTLC won't error, but the
-	// HTLC should be failed backwards. When sending we only check for the
-	// dust amount without the commitment fee. When the HTLC is added to the
-	// commitment state (link) we also take into account the commitment fee
-	// and with a fee of 6000 sat/kw and a commitment size of 724 (non
-	// anchor channel) we are overexposed in fees (maxFeeExposure) that's
-	// why the HTLC is failed back.
+	// HTLC should be failed backwards.
 	err = n.bobServer.htlcSwitch.SendHTLC(
 		aliceBobFirstHop, uint64(bobAttemptID), failingHtlc,
 	)
@@ -4412,7 +4412,9 @@ func TestSwitchDustForwarding(t *testing.T) {
 		aliceBobFirstHop, uint64(bobAttemptID), nondustHtlc,
 	)
 	require.NoError(t, err)
-	assertAlmostDust(n.firstBobChannelLink, bobMbox, lntypes.Local)
+	require.True(t, checkAlmostDust(
+		n.firstBobChannelLink, bobMbox, lntypes.Local,
+	))
 
 	// Check that the HTLC failed.
 	bobResultChan, err = n.bobServer.htlcSwitch.GetAttemptResult(
@@ -4490,7 +4492,11 @@ func TestSwitchDustForwarding(t *testing.T) {
 	aliceMbox := aliceOrch.GetOrCreateMailBox(
 		n.aliceChannelLink.ChanID(), n.aliceChannelLink.ShortChanID(),
 	)
-	assertAlmostDust(n.aliceChannelLink, aliceMbox, lntypes.Remote)
+	require.True(
+		t, checkAlmostDust(
+			n.aliceChannelLink, aliceMbox, lntypes.Remote,
+		),
+	)
 
 	err = n.aliceServer.htlcSwitch.SendHTLC(
 		n.aliceChannelLink.ShortChanID(), uint64(aliceAttemptID),
diff --git a/htlcswitch/test_utils.go b/htlcswitch/test_utils.go
index 3719d7ae4..427dc8cb5 100644
--- a/htlcswitch/test_utils.go
+++ b/htlcswitch/test_utils.go
@@ -43,10 +43,6 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
-// maxInflightHtlcs specifies the max number of inflight HTLCs. This number is
-// chosen to be smaller than the default 483 so the test can run faster.
-const maxInflightHtlcs = 50
-
 var (
 	alicePrivKey = []byte("alice priv key")
 	bobPrivKey   = []byte("bob priv key")
@@ -149,7 +145,7 @@ func createTestChannel(t *testing.T, alicePrivKey, bobPrivKey []byte,
 			channelCapacity),
 		ChanReserve:      aliceReserve,
 		MinHTLC:          0,
-		MaxAcceptedHtlcs: maxInflightHtlcs,
+		MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
 	}
 	aliceCommitParams := channeldb.CommitmentParams{
 		DustLimit: btcutil.Amount(200),
@@ -161,7 +157,7 @@ func createTestChannel(t *testing.T, alicePrivKey, bobPrivKey []byte,
 			channelCapacity),
 		ChanReserve:      bobReserve,
 		MinHTLC:          0,
-		MaxAcceptedHtlcs: maxInflightHtlcs,
+		MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
 	}
 	bobCommitParams := channeldb.CommitmentParams{
 		DustLimit: btcutil.Amount(800),
diff --git a/itest/lnd_coop_close_external_delivery_test.go b/itest/lnd_coop_close_external_delivery_test.go
index 57c2da2f4..755792303 100644
--- a/itest/lnd_coop_close_external_delivery_test.go
+++ b/itest/lnd_coop_close_external_delivery_test.go
@@ -10,44 +10,13 @@ import (
 )
 
 func testCoopCloseWithExternalDelivery(ht *lntest.HarnessTest) {
-	ok := ht.Run("set P2WPKH delivery address at open", func(t *testing.T) {
+	ht.Run("set delivery address at open", func(t *testing.T) {
 		tt := ht.Subtest(t)
-		testCoopCloseWithExternalDeliveryImpl(
-			tt, true, lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH,
-		)
+		testCoopCloseWithExternalDeliveryImpl(tt, true)
 	})
-	// Abort the test if failed.
-	if !ok {
-		return
-	}
-
-	ok = ht.Run("set P2WPKH delivery address at close", func(t *testing.T) {
-		tt := ht.Subtest(t)
-		testCoopCloseWithExternalDeliveryImpl(
-			tt, false, lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH,
-		)
-	})
-	// Abort the test if failed.
-	if !ok {
-		return
-	}
-
-	ok = ht.Run("set P2TR delivery address at open", func(t *testing.T) {
-		tt := ht.Subtest(t)
-		testCoopCloseWithExternalDeliveryImpl(
-			tt, true, lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
-		)
-	})
-	// Abort the test if failed.
-	if !ok {
-		return
-	}
-
-	ht.Run("set P2TR delivery address at close", func(t *testing.T) {
+	ht.Run("set delivery address at close", func(t *testing.T) {
 		tt := ht.Subtest(t)
-		testCoopCloseWithExternalDeliveryImpl(
-			tt, false, lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY,
-		)
+		testCoopCloseWithExternalDeliveryImpl(tt, false)
 	})
 }
 
@@ -56,7 +25,7 @@ func testCoopCloseWithExternalDelivery(ht *lntest.HarnessTest) {
 // not. Some users set this value to be an address in a different wallet and
 // this should not affect our ability to accurately report the settled balance.
 func testCoopCloseWithExternalDeliveryImpl(ht *lntest.HarnessTest,
-	upfrontShutdown bool, deliveryAddressType lnrpc.AddressType) {
+	upfrontShutdown bool) {
 
 	alice, bob := ht.Alice, ht.Bob
 	ht.ConnectNodes(alice, bob)
@@ -66,7 +35,7 @@ func testCoopCloseWithExternalDeliveryImpl(ht *lntest.HarnessTest,
 	// wallet. We already correctly track settled balances when the address
 	// is in the LND wallet.
 	addr := bob.RPC.NewAddress(&lnrpc.NewAddressRequest{
-		Type: deliveryAddressType,
+		Type: lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH,
 	})
 
 	// Prepare for channel open.
diff --git a/lnrpc/walletrpc/walletkit_server_test.go b/lnrpc/walletrpc/walletkit_server_test.go
index d567eb028..115ccf96e 100644
--- a/lnrpc/walletrpc/walletkit_server_test.go
+++ b/lnrpc/walletrpc/walletkit_server_test.go
@@ -162,18 +162,10 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 		// packet in bytes.
 		expectedFee btcutil.Amount
 
-		// maxFeeRatio is the maximum fee to total output amount ratio
-		// that we consider valid.
-		maxFeeRatio float64
-
 		// expectedErr is the expected concrete error. If not nil, then
 		// the error must match exactly.
 		expectedErr error
 
-		// expectedContainedErrStr is the expected string to be
-		// contained in the returned error.
-		expectedContainedErrStr string
-
 		// expectedErrType is the expected error type. If not nil, then
 		// the error must be of this type.
 		expectedErrType error
@@ -186,7 +178,6 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 		}),
 		changeIndex:     -1,
 		feeRate:         chainfee.FeePerKwFloor,
-		maxFeeRatio:     chanfunding.DefaultMaxFeeRatio,
 		expectedErrType: &chanfunding.ErrInsufficientFunds{},
 	}, {
 		name: "1 p2wpkh utxo, add p2wkh change",
@@ -202,7 +193,6 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 		}),
 		changeIndex:             -1,
 		feeRate:                 chainfee.FeePerKwFloor,
-		maxFeeRatio:             chanfunding.DefaultMaxFeeRatio,
 		expectedUtxoIndexes:     []int{0},
 		expectChangeOutputIndex: 1,
 		expectedFee:             calcFee(0, 1, 1, 1, 0),
@@ -220,7 +210,6 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 		}),
 		changeIndex:             -1,
 		feeRate:                 chainfee.FeePerKwFloor,
-		maxFeeRatio:             chanfunding.DefaultMaxFeeRatio,
 		changeType:              chanfunding.P2TRChangeAddress,
 		expectedUtxoIndexes:     []int{0},
 		expectChangeOutputIndex: 1,
@@ -239,7 +228,6 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 		}),
 		changeIndex:             -1,
 		feeRate:                 chainfee.FeePerKwFloor,
-		maxFeeRatio:             chanfunding.DefaultMaxFeeRatio,
 		expectedUtxoIndexes:     []int{0},
 		expectChangeOutputIndex: -1,
 		expectedFee:             calcFee(0, 1, 1, 0, 0),
@@ -259,7 +247,6 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 		}),
 		changeIndex:             -1,
 		feeRate:                 chainfee.FeePerKwFloor,
-		maxFeeRatio:             chanfunding.DefaultMaxFeeRatio,
 		changeType:              chanfunding.P2WKHChangeAddress,
 		expectedUtxoIndexes:     []int{0},
 		expectChangeOutputIndex: -1,
@@ -280,7 +267,6 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 		}),
 		changeIndex:             -1,
 		feeRate:                 chainfee.FeePerKwFloor,
-		maxFeeRatio:             chanfunding.DefaultMaxFeeRatio,
 		changeType:              chanfunding.P2TRChangeAddress,
 		expectedUtxoIndexes:     []int{0},
 		expectChangeOutputIndex: -1,
@@ -299,7 +285,6 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 		}),
 		changeIndex:             0,
 		feeRate:                 chainfee.FeePerKwFloor,
-		maxFeeRatio:             chanfunding.DefaultMaxFeeRatio,
 		changeType:              chanfunding.ExistingChangeAddress,
 		expectedUtxoIndexes:     []int{0},
 		expectChangeOutputIndex: 0,
@@ -318,7 +303,6 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 		}),
 		changeIndex:             0,
 		feeRate:                 chainfee.FeePerKwFloor,
-		maxFeeRatio:             chanfunding.DefaultMaxFeeRatio,
 		changeType:              chanfunding.ExistingChangeAddress,
 		expectedUtxoIndexes:     []int{0},
 		expectChangeOutputIndex: 0,
@@ -337,7 +321,6 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 		}),
 		changeIndex:             0,
 		feeRate:                 chainfee.FeePerKwFloor,
-		maxFeeRatio:             chanfunding.DefaultMaxFeeRatio,
 		changeType:              chanfunding.ExistingChangeAddress,
 		expectedUtxoIndexes:     []int{0},
 		expectChangeOutputIndex: 0,
@@ -386,7 +369,6 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 		}),
 		changeIndex:             0,
 		feeRate:                 chainfee.FeePerKwFloor,
-		maxFeeRatio:             chanfunding.DefaultMaxFeeRatio,
 		changeType:              chanfunding.ExistingChangeAddress,
 		expectedUtxoIndexes:     []int{0, 1},
 		expectChangeOutputIndex: 0,
@@ -435,7 +417,6 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 		}),
 		changeIndex:             -1,
 		feeRate:                 chainfee.FeePerKwFloor,
-		maxFeeRatio:             chanfunding.DefaultMaxFeeRatio,
 		changeType:              chanfunding.P2TRChangeAddress,
 		expectedUtxoIndexes:     []int{0, 1},
 		expectChangeOutputIndex: 1,
@@ -475,7 +456,6 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 		}),
 		changeIndex:             -1,
 		feeRate:                 chainfee.FeePerKwFloor,
-		maxFeeRatio:             chanfunding.DefaultMaxFeeRatio,
 		changeType:              chanfunding.P2WKHChangeAddress,
 		expectedUtxoIndexes:     []int{},
 		expectChangeOutputIndex: 1,
@@ -517,74 +497,10 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 		}),
 		changeIndex:             -1,
 		feeRate:                 chainfee.FeePerKwFloor,
-		maxFeeRatio:             chanfunding.DefaultMaxFeeRatio,
 		changeType:              chanfunding.P2TRChangeAddress,
 		expectedUtxoIndexes:     []int{},
 		expectChangeOutputIndex: -1,
 		expectedFee:             calcFee(1, 0, 1, 0, 0),
-	}, {
-		name: "1 p2wpkh utxo, existing p2wkh change, invalid fee ratio",
-		utxos: []*lnwallet.Utxo{
-			{
-				Value:    250,
-				PkScript: p2wkhScript,
-			},
-		},
-		packet: makePacket(&wire.TxOut{
-			Value:    50,
-			PkScript: p2wkhScript,
-		}),
-		changeIndex:             0,
-		feeRate:                 chainfee.FeePerKwFloor,
-		maxFeeRatio:             chanfunding.DefaultMaxFeeRatio,
-		changeType:              chanfunding.ExistingChangeAddress,
-		expectedUtxoIndexes:     []int{0},
-		expectChangeOutputIndex: 0,
-		expectedFee:             calcFee(0, 1, 0, 1, 0),
-
-		expectedContainedErrStr: "fee 0.00000111 BTC exceeds max fee " +
-			"(0.00000027 BTC) on total output value",
-	}, {
-		name: "1 p2wpkh utxo, existing p2wkh change, negative feeratio",
-		utxos: []*lnwallet.Utxo{
-			{
-				Value:    250,
-				PkScript: p2wkhScript,
-			},
-		},
-		packet: makePacket(&wire.TxOut{
-			Value:    50,
-			PkScript: p2wkhScript,
-		}),
-		changeIndex:             0,
-		feeRate:                 chainfee.FeePerKwFloor,
-		maxFeeRatio:             chanfunding.DefaultMaxFeeRatio * (-1),
-		changeType:              chanfunding.ExistingChangeAddress,
-		expectedUtxoIndexes:     []int{0},
-		expectChangeOutputIndex: 0,
-		expectedFee:             calcFee(0, 1, 0, 1, 0),
-
-		expectedContainedErrStr: "maxFeeRatio must be between 0.00 " +
-			"and 1.00 got -0.20",
-	}, {
-		name: "1 p2wpkh utxo, existing p2wkh change, big fee ratio",
-		utxos: []*lnwallet.Utxo{
-			{
-				Value:    250,
-				PkScript: p2wkhScript,
-			},
-		},
-		packet: makePacket(&wire.TxOut{
-			Value:    50,
-			PkScript: p2wkhScript,
-		}),
-		changeIndex:             0,
-		feeRate:                 chainfee.FeePerKwFloor,
-		maxFeeRatio:             0.85,
-		changeType:              chanfunding.ExistingChangeAddress,
-		expectedUtxoIndexes:     []int{0},
-		expectChangeOutputIndex: 0,
-		expectedFee:             calcFee(0, 1, 0, 1, 0),
 	}, {
 		name: "large existing p2tr input, fee estimation existing " +
 			"change output",
@@ -620,7 +536,6 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 		}),
 		changeIndex:                0,
 		feeRate:                    chainfee.FeePerKwFloor,
-		maxFeeRatio:                chanfunding.DefaultMaxFeeRatio,
 		changeType:                 chanfunding.ExistingChangeAddress,
 		expectedUtxoIndexes:        []int{},
 		expectChangeOutputIndex:    0,
@@ -660,7 +575,6 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 				"", tc.changeIndex, copiedPacket, 0,
 				tc.changeType, tc.feeRate,
 				rpcServer.cfg.CoinSelectionStrategy,
-				tc.maxFeeRatio,
 			)
 
 			switch {
@@ -674,12 +588,6 @@ func TestFundPsbtCoinSelect(t *testing.T) {
 				require.Error(tt, err)
 				require.ErrorAs(tt, err, &tc.expectedErr)
 
-				return
-			case tc.expectedContainedErrStr != "":
-				require.ErrorContains(
-					tt, err, tc.expectedContainedErrStr,
-				)
-
 				return
 			}
 
diff --git a/lnwallet/chanfunding/coin_select_test.go b/lnwallet/chanfunding/coin_select_test.go
index 77c5a0e68..3d09668b4 100644
--- a/lnwallet/chanfunding/coin_select_test.go
+++ b/lnwallet/chanfunding/coin_select_test.go
@@ -317,7 +317,6 @@ func TestCoinSelect(t *testing.T) {
 				feeRate, test.outputValue, dustLimit,
 				test.coins, wallet.CoinSelectionLargest,
 				fundingOutputEstimate, test.changeType,
-				DefaultMaxFeeRatio,
 			)
 
 			if test.expectErr {
@@ -357,7 +356,6 @@ func TestCalculateChangeAmount(t *testing.T) {
 		feeWithChange btcutil.Amount
 		dustLimit     btcutil.Amount
 		changeType    ChangeAddressType
-		maxFeeRatio   float64
 
 		expectErr       string
 		expectChangeAmt btcutil.Amount
@@ -371,7 +369,6 @@ func TestCalculateChangeAmount(t *testing.T) {
 		totalInputAmt: 500,
 		requiredAmt:   490,
 		feeNoChange:   12,
-		maxFeeRatio:   DefaultMaxFeeRatio,
 
 		expectNeedMore: 502,
 	}, {
@@ -386,7 +383,6 @@ func TestCalculateChangeAmount(t *testing.T) {
 		feeWithChange: 10,
 		dustLimit:     100,
 		changeType:    ExistingChangeAddress,
-		maxFeeRatio:   DefaultMaxFeeRatio,
 
 		expectChangeAmt: 90,
 	}, {
@@ -396,7 +392,6 @@ func TestCalculateChangeAmount(t *testing.T) {
 		feeNoChange:   40,
 		feeWithChange: 50,
 		dustLimit:     100,
-		maxFeeRatio:   DefaultMaxFeeRatio,
 
 		expectChangeAmt: 150,
 	}, {
@@ -406,7 +401,6 @@ func TestCalculateChangeAmount(t *testing.T) {
 		requiredAmt:   460,
 		feeNoChange:   40,
 		feeWithChange: 50,
-		maxFeeRatio:   DefaultMaxFeeRatio,
 
 		expectChangeAmt: 0,
 	}, {
@@ -416,36 +410,14 @@ func TestCalculateChangeAmount(t *testing.T) {
 		feeNoChange:   10,
 		feeWithChange: 45,
 		dustLimit:     5,
-		maxFeeRatio:   DefaultMaxFeeRatio,
 
-		expectErr: "fee 0.00000045 BTC exceeds max fee (0.00000011 " +
-			"BTC) on total output value 0.00000055 BTC",
-	}, {
-		name:          "fee percent ok",
-		totalInputAmt: 100,
-		requiredAmt:   50,
-		feeNoChange:   10,
-		feeWithChange: 45,
-		dustLimit:     5,
-		maxFeeRatio:   0.95,
-
-		expectChangeAmt: 5,
-	}, {
-		name:          "invalid max fee ratio",
-		totalInputAmt: 100,
-		requiredAmt:   50,
-		feeNoChange:   10,
-		feeWithChange: 45,
-		dustLimit:     5,
-		maxFeeRatio:   3.14,
-
-		expectErr: "maxFeeRatio must be between 0.00 and 1.00",
+		expectErr: "fee (0.00000045 BTC) exceeds 20% of total output " +
+			"(0.00000055 BTC)",
 	}, {
 		name:          "invalid usage of function",
 		feeNoChange:   5,
 		feeWithChange: 10,
 		changeType:    ExistingChangeAddress,
-		maxFeeRatio:   DefaultMaxFeeRatio,
 
 		expectErr: "fees for with or without change must be the same",
 	}}
@@ -456,7 +428,7 @@ func TestCalculateChangeAmount(t *testing.T) {
 			changeAmt, needMore, err := CalculateChangeAmount(
 				tc.totalInputAmt, tc.requiredAmt,
 				tc.feeNoChange, tc.feeWithChange, tc.dustLimit,
-				tc.changeType, tc.maxFeeRatio,
+				tc.changeType,
 			)
 
 			if tc.expectErr != "" {
@@ -634,9 +606,8 @@ func TestCoinSelectSubtractFees(t *testing.T) {
 			},
 			spendValue: 5 * fundingFee(highFeeRate, 1, false),
 
-			expectErr: "fee <amt> BTC exceeds max fee (<amt> " +
-				"BTC) on total output value <amt> BTC with " +
-				"max fee ratio of <amt>",
+			expectErr: "fee (<amt> BTC) exceeds <amt>% of total " +
+				"output (<amt> BTC)",
 		},
 	}
 
@@ -657,7 +628,6 @@ func TestCoinSelectSubtractFees(t *testing.T) {
 				wallet.CoinSelectionLargest,
 				fundingOutputEstimate,
 				defaultChanFundingChangeType,
-				DefaultMaxFeeRatio,
 			)
 			if err != nil {
 				switch {
@@ -843,9 +813,8 @@ func TestCoinSelectUpToAmount(t *testing.T) {
 		minValue: minValue,
 		maxValue: 16 * fundingFee(feeRate, 1, false),
 
-		expectErr: "fee 0.00000192 BTC exceeds max fee (0.00000153 " +
-			"BTC) on total output value 0.00000768 BTC with max " +
-			"fee ratio of 0.20",
+		expectErr: "fee (0.00000192 BTC) exceeds 20% of total output " +
+			"(0.00000768 BTC)",
 	}, {
 		// This test makes sure that the implementation detail of using
 		// CoinSelect and CoinSelectSubtractFees is done correctly.
@@ -904,7 +873,6 @@ func TestCoinSelectUpToAmount(t *testing.T) {
 				wallet.CoinSelectionLargest,
 				fundingOutputEstimate,
 				defaultChanFundingChangeType,
-				DefaultMaxFeeRatio,
 			)
 			if len(test.expectErr) == 0 && err != nil {
 				t.Fatal(err.Error())
diff --git a/routing/missioncontrol_store_test.go b/routing/missioncontrol_store_test.go
index f1788a96a..2dbfc1121 100644
--- a/routing/missioncontrol_store_test.go
+++ b/routing/missioncontrol_store_test.go
@@ -11,25 +11,27 @@ import (
 	"github.com/lightningnetwork/lnd/lntest/wait"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/routing/route"
-	"github.com/lightningnetwork/lnd/tlv"
 	"github.com/stretchr/testify/require"
 )
 
 const testMaxRecords = 2
 
-// mcStoreTestRoute is a test route for the mission control store tests.
-var mcStoreTestRoute = extractMCRoute(&route.Route{
-	TotalAmount:  lnwire.MilliSatoshi(5),
-	SourcePubKey: route.Vertex{1},
-	Hops: []*route.Hop{
-		{
-			PubKeyBytes:   route.Vertex{2},
-			ChannelID:     4,
-			AmtToForward:  lnwire.MilliSatoshi(7),
-			CustomRecords: make(map[uint64][]byte),
+var (
+	// mcStoreTestRoute is a test route for the mission control store tests.
+	mcStoreTestRoute = mcRoute{
+		totalAmount:  lnwire.MilliSatoshi(5),
+		sourcePubKey: route.Vertex{1},
+		hops: []*mcHop{
+			{
+				pubKeyBytes:      route.Vertex{2},
+				channelID:        4,
+				amtToFwd:         lnwire.MilliSatoshi(7),
+				hasCustomRecords: true,
+				hasBlindingPoint: false,
+			},
 		},
-	},
-})
+	}
+)
 
 // mcStoreTestHarness is the harness for a MissonControlStore test.
 type mcStoreTestHarness struct {
@@ -82,31 +84,28 @@ func TestMissionControlStore(t *testing.T) {
 
 	failureSourceIdx := 1
 
-	result1 := newPaymentResult(
-		99, mcStoreTestRoute, testTime, testTime,
-		newPaymentFailure(
-			&failureSourceIdx,
-			lnwire.NewFailIncorrectDetails(100, 1000),
-		),
-	)
+	result1 := paymentResult{
+		route:            &mcStoreTestRoute,
+		failure:          lnwire.NewFailIncorrectDetails(100, 1000),
+		failureSourceIdx: &failureSourceIdx,
+		id:               99,
+		timeReply:        testTime,
+		timeFwd:          testTime.Add(-time.Minute),
+	}
 
-	result2 := newPaymentResult(
-		2, mcStoreTestRoute, testTime.Add(time.Hour),
-		testTime.Add(time.Hour),
-		newPaymentFailure(
-			&failureSourceIdx,
-			lnwire.NewFailIncorrectDetails(100, 1000),
-		),
-	)
+	result2 := result1
+	result2.timeReply = result1.timeReply.Add(time.Hour)
+	result2.timeFwd = result1.timeReply.Add(time.Hour)
+	result2.id = 2
 
 	// Store result.
-	store.AddResult(result2)
+	store.AddResult(&result2)
 
 	// Store again to test idempotency.
-	store.AddResult(result2)
+	store.AddResult(&result2)
 
 	// Store second result which has an earlier timestamp.
-	store.AddResult(result1)
+	store.AddResult(&result1)
 	require.NoError(t, store.storeResults())
 
 	results, err = store.fetchAll()
@@ -114,8 +113,8 @@ func TestMissionControlStore(t *testing.T) {
 	require.Len(t, results, 2)
 
 	// Check that results are stored in chronological order.
-	require.Equal(t, result1, results[0])
-	require.Equal(t, result2, results[1])
+	require.Equal(t, &result1, results[0])
+	require.Equal(t, &result2, results[1])
 
 	// Recreate store to test pruning.
 	store, err = newMissionControlStore(
@@ -125,20 +124,12 @@ func TestMissionControlStore(t *testing.T) {
 
 	// Add a newer result which failed due to mpp timeout.
 	result3 := result1
-	result3.timeReply = tlv.NewPrimitiveRecord[tlv.TlvType1](
-		uint64(testTime.Add(2 * time.Hour).UnixNano()),
-	)
-	result3.timeFwd = tlv.NewPrimitiveRecord[tlv.TlvType0](
-		uint64(testTime.Add(2 * time.Hour).UnixNano()),
-	)
+	result3.timeReply = result1.timeReply.Add(2 * time.Hour)
+	result3.timeFwd = result1.timeReply.Add(2 * time.Hour)
 	result3.id = 3
-	result3.failure = tlv.SomeRecordT(
-		tlv.NewRecordT[tlv.TlvType3](*newPaymentFailure(
-			&failureSourceIdx, &lnwire.FailMPPTimeout{},
-		)),
-	)
+	result3.failure = &lnwire.FailMPPTimeout{}
 
-	store.AddResult(result3)
+	store.AddResult(&result3)
 	require.NoError(t, store.storeResults())
 
 	// Check that results are pruned.
@@ -146,25 +137,8 @@ func TestMissionControlStore(t *testing.T) {
 	require.NoError(t, err)
 	require.Len(t, results, 2)
 
-	require.Equal(t, result2, results[0])
-	require.Equal(t, result3, results[1])
-
-	// Also demonstrate the persistence of a success result.
-	result4 := newPaymentResult(
-		5, mcStoreTestRoute, testTime.Add(3*time.Hour),
-		testTime.Add(3*time.Hour), nil,
-	)
-	store.AddResult(result4)
-	require.NoError(t, store.storeResults())
-
-	// We should still only have 2 results.
-	results, err = store.fetchAll()
-	require.NoError(t, err)
-	require.Len(t, results, 2)
-
-	// The two latest results should have been returned.
-	require.Equal(t, result3, results[0])
-	require.Equal(t, result4, results[1])
+	require.Equal(t, &result2, results[0])
+	require.Equal(t, &result3, results[1])
 }
 
 // TestMissionControlStoreFlushing asserts the periodic flushing of the store
@@ -182,11 +156,14 @@ func TestMissionControlStoreFlushing(t *testing.T) {
 	)
 	nextResult := func() *paymentResult {
 		lastID += 1
-		return newPaymentResult(
-			lastID, mcStoreTestRoute, testTime.Add(-time.Hour),
-			testTime,
-			newPaymentFailure(&failureSourceIdx, failureDetails),
-		)
+		return &paymentResult{
+			route:            &mcStoreTestRoute,
+			failure:          failureDetails,
+			failureSourceIdx: &failureSourceIdx,
+			id:               lastID,
+			timeReply:        testTime,
+			timeFwd:          testTime.Add(-time.Minute),
+		}
 	}
 
 	// Helper to assert the number of results is correct.
@@ -283,14 +260,14 @@ func BenchmarkMissionControlStoreFlushing(b *testing.B) {
 			var lastID uint64
 			for i := 0; i < testMaxRecords; i++ {
 				lastID++
-				result := newPaymentResult(
-					lastID, mcStoreTestRoute, testTimeFwd,
-					testTime,
-					newPaymentFailure(
-						&failureSourceIdx,
-						failureDetails,
-					),
-				)
+				result := &paymentResult{
+					route:            &mcStoreTestRoute,
+					failure:          failureDetails,
+					failureSourceIdx: &failureSourceIdx,
+					id:               lastID,
+					timeReply:        testTime,
+					timeFwd:          testTimeFwd,
+				}
 				store.AddResult(result)
 			}
 
@@ -301,14 +278,13 @@ func BenchmarkMissionControlStoreFlushing(b *testing.B) {
 			// Create the additional results.
 			results := make([]*paymentResult, tc)
 			for i := 0; i < len(results); i++ {
-				results[i] = newPaymentResult(
-					0, mcStoreTestRoute, testTimeFwd,
-					testTime,
-					newPaymentFailure(
-						&failureSourceIdx,
-						failureDetails,
-					),
-				)
+				results[i] = &paymentResult{
+					route:            &mcStoreTestRoute,
+					failure:          failureDetails,
+					failureSourceIdx: &failureSourceIdx,
+					timeReply:        testTime,
+					timeFwd:          testTimeFwd,
+				}
 			}
 
 			// Run the actual benchmark.
diff --git a/routing/result_interpretation_test.go b/routing/result_interpretation_test.go
index b213eb183..14506e3a1 100644
--- a/routing/result_interpretation_test.go
+++ b/routing/result_interpretation_test.go
@@ -4,9 +4,7 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/btcsuite/btcd/btcec/v2"
 	"github.com/davecgh/go-spew/spew"
-	"github.com/lightningnetwork/lnd/fn"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/routing/route"
 )
@@ -16,170 +14,110 @@ var (
 		{1, 0}, {1, 1}, {1, 2}, {1, 3}, {1, 4},
 	}
 
-	routeOneHop = extractMCRoute(&route.Route{
-		SourcePubKey: hops[0],
-		TotalAmount:  100,
-		Hops: []*route.Hop{
-			{
-				PubKeyBytes:  hops[1],
-				AmtToForward: 99,
-			},
+	routeOneHop = mcRoute{
+		sourcePubKey: hops[0],
+		totalAmount:  100,
+		hops: []*mcHop{
+			{pubKeyBytes: hops[1], amtToFwd: 99},
 		},
-	})
+	}
 
-	routeTwoHop = extractMCRoute(&route.Route{
-		SourcePubKey: hops[0],
-		TotalAmount:  100,
-		Hops: []*route.Hop{
-			{
-				PubKeyBytes:  hops[1],
-				AmtToForward: 99,
-			},
-			{
-				PubKeyBytes:  hops[2],
-				AmtToForward: 97,
-			},
+	routeTwoHop = mcRoute{
+		sourcePubKey: hops[0],
+		totalAmount:  100,
+		hops: []*mcHop{
+			{pubKeyBytes: hops[1], amtToFwd: 99},
+			{pubKeyBytes: hops[2], amtToFwd: 97},
 		},
-	})
+	}
 
-	routeThreeHop = extractMCRoute(&route.Route{
-		SourcePubKey: hops[0],
-		TotalAmount:  100,
-		Hops: []*route.Hop{
-			{
-				PubKeyBytes:  hops[1],
-				AmtToForward: 99,
-			},
-			{
-				PubKeyBytes:  hops[2],
-				AmtToForward: 97,
-			},
-			{
-				PubKeyBytes:  hops[3],
-				AmtToForward: 94,
-			},
+	routeThreeHop = mcRoute{
+		sourcePubKey: hops[0],
+		totalAmount:  100,
+		hops: []*mcHop{
+			{pubKeyBytes: hops[1], amtToFwd: 99},
+			{pubKeyBytes: hops[2], amtToFwd: 97},
+			{pubKeyBytes: hops[3], amtToFwd: 94},
 		},
-	})
+	}
 
-	routeFourHop = extractMCRoute(&route.Route{
-		SourcePubKey: hops[0],
-		TotalAmount:  100,
-		Hops: []*route.Hop{
-			{
-				PubKeyBytes:  hops[1],
-				AmtToForward: 99,
-			},
-			{
-				PubKeyBytes:  hops[2],
-				AmtToForward: 97,
-			},
-			{
-				PubKeyBytes:  hops[3],
-				AmtToForward: 94,
-			},
-			{
-				PubKeyBytes:  hops[4],
-				AmtToForward: 90,
-			},
+	routeFourHop = mcRoute{
+		sourcePubKey: hops[0],
+		totalAmount:  100,
+		hops: []*mcHop{
+			{pubKeyBytes: hops[1], amtToFwd: 99},
+			{pubKeyBytes: hops[2], amtToFwd: 97},
+			{pubKeyBytes: hops[3], amtToFwd: 94},
+			{pubKeyBytes: hops[4], amtToFwd: 90},
 		},
-	})
+	}
 
 	// blindedMultiHop is a blinded path where there are cleartext hops
 	// before the introduction node, and an intermediate blinded hop before
 	// the recipient after it.
-	blindedMultiHop = extractMCRoute(&route.Route{
-		SourcePubKey: hops[0],
-		TotalAmount:  100,
-		Hops: []*route.Hop{
+	blindedMultiHop = mcRoute{
+		sourcePubKey: hops[0],
+		totalAmount:  100,
+		hops: []*mcHop{
+			{pubKeyBytes: hops[1], amtToFwd: 99},
 			{
-				PubKeyBytes:  hops[1],
-				AmtToForward: 99,
-			},
-			{
-				PubKeyBytes:   hops[2],
-				AmtToForward:  95,
-				BlindingPoint: genTestPubKey(),
-			},
-			{
-				PubKeyBytes:  hops[3],
-				AmtToForward: 88,
-			},
-			{
-				PubKeyBytes:  hops[4],
-				AmtToForward: 77,
+				pubKeyBytes:      hops[2],
+				amtToFwd:         95,
+				hasBlindingPoint: true,
 			},
+			{pubKeyBytes: hops[3], amtToFwd: 88},
+			{pubKeyBytes: hops[4], amtToFwd: 77},
 		},
-	})
+	}
 
 	// blindedSingleHop is a blinded path with a single blinded hop after
 	// the introduction node.
-	blindedSingleHop = extractMCRoute(&route.Route{
-		SourcePubKey: hops[0],
-		TotalAmount:  100,
-		Hops: []*route.Hop{
+	blindedSingleHop = mcRoute{
+		sourcePubKey: hops[0],
+		totalAmount:  100,
+		hops: []*mcHop{
+			{pubKeyBytes: hops[1], amtToFwd: 99},
 			{
-				PubKeyBytes:  hops[1],
-				AmtToForward: 99,
-			},
-			{
-				PubKeyBytes:   hops[2],
-				AmtToForward:  95,
-				BlindingPoint: genTestPubKey(),
-			},
-			{
-				PubKeyBytes:  hops[3],
-				AmtToForward: 88,
+				pubKeyBytes:      hops[2],
+				amtToFwd:         95,
+				hasBlindingPoint: true,
 			},
+			{pubKeyBytes: hops[3], amtToFwd: 88},
 		},
-	})
+	}
 
 	// blindedMultiToIntroduction is a blinded path which goes directly
 	// to the introduction node, with multiple blinded hops after it.
-	blindedMultiToIntroduction = extractMCRoute(&route.Route{
-		SourcePubKey: hops[0],
-		TotalAmount:  100,
-		Hops: []*route.Hop{
-			{
-				PubKeyBytes:   hops[1],
-				AmtToForward:  90,
-				BlindingPoint: genTestPubKey(),
-			},
-			{
-				PubKeyBytes:  hops[2],
-				AmtToForward: 75,
-			},
+	blindedMultiToIntroduction = mcRoute{
+		sourcePubKey: hops[0],
+		totalAmount:  100,
+		hops: []*mcHop{
 			{
-				PubKeyBytes:  hops[3],
-				AmtToForward: 58,
+				pubKeyBytes:      hops[1],
+				amtToFwd:         90,
+				hasBlindingPoint: true,
 			},
+			{pubKeyBytes: hops[2], amtToFwd: 75},
+			{pubKeyBytes: hops[3], amtToFwd: 58},
 		},
-	})
+	}
 
 	// blindedIntroReceiver is a blinded path where the introduction node
 	// is the recipient.
-	blindedIntroReceiver = extractMCRoute(&route.Route{
-		SourcePubKey: hops[0],
-		TotalAmount:  100,
-		Hops: []*route.Hop{
-			{
-				PubKeyBytes:  hops[1],
-				AmtToForward: 95,
-			},
+	blindedIntroReceiver = mcRoute{
+		sourcePubKey: hops[0],
+		totalAmount:  100,
+		hops: []*mcHop{
+			{pubKeyBytes: hops[1], amtToFwd: 95},
 			{
-				PubKeyBytes:   hops[2],
-				AmtToForward:  90,
-				BlindingPoint: genTestPubKey(),
+				pubKeyBytes:      hops[2],
+				amtToFwd:         90,
+				hasBlindingPoint: true,
 			},
 		},
-	})
+	}
 )
 
-func genTestPubKey() *btcec.PublicKey {
-	key, _ := btcec.NewPrivateKey()
-
-	return key.PubKey()
-}
-
 func getTestPair(from, to int) DirectedNodePair {
 	return NewDirectedNodePair(hops[from], hops[to])
 }
@@ -204,7 +142,7 @@ var resultTestCases = []resultTestCase{
 	// interpreted.
 	{
 		name:          "fail",
-		route:         routeTwoHop,
+		route:         &routeTwoHop,
 		failureSrcIdx: 1,
 		failure:       lnwire.NewTemporaryChannelFailure(nil),
 
@@ -219,7 +157,7 @@ var resultTestCases = []resultTestCase{
 	// Tests that an expiry too soon failure result is properly interpreted.
 	{
 		name:          "fail expiry too soon",
-		route:         routeFourHop,
+		route:         &routeFourHop,
 		failureSrcIdx: 3,
 		failure:       lnwire.NewExpiryTooSoon(lnwire.ChannelUpdate1{}),
 
@@ -239,7 +177,7 @@ var resultTestCases = []resultTestCase{
 	// failure, but mark all pairs along the route as successful.
 	{
 		name:          "fail incorrect details",
-		route:         routeTwoHop,
+		route:         &routeTwoHop,
 		failureSrcIdx: 2,
 		failure:       lnwire.NewFailIncorrectDetails(97, 0),
 
@@ -255,7 +193,7 @@ var resultTestCases = []resultTestCase{
 	// Tests a successful direct payment.
 	{
 		name:    "success direct",
-		route:   routeOneHop,
+		route:   &routeOneHop,
 		success: true,
 
 		expectedResult: &interpretedResult{
@@ -268,7 +206,7 @@ var resultTestCases = []resultTestCase{
 	// Tests a successful two hop payment.
 	{
 		name:    "success",
-		route:   routeTwoHop,
+		route:   &routeTwoHop,
 		success: true,
 
 		expectedResult: &interpretedResult{
@@ -282,7 +220,7 @@ var resultTestCases = []resultTestCase{
 	// Tests a malformed htlc from a direct peer.
 	{
 		name:          "fail malformed htlc from direct peer",
-		route:         routeTwoHop,
+		route:         &routeTwoHop,
 		failureSrcIdx: 0,
 		failure:       lnwire.NewInvalidOnionKey(nil),
 
@@ -301,7 +239,7 @@ var resultTestCases = []resultTestCase{
 	// destination.
 	{
 		name:          "fail malformed htlc from direct final peer",
-		route:         routeOneHop,
+		route:         &routeOneHop,
 		failureSrcIdx: 0,
 		failure:       lnwire.NewInvalidOnionKey(nil),
 
@@ -321,7 +259,7 @@ var resultTestCases = []resultTestCase{
 	// in a policy failure for the outgoing hop.
 	{
 		name:          "fail fee insufficient intermediate",
-		route:         routeFourHop,
+		route:         &routeFourHop,
 		failureSrcIdx: 2,
 		failure: lnwire.NewFeeInsufficient(
 			0, lnwire.ChannelUpdate1{},
@@ -344,7 +282,7 @@ var resultTestCases = []resultTestCase{
 	// failure is terminal since the receiver can't process our onion.
 	{
 		name:          "fail invalid onion payload final hop four",
-		route:         routeFourHop,
+		route:         &routeFourHop,
 		failureSrcIdx: 4,
 		failure:       lnwire.NewInvalidOnionPayload(0, 0),
 
@@ -373,7 +311,7 @@ var resultTestCases = []resultTestCase{
 	// Tests an invalid onion payload from a final hop on a three hop route.
 	{
 		name:          "fail invalid onion payload final hop three",
-		route:         routeThreeHop,
+		route:         &routeThreeHop,
 		failureSrcIdx: 3,
 		failure:       lnwire.NewInvalidOnionPayload(0, 0),
 
@@ -400,7 +338,7 @@ var resultTestCases = []resultTestCase{
 	// can still try other paths.
 	{
 		name:          "fail invalid onion payload intermediate",
-		route:         routeFourHop,
+		route:         &routeFourHop,
 		failureSrcIdx: 3,
 		failure:       lnwire.NewInvalidOnionPayload(0, 0),
 
@@ -428,7 +366,7 @@ var resultTestCases = []resultTestCase{
 	// since the remote node can't process our onion.
 	{
 		name:          "fail invalid onion payload direct",
-		route:         routeOneHop,
+		route:         &routeOneHop,
 		failureSrcIdx: 1,
 		failure:       lnwire.NewInvalidOnionPayload(0, 0),
 
@@ -447,7 +385,7 @@ var resultTestCases = []resultTestCase{
 	// penalize mpp timeouts.
 	{
 		name:          "one hop mpp timeout",
-		route:         routeOneHop,
+		route:         &routeOneHop,
 		failureSrcIdx: 1,
 		failure:       &lnwire.FailMPPTimeout{},
 
@@ -464,7 +402,7 @@ var resultTestCases = []resultTestCase{
 	// temporary measure while we decide how to penalize mpp timeouts.
 	{
 		name:          "two hop mpp timeout",
-		route:         routeTwoHop,
+		route:         &routeTwoHop,
 		failureSrcIdx: 2,
 		failure:       &lnwire.FailMPPTimeout{},
 
@@ -481,7 +419,7 @@ var resultTestCases = []resultTestCase{
 	// disabled channel should be penalized for any amount.
 	{
 		name:          "two hop channel disabled",
-		route:         routeTwoHop,
+		route:         &routeTwoHop,
 		failureSrcIdx: 1,
 		failure:       &lnwire.FailChannelDisabled{},
 
@@ -499,7 +437,7 @@ var resultTestCases = []resultTestCase{
 	// has not followed the specification properly.
 	{
 		name:          "error after introduction",
-		route:         blindedMultiToIntroduction,
+		route:         &blindedMultiToIntroduction,
 		failureSrcIdx: 2,
 		// Note that the failure code doesn't matter in this case -
 		// all we're worried about is errors originating after the
@@ -522,7 +460,7 @@ var resultTestCases = []resultTestCase{
 	// hop when we expected the introduction node to convert.
 	{
 		name:          "final failure expected intro",
-		route:         blindedMultiHop,
+		route:         &blindedMultiHop,
 		failureSrcIdx: 4,
 		failure:       &lnwire.FailInvalidBlinding{},
 
@@ -544,7 +482,7 @@ var resultTestCases = []resultTestCase{
 	// introduction point.
 	{
 		name:          "blinded multi-hop introduction",
-		route:         blindedMultiHop,
+		route:         &blindedMultiHop,
 		failureSrcIdx: 2,
 		failure:       &lnwire.FailInvalidBlinding{},
 
@@ -560,7 +498,7 @@ var resultTestCases = []resultTestCase{
 	// introduction point, which is a direct peer.
 	{
 		name:          "blinded multi-hop introduction peer",
-		route:         blindedMultiToIntroduction,
+		route:         &blindedMultiToIntroduction,
 		failureSrcIdx: 1,
 		failure:       &lnwire.FailInvalidBlinding{},
 
@@ -575,7 +513,7 @@ var resultTestCases = []resultTestCase{
 	// connected to the introduction node.
 	{
 		name:          "blinded single hop introduction failure",
-		route:         blindedSingleHop,
+		route:         &blindedSingleHop,
 		failureSrcIdx: 2,
 		failure:       &lnwire.FailInvalidBlinding{},
 
@@ -591,7 +529,7 @@ var resultTestCases = []resultTestCase{
 	// blinding error and is penalized for returning the wrong error.
 	{
 		name:          "error before introduction",
-		route:         blindedMultiHop,
+		route:         &blindedMultiHop,
 		failureSrcIdx: 1,
 		failure:       &lnwire.FailInvalidBlinding{},
 
@@ -611,7 +549,7 @@ var resultTestCases = []resultTestCase{
 	// successful hop before the incorrect error.
 	{
 		name:          "intermediate unexpected blinding",
-		route:         routeThreeHop,
+		route:         &routeThreeHop,
 		failureSrcIdx: 2,
 		failure:       &lnwire.FailInvalidBlinding{},
 
@@ -632,7 +570,7 @@ var resultTestCases = []resultTestCase{
 	// hops before the erring incoming link (the erring node if our peer).
 	{
 		name:          "peer unexpected blinding",
-		route:         routeThreeHop,
+		route:         &routeThreeHop,
 		failureSrcIdx: 1,
 		failure:       &lnwire.FailInvalidBlinding{},
 
@@ -650,7 +588,7 @@ var resultTestCases = []resultTestCase{
 	// A node in a non-blinded route returns a blinding related error.
 	{
 		name:          "final node unexpected blinding",
-		route:         routeThreeHop,
+		route:         &routeThreeHop,
 		failureSrcIdx: 3,
 		failure:       &lnwire.FailInvalidBlinding{},
 
@@ -668,7 +606,7 @@ var resultTestCases = []resultTestCase{
 	// Introduction node returns invalid blinding erroneously.
 	{
 		name:          "final node intro blinding",
-		route:         blindedIntroReceiver,
+		route:         &blindedIntroReceiver,
 		failureSrcIdx: 2,
 		failure:       &lnwire.FailInvalidBlinding{},
 
@@ -691,15 +629,10 @@ func TestResultInterpretation(t *testing.T) {
 
 	for _, testCase := range resultTestCases {
 		t.Run(testCase.name, func(t *testing.T) {
-			var failure fn.Option[paymentFailure]
-			if !testCase.success {
-				failure = fn.Some(*newPaymentFailure(
-					&testCase.failureSrcIdx,
-					testCase.failure,
-				))
-			}
-
-			i := interpretResult(testCase.route, failure)
+			i := interpretResult(
+				testCase.route, testCase.success,
+				&testCase.failureSrcIdx, testCase.failure,
+			)
 
 			expected := testCase.expectedResult
 
diff --git a/watchtower/lookout/lookout_test.go b/watchtower/lookout/lookout_test.go
index 64d182aa2..3800a5682 100644
--- a/watchtower/lookout/lookout_test.go
+++ b/watchtower/lookout/lookout_test.go
@@ -90,9 +90,6 @@ func TestLookoutBreachMatching(t *testing.T) {
 		DB:             db,
 		EpochRegistrar: backend,
 		Punisher:       punisher,
-		MinBackoff:     time.Second,
-		MaxBackoff:     time.Minute,
-		MaxNumRetries:  1,
 	})
 	if err := watcher.Start(); err != nil {
 		t.Fatalf("unable to start watcher: %v", err)