Repository: lightningnetwork/lnd
Pull request #4909 (2021-01-11 13:52:29)

routing: allow runtime updates to mission control config
This PR adds the ability to get and set mission control's config via rpc, allowing for experimentation with these values without a restart. 

Since we already have locking in mission control, we can just acquire the lock and update the cfg. 

halseth: Just from a high level look, I'm wondering if we can do this without introducing race conditions?

Even though we get/set the config behind a mutex, `MissionControl` itself still reads the config without acquiring the lock first.
carlaKC: > `MissionControl` itself still reads the config without acquiring the lock first.

I thought I'd checked all of these, but looks like `ReportPaymentSuccess` and `ReportPaymentFailure` don't acquire the lock for adding results to the store. Although they do acquire it later to update MC, so wondering whether than can be moved up. Otherwise the other calls to MC all use the lock so it shouldn't be too much of an issue?
halseth: @carlaKC I was thinking about places like this: https://github.com/lightningnetwork/lnd/blob/d7ecde2972bfb949c6df717d53ebfbb3283de90b/routing/probability_estimator.go#L82

One alternative to swapping out the mission control config, is to create a new MissionControl with the new config and swap that out instead.

Patch:
diff --git a/cmd/lncli/cmd_mc_cfg_get.go b/cmd/lncli/cmd_mc_cfg_get.go
new file mode 100644
index 000000000..017449f8b
--- /dev/null
+++ b/cmd/lncli/cmd_mc_cfg_get.go
@@ -0,0 +1,36 @@
+package main
+
+import (
+	"context"
+
+	"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
+	"github.com/urfave/cli"
+)
+
+var getCfgCommand = cli.Command{
+	Name:  "getmccfg",
+	Usage: "Display mission control's config.",
+	Description: `
+	Returns the config currently being used by mission control.
+	`,
+	Action: actionDecorator(getCfg),
+}
+
+func getCfg(ctx *cli.Context) error {
+	conn := getClientConn(ctx, false)
+	defer conn.Close()
+
+	client := routerrpc.NewRouterClient(conn)
+
+	ctxb := context.Background()
+	resp, err := client.GetMissionControlConfig(
+		ctxb, &routerrpc.GetMissionControlConfigRequest{},
+	)
+	if err != nil {
+		return err
+	}
+
+	printRespJSON(resp)
+
+	return nil
+}
diff --git a/cmd/lncli/cmd_mc_cfg_set.go b/cmd/lncli/cmd_mc_cfg_set.go
new file mode 100644
index 000000000..874ff2db9
--- /dev/null
+++ b/cmd/lncli/cmd_mc_cfg_set.go
@@ -0,0 +1,102 @@
+package main
+
+import (
+	"context"
+
+	"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
+	"github.com/urfave/cli"
+)
+
+var setCfgCommand = cli.Command{
+	Name:  "setmccfg",
+	Usage: "Set mission control's config.",
+	Description: `
+	Update the config values being used by mission control to calculate 
+	the probability that payment routes will succeed.
+	`,
+	Flags: []cli.Flag{
+		cli.DurationFlag{
+			Name: "halflife",
+			Usage: "the amount of time taken to restore a node " +
+				"or channel to 50% probability of success.",
+		},
+		cli.Float64Flag{
+			Name: "hopprob",
+			Usage: "the probability of success assigned " +
+				"to hops that we have no information about",
+		},
+		cli.Float64Flag{
+			Name: "weight",
+			Usage: "the degree to which mission control should " +
+				"rely on historical results, expressed as " +
+				"value in [0;1]",
+		}, cli.UintFlag{
+			Name: "pmtnr",
+			Usage: "the number of payments mission control " +
+				"should store",
+		},
+		cli.DurationFlag{
+			Name: "failrelax",
+			Usage: "the amount of time to wait after a failure " +
+				"before raising failure amount",
+		},
+	},
+	Action: actionDecorator(setCfg),
+}
+
+func setCfg(ctx *cli.Context) error {
+	conn := getClientConn(ctx, false)
+	defer conn.Close()
+
+	client := routerrpc.NewRouterClient(conn)
+
+	ctxb := context.Background()
+	resp, err := client.GetMissionControlConfig(
+		ctxb, &routerrpc.GetMissionControlConfigRequest{},
+	)
+	if err != nil {
+		return err
+	}
+
+	var haveValue bool
+
+	if ctx.IsSet("halflife") {
+		haveValue = true
+		resp.Config.HalfLifeSeconds = uint64(ctx.Duration(
+			"halflife",
+		).Seconds())
+	}
+
+	if ctx.IsSet("hopprob") {
+		haveValue = true
+		resp.Config.HopProbability = float32(ctx.Float64("hopprob"))
+	}
+
+	if ctx.IsSet("weight") {
+		haveValue = true
+		resp.Config.Weight = float32(ctx.Float64("weight"))
+	}
+
+	if ctx.IsSet("pmtnr") {
+		haveValue = true
+		resp.Config.MaximumPaymentResults = uint32(ctx.Int("pmtnr"))
+	}
+
+	if ctx.IsSet("failrelax") {
+		haveValue = true
+		resp.Config.MinimumFailureRelaxInterval = uint64(ctx.Duration(
+			"failrelax",
+		).Seconds())
+	}
+
+	if !haveValue {
+		return cli.ShowCommandHelp(ctx, "setmccfg")
+	}
+
+	_, err = client.SetMissionControlConfig(
+		ctxb, &routerrpc.SetMissionControlConfigRequest{
+			Config: resp.Config,
+		},
+	)
+	return err
+}
diff --git a/cmd/lncli/routerrpc.go b/cmd/lncli/routerrpc.go
index 819f66d22..04c9676ec 100644
--- a/cmd/lncli/routerrpc.go
+++ b/cmd/lncli/routerrpc.go
@@ -9,5 +9,7 @@ func routerCommands() []cli.Command {
 		queryProbCommand,
 		resetMissionControlCommand,
 		buildRouteCommand,
+		getCfgCommand,
+		setCfgCommand,
 	}
 }
diff --git a/lnrpc/rest-annotations.yaml b/lnrpc/rest-annotations.yaml
index fae8d577a..927dd63ee 100644
--- a/lnrpc/rest-annotations.yaml
+++ b/lnrpc/rest-annotations.yaml
@@ -208,6 +208,11 @@ http:
       body: "*"
     - selector: routerrpc.Router.QueryMissionControl
       get: "/v2/router/mc"
+    - selector: routerrpc.Router.GetMissionControlConfig
+      get: "/v2/router/mccfg"
+    - selector: routerroc.Router.SetMissionControlConfig
+      post: "/v2/router/mccfg"
+      body: "*"
     - selector: routerrpc.Router.QueryProbability
       get: "/v2/router/mc/probability/{from_node}/{to_node}/{amt_msat}"
     - selector: routerrpc.Router.BuildRoute
diff --git a/lnrpc/routerrpc/router.pb.go b/lnrpc/routerrpc/router.pb.go
index 7d454125c..5d552c19b 100644
--- a/lnrpc/routerrpc/router.pb.go
+++ b/lnrpc/routerrpc/router.pb.go
@@ -225,7 +225,7 @@ func (x HtlcEvent_EventType) String() string {
 }
 
 func (HtlcEvent_EventType) EnumDescriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{17, 0}
+	return fileDescriptor_7a0613f69d37b0a5, []int{22, 0}
 }
 
 type SendPaymentRequest struct {
@@ -1029,6 +1029,245 @@ func (m *PairData) GetSuccessAmtMsat() int64 {
 	return 0
 }
 
+type GetMissionControlConfigRequest struct {
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *GetMissionControlConfigRequest) Reset()         { *m = GetMissionControlConfigRequest{} }
+func (m *GetMissionControlConfigRequest) String() string { return proto.CompactTextString(m) }
+func (*GetMissionControlConfigRequest) ProtoMessage()    {}
+func (*GetMissionControlConfigRequest) Descriptor() ([]byte, []int) {
+	return fileDescriptor_7a0613f69d37b0a5, []int{12}
+}
+
+func (m *GetMissionControlConfigRequest) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_GetMissionControlConfigRequest.Unmarshal(m, b)
+}
+func (m *GetMissionControlConfigRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_GetMissionControlConfigRequest.Marshal(b, m, deterministic)
+}
+func (m *GetMissionControlConfigRequest) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_GetMissionControlConfigRequest.Merge(m, src)
+}
+func (m *GetMissionControlConfigRequest) XXX_Size() int {
+	return xxx_messageInfo_GetMissionControlConfigRequest.Size(m)
+}
+func (m *GetMissionControlConfigRequest) XXX_DiscardUnknown() {
+	xxx_messageInfo_GetMissionControlConfigRequest.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_GetMissionControlConfigRequest proto.InternalMessageInfo
+
+type GetMissionControlConfigResponse struct {
+	//
+	//Mission control's currently active config.
+	Config               *MissionControlConfig `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}              `json:"-"`
+	XXX_unrecognized     []byte                `json:"-"`
+	XXX_sizecache        int32                 `json:"-"`
+}
+
+func (m *GetMissionControlConfigResponse) Reset()         { *m = GetMissionControlConfigResponse{} }
+func (m *GetMissionControlConfigResponse) String() string { return proto.CompactTextString(m) }
+func (*GetMissionControlConfigResponse) ProtoMessage()    {}
+func (*GetMissionControlConfigResponse) Descriptor() ([]byte, []int) {
+	return fileDescriptor_7a0613f69d37b0a5, []int{13}
+}
+
+func (m *GetMissionControlConfigResponse) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_GetMissionControlConfigResponse.Unmarshal(m, b)
+}
+func (m *GetMissionControlConfigResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_GetMissionControlConfigResponse.Marshal(b, m, deterministic)
+}
+func (m *GetMissionControlConfigResponse) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_GetMissionControlConfigResponse.Merge(m, src)
+}
+func (m *GetMissionControlConfigResponse) XXX_Size() int {
+	return xxx_messageInfo_GetMissionControlConfigResponse.Size(m)
+}
+func (m *GetMissionControlConfigResponse) XXX_DiscardUnknown() {
+	xxx_messageInfo_GetMissionControlConfigResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_GetMissionControlConfigResponse proto.InternalMessageInfo
+
+func (m *GetMissionControlConfigResponse) GetConfig() *MissionControlConfig {
+	if m != nil {
+		return m.Config
+	}
+	return nil
+}
+
+type SetMissionControlConfigRequest struct {
+	//
+	//The config to set for mission control. Note that all values *must* be set,
+	//because the full config will be applied.
+	Config               *MissionControlConfig `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}              `json:"-"`
+	XXX_unrecognized     []byte                `json:"-"`
+	XXX_sizecache        int32                 `json:"-"`
+}
+
+func (m *SetMissionControlConfigRequest) Reset()         { *m = SetMissionControlConfigRequest{} }
+func (m *SetMissionControlConfigRequest) String() string { return proto.CompactTextString(m) }
+func (*SetMissionControlConfigRequest) ProtoMessage()    {}
+func (*SetMissionControlConfigRequest) Descriptor() ([]byte, []int) {
+	return fileDescriptor_7a0613f69d37b0a5, []int{14}
+}
+
+func (m *SetMissionControlConfigRequest) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_SetMissionControlConfigRequest.Unmarshal(m, b)
+}
+func (m *SetMissionControlConfigRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_SetMissionControlConfigRequest.Marshal(b, m, deterministic)
+}
+func (m *SetMissionControlConfigRequest) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_SetMissionControlConfigRequest.Merge(m, src)
+}
+func (m *SetMissionControlConfigRequest) XXX_Size() int {
+	return xxx_messageInfo_SetMissionControlConfigRequest.Size(m)
+}
+func (m *SetMissionControlConfigRequest) XXX_DiscardUnknown() {
+	xxx_messageInfo_SetMissionControlConfigRequest.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_SetMissionControlConfigRequest proto.InternalMessageInfo
+
+func (m *SetMissionControlConfigRequest) GetConfig() *MissionControlConfig {
+	if m != nil {
+		return m.Config
+	}
+	return nil
+}
+
+type SetMissionControlConfigResponse struct {
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *SetMissionControlConfigResponse) Reset()         { *m = SetMissionControlConfigResponse{} }
+func (m *SetMissionControlConfigResponse) String() string { return proto.CompactTextString(m) }
+func (*SetMissionControlConfigResponse) ProtoMessage()    {}
+func (*SetMissionControlConfigResponse) Descriptor() ([]byte, []int) {
+	return fileDescriptor_7a0613f69d37b0a5, []int{15}
+}
+
+func (m *SetMissionControlConfigResponse) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_SetMissionControlConfigResponse.Unmarshal(m, b)
+}
+func (m *SetMissionControlConfigResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_SetMissionControlConfigResponse.Marshal(b, m, deterministic)
+}
+func (m *SetMissionControlConfigResponse) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_SetMissionControlConfigResponse.Merge(m, src)
+}
+func (m *SetMissionControlConfigResponse) XXX_Size() int {
+	return xxx_messageInfo_SetMissionControlConfigResponse.Size(m)
+}
+func (m *SetMissionControlConfigResponse) XXX_DiscardUnknown() {
+	xxx_messageInfo_SetMissionControlConfigResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_SetMissionControlConfigResponse proto.InternalMessageInfo
+
+type MissionControlConfig struct {
+	//
+	//The amount of time mission control will take to restore a penalized node
+	//or channel back to 50% success probability, expressed as a unix timestamp
+	//in seconds. Setting this value to a higher value will penalize failures for
+	//longer, making mission control less likely to route through nodes and
+	//channels that we have previously recorded failures for.
+	HalfLifeSeconds uint64 `protobuf:"varint,1,opt,name=half_life_seconds,json=halfLifeSeconds,proto3" json:"half_life_seconds,omitempty"`
+	//
+	//The probability of success mission control should assign to hop in a route
+	//where it has no other information available. Higher values will make mission
+	//control more willing to try hops that we have no information about, lower
+	//values will discourage trying these hops.
+	HopProbability float32 `protobuf:"fixed32,2,opt,name=hop_probability,json=hopProbability,proto3" json:"hop_probability,omitempty"`
+	//
+	//The importance that mission control should place on historical results,
+	//expressed as a value in [0;1]. Setting this value to 1 will ignore all
+	//historical payments and just use the hop probability to assess the
+	//probability of success for each hop. A zero value ignores hop probability
+	//completely and relies entirely on historical results, unless none are
+	//available.
+	Weight float32 `protobuf:"fixed32,3,opt,name=weight,proto3" json:"weight,omitempty"`
+	//
+	//The maximum number of payment results that mission control will store.
+	MaximumPaymentResults uint32 `protobuf:"varint,4,opt,name=maximum_payment_results,json=maximumPaymentResults,proto3" json:"maximum_payment_results,omitempty"`
+	//
+	//The minimum time that must have passed since the previously recorded failure
+	//before we raise the failure amount.
+	MinimumFailureRelaxInterval uint64   `protobuf:"varint,5,opt,name=minimum_failure_relax_interval,json=minimumFailureRelaxInterval,proto3" json:"minimum_failure_relax_interval,omitempty"`
+	XXX_NoUnkeyedLiteral        struct{} `json:"-"`
+	XXX_unrecognized            []byte   `json:"-"`
+	XXX_sizecache               int32    `json:"-"`
+}
+
+func (m *MissionControlConfig) Reset()         { *m = MissionControlConfig{} }
+func (m *MissionControlConfig) String() string { return proto.CompactTextString(m) }
+func (*MissionControlConfig) ProtoMessage()    {}
+func (*MissionControlConfig) Descriptor() ([]byte, []int) {
+	return fileDescriptor_7a0613f69d37b0a5, []int{16}
+}
+
+func (m *MissionControlConfig) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_MissionControlConfig.Unmarshal(m, b)
+}
+func (m *MissionControlConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_MissionControlConfig.Marshal(b, m, deterministic)
+}
+func (m *MissionControlConfig) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_MissionControlConfig.Merge(m, src)
+}
+func (m *MissionControlConfig) XXX_Size() int {
+	return xxx_messageInfo_MissionControlConfig.Size(m)
+}
+func (m *MissionControlConfig) XXX_DiscardUnknown() {
+	xxx_messageInfo_MissionControlConfig.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MissionControlConfig proto.InternalMessageInfo
+
+func (m *MissionControlConfig) GetHalfLifeSeconds() uint64 {
+	if m != nil {
+		return m.HalfLifeSeconds
+	}
+	return 0
+}
+
+func (m *MissionControlConfig) GetHopProbability() float32 {
+	if m != nil {
+		return m.HopProbability
+	}
+	return 0
+}
+
+func (m *MissionControlConfig) GetWeight() float32 {
+	if m != nil {
+		return m.Weight
+	}
+	return 0
+}
+
+func (m *MissionControlConfig) GetMaximumPaymentResults() uint32 {
+	if m != nil {
+		return m.MaximumPaymentResults
+	}
+	return 0
+}
+
+func (m *MissionControlConfig) GetMinimumFailureRelaxInterval() uint64 {
+	if m != nil {
+		return m.MinimumFailureRelaxInterval
+	}
+	return 0
+}
+
 type QueryProbabilityRequest struct {
 	// The source node pubkey of the pair.
 	FromNode []byte `protobuf:"bytes,1,opt,name=from_node,json=fromNode,proto3" json:"from_node,omitempty"`
@@ -1045,7 +1284,7 @@ func (m *QueryProbabilityRequest) Reset()         { *m = QueryProbabilityRequest
 func (m *QueryProbabilityRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryProbabilityRequest) ProtoMessage()    {}
 func (*QueryProbabilityRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{12}
+	return fileDescriptor_7a0613f69d37b0a5, []int{17}
 }
 
 func (m *QueryProbabilityRequest) XXX_Unmarshal(b []byte) error {
@@ -1101,7 +1340,7 @@ func (m *QueryProbabilityResponse) Reset()         { *m = QueryProbabilityRespon
 func (m *QueryProbabilityResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryProbabilityResponse) ProtoMessage()    {}
 func (*QueryProbabilityResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{13}
+	return fileDescriptor_7a0613f69d37b0a5, []int{18}
 }
 
 func (m *QueryProbabilityResponse) XXX_Unmarshal(b []byte) error {
@@ -1164,7 +1403,7 @@ func (m *BuildRouteRequest) Reset()         { *m = BuildRouteRequest{} }
 func (m *BuildRouteRequest) String() string { return proto.CompactTextString(m) }
 func (*BuildRouteRequest) ProtoMessage()    {}
 func (*BuildRouteRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{14}
+	return fileDescriptor_7a0613f69d37b0a5, []int{19}
 }
 
 func (m *BuildRouteRequest) XXX_Unmarshal(b []byte) error {
@@ -1233,7 +1472,7 @@ func (m *BuildRouteResponse) Reset()         { *m = BuildRouteResponse{} }
 func (m *BuildRouteResponse) String() string { return proto.CompactTextString(m) }
 func (*BuildRouteResponse) ProtoMessage()    {}
 func (*BuildRouteResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{15}
+	return fileDescriptor_7a0613f69d37b0a5, []int{20}
 }
 
 func (m *BuildRouteResponse) XXX_Unmarshal(b []byte) error {
@@ -1271,7 +1510,7 @@ func (m *SubscribeHtlcEventsRequest) Reset()         { *m = SubscribeHtlcEventsR
 func (m *SubscribeHtlcEventsRequest) String() string { return proto.CompactTextString(m) }
 func (*SubscribeHtlcEventsRequest) ProtoMessage()    {}
 func (*SubscribeHtlcEventsRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{16}
+	return fileDescriptor_7a0613f69d37b0a5, []int{21}
 }
 
 func (m *SubscribeHtlcEventsRequest) XXX_Unmarshal(b []byte) error {
@@ -1338,7 +1577,7 @@ func (m *HtlcEvent) Reset()         { *m = HtlcEvent{} }
 func (m *HtlcEvent) String() string { return proto.CompactTextString(m) }
 func (*HtlcEvent) ProtoMessage()    {}
 func (*HtlcEvent) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{17}
+	return fileDescriptor_7a0613f69d37b0a5, []int{22}
 }
 
 func (m *HtlcEvent) XXX_Unmarshal(b []byte) error {
@@ -1492,7 +1731,7 @@ func (m *HtlcInfo) Reset()         { *m = HtlcInfo{} }
 func (m *HtlcInfo) String() string { return proto.CompactTextString(m) }
 func (*HtlcInfo) ProtoMessage()    {}
 func (*HtlcInfo) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{18}
+	return fileDescriptor_7a0613f69d37b0a5, []int{23}
 }
 
 func (m *HtlcInfo) XXX_Unmarshal(b []byte) error {
@@ -1553,7 +1792,7 @@ func (m *ForwardEvent) Reset()         { *m = ForwardEvent{} }
 func (m *ForwardEvent) String() string { return proto.CompactTextString(m) }
 func (*ForwardEvent) ProtoMessage()    {}
 func (*ForwardEvent) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{19}
+	return fileDescriptor_7a0613f69d37b0a5, []int{24}
 }
 
 func (m *ForwardEvent) XXX_Unmarshal(b []byte) error {
@@ -1591,7 +1830,7 @@ func (m *ForwardFailEvent) Reset()         { *m = ForwardFailEvent{} }
 func (m *ForwardFailEvent) String() string { return proto.CompactTextString(m) }
 func (*ForwardFailEvent) ProtoMessage()    {}
 func (*ForwardFailEvent) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{20}
+	return fileDescriptor_7a0613f69d37b0a5, []int{25}
 }
 
 func (m *ForwardFailEvent) XXX_Unmarshal(b []byte) error {
@@ -1622,7 +1861,7 @@ func (m *SettleEvent) Reset()         { *m = SettleEvent{} }
 func (m *SettleEvent) String() string { return proto.CompactTextString(m) }
 func (*SettleEvent) ProtoMessage()    {}
 func (*SettleEvent) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{21}
+	return fileDescriptor_7a0613f69d37b0a5, []int{26}
 }
 
 func (m *SettleEvent) XXX_Unmarshal(b []byte) error {
@@ -1664,7 +1903,7 @@ func (m *LinkFailEvent) Reset()         { *m = LinkFailEvent{} }
 func (m *LinkFailEvent) String() string { return proto.CompactTextString(m) }
 func (*LinkFailEvent) ProtoMessage()    {}
 func (*LinkFailEvent) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{22}
+	return fileDescriptor_7a0613f69d37b0a5, []int{27}
 }
 
 func (m *LinkFailEvent) XXX_Unmarshal(b []byte) error {
@@ -1731,7 +1970,7 @@ func (m *PaymentStatus) Reset()         { *m = PaymentStatus{} }
 func (m *PaymentStatus) String() string { return proto.CompactTextString(m) }
 func (*PaymentStatus) ProtoMessage()    {}
 func (*PaymentStatus) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{23}
+	return fileDescriptor_7a0613f69d37b0a5, []int{28}
 }
 
 func (m *PaymentStatus) XXX_Unmarshal(b []byte) error {
@@ -1787,7 +2026,7 @@ func (m *CircuitKey) Reset()         { *m = CircuitKey{} }
 func (m *CircuitKey) String() string { return proto.CompactTextString(m) }
 func (*CircuitKey) ProtoMessage()    {}
 func (*CircuitKey) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{24}
+	return fileDescriptor_7a0613f69d37b0a5, []int{29}
 }
 
 func (m *CircuitKey) XXX_Unmarshal(b []byte) error {
@@ -1857,7 +2096,7 @@ func (m *ForwardHtlcInterceptRequest) Reset()         { *m = ForwardHtlcIntercep
 func (m *ForwardHtlcInterceptRequest) String() string { return proto.CompactTextString(m) }
 func (*ForwardHtlcInterceptRequest) ProtoMessage()    {}
 func (*ForwardHtlcInterceptRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{25}
+	return fileDescriptor_7a0613f69d37b0a5, []int{30}
 }
 
 func (m *ForwardHtlcInterceptRequest) XXX_Unmarshal(b []byte) error {
@@ -1965,7 +2204,7 @@ func (m *ForwardHtlcInterceptResponse) Reset()         { *m = ForwardHtlcInterce
 func (m *ForwardHtlcInterceptResponse) String() string { return proto.CompactTextString(m) }
 func (*ForwardHtlcInterceptResponse) ProtoMessage()    {}
 func (*ForwardHtlcInterceptResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7a0613f69d37b0a5, []int{26}
+	return fileDescriptor_7a0613f69d37b0a5, []int{31}
 }
 
 func (m *ForwardHtlcInterceptResponse) XXX_Unmarshal(b []byte) error {
@@ -2025,6 +2264,11 @@ func init() {
 	proto.RegisterType((*QueryMissionControlResponse)(nil), "routerrpc.QueryMissionControlResponse")
 	proto.RegisterType((*PairHistory)(nil), "routerrpc.PairHistory")
 	proto.RegisterType((*PairData)(nil), "routerrpc.PairData")
+	proto.RegisterType((*GetMissionControlConfigRequest)(nil), "routerrpc.GetMissionControlConfigRequest")
+	proto.RegisterType((*GetMissionControlConfigResponse)(nil), "routerrpc.GetMissionControlConfigResponse")
+	proto.RegisterType((*SetMissionControlConfigRequest)(nil), "routerrpc.SetMissionControlConfigRequest")
+	proto.RegisterType((*SetMissionControlConfigResponse)(nil), "routerrpc.SetMissionControlConfigResponse")
+	proto.RegisterType((*MissionControlConfig)(nil), "routerrpc.MissionControlConfig")
 	proto.RegisterType((*QueryProbabilityRequest)(nil), "routerrpc.QueryProbabilityRequest")
 	proto.RegisterType((*QueryProbabilityResponse)(nil), "routerrpc.QueryProbabilityResponse")
 	proto.RegisterType((*BuildRouteRequest)(nil), "routerrpc.BuildRouteRequest")
@@ -2046,171 +2290,184 @@ func init() {
 func init() { proto.RegisterFile("routerrpc/router.proto", fileDescriptor_7a0613f69d37b0a5) }
 
 var fileDescriptor_7a0613f69d37b0a5 = []byte{
-	// 2622 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x59, 0xcd, 0x76, 0xdb, 0xc6,
-	0xf5, 0x0f, 0xf8, 0x25, 0xf2, 0xf2, 0x43, 0xd0, 0x48, 0xb1, 0xf8, 0xa7, 0xec, 0x84, 0x61, 0x12,
-	0x9b, 0xc7, 0xff, 0x44, 0x56, 0xd4, 0x9e, 0x36, 0x6d, 0x3e, 0x1a, 0x8a, 0x84, 0x2c, 0xd8, 0x14,
-	0xa9, 0x0c, 0x29, 0x27, 0x69, 0x16, 0x53, 0x88, 0x18, 0x8a, 0xa8, 0x40, 0x80, 0x05, 0x86, 0x76,
-	0xb4, 0xec, 0xae, 0xa7, 0x0f, 0xd0, 0xc7, 0xe8, 0x13, 0xf4, 0x9c, 0x76, 0xd1, 0x55, 0x5f, 0xa2,
-	0xdb, 0x3e, 0x41, 0xd7, 0x3d, 0xf3, 0x01, 0x10, 0x90, 0x28, 0xbb, 0x3d, 0xed, 0xc6, 0x26, 0x7e,
-	0xf7, 0xce, 0x9d, 0x7b, 0xe7, 0x7e, 0xce, 0x08, 0xee, 0x05, 0xfe, 0x92, 0xd1, 0x20, 0x58, 0x4c,
-	0x9e, 0xc8, 0x5f, 0xfb, 0x8b, 0xc0, 0x67, 0x3e, 0x2a, 0xc5, 0x78, 0xa3, 0x14, 0x2c, 0x26, 0x12,
-	0x6d, 0xfd, 0x61, 0x03, 0xd0, 0x88, 0x7a, 0xf6, 0x99, 0x75, 0x3d, 0xa7, 0x1e, 0xc3, 0xf4, 0x37,
-	0x4b, 0x1a, 0x32, 0x84, 0x20, 0x67, 0xd3, 0x90, 0xd5, 0xb5, 0xa6, 0xd6, 0xae, 0x60, 0xf1, 0x1b,
-	0xe9, 0x90, 0xb5, 0xe6, 0xac, 0x9e, 0x69, 0x6a, 0xed, 0x2c, 0xe6, 0x3f, 0xd1, 0xff, 0x41, 0xd1,
-	0x9a, 0x33, 0x32, 0x0f, 0x2d, 0x56, 0xaf, 0x08, 0x78, 0xc3, 0x9a, 0xb3, 0xd3, 0xd0, 0x62, 0xe8,
-	0x3d, 0xa8, 0x2c, 0xa4, 0x48, 0x32, 0xb3, 0xc2, 0x59, 0x3d, 0x2b, 0x04, 0x95, 0x15, 0x76, 0x62,
-	0x85, 0x33, 0xd4, 0x06, 0x7d, 0xea, 0x78, 0x96, 0x4b, 0x26, 0x2e, 0x7b, 0x49, 0x6c, 0xea, 0x32,
-	0xab, 0x9e, 0x6b, 0x6a, 0xed, 0x3c, 0xae, 0x09, 0xbc, 0xeb, 0xb2, 0x97, 0x3d, 0x8e, 0x26, 0x85,
-	0x59, 0xb6, 0x1d, 0xd4, 0x77, 0x52, 0xc2, 0x3a, 0xb6, 0x1d, 0xa0, 0x47, 0xb0, 0x19, 0xb1, 0x04,
-	0xd2, 0x86, 0x7a, 0xbe, 0xa9, 0xb5, 0x4b, 0xb8, 0xb6, 0x48, 0x5b, 0xf6, 0x08, 0x36, 0x99, 0x33,
-	0xa7, 0xfe, 0x92, 0x91, 0x90, 0x4e, 0x7c, 0xcf, 0x0e, 0xeb, 0x05, 0xb9, 0xa9, 0x82, 0x47, 0x12,
-	0x45, 0x2d, 0xa8, 0x4e, 0x29, 0x25, 0xae, 0x33, 0x77, 0x18, 0xe1, 0x16, 0x6e, 0x08, 0x0b, 0xcb,
-	0x53, 0x4a, 0xfb, 0x1c, 0x1b, 0x59, 0x0c, 0x7d, 0x00, 0xb5, 0x15, 0x8f, 0x38, 0x86, 0xaa, 0x60,
-	0xaa, 0x44, 0x4c, 0xe2, 0x2c, 0xf6, 0x41, 0xf7, 0x97, 0xec, 0xd2, 0x77, 0xbc, 0x4b, 0x32, 0x99,
-	0x59, 0x1e, 0x71, 0xec, 0x7a, 0xb1, 0xa9, 0xb5, 0x73, 0x47, 0xb9, 0xba, 0x76, 0xa0, 0xe1, 0x5a,
-	0x44, 0xed, 0xce, 0x2c, 0xcf, 0xb4, 0xd1, 0x63, 0xd8, 0xba, 0xc9, 0x1f, 0xd6, 0xb7, 0x9b, 0xd9,
-	0x76, 0x0e, 0x6f, 0xa6, 0x59, 0x43, 0xf4, 0x10, 0x36, 0x5d, 0x2b, 0x64, 0x64, 0xe6, 0x2f, 0xc8,
-	0x62, 0x79, 0x71, 0x45, 0xaf, 0xeb, 0x35, 0x71, 0x3a, 0x55, 0x0e, 0x9f, 0xf8, 0x8b, 0x33, 0x01,
-	0xa2, 0x07, 0x00, 0xe2, 0x98, 0x85, 0xaa, 0xf5, 0x92, 0xb0, 0xb8, 0xc4, 0x11, 0xa1, 0x26, 0xfa,
-	0x04, 0xca, 0x22, 0x3c, 0xc8, 0xcc, 0xf1, 0x58, 0x58, 0x87, 0x66, 0xb6, 0x5d, 0x3e, 0xd4, 0xf7,
-	0x5d, 0x8f, 0x47, 0x0a, 0xe6, 0x94, 0x13, 0xc7, 0x63, 0x18, 0x82, 0xe8, 0x67, 0x88, 0x6c, 0xd8,
-	0xe6, 0x61, 0x41, 0x26, 0xcb, 0x90, 0xf9, 0x73, 0x12, 0xd0, 0x89, 0x1f, 0xd8, 0x61, 0xbd, 0x2c,
-	0x96, 0xfe, 0x78, 0x3f, 0x8e, 0xb6, 0xfd, 0xdb, 0xe1, 0xb5, 0xdf, 0xa3, 0x21, 0xeb, 0x8a, 0x75,
-	0x58, 0x2e, 0x33, 0x3c, 0x16, 0x5c, 0xe3, 0x2d, 0xfb, 0x26, 0x8e, 0x3e, 0x02, 0x64, 0xb9, 0xae,
-	0xff, 0x8a, 0x84, 0xd4, 0x9d, 0x12, 0xe5, 0xcb, 0xfa, 0x66, 0x53, 0x6b, 0x17, 0xb1, 0x2e, 0x28,
-	0x23, 0xea, 0x4e, 0x95, 0x78, 0xf4, 0x13, 0xa8, 0x0a, 0x9d, 0xa6, 0xd4, 0x62, 0xcb, 0x80, 0x86,
-	0x75, 0xbd, 0x99, 0x6d, 0xd7, 0x0e, 0xb7, 0x94, 0x21, 0xc7, 0x12, 0x3e, 0x72, 0x18, 0xae, 0x70,
-	0x3e, 0xf5, 0x1d, 0xa2, 0x3d, 0x28, 0xcd, 0xad, 0x1f, 0xc8, 0xc2, 0x0a, 0x58, 0x58, 0xdf, 0x6a,
-	0x6a, 0xed, 0x2a, 0x2e, 0xce, 0xad, 0x1f, 0xce, 0xf8, 0x37, 0xda, 0x87, 0x6d, 0xcf, 0x27, 0x8e,
-	0x37, 0x75, 0x9d, 0xcb, 0x19, 0x23, 0xcb, 0x85, 0x6d, 0x31, 0x1a, 0xd6, 0x91, 0xd0, 0x61, 0xcb,
-	0xf3, 0x4d, 0x45, 0x39, 0x97, 0x84, 0x46, 0x0f, 0xee, 0xad, 0xb7, 0x8f, 0x67, 0x10, 0x77, 0x10,
-	0x4f, 0xaa, 0x1c, 0xe6, 0x3f, 0xd1, 0x0e, 0xe4, 0x5f, 0x5a, 0xee, 0x92, 0x8a, 0xac, 0xaa, 0x60,
-	0xf9, 0xf1, 0xf3, 0xcc, 0xa7, 0x5a, 0x6b, 0x06, 0xdb, 0xe3, 0xc0, 0x9a, 0x5c, 0xdd, 0x48, 0xcc,
-	0x9b, 0x79, 0xa5, 0xdd, 0xce, 0xab, 0x3b, 0xf4, 0xcd, 0xdc, 0xa1, 0x6f, 0xeb, 0x4b, 0xd8, 0x14,
-	0x1e, 0x3e, 0xa6, 0xf4, 0x75, 0xe9, 0xbf, 0x0b, 0x3c, 0xb9, 0x45, 0x26, 0xc8, 0x12, 0x50, 0xb0,
-	0xe6, 0x3c, 0x09, 0x5a, 0x36, 0xe8, 0xab, 0xf5, 0xe1, 0xc2, 0xf7, 0x42, 0xca, 0x73, 0x9b, 0x07,
-	0x00, 0x8f, 0x60, 0x9e, 0x20, 0x22, 0x35, 0x34, 0xb1, 0xaa, 0xa6, 0xf0, 0x63, 0x4a, 0x45, 0x72,
-	0x3c, 0x94, 0xf9, 0x48, 0x5c, 0x7f, 0x72, 0xc5, 0x8b, 0x80, 0x75, 0xad, 0xc4, 0x57, 0x39, 0xdc,
-	0xf7, 0x27, 0x57, 0x3d, 0x0e, 0xb6, 0xbe, 0x97, 0x75, 0x6a, 0xec, 0x8b, 0xbd, 0xfe, 0x83, 0xe3,
-	0x68, 0x41, 0x5e, 0xc4, 0xa2, 0x10, 0x5b, 0x3e, 0xac, 0x24, 0x83, 0x1a, 0x4b, 0x52, 0xeb, 0x7b,
-	0xd8, 0x4e, 0x09, 0x57, 0x56, 0x34, 0xa0, 0xb8, 0x08, 0xa8, 0x33, 0xb7, 0x2e, 0xa9, 0x92, 0x1c,
-	0x7f, 0xa3, 0x36, 0x6c, 0x4c, 0x2d, 0xc7, 0x5d, 0x06, 0x91, 0xe0, 0x5a, 0x14, 0x64, 0x12, 0xc5,
-	0x11, 0xb9, 0x75, 0x1f, 0x1a, 0x98, 0x86, 0x94, 0x9d, 0x3a, 0x61, 0xe8, 0xf8, 0x5e, 0xd7, 0xf7,
-	0x58, 0xe0, 0xbb, 0xca, 0x82, 0xd6, 0x03, 0xd8, 0x5b, 0x4b, 0x95, 0x2a, 0xf0, 0xc5, 0x5f, 0x2f,
-	0x69, 0x70, 0xbd, 0x7e, 0xf1, 0xd7, 0xb0, 0xb7, 0x96, 0xaa, 0xf4, 0xff, 0x08, 0xf2, 0x0b, 0xcb,
-	0x09, 0xb8, 0xef, 0x79, 0x52, 0xde, 0x4b, 0x24, 0xe5, 0x99, 0xe5, 0x04, 0x27, 0x4e, 0xc8, 0xfc,
-	0xe0, 0x1a, 0x4b, 0xa6, 0x67, 0xb9, 0xa2, 0xa6, 0x67, 0x5a, 0xbf, 0xd7, 0xa0, 0x9c, 0x20, 0xf2,
-	0xd4, 0xf0, 0x7c, 0x9b, 0x92, 0x69, 0xe0, 0xcf, 0xa3, 0x43, 0xe0, 0xc0, 0x71, 0xe0, 0xcf, 0x79,
-	0x4c, 0x08, 0x22, 0xf3, 0x55, 0x00, 0x17, 0xf8, 0xe7, 0xd8, 0x47, 0x1f, 0xc3, 0xc6, 0x4c, 0x0a,
-	0x10, 0x65, 0xb3, 0x7c, 0xb8, 0x7d, 0x63, 0xef, 0x9e, 0xc5, 0x2c, 0x1c, 0xf1, 0x3c, 0xcb, 0x15,
-	0xb3, 0x7a, 0xee, 0x59, 0xae, 0x98, 0xd3, 0xf3, 0xcf, 0x72, 0xc5, 0xbc, 0x5e, 0x78, 0x96, 0x2b,
-	0x16, 0xf4, 0x8d, 0xd6, 0x3f, 0x34, 0x28, 0x46, 0xdc, 0x5c, 0x13, 0x7e, 0xa4, 0x84, 0xc7, 0x85,
-	0x0a, 0xa6, 0x22, 0x07, 0xc6, 0xce, 0x9c, 0xa2, 0x26, 0x54, 0x04, 0x31, 0x1d, 0xa2, 0xc0, 0xb1,
-	0x8e, 0x08, 0x53, 0x51, 0xcf, 0x23, 0x0e, 0x11, 0x8f, 0x39, 0x55, 0xcf, 0x25, 0x4b, 0xd4, 0xb5,
-	0xc2, 0xe5, 0x64, 0x42, 0xc3, 0x50, 0xee, 0x92, 0x97, 0x2c, 0x0a, 0x13, 0x1b, 0x3d, 0x84, 0xcd,
-	0x88, 0x25, 0xda, 0xab, 0x20, 0xe3, 0x55, 0xc1, 0x6a, 0xbb, 0x36, 0xe8, 0x49, 0xbe, 0xf9, 0xaa,
-	0x83, 0xd4, 0x56, 0x8c, 0x7c, 0x53, 0x69, 0x7c, 0xeb, 0xd7, 0xb0, 0x2b, 0x5c, 0x79, 0x16, 0xf8,
-	0x17, 0xd6, 0x85, 0xe3, 0x3a, 0xec, 0x3a, 0x0a, 0x72, 0x6e, 0x78, 0xe0, 0xcf, 0x09, 0x3f, 0xdb,
-	0xc8, 0x05, 0x1c, 0x18, 0xf8, 0x36, 0xe5, 0x2e, 0x60, 0xbe, 0x24, 0x29, 0x17, 0x30, 0x5f, 0x10,
-	0x92, 0xcd, 0x39, 0x9b, 0x6a, 0xce, 0xad, 0x2b, 0xa8, 0xdf, 0xde, 0x4b, 0xc5, 0x4c, 0x13, 0xca,
-	0x8b, 0x15, 0x2c, 0xb6, 0xd3, 0x70, 0x12, 0x4a, 0xfa, 0x36, 0xf3, 0x66, 0xdf, 0xb6, 0xfe, 0xa6,
-	0xc1, 0xd6, 0xd1, 0xd2, 0x71, 0xed, 0x54, 0xe2, 0x26, 0xb5, 0xd3, 0xd2, 0xa3, 0xc3, 0xba, 0xb9,
-	0x20, 0xb3, 0x76, 0x2e, 0xf8, 0x68, 0x4d, 0x63, 0xcd, 0x8a, 0xc6, 0x9a, 0x59, 0xd3, 0x56, 0xdf,
-	0x85, 0xf2, 0xaa, 0x4b, 0x86, 0xf5, 0x5c, 0x33, 0xdb, 0xae, 0x60, 0x98, 0x45, 0x2d, 0x32, 0xbc,
-	0x35, 0x66, 0xe4, 0x6f, 0x8d, 0x19, 0xad, 0x4f, 0x01, 0x25, 0x6d, 0x51, 0x67, 0x16, 0x97, 0x18,
-	0xed, 0xee, 0x12, 0x73, 0x1f, 0x1a, 0xa3, 0xe5, 0x45, 0x38, 0x09, 0x9c, 0x0b, 0x7a, 0xc2, 0xdc,
-	0x89, 0xf1, 0x92, 0x7a, 0x2c, 0x8c, 0x12, 0xf9, 0x9f, 0x39, 0x28, 0xc5, 0x28, 0xaf, 0xe0, 0x8e,
-	0x37, 0xf1, 0xe7, 0x91, 0x5d, 0x1e, 0x75, 0xb9, 0x69, 0xb2, 0x6f, 0x6c, 0x45, 0xa4, 0xae, 0xa4,
-	0x98, 0x36, 0xe7, 0x4f, 0x9d, 0x83, 0xe2, 0xcf, 0x48, 0xfe, 0xe4, 0x31, 0x48, 0xfe, 0x36, 0xe8,
-	0xb1, 0xfc, 0x19, 0x73, 0x27, 0xf1, 0xb9, 0xe1, 0x5a, 0x84, 0x73, 0x65, 0x24, 0x67, 0x2c, 0x39,
-	0xe2, 0xcc, 0x49, 0xce, 0x08, 0x57, 0x9c, 0xef, 0x41, 0x85, 0xa7, 0x4c, 0xc8, 0xac, 0xf9, 0x82,
-	0x78, 0xa1, 0x38, 0xbc, 0x1c, 0x2e, 0xc7, 0xd8, 0x20, 0x44, 0x5f, 0x00, 0x50, 0x6e, 0x1f, 0x61,
-	0xd7, 0x0b, 0x2a, 0xb2, 0xa6, 0x76, 0xf8, 0x4e, 0x22, 0x76, 0xe2, 0x03, 0xd8, 0x17, 0xff, 0x8e,
-	0xaf, 0x17, 0x14, 0x97, 0x68, 0xf4, 0x13, 0x7d, 0x09, 0xd5, 0xa9, 0x1f, 0xbc, 0xb2, 0x02, 0x9b,
-	0x08, 0x50, 0x55, 0x96, 0xdd, 0x84, 0x84, 0x63, 0x49, 0x17, 0xcb, 0x4f, 0xde, 0xc2, 0x95, 0x69,
-	0xe2, 0x1b, 0x3d, 0x07, 0x14, 0xad, 0x17, 0x85, 0x40, 0x0a, 0x29, 0x0a, 0x21, 0x7b, 0xb7, 0x85,
-	0xf0, 0x3a, 0x1e, 0x09, 0xd2, 0xa7, 0x37, 0x30, 0xf4, 0x19, 0x54, 0x42, 0xca, 0x98, 0x4b, 0x95,
-	0x98, 0x92, 0x10, 0x73, 0x2f, 0x35, 0xf6, 0x70, 0x72, 0x24, 0xa1, 0x1c, 0xae, 0x3e, 0xd1, 0x11,
-	0x6c, 0xba, 0x8e, 0x77, 0x95, 0x54, 0x03, 0xc4, 0xfa, 0x7a, 0x62, 0x7d, 0xdf, 0xf1, 0xae, 0x92,
-	0x3a, 0x54, 0xdd, 0x24, 0xd0, 0xfa, 0x1c, 0x4a, 0xf1, 0x29, 0xa1, 0x32, 0x6c, 0x9c, 0x0f, 0x9e,
-	0x0f, 0x86, 0xdf, 0x0c, 0xf4, 0xb7, 0x50, 0x11, 0x72, 0x23, 0x63, 0xd0, 0xd3, 0x35, 0x0e, 0x63,
-	0xa3, 0x6b, 0x98, 0x2f, 0x0c, 0x3d, 0xc3, 0x3f, 0x8e, 0x87, 0xf8, 0x9b, 0x0e, 0xee, 0xe9, 0xd9,
-	0xa3, 0x0d, 0xc8, 0x8b, 0x7d, 0x5b, 0x7f, 0xd2, 0xa0, 0x28, 0x3c, 0xe8, 0x4d, 0x7d, 0xf4, 0xff,
-	0x10, 0x07, 0x97, 0xa8, 0x7f, 0xbc, 0x27, 0x8b, 0xa8, 0xab, 0xe2, 0x38, 0x60, 0xc6, 0x0a, 0xe7,
-	0xcc, 0x71, 0x68, 0xc4, 0xcc, 0x19, 0xc9, 0x1c, 0x11, 0x62, 0xe6, 0xc7, 0x09, 0xc9, 0xa9, 0xaa,
-	0x94, 0xc3, 0x9b, 0x11, 0x21, 0x2a, 0xc2, 0xc9, 0xf1, 0x37, 0x55, 0xac, 0x13, 0xe3, 0xaf, 0xe2,
-	0x6d, 0xfd, 0x14, 0x2a, 0x49, 0x9f, 0xa3, 0x47, 0x90, 0x73, 0xbc, 0xa9, 0xaf, 0x12, 0x71, 0xfb,
-	0x46, 0x70, 0x71, 0x23, 0xb1, 0x60, 0x68, 0x21, 0xd0, 0x6f, 0xfa, 0xb9, 0x55, 0x85, 0x72, 0xc2,
-	0x69, 0xad, 0xbf, 0x6b, 0x50, 0x4d, 0x39, 0xe1, 0xdf, 0x96, 0x8e, 0xbe, 0x80, 0xca, 0x2b, 0x27,
-	0xa0, 0x24, 0x39, 0x21, 0xd4, 0x0e, 0x1b, 0xe9, 0x09, 0x21, 0xfa, 0xbf, 0xeb, 0xdb, 0x14, 0x97,
-	0x39, 0xbf, 0x02, 0xd0, 0x2f, 0xa0, 0xa6, 0x56, 0x12, 0x9b, 0x32, 0xcb, 0x71, 0xc5, 0x51, 0xd5,
-	0x52, 0xe1, 0xa1, 0x78, 0x7b, 0x82, 0x8e, 0xab, 0xd3, 0xe4, 0x27, 0xfa, 0x70, 0x25, 0x20, 0x64,
-	0x81, 0xe3, 0x5d, 0x8a, 0xf3, 0x2b, 0xc5, 0x6c, 0x23, 0x01, 0xf2, 0x5e, 0x5f, 0x55, 0xf3, 0xe5,
-	0x88, 0x59, 0x6c, 0x19, 0xa2, 0x8f, 0x21, 0x1f, 0x32, 0x4b, 0x55, 0xb2, 0x5a, 0x2a, 0xb7, 0x12,
-	0x8c, 0x14, 0x4b, 0xae, 0xd4, 0x80, 0x94, 0xb9, 0x35, 0x20, 0xe5, 0x79, 0xc5, 0x90, 0x85, 0xb6,
-	0x7c, 0x88, 0x94, 0xf1, 0x27, 0xe3, 0x7e, 0xb7, 0xc3, 0x18, 0x9d, 0x2f, 0x18, 0x96, 0x0c, 0xaa,
-	0x01, 0x7e, 0x09, 0xd0, 0x75, 0x82, 0xc9, 0xd2, 0x61, 0xcf, 0xe9, 0x35, 0x6f, 0x6b, 0x51, 0x45,
-	0x97, 0x65, 0xaf, 0x30, 0x91, 0x55, 0x7c, 0x17, 0x36, 0xa2, 0x42, 0x24, 0xeb, 0x5b, 0x61, 0x26,
-	0x0a, 0x50, 0xeb, 0xcf, 0x39, 0xd8, 0x53, 0x2e, 0x95, 0xde, 0x60, 0x34, 0x98, 0xd0, 0x45, 0x3c,
-	0x39, 0x3f, 0x85, 0x9d, 0x55, 0x51, 0x95, 0x1b, 0x91, 0x68, 0x1a, 0x2f, 0x1f, 0xbe, 0x9d, 0xb0,
-	0x74, 0xa5, 0x06, 0x46, 0x71, 0xb1, 0x5d, 0xa9, 0x76, 0x90, 0x10, 0x64, 0xcd, 0xfd, 0xa5, 0xa7,
-	0x42, 0x54, 0x56, 0x3c, 0xb4, 0x0a, 0x67, 0x4e, 0x12, 0x11, 0xfd, 0x08, 0xe2, 0x20, 0x27, 0xf4,
-	0x87, 0x85, 0x13, 0x5c, 0x8b, 0xea, 0x57, 0x5d, 0x95, 0x5b, 0x43, 0xa0, 0xb7, 0xc6, 0xd9, 0xcc,
-	0xed, 0x71, 0xf6, 0x33, 0x68, 0xc4, 0xd9, 0xa1, 0x6e, 0xba, 0xd4, 0x8e, 0xbb, 0xdf, 0x86, 0xd0,
-	0x61, 0x37, 0xe2, 0xc0, 0x11, 0x83, 0x6a, 0x81, 0x07, 0xb0, 0x93, 0x48, 0xad, 0x95, 0xea, 0x32,
-	0x13, 0xd1, 0x2a, 0xbb, 0x92, 0xaa, 0xc7, 0x2b, 0x94, 0xea, 0x39, 0xa9, 0x7a, 0x04, 0x2b, 0xd5,
-	0x7f, 0x05, 0xb5, 0x1b, 0x37, 0xc1, 0xa2, 0xf0, 0xfb, 0xcf, 0x6e, 0x57, 0xd6, 0x75, 0xee, 0xd9,
-	0x5f, 0x73, 0x1d, 0xac, 0x4e, 0x52, 0x57, 0xc1, 0x07, 0x00, 0xbe, 0xe7, 0xf8, 0x1e, 0xb9, 0x70,
-	0xfd, 0x0b, 0x51, 0x70, 0x2b, 0xb8, 0x24, 0x90, 0x23, 0xd7, 0xbf, 0x68, 0x7c, 0x05, 0xe8, 0xbf,
-	0xbc, 0x72, 0xfd, 0x45, 0x83, 0xfb, 0xeb, 0x55, 0x54, 0x7d, 0xfe, 0x7f, 0x16, 0x42, 0x9f, 0x41,
-	0xc1, 0x9a, 0x30, 0xc7, 0xf7, 0x54, 0x65, 0x78, 0x3f, 0xb1, 0x14, 0xd3, 0xd0, 0x77, 0x5f, 0xd2,
-	0x13, 0xdf, 0xb5, 0x95, 0x32, 0x1d, 0xc1, 0x8a, 0xd5, 0x92, 0x54, 0xd2, 0x65, 0xd3, 0x49, 0xf7,
-	0xf8, 0xb7, 0x39, 0xa8, 0xa6, 0x2a, 0x43, 0xba, 0x35, 0x54, 0xa1, 0x34, 0x18, 0x92, 0x9e, 0x31,
-	0xee, 0x98, 0x7d, 0x5d, 0x43, 0x3a, 0x54, 0x86, 0x03, 0x73, 0x38, 0x20, 0x3d, 0xa3, 0x3b, 0xec,
-	0xf1, 0x26, 0xf1, 0x36, 0x6c, 0xf5, 0xcd, 0xc1, 0x73, 0x32, 0x18, 0x8e, 0x89, 0xd1, 0x37, 0x9f,
-	0x9a, 0x47, 0x7d, 0x43, 0xcf, 0xa2, 0x1d, 0xd0, 0x87, 0x03, 0xd2, 0x3d, 0xe9, 0x98, 0x03, 0x32,
-	0x36, 0x4f, 0x8d, 0xe1, 0xf9, 0x58, 0xcf, 0x71, 0x94, 0x67, 0x33, 0x31, 0xbe, 0xed, 0x1a, 0x46,
-	0x6f, 0x44, 0x4e, 0x3b, 0xdf, 0xea, 0x79, 0x54, 0x87, 0x1d, 0x73, 0x30, 0x3a, 0x3f, 0x3e, 0x36,
-	0xbb, 0xa6, 0x31, 0x18, 0x93, 0xa3, 0x4e, 0xbf, 0x33, 0xe8, 0x1a, 0x7a, 0x01, 0xdd, 0x03, 0x64,
-	0x0e, 0xba, 0xc3, 0xd3, 0xb3, 0xbe, 0x31, 0x36, 0x48, 0xd4, 0x8c, 0x36, 0xd0, 0x36, 0x6c, 0x0a,
-	0x39, 0x9d, 0x5e, 0x8f, 0x1c, 0x77, 0xcc, 0xbe, 0xd1, 0xd3, 0x8b, 0x5c, 0x13, 0xc5, 0x31, 0x22,
-	0x3d, 0x73, 0xd4, 0x39, 0xe2, 0x70, 0x89, 0xef, 0x69, 0x0e, 0x5e, 0x0c, 0xcd, 0xae, 0x41, 0xba,
-	0x5c, 0x2c, 0x47, 0x81, 0x33, 0x47, 0xe8, 0xf9, 0xa0, 0x67, 0xe0, 0xb3, 0x8e, 0xd9, 0xd3, 0xcb,
-	0x68, 0x0f, 0x76, 0x23, 0xd8, 0xf8, 0xf6, 0xcc, 0xc4, 0xdf, 0x91, 0xf1, 0x70, 0x48, 0x46, 0xc3,
-	0xe1, 0x40, 0xaf, 0x24, 0x25, 0x71, 0x6b, 0x87, 0x67, 0xc6, 0x40, 0xaf, 0xa2, 0x5d, 0xd8, 0x3e,
-	0x3d, 0x3b, 0x23, 0x11, 0x25, 0x32, 0xb6, 0xc6, 0xd9, 0x3b, 0xbd, 0x1e, 0x36, 0x46, 0x23, 0x72,
-	0x6a, 0x8e, 0x4e, 0x3b, 0xe3, 0xee, 0x89, 0xbe, 0xc9, 0x4d, 0x1a, 0x19, 0x63, 0x32, 0x1e, 0x8e,
-	0x3b, 0xfd, 0x15, 0xae, 0x73, 0x85, 0x56, 0x38, 0xdf, 0xb4, 0x3f, 0xfc, 0x46, 0xdf, 0xe2, 0x07,
-	0xce, 0xe1, 0xe1, 0x0b, 0xa5, 0x22, 0xe2, 0xb6, 0x2b, 0xf7, 0x44, 0x7b, 0xea, 0xdb, 0x1c, 0x34,
-	0x07, 0x2f, 0x3a, 0x7d, 0xb3, 0x47, 0x9e, 0x1b, 0xdf, 0x89, 0x66, 0xbe, 0xc3, 0x41, 0xa9, 0x19,
-	0x39, 0xc3, 0xc3, 0xa7, 0x5c, 0x11, 0xfd, 0x6d, 0x84, 0xa0, 0xd6, 0x35, 0x71, 0xf7, 0xbc, 0xdf,
-	0xc1, 0x04, 0x0f, 0xcf, 0xc7, 0x86, 0x7e, 0xef, 0xf1, 0x1f, 0x35, 0xa8, 0x24, 0x8b, 0x35, 0xf7,
-	0xba, 0x39, 0x20, 0xc7, 0x7d, 0xf3, 0xe9, 0xc9, 0x58, 0x06, 0xc1, 0xe8, 0xbc, 0xcb, 0x5d, 0x66,
-	0xf0, 0x21, 0x01, 0x41, 0x4d, 0x1e, 0x7a, 0x6c, 0x6c, 0x86, 0xef, 0xa5, 0xb0, 0xc1, 0x50, 0xc9,
-	0xcd, 0x72, 0xe5, 0x15, 0x68, 0x60, 0x3c, 0xc4, 0x7a, 0x0e, 0x7d, 0x00, 0x4d, 0x85, 0x70, 0xbf,
-	0x62, 0x6c, 0x74, 0xc7, 0xe4, 0xac, 0xf3, 0xdd, 0x29, 0x77, 0xbb, 0x0c, 0xb2, 0x91, 0x9e, 0x47,
-	0xef, 0xc2, 0x5e, 0xcc, 0xb5, 0x2e, 0x2e, 0x1e, 0x7f, 0x0e, 0xf5, 0xbb, 0x82, 0x1e, 0x01, 0x14,
-	0x46, 0xc6, 0x78, 0xdc, 0x37, 0xe4, 0x60, 0x73, 0x2c, 0x03, 0x17, 0xa0, 0x80, 0x8d, 0xd1, 0xf9,
-	0xa9, 0xa1, 0x67, 0x0e, 0xff, 0x5a, 0x84, 0x82, 0x98, 0xb4, 0x03, 0xf4, 0x15, 0x54, 0x13, 0x8f,
-	0x4d, 0x2f, 0x0e, 0xd1, 0x83, 0xd7, 0x3e, 0x43, 0x35, 0xa2, 0x2b, 0xbb, 0x82, 0x0f, 0x34, 0x74,
-	0x04, 0xb5, 0xe4, 0xab, 0xcb, 0x8b, 0x43, 0x94, 0x1c, 0x50, 0xd7, 0x3c, 0xc8, 0xac, 0x91, 0xf1,
-	0x1c, 0x74, 0x23, 0x64, 0xce, 0x9c, 0xf7, 0x49, 0xf5, 0x2e, 0x82, 0x1a, 0xc9, 0x04, 0x4f, 0x3f,
-	0xb6, 0x34, 0xf6, 0xd6, 0xd2, 0x54, 0xc9, 0xf9, 0x9a, 0xcf, 0x24, 0xf1, 0xcb, 0xc4, 0x2d, 0x83,
-	0xd2, 0xcf, 0x21, 0x8d, 0x77, 0xee, 0x22, 0xab, 0xd7, 0x84, 0xec, 0xef, 0x32, 0xdc, 0xc6, 0x6a,
-	0x82, 0xb6, 0xe6, 0x94, 0x6e, 0x08, 0x5d, 0xd3, 0xb9, 0x91, 0x0d, 0xdb, 0x6b, 0x5e, 0x2d, 0xd0,
-	0x87, 0xe9, 0x3a, 0x76, 0xc7, 0x9b, 0x47, 0xe3, 0xe1, 0x9b, 0xd8, 0x94, 0xf1, 0x36, 0x6c, 0xaf,
-	0x79, 0xde, 0x48, 0xed, 0x72, 0xf7, 0xe3, 0x48, 0x6a, 0x97, 0xd7, 0xbd, 0x92, 0x7c, 0x0f, 0xfa,
-	0xcd, 0xdb, 0x30, 0x6a, 0xdd, 0x5c, 0x7b, 0xfb, 0x5a, 0xde, 0x78, 0xff, 0xb5, 0x3c, 0x4a, 0xb8,
-	0x09, 0xb0, 0xba, 0x30, 0xa2, 0xfb, 0x89, 0x25, 0xb7, 0xee, 0xc4, 0x8d, 0x07, 0x77, 0x50, 0x95,
-	0xa8, 0x31, 0x6c, 0xaf, 0xb9, 0x41, 0xa6, 0x4e, 0xe3, 0xee, 0x1b, 0x66, 0x63, 0x67, 0xdd, 0x45,
-	0xeb, 0x40, 0x43, 0xa7, 0x32, 0xc0, 0xa2, 0x17, 0xd4, 0x37, 0x64, 0x4c, 0x7d, 0xfd, 0x40, 0xb8,
-	0x0c, 0x45, 0x68, 0x1d, 0x68, 0x68, 0x08, 0x95, 0x64, 0x96, 0xbc, 0x31, 0x7d, 0xde, 0x28, 0x70,
-	0x0a, 0x9b, 0xa9, 0x66, 0xec, 0x07, 0xe8, 0xd1, 0x1b, 0x47, 0x0a, 0x79, 0x62, 0xa9, 0x08, 0x78,
-	0xcd, 0xec, 0xd1, 0xd6, 0x0e, 0xb4, 0xa3, 0x4f, 0x7e, 0xf9, 0xe4, 0xd2, 0x61, 0xb3, 0xe5, 0xc5,
-	0xfe, 0xc4, 0x9f, 0x3f, 0x11, 0x0f, 0xa4, 0x9e, 0xe3, 0x5d, 0x7a, 0x94, 0xbd, 0xf2, 0x83, 0xab,
-	0x27, 0xae, 0x67, 0x3f, 0x11, 0x69, 0xf0, 0x24, 0x16, 0x79, 0x51, 0x10, 0x7f, 0x42, 0xf9, 0xd1,
-	0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xbf, 0xfc, 0xb7, 0xb8, 0x72, 0x19, 0x00, 0x00,
+	// 2823 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x59, 0xcb, 0x7a, 0xdb, 0xc6,
+	0x15, 0x0e, 0x78, 0x13, 0x79, 0x78, 0x83, 0x46, 0xb2, 0xc5, 0x52, 0xbe, 0x30, 0x4c, 0x62, 0xb3,
+	0x6e, 0x22, 0x3b, 0x6a, 0xbf, 0x24, 0x6d, 0x2e, 0x0d, 0x45, 0x42, 0x16, 0x6c, 0x8a, 0x54, 0x86,
+	0x94, 0x13, 0x27, 0x8b, 0x29, 0x44, 0x0e, 0x45, 0x54, 0xb8, 0xb0, 0xc0, 0xd0, 0xb6, 0x76, 0xed,
+	0xae, 0x5f, 0x1f, 0xa0, 0xcf, 0xd0, 0x55, 0x9f, 0xa0, 0xdf, 0xd7, 0xae, 0xfb, 0x12, 0xdd, 0xf6,
+	0x09, 0xba, 0xee, 0x37, 0x83, 0x01, 0x08, 0x48, 0x94, 0xe4, 0x5e, 0x36, 0x36, 0xf1, 0x9f, 0x7f,
+	0xce, 0x9c, 0x99, 0x39, 0xb7, 0x19, 0xc1, 0x6d, 0xcf, 0x5d, 0x30, 0xea, 0x79, 0xf3, 0xf1, 0xe3,
+	0xe0, 0xd7, 0xce, 0xdc, 0x73, 0x99, 0x8b, 0x0a, 0x11, 0x5e, 0x2f, 0x78, 0xf3, 0x71, 0x80, 0x36,
+	0xff, 0xb8, 0x06, 0x68, 0x48, 0x9d, 0xc9, 0x91, 0x71, 0x6e, 0x53, 0x87, 0x61, 0xfa, 0x9b, 0x05,
+	0xf5, 0x19, 0x42, 0x90, 0x99, 0x50, 0x9f, 0xd5, 0x94, 0x86, 0xd2, 0x2a, 0x61, 0xf1, 0x1b, 0xa9,
+	0x90, 0x36, 0x6c, 0x56, 0x4b, 0x35, 0x94, 0x56, 0x1a, 0xf3, 0x9f, 0xe8, 0x47, 0x90, 0x37, 0x6c,
+	0x46, 0x6c, 0xdf, 0x60, 0xb5, 0x92, 0x80, 0xd7, 0x0c, 0x9b, 0x1d, 0xfa, 0x06, 0x43, 0xef, 0x42,
+	0x69, 0x1e, 0xa8, 0x24, 0x33, 0xc3, 0x9f, 0xd5, 0xd2, 0x42, 0x51, 0x51, 0x62, 0x07, 0x86, 0x3f,
+	0x43, 0x2d, 0x50, 0xa7, 0xa6, 0x63, 0x58, 0x64, 0x6c, 0xb1, 0x57, 0x64, 0x42, 0x2d, 0x66, 0xd4,
+	0x32, 0x0d, 0xa5, 0x95, 0xc5, 0x15, 0x81, 0x77, 0x2c, 0xf6, 0xaa, 0xcb, 0xd1, 0xb8, 0x32, 0x63,
+	0x32, 0xf1, 0x6a, 0x9b, 0x09, 0x65, 0xed, 0xc9, 0xc4, 0x43, 0x0f, 0xa1, 0x1a, 0x52, 0xbc, 0x60,
+	0x0d, 0xb5, 0x6c, 0x43, 0x69, 0x15, 0x70, 0x65, 0x9e, 0x5c, 0xd9, 0x43, 0xa8, 0x32, 0xd3, 0xa6,
+	0xee, 0x82, 0x11, 0x9f, 0x8e, 0x5d, 0x67, 0xe2, 0xd7, 0x72, 0xc1, 0xa4, 0x12, 0x1e, 0x06, 0x28,
+	0x6a, 0x42, 0x79, 0x4a, 0x29, 0xb1, 0x4c, 0xdb, 0x64, 0x84, 0xaf, 0x70, 0x4d, 0xac, 0xb0, 0x38,
+	0xa5, 0xb4, 0xc7, 0xb1, 0xa1, 0xc1, 0xd0, 0xfb, 0x50, 0x59, 0x72, 0xc4, 0x36, 0x94, 0x05, 0xa9,
+	0x14, 0x92, 0xc4, 0x5e, 0xec, 0x80, 0xea, 0x2e, 0xd8, 0xa9, 0x6b, 0x3a, 0xa7, 0x64, 0x3c, 0x33,
+	0x1c, 0x62, 0x4e, 0x6a, 0xf9, 0x86, 0xd2, 0xca, 0xec, 0x65, 0x6a, 0xca, 0x13, 0x05, 0x57, 0x42,
+	0x69, 0x67, 0x66, 0x38, 0xfa, 0x04, 0x3d, 0x82, 0xf5, 0x8b, 0x7c, 0xbf, 0xb6, 0xd1, 0x48, 0xb7,
+	0x32, 0xb8, 0x9a, 0xa4, 0xfa, 0xe8, 0x01, 0x54, 0x2d, 0xc3, 0x67, 0x64, 0xe6, 0xce, 0xc9, 0x7c,
+	0x71, 0x72, 0x46, 0xcf, 0x6b, 0x15, 0xb1, 0x3b, 0x65, 0x0e, 0x1f, 0xb8, 0xf3, 0x23, 0x01, 0xa2,
+	0xbb, 0x00, 0x62, 0x9b, 0x85, 0xa9, 0xb5, 0x82, 0x58, 0x71, 0x81, 0x23, 0xc2, 0x4c, 0xf4, 0x31,
+	0x14, 0x85, 0x7b, 0x90, 0x99, 0xe9, 0x30, 0xbf, 0x06, 0x8d, 0x74, 0xab, 0xb8, 0xab, 0xee, 0x58,
+	0x0e, 0xf7, 0x14, 0xcc, 0x25, 0x07, 0xa6, 0xc3, 0x30, 0x78, 0xe1, 0x4f, 0x1f, 0x4d, 0x60, 0x83,
+	0xbb, 0x05, 0x19, 0x2f, 0x7c, 0xe6, 0xda, 0xc4, 0xa3, 0x63, 0xd7, 0x9b, 0xf8, 0xb5, 0xa2, 0x18,
+	0xfa, 0xb3, 0x9d, 0xc8, 0xdb, 0x76, 0x2e, 0xbb, 0xd7, 0x4e, 0x97, 0xfa, 0xac, 0x23, 0xc6, 0xe1,
+	0x60, 0x98, 0xe6, 0x30, 0xef, 0x1c, 0xaf, 0x4f, 0x2e, 0xe2, 0xe8, 0x43, 0x40, 0x86, 0x65, 0xb9,
+	0xaf, 0x89, 0x4f, 0xad, 0x29, 0x91, 0x67, 0x59, 0xab, 0x36, 0x94, 0x56, 0x1e, 0xab, 0x42, 0x32,
+	0xa4, 0xd6, 0x54, 0xaa, 0x47, 0x9f, 0x40, 0x59, 0xd8, 0x34, 0xa5, 0x06, 0x5b, 0x78, 0xd4, 0xaf,
+	0xa9, 0x8d, 0x74, 0xab, 0xb2, 0xbb, 0x2e, 0x17, 0xb2, 0x1f, 0xc0, 0x7b, 0x26, 0xc3, 0x25, 0xce,
+	0x93, 0xdf, 0x3e, 0xda, 0x86, 0x82, 0x6d, 0xbc, 0x21, 0x73, 0xc3, 0x63, 0x7e, 0x6d, 0xbd, 0xa1,
+	0xb4, 0xca, 0x38, 0x6f, 0x1b, 0x6f, 0x8e, 0xf8, 0x37, 0xda, 0x81, 0x0d, 0xc7, 0x25, 0xa6, 0x33,
+	0xb5, 0xcc, 0xd3, 0x19, 0x23, 0x8b, 0xf9, 0xc4, 0x60, 0xd4, 0xaf, 0x21, 0x61, 0xc3, 0xba, 0xe3,
+	0xea, 0x52, 0x72, 0x1c, 0x08, 0xea, 0x5d, 0xb8, 0xbd, 0x7a, 0x7d, 0x3c, 0x82, 0xf8, 0x01, 0xf1,
+	0xa0, 0xca, 0x60, 0xfe, 0x13, 0x6d, 0x42, 0xf6, 0x95, 0x61, 0x2d, 0xa8, 0x88, 0xaa, 0x12, 0x0e,
+	0x3e, 0x7e, 0x91, 0xfa, 0x4c, 0x69, 0xce, 0x60, 0x63, 0xe4, 0x19, 0xe3, 0xb3, 0x0b, 0x81, 0x79,
+	0x31, 0xae, 0x94, 0xcb, 0x71, 0x75, 0x85, 0xbd, 0xa9, 0x2b, 0xec, 0x6d, 0x7e, 0x05, 0x55, 0x71,
+	0xc2, 0xfb, 0x94, 0x5e, 0x17, 0xfe, 0x5b, 0xc0, 0x83, 0x5b, 0x44, 0x42, 0x90, 0x02, 0x72, 0x86,
+	0xcd, 0x83, 0xa0, 0x39, 0x01, 0x75, 0x39, 0xde, 0x9f, 0xbb, 0x8e, 0x4f, 0x79, 0x6c, 0x73, 0x07,
+	0xe0, 0x1e, 0xcc, 0x03, 0x44, 0x84, 0x86, 0x22, 0x46, 0x55, 0x24, 0xbe, 0x4f, 0xa9, 0x08, 0x8e,
+	0x07, 0x41, 0x3c, 0x12, 0xcb, 0x1d, 0x9f, 0xf1, 0x24, 0x60, 0x9c, 0x4b, 0xf5, 0x65, 0x0e, 0xf7,
+	0xdc, 0xf1, 0x59, 0x97, 0x83, 0xcd, 0x1f, 0x82, 0x3c, 0x35, 0x72, 0xc5, 0x5c, 0xff, 0xc1, 0x76,
+	0x34, 0x21, 0x2b, 0x7c, 0x51, 0xa8, 0x2d, 0xee, 0x96, 0xe2, 0x4e, 0x8d, 0x03, 0x51, 0xf3, 0x07,
+	0xd8, 0x48, 0x28, 0x97, 0xab, 0xa8, 0x43, 0x7e, 0xee, 0x51, 0xd3, 0x36, 0x4e, 0xa9, 0xd4, 0x1c,
+	0x7d, 0xa3, 0x16, 0xac, 0x4d, 0x0d, 0xd3, 0x5a, 0x78, 0xa1, 0xe2, 0x4a, 0xe8, 0x64, 0x01, 0x8a,
+	0x43, 0x71, 0xf3, 0x0e, 0xd4, 0x31, 0xf5, 0x29, 0x3b, 0x34, 0x7d, 0xdf, 0x74, 0x9d, 0x8e, 0xeb,
+	0x30, 0xcf, 0xb5, 0xe4, 0x0a, 0x9a, 0x77, 0x61, 0x7b, 0xa5, 0x34, 0x30, 0x81, 0x0f, 0xfe, 0x66,
+	0x41, 0xbd, 0xf3, 0xd5, 0x83, 0xbf, 0x81, 0xed, 0x95, 0x52, 0x69, 0xff, 0x87, 0x90, 0x9d, 0x1b,
+	0xa6, 0xc7, 0xcf, 0x9e, 0x07, 0xe5, 0xed, 0x58, 0x50, 0x1e, 0x19, 0xa6, 0x77, 0x60, 0xfa, 0xcc,
+	0xf5, 0xce, 0x71, 0x40, 0x7a, 0x96, 0xc9, 0x2b, 0x6a, 0xaa, 0xf9, 0x07, 0x05, 0x8a, 0x31, 0x21,
+	0x0f, 0x0d, 0xc7, 0x9d, 0x50, 0x32, 0xf5, 0x5c, 0x3b, 0xdc, 0x04, 0x0e, 0xec, 0x7b, 0xae, 0xcd,
+	0x7d, 0x42, 0x08, 0x99, 0x2b, 0x1d, 0x38, 0xc7, 0x3f, 0x47, 0x2e, 0xfa, 0x08, 0xd6, 0x66, 0x81,
+	0x02, 0x91, 0x36, 0x8b, 0xbb, 0x1b, 0x17, 0xe6, 0xee, 0x1a, 0xcc, 0xc0, 0x21, 0xe7, 0x59, 0x26,
+	0x9f, 0x56, 0x33, 0xcf, 0x32, 0xf9, 0x8c, 0x9a, 0x7d, 0x96, 0xc9, 0x67, 0xd5, 0xdc, 0xb3, 0x4c,
+	0x3e, 0xa7, 0xae, 0x35, 0xff, 0xa9, 0x40, 0x3e, 0x64, 0x73, 0x4b, 0xf8, 0x96, 0x12, 0xee, 0x17,
+	0xd2, 0x99, 0xf2, 0x1c, 0x18, 0x99, 0x36, 0x45, 0x0d, 0x28, 0x09, 0x61, 0xd2, 0x45, 0x81, 0x63,
+	0x6d, 0xe1, 0xa6, 0x22, 0x9f, 0x87, 0x0c, 0xe1, 0x8f, 0x19, 0x99, 0xcf, 0x03, 0x4a, 0x58, 0xb5,
+	0xfc, 0xc5, 0x78, 0x4c, 0x7d, 0x3f, 0x98, 0x25, 0x1b, 0x50, 0x24, 0x26, 0x26, 0x7a, 0x00, 0xd5,
+	0x90, 0x12, 0xce, 0x95, 0x0b, 0xfc, 0x55, 0xc2, 0x72, 0xba, 0x16, 0xa8, 0x71, 0x9e, 0xbd, 0xac,
+	0x20, 0x95, 0x25, 0x91, 0x4f, 0x1a, 0x2c, 0xbe, 0xd9, 0x80, 0x7b, 0x4f, 0x2f, 0x7a, 0x41, 0xc7,
+	0x75, 0xa6, 0xe6, 0x69, 0x78, 0xd8, 0xdf, 0xc3, 0xfd, 0x2b, 0x19, 0xf2, 0xc0, 0x3f, 0x85, 0xdc,
+	0x58, 0x20, 0x62, 0x7f, 0x8a, 0xbb, 0xf7, 0x63, 0xbb, 0xbe, 0x72, 0xa0, 0xa4, 0x37, 0x5f, 0xc2,
+	0xbd, 0xe1, 0xb5, 0xb3, 0xff, 0xf7, 0xaa, 0xdf, 0x85, 0xfb, 0xc3, 0xeb, 0xcd, 0x6e, 0xfe, 0x36,
+	0x05, 0x9b, 0xab, 0x08, 0xbc, 0x12, 0xce, 0x0c, 0x6b, 0x4a, 0x2c, 0x73, 0x4a, 0xa3, 0x72, 0x1d,
+	0xa4, 0xcf, 0x2a, 0x17, 0xf4, 0xcc, 0x29, 0x0d, 0xeb, 0xf5, 0x43, 0xa8, 0x8a, 0x22, 0xe8, 0xb9,
+	0x27, 0xc6, 0x89, 0x69, 0x99, 0x2c, 0x48, 0x24, 0x29, 0x5c, 0x99, 0xb9, 0xf3, 0xa3, 0x25, 0x8a,
+	0x6e, 0x43, 0xee, 0x35, 0xe5, 0x09, 0x50, 0x34, 0x25, 0x29, 0x2c, 0xbf, 0xd0, 0x27, 0xb0, 0x65,
+	0x1b, 0x6f, 0x4c, 0x7b, 0x61, 0x93, 0x65, 0x2b, 0xe1, 0x2f, 0x2c, 0xe6, 0x0b, 0x57, 0x29, 0xe3,
+	0x5b, 0x52, 0x1c, 0xa5, 0x64, 0x21, 0x44, 0x1d, 0xb8, 0x67, 0x9b, 0x8e, 0x18, 0x27, 0x43, 0x9e,
+	0x78, 0xd4, 0x32, 0xde, 0x10, 0xd3, 0x61, 0xd4, 0x7b, 0x65, 0x58, 0xc2, 0x8d, 0x32, 0x78, 0x5b,
+	0xb2, 0xc2, 0x04, 0xc1, 0x39, 0xba, 0xa4, 0x34, 0x7f, 0x0d, 0x5b, 0x22, 0x92, 0x63, 0x86, 0x86,
+	0x3b, 0xcf, 0xfd, 0xde, 0x73, 0x6d, 0xc2, 0x43, 0x2b, 0x8c, 0x40, 0x0e, 0xf4, 0xdd, 0x09, 0xe5,
+	0x11, 0xc8, 0xdc, 0x40, 0x24, 0x23, 0x90, 0xb9, 0x42, 0x10, 0xef, 0xcd, 0xd2, 0x89, 0xde, 0xac,
+	0x79, 0x06, 0xb5, 0xcb, 0x73, 0x49, 0x0f, 0x6a, 0x40, 0x31, 0xbe, 0x83, 0x7c, 0x3a, 0x05, 0xc7,
+	0xa1, 0x78, 0x68, 0xa7, 0x6e, 0x0e, 0xed, 0xe6, 0xdf, 0x15, 0x58, 0xdf, 0x5b, 0x98, 0xd6, 0x24,
+	0x91, 0xb7, 0xe3, 0xd6, 0x29, 0xc9, 0xce, 0x71, 0x55, 0x5b, 0x98, 0x5a, 0xd9, 0x16, 0x7e, 0xb8,
+	0xa2, 0xaf, 0x4a, 0x8b, 0xbe, 0x2a, 0xb5, 0xa2, 0xab, 0xba, 0x0f, 0xc5, 0x65, 0x93, 0xc4, 0x8f,
+	0x34, 0xdd, 0x2a, 0x61, 0x98, 0x85, 0x1d, 0x92, 0x7f, 0xa9, 0xcb, 0xcc, 0x5e, 0xea, 0x32, 0x9b,
+	0x9f, 0x01, 0x8a, 0xaf, 0x45, 0xee, 0x59, 0x54, 0x61, 0x94, 0xab, 0x2b, 0xcc, 0x1d, 0xa8, 0x0f,
+	0x17, 0x27, 0xfe, 0xd8, 0x33, 0x4f, 0xe8, 0x01, 0xb3, 0xc6, 0xda, 0x2b, 0xea, 0x30, 0x3f, 0x0c,
+	0xed, 0x7f, 0x65, 0xa0, 0x10, 0xa1, 0xbc, 0x80, 0x9b, 0xce, 0xd8, 0xb5, 0xc3, 0x75, 0x39, 0xd4,
+	0xe2, 0x4b, 0x0b, 0xfc, 0x7e, 0x3d, 0x14, 0x75, 0x02, 0x89, 0x3e, 0xe1, 0xfc, 0xc4, 0x3e, 0x48,
+	0x7e, 0x2a, 0xe0, 0xc7, 0xb7, 0x21, 0xe0, 0xb7, 0x40, 0x8d, 0xf4, 0xcf, 0x98, 0x35, 0x8e, 0xf6,
+	0x0d, 0x57, 0x42, 0x9c, 0x1b, 0x13, 0x30, 0x23, 0xcd, 0x21, 0x33, 0x13, 0x30, 0x43, 0x5c, 0x32,
+	0xdf, 0x85, 0x12, 0xcf, 0x98, 0x3e, 0x33, 0xec, 0x39, 0x71, 0x7c, 0xe9, 0xf2, 0xc5, 0x08, 0xeb,
+	0xfb, 0xe8, 0x4b, 0x00, 0xca, 0xd7, 0x47, 0xd8, 0xf9, 0x9c, 0x8a, 0xa4, 0x59, 0xd9, 0xbd, 0x17,
+	0xf3, 0x9d, 0x68, 0x03, 0x76, 0xc4, 0xbf, 0xa3, 0xf3, 0x39, 0xc5, 0x05, 0x1a, 0xfe, 0x44, 0x5f,
+	0x41, 0x79, 0xea, 0x7a, 0xaf, 0x0d, 0x6f, 0x42, 0x04, 0x28, 0x0b, 0xcb, 0x56, 0x4c, 0xc3, 0x7e,
+	0x20, 0x17, 0xc3, 0x0f, 0xde, 0xc1, 0xa5, 0x69, 0xec, 0x1b, 0x3d, 0x07, 0x14, 0x8e, 0x17, 0x75,
+	0x20, 0x50, 0x92, 0x17, 0x4a, 0xb6, 0x2f, 0x2b, 0xe1, 0x51, 0x1a, 0x2a, 0x52, 0xa7, 0x17, 0x30,
+	0xf4, 0x39, 0x94, 0x7c, 0xca, 0x98, 0x45, 0xa5, 0x9a, 0x82, 0x50, 0x73, 0x3b, 0xd1, 0xf5, 0x72,
+	0x71, 0xa8, 0xa1, 0xe8, 0x2f, 0x3f, 0xd1, 0x1e, 0x54, 0x2d, 0xd3, 0x39, 0x8b, 0x9b, 0x01, 0x62,
+	0x7c, 0x2d, 0x36, 0xbe, 0x67, 0x3a, 0x67, 0x71, 0x1b, 0xca, 0x56, 0x1c, 0x68, 0x7e, 0x01, 0x85,
+	0x68, 0x97, 0x50, 0x11, 0xd6, 0x8e, 0xfb, 0xcf, 0xfb, 0x83, 0x6f, 0xfb, 0xea, 0x3b, 0x28, 0x0f,
+	0x99, 0xa1, 0xd6, 0xef, 0xaa, 0x0a, 0x87, 0xb1, 0xd6, 0xd1, 0xf4, 0x17, 0x9a, 0x9a, 0xe2, 0x1f,
+	0xfb, 0x03, 0xfc, 0x6d, 0x1b, 0x77, 0xd5, 0xf4, 0xde, 0x1a, 0x64, 0xc5, 0xbc, 0xcd, 0xbf, 0x28,
+	0x90, 0x17, 0x27, 0xe8, 0x4c, 0x5d, 0xf4, 0x13, 0x88, 0x9c, 0x4b, 0x94, 0x3f, 0xde, 0x92, 0x09,
+	0xaf, 0x2b, 0xe3, 0xc8, 0x61, 0x46, 0x12, 0xe7, 0xe4, 0xc8, 0x35, 0x22, 0x72, 0x2a, 0x20, 0x87,
+	0x82, 0x88, 0xfc, 0x28, 0xa6, 0x39, 0x91, 0x95, 0x32, 0xb8, 0x1a, 0x0a, 0xc2, 0x1a, 0x1c, 0xbf,
+	0xfd, 0x24, 0x6a, 0x75, 0xec, 0xf6, 0x23, 0xb9, 0xcd, 0x4f, 0xa1, 0x14, 0x3f, 0x73, 0xf4, 0x10,
+	0x32, 0xa6, 0x33, 0x75, 0x65, 0x20, 0x6e, 0x5c, 0x70, 0x2e, 0xbe, 0x48, 0x2c, 0x08, 0x4d, 0x04,
+	0xea, 0xc5, 0x73, 0x6e, 0x96, 0xa1, 0x18, 0x3b, 0xb4, 0xe6, 0x3f, 0x14, 0x28, 0x27, 0x0e, 0xe1,
+	0xad, 0xb5, 0xa3, 0x2f, 0xa1, 0xf4, 0xda, 0xf4, 0x28, 0x89, 0x37, 0x88, 0x95, 0xdd, 0x7a, 0xb2,
+	0x41, 0x0c, 0xff, 0xef, 0xb8, 0x13, 0x8a, 0x8b, 0x9c, 0x2f, 0x01, 0xf4, 0x4b, 0xa8, 0x84, 0x85,
+	0x64, 0x42, 0x99, 0x61, 0x5a, 0x62, 0xab, 0x2a, 0x09, 0xf7, 0x90, 0xdc, 0xae, 0x90, 0xe3, 0xf2,
+	0x34, 0xfe, 0x89, 0x3e, 0x58, 0x2a, 0xf0, 0x99, 0x67, 0x3a, 0xa7, 0x62, 0xff, 0x0a, 0x11, 0x6d,
+	0x28, 0x40, 0xde, 0xea, 0x95, 0x65, 0x2d, 0x1b, 0x32, 0x83, 0x2d, 0x7c, 0xf4, 0x11, 0x64, 0x7d,
+	0x66, 0xc8, 0x4c, 0x56, 0x49, 0xc4, 0x56, 0x8c, 0x48, 0x71, 0xc0, 0x4a, 0xf4, 0xc7, 0xa9, 0x4b,
+	0xfd, 0x71, 0x96, 0x67, 0x8c, 0x20, 0xd1, 0x16, 0x77, 0x91, 0x5c, 0xfc, 0xc1, 0xa8, 0xd7, 0x69,
+	0x33, 0x46, 0xed, 0x39, 0xc3, 0x01, 0x41, 0xf6, 0x3f, 0x5f, 0x01, 0x74, 0x4c, 0x6f, 0xbc, 0x30,
+	0xd9, 0x73, 0x7a, 0xce, 0xcb, 0x5a, 0x98, 0xd1, 0x83, 0xb4, 0x97, 0x1b, 0x07, 0x59, 0x7c, 0x0b,
+	0xd6, 0xc2, 0x44, 0x14, 0xe4, 0xb7, 0xdc, 0x4c, 0x24, 0xa0, 0xe6, 0x5f, 0x33, 0xb0, 0x2d, 0x8f,
+	0x34, 0x38, 0x0d, 0x46, 0xbd, 0x31, 0x9d, 0x47, 0x17, 0xa7, 0xa7, 0xb0, 0xb9, 0x4c, 0xaa, 0xc1,
+	0x44, 0x24, 0xbc, 0x8c, 0x15, 0x77, 0x6f, 0xc5, 0x56, 0xba, 0x34, 0x03, 0xa3, 0x28, 0xd9, 0x2e,
+	0x4d, 0x7b, 0x12, 0x53, 0x64, 0xd8, 0xee, 0xc2, 0x91, 0x2e, 0x1a, 0x64, 0x3c, 0xb4, 0x74, 0x67,
+	0x2e, 0x12, 0x1e, 0xfd, 0x10, 0x22, 0x27, 0x27, 0xf4, 0xcd, 0xdc, 0xf4, 0xce, 0x45, 0xf6, 0x2b,
+	0x2f, 0xd3, 0xad, 0x26, 0xd0, 0x4b, 0xb7, 0x99, 0xd4, 0xe5, 0xdb, 0xcc, 0xe7, 0x50, 0x8f, 0xa2,
+	0x43, 0x3e, 0x74, 0xd0, 0x49, 0x54, 0xfd, 0xd6, 0x84, 0x0d, 0x5b, 0x21, 0x03, 0x87, 0x04, 0x59,
+	0x02, 0x9f, 0xc0, 0x66, 0x2c, 0xb4, 0x96, 0xa6, 0x07, 0x91, 0x88, 0x96, 0xd1, 0x15, 0x37, 0x3d,
+	0x1a, 0x21, 0x4d, 0x0f, 0x7a, 0xa1, 0x28, 0xff, 0x4b, 0xd3, 0x7f, 0x05, 0x95, 0x0b, 0x0f, 0x01,
+	0x79, 0x71, 0xee, 0x3f, 0xbf, 0x9c, 0x59, 0x57, 0x1d, 0xcf, 0xce, 0x8a, 0xd7, 0x80, 0xf2, 0x38,
+	0xf1, 0x12, 0x70, 0x17, 0xc0, 0x75, 0x4c, 0xd7, 0x21, 0x27, 0x96, 0x7b, 0x22, 0x12, 0x6e, 0x09,
+	0x17, 0x04, 0xb2, 0x67, 0xb9, 0x27, 0xf5, 0xaf, 0x01, 0xfd, 0x8f, 0x37, 0xee, 0xbf, 0x29, 0x70,
+	0x67, 0xb5, 0x89, 0xb2, 0xce, 0xff, 0xdf, 0x5c, 0xe8, 0x73, 0xc8, 0x19, 0x63, 0x66, 0xba, 0x8e,
+	0xcc, 0x0c, 0xef, 0xc5, 0x86, 0x62, 0xea, 0xbb, 0xd6, 0x2b, 0x7a, 0xe0, 0x5a, 0x13, 0x69, 0x4c,
+	0x5b, 0x50, 0xb1, 0x1c, 0x92, 0x08, 0xba, 0x74, 0x32, 0xe8, 0x1e, 0xfd, 0x2e, 0x03, 0xe5, 0x44,
+	0x66, 0x48, 0x96, 0x86, 0x32, 0x14, 0xfa, 0x03, 0xd2, 0xd5, 0x46, 0x6d, 0xbd, 0xa7, 0x2a, 0x48,
+	0x85, 0xd2, 0xa0, 0xaf, 0x0f, 0xfa, 0xa4, 0xab, 0x75, 0x06, 0x5d, 0x5e, 0x24, 0x6e, 0xc1, 0x7a,
+	0x4f, 0xef, 0x3f, 0x27, 0xfd, 0xc1, 0x88, 0x68, 0x3d, 0xfd, 0xa9, 0xbe, 0xd7, 0xd3, 0xd4, 0x34,
+	0xda, 0x04, 0x75, 0xd0, 0x27, 0x9d, 0x83, 0xb6, 0xde, 0x27, 0x23, 0xfd, 0x50, 0x1b, 0x1c, 0x8f,
+	0xd4, 0x0c, 0x47, 0x79, 0x34, 0x13, 0xed, 0xbb, 0x8e, 0xa6, 0x75, 0x87, 0xe4, 0xb0, 0xfd, 0x9d,
+	0x9a, 0x45, 0x35, 0xd8, 0xd4, 0xfb, 0xc3, 0xe3, 0xfd, 0x7d, 0xbd, 0xa3, 0x6b, 0xfd, 0x11, 0xd9,
+	0x6b, 0xf7, 0xda, 0xfd, 0x8e, 0xa6, 0xe6, 0xd0, 0x6d, 0x40, 0x7a, 0xbf, 0x33, 0x38, 0x3c, 0xea,
+	0x69, 0x23, 0x8d, 0x84, 0xc5, 0x68, 0x0d, 0x6d, 0x40, 0x55, 0xe8, 0x69, 0x77, 0xbb, 0x64, 0xbf,
+	0xad, 0xf7, 0xb4, 0xae, 0x9a, 0xe7, 0x96, 0x48, 0xc6, 0x90, 0x74, 0xf5, 0x61, 0x7b, 0x8f, 0xc3,
+	0x05, 0x3e, 0xa7, 0xde, 0x7f, 0x31, 0xd0, 0x3b, 0x1a, 0xe9, 0x70, 0xb5, 0x1c, 0x05, 0x4e, 0x0e,
+	0xd1, 0xe3, 0x7e, 0x57, 0xc3, 0x47, 0x6d, 0xbd, 0xab, 0x16, 0xd1, 0x36, 0x6c, 0x85, 0xb0, 0xf6,
+	0xdd, 0x91, 0x8e, 0x5f, 0x92, 0xd1, 0x60, 0x40, 0x86, 0x83, 0x41, 0x5f, 0x2d, 0xc5, 0x35, 0xf1,
+	0xd5, 0x0e, 0x8e, 0xb4, 0xbe, 0x5a, 0x46, 0x5b, 0xb0, 0x71, 0x78, 0x74, 0x44, 0x42, 0x49, 0xb8,
+	0xd8, 0x0a, 0xa7, 0xb7, 0xbb, 0x5d, 0xac, 0x0d, 0x87, 0xe4, 0x50, 0x1f, 0x1e, 0xb6, 0x47, 0x9d,
+	0x03, 0xb5, 0xca, 0x97, 0x34, 0xd4, 0x46, 0x64, 0x34, 0x18, 0xb5, 0x7b, 0x4b, 0x5c, 0xe5, 0x06,
+	0x2d, 0x71, 0x3e, 0x69, 0x6f, 0xf0, 0xad, 0xba, 0xce, 0x37, 0x9c, 0xc3, 0x83, 0x17, 0xd2, 0x44,
+	0xc4, 0xd7, 0x2e, 0x8f, 0x27, 0x9c, 0x53, 0xdd, 0xe0, 0xa0, 0xde, 0x7f, 0xd1, 0xee, 0xe9, 0x5d,
+	0xf2, 0x5c, 0x7b, 0x29, 0x8a, 0xf9, 0x26, 0x07, 0x03, 0xcb, 0xc8, 0x11, 0x1e, 0x3c, 0xe5, 0x86,
+	0xa8, 0xb7, 0x10, 0x82, 0x4a, 0x47, 0xc7, 0x9d, 0xe3, 0x5e, 0x1b, 0x13, 0x3c, 0x38, 0x1e, 0x69,
+	0xea, 0xed, 0x47, 0x7f, 0x56, 0xa0, 0x14, 0x4f, 0xd6, 0xfc, 0xd4, 0xf5, 0x3e, 0xd9, 0xef, 0xe9,
+	0x4f, 0x0f, 0x46, 0x81, 0x13, 0x0c, 0x8f, 0x3b, 0xfc, 0xc8, 0x34, 0xde, 0x24, 0x20, 0xa8, 0x04,
+	0x9b, 0x1e, 0x2d, 0x36, 0xc5, 0xe7, 0x92, 0x58, 0x7f, 0x20, 0xf5, 0xa6, 0xb9, 0xf1, 0x12, 0xd4,
+	0x30, 0x1e, 0x60, 0x35, 0x83, 0xde, 0x87, 0x86, 0x44, 0xf8, 0xb9, 0x62, 0xac, 0x75, 0x46, 0xe4,
+	0xa8, 0xfd, 0xf2, 0x90, 0x1f, 0x7b, 0xe0, 0x64, 0x43, 0x35, 0x8b, 0xee, 0xc3, 0x76, 0xc4, 0x5a,
+	0xe5, 0x17, 0x8f, 0xbe, 0x80, 0xda, 0x55, 0x4e, 0x8f, 0x00, 0x72, 0x43, 0x6d, 0x34, 0xea, 0x69,
+	0x41, 0x63, 0xb3, 0x1f, 0x38, 0x2e, 0x40, 0x0e, 0x6b, 0xc3, 0xe3, 0x43, 0x4d, 0x4d, 0xed, 0xfe,
+	0x89, 0x7f, 0x88, 0xe8, 0x41, 0x5f, 0x43, 0x39, 0xf6, 0xd6, 0xf8, 0x62, 0x17, 0xdd, 0xbd, 0xf6,
+	0x15, 0xb2, 0x1e, 0xbe, 0xd8, 0x48, 0xf8, 0x89, 0x82, 0xf6, 0xa0, 0x12, 0x7f, 0x74, 0x7b, 0xb1,
+	0x8b, 0xe2, 0x0d, 0xea, 0x8a, 0xf7, 0xb8, 0x15, 0x3a, 0x9e, 0x83, 0xaa, 0xf9, 0xcc, 0xb4, 0x79,
+	0x9d, 0x94, 0xcf, 0x62, 0xa8, 0x1e, 0x0f, 0xf0, 0xe4, 0x5b, 0x5b, 0x7d, 0x7b, 0xa5, 0x4c, 0xa6,
+	0x9c, 0x6f, 0x78, 0x4f, 0x12, 0x3d, 0x4c, 0x5d, 0x5a, 0x50, 0xf2, 0x35, 0xac, 0x7e, 0xef, 0x2a,
+	0xb1, 0xbc, 0x67, 0xa7, 0x7f, 0x9f, 0xe2, 0x6b, 0x2c, 0xc7, 0x64, 0x2b, 0x76, 0xe9, 0x82, 0xd2,
+	0x15, 0x95, 0x1b, 0x4d, 0x60, 0x63, 0xc5, 0xa3, 0x15, 0xfa, 0x20, 0x99, 0xc7, 0xae, 0x78, 0xf2,
+	0xaa, 0x3f, 0xb8, 0x89, 0x26, 0x17, 0x3f, 0x81, 0x8d, 0x15, 0xaf, 0x5b, 0x89, 0x59, 0xae, 0x7e,
+	0x1b, 0x4b, 0xcc, 0x72, 0xdd, 0x23, 0xd9, 0x1c, 0xb6, 0xae, 0x78, 0x56, 0x41, 0x3f, 0x8e, 0xa9,
+	0xb8, 0xfe, 0x71, 0xa6, 0xfe, 0xe8, 0x6d, 0xa8, 0xcb, 0x19, 0x87, 0x6f, 0x31, 0xe3, 0xf0, 0xed,
+	0x67, 0xbc, 0xe1, 0x81, 0x05, 0xfd, 0x00, 0xea, 0xc5, 0x1b, 0x3f, 0x6a, 0x5e, 0xdc, 0x9f, 0xcb,
+	0x4f, 0x0f, 0xf5, 0xf7, 0xae, 0xe5, 0x48, 0xe5, 0x3a, 0xc0, 0xf2, 0x52, 0x8c, 0xee, 0xc4, 0x86,
+	0x5c, 0xba, 0xf7, 0xd7, 0xef, 0x5e, 0x21, 0x95, 0xaa, 0x46, 0xb0, 0xb1, 0xe2, 0x96, 0x9c, 0x38,
+	0xf1, 0xab, 0x6f, 0xd1, 0xf5, 0xcd, 0x55, 0x97, 0xc9, 0x27, 0x0a, 0x3a, 0x0c, 0x82, 0x28, 0xfc,
+	0x23, 0xc1, 0x0d, 0x59, 0xa1, 0xb6, 0xba, 0xe9, 0x5d, 0xf8, 0x22, 0x7c, 0x9e, 0x28, 0x68, 0x00,
+	0xa5, 0x78, 0x26, 0xb8, 0x31, 0x45, 0xdc, 0xa8, 0x70, 0x0a, 0xd5, 0x44, 0xc3, 0xe1, 0x7a, 0xe8,
+	0xe1, 0x8d, 0x6d, 0x53, 0xb0, 0x63, 0x09, 0x2f, 0xbf, 0xa6, 0xbf, 0x6a, 0x29, 0x4f, 0x94, 0xbd,
+	0x8f, 0xbf, 0x7f, 0x7c, 0x6a, 0xb2, 0xd9, 0xe2, 0x64, 0x67, 0xec, 0xda, 0x8f, 0xc5, 0xdf, 0x00,
+	0x1c, 0xd3, 0x39, 0x75, 0x28, 0x7b, 0xed, 0x7a, 0x67, 0x8f, 0x2d, 0x67, 0xf2, 0x58, 0x84, 0xfa,
+	0xe3, 0x48, 0xe5, 0x49, 0x4e, 0xfc, 0x95, 0xf0, 0xa7, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xff,
+	0x7e, 0x76, 0x2e, 0x55, 0x1c, 0x00, 0x00,
 }
 
 // Reference imports to suppress errors if they are not otherwise used.
@@ -2260,6 +2517,13 @@ type RouterClient interface {
 	//It is a development feature.
 	QueryMissionControl(ctx context.Context, in *QueryMissionControlRequest, opts ...grpc.CallOption) (*QueryMissionControlResponse, error)
 	//
+	//GetMissionControlConfig returns mission control's current config.
+	GetMissionControlConfig(ctx context.Context, in *GetMissionControlConfigRequest, opts ...grpc.CallOption) (*GetMissionControlConfigResponse, error)
+	//
+	//SetMissionControlConfig will set mission control's config, if the config
+	//provided is valid.
+	SetMissionControlConfig(ctx context.Context, in *SetMissionControlConfigRequest, opts ...grpc.CallOption) (*SetMissionControlConfigResponse, error)
+	//
 	//QueryProbability returns the current success probability estimate for a
 	//given node pair and amount.
 	QueryProbability(ctx context.Context, in *QueryProbabilityRequest, opts ...grpc.CallOption) (*QueryProbabilityResponse, error)
@@ -2408,6 +2672,24 @@ func (c *routerClient) QueryMissionControl(ctx context.Context, in *QueryMission
 	return out, nil
 }
 
+func (c *routerClient) GetMissionControlConfig(ctx context.Context, in *GetMissionControlConfigRequest, opts ...grpc.CallOption) (*GetMissionControlConfigResponse, error) {
+	out := new(GetMissionControlConfigResponse)
+	err := c.cc.Invoke(ctx, "/routerrpc.Router/GetMissionControlConfig", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *routerClient) SetMissionControlConfig(ctx context.Context, in *SetMissionControlConfigRequest, opts ...grpc.CallOption) (*SetMissionControlConfigResponse, error) {
+	out := new(SetMissionControlConfigResponse)
+	err := c.cc.Invoke(ctx, "/routerrpc.Router/SetMissionControlConfig", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 func (c *routerClient) QueryProbability(ctx context.Context, in *QueryProbabilityRequest, opts ...grpc.CallOption) (*QueryProbabilityResponse, error) {
 	out := new(QueryProbabilityResponse)
 	err := c.cc.Invoke(ctx, "/routerrpc.Router/QueryProbability", in, out, opts...)
@@ -2592,6 +2874,13 @@ type RouterServer interface {
 	//It is a development feature.
 	QueryMissionControl(context.Context, *QueryMissionControlRequest) (*QueryMissionControlResponse, error)
 	//
+	//GetMissionControlConfig returns mission control's current config.
+	GetMissionControlConfig(context.Context, *GetMissionControlConfigRequest) (*GetMissionControlConfigResponse, error)
+	//
+	//SetMissionControlConfig will set mission control's config, if the config
+	//provided is valid.
+	SetMissionControlConfig(context.Context, *SetMissionControlConfigRequest) (*SetMissionControlConfigResponse, error)
+	//
 	//QueryProbability returns the current success probability estimate for a
 	//given node pair and amount.
 	QueryProbability(context.Context, *QueryProbabilityRequest) (*QueryProbabilityResponse, error)
@@ -2647,6 +2936,12 @@ func (*UnimplementedRouterServer) ResetMissionControl(ctx context.Context, req *
 func (*UnimplementedRouterServer) QueryMissionControl(ctx context.Context, req *QueryMissionControlRequest) (*QueryMissionControlResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method QueryMissionControl not implemented")
 }
+func (*UnimplementedRouterServer) GetMissionControlConfig(ctx context.Context, req *GetMissionControlConfigRequest) (*GetMissionControlConfigResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetMissionControlConfig not implemented")
+}
+func (*UnimplementedRouterServer) SetMissionControlConfig(ctx context.Context, req *SetMissionControlConfigRequest) (*SetMissionControlConfigResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method SetMissionControlConfig not implemented")
+}
 func (*UnimplementedRouterServer) QueryProbability(ctx context.Context, req *QueryProbabilityRequest) (*QueryProbabilityResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method QueryProbability not implemented")
 }
@@ -2802,6 +3097,42 @@ func _Router_QueryMissionControl_Handler(srv interface{}, ctx context.Context, d
 	return interceptor(ctx, in, info, handler)
 }
 
+func _Router_GetMissionControlConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(GetMissionControlConfigRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(RouterServer).GetMissionControlConfig(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/routerrpc.Router/GetMissionControlConfig",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(RouterServer).GetMissionControlConfig(ctx, req.(*GetMissionControlConfigRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Router_SetMissionControlConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SetMissionControlConfigRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(RouterServer).SetMissionControlConfig(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/routerrpc.Router/SetMissionControlConfig",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(RouterServer).SetMissionControlConfig(ctx, req.(*SetMissionControlConfigRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 func _Router_QueryProbability_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(QueryProbabilityRequest)
 	if err := dec(in); err != nil {
@@ -2951,6 +3282,14 @@ var _Router_serviceDesc = grpc.ServiceDesc{
 			MethodName: "QueryMissionControl",
 			Handler:    _Router_QueryMissionControl_Handler,
 		},
+		{
+			MethodName: "GetMissionControlConfig",
+			Handler:    _Router_GetMissionControlConfig_Handler,
+		},
+		{
+			MethodName: "SetMissionControlConfig",
+			Handler:    _Router_SetMissionControlConfig_Handler,
+		},
 		{
 			MethodName: "QueryProbability",
 			Handler:    _Router_QueryProbability_Handler,
diff --git a/lnrpc/routerrpc/router.pb.gw.go b/lnrpc/routerrpc/router.pb.gw.go
index 233503119..80638c129 100644
--- a/lnrpc/routerrpc/router.pb.gw.go
+++ b/lnrpc/routerrpc/router.pb.gw.go
@@ -222,6 +222,24 @@ func local_request_Router_QueryMissionControl_0(ctx context.Context, marshaler r
 
 }
 
+func request_Router_GetMissionControlConfig_0(ctx context.Context, marshaler runtime.Marshaler, client RouterClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq GetMissionControlConfigRequest
+	var metadata runtime.ServerMetadata
+
+	msg, err := client.GetMissionControlConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func local_request_Router_GetMissionControlConfig_0(ctx context.Context, marshaler runtime.Marshaler, server RouterServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq GetMissionControlConfigRequest
+	var metadata runtime.ServerMetadata
+
+	msg, err := server.GetMissionControlConfig(ctx, &protoReq)
+	return msg, metadata, err
+
+}
+
 func request_Router_QueryProbability_0(ctx context.Context, marshaler runtime.Marshaler, client RouterClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
 	var protoReq QueryProbabilityRequest
 	var metadata runtime.ServerMetadata
@@ -470,6 +488,26 @@ func RegisterRouterHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser
 
 	})
 
+	mux.Handle("GET", pattern_Router_GetMissionControlConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := local_request_Router_GetMissionControlConfig_0(rctx, inboundMarshaler, server, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_Router_GetMissionControlConfig_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
 	mux.Handle("GET", pattern_Router_QueryProbability_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
@@ -678,6 +716,26 @@ func RegisterRouterHandlerClient(ctx context.Context, mux *runtime.ServeMux, cli
 
 	})
 
+	mux.Handle("GET", pattern_Router_GetMissionControlConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_Router_GetMissionControlConfig_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_Router_GetMissionControlConfig_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
 	mux.Handle("GET", pattern_Router_QueryProbability_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
@@ -754,6 +812,8 @@ var (
 
 	pattern_Router_QueryMissionControl_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v2", "router", "mc"}, "", runtime.AssumeColonVerbOpt(true)))
 
+	pattern_Router_GetMissionControlConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v2", "router", "mccfg"}, "", runtime.AssumeColonVerbOpt(true)))
+
 	pattern_Router_QueryProbability_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6}, []string{"v2", "router", "mc", "probability", "from_node", "to_node", "amt_msat"}, "", runtime.AssumeColonVerbOpt(true)))
 
 	pattern_Router_BuildRoute_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v2", "router", "route"}, "", runtime.AssumeColonVerbOpt(true)))
@@ -774,6 +834,8 @@ var (
 
 	forward_Router_QueryMissionControl_0 = runtime.ForwardResponseMessage
 
+	forward_Router_GetMissionControlConfig_0 = runtime.ForwardResponseMessage
+
 	forward_Router_QueryProbability_0 = runtime.ForwardResponseMessage
 
 	forward_Router_BuildRoute_0 = runtime.ForwardResponseMessage
diff --git a/lnrpc/routerrpc/router.proto b/lnrpc/routerrpc/router.proto
index 8aecab8b3..5a5830d0d 100644
--- a/lnrpc/routerrpc/router.proto
+++ b/lnrpc/routerrpc/router.proto
@@ -61,6 +61,19 @@ service Router {
     rpc QueryMissionControl (QueryMissionControlRequest)
         returns (QueryMissionControlResponse);
 
+    /*
+    GetMissionControlConfig returns mission control's current config.
+    */
+    rpc GetMissionControlConfig (GetMissionControlConfigRequest)
+        returns (GetMissionControlConfigResponse);
+
+    /*
+    SetMissionControlConfig will set mission control's config, if the config
+    provided is valid.
+    */
+    rpc SetMissionControlConfig (SetMissionControlConfigRequest)
+        returns (SetMissionControlConfigResponse);
+
     /*
     QueryProbability returns the current success probability estimate for a
     given node pair and amount.
@@ -354,6 +367,67 @@ message PairData {
     int64 success_amt_msat = 7;
 }
 
+message GetMissionControlConfigRequest {
+}
+
+message GetMissionControlConfigResponse {
+    /*
+    Mission control's currently active config.
+    */
+    MissionControlConfig config = 1;
+}
+
+message SetMissionControlConfigRequest {
+    /*
+    The config to set for mission control. Note that all values *must* be set,
+    because the full config will be applied.
+    */
+    MissionControlConfig config = 1;
+}
+
+message SetMissionControlConfigResponse {
+}
+
+message MissionControlConfig {
+    /*
+    The amount of time mission control will take to restore a penalized node
+    or channel back to 50% success probability, expressed as a unix timestamp
+    in seconds. Setting this value to a higher value will penalize failures for
+    longer, making mission control less likely to route through nodes and
+    channels that we have previously recorded failures for.
+    */
+    uint64 half_life_seconds = 1;
+
+    /*
+    The probability of success mission control should assign to hop in a route 
+    where it has no other information available. Higher values will make mission 
+    control more willing to try hops that we have no information about, lower 
+    values will discourage trying these hops.
+    */
+    float hop_probability = 2;
+
+    /*
+    The importance that mission control should place on historical results,
+    expressed as a value in [0;1]. Setting this value to 1 will ignore all
+    historical payments and just use the hop probability to assess the
+    probability of success for each hop. A zero value ignores hop probability
+    completely and relies entirely on historical results, unless none are
+    available.
+    */
+    float weight = 3;
+
+    /*
+    The maximum number of payment results that mission control will store.
+    */
+    uint32 maximum_payment_results = 4;
+
+    /*
+    The minimum time that must have passed since the previously recorded failure
+    before we raise the failure amount.
+    */
+    uint64 minimum_failure_relax_interval = 5;
+}
+
 message QueryProbabilityRequest {
     // The source node pubkey of the pair.
     bytes from_node = 1;
diff --git a/lnrpc/routerrpc/router.swagger.json b/lnrpc/routerrpc/router.swagger.json
index 0c630f19e..7702fe8ea 100644
--- a/lnrpc/routerrpc/router.swagger.json
+++ b/lnrpc/routerrpc/router.swagger.json
@@ -148,6 +148,29 @@
         ]
       }
     },
+    "/v2/router/mccfg": {
+      "get": {
+        "summary": "GetMissionControlConfig returns mission control's current config.",
+        "operationId": "GetMissionControlConfig",
+        "responses": {
+          "200": {
+            "description": "A successful response.",
+            "schema": {
+              "$ref": "#/definitions/routerrpcGetMissionControlConfigResponse"
+            }
+          },
+          "default": {
+            "description": "An unexpected error response",
+            "schema": {
+              "$ref": "#/definitions/runtimeError"
+            }
+          }
+        },
+        "tags": [
+          "Router"
+        ]
+      }
+    },
     "/v2/router/route": {
       "post": {
         "summary": "BuildRoute builds a fully specified route based on a list of hop public\nkeys. It retrieves the relevant channel policies from the graph in order to\ncalculate the correct fees and time locks.",
@@ -957,6 +980,15 @@
         }
       }
     },
+    "routerrpcGetMissionControlConfigResponse": {
+      "type": "object",
+      "properties": {
+        "config": {
+          "$ref": "#/definitions/routerrpcMissionControlConfig",
+          "description": "Mission control's currently active config."
+        }
+      }
+    },
     "routerrpcHtlcEvent": {
       "type": "object",
       "properties": {
@@ -1060,6 +1092,36 @@
         }
       }
     },
+    "routerrpcMissionControlConfig": {
+      "type": "object",
+      "properties": {
+        "half_life_seconds": {
+          "type": "string",
+          "format": "uint64",
+          "description": "The amount of time mission control will take to restore a penalized node\nor channel back to 50% success probability, expressed as a unix timestamp\nin seconds. Setting this value to a higher value will penalize failures for\nlonger, making mission control less likely to route through nodes and\nchannels that we have previously recorded failures for."
+        },
+        "hop_probability": {
+          "type": "number",
+          "format": "float",
+          "description": "The probability of success mission control should assign to hop in a route \nwhere it has no other information available. Higher values will make mission \ncontrol more willing to try hops that we have no information about, lower \nvalues will discourage trying these hops."
+        },
+        "weight": {
+          "type": "number",
+          "format": "float",
+          "description": "The importance that mission control should place on historical results,\nexpressed as a value in [0;1]. Setting this value to 1 will ignore all\nhistorical payments and just use the hop probability to assess the\nprobability of success for each hop. A zero value ignores hop probability\ncompletely and relies entirely on historical results, unless none are\navailable."
+        },
+        "maximum_payment_results": {
+          "type": "integer",
+          "format": "int64",
+          "description": "The maximum number of payment results that mission control will store."
+        },
+        "minimum_failure_relax_interval": {
+          "type": "string",
+          "format": "uint64",
+          "description": "The minimum time that must have passed since the previously recorded failure\nbefore we raise the failure amount."
+        }
+      }
+    },
     "routerrpcPairData": {
       "type": "object",
       "properties": {
@@ -1363,6 +1425,9 @@
         }
       }
     },
+    "routerrpcSetMissionControlConfigResponse": {
+      "type": "object"
+    },
     "routerrpcSettleEvent": {
       "type": "object"
     },
diff --git a/lnrpc/routerrpc/router_backend.go b/lnrpc/routerrpc/router_backend.go
index 74775fc5c..a569d41f3 100644
--- a/lnrpc/routerrpc/router_backend.go
+++ b/lnrpc/routerrpc/router_backend.go
@@ -95,6 +95,13 @@ type MissionControl interface {
 	// pair.
 	GetPairHistorySnapshot(fromNode,
 		toNode route.Vertex) routing.TimedPairResult
+
+	// GetConfig gets mission control's current config.
+	GetConfig() *routing.MissionControlConfig
+
+	// SetConfig sets mission control's config to the values provided, if
+	// they are valid.
+	SetConfig(cfg *routing.MissionControlConfig) error
 }
 
 // QueryRoutes attempts to query the daemons' Channel Router for a possible
diff --git a/lnrpc/routerrpc/router_server.go b/lnrpc/routerrpc/router_server.go
index 2aead9e0b..e3c0a2ae0 100644
--- a/lnrpc/routerrpc/router_server.go
+++ b/lnrpc/routerrpc/router_server.go
@@ -8,6 +8,7 @@ import (
 	"os"
 	"path/filepath"
 	"sync/atomic"
+	"time"
 
 	"github.com/btcsuite/btcutil"
 	"github.com/grpc-ecosystem/grpc-gateway/runtime"
@@ -79,6 +80,13 @@ var (
 			Entity: "offchain",
 			Action: "read",
 		}},
+		"/routerrpc.Router/GetMissionControlConfig": {{
+			Entity: "offchain",
+			Action: "read",
+		}}, "/routerrpc.Router/SetMissionControlConfig": {{
+			Entity: "offchain",
+			Action: "write",
+		}},
 		"/routerrpc.Router/QueryProbability": {{
 			Entity: "offchain",
 			Action: "read",
@@ -391,6 +399,46 @@ func (s *Server) ResetMissionControl(ctx context.Context,
 	return &ResetMissionControlResponse{}, nil
 }
 
+// GetMissionControlConfig returns our current mission control config.
+func (s *Server) GetMissionControlConfig(ctx context.Context,
+	req *GetMissionControlConfigRequest) (*GetMissionControlConfigResponse,
+	error) {
+
+	cfg := s.cfg.RouterBackend.MissionControl.GetConfig()
+	return &GetMissionControlConfigResponse{
+		Config: &MissionControlConfig{
+			HalfLifeSeconds:             uint64(cfg.PenaltyHalfLife.Seconds()),
+			HopProbability:              float32(cfg.AprioriHopProbability),
+			Weight:                      float32(cfg.AprioriWeight),
+			MaximumPaymentResults:       uint32(cfg.MaxMcHistory),
+			MinimumFailureRelaxInterval: uint64(cfg.MinFailureRelaxInterval.Seconds()),
+		},
+	}, nil
+}
+
+// SetMissionControlConfig returns our current mission control config.
+func (s *Server) SetMissionControlConfig(ctx context.Context,
+	req *SetMissionControlConfigRequest) (*SetMissionControlConfigResponse,
+	error) {
+
+	cfg := &routing.MissionControlConfig{
+		ProbabilityEstimatorCfg: routing.ProbabilityEstimatorCfg{
+			PenaltyHalfLife: time.Duration(
+				req.Config.HalfLifeSeconds,
+			) * time.Second,
+			AprioriHopProbability: float64(req.Config.HopProbability),
+			AprioriWeight:         float64(req.Config.Weight),
+		},
+		MaxMcHistory: int(req.Config.MaximumPaymentResults),
+		MinFailureRelaxInterval: time.Duration(
+			req.Config.MinimumFailureRelaxInterval,
+		) * time.Second,
+	}
+
+	return &SetMissionControlConfigResponse{},
+		s.cfg.RouterBackend.MissionControl.SetConfig(cfg)
+}
+
 // QueryMissionControl exposes the internal mission control state to callers. It
 // is a development feature.
 func (s *Server) QueryMissionControl(ctx context.Context,
diff --git a/routing/missioncontrol.go b/routing/missioncontrol.go
index f48f8f5f0..29d62dcc3 100644
--- a/routing/missioncontrol.go
+++ b/routing/missioncontrol.go
@@ -1,6 +1,8 @@
 package routing
 
 import (
+	"errors"
+	"fmt"
 	"sync"
 	"time"
 
@@ -57,6 +59,17 @@ const (
 	DefaultMinFailureRelaxInterval = time.Minute
 )
 
+var (
+	// ErrInvalidMcHistory is returned if we get a negative mission control
+	// history count.
+	ErrInvalidMcHistory = errors.New("mission control history must be " +
+		">= 0")
+
+	// ErrInvalidFailureInterval is returned if we get an invalid failure
+	// interval.
+	ErrInvalidFailureInterval = errors.New("failure interval must be >= 0")
+)
+
 // NodeResults contains previous results from a node to its peers.
 type NodeResults map[route.Vertex]TimedPairResult
 
@@ -78,7 +91,8 @@ type MissionControl struct {
 	// external function to enable deterministic unit tests.
 	now func() time.Time
 
-	cfg *MissionControlConfig
+	// selfNode is our pubkey.
+	selfNode route.Vertex
 
 	store *missionControlStore
 
@@ -97,34 +111,43 @@ type MissionControl struct {
 // MissionControlConfig defines parameters that control mission control
 // behaviour.
 type MissionControlConfig struct {
-	// PenaltyHalfLife defines after how much time a penalized node or
-	// channel is back at 50% probability.
-	PenaltyHalfLife time.Duration
-
-	// AprioriHopProbability is the assumed success probability of a hop in
-	// a route when no other information is available.
-	AprioriHopProbability float64
+	// ProbabilityEstimatorConfig is the config we will use for probability
+	// calculations.
+	ProbabilityEstimatorCfg
 
 	// MaxMcHistory defines the maximum number of payment results that are
 	// held on disk.
 	MaxMcHistory int
 
-	// AprioriWeight is a value in the range [0, 1] that defines to what
-	// extent historical results should be extrapolated to untried
-	// connections. Setting it to one will completely ignore historical
-	// results and always assume the configured a priori probability for
-	// untried connections. A value of zero will ignore the a priori
-	// probability completely and only base the probability on historical
-	// results, unless there are none available.
-	AprioriWeight float64
-
 	// MinFailureRelaxInterval is the minimum time that must have passed
 	// since the previously recorded failure before the failure amount may
 	// be raised.
 	MinFailureRelaxInterval time.Duration
+}
+
+func (c *MissionControlConfig) validate() error {
+	if err := c.ProbabilityEstimatorCfg.validate(); err != nil {
+		return err
+	}
+
+	if c.MaxMcHistory < 0 {
+		return ErrInvalidMcHistory
+	}
+
+	if c.MinFailureRelaxInterval < 0 {
+		return ErrInvalidFailureInterval
+	}
+
+	return nil
+}
 
-	// SelfNode is our own pubkey.
-	SelfNode route.Vertex
+// String returns a string representation of a mission control config.
+func (c *MissionControlConfig) String() string {
+	return fmt.Sprintf("Penalty Half Life: %v, Apriori Hop "+
+		"Probablity: %v, Maximum History: %v, Apriori Weight: %v, "+
+		"Minimum Failure Relax Interval: %v", c.PenaltyHalfLife,
+		c.AprioriHopProbability, c.MaxMcHistory, c.AprioriWeight,
+		c.MinFailureRelaxInterval)
 }
 
 // TimedPairResult describes a timestamped pair result.
@@ -177,13 +200,14 @@ type paymentResult struct {
 }
 
 // NewMissionControl returns a new instance of missionControl.
-func NewMissionControl(db kvdb.Backend, cfg *MissionControlConfig) (
-	*MissionControl, error) {
+func NewMissionControl(db kvdb.Backend, self route.Vertex,
+	cfg *MissionControlConfig) (*MissionControl, error) {
 
-	log.Debugf("Instantiating mission control with config: "+
-		"PenaltyHalfLife=%v, AprioriHopProbability=%v, "+
-		"AprioriWeight=%v", cfg.PenaltyHalfLife,
-		cfg.AprioriHopProbability, cfg.AprioriWeight)
+	log.Debugf("Instantiating mission control with config: %v", cfg)
+
+	if err := cfg.validate(); err != nil {
+		return nil, err
+	}
 
 	store, err := newMissionControlStore(db, cfg.MaxMcHistory)
 	if err != nil {
@@ -191,16 +215,14 @@ func NewMissionControl(db kvdb.Backend, cfg *MissionControlConfig) (
 	}
 
 	estimator := &probabilityEstimator{
-		aprioriHopProbability:  cfg.AprioriHopProbability,
-		aprioriWeight:          cfg.AprioriWeight,
-		penaltyHalfLife:        cfg.PenaltyHalfLife,
-		prevSuccessProbability: prevSuccessProbability,
+		ProbabilityEstimatorCfg: cfg.ProbabilityEstimatorCfg,
+		prevSuccessProbability:  prevSuccessProbability,
 	}
 
 	mc := &MissionControl{
 		state:     newMissionControlState(cfg.MinFailureRelaxInterval),
 		now:       time.Now,
-		cfg:       cfg,
+		selfNode:  self,
 		store:     store,
 		estimator: estimator,
 	}
@@ -216,6 +238,9 @@ func NewMissionControl(db kvdb.Backend, cfg *MissionControlConfig) (
 func (m *MissionControl) init() error {
 	log.Debugf("Mission control state reconstruction started")
 
+	m.Lock()
+	defer m.Unlock()
+
 	start := time.Now()
 
 	results, err := m.store.fetchAll()
@@ -233,6 +258,43 @@ func (m *MissionControl) init() error {
 	return nil
 }
 
+// GetConfig returns the config that mission control is currently configured
+// with. All fields are copied by value, so we do not need to worry about
+// mutation.
+func (m *MissionControl) GetConfig() *MissionControlConfig {
+	m.Lock()
+	defer m.Unlock()
+
+	return &MissionControlConfig{
+		ProbabilityEstimatorCfg: m.estimator.ProbabilityEstimatorCfg,
+		MaxMcHistory:            m.store.maxRecords,
+		MinFailureRelaxInterval: m.state.minFailureRelaxInterval,
+	}
+}
+
+// SetConfig validates the config provided and updates mission control's config
+// if it is valid.
+func (m *MissionControl) SetConfig(cfg *MissionControlConfig) error {
+	if cfg == nil {
+		return errors.New("nil mission control config")
+	}
+
+	if err := cfg.validate(); err != nil {
+		return err
+	}
+
+	m.Lock()
+	defer m.Unlock()
+
+	log.Infof("Updating mission control cfg: %v", cfg)
+
+	m.store.maxRecords = cfg.MaxMcHistory
+	m.state.minFailureRelaxInterval = cfg.MinFailureRelaxInterval
+	m.estimator.ProbabilityEstimatorCfg = cfg.ProbabilityEstimatorCfg
+
+	return nil
+}
+
 // ResetHistory resets the history of MissionControl returning it to a state as
 // if no payment attempts have been made.
 func (m *MissionControl) ResetHistory() error {
@@ -262,7 +324,7 @@ func (m *MissionControl) GetProbability(fromNode, toNode route.Vertex,
 	results, _ := m.state.getLastPairResult(fromNode)
 
 	// Use a distinct probability estimation function for local channels.
-	if fromNode == m.cfg.SelfNode {
+	if fromNode == m.selfNode {
 		return m.estimator.getLocalPairProbability(now, results, toNode)
 	}
 
@@ -309,6 +371,9 @@ func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route,
 	failureSourceIdx *int, failure lnwire.FailureMessage) (
 	*channeldb.FailureReason, error) {
 
+	m.Lock()
+	defer m.Unlock()
+
 	timestamp := m.now()
 
 	result := &paymentResult{
@@ -329,6 +394,9 @@ func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route,
 func (m *MissionControl) ReportPaymentSuccess(paymentID uint64,
 	rt *route.Route) error {
 
+	m.Lock()
+	defer m.Unlock()
+
 	timestamp := m.now()
 
 	result := &paymentResult{
@@ -371,10 +439,6 @@ func (m *MissionControl) applyPaymentResult(
 		result.failure,
 	)
 
-	// Update mission control state using the interpretation.
-	m.Lock()
-	defer m.Unlock()
-
 	if i.policyFailure != nil {
 		if m.state.requestSecondChance(
 			result.timeReply,
diff --git a/routing/probability_estimator.go b/routing/probability_estimator.go
index 238a765f1..7cd2df169 100644
--- a/routing/probability_estimator.go
+++ b/routing/probability_estimator.go
@@ -1,6 +1,7 @@
 package routing
 
 import (
+	"errors"
 	"math"
 	"time"
 
@@ -8,25 +9,61 @@ import (
 	"github.com/lightningnetwork/lnd/routing/route"
 )
 
-// probabilityEstimator returns node and pair probabilities based on historical
-// payment results.
-type probabilityEstimator struct {
-	// penaltyHalfLife defines after how much time a penalized node or
+var (
+	// ErrInvalidHalflife is returned when we get an invalid half life.
+	ErrInvalidHalflife = errors.New("penalty half life must be >= 0")
+
+	// ErrInvalidHopProbability is returned when we get an invalid hop
+	// probability.
+	ErrInvalidHopProbability = errors.New("hop probability must be in [0;1]")
+
+	// ErrInvalidAprioriWeight is returned when we get an apriori weight
+	// that is out of range.
+	ErrInvalidAprioriWeight = errors.New("apriori weight must be in [0;1]")
+)
+
+// ProbabilityEstimatorCfg contains configuration for our probability estimator.
+type ProbabilityEstimatorCfg struct {
+	// PenaltyHalfLife defines after how much time a penalized node or
 	// channel is back at 50% probability.
-	penaltyHalfLife time.Duration
+	PenaltyHalfLife time.Duration
 
-	// aprioriHopProbability is the assumed success probability of a hop in
+	// AprioriHopProbability is the assumed success probability of a hop in
 	// a route when no other information is available.
-	aprioriHopProbability float64
+	AprioriHopProbability float64
 
-	// aprioriWeight is a value in the range [0, 1] that defines to what
+	// AprioriWeight is a value in the range [0, 1] that defines to what
 	// extent historical results should be extrapolated to untried
 	// connections. Setting it to one will completely ignore historical
 	// results and always assume the configured a priori probability for
 	// untried connections. A value of zero will ignore the a priori
 	// probability completely and only base the probability on historical
 	// results, unless there are none available.
-	aprioriWeight float64
+	AprioriWeight float64
+}
+
+func (p ProbabilityEstimatorCfg) validate() error {
+	if p.PenaltyHalfLife < 0 {
+		return ErrInvalidHalflife
+	}
+
+	if p.AprioriHopProbability < 0 || p.AprioriHopProbability > 1 {
+		return ErrInvalidHopProbability
+	}
+
+	if p.AprioriWeight < 0 || p.AprioriWeight > 1 {
+		return ErrInvalidAprioriWeight
+	}
+
+	return nil
+}
+
+// probabilityEstimator returns node and pair probabilities based on historical
+// payment results.
+type probabilityEstimator struct {
+	// ProbabilityEstimatorCfg contains configuration options for our
+	// estimator.
+	ProbabilityEstimatorCfg
 
 	// prevSuccessProbability is the assumed probability for node pairs that
 	// successfully relayed the previous attempt.
@@ -41,14 +78,14 @@ func (p *probabilityEstimator) getNodeProbability(now time.Time,
 
 	// If the channel history is not to be taken into account, we can return
 	// early here with the configured a priori probability.
-	if p.aprioriWeight == 1 {
-		return p.aprioriHopProbability
+	if p.AprioriWeight == 1 {
+		return p.AprioriHopProbability
 	}
 
 	// If there is no channel history, our best estimate is still the a
 	// priori probability.
 	if len(results) == 0 {
-		return p.aprioriHopProbability
+		return p.AprioriHopProbability
 	}
 
 	// The value of the apriori weight is in the range [0, 1]. Convert it to
@@ -58,7 +95,7 @@ func (p *probabilityEstimator) getNodeProbability(now time.Time,
 	// the weighted average calculation below. When the apriori weight
 	// approaches 1, the apriori factor goes to infinity. It will heavily
 	// outweigh any observations that have been collected.
-	aprioriFactor := 1/(1-p.aprioriWeight) - 1
+	aprioriFactor := 1/(1-p.AprioriWeight) - 1
 
 	// Calculate a weighted average consisting of the apriori probability
 	// and historical observations. This is the part that incentivizes nodes
@@ -76,7 +113,7 @@ func (p *probabilityEstimator) getNodeProbability(now time.Time,
 	// effectively prunes all channels of the node forever. This is the most
 	// aggressive way in which we can penalize nodes and unlikely to yield
 	// good results in a real network.
-	probabilitiesTotal := p.aprioriHopProbability * aprioriFactor
+	probabilitiesTotal := p.AprioriHopProbability * aprioriFactor
 	totalWeight := aprioriFactor
 
 	for _, result := range results {
@@ -106,7 +143,7 @@ func (p *probabilityEstimator) getNodeProbability(now time.Time,
 // the result is fresh and asymptotically approaches zero over time. The rate at
 // which this happens is controlled by the penaltyHalfLife parameter.
 func (p *probabilityEstimator) getWeight(age time.Duration) float64 {
-	exp := -age.Hours() / p.penaltyHalfLife.Hours()
+	exp := -age.Hours() / p.PenaltyHalfLife.Hours()
 	return math.Pow(2, exp)
 }
 
diff --git a/server.go b/server.go
index 2e4fb8b0b..f10e84948 100644
--- a/server.go
+++ b/server.go
@@ -725,14 +725,17 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
 	// servers, the mission control instance itself can be moved there too.
 	routingConfig := routerrpc.GetRoutingConfig(cfg.SubRPCServers.RouterRPC)
 
+	estimatorCfg := routing.ProbabilityEstimatorCfg{
+		AprioriHopProbability: routingConfig.AprioriHopProbability,
+		PenaltyHalfLife:       routingConfig.PenaltyHalfLife,
+		AprioriWeight:         routingConfig.AprioriWeight,
+	}
+
 	s.missionControl, err = routing.NewMissionControl(
-		remoteChanDB,
+		remoteChanDB, selfNode.PubKeyBytes,
 		&routing.MissionControlConfig{
-			AprioriHopProbability:   routingConfig.AprioriHopProbability,
-			PenaltyHalfLife:         routingConfig.PenaltyHalfLife,
+			ProbabilityEstimatorCfg: estimatorCfg,
 			MaxMcHistory:            routingConfig.MaxMcHistory,
-			AprioriWeight:           routingConfig.AprioriWeight,
-			SelfNode:                selfNode.PubKeyBytes,
 			MinFailureRelaxInterval: routing.DefaultMinFailureRelaxInterval,
 		},
 	)


Test patch:
diff --git a/lnrpc/routerrpc/router_backend_test.go b/lnrpc/routerrpc/router_backend_test.go
index bd9fee375..f100909ad 100644
--- a/lnrpc/routerrpc/router_backend_test.go
+++ b/lnrpc/routerrpc/router_backend_test.go
@@ -216,6 +216,7 @@ func testQueryRoutes(t *testing.T, useMissionControl bool, useMsat bool) {
 }
 
 type mockMissionControl struct {
+	MissionControl
 }
 
 func (m *mockMissionControl) GetProbability(fromNode, toNode route.Vertex,
diff --git a/lntest/itest/lnd_test.go b/lntest/itest/lnd_test.go
index 9b94a671c..ac6fe05ba 100644
--- a/lntest/itest/lnd_test.go
+++ b/lntest/itest/lnd_test.go
@@ -12664,6 +12664,10 @@ func testQueryRoutes(net *lntest.NetworkHarness, t *harnessTest) {
 		}
 	}
 
+	// While we're here, we test updating mission control's config values
+	// and assert that they are correctly updated.
+	testMissionControlCfg(t.t, net.Alice)
+
 	// We clean up the test case by closing channels that were created for
 	// the duration of the tests.
 	ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout)
@@ -12674,6 +12678,51 @@ func testQueryRoutes(net *lntest.NetworkHarness, t *harnessTest) {
 	closeChannelAndAssert(ctxt, t, net, carol, chanPointCarol, false)
 }
 
+// testMissionControlCfg tests getting and setting of a node's mission control
+// config, resetting to the original values after testing so that no other
+// tests are affected.
+func testMissionControlCfg(t *testing.T, node *lntest.HarnessNode) {
+	ctxb := context.Background()
+	startCfg, err := node.RouterClient.GetMissionControlConfig(
+		ctxb, &routerrpc.GetMissionControlConfigRequest{},
+	)
+	require.NoError(t, err)
+
+	cfg := &routerrpc.MissionControlConfig{
+		HalfLifeSeconds:             8000,
+		HopProbability:              0.8,
+		Weight:                      0.3,
+		MaximumPaymentResults:       30,
+		MinimumFailureRelaxInterval: 60,
+	}
+
+	_, err = node.RouterClient.SetMissionControlConfig(
+		ctxb, &routerrpc.SetMissionControlConfigRequest{
+			Config: cfg,
+		},
+	)
+	require.NoError(t, err)
+
+	resp, err := node.RouterClient.GetMissionControlConfig(
+		ctxb, &routerrpc.GetMissionControlConfigRequest{},
+	)
+	require.NoError(t, err)
+
+	// Set the hidden fields on the cfg we set so that we can use require
+	// equal rather than comparing field by field.
+	cfg.XXX_sizecache = resp.XXX_sizecache
+	cfg.XXX_NoUnkeyedLiteral = resp.XXX_NoUnkeyedLiteral
+	cfg.XXX_unrecognized = resp.XXX_unrecognized
+	require.Equal(t, cfg, resp.Config)
+
+	_, err = node.RouterClient.SetMissionControlConfig(
+		ctxb, &routerrpc.SetMissionControlConfigRequest{
+			Config: startCfg.Config,
+		},
+	)
+	require.NoError(t, err)
+}
+
 // testRouteFeeCutoff tests that we are able to prevent querying routes and
 // sending payments that incur a fee higher than the fee limit.
 func testRouteFeeCutoff(net *lntest.NetworkHarness, t *harnessTest) {
diff --git a/routing/integrated_routing_context_test.go b/routing/integrated_routing_context_test.go
index 3bad60857..6399dc472 100644
--- a/routing/integrated_routing_context_test.go
+++ b/routing/integrated_routing_context_test.go
@@ -58,10 +58,11 @@ func newIntegratedRoutingContext(t *testing.T) *integratedRoutingContext {
 		finalExpiry: 40,
 
 		mcCfg: MissionControlConfig{
-			PenaltyHalfLife:       30 * time.Minute,
-			AprioriHopProbability: 0.6,
-			AprioriWeight:         0.5,
-			SelfNode:              source.pubkey,
+			ProbabilityEstimatorCfg: ProbabilityEstimatorCfg{
+				PenaltyHalfLife:       30 * time.Minute,
+				AprioriHopProbability: 0.6,
+				AprioriWeight:         0.5,
+			},
 		},
 
 		pathFindingCfg: PathFindingConfig{
@@ -115,7 +116,7 @@ func (c *integratedRoutingContext) testPayment(maxParts uint32) ([]htlcAttempt,
 
 	// Instantiate a new mission control with the current configuration
 	// values.
-	mc, err := NewMissionControl(db, &c.mcCfg)
+	mc, err := NewMissionControl(db, c.source.pubkey, &c.mcCfg)
 	if err != nil {
 		c.t.Fatal(err)
 	}
diff --git a/routing/missioncontrol_test.go b/routing/missioncontrol_test.go
index 001e7b036..48922a3bf 100644
--- a/routing/missioncontrol_test.go
+++ b/routing/missioncontrol_test.go
@@ -78,12 +78,13 @@ func createMcTestContext(t *testing.T) *mcTestContext {
 // restartMc creates a new instances of mission control on the same database.
 func (ctx *mcTestContext) restartMc() {
 	mc, err := NewMissionControl(
-		ctx.db,
+		ctx.db, mcTestSelf,
 		&MissionControlConfig{
-			PenaltyHalfLife:       testPenaltyHalfLife,
-			AprioriHopProbability: testAprioriHopProbability,
-			AprioriWeight:         testAprioriWeight,
-			SelfNode:              mcTestSelf,
+			ProbabilityEstimatorCfg: ProbabilityEstimatorCfg{
+				PenaltyHalfLife:       testPenaltyHalfLife,
+				AprioriHopProbability: testAprioriHopProbability,
+				AprioriWeight:         testAprioriWeight,
+			},
 		},
 	)
 	if err != nil {
diff --git a/routing/mock_test.go b/routing/mock_test.go
index a284cf57d..9c4f79e5d 100644
--- a/routing/mock_test.go
+++ b/routing/mock_test.go
@@ -104,6 +104,7 @@ func (m *mockPaymentSessionSource) NewPaymentSessionEmpty() PaymentSession {
 }
 
 type mockMissionControl struct {
+	MissionControl
 }
 
 var _ MissionController = (*mockMissionControl)(nil)
diff --git a/routing/payment_session_test.go b/routing/payment_session_test.go
index ba55fcea6..6a84e1f0e 100644
--- a/routing/payment_session_test.go
+++ b/routing/payment_session_test.go
@@ -33,7 +33,7 @@ func TestRequestRoute(t *testing.T) {
 		func() (routingGraph, func(), error) {
 			return &sessionGraph{}, func() {}, nil
 		},
-		&MissionControl{cfg: &MissionControlConfig{}},
+		&MissionControl{},
 		PathFindingConfig{},
 	)
 	if err != nil {
diff --git a/routing/probability_estimator_test.go b/routing/probability_estimator_test.go
index 384b39b63..094c0550e 100644
--- a/routing/probability_estimator_test.go
+++ b/routing/probability_estimator_test.go
@@ -40,9 +40,11 @@ func newEstimatorTestContext(t *testing.T) *estimatorTestContext {
 	return &estimatorTestContext{
 		t: t,
 		estimator: &probabilityEstimator{
-			aprioriHopProbability:  aprioriHopProb,
-			aprioriWeight:          aprioriWeight,
-			penaltyHalfLife:        time.Hour,
+			ProbabilityEstimatorCfg: ProbabilityEstimatorCfg{
+				AprioriHopProbability: aprioriHopProb,
+				AprioriWeight:         aprioriWeight,
+				PenaltyHalfLife:       time.Hour,
+			},
 			prevSuccessProbability: aprioriPrevSucProb,
 		},
 	}
diff --git a/routing/router_test.go b/routing/router_test.go
index 5db80dc97..a04aa7b3d 100644
--- a/routing/router_test.go
+++ b/routing/router_test.go
@@ -85,13 +85,15 @@ func createTestCtxFromGraphInstance(startingHeight uint32, graphInstance *testGr
 	}
 
 	mcConfig := &MissionControlConfig{
-		PenaltyHalfLife:       time.Hour,
-		AprioriHopProbability: 0.9,
-		AprioriWeight:         0.5,
+		ProbabilityEstimatorCfg: ProbabilityEstimatorCfg{
+			PenaltyHalfLife:       time.Hour,
+			AprioriHopProbability: 0.9,
+			AprioriWeight:         0.5,
+		},
 	}
 
 	mc, err := NewMissionControl(
-		graphInstance.graph.Database(),
+		graphInstance.graph.Database(), route.Vertex{},
 		mcConfig,
 	)
 	if err != nil {