mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-14 12:43:03 +02:00
Merge pull request #332 from carlaKC/autoloop-1-disqualified
autoloop: add reasons to explain no action
This commit is contained in:
commit
fe42664e16
10 changed files with 1063 additions and 366 deletions
|
|
@ -2,12 +2,15 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/lightninglabs/loop/liquidity"
|
||||
"github.com/lightninglabs/loop/looprpc"
|
||||
"github.com/urfave/cli"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
var getLiquidityParamsCommand = cli.Command{
|
||||
|
|
@ -411,11 +414,22 @@ func suggestSwap(ctx *cli.Context) error {
|
|||
resp, err := client.SuggestSwaps(
|
||||
context.Background(), &looprpc.SuggestSwapsRequest{},
|
||||
)
|
||||
if err != nil {
|
||||
if err == nil {
|
||||
printRespJSON(resp)
|
||||
return nil
|
||||
}
|
||||
|
||||
// If we got an error because no rules are set, we want to display a
|
||||
// friendly message.
|
||||
rpcErr, ok := status.FromError(err)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
||||
printJSON(resp)
|
||||
if rpcErr.Code() != codes.FailedPrecondition {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return errors.New("no rules set for autolooper, please set rules " +
|
||||
"using the setrule command")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,8 +224,51 @@ in manually dispatched swaps - for loop out, this would mean the channel is
|
|||
specified in the outgoing channel swap, and for loop in the channel's peer is
|
||||
specified as the last hop for an ongoing swap. This check is put in place to
|
||||
prevent the autolooper from interfering with swaps you have created yourself.
|
||||
If there is an ongoing swap that does not have a restriction placed on it (no
|
||||
outgoing channel set, or last hop), then the autolooper will take no action
|
||||
until it has resolved, because it does not know how that swap will affect
|
||||
liquidity balances.
|
||||
|
||||
## Disqualified Swaps
|
||||
There are various restrictions placed on the client's autoloop functionality.
|
||||
If a channel is not eligible for a swap at present, or it does not need one
|
||||
based on the current set of liquidity rules, it will be listed in the
|
||||
`Disqualified` section of the output of the `SuggestSwaps` API. One of the
|
||||
following reasons will be displayed:
|
||||
|
||||
* Budget not started: if the start date for your budget is in the future,
|
||||
no swaps will be executed until the start date is reached. See [budget](#budget) to
|
||||
update.
|
||||
* Budget elapsed: if the autolooper has elapsed the budget assigned to it for
|
||||
fees, this reason will be returned. See [budget](#budget) to update.
|
||||
* Sweep fees: this reason will be displayed if the estimated chain fee rate for
|
||||
sweeping a loop out swap is higher than the current limit. See [sweep fees](#fee-market-awareness)
|
||||
to update.
|
||||
* In flight: there is a limit to the number of automatically dispatched swaps
|
||||
that the client allows. If this limit has been reached, no further swaps
|
||||
will be automatically dispatched until the in-flight swaps complete. See
|
||||
[in flight limit](#in-flight-limit) to update.
|
||||
* Budget insufficient: if there is not enough remaining budget for a swap,
|
||||
including the amount currently reserved for in flight swaps, an insufficient
|
||||
reason will be displayed. This differs from budget elapsed because there is
|
||||
still budget remaining, just not enough to execute a specific swap.
|
||||
* Swap fee: there is a limit placed on the fee that the client will pay to the
|
||||
server for automatically dispatched swaps. The swap fee reason will be shown
|
||||
if the fees advertised by the server are too high. See [swap fee](#swap-fee)
|
||||
to update.
|
||||
* Miner fee: if the estimated on-chain fees for a swap are too high, autoloop
|
||||
will display a miner fee reason. See [miner fee](#miner-fee) to update.
|
||||
* Prepay: if the no-show fee that the server will pay in the unlikely event
|
||||
that the client fails to complete a swap is too high, a prepay reason will
|
||||
be returned. See [no show fees](#no-show-fee) to update.
|
||||
* Backoff: if an automatically dispatched swap has recently failed for a channel,
|
||||
autoloop will backoff for a period before retrying. See [failure backoff](#failure-backoff)
|
||||
to update.
|
||||
* Loop out: if there is currently a loop out swap in-flight on a channel, it
|
||||
will not be used for automated swaps. This issue will resolve itself once the
|
||||
in-flight swap completes.
|
||||
* Loop in: if there is currently a loop in swap in-flight for a peer, it will
|
||||
not be used for automated swaps. This will resolve itself once the swap is
|
||||
completed.
|
||||
* Liquidity ok: if a channel's current liquidity balance is within the bound set
|
||||
by the rule that it applies to, then a liquidity ok reason will be displayed
|
||||
to indicate that no action is required for that channel.
|
||||
|
||||
Further details for all of these reasons can be found in loopd's debug level
|
||||
logs.
|
||||
|
|
|
|||
|
|
@ -178,6 +178,9 @@ var (
|
|||
// less than the server minimum.
|
||||
ErrMinLessThanServer = errors.New("minimum swap amount is less than " +
|
||||
"server minimum")
|
||||
|
||||
// ErrNoRules is returned when no rules are set for swap suggestions.
|
||||
ErrNoRules = errors.New("no rules set for autoloop")
|
||||
)
|
||||
|
||||
// Config contains the external functionality required to run the
|
||||
|
|
@ -439,7 +442,14 @@ func (m *Manager) Run(ctx context.Context) error {
|
|||
for {
|
||||
select {
|
||||
case <-m.cfg.AutoloopTicker.Ticks():
|
||||
if err := m.autoloop(ctx); err != nil {
|
||||
err := m.autoloop(ctx)
|
||||
switch err {
|
||||
case ErrNoRules:
|
||||
log.Debugf("No rules configured for autoloop")
|
||||
|
||||
case nil:
|
||||
|
||||
default:
|
||||
log.Errorf("autoloop failed: %v", err)
|
||||
}
|
||||
|
||||
|
|
@ -506,12 +516,12 @@ func cloneParameters(params Parameters) Parameters {
|
|||
// autoloop gets a set of suggested swaps and dispatches them automatically if
|
||||
// we have automated looping enabled.
|
||||
func (m *Manager) autoloop(ctx context.Context) error {
|
||||
swaps, err := m.SuggestSwaps(ctx, true)
|
||||
suggestion, err := m.SuggestSwaps(ctx, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, swap := range swaps {
|
||||
for _, swap := range suggestion.OutSwaps {
|
||||
// If we don't actually have dispatch of swaps enabled, log
|
||||
// suggestions.
|
||||
if !m.params.Autoloop {
|
||||
|
|
@ -547,6 +557,36 @@ func (m *Manager) ForceAutoLoop(ctx context.Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Suggestions provides a set of suggested swaps, and the set of channels that
|
||||
// were excluded from consideration.
|
||||
type Suggestions struct {
|
||||
// OutSwaps is the set of loop out swaps that we suggest executing.
|
||||
OutSwaps []loop.OutRequest
|
||||
|
||||
// DisqualifiedChans maps the set of channels that we do not recommend
|
||||
// swaps on to the reason that we did not recommend a swap.
|
||||
DisqualifiedChans map[lnwire.ShortChannelID]Reason
|
||||
}
|
||||
|
||||
func newSuggestions() *Suggestions {
|
||||
return &Suggestions{
|
||||
DisqualifiedChans: make(map[lnwire.ShortChannelID]Reason),
|
||||
}
|
||||
}
|
||||
|
||||
// singleReasonSuggestion is a helper function which returns a set of
|
||||
// suggestions where all of our rules are disqualified due to a reason that
|
||||
// applies to all of them (such as being out of budget).
|
||||
func (m *Manager) singleReasonSuggestion(reason Reason) *Suggestions {
|
||||
resp := newSuggestions()
|
||||
|
||||
for id := range m.params.ChannelRules {
|
||||
resp.DisqualifiedChans[id] = reason
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
// SuggestSwaps returns a set of swap suggestions based on our current liquidity
|
||||
// balance for the set of rules configured for the manager, failing if there are
|
||||
// no rules set. It takes an autoloop boolean that indicates whether the
|
||||
|
|
@ -554,7 +594,7 @@ func (m *Manager) ForceAutoLoop(ctx context.Context) error {
|
|||
// to determine the information we add to our swap suggestion and whether we
|
||||
// return any suggestions.
|
||||
func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
|
||||
[]loop.OutRequest, error) {
|
||||
*Suggestions, error) {
|
||||
|
||||
m.paramsLock.Lock()
|
||||
defer m.paramsLock.Unlock()
|
||||
|
|
@ -562,7 +602,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
|
|||
// If we have no rules set, exit early to avoid unnecessary calls to
|
||||
// lnd and the server.
|
||||
if len(m.params.ChannelRules) == 0 {
|
||||
return nil, nil
|
||||
return nil, ErrNoRules
|
||||
}
|
||||
|
||||
// If our start date is in the future, we interpret this as meaning that
|
||||
|
|
@ -572,7 +612,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
|
|||
log.Debugf("autoloop fee budget start time: %v is in "+
|
||||
"the future", m.params.AutoFeeStartDate)
|
||||
|
||||
return nil, nil
|
||||
return m.singleReasonSuggestion(ReasonBudgetNotStarted), nil
|
||||
}
|
||||
|
||||
// Before we get any swap suggestions, we check what the current fee
|
||||
|
|
@ -593,7 +633,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
|
|||
satPerKwToSatPerVByte(estimate),
|
||||
satPerKwToSatPerVByte(m.params.SweepFeeRateLimit))
|
||||
|
||||
return nil, nil
|
||||
return m.singleReasonSuggestion(ReasonSweepFees), nil
|
||||
}
|
||||
|
||||
// Get the current server side restrictions, combined with the client
|
||||
|
|
@ -630,7 +670,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
|
|||
m.params.AutoFeeBudget, summary.spentFees,
|
||||
summary.pendingFees)
|
||||
|
||||
return nil, nil
|
||||
return m.singleReasonSuggestion(ReasonBudgetElapsed), nil
|
||||
}
|
||||
|
||||
// If we have already reached our total allowed number of in flight
|
||||
|
|
@ -639,29 +679,45 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
|
|||
if allowedSwaps <= 0 {
|
||||
log.Debugf("%v autoloops allowed, %v in flight",
|
||||
m.params.MaxAutoInFlight, summary.inFlightCount)
|
||||
return nil, nil
|
||||
|
||||
return m.singleReasonSuggestion(ReasonInFlight), nil
|
||||
}
|
||||
|
||||
eligible, err := m.getEligibleChannels(ctx, loopOut, loopIn)
|
||||
channels, err := m.cfg.Lnd.Client.ListChannels(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var suggestions []loop.OutRequest
|
||||
for _, channel := range eligible {
|
||||
channelID := lnwire.NewShortChanIDFromInt(channel.ChannelID)
|
||||
rule, ok := m.params.ChannelRules[channelID]
|
||||
// Get a summary of the channels and peers that are not eligible due
|
||||
// to ongoing swaps.
|
||||
traffic := m.currentSwapTraffic(loopOut, loopIn)
|
||||
|
||||
var (
|
||||
suggestions []loop.OutRequest
|
||||
disqualified = make(map[lnwire.ShortChannelID]Reason)
|
||||
)
|
||||
|
||||
for _, channel := range channels {
|
||||
balance := newBalances(channel)
|
||||
|
||||
rule, ok := m.params.ChannelRules[balance.channelID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
balance := newBalances(channel)
|
||||
|
||||
suggestion := rule.suggestSwap(balance, restrictions)
|
||||
// Check whether we can perform a swap, adding the channel to
|
||||
// our set of disqualified swaps if it is not eligible.
|
||||
reason := traffic.maySwap(channel.PubKeyBytes, balance.channelID)
|
||||
if reason != ReasonNone {
|
||||
disqualified[balance.channelID] = reason
|
||||
continue
|
||||
}
|
||||
|
||||
// We can have nil suggestions in the case where no action is
|
||||
// required, so we skip over them.
|
||||
suggestion := rule.suggestSwap(balance, restrictions)
|
||||
if suggestion == nil {
|
||||
disqualified[balance.channelID] = ReasonLiquidityOk
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -683,11 +739,9 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
|
|||
|
||||
// Check that the estimated fees for the suggested swap are
|
||||
// below the fee limits configured by the manager.
|
||||
err = m.checkFeeLimits(quote, suggestion.Amount)
|
||||
if err != nil {
|
||||
log.Infof("suggestion: %v expected fees too high: %v",
|
||||
suggestion, err)
|
||||
|
||||
feeReason := m.checkFeeLimits(quote, suggestion.Amount)
|
||||
if feeReason != ReasonNone {
|
||||
disqualified[balance.channelID] = feeReason
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -700,10 +754,16 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
|
|||
suggestions = append(suggestions, outRequest)
|
||||
}
|
||||
|
||||
// If we have no suggestions after we have applied all of our limits,
|
||||
// just return.
|
||||
// Finally, run through all possible swaps, excluding swaps that are
|
||||
// not feasible due to fee or budget restrictions.
|
||||
resp := &Suggestions{
|
||||
DisqualifiedChans: disqualified,
|
||||
}
|
||||
|
||||
// If we have no swaps to execute after we have applied all of our
|
||||
// limits, just return our set of disqualified swaps.
|
||||
if len(suggestions) == 0 {
|
||||
return nil, nil
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// Sort suggestions by amount in descending order.
|
||||
|
|
@ -713,12 +773,38 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
|
|||
|
||||
// Run through our suggested swaps in descending order of amount and
|
||||
// return all of the swaps which will fit within our remaining budget.
|
||||
var (
|
||||
available = m.params.AutoFeeBudget - summary.totalFees()
|
||||
inBudget []loop.OutRequest
|
||||
)
|
||||
available := m.params.AutoFeeBudget - summary.totalFees()
|
||||
|
||||
// setReason is a helper that adds a swap's channels to our disqualified
|
||||
// list with the reason provided.
|
||||
setReason := func(reason Reason, swap loop.OutRequest) {
|
||||
for _, id := range swap.OutgoingChanSet {
|
||||
chanID := lnwire.NewShortChanIDFromInt(id)
|
||||
|
||||
resp.DisqualifiedChans[chanID] = reason
|
||||
}
|
||||
}
|
||||
|
||||
for _, swap := range suggestions {
|
||||
swap := swap
|
||||
|
||||
// If we do not have enough funds available, or we hit our
|
||||
// in flight limit, we record this value for the rest of the
|
||||
// swaps.
|
||||
var reason Reason
|
||||
switch {
|
||||
case available == 0:
|
||||
reason = ReasonBudgetInsufficient
|
||||
|
||||
case len(resp.OutSwaps) == allowedSwaps:
|
||||
reason = ReasonInFlight
|
||||
}
|
||||
|
||||
if reason != ReasonNone {
|
||||
setReason(reason, swap)
|
||||
continue
|
||||
}
|
||||
|
||||
fees := worstCaseOutFees(
|
||||
swap.MaxPrepayRoutingFee, swap.MaxSwapRoutingFee,
|
||||
swap.MaxSwapFee, swap.MaxMinerFee, swap.MaxPrepayAmount,
|
||||
|
|
@ -729,17 +815,13 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
|
|||
// fall within the budget and decrement our available amount.
|
||||
if fees <= available {
|
||||
available -= fees
|
||||
inBudget = append(inBudget, swap)
|
||||
}
|
||||
|
||||
// If we're out of budget, or we have hit the max number of
|
||||
// swaps that we want to dispatch at one time, exit early.
|
||||
if available == 0 || allowedSwaps == len(inBudget) {
|
||||
break
|
||||
resp.OutSwaps = append(resp.OutSwaps, swap)
|
||||
} else {
|
||||
setReason(ReasonBudgetInsufficient, swap)
|
||||
}
|
||||
}
|
||||
|
||||
return inBudget, nil
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// getSwapRestrictions queries the server for its latest swap size restrictions,
|
||||
|
|
@ -918,19 +1000,13 @@ func (m *Manager) checkExistingAutoLoops(ctx context.Context,
|
|||
return &summary, nil
|
||||
}
|
||||
|
||||
// getEligibleChannels takes lists of our existing loop out and in swaps, and
|
||||
// gets a list of channels that are not currently being utilized for a swap.
|
||||
// If an unrestricted swap is ongoing, we return an empty set of channels
|
||||
// because we don't know which channels balances it will affect.
|
||||
func (m *Manager) getEligibleChannels(ctx context.Context,
|
||||
loopOut []*loopdb.LoopOut, loopIn []*loopdb.LoopIn) (
|
||||
[]lndclient.ChannelInfo, error) {
|
||||
// currentSwapTraffic examines our existing swaps and returns a summary of the
|
||||
// current activity which can be used to determine whether we should perform
|
||||
// any swaps.
|
||||
func (m *Manager) currentSwapTraffic(loopOut []*loopdb.LoopOut,
|
||||
loopIn []*loopdb.LoopIn) *swapTraffic {
|
||||
|
||||
var (
|
||||
existingOut = make(map[lnwire.ShortChannelID]bool)
|
||||
existingIn = make(map[route.Vertex]bool)
|
||||
failedOut = make(map[lnwire.ShortChannelID]time.Time)
|
||||
)
|
||||
traffic := newSwapTraffic()
|
||||
|
||||
// Failure cutoff is the most recent failure timestamp we will still
|
||||
// consider a channel eligible. Any channels involved in swaps that have
|
||||
|
|
@ -963,7 +1039,7 @@ func (m *Manager) getEligibleChannels(ctx context.Context,
|
|||
id,
|
||||
)
|
||||
|
||||
failedOut[chanID] = failedAt
|
||||
traffic.failedLoopOut[chanID] = failedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -978,16 +1054,9 @@ func (m *Manager) getEligibleChannels(ctx context.Context,
|
|||
continue
|
||||
}
|
||||
|
||||
if len(chanSet) == 0 {
|
||||
log.Debugf("Ongoing unrestricted loop out: "+
|
||||
"%v, no suggestions at present", out.Hash)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for _, id := range chanSet {
|
||||
chanID := lnwire.NewShortChanIDFromInt(id)
|
||||
existingOut[chanID] = true
|
||||
traffic.ongoingLoopOut[chanID] = true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -997,83 +1066,91 @@ func (m *Manager) getEligibleChannels(ctx context.Context,
|
|||
continue
|
||||
}
|
||||
|
||||
// Skip over swaps that may come through any peer.
|
||||
if in.Contract.LastHop == nil {
|
||||
log.Debugf("Ongoing unrestricted loop in: "+
|
||||
"%v, no suggestions at present", in.Hash)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
existingIn[*in.Contract.LastHop] = true
|
||||
}
|
||||
|
||||
channels, err := m.cfg.Lnd.Client.ListChannels(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Run through our set of channels and skip over any channels that
|
||||
// are currently being utilized by a restricted swap (where restricted
|
||||
// means that a loop out limited channels, or a loop in limited last
|
||||
// hop).
|
||||
var eligible []lndclient.ChannelInfo
|
||||
for _, channel := range channels {
|
||||
shortID := lnwire.NewShortChanIDFromInt(channel.ChannelID)
|
||||
|
||||
lastFail, recentFail := failedOut[shortID]
|
||||
if recentFail {
|
||||
log.Debugf("Channel: %v not eligible for "+
|
||||
"suggestions, was part of a failed swap at: %v",
|
||||
channel.ChannelID, lastFail)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if existingOut[shortID] {
|
||||
log.Debugf("Channel: %v not eligible for "+
|
||||
"suggestions, ongoing loop out utilizing "+
|
||||
"channel", channel.ChannelID)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if existingIn[channel.PubKeyBytes] {
|
||||
log.Debugf("Channel: %v not eligible for "+
|
||||
"suggestions, ongoing loop in utilizing "+
|
||||
"peer", channel.ChannelID)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
eligible = append(eligible, channel)
|
||||
traffic.ongoingLoopIn[*in.Contract.LastHop] = true
|
||||
}
|
||||
|
||||
return eligible, nil
|
||||
return traffic
|
||||
}
|
||||
|
||||
// swapTraffic contains a summary of our current and previously failed swaps.
|
||||
type swapTraffic struct {
|
||||
ongoingLoopOut map[lnwire.ShortChannelID]bool
|
||||
ongoingLoopIn map[route.Vertex]bool
|
||||
failedLoopOut map[lnwire.ShortChannelID]time.Time
|
||||
}
|
||||
|
||||
func newSwapTraffic() *swapTraffic {
|
||||
return &swapTraffic{
|
||||
ongoingLoopOut: make(map[lnwire.ShortChannelID]bool),
|
||||
ongoingLoopIn: make(map[route.Vertex]bool),
|
||||
failedLoopOut: make(map[lnwire.ShortChannelID]time.Time),
|
||||
}
|
||||
}
|
||||
|
||||
// maySwap returns a boolean that indicates whether we may perform a swap for a
|
||||
// peer and its set of channels.
|
||||
func (s *swapTraffic) maySwap(peer route.Vertex,
|
||||
chanID lnwire.ShortChannelID) Reason {
|
||||
|
||||
lastFail, recentFail := s.failedLoopOut[chanID]
|
||||
if recentFail {
|
||||
log.Debugf("Channel: %v not eligible for suggestions, was "+
|
||||
"part of a failed swap at: %v", chanID, lastFail)
|
||||
|
||||
return ReasonFailureBackoff
|
||||
}
|
||||
|
||||
if s.ongoingLoopOut[chanID] {
|
||||
log.Debugf("Channel: %v not eligible for suggestions, "+
|
||||
"ongoing loop out utilizing channel", chanID)
|
||||
|
||||
return ReasonLoopOut
|
||||
}
|
||||
|
||||
if s.ongoingLoopIn[peer] {
|
||||
log.Debugf("Peer: %x not eligible for suggestions ongoing "+
|
||||
"loop in utilizing peer", peer)
|
||||
|
||||
return ReasonLoopIn
|
||||
}
|
||||
|
||||
return ReasonNone
|
||||
}
|
||||
|
||||
// checkFeeLimits takes a set of fees for a swap and checks whether they exceed
|
||||
// our swap limits.
|
||||
func (m *Manager) checkFeeLimits(quote *loop.LoopOutQuote,
|
||||
swapAmt btcutil.Amount) error {
|
||||
swapAmt btcutil.Amount) Reason {
|
||||
|
||||
maxFee := ppmToSat(swapAmt, m.params.MaximumSwapFeePPM)
|
||||
|
||||
if quote.SwapFee > maxFee {
|
||||
return fmt.Errorf("quoted swap fee: %v > maximum swap fee: %v",
|
||||
log.Debugf("quoted swap fee: %v > maximum swap fee: %v",
|
||||
quote.SwapFee, maxFee)
|
||||
|
||||
return ReasonSwapFee
|
||||
}
|
||||
|
||||
if quote.MinerFee > m.params.MaximumMinerFee {
|
||||
return fmt.Errorf("quoted miner fee: %v > maximum miner "+
|
||||
log.Debugf("quoted miner fee: %v > maximum miner "+
|
||||
"fee: %v", quote.MinerFee, m.params.MaximumMinerFee)
|
||||
|
||||
return ReasonMinerFee
|
||||
}
|
||||
|
||||
if quote.PrepayAmount > m.params.MaximumPrepay {
|
||||
return fmt.Errorf("quoted prepay: %v > maximum prepay: %v",
|
||||
log.Debugf("quoted prepay: %v > maximum prepay: %v",
|
||||
quote.PrepayAmount, m.params.MaximumPrepay)
|
||||
|
||||
return ReasonPrepay
|
||||
}
|
||||
|
||||
return nil
|
||||
return ReasonNone
|
||||
}
|
||||
|
||||
// satPerKwToSatPerVByte converts sat per kWeight to sat per vByte.
|
||||
|
|
|
|||
|
|
@ -107,6 +107,10 @@ var (
|
|||
}
|
||||
|
||||
testRestrictions = NewRestrictions(1, 10000)
|
||||
|
||||
// noneDisqualified can be used in tests where we don't have any
|
||||
// disqualified channels so that we can use require.Equal.
|
||||
noneDisqualified = make(map[lnwire.ShortChannelID]Reason)
|
||||
)
|
||||
|
||||
// newTestConfig creates a default test config.
|
||||
|
|
@ -283,7 +287,7 @@ func TestRestrictedSuggestions(t *testing.T) {
|
|||
channels []lndclient.ChannelInfo
|
||||
loopOut []*loopdb.LoopOut
|
||||
loopIn []*loopdb.LoopIn
|
||||
expected []loop.OutRequest
|
||||
expected *Suggestions
|
||||
}{
|
||||
{
|
||||
name: "no existing swaps",
|
||||
|
|
@ -292,14 +296,17 @@ func TestRestrictedSuggestions(t *testing.T) {
|
|||
},
|
||||
loopOut: nil,
|
||||
loopIn: nil,
|
||||
expected: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
expected: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unrestricted loop out",
|
||||
channels: []lndclient.ChannelInfo{
|
||||
channel1, channel2,
|
||||
channel1,
|
||||
},
|
||||
loopOut: []*loopdb.LoopOut{
|
||||
{
|
||||
|
|
@ -308,12 +315,17 @@ func TestRestrictedSuggestions(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
expected: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unrestricted loop in",
|
||||
channels: []lndclient.ChannelInfo{
|
||||
channel1, channel2,
|
||||
channel1,
|
||||
},
|
||||
loopIn: []*loopdb.LoopIn{
|
||||
{
|
||||
|
|
@ -322,7 +334,12 @@ func TestRestrictedSuggestions(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
expected: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "restricted loop out",
|
||||
|
|
@ -334,8 +351,13 @@ func TestRestrictedSuggestions(t *testing.T) {
|
|||
Contract: chan1Out,
|
||||
},
|
||||
},
|
||||
expected: []loop.OutRequest{
|
||||
chan2Rec,
|
||||
expected: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan2Rec,
|
||||
},
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID1: ReasonLoopOut,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -350,8 +372,13 @@ func TestRestrictedSuggestions(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
expected: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
expected: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
},
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID2: ReasonLoopIn,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -369,7 +396,11 @@ func TestRestrictedSuggestions(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
expected: &Suggestions{
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID1: ReasonFailureBackoff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "swap failed before cutoff",
|
||||
|
|
@ -386,8 +417,11 @@ func TestRestrictedSuggestions(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
expected: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
expected: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -405,7 +439,11 @@ func TestRestrictedSuggestions(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
expected: &Suggestions{
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID1: ReasonLoopOut,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -443,21 +481,28 @@ func TestRestrictedSuggestions(t *testing.T) {
|
|||
// fee is above and below the configured limit.
|
||||
func TestSweepFeeLimit(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
feeRate chainfee.SatPerKWeight
|
||||
swaps []loop.OutRequest
|
||||
name string
|
||||
feeRate chainfee.SatPerKWeight
|
||||
suggestions *Suggestions
|
||||
}{
|
||||
{
|
||||
name: "fee estimate ok",
|
||||
feeRate: defaultSweepFeeRateLimit,
|
||||
swaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fee estimate above limit",
|
||||
feeRate: defaultSweepFeeRateLimit + 1,
|
||||
swaps: nil,
|
||||
suggestions: &Suggestions{
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID1: ReasonSweepFees,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -483,7 +528,7 @@ func TestSweepFeeLimit(t *testing.T) {
|
|||
|
||||
testSuggestSwaps(
|
||||
t, newSuggestSwapsSetup(cfg, lnd, params),
|
||||
testCase.swaps, nil,
|
||||
testCase.suggestions, nil,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -493,21 +538,26 @@ func TestSweepFeeLimit(t *testing.T) {
|
|||
// the liquidity manager and the current set of channel balances.
|
||||
func TestSuggestSwaps(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
rules map[lnwire.ShortChannelID]*ThresholdRule
|
||||
swaps []loop.OutRequest
|
||||
name string
|
||||
rules map[lnwire.ShortChannelID]*ThresholdRule
|
||||
suggestions *Suggestions
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "no rules",
|
||||
rules: map[lnwire.ShortChannelID]*ThresholdRule{},
|
||||
err: ErrNoRules,
|
||||
},
|
||||
{
|
||||
name: "loop out",
|
||||
rules: map[lnwire.ShortChannelID]*ThresholdRule{
|
||||
chanID1: chanRule,
|
||||
},
|
||||
swaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -515,7 +565,9 @@ func TestSuggestSwaps(t *testing.T) {
|
|||
rules: map[lnwire.ShortChannelID]*ThresholdRule{
|
||||
chanID2: NewThresholdRule(10, 10),
|
||||
},
|
||||
swaps: nil,
|
||||
suggestions: &Suggestions{
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -534,7 +586,7 @@ func TestSuggestSwaps(t *testing.T) {
|
|||
|
||||
testSuggestSwaps(
|
||||
t, newSuggestSwapsSetup(cfg, lnd, params),
|
||||
testCase.swaps, nil,
|
||||
testCase.suggestions, testCase.err,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -543,15 +595,18 @@ func TestSuggestSwaps(t *testing.T) {
|
|||
// TestFeeLimits tests limiting of swap suggestions by fees.
|
||||
func TestFeeLimits(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
quote *loop.LoopOutQuote
|
||||
expected []loop.OutRequest
|
||||
name string
|
||||
quote *loop.LoopOutQuote
|
||||
suggestions *Suggestions
|
||||
}{
|
||||
{
|
||||
name: "fees ok",
|
||||
quote: testQuote,
|
||||
expected: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -561,6 +616,11 @@ func TestFeeLimits(t *testing.T) {
|
|||
PrepayAmount: defaultMaximumPrepay + 1,
|
||||
MinerFee: 50,
|
||||
},
|
||||
suggestions: &Suggestions{
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID1: ReasonPrepay,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "insufficient miner fee",
|
||||
|
|
@ -569,6 +629,11 @@ func TestFeeLimits(t *testing.T) {
|
|||
PrepayAmount: 100,
|
||||
MinerFee: defaultMaximumMinerFee + 1,
|
||||
},
|
||||
suggestions: &Suggestions{
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID1: ReasonMinerFee,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Swap fee limited to 0.5% of 7500 = 37,5.
|
||||
|
|
@ -578,6 +643,11 @@ func TestFeeLimits(t *testing.T) {
|
|||
PrepayAmount: 100,
|
||||
MinerFee: 500,
|
||||
},
|
||||
suggestions: &Suggestions{
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID1: ReasonSwapFee,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -604,7 +674,7 @@ func TestFeeLimits(t *testing.T) {
|
|||
|
||||
testSuggestSwaps(
|
||||
t, newSuggestSwapsSetup(cfg, lnd, params),
|
||||
testCase.expected, nil,
|
||||
testCase.suggestions, nil,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -635,8 +705,8 @@ func TestFeeBudget(t *testing.T) {
|
|||
// last update time to their total cost.
|
||||
existingSwaps map[time.Time]btcutil.Amount
|
||||
|
||||
// expectedSwaps is the set of swaps we expect to be suggested.
|
||||
expectedSwaps []loop.OutRequest
|
||||
// suggestions is the set of swaps we expect to be suggested.
|
||||
suggestions *Suggestions
|
||||
}{
|
||||
{
|
||||
// Two swaps will cost (78+5000)*2, set exactly 10156
|
||||
|
|
@ -644,8 +714,11 @@ func TestFeeBudget(t *testing.T) {
|
|||
name: "budget for 2 swaps, no existing",
|
||||
budget: 10156,
|
||||
maxMinerFee: 5000,
|
||||
expectedSwaps: []loop.OutRequest{
|
||||
chan1Rec, chan2Rec,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec, chan2Rec,
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -654,8 +727,13 @@ func TestFeeBudget(t *testing.T) {
|
|||
name: "budget for 1 swaps, no existing",
|
||||
budget: 10155,
|
||||
maxMinerFee: 5000,
|
||||
expectedSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
},
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID2: ReasonBudgetInsufficient,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -667,8 +745,11 @@ func TestFeeBudget(t *testing.T) {
|
|||
existingSwaps: map[time.Time]btcutil.Amount{
|
||||
testBudgetStart.Add(time.Hour * -1): 200,
|
||||
},
|
||||
expectedSwaps: []loop.OutRequest{
|
||||
chan1Rec, chan2Rec,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec, chan2Rec,
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -680,8 +761,13 @@ func TestFeeBudget(t *testing.T) {
|
|||
existingSwaps: map[time.Time]btcutil.Amount{
|
||||
testBudgetStart.Add(time.Hour): 500,
|
||||
},
|
||||
expectedSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
},
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID2: ReasonBudgetInsufficient,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -691,7 +777,12 @@ func TestFeeBudget(t *testing.T) {
|
|||
existingSwaps: map[time.Time]btcutil.Amount{
|
||||
testBudgetStart.Add(time.Hour): 500,
|
||||
},
|
||||
expectedSwaps: nil,
|
||||
suggestions: &Suggestions{
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID1: ReasonBudgetElapsed,
|
||||
chanID2: ReasonBudgetElapsed,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -754,14 +845,14 @@ func TestFeeBudget(t *testing.T) {
|
|||
// Set our custom max miner fee on each expected swap,
|
||||
// rather than having to create multiple vars for
|
||||
// different rates.
|
||||
for i := range testCase.expectedSwaps {
|
||||
testCase.expectedSwaps[i].MaxMinerFee =
|
||||
for i := range testCase.suggestions.OutSwaps {
|
||||
testCase.suggestions.OutSwaps[i].MaxMinerFee =
|
||||
testCase.maxMinerFee
|
||||
}
|
||||
|
||||
testSuggestSwaps(
|
||||
t, newSuggestSwapsSetup(cfg, lnd, params),
|
||||
testCase.expectedSwaps, nil,
|
||||
testCase.suggestions, nil,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -774,20 +865,26 @@ func TestInFlightLimit(t *testing.T) {
|
|||
name string
|
||||
maxInFlight int
|
||||
existingSwaps []*loopdb.LoopOut
|
||||
expectedSwaps []loop.OutRequest
|
||||
suggestions *Suggestions
|
||||
}{
|
||||
{
|
||||
name: "none in flight, extra space",
|
||||
maxInFlight: 3,
|
||||
expectedSwaps: []loop.OutRequest{
|
||||
chan1Rec, chan2Rec,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec, chan2Rec,
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "none in flight, exact match",
|
||||
maxInFlight: 2,
|
||||
expectedSwaps: []loop.OutRequest{
|
||||
chan1Rec, chan2Rec,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec, chan2Rec,
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -798,8 +895,13 @@ func TestInFlightLimit(t *testing.T) {
|
|||
Contract: autoOutContract,
|
||||
},
|
||||
},
|
||||
expectedSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
},
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID2: ReasonInFlight,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -810,7 +912,12 @@ func TestInFlightLimit(t *testing.T) {
|
|||
Contract: autoOutContract,
|
||||
},
|
||||
},
|
||||
expectedSwaps: nil,
|
||||
suggestions: &Suggestions{
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID1: ReasonInFlight,
|
||||
chanID2: ReasonInFlight,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "max swaps exceeded",
|
||||
|
|
@ -823,7 +930,12 @@ func TestInFlightLimit(t *testing.T) {
|
|||
Contract: autoOutContract,
|
||||
},
|
||||
},
|
||||
expectedSwaps: nil,
|
||||
suggestions: &Suggestions{
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID1: ReasonInFlight,
|
||||
chanID2: ReasonInFlight,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -854,7 +966,7 @@ func TestInFlightLimit(t *testing.T) {
|
|||
|
||||
testSuggestSwaps(
|
||||
t, newSuggestSwapsSetup(cfg, lnd, params),
|
||||
testCase.expectedSwaps, nil,
|
||||
testCase.suggestions, nil,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -869,13 +981,18 @@ func TestSizeRestrictions(t *testing.T) {
|
|||
}
|
||||
|
||||
outSwap = loop.OutRequest{
|
||||
Amount: 7000,
|
||||
OutgoingChanSet: loopdb.ChannelSet{chanID1.ToUint64()},
|
||||
MaxPrepayRoutingFee: prepayFee,
|
||||
MaxMinerFee: defaultMaximumMinerFee,
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
SweepConfTarget: loop.DefaultSweepConfTarget,
|
||||
Initiator: autoloopSwapInitiator,
|
||||
MaxSwapRoutingFee: ppmToSat(
|
||||
7000,
|
||||
defaultRoutingFeePPM,
|
||||
),
|
||||
MaxMinerFee: defaultMaximumMinerFee,
|
||||
MaxSwapFee: testQuote.SwapFee,
|
||||
MaxPrepayAmount: testQuote.PrepayAmount,
|
||||
SweepConfTarget: loop.DefaultSweepConfTarget,
|
||||
Initiator: autoloopSwapInitiator,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -890,8 +1007,8 @@ func TestSizeRestrictions(t *testing.T) {
|
|||
// endpoint.
|
||||
serverRestrictions []Restrictions
|
||||
|
||||
// expectedAmount is the amount that we expect for our swap.
|
||||
expectedAmount btcutil.Amount
|
||||
// suggestions is the set of suggestions we expect.
|
||||
suggestions *Suggestions
|
||||
|
||||
// expectedError is the error we expect.
|
||||
expectedError error
|
||||
|
|
@ -904,7 +1021,12 @@ func TestSizeRestrictions(t *testing.T) {
|
|||
serverRestrictions: []Restrictions{
|
||||
serverRestrictions, serverRestrictions,
|
||||
},
|
||||
expectedAmount: 7500,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
chan1Rec,
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "minimum more than server, no swap",
|
||||
|
|
@ -914,7 +1036,11 @@ func TestSizeRestrictions(t *testing.T) {
|
|||
serverRestrictions: []Restrictions{
|
||||
serverRestrictions, serverRestrictions,
|
||||
},
|
||||
expectedAmount: 0,
|
||||
suggestions: &Suggestions{
|
||||
DisqualifiedChans: map[lnwire.ShortChannelID]Reason{
|
||||
chanID1: ReasonLiquidityOk,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "maximum less than server, swap happens",
|
||||
|
|
@ -924,7 +1050,12 @@ func TestSizeRestrictions(t *testing.T) {
|
|||
serverRestrictions: []Restrictions{
|
||||
serverRestrictions, serverRestrictions,
|
||||
},
|
||||
expectedAmount: 7000,
|
||||
suggestions: &Suggestions{
|
||||
OutSwaps: []loop.OutRequest{
|
||||
outSwap,
|
||||
},
|
||||
DisqualifiedChans: noneDisqualified,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Originally, our client params are ok. But then the
|
||||
|
|
@ -942,8 +1073,8 @@ func TestSizeRestrictions(t *testing.T) {
|
|||
Maximum: 6000,
|
||||
},
|
||||
},
|
||||
expectedAmount: 0,
|
||||
expectedError: ErrMaxExceedsServer,
|
||||
suggestions: nil,
|
||||
expectedError: ErrMaxExceedsServer,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -975,25 +1106,9 @@ func TestSizeRestrictions(t *testing.T) {
|
|||
|
||||
return &restrictions, nil
|
||||
}
|
||||
|
||||
// If we expect a swap (non-zero amount), we add a
|
||||
// swap to our set of expected swaps, and update amount
|
||||
// and fee accordingly.
|
||||
var expectedSwaps []loop.OutRequest
|
||||
if testCase.expectedAmount != 0 {
|
||||
outSwap.Amount = testCase.expectedAmount
|
||||
|
||||
outSwap.MaxSwapRoutingFee = ppmToSat(
|
||||
testCase.expectedAmount,
|
||||
defaultRoutingFeePPM,
|
||||
)
|
||||
|
||||
expectedSwaps = append(expectedSwaps, outSwap)
|
||||
}
|
||||
|
||||
testSuggestSwaps(
|
||||
t, newSuggestSwapsSetup(cfg, lnd, params),
|
||||
expectedSwaps, testCase.expectedError,
|
||||
testCase.suggestions, testCase.expectedError,
|
||||
)
|
||||
|
||||
require.Equal(
|
||||
|
|
@ -1028,7 +1143,7 @@ func newSuggestSwapsSetup(cfg *Config, lnd *test.LndMockServices,
|
|||
// use the default parameters and setup two channels (channel1 + channel2) with
|
||||
// chanRule set for each.
|
||||
func testSuggestSwaps(t *testing.T, setup *testSuggestSwapsSetup,
|
||||
expected []loop.OutRequest, expectedErr error) {
|
||||
expected *Suggestions, expectedErr error) {
|
||||
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
|||
62
liquidity/reasons.go
Normal file
62
liquidity/reasons.go
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package liquidity
|
||||
|
||||
// Reason is an enum which represents the various reasons we have for not
|
||||
// executing a swap.
|
||||
type Reason uint8
|
||||
|
||||
const (
|
||||
// ReasonNone is the zero value reason, added so that this enum can
|
||||
// align with the numeric values used in our protobufs and avoid
|
||||
// ambiguity around default zero values.
|
||||
ReasonNone Reason = iota
|
||||
|
||||
// ReasonBudgetNotStarted indicates that we do not recommend any swaps
|
||||
// because the start time for our budget has not arrived yet.
|
||||
ReasonBudgetNotStarted
|
||||
|
||||
// ReasonSweepFees indicates that the estimated fees to sweep swaps
|
||||
// are too high right now.
|
||||
ReasonSweepFees
|
||||
|
||||
// ReasonBudgetElapsed indicates that the autoloop budget for the
|
||||
// period has been elapsed.
|
||||
ReasonBudgetElapsed
|
||||
|
||||
// ReasonInFlight indicates that the limit on in-flight automatically
|
||||
// dispatched swaps has already been reached.
|
||||
ReasonInFlight
|
||||
|
||||
// ReasonSwapFee indicates that the server fee for a specific swap is
|
||||
// too high.
|
||||
ReasonSwapFee
|
||||
|
||||
// ReasonMinerFee indicates that the miner fee for a specific swap is
|
||||
// to high.
|
||||
ReasonMinerFee
|
||||
|
||||
// ReasonPrepay indicates that the prepay fee for a specific swap is
|
||||
// too high.
|
||||
ReasonPrepay
|
||||
|
||||
// ReasonFailureBackoff indicates that a swap has recently failed for
|
||||
// this target, and the backoff period has not yet passed.
|
||||
ReasonFailureBackoff
|
||||
|
||||
// ReasonLoopOut indicates that a loop out swap is currently utilizing
|
||||
// the channel, so it is not eligible.
|
||||
ReasonLoopOut
|
||||
|
||||
// ReasonLoopIn indicates that a loop in swap is currently in flight
|
||||
// for the peer, so it is not eligible.
|
||||
ReasonLoopIn
|
||||
|
||||
// ReasonLiquidityOk indicates that a target meets the liquidity
|
||||
// balance expressed in its rule, so no swap is needed.
|
||||
ReasonLiquidityOk
|
||||
|
||||
// ReasonBudgetInsufficient indicates that we cannot perform a swap
|
||||
// because we do not have enough pending budget available. This differs
|
||||
// from budget elapsed, because we still have some budget available,
|
||||
// but we have allocated it to other swaps.
|
||||
ReasonBudgetInsufficient
|
||||
)
|
||||
|
|
@ -21,6 +21,8 @@ import (
|
|||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/queue"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -702,14 +704,23 @@ func rpcToRule(rule *looprpc.LiquidityRule) (*liquidity.ThresholdRule, error) {
|
|||
func (s *swapClientServer) SuggestSwaps(ctx context.Context,
|
||||
_ *looprpc.SuggestSwapsRequest) (*looprpc.SuggestSwapsResponse, error) {
|
||||
|
||||
swaps, err := s.liquidityMgr.SuggestSwaps(ctx, false)
|
||||
if err != nil {
|
||||
suggestions, err := s.liquidityMgr.SuggestSwaps(ctx, false)
|
||||
switch err {
|
||||
case liquidity.ErrNoRules:
|
||||
return nil, status.Error(codes.FailedPrecondition, err.Error())
|
||||
|
||||
case nil:
|
||||
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var loopOut []*looprpc.LoopOutRequest
|
||||
var (
|
||||
loopOut []*looprpc.LoopOutRequest
|
||||
disqualified []*looprpc.Disqualified
|
||||
)
|
||||
|
||||
for _, swap := range swaps {
|
||||
for _, swap := range suggestions.OutSwaps {
|
||||
loopOut = append(loopOut, &looprpc.LoopOutRequest{
|
||||
Amt: int64(swap.Amount),
|
||||
OutgoingChanSet: swap.OutgoingChanSet,
|
||||
|
|
@ -722,11 +733,71 @@ func (s *swapClientServer) SuggestSwaps(ctx context.Context,
|
|||
})
|
||||
}
|
||||
|
||||
for id, reason := range suggestions.DisqualifiedChans {
|
||||
autoloopReason, err := rpcAutoloopReason(reason)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
exclChan := &looprpc.Disqualified{
|
||||
Reason: autoloopReason,
|
||||
ChannelId: id.ToUint64(),
|
||||
}
|
||||
disqualified = append(disqualified, exclChan)
|
||||
}
|
||||
|
||||
return &looprpc.SuggestSwapsResponse{
|
||||
LoopOut: loopOut,
|
||||
LoopOut: loopOut,
|
||||
Disqualified: disqualified,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func rpcAutoloopReason(reason liquidity.Reason) (looprpc.AutoReason, error) {
|
||||
switch reason {
|
||||
case liquidity.ReasonNone:
|
||||
return looprpc.AutoReason_AUTO_REASON_UNKNOWN, nil
|
||||
|
||||
case liquidity.ReasonBudgetNotStarted:
|
||||
return looprpc.AutoReason_AUTO_REASON_BUDGET_NOT_STARTED, nil
|
||||
|
||||
case liquidity.ReasonSweepFees:
|
||||
return looprpc.AutoReason_AUTO_REASON_SWEEP_FEES, nil
|
||||
|
||||
case liquidity.ReasonBudgetElapsed:
|
||||
return looprpc.AutoReason_AUTO_REASON_BUDGET_ELAPSED, nil
|
||||
|
||||
case liquidity.ReasonInFlight:
|
||||
return looprpc.AutoReason_AUTO_REASON_IN_FLIGHT, nil
|
||||
|
||||
case liquidity.ReasonSwapFee:
|
||||
return looprpc.AutoReason_AUTO_REASON_SWAP_FEE, nil
|
||||
|
||||
case liquidity.ReasonMinerFee:
|
||||
return looprpc.AutoReason_AUTO_REASON_MINER_FEE, nil
|
||||
|
||||
case liquidity.ReasonPrepay:
|
||||
return looprpc.AutoReason_AUTO_REASON_PREPAY, nil
|
||||
|
||||
case liquidity.ReasonFailureBackoff:
|
||||
return looprpc.AutoReason_AUTO_REASON_FAILURE_BACKOFF, nil
|
||||
|
||||
case liquidity.ReasonLoopOut:
|
||||
return looprpc.AutoReason_AUTO_REASON_LOOP_OUT, nil
|
||||
|
||||
case liquidity.ReasonLoopIn:
|
||||
return looprpc.AutoReason_AUTO_REASON_LOOP_IN, nil
|
||||
|
||||
case liquidity.ReasonLiquidityOk:
|
||||
return looprpc.AutoReason_AUTO_REASON_LIQUIDITY_OK, nil
|
||||
|
||||
case liquidity.ReasonBudgetInsufficient:
|
||||
return looprpc.AutoReason_AUTO_REASON_BUDGET_INSUFFICIENT, nil
|
||||
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown autoloop reason: %v", reason)
|
||||
}
|
||||
}
|
||||
|
||||
// processStatusUpdates reads updates on the status channel and processes them.
|
||||
//
|
||||
// NOTE: This must run inside a goroutine as it blocks until the main context
|
||||
|
|
|
|||
|
|
@ -200,6 +200,99 @@ func (LiquidityRuleType) EnumDescriptor() ([]byte, []int) {
|
|||
return fileDescriptor_014de31d7ac8c57c, []int{3}
|
||||
}
|
||||
|
||||
type AutoReason int32
|
||||
|
||||
const (
|
||||
AutoReason_AUTO_REASON_UNKNOWN AutoReason = 0
|
||||
//
|
||||
//Budget not started indicates that we do not recommend any swaps because
|
||||
//the start time for our budget has not arrived yet.
|
||||
AutoReason_AUTO_REASON_BUDGET_NOT_STARTED AutoReason = 1
|
||||
//
|
||||
//Sweep fees indicates that the estimated fees to sweep swaps are too high
|
||||
//right now.
|
||||
AutoReason_AUTO_REASON_SWEEP_FEES AutoReason = 2
|
||||
//
|
||||
//Budget elapsed indicates that the autoloop budget for the period has been
|
||||
//elapsed.
|
||||
AutoReason_AUTO_REASON_BUDGET_ELAPSED AutoReason = 3
|
||||
//
|
||||
//In flight indicates that the limit on in-flight automatically dispatched
|
||||
//swaps has already been reached.
|
||||
AutoReason_AUTO_REASON_IN_FLIGHT AutoReason = 4
|
||||
//
|
||||
//Swap fee indicates that the server fee for a specific swap is too high.
|
||||
AutoReason_AUTO_REASON_SWAP_FEE AutoReason = 5
|
||||
//
|
||||
//Miner fee indicates that the miner fee for a specific swap is to high.
|
||||
AutoReason_AUTO_REASON_MINER_FEE AutoReason = 6
|
||||
//
|
||||
//Prepay indicates that the prepay fee for a specific swap is too high.
|
||||
AutoReason_AUTO_REASON_PREPAY AutoReason = 7
|
||||
//
|
||||
//Failure backoff indicates that a swap has recently failed for this target,
|
||||
//and the backoff period has not yet passed.
|
||||
AutoReason_AUTO_REASON_FAILURE_BACKOFF AutoReason = 8
|
||||
//
|
||||
//Loop out indicates that a loop out swap is currently utilizing the channel,
|
||||
//so it is not eligible.
|
||||
AutoReason_AUTO_REASON_LOOP_OUT AutoReason = 9
|
||||
//
|
||||
//Loop In indicates that a loop in swap is currently in flight for the peer,
|
||||
//so it is not eligible.
|
||||
AutoReason_AUTO_REASON_LOOP_IN AutoReason = 10
|
||||
//
|
||||
//Liquidity ok indicates that a target meets the liquidity balance expressed
|
||||
//in its rule, so no swap is needed.
|
||||
AutoReason_AUTO_REASON_LIQUIDITY_OK AutoReason = 11
|
||||
//
|
||||
//Budget insufficient indicates that we cannot perform a swap because we do
|
||||
//not have enough pending budget available. This differs from budget elapsed,
|
||||
//because we still have some budget available, but we have allocated it to
|
||||
//other swaps.
|
||||
AutoReason_AUTO_REASON_BUDGET_INSUFFICIENT AutoReason = 12
|
||||
)
|
||||
|
||||
var AutoReason_name = map[int32]string{
|
||||
0: "AUTO_REASON_UNKNOWN",
|
||||
1: "AUTO_REASON_BUDGET_NOT_STARTED",
|
||||
2: "AUTO_REASON_SWEEP_FEES",
|
||||
3: "AUTO_REASON_BUDGET_ELAPSED",
|
||||
4: "AUTO_REASON_IN_FLIGHT",
|
||||
5: "AUTO_REASON_SWAP_FEE",
|
||||
6: "AUTO_REASON_MINER_FEE",
|
||||
7: "AUTO_REASON_PREPAY",
|
||||
8: "AUTO_REASON_FAILURE_BACKOFF",
|
||||
9: "AUTO_REASON_LOOP_OUT",
|
||||
10: "AUTO_REASON_LOOP_IN",
|
||||
11: "AUTO_REASON_LIQUIDITY_OK",
|
||||
12: "AUTO_REASON_BUDGET_INSUFFICIENT",
|
||||
}
|
||||
|
||||
var AutoReason_value = map[string]int32{
|
||||
"AUTO_REASON_UNKNOWN": 0,
|
||||
"AUTO_REASON_BUDGET_NOT_STARTED": 1,
|
||||
"AUTO_REASON_SWEEP_FEES": 2,
|
||||
"AUTO_REASON_BUDGET_ELAPSED": 3,
|
||||
"AUTO_REASON_IN_FLIGHT": 4,
|
||||
"AUTO_REASON_SWAP_FEE": 5,
|
||||
"AUTO_REASON_MINER_FEE": 6,
|
||||
"AUTO_REASON_PREPAY": 7,
|
||||
"AUTO_REASON_FAILURE_BACKOFF": 8,
|
||||
"AUTO_REASON_LOOP_OUT": 9,
|
||||
"AUTO_REASON_LOOP_IN": 10,
|
||||
"AUTO_REASON_LIQUIDITY_OK": 11,
|
||||
"AUTO_REASON_BUDGET_INSUFFICIENT": 12,
|
||||
}
|
||||
|
||||
func (x AutoReason) String() string {
|
||||
return proto.EnumName(AutoReason_name, int32(x))
|
||||
}
|
||||
|
||||
func (AutoReason) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_014de31d7ac8c57c, []int{4}
|
||||
}
|
||||
|
||||
type LoopOutRequest struct {
|
||||
//
|
||||
//Requested swap amount in sat. This does not include the swap and miner fee.
|
||||
|
|
@ -1954,20 +2047,75 @@ func (m *SuggestSwapsRequest) XXX_DiscardUnknown() {
|
|||
|
||||
var xxx_messageInfo_SuggestSwapsRequest proto.InternalMessageInfo
|
||||
|
||||
type Disqualified struct {
|
||||
//
|
||||
//The short channel ID of the channel that was excluded from our suggestions.
|
||||
ChannelId uint64 `protobuf:"varint,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
|
||||
//
|
||||
//The reason that we excluded the channel from the our suggestions.
|
||||
Reason AutoReason `protobuf:"varint,2,opt,name=reason,proto3,enum=looprpc.AutoReason" json:"reason,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Disqualified) Reset() { *m = Disqualified{} }
|
||||
func (m *Disqualified) String() string { return proto.CompactTextString(m) }
|
||||
func (*Disqualified) ProtoMessage() {}
|
||||
func (*Disqualified) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_014de31d7ac8c57c, []int{23}
|
||||
}
|
||||
|
||||
func (m *Disqualified) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Disqualified.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Disqualified) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Disqualified.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Disqualified) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Disqualified.Merge(m, src)
|
||||
}
|
||||
func (m *Disqualified) XXX_Size() int {
|
||||
return xxx_messageInfo_Disqualified.Size(m)
|
||||
}
|
||||
func (m *Disqualified) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Disqualified.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Disqualified proto.InternalMessageInfo
|
||||
|
||||
func (m *Disqualified) GetChannelId() uint64 {
|
||||
if m != nil {
|
||||
return m.ChannelId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *Disqualified) GetReason() AutoReason {
|
||||
if m != nil {
|
||||
return m.Reason
|
||||
}
|
||||
return AutoReason_AUTO_REASON_UNKNOWN
|
||||
}
|
||||
|
||||
type SuggestSwapsResponse struct {
|
||||
//
|
||||
//The set of recommended loop outs.
|
||||
LoopOut []*LoopOutRequest `protobuf:"bytes,1,rep,name=loop_out,json=loopOut,proto3" json:"loop_out,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
LoopOut []*LoopOutRequest `protobuf:"bytes,1,rep,name=loop_out,json=loopOut,proto3" json:"loop_out,omitempty"`
|
||||
//
|
||||
//Disqualified contains the set of channels that swaps are not recommended
|
||||
//for.
|
||||
Disqualified []*Disqualified `protobuf:"bytes,2,rep,name=disqualified,proto3" json:"disqualified,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *SuggestSwapsResponse) Reset() { *m = SuggestSwapsResponse{} }
|
||||
func (m *SuggestSwapsResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*SuggestSwapsResponse) ProtoMessage() {}
|
||||
func (*SuggestSwapsResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_014de31d7ac8c57c, []int{23}
|
||||
return fileDescriptor_014de31d7ac8c57c, []int{24}
|
||||
}
|
||||
|
||||
func (m *SuggestSwapsResponse) XXX_Unmarshal(b []byte) error {
|
||||
|
|
@ -1995,11 +2143,19 @@ func (m *SuggestSwapsResponse) GetLoopOut() []*LoopOutRequest {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *SuggestSwapsResponse) GetDisqualified() []*Disqualified {
|
||||
if m != nil {
|
||||
return m.Disqualified
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("looprpc.SwapType", SwapType_name, SwapType_value)
|
||||
proto.RegisterEnum("looprpc.SwapState", SwapState_name, SwapState_value)
|
||||
proto.RegisterEnum("looprpc.FailureReason", FailureReason_name, FailureReason_value)
|
||||
proto.RegisterEnum("looprpc.LiquidityRuleType", LiquidityRuleType_name, LiquidityRuleType_value)
|
||||
proto.RegisterEnum("looprpc.AutoReason", AutoReason_name, AutoReason_value)
|
||||
proto.RegisterType((*LoopOutRequest)(nil), "looprpc.LoopOutRequest")
|
||||
proto.RegisterType((*LoopInRequest)(nil), "looprpc.LoopInRequest")
|
||||
proto.RegisterType((*SwapResponse)(nil), "looprpc.SwapResponse")
|
||||
|
|
@ -2023,163 +2179,177 @@ func init() {
|
|||
proto.RegisterType((*SetLiquidityParamsRequest)(nil), "looprpc.SetLiquidityParamsRequest")
|
||||
proto.RegisterType((*SetLiquidityParamsResponse)(nil), "looprpc.SetLiquidityParamsResponse")
|
||||
proto.RegisterType((*SuggestSwapsRequest)(nil), "looprpc.SuggestSwapsRequest")
|
||||
proto.RegisterType((*Disqualified)(nil), "looprpc.Disqualified")
|
||||
proto.RegisterType((*SuggestSwapsResponse)(nil), "looprpc.SuggestSwapsResponse")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("client.proto", fileDescriptor_014de31d7ac8c57c) }
|
||||
|
||||
var fileDescriptor_014de31d7ac8c57c = []byte{
|
||||
// 2389 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcd, 0x6f, 0xe3, 0xc6,
|
||||
0x15, 0x5f, 0x7d, 0x59, 0xd2, 0x13, 0x45, 0xd1, 0xe3, 0x5d, 0x5b, 0x56, 0x1c, 0xc4, 0xcb, 0x64,
|
||||
0x1b, 0xc7, 0x49, 0xac, 0xc6, 0x39, 0x25, 0x48, 0x0a, 0x68, 0x65, 0x39, 0x96, 0x6b, 0x4b, 0x2a,
|
||||
0x25, 0x6f, 0x90, 0xa2, 0x00, 0x31, 0x96, 0xc6, 0x16, 0x11, 0xf1, 0x23, 0xe4, 0x68, 0xd7, 0x46,
|
||||
0xd0, 0x16, 0x28, 0xd0, 0x73, 0x0f, 0xfd, 0x0f, 0x7a, 0xef, 0xad, 0xb7, 0xf6, 0xde, 0x4b, 0x4f,
|
||||
0xed, 0xb1, 0xd7, 0x5e, 0x7a, 0xe8, 0xff, 0x50, 0xcc, 0x1b, 0x92, 0x22, 0x65, 0xc9, 0x41, 0x0f,
|
||||
0xbd, 0x89, 0xef, 0xfd, 0xe6, 0xcd, 0x9b, 0xf7, 0xfd, 0x04, 0xca, 0x78, 0x66, 0x31, 0x87, 0x1f,
|
||||
0x79, 0xbe, 0xcb, 0x5d, 0x52, 0x9c, 0xb9, 0xae, 0xe7, 0x7b, 0xe3, 0xc6, 0xde, 0xad, 0xeb, 0xde,
|
||||
0xce, 0x58, 0x93, 0x7a, 0x56, 0x93, 0x3a, 0x8e, 0xcb, 0x29, 0xb7, 0x5c, 0x27, 0x90, 0x30, 0xfd,
|
||||
0x8f, 0x79, 0x50, 0x2f, 0x5c, 0xd7, 0xeb, 0xcf, 0xb9, 0xc1, 0xbe, 0x9b, 0xb3, 0x80, 0x13, 0x0d,
|
||||
0x72, 0xd4, 0xe6, 0xf5, 0xcc, 0x7e, 0xe6, 0x20, 0x67, 0x88, 0x9f, 0x84, 0x40, 0x7e, 0xc2, 0x02,
|
||||
0x5e, 0xcf, 0xee, 0x67, 0x0e, 0xca, 0x06, 0xfe, 0x26, 0x4d, 0x78, 0x6a, 0xd3, 0x3b, 0x33, 0x78,
|
||||
0x43, 0x3d, 0xd3, 0x77, 0xe7, 0xdc, 0x72, 0x6e, 0xcd, 0x1b, 0xc6, 0xea, 0x39, 0x3c, 0xb6, 0x69,
|
||||
0xd3, 0xbb, 0xe1, 0x1b, 0xea, 0x19, 0x92, 0x73, 0xca, 0x18, 0xf9, 0x14, 0xb6, 0xc5, 0x01, 0xcf,
|
||||
0x67, 0x1e, 0xbd, 0x4f, 0x1d, 0xc9, 0xe3, 0x91, 0x2d, 0x9b, 0xde, 0x0d, 0x90, 0x99, 0x38, 0xb4,
|
||||
0x0f, 0x4a, 0x7c, 0x8b, 0x80, 0x16, 0x10, 0x0a, 0xa1, 0x74, 0x81, 0x78, 0x0f, 0xd4, 0x84, 0x58,
|
||||
0xa1, 0xf8, 0x06, 0x62, 0x94, 0x58, 0x5c, 0xcb, 0xe6, 0x44, 0x87, 0xaa, 0x40, 0xd9, 0x96, 0xc3,
|
||||
0x7c, 0x14, 0x54, 0x44, 0x50, 0xc5, 0xa6, 0x77, 0x97, 0x82, 0x26, 0x24, 0x7d, 0x04, 0x9a, 0xb0,
|
||||
0x99, 0xe9, 0xce, 0xb9, 0x39, 0x9e, 0x52, 0xc7, 0x61, 0xb3, 0x7a, 0x69, 0x3f, 0x73, 0x90, 0x7f,
|
||||
0x99, 0xad, 0x67, 0x0c, 0x75, 0x26, 0xad, 0xd4, 0x96, 0x1c, 0x72, 0x08, 0x9b, 0xee, 0x9c, 0xdf,
|
||||
0xba, 0xe2, 0x11, 0x02, 0x6d, 0x06, 0x8c, 0xd7, 0x2b, 0xfb, 0xb9, 0x83, 0xbc, 0x51, 0x8b, 0x18,
|
||||
0x02, 0x3b, 0x64, 0x5c, 0x60, 0x83, 0x37, 0x8c, 0x79, 0xe6, 0xd8, 0x75, 0x6e, 0x4c, 0x4e, 0xfd,
|
||||
0x5b, 0xc6, 0xeb, 0xe5, 0xfd, 0xcc, 0x41, 0xc1, 0xa8, 0x21, 0xa3, 0xed, 0x3a, 0x37, 0x23, 0x24,
|
||||
0x93, 0x8f, 0x81, 0x4c, 0xf9, 0x6c, 0x8c, 0x50, 0xcb, 0xb7, 0xa5, 0xb3, 0xea, 0x55, 0x04, 0x6f,
|
||||
0x0a, 0x4e, 0x3b, 0xc9, 0x20, 0x9f, 0xc3, 0x2e, 0x1a, 0xc7, 0x9b, 0x5f, 0xcf, 0xac, 0x31, 0x12,
|
||||
0xcd, 0x09, 0xa3, 0x93, 0x99, 0xe5, 0xb0, 0x3a, 0x08, 0xed, 0x8d, 0x1d, 0x01, 0x18, 0x2c, 0xf8,
|
||||
0x27, 0x21, 0x9b, 0x3c, 0x85, 0xc2, 0x8c, 0x5e, 0xb3, 0x59, 0x5d, 0x41, 0xbf, 0xca, 0x0f, 0xb2,
|
||||
0x07, 0x65, 0xcb, 0xb1, 0xb8, 0x45, 0xb9, 0xeb, 0xd7, 0x55, 0xe4, 0x2c, 0x08, 0xfa, 0x6f, 0xb3,
|
||||
0x50, 0x15, 0xf1, 0xd2, 0x75, 0xd6, 0x87, 0xcb, 0xb2, 0xd3, 0xb2, 0x0f, 0x9c, 0xf6, 0xc0, 0x1d,
|
||||
0xb9, 0x87, 0xee, 0xd8, 0x85, 0xd2, 0x8c, 0x06, 0xdc, 0x9c, 0xba, 0x1e, 0x46, 0x88, 0x62, 0x14,
|
||||
0xc5, 0xf7, 0x99, 0xeb, 0x91, 0x77, 0xa1, 0xca, 0xee, 0x38, 0xf3, 0x1d, 0x3a, 0x33, 0x85, 0x49,
|
||||
0x30, 0x2c, 0x4a, 0x86, 0x12, 0x11, 0xcf, 0xf8, 0x6c, 0x4c, 0x0e, 0x40, 0x8b, 0x0d, 0x19, 0xd9,
|
||||
0x7c, 0x03, 0xcd, 0xa8, 0x46, 0x66, 0x0c, 0x4d, 0x1e, 0xdb, 0xa1, 0xb8, 0xd6, 0x0e, 0xa5, 0x65,
|
||||
0x3b, 0xfc, 0x3b, 0x03, 0x0a, 0x06, 0x38, 0x0b, 0x3c, 0xd7, 0x09, 0x18, 0x21, 0x90, 0xb5, 0x26,
|
||||
0x68, 0x85, 0x32, 0xc6, 0x4b, 0xd6, 0x9a, 0x88, 0x27, 0x58, 0x13, 0xf3, 0xfa, 0x9e, 0xb3, 0x00,
|
||||
0x5f, 0xa8, 0x18, 0x45, 0x6b, 0xf2, 0x52, 0x7c, 0x92, 0x17, 0xa0, 0xa0, 0x76, 0x74, 0x32, 0xf1,
|
||||
0x59, 0x10, 0xc8, 0xd4, 0xc2, 0x83, 0x15, 0x41, 0x6f, 0x49, 0x32, 0x39, 0x82, 0xad, 0x24, 0xcc,
|
||||
0x74, 0xbc, 0xe3, 0x37, 0xc1, 0x14, 0xed, 0x51, 0x96, 0xe1, 0x10, 0x22, 0x7b, 0xc8, 0x20, 0x1f,
|
||||
0x85, 0xd1, 0x13, 0xe1, 0x25, 0xbc, 0x80, 0x70, 0x2d, 0x01, 0x1f, 0x20, 0xfa, 0x05, 0xa8, 0x01,
|
||||
0xf3, 0x5f, 0x33, 0xdf, 0xb4, 0x59, 0x10, 0xd0, 0x5b, 0x86, 0x06, 0x2a, 0x1b, 0x55, 0x49, 0xbd,
|
||||
0x94, 0x44, 0x5d, 0x03, 0xf5, 0xd2, 0x75, 0x2c, 0xee, 0xfa, 0xa1, 0xcf, 0xf5, 0x3f, 0xe5, 0x01,
|
||||
0xc4, 0xeb, 0x87, 0x9c, 0xf2, 0x79, 0xb0, 0xb2, 0x62, 0x08, 0x6b, 0x64, 0xd7, 0x5a, 0xa3, 0xb2,
|
||||
0x6c, 0x8d, 0x3c, 0xbf, 0xf7, 0x64, 0x18, 0xa8, 0xc7, 0x9b, 0x47, 0x61, 0xed, 0x3a, 0x12, 0x77,
|
||||
0x8c, 0xee, 0x3d, 0x66, 0x20, 0x9b, 0x1c, 0x40, 0x21, 0xe0, 0x94, 0xcb, 0x8a, 0xa1, 0x1e, 0x93,
|
||||
0x14, 0x4e, 0xe8, 0xc2, 0x0c, 0x09, 0x20, 0x5f, 0x82, 0x7a, 0x43, 0xad, 0xd9, 0xdc, 0x67, 0xa6,
|
||||
0xcf, 0x68, 0xe0, 0x3a, 0x18, 0xc9, 0xea, 0xf1, 0x76, 0x7c, 0xe4, 0x54, 0xb2, 0x0d, 0xe4, 0x1a,
|
||||
0xd5, 0x9b, 0xe4, 0x27, 0x79, 0x1f, 0x6a, 0xa1, 0xab, 0x45, 0x3e, 0x71, 0xcb, 0x8e, 0x2a, 0x8f,
|
||||
0xba, 0x20, 0x8f, 0x2c, 0x5b, 0x68, 0xa4, 0x61, 0x90, 0xce, 0xbd, 0x09, 0xe5, 0x4c, 0x22, 0x65,
|
||||
0xfd, 0x51, 0x05, 0xfd, 0x0a, 0xc9, 0x88, 0x5c, 0x76, 0x78, 0x71, 0xb5, 0xc3, 0x57, 0x3b, 0x50,
|
||||
0x59, 0xe3, 0xc0, 0x35, 0xe1, 0x51, 0x5d, 0x17, 0x1e, 0xef, 0x40, 0x65, 0xec, 0x06, 0xdc, 0x94,
|
||||
0xfe, 0xc5, 0xa8, 0xce, 0x19, 0x20, 0x48, 0x43, 0xa4, 0x90, 0xe7, 0xa0, 0x20, 0xc0, 0x75, 0xc6,
|
||||
0x53, 0x6a, 0x39, 0x58, 0xa4, 0x72, 0x06, 0x1e, 0xea, 0x4b, 0x92, 0x48, 0x3e, 0x09, 0xb9, 0xb9,
|
||||
0x91, 0x18, 0x90, 0xf5, 0x16, 0x31, 0x21, 0x6d, 0x91, 0x52, 0xb5, 0x44, 0x4a, 0xe9, 0x04, 0xb4,
|
||||
0x0b, 0x2b, 0xe0, 0xc2, 0x5b, 0x41, 0x14, 0x4a, 0x3f, 0x81, 0xcd, 0x04, 0x2d, 0x4c, 0xa6, 0x0f,
|
||||
0xa0, 0x20, 0xaa, 0x47, 0x50, 0xcf, 0xec, 0xe7, 0x0e, 0x2a, 0xc7, 0x5b, 0x0f, 0x1c, 0x3d, 0x0f,
|
||||
0x0c, 0x89, 0xd0, 0x9f, 0x43, 0x4d, 0x10, 0xbb, 0xce, 0x8d, 0x1b, 0x55, 0x24, 0x35, 0x4e, 0x45,
|
||||
0x45, 0x04, 0x9e, 0xae, 0x82, 0x32, 0x62, 0xbe, 0x1d, 0x5f, 0xf9, 0x6b, 0xa8, 0x75, 0x9d, 0x90,
|
||||
0x12, 0x5e, 0xf8, 0x23, 0xa8, 0xd9, 0x96, 0x23, 0x4b, 0x16, 0xb5, 0xdd, 0xb9, 0xc3, 0x43, 0x87,
|
||||
0x57, 0x6d, 0xcb, 0x11, 0xf2, 0x5b, 0x48, 0x44, 0x5c, 0x54, 0xda, 0x42, 0xdc, 0x46, 0x88, 0x93,
|
||||
0xd5, 0x4d, 0xe2, 0xce, 0xf3, 0xa5, 0x8c, 0x96, 0x3d, 0xcf, 0x97, 0xb2, 0x5a, 0xee, 0x3c, 0x5f,
|
||||
0xca, 0x69, 0xf9, 0xf3, 0x7c, 0x29, 0xaf, 0x15, 0xce, 0xf3, 0xa5, 0xa2, 0x56, 0xd2, 0xff, 0x96,
|
||||
0x01, 0xad, 0x3f, 0xe7, 0xff, 0x57, 0x15, 0xb0, 0x31, 0x5a, 0x8e, 0x39, 0x9e, 0xf1, 0xd7, 0xe6,
|
||||
0x84, 0xcd, 0x38, 0x45, 0x77, 0x17, 0x0c, 0xc5, 0xb6, 0x9c, 0xf6, 0x8c, 0xbf, 0x3e, 0x11, 0xb4,
|
||||
0xa8, 0x7d, 0x26, 0x50, 0xe5, 0x10, 0x45, 0xef, 0x62, 0xd4, 0x0f, 0x3c, 0xe7, 0x0f, 0x19, 0x50,
|
||||
0x7e, 0x36, 0x77, 0x39, 0x5b, 0xdf, 0x12, 0x30, 0xf0, 0x16, 0x75, 0x38, 0x8b, 0x77, 0xc0, 0x78,
|
||||
0x51, 0x83, 0x1f, 0x94, 0xf4, 0xdc, 0x8a, 0x92, 0xfe, 0x68, 0xb3, 0xcb, 0x3f, 0xda, 0xec, 0xf4,
|
||||
0xdf, 0x65, 0x84, 0xd7, 0x43, 0x35, 0x43, 0x93, 0xef, 0x83, 0x12, 0x35, 0x29, 0x33, 0xa0, 0x91,
|
||||
0xc2, 0x10, 0xc8, 0x2e, 0x35, 0xa4, 0x38, 0xe5, 0x60, 0x82, 0xe1, 0x8d, 0xc1, 0x34, 0x46, 0x86,
|
||||
0x53, 0x8e, 0xe0, 0x0d, 0x24, 0x2b, 0x3c, 0xf0, 0x36, 0x40, 0xc2, 0x96, 0x05, 0x7c, 0x67, 0x79,
|
||||
0x9c, 0x30, 0xa4, 0x34, 0x61, 0x5e, 0x2b, 0xe8, 0x7f, 0x97, 0x51, 0xf0, 0xbf, 0xaa, 0xf4, 0x1e,
|
||||
0xa8, 0x8b, 0x61, 0x07, 0x31, 0xb2, 0xbf, 0x2a, 0x5e, 0x34, 0xed, 0x08, 0xd4, 0x87, 0x61, 0x1d,
|
||||
0x91, 0x73, 0x47, 0x5a, 0xed, 0x9a, 0xe0, 0x0c, 0x05, 0x23, 0x14, 0x89, 0xf3, 0x89, 0xb0, 0x2b,
|
||||
0xbd, 0xb7, 0x99, 0xc3, 0x4d, 0x1c, 0xf6, 0x64, 0xcf, 0xad, 0xa1, 0x3d, 0x25, 0xfd, 0x44, 0xf8,
|
||||
0xf6, 0xf1, 0x07, 0xea, 0x35, 0xa8, 0x8e, 0xdc, 0x6f, 0x99, 0x13, 0x27, 0xdb, 0x17, 0xa0, 0x46,
|
||||
0x84, 0xf0, 0x89, 0x87, 0xb0, 0xc1, 0x91, 0x12, 0x66, 0xf7, 0xa2, 0x8c, 0x5f, 0x04, 0x94, 0x23,
|
||||
0xd8, 0x08, 0x11, 0xfa, 0x9f, 0xb3, 0x50, 0x8e, 0xa9, 0x22, 0x48, 0xae, 0x69, 0xc0, 0x4c, 0x9b,
|
||||
0x8e, 0xa9, 0xef, 0xba, 0x4e, 0x98, 0xe3, 0x8a, 0x20, 0x5e, 0x86, 0x34, 0x51, 0xc2, 0xa2, 0x77,
|
||||
0x4c, 0x69, 0x30, 0x45, 0xeb, 0x28, 0x46, 0x25, 0xa4, 0x9d, 0xd1, 0x60, 0x4a, 0x3e, 0x00, 0x2d,
|
||||
0x82, 0x78, 0x3e, 0xb3, 0x6c, 0xd1, 0xf9, 0x64, 0x7f, 0xae, 0x85, 0xf4, 0x41, 0x48, 0x16, 0x05,
|
||||
0x5e, 0x26, 0x99, 0xe9, 0x51, 0x6b, 0x62, 0xda, 0xc2, 0x8a, 0x72, 0x5e, 0x55, 0x25, 0x7d, 0x40,
|
||||
0xad, 0xc9, 0x65, 0x40, 0x39, 0xf9, 0x04, 0x9e, 0x25, 0x86, 0xda, 0x04, 0x5c, 0x66, 0x31, 0xf1,
|
||||
0xe3, 0xa9, 0x36, 0x3e, 0xf2, 0x1c, 0x14, 0xd1, 0x31, 0xcc, 0xb1, 0xcf, 0x28, 0x67, 0x93, 0x30,
|
||||
0x8f, 0x2b, 0x82, 0xd6, 0x96, 0x24, 0x52, 0x87, 0x22, 0xbb, 0xf3, 0x2c, 0x9f, 0x4d, 0xb0, 0x63,
|
||||
0x94, 0x8c, 0xe8, 0x53, 0x1c, 0x0e, 0xb8, 0xeb, 0xd3, 0x5b, 0x66, 0x3a, 0xd4, 0x66, 0xe1, 0x88,
|
||||
0x52, 0x09, 0x69, 0x3d, 0x6a, 0x33, 0xfd, 0x2d, 0xd8, 0xfd, 0x8a, 0xf1, 0x0b, 0xeb, 0xbb, 0xb9,
|
||||
0x35, 0xb1, 0xf8, 0xfd, 0x80, 0xfa, 0x74, 0x51, 0x05, 0xff, 0x5a, 0x80, 0xad, 0x34, 0x8b, 0x71,
|
||||
0xe6, 0x8b, 0x0e, 0x54, 0xf0, 0xe7, 0x33, 0x16, 0x79, 0x67, 0xd1, 0x31, 0x63, 0xb0, 0x31, 0x9f,
|
||||
0x31, 0x43, 0x82, 0xc8, 0x97, 0xb0, 0xb7, 0x08, 0x31, 0x5f, 0xf4, 0xc0, 0x80, 0x72, 0xd3, 0x63,
|
||||
0xbe, 0xf9, 0x5a, 0x74, 0x7a, 0xb4, 0x3e, 0x66, 0xa5, 0x8c, 0x36, 0x83, 0x72, 0x11, 0x71, 0x03,
|
||||
0xe6, 0xbf, 0x12, 0x6c, 0xf2, 0x3e, 0x68, 0xc9, 0x51, 0xd1, 0xf4, 0x3c, 0x1b, 0x3d, 0x91, 0x8f,
|
||||
0xab, 0x99, 0xb0, 0x97, 0x67, 0x93, 0x8f, 0x41, 0xec, 0x07, 0x66, 0xca, 0xc2, 0x9e, 0x1d, 0x26,
|
||||
0xbd, 0x90, 0xb1, 0x58, 0x1a, 0x04, 0xfc, 0x73, 0x68, 0xac, 0x5e, 0x36, 0xf0, 0x54, 0x01, 0x4f,
|
||||
0x6d, 0xaf, 0x58, 0x38, 0xc4, 0xd9, 0xf4, 0x46, 0x21, 0x3c, 0xb8, 0x81, 0xf8, 0xc5, 0x46, 0x21,
|
||||
0x72, 0xe6, 0x03, 0xd8, 0x4c, 0x8d, 0xb0, 0x08, 0x2c, 0x22, 0x50, 0x4d, 0x8c, 0xb1, 0x71, 0x7a,
|
||||
0x2d, 0x8f, 0xff, 0xa5, 0xd5, 0xe3, 0xff, 0x11, 0x6c, 0x45, 0x83, 0xcb, 0x35, 0x1d, 0x7f, 0xeb,
|
||||
0xde, 0xdc, 0x98, 0x01, 0x1b, 0x63, 0x51, 0xce, 0x1b, 0x9b, 0x21, 0xeb, 0xa5, 0xe4, 0x0c, 0xd9,
|
||||
0x98, 0x34, 0xa0, 0x44, 0xe7, 0xdc, 0x15, 0x3e, 0xc2, 0x46, 0x5c, 0x32, 0xe2, 0x6f, 0x21, 0x2b,
|
||||
0xfa, 0x6d, 0x5e, 0xcf, 0x27, 0xb7, 0x4c, 0x96, 0x8b, 0x8a, 0x94, 0x15, 0xb1, 0x5e, 0x22, 0x47,
|
||||
0xe8, 0xf9, 0x19, 0xec, 0x3e, 0xc0, 0x73, 0xea, 0x73, 0xd4, 0x40, 0x91, 0x36, 0x5b, 0x3a, 0x25,
|
||||
0xd8, 0x42, 0x8d, 0x0f, 0x81, 0x08, 0x8e, 0x29, 0x4c, 0x62, 0x39, 0xe6, 0xcd, 0xcc, 0xba, 0x9d,
|
||||
0x72, 0x9c, 0x43, 0xf2, 0x46, 0x4d, 0x70, 0x2e, 0xe9, 0x5d, 0xd7, 0x39, 0x45, 0xf2, 0xaa, 0x4e,
|
||||
0xa7, 0x86, 0x3e, 0xff, 0xa1, 0x4e, 0x57, 0x4b, 0xc5, 0x86, 0xc4, 0xe9, 0x7f, 0xc9, 0x40, 0x35,
|
||||
0x15, 0x9c, 0x58, 0xa4, 0xe4, 0x9e, 0x66, 0x86, 0x93, 0x40, 0xde, 0x28, 0x87, 0x94, 0xee, 0x84,
|
||||
0x1c, 0x85, 0xe3, 0x66, 0x16, 0x67, 0xc2, 0xc6, 0xea, 0x08, 0x4f, 0xcc, 0x9d, 0x1f, 0x03, 0xb1,
|
||||
0x9c, 0xb1, 0x6b, 0x8b, 0x18, 0xe2, 0x53, 0x9f, 0x05, 0x53, 0x77, 0x36, 0xc1, 0x38, 0xad, 0x1a,
|
||||
0x9b, 0x11, 0x67, 0x14, 0x31, 0x04, 0x3c, 0x5e, 0x0d, 0x17, 0xf0, 0xbc, 0x84, 0x47, 0x9c, 0x18,
|
||||
0xae, 0x7f, 0x03, 0xbb, 0xc3, 0x75, 0x59, 0x4a, 0xbe, 0x00, 0xf0, 0xe2, 0xdc, 0xc4, 0x97, 0x54,
|
||||
0x8e, 0xf7, 0x1e, 0x2a, 0xbc, 0xc8, 0x5f, 0x23, 0x81, 0xd7, 0xf7, 0xa0, 0xb1, 0x4a, 0xb4, 0x2c,
|
||||
0xc4, 0xfa, 0x33, 0xd8, 0x1a, 0xce, 0x6f, 0x6f, 0xd9, 0xd2, 0x44, 0x76, 0x0e, 0x4f, 0xd3, 0xe4,
|
||||
0xb0, 0x6e, 0x1f, 0x43, 0x29, 0xda, 0x8f, 0xc3, 0xda, 0xb0, 0xb3, 0x50, 0x24, 0xf5, 0x17, 0x82,
|
||||
0x51, 0x0c, 0x97, 0xe5, 0xc3, 0x17, 0x50, 0x8a, 0x66, 0x78, 0xa2, 0x40, 0xe9, 0xa2, 0xdf, 0x1f,
|
||||
0x98, 0xfd, 0xab, 0x91, 0xf6, 0x84, 0x54, 0xa0, 0x88, 0x5f, 0xdd, 0x9e, 0x96, 0x39, 0x0c, 0xa0,
|
||||
0x1c, 0x8f, 0xf0, 0xa4, 0x0a, 0xe5, 0x6e, 0xaf, 0x3b, 0xea, 0xb6, 0x46, 0x9d, 0x13, 0xed, 0x09,
|
||||
0x79, 0x06, 0x9b, 0x03, 0xa3, 0xd3, 0xbd, 0x6c, 0x7d, 0xd5, 0x31, 0x8d, 0xce, 0xab, 0x4e, 0xeb,
|
||||
0xa2, 0x73, 0xa2, 0x65, 0x08, 0x01, 0xf5, 0x6c, 0x74, 0xd1, 0x36, 0x07, 0x57, 0x2f, 0x2f, 0xba,
|
||||
0xc3, 0xb3, 0xce, 0x89, 0x96, 0x15, 0x32, 0x87, 0x57, 0xed, 0x76, 0x67, 0x38, 0xd4, 0x72, 0x04,
|
||||
0x60, 0xe3, 0xb4, 0xd5, 0x15, 0xe0, 0x3c, 0xd9, 0x82, 0x5a, 0xb7, 0xf7, 0xaa, 0xdf, 0x6d, 0x77,
|
||||
0xcc, 0x61, 0x67, 0x34, 0x12, 0xc4, 0xc2, 0xe1, 0x7f, 0x32, 0x50, 0x4d, 0x6d, 0x01, 0x64, 0x07,
|
||||
0xb6, 0xc4, 0x91, 0x2b, 0x43, 0xdc, 0xd4, 0x1a, 0xf6, 0x7b, 0x66, 0xaf, 0xdf, 0xeb, 0x68, 0x4f,
|
||||
0xc8, 0x5b, 0xb0, 0xb3, 0xc4, 0xe8, 0x9f, 0x9e, 0xb6, 0xcf, 0x5a, 0x42, 0x79, 0xd2, 0x80, 0xed,
|
||||
0x25, 0xe6, 0xa8, 0x7b, 0xd9, 0x11, 0xaf, 0xcc, 0x92, 0x7d, 0xd8, 0x5b, 0xe2, 0x0d, 0xbf, 0xee,
|
||||
0x74, 0x06, 0x31, 0x22, 0x47, 0x5e, 0xc0, 0xf3, 0x25, 0x44, 0xb7, 0x37, 0xbc, 0x3a, 0x3d, 0xed,
|
||||
0xb6, 0xbb, 0x9d, 0xde, 0xc8, 0x7c, 0xd5, 0xba, 0xb8, 0xea, 0x68, 0x79, 0xb2, 0x07, 0xf5, 0xe5,
|
||||
0x4b, 0x3a, 0x97, 0x83, 0xbe, 0xd1, 0x32, 0xbe, 0xd1, 0x0a, 0xe4, 0x5d, 0x78, 0xe7, 0x81, 0x90,
|
||||
0x76, 0xdf, 0x30, 0x3a, 0xed, 0x91, 0xd9, 0xba, 0xec, 0x5f, 0xf5, 0x46, 0xda, 0xc6, 0x61, 0x53,
|
||||
0x4c, 0xda, 0x4b, 0x01, 0x2e, 0x4c, 0x76, 0xd5, 0xfb, 0x69, 0xaf, 0xff, 0x75, 0x4f, 0x7b, 0x22,
|
||||
0x2c, 0x3f, 0x3a, 0x33, 0x3a, 0xc3, 0xb3, 0xfe, 0xc5, 0x89, 0x96, 0x39, 0xfe, 0x67, 0x59, 0x6e,
|
||||
0x79, 0x6d, 0xfc, 0x5f, 0x89, 0x18, 0x50, 0x0c, 0xdd, 0x4c, 0xd6, 0x39, 0xbe, 0xf1, 0x2c, 0x35,
|
||||
0xa9, 0xc7, 0x91, 0xb6, 0xf3, 0x9b, 0x7f, 0xfc, 0xeb, 0xf7, 0xd9, 0x4d, 0x5d, 0x69, 0xbe, 0xfe,
|
||||
0xa4, 0x29, 0x10, 0x4d, 0x77, 0xce, 0x3f, 0xcf, 0x1c, 0x92, 0x3e, 0x6c, 0xc8, 0x7f, 0x13, 0xc8,
|
||||
0x76, 0x4a, 0x64, 0xfc, 0xf7, 0xc2, 0x3a, 0x89, 0xdb, 0x28, 0x51, 0xd3, 0x2b, 0xb1, 0x44, 0xcb,
|
||||
0x11, 0x02, 0x3f, 0x83, 0x62, 0xb8, 0xab, 0x26, 0x94, 0x4c, 0x6f, 0xaf, 0x8d, 0x55, 0xeb, 0xc4,
|
||||
0x8f, 0x33, 0xe4, 0xe7, 0x50, 0x8e, 0x37, 0x11, 0xb2, 0x9b, 0xc8, 0xb1, 0x74, 0x7e, 0x34, 0x1a,
|
||||
0xab, 0x58, 0x69, 0xb5, 0x88, 0x1a, 0xab, 0x85, 0x5b, 0x0a, 0xb9, 0x92, 0x79, 0x20, 0xb6, 0x14,
|
||||
0x52, 0x4f, 0x5d, 0x9f, 0x58, 0x5c, 0x56, 0x2a, 0xa6, 0x37, 0x50, 0xe4, 0x53, 0x42, 0x52, 0x22,
|
||||
0x9b, 0xdf, 0x5b, 0x93, 0x5f, 0x92, 0x5f, 0x80, 0x12, 0x3a, 0x00, 0x77, 0x09, 0xb2, 0x30, 0x56,
|
||||
0x72, 0xe1, 0x69, 0x2c, 0x1e, 0xb3, 0xbc, 0x75, 0xac, 0x90, 0xee, 0xce, 0x79, 0x93, 0xa3, 0xb4,
|
||||
0xeb, 0x58, 0x3a, 0xce, 0xa8, 0x09, 0xe9, 0xc9, 0x69, 0x3f, 0x2d, 0x3d, 0x35, 0xcd, 0xea, 0xfb,
|
||||
0x28, 0xbd, 0x41, 0xea, 0x29, 0xe9, 0xdf, 0x09, 0x4c, 0xf3, 0x7b, 0x6a, 0x73, 0xf1, 0x02, 0x55,
|
||||
0x8c, 0x28, 0xe8, 0xf2, 0x47, 0xdf, 0xb0, 0xb0, 0xda, 0xd2, 0xee, 0xa6, 0xef, 0xe2, 0x25, 0x5b,
|
||||
0x64, 0x33, 0x11, 0x0a, 0xf1, 0x0b, 0x16, 0xd2, 0x1f, 0x7d, 0x43, 0x52, 0x7a, 0xfa, 0x09, 0xef,
|
||||
0xa0, 0xf4, 0x5d, 0xb2, 0x93, 0x94, 0x9e, 0x7c, 0xc1, 0x37, 0x50, 0x15, 0x77, 0x44, 0x43, 0x6a,
|
||||
0x90, 0x88, 0xe4, 0xd4, 0x24, 0xdc, 0xd8, 0x79, 0x40, 0x4f, 0x67, 0x07, 0xa9, 0xe1, 0x15, 0x01,
|
||||
0xe5, 0x4d, 0x39, 0xfd, 0x12, 0x0e, 0xe4, 0xe1, 0xfc, 0x46, 0xf4, 0x58, 0xce, 0xda, 0xe1, 0xae,
|
||||
0xf1, 0x68, 0x8b, 0xd0, 0xf7, 0xf0, 0xc2, 0x6d, 0xf2, 0x14, 0x2f, 0x8c, 0x00, 0x4d, 0x4f, 0xca,
|
||||
0xff, 0x15, 0x90, 0xe1, 0x63, 0xb7, 0xae, 0x6d, 0x56, 0x8d, 0x77, 0x1f, 0xc5, 0xa4, 0x0d, 0xaa,
|
||||
0xaf, 0xbc, 0x5c, 0xa4, 0x30, 0x03, 0x25, 0xd9, 0x7f, 0xc8, 0xe2, 0x2d, 0x2b, 0xba, 0x55, 0xe3,
|
||||
0xed, 0x35, 0xdc, 0xf0, 0xb6, 0x3a, 0xde, 0x46, 0x88, 0x26, 0x6e, 0x13, 0x83, 0x48, 0x33, 0x90,
|
||||
0xb0, 0xeb, 0x0d, 0xfc, 0x03, 0xfc, 0xd3, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xe8, 0x03, 0x91,
|
||||
0x2d, 0x37, 0x17, 0x00, 0x00,
|
||||
// 2605 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x59, 0x4b, 0x73, 0x1b, 0xc7,
|
||||
0xf1, 0x17, 0x5e, 0x04, 0xd0, 0x58, 0x00, 0xcb, 0xa1, 0x44, 0x82, 0x30, 0x6d, 0x51, 0x6b, 0xeb,
|
||||
0x6f, 0x9a, 0xb6, 0xc5, 0xbf, 0xe9, 0x93, 0x5d, 0x76, 0xaa, 0x40, 0x70, 0x29, 0x42, 0x26, 0x01,
|
||||
0x78, 0x01, 0xc8, 0x25, 0x57, 0xaa, 0xb6, 0x86, 0xc0, 0x90, 0xdc, 0x32, 0xf6, 0xa1, 0xdd, 0x81,
|
||||
0x44, 0x95, 0x2b, 0x49, 0x55, 0x2a, 0x3e, 0xe7, 0x90, 0x6f, 0x90, 0x7b, 0x6e, 0xb9, 0x25, 0xf7,
|
||||
0x5c, 0x72, 0x4a, 0x8e, 0xb9, 0xe6, 0x92, 0x43, 0xbe, 0x43, 0x6a, 0x7a, 0x76, 0x17, 0xbb, 0x20,
|
||||
0x40, 0x55, 0x0e, 0xb9, 0x11, 0xdd, 0xbf, 0xe9, 0x9e, 0x7e, 0x4e, 0xf7, 0x12, 0x94, 0xf1, 0xd4,
|
||||
0x62, 0x0e, 0x7f, 0xe2, 0xf9, 0x2e, 0x77, 0x49, 0x71, 0xea, 0xba, 0x9e, 0xef, 0x8d, 0x9b, 0x3b,
|
||||
0x57, 0xae, 0x7b, 0x35, 0x65, 0x07, 0xd4, 0xb3, 0x0e, 0xa8, 0xe3, 0xb8, 0x9c, 0x72, 0xcb, 0x75,
|
||||
0x02, 0x09, 0xd3, 0xfe, 0x90, 0x87, 0xda, 0x99, 0xeb, 0x7a, 0xbd, 0x19, 0x37, 0xd8, 0xcb, 0x19,
|
||||
0x0b, 0x38, 0x51, 0x21, 0x47, 0x6d, 0xde, 0xc8, 0xec, 0x66, 0xf6, 0x72, 0x86, 0xf8, 0x93, 0x10,
|
||||
0xc8, 0x4f, 0x58, 0xc0, 0x1b, 0xd9, 0xdd, 0xcc, 0x5e, 0xd9, 0xc0, 0xbf, 0xc9, 0x01, 0xdc, 0xb7,
|
||||
0xe9, 0x8d, 0x19, 0xbc, 0xa6, 0x9e, 0xe9, 0xbb, 0x33, 0x6e, 0x39, 0x57, 0xe6, 0x25, 0x63, 0x8d,
|
||||
0x1c, 0x1e, 0x5b, 0xb7, 0xe9, 0xcd, 0xe0, 0x35, 0xf5, 0x0c, 0xc9, 0x39, 0x61, 0x8c, 0x7c, 0x0e,
|
||||
0x9b, 0xe2, 0x80, 0xe7, 0x33, 0x8f, 0xbe, 0x49, 0x1d, 0xc9, 0xe3, 0x91, 0x0d, 0x9b, 0xde, 0xf4,
|
||||
0x91, 0x99, 0x38, 0xb4, 0x0b, 0x4a, 0xac, 0x45, 0x40, 0x0b, 0x08, 0x85, 0x50, 0xba, 0x40, 0x7c,
|
||||
0x00, 0xb5, 0x84, 0x58, 0x71, 0xf1, 0x35, 0xc4, 0x28, 0xb1, 0xb8, 0x96, 0xcd, 0x89, 0x06, 0x55,
|
||||
0x81, 0xb2, 0x2d, 0x87, 0xf9, 0x28, 0xa8, 0x88, 0xa0, 0x8a, 0x4d, 0x6f, 0xce, 0x05, 0x4d, 0x48,
|
||||
0xfa, 0x04, 0x54, 0xe1, 0x33, 0xd3, 0x9d, 0x71, 0x73, 0x7c, 0x4d, 0x1d, 0x87, 0x4d, 0x1b, 0xa5,
|
||||
0xdd, 0xcc, 0x5e, 0xfe, 0x28, 0xdb, 0xc8, 0x18, 0xb5, 0xa9, 0xf4, 0x52, 0x5b, 0x72, 0xc8, 0x3e,
|
||||
0xac, 0xbb, 0x33, 0x7e, 0xe5, 0x0a, 0x23, 0x04, 0xda, 0x0c, 0x18, 0x6f, 0x54, 0x76, 0x73, 0x7b,
|
||||
0x79, 0xa3, 0x1e, 0x31, 0x04, 0x76, 0xc0, 0xb8, 0xc0, 0x06, 0xaf, 0x19, 0xf3, 0xcc, 0xb1, 0xeb,
|
||||
0x5c, 0x9a, 0x9c, 0xfa, 0x57, 0x8c, 0x37, 0xca, 0xbb, 0x99, 0xbd, 0x82, 0x51, 0x47, 0x46, 0xdb,
|
||||
0x75, 0x2e, 0x87, 0x48, 0x26, 0x9f, 0x02, 0xb9, 0xe6, 0xd3, 0x31, 0x42, 0x2d, 0xdf, 0x96, 0xc1,
|
||||
0x6a, 0x54, 0x11, 0xbc, 0x2e, 0x38, 0xed, 0x24, 0x83, 0x7c, 0x09, 0xdb, 0xe8, 0x1c, 0x6f, 0x76,
|
||||
0x31, 0xb5, 0xc6, 0x48, 0x34, 0x27, 0x8c, 0x4e, 0xa6, 0x96, 0xc3, 0x1a, 0x20, 0x6e, 0x6f, 0x6c,
|
||||
0x09, 0x40, 0x7f, 0xce, 0x3f, 0x0e, 0xd9, 0xe4, 0x3e, 0x14, 0xa6, 0xf4, 0x82, 0x4d, 0x1b, 0x0a,
|
||||
0xc6, 0x55, 0xfe, 0x20, 0x3b, 0x50, 0xb6, 0x1c, 0x8b, 0x5b, 0x94, 0xbb, 0x7e, 0xa3, 0x86, 0x9c,
|
||||
0x39, 0x41, 0xfb, 0x29, 0x0b, 0x55, 0x91, 0x2f, 0x1d, 0x67, 0x75, 0xba, 0x2c, 0x06, 0x2d, 0x7b,
|
||||
0x2b, 0x68, 0xb7, 0xc2, 0x91, 0xbb, 0x1d, 0x8e, 0x6d, 0x28, 0x4d, 0x69, 0xc0, 0xcd, 0x6b, 0xd7,
|
||||
0xc3, 0x0c, 0x51, 0x8c, 0xa2, 0xf8, 0x7d, 0xea, 0x7a, 0xe4, 0x7d, 0xa8, 0xb2, 0x1b, 0xce, 0x7c,
|
||||
0x87, 0x4e, 0x4d, 0xe1, 0x12, 0x4c, 0x8b, 0x92, 0xa1, 0x44, 0xc4, 0x53, 0x3e, 0x1d, 0x93, 0x3d,
|
||||
0x50, 0x63, 0x47, 0x46, 0x3e, 0x5f, 0x43, 0x37, 0xd6, 0x22, 0x37, 0x86, 0x2e, 0x8f, 0xfd, 0x50,
|
||||
0x5c, 0xe9, 0x87, 0xd2, 0xa2, 0x1f, 0xfe, 0x95, 0x01, 0x05, 0x13, 0x9c, 0x05, 0x9e, 0xeb, 0x04,
|
||||
0x8c, 0x10, 0xc8, 0x5a, 0x13, 0xf4, 0x42, 0x19, 0xf3, 0x25, 0x6b, 0x4d, 0x84, 0x09, 0xd6, 0xc4,
|
||||
0xbc, 0x78, 0xc3, 0x59, 0x80, 0x16, 0x2a, 0x46, 0xd1, 0x9a, 0x1c, 0x89, 0x9f, 0xe4, 0x31, 0x28,
|
||||
0x78, 0x3b, 0x3a, 0x99, 0xf8, 0x2c, 0x08, 0x64, 0x69, 0xe1, 0xc1, 0x8a, 0xa0, 0xb7, 0x24, 0x99,
|
||||
0x3c, 0x81, 0x8d, 0x24, 0xcc, 0x74, 0xbc, 0xc3, 0xd7, 0xc1, 0x35, 0xfa, 0xa3, 0x2c, 0xd3, 0x21,
|
||||
0x44, 0x76, 0x91, 0x41, 0x3e, 0x09, 0xb3, 0x27, 0xc2, 0x4b, 0x78, 0x01, 0xe1, 0x6a, 0x02, 0xde,
|
||||
0x47, 0xf4, 0x63, 0xa8, 0x05, 0xcc, 0x7f, 0xc5, 0x7c, 0xd3, 0x66, 0x41, 0x40, 0xaf, 0x18, 0x3a,
|
||||
0xa8, 0x6c, 0x54, 0x25, 0xf5, 0x5c, 0x12, 0x35, 0x15, 0x6a, 0xe7, 0xae, 0x63, 0x71, 0xd7, 0x0f,
|
||||
0x63, 0xae, 0xfd, 0x31, 0x0f, 0x20, 0xac, 0x1f, 0x70, 0xca, 0x67, 0xc1, 0xd2, 0x8e, 0x21, 0xbc,
|
||||
0x91, 0x5d, 0xe9, 0x8d, 0xca, 0xa2, 0x37, 0xf2, 0xfc, 0x8d, 0x27, 0xd3, 0xa0, 0x76, 0xb8, 0xfe,
|
||||
0x24, 0xec, 0x5d, 0x4f, 0x84, 0x8e, 0xe1, 0x1b, 0x8f, 0x19, 0xc8, 0x26, 0x7b, 0x50, 0x08, 0x38,
|
||||
0xe5, 0xb2, 0x63, 0xd4, 0x0e, 0x49, 0x0a, 0x27, 0xee, 0xc2, 0x0c, 0x09, 0x20, 0x5f, 0x43, 0xed,
|
||||
0x92, 0x5a, 0xd3, 0x99, 0xcf, 0x4c, 0x9f, 0xd1, 0xc0, 0x75, 0x30, 0x93, 0x6b, 0x87, 0x9b, 0xf1,
|
||||
0x91, 0x13, 0xc9, 0x36, 0x90, 0x6b, 0x54, 0x2f, 0x93, 0x3f, 0xc9, 0x87, 0x50, 0x0f, 0x43, 0x2d,
|
||||
0xea, 0x89, 0x5b, 0x76, 0xd4, 0x79, 0x6a, 0x73, 0xf2, 0xd0, 0xb2, 0xc5, 0x8d, 0x54, 0x4c, 0xd2,
|
||||
0x99, 0x37, 0xa1, 0x9c, 0x49, 0xa4, 0xec, 0x3f, 0x35, 0x41, 0x1f, 0x21, 0x19, 0x91, 0x8b, 0x01,
|
||||
0x2f, 0x2e, 0x0f, 0xf8, 0xf2, 0x00, 0x2a, 0x2b, 0x02, 0xb8, 0x22, 0x3d, 0xaa, 0xab, 0xd2, 0xe3,
|
||||
0x21, 0x54, 0xc6, 0x6e, 0xc0, 0x4d, 0x19, 0x5f, 0xcc, 0xea, 0x9c, 0x01, 0x82, 0x34, 0x40, 0x0a,
|
||||
0x79, 0x04, 0x0a, 0x02, 0x5c, 0x67, 0x7c, 0x4d, 0x2d, 0x07, 0x9b, 0x54, 0xce, 0xc0, 0x43, 0x3d,
|
||||
0x49, 0x12, 0xc5, 0x27, 0x21, 0x97, 0x97, 0x12, 0x03, 0xb2, 0xdf, 0x22, 0x26, 0xa4, 0xcd, 0x4b,
|
||||
0xaa, 0x9e, 0x28, 0x29, 0x8d, 0x80, 0x7a, 0x66, 0x05, 0x5c, 0x44, 0x2b, 0x88, 0x52, 0xe9, 0x67,
|
||||
0xb0, 0x9e, 0xa0, 0x85, 0xc5, 0xf4, 0x11, 0x14, 0x44, 0xf7, 0x08, 0x1a, 0x99, 0xdd, 0xdc, 0x5e,
|
||||
0xe5, 0x70, 0xe3, 0x56, 0xa0, 0x67, 0x81, 0x21, 0x11, 0xda, 0x23, 0xa8, 0x0b, 0x62, 0xc7, 0xb9,
|
||||
0x74, 0xa3, 0x8e, 0x54, 0x8b, 0x4b, 0x51, 0x11, 0x89, 0xa7, 0xd5, 0x40, 0x19, 0x32, 0xdf, 0x8e,
|
||||
0x55, 0xfe, 0x0a, 0xea, 0x1d, 0x27, 0xa4, 0x84, 0x0a, 0xff, 0x0f, 0xea, 0xb6, 0xe5, 0xc8, 0x96,
|
||||
0x45, 0x6d, 0x77, 0xe6, 0xf0, 0x30, 0xe0, 0x55, 0xdb, 0x72, 0x84, 0xfc, 0x16, 0x12, 0x11, 0x17,
|
||||
0xb5, 0xb6, 0x10, 0xb7, 0x16, 0xe2, 0x64, 0x77, 0x93, 0xb8, 0x67, 0xf9, 0x52, 0x46, 0xcd, 0x3e,
|
||||
0xcb, 0x97, 0xb2, 0x6a, 0xee, 0x59, 0xbe, 0x94, 0x53, 0xf3, 0xcf, 0xf2, 0xa5, 0xbc, 0x5a, 0x78,
|
||||
0x96, 0x2f, 0x15, 0xd5, 0x92, 0xf6, 0xd7, 0x0c, 0xa8, 0xbd, 0x19, 0xff, 0x9f, 0x5e, 0x01, 0x1f,
|
||||
0x46, 0xcb, 0x31, 0xc7, 0x53, 0xfe, 0xca, 0x9c, 0xb0, 0x29, 0xa7, 0x18, 0xee, 0x82, 0xa1, 0xd8,
|
||||
0x96, 0xd3, 0x9e, 0xf2, 0x57, 0xc7, 0x82, 0x16, 0x3d, 0x9f, 0x09, 0x54, 0x39, 0x44, 0xd1, 0x9b,
|
||||
0x18, 0xf5, 0x16, 0x73, 0x7e, 0x9f, 0x01, 0xe5, 0xdb, 0x99, 0xcb, 0xd9, 0xea, 0x27, 0x01, 0x13,
|
||||
0x6f, 0xde, 0x87, 0xb3, 0xa8, 0x03, 0xc6, 0xf3, 0x1e, 0x7c, 0xab, 0xa5, 0xe7, 0x96, 0xb4, 0xf4,
|
||||
0x3b, 0x1f, 0xbb, 0xfc, 0x9d, 0x8f, 0x9d, 0xf6, 0xdb, 0x8c, 0x88, 0x7a, 0x78, 0xcd, 0xd0, 0xe5,
|
||||
0xbb, 0xa0, 0x44, 0x8f, 0x94, 0x19, 0xd0, 0xe8, 0xc2, 0x10, 0xc8, 0x57, 0x6a, 0x40, 0x71, 0xca,
|
||||
0xc1, 0x02, 0x43, 0x8d, 0xc1, 0x75, 0x8c, 0x0c, 0xa7, 0x1c, 0xc1, 0xeb, 0x4b, 0x56, 0x78, 0xe0,
|
||||
0x5d, 0x80, 0x84, 0x2f, 0x0b, 0x68, 0x67, 0x79, 0x9c, 0x70, 0xa4, 0x74, 0x61, 0x5e, 0x2d, 0x68,
|
||||
0x7f, 0x93, 0x59, 0xf0, 0xdf, 0x5e, 0xe9, 0x03, 0xa8, 0xcd, 0x87, 0x1d, 0xc4, 0xc8, 0xf7, 0x55,
|
||||
0xf1, 0xa2, 0x69, 0x47, 0xa0, 0x3e, 0x0e, 0xfb, 0x88, 0x9c, 0x3b, 0xd2, 0xd7, 0xae, 0x0b, 0xce,
|
||||
0x40, 0x30, 0x42, 0x91, 0x38, 0x9f, 0x08, 0xbf, 0xd2, 0x37, 0x36, 0x73, 0xb8, 0x89, 0xc3, 0x9e,
|
||||
0x7c, 0x73, 0xeb, 0xe8, 0x4f, 0x49, 0x3f, 0x16, 0xb1, 0xbd, 0xdb, 0x40, 0xad, 0x0e, 0xd5, 0xa1,
|
||||
0xfb, 0x03, 0x73, 0xe2, 0x62, 0xfb, 0x0a, 0x6a, 0x11, 0x21, 0x34, 0x71, 0x1f, 0xd6, 0x38, 0x52,
|
||||
0xc2, 0xea, 0x9e, 0xb7, 0xf1, 0xb3, 0x80, 0x72, 0x04, 0x1b, 0x21, 0x42, 0xfb, 0x53, 0x16, 0xca,
|
||||
0x31, 0x55, 0x24, 0xc9, 0x05, 0x0d, 0x98, 0x69, 0xd3, 0x31, 0xf5, 0x5d, 0xd7, 0x09, 0x6b, 0x5c,
|
||||
0x11, 0xc4, 0xf3, 0x90, 0x26, 0x5a, 0x58, 0x64, 0xc7, 0x35, 0x0d, 0xae, 0xd1, 0x3b, 0x8a, 0x51,
|
||||
0x09, 0x69, 0xa7, 0x34, 0xb8, 0x26, 0x1f, 0x81, 0x1a, 0x41, 0x3c, 0x9f, 0x59, 0xb6, 0x78, 0xf9,
|
||||
0xe4, 0xfb, 0x5c, 0x0f, 0xe9, 0xfd, 0x90, 0x2c, 0x1a, 0xbc, 0x2c, 0x32, 0xd3, 0xa3, 0xd6, 0xc4,
|
||||
0xb4, 0x85, 0x17, 0xe5, 0xbc, 0x5a, 0x93, 0xf4, 0x3e, 0xb5, 0x26, 0xe7, 0x01, 0xe5, 0xe4, 0x33,
|
||||
0x78, 0x90, 0x18, 0x6a, 0x13, 0x70, 0x59, 0xc5, 0xc4, 0x8f, 0xa7, 0xda, 0xf8, 0xc8, 0x23, 0x50,
|
||||
0xc4, 0x8b, 0x61, 0x8e, 0x7d, 0x46, 0x39, 0x9b, 0x84, 0x75, 0x5c, 0x11, 0xb4, 0xb6, 0x24, 0x91,
|
||||
0x06, 0x14, 0xd9, 0x8d, 0x67, 0xf9, 0x6c, 0x82, 0x2f, 0x46, 0xc9, 0x88, 0x7e, 0x8a, 0xc3, 0x01,
|
||||
0x77, 0x7d, 0x7a, 0xc5, 0x4c, 0x87, 0xda, 0x2c, 0x1c, 0x51, 0x2a, 0x21, 0xad, 0x4b, 0x6d, 0xa6,
|
||||
0xbd, 0x03, 0xdb, 0x4f, 0x19, 0x3f, 0xb3, 0x5e, 0xce, 0xac, 0x89, 0xc5, 0xdf, 0xf4, 0xa9, 0x4f,
|
||||
0xe7, 0x5d, 0xf0, 0x2f, 0x05, 0xd8, 0x48, 0xb3, 0x18, 0x67, 0xbe, 0x78, 0x81, 0x0a, 0xfe, 0x6c,
|
||||
0xca, 0xa2, 0xe8, 0xcc, 0x5f, 0xcc, 0x18, 0x6c, 0xcc, 0xa6, 0xcc, 0x90, 0x20, 0xf2, 0x35, 0xec,
|
||||
0xcc, 0x53, 0xcc, 0x17, 0x6f, 0x60, 0x40, 0xb9, 0xe9, 0x31, 0xdf, 0x7c, 0x25, 0x5e, 0x7a, 0xf4,
|
||||
0x3e, 0x56, 0xa5, 0xcc, 0x36, 0x83, 0x72, 0x91, 0x71, 0x7d, 0xe6, 0x3f, 0x17, 0x6c, 0xf2, 0x21,
|
||||
0xa8, 0xc9, 0x51, 0xd1, 0xf4, 0x3c, 0x1b, 0x23, 0x91, 0x8f, 0xbb, 0x99, 0xf0, 0x97, 0x67, 0x93,
|
||||
0x4f, 0x41, 0xec, 0x07, 0x66, 0xca, 0xc3, 0x9e, 0x1d, 0x16, 0xbd, 0x90, 0x31, 0x5f, 0x1a, 0x04,
|
||||
0xfc, 0x4b, 0x68, 0x2e, 0x5f, 0x36, 0xf0, 0x54, 0x01, 0x4f, 0x6d, 0x2e, 0x59, 0x38, 0xc4, 0xd9,
|
||||
0xf4, 0x46, 0x21, 0x22, 0xb8, 0x86, 0xf8, 0xf9, 0x46, 0x21, 0x6a, 0xe6, 0x23, 0x58, 0x4f, 0x8d,
|
||||
0xb0, 0x08, 0x2c, 0x22, 0xb0, 0x96, 0x18, 0x63, 0xe3, 0xf2, 0x5a, 0x1c, 0xff, 0x4b, 0xcb, 0xc7,
|
||||
0xff, 0x27, 0xb0, 0x11, 0x0d, 0x2e, 0x17, 0x74, 0xfc, 0x83, 0x7b, 0x79, 0x69, 0x06, 0x6c, 0x8c,
|
||||
0x4d, 0x39, 0x6f, 0xac, 0x87, 0xac, 0x23, 0xc9, 0x19, 0xb0, 0x31, 0x69, 0x42, 0x89, 0xce, 0xb8,
|
||||
0x2b, 0x62, 0x84, 0x0f, 0x71, 0xc9, 0x88, 0x7f, 0x0b, 0x59, 0xd1, 0xdf, 0xe6, 0xc5, 0x6c, 0x72,
|
||||
0xc5, 0x64, 0xbb, 0xa8, 0x48, 0x59, 0x11, 0xeb, 0x08, 0x39, 0xe2, 0x9e, 0x5f, 0xc0, 0xf6, 0x2d,
|
||||
0x3c, 0xa7, 0x3e, 0xc7, 0x1b, 0x28, 0xd2, 0x67, 0x0b, 0xa7, 0x04, 0x5b, 0x5c, 0xe3, 0x63, 0x20,
|
||||
0x82, 0x63, 0x0a, 0x97, 0x58, 0x8e, 0x79, 0x39, 0xb5, 0xae, 0xae, 0x39, 0xce, 0x21, 0x79, 0xa3,
|
||||
0x2e, 0x38, 0xe7, 0xf4, 0xa6, 0xe3, 0x9c, 0x20, 0x79, 0xd9, 0x4b, 0x57, 0x0b, 0x63, 0xfe, 0xb6,
|
||||
0x97, 0xae, 0x9e, 0xca, 0x0d, 0x89, 0xd3, 0xfe, 0x9c, 0x81, 0x6a, 0x2a, 0x39, 0xb1, 0x49, 0xc9,
|
||||
0x3d, 0xcd, 0x0c, 0x27, 0x81, 0xbc, 0x51, 0x0e, 0x29, 0x9d, 0x09, 0x79, 0x12, 0x8e, 0x9b, 0x59,
|
||||
0x9c, 0x09, 0x9b, 0xcb, 0x33, 0x3c, 0x31, 0x77, 0x7e, 0x0a, 0xc4, 0x72, 0xc6, 0xae, 0x2d, 0x72,
|
||||
0x88, 0x5f, 0xfb, 0x2c, 0xb8, 0x76, 0xa7, 0x13, 0xcc, 0xd3, 0xaa, 0xb1, 0x1e, 0x71, 0x86, 0x11,
|
||||
0x43, 0xc0, 0xe3, 0xd5, 0x70, 0x0e, 0xcf, 0x4b, 0x78, 0xc4, 0x89, 0xe1, 0xda, 0x0b, 0xd8, 0x1e,
|
||||
0xac, 0xaa, 0x52, 0xf2, 0x15, 0x80, 0x17, 0xd7, 0x26, 0x5a, 0x52, 0x39, 0xdc, 0xb9, 0x7d, 0xe1,
|
||||
0x79, 0xfd, 0x1a, 0x09, 0xbc, 0xb6, 0x03, 0xcd, 0x65, 0xa2, 0x65, 0x23, 0xd6, 0x1e, 0xc0, 0xc6,
|
||||
0x60, 0x76, 0x75, 0xc5, 0x16, 0x26, 0xb2, 0xef, 0x41, 0x39, 0xb6, 0x82, 0x97, 0x33, 0x3a, 0xb5,
|
||||
0x2e, 0x2d, 0x36, 0x79, 0x9b, 0x33, 0x3f, 0x86, 0xb5, 0x70, 0xc4, 0x96, 0xee, 0x9c, 0x0f, 0x6b,
|
||||
0xad, 0x19, 0x77, 0xc3, 0xf9, 0x3a, 0x84, 0x68, 0x3f, 0x65, 0xe0, 0x7e, 0x5a, 0x67, 0xf8, 0x28,
|
||||
0x1c, 0x42, 0x29, 0x5a, 0xbe, 0xc3, 0xc6, 0xb3, 0x35, 0xb7, 0x32, 0xf5, 0x7d, 0xc2, 0x28, 0x86,
|
||||
0x9b, 0x38, 0xf9, 0x02, 0x94, 0x49, 0xe2, 0xa2, 0x8d, 0x2c, 0x9e, 0x7b, 0x10, 0x9f, 0x4b, 0x5a,
|
||||
0x61, 0xa4, 0xa0, 0xfb, 0x8f, 0xa1, 0x14, 0xed, 0x16, 0x44, 0x81, 0xd2, 0x59, 0xaf, 0xd7, 0x37,
|
||||
0x7b, 0xa3, 0xa1, 0x7a, 0x8f, 0x54, 0xa0, 0x88, 0xbf, 0x3a, 0x5d, 0x35, 0xb3, 0x1f, 0x40, 0x39,
|
||||
0x5e, 0x2d, 0x48, 0x15, 0xca, 0x9d, 0x6e, 0x67, 0xd8, 0x69, 0x0d, 0xf5, 0x63, 0xf5, 0x1e, 0x79,
|
||||
0x00, 0xeb, 0x7d, 0x43, 0xef, 0x9c, 0xb7, 0x9e, 0xea, 0xa6, 0xa1, 0x3f, 0xd7, 0x5b, 0x67, 0xfa,
|
||||
0xb1, 0x9a, 0x21, 0x04, 0x6a, 0xa7, 0xc3, 0xb3, 0xb6, 0xd9, 0x1f, 0x1d, 0x9d, 0x75, 0x06, 0xa7,
|
||||
0xfa, 0xb1, 0x9a, 0x15, 0x32, 0x07, 0xa3, 0x76, 0x5b, 0x1f, 0x0c, 0xd4, 0x1c, 0x01, 0x58, 0x3b,
|
||||
0x69, 0x75, 0x04, 0x38, 0x4f, 0x36, 0xa0, 0xde, 0xe9, 0x3e, 0xef, 0x75, 0xda, 0xba, 0x39, 0xd0,
|
||||
0x87, 0x43, 0x41, 0x2c, 0xec, 0xff, 0x3b, 0x03, 0xd5, 0xd4, 0x76, 0x42, 0xb6, 0x60, 0x43, 0x1c,
|
||||
0x19, 0x19, 0x42, 0x53, 0x6b, 0xd0, 0xeb, 0x9a, 0xdd, 0x5e, 0x57, 0x57, 0xef, 0x91, 0x77, 0x60,
|
||||
0x6b, 0x81, 0xd1, 0x3b, 0x39, 0x69, 0x9f, 0xb6, 0xc4, 0xe5, 0x49, 0x13, 0x36, 0x17, 0x98, 0xc3,
|
||||
0xce, 0xb9, 0x2e, 0xac, 0xcc, 0x92, 0x5d, 0xd8, 0x59, 0xe0, 0x0d, 0xbe, 0xd3, 0xf5, 0x7e, 0x8c,
|
||||
0xc8, 0x91, 0xc7, 0xf0, 0x68, 0x01, 0xd1, 0xe9, 0x0e, 0x46, 0x27, 0x27, 0x9d, 0x76, 0x47, 0xef,
|
||||
0x0e, 0xcd, 0xe7, 0xad, 0xb3, 0x91, 0xae, 0xe6, 0xc9, 0x0e, 0x34, 0x16, 0x95, 0xe8, 0xe7, 0xfd,
|
||||
0x9e, 0xd1, 0x32, 0x5e, 0xa8, 0x05, 0xf2, 0x3e, 0x3c, 0xbc, 0x25, 0xa4, 0xdd, 0x33, 0x0c, 0xbd,
|
||||
0x3d, 0x34, 0x5b, 0xe7, 0xbd, 0x51, 0x77, 0xa8, 0xae, 0xed, 0x1f, 0x88, 0x0d, 0x60, 0xa1, 0xf0,
|
||||
0x84, 0xcb, 0x46, 0xdd, 0x6f, 0xba, 0xbd, 0xef, 0xba, 0xea, 0x3d, 0xe1, 0xf9, 0xe1, 0xa9, 0xa1,
|
||||
0x0f, 0x4e, 0x7b, 0x67, 0xc7, 0x6a, 0x66, 0xff, 0x37, 0x39, 0x80, 0x79, 0x6e, 0x09, 0xef, 0xb4,
|
||||
0x46, 0xc3, 0x5e, 0xa4, 0x61, 0x7e, 0x4c, 0x83, 0xf7, 0x92, 0x8c, 0xa3, 0xd1, 0xf1, 0x53, 0x7d,
|
||||
0x68, 0x76, 0x7b, 0x43, 0x73, 0x30, 0x6c, 0x19, 0x43, 0x0c, 0x57, 0x13, 0x36, 0x93, 0x18, 0xe9,
|
||||
0x85, 0x13, 0x5d, 0x1f, 0xa8, 0x59, 0xf2, 0x1e, 0x34, 0x97, 0x9c, 0xd7, 0xcf, 0x5a, 0xfd, 0x81,
|
||||
0x7e, 0xac, 0xe6, 0xc8, 0x36, 0x3c, 0x48, 0xf2, 0x3b, 0x5d, 0xf3, 0xe4, 0xac, 0xf3, 0xf4, 0x74,
|
||||
0xa8, 0xe6, 0x49, 0x03, 0xee, 0xa7, 0xc5, 0xb6, 0x50, 0xaa, 0x5a, 0x58, 0x3c, 0x74, 0xde, 0xe9,
|
||||
0xea, 0x06, 0xb2, 0xd6, 0xc8, 0x26, 0x90, 0x24, 0xab, 0x6f, 0xe8, 0xfd, 0xd6, 0x0b, 0xb5, 0x48,
|
||||
0x1e, 0xc2, 0x3b, 0x49, 0x7a, 0xe4, 0xd1, 0xa3, 0x56, 0xfb, 0x9b, 0xde, 0xc9, 0x89, 0x5a, 0x5a,
|
||||
0xd4, 0x16, 0x67, 0x73, 0x79, 0xd1, 0x37, 0x51, 0x66, 0x83, 0x88, 0x5b, 0x8a, 0xd1, 0xf9, 0x76,
|
||||
0xd4, 0x39, 0xee, 0x0c, 0x5f, 0x98, 0xbd, 0x6f, 0xd4, 0x8a, 0x88, 0xdb, 0x12, 0xcb, 0x93, 0x09,
|
||||
0xa0, 0x2a, 0x87, 0xff, 0x28, 0xcb, 0x8f, 0x00, 0x6d, 0xfc, 0xec, 0x48, 0x0c, 0x28, 0x86, 0x85,
|
||||
0x4a, 0x56, 0x95, 0x6e, 0xf3, 0x41, 0x6a, 0x91, 0x8b, 0x1b, 0xd1, 0xd6, 0xaf, 0xff, 0xfe, 0xcf,
|
||||
0xdf, 0x65, 0xd7, 0x35, 0xe5, 0xe0, 0xd5, 0x67, 0x07, 0x02, 0x71, 0xe0, 0xce, 0xf8, 0x97, 0x99,
|
||||
0x7d, 0xd2, 0x83, 0x35, 0xf9, 0xb1, 0x89, 0x6c, 0xa6, 0x44, 0xc6, 0x5f, 0x9f, 0x56, 0x49, 0xdc,
|
||||
0x44, 0x89, 0xaa, 0x56, 0x89, 0x25, 0x5a, 0x8e, 0x10, 0xf8, 0x05, 0x14, 0xc3, 0x4f, 0x19, 0x89,
|
||||
0x4b, 0xa6, 0x3f, 0x6e, 0x34, 0x97, 0x6d, 0x9b, 0xff, 0x9f, 0x21, 0xdf, 0x43, 0x39, 0x5e, 0x54,
|
||||
0xc9, 0x76, 0xa2, 0x05, 0xa7, 0xdb, 0x67, 0xb3, 0xb9, 0x8c, 0x95, 0xbe, 0x16, 0xa9, 0xc5, 0xd7,
|
||||
0xc2, 0x25, 0x96, 0x8c, 0x64, 0x3b, 0x12, 0x4b, 0x2c, 0x69, 0xa4, 0xd4, 0x27, 0xf6, 0xda, 0xa5,
|
||||
0x17, 0xd3, 0x9a, 0x28, 0xf2, 0x3e, 0x21, 0x29, 0x91, 0x07, 0x3f, 0x5a, 0x93, 0x5f, 0x90, 0x9f,
|
||||
0x83, 0x12, 0x06, 0x00, 0x57, 0x4d, 0x32, 0x77, 0x56, 0x72, 0x1f, 0x6e, 0xce, 0x8d, 0x59, 0x5c,
|
||||
0x4a, 0x97, 0x48, 0x77, 0x67, 0xfc, 0x80, 0xa3, 0xb4, 0x8b, 0x58, 0x3a, 0xae, 0x30, 0x09, 0xe9,
|
||||
0xc9, 0x65, 0x30, 0x2d, 0x3d, 0xb5, 0xec, 0x68, 0xbb, 0x28, 0xbd, 0x49, 0x1a, 0x29, 0xe9, 0x2f,
|
||||
0x05, 0xe6, 0xe0, 0x47, 0x6a, 0x73, 0x61, 0x41, 0x4d, 0x4c, 0xb0, 0x18, 0xf2, 0x3b, 0x6d, 0x98,
|
||||
0x7b, 0x6d, 0x61, 0xb5, 0xd7, 0xb6, 0x51, 0xc9, 0x06, 0x59, 0x4f, 0xa4, 0x42, 0x6c, 0xc1, 0x5c,
|
||||
0xfa, 0x9d, 0x36, 0x24, 0xa5, 0xa7, 0x4d, 0x78, 0x88, 0xd2, 0xb7, 0xc9, 0x56, 0x52, 0x7a, 0xd2,
|
||||
0x82, 0x17, 0x50, 0x15, 0x3a, 0xa2, 0x1d, 0x26, 0x48, 0x64, 0x72, 0x6a, 0x51, 0x6a, 0x6e, 0xdd,
|
||||
0xa2, 0xa7, 0xab, 0x83, 0xd4, 0x51, 0x45, 0x40, 0xf9, 0x81, 0x5c, 0x8e, 0x08, 0x07, 0x72, 0x7b,
|
||||
0xbc, 0x27, 0x5a, 0x2c, 0x67, 0xe5, 0xec, 0xdf, 0xbc, 0x73, 0x82, 0xd0, 0x76, 0x50, 0xe1, 0x26,
|
||||
0xb9, 0x8f, 0x0a, 0x23, 0xc0, 0x81, 0x27, 0xe5, 0xff, 0x12, 0xc8, 0xe0, 0x2e, 0xad, 0x2b, 0x67,
|
||||
0x99, 0xe6, 0xfb, 0x77, 0x62, 0xd2, 0x0e, 0xd5, 0x96, 0x2a, 0x17, 0x25, 0xcc, 0x40, 0x49, 0x4e,
|
||||
0x10, 0x64, 0x6e, 0xcb, 0x92, 0x61, 0xa6, 0xf9, 0xee, 0x0a, 0x6e, 0xa8, 0xad, 0x81, 0xda, 0x08,
|
||||
0x51, 0x85, 0x36, 0x31, 0xa7, 0x1e, 0x04, 0x12, 0x76, 0xb1, 0x86, 0xff, 0x1f, 0xf9, 0xfc, 0x3f,
|
||||
0x01, 0x00, 0x00, 0xff, 0xff, 0xb9, 0xba, 0x11, 0xb0, 0x56, 0x19, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
|
|
|||
|
|
@ -872,9 +872,102 @@ message SetLiquidityParamsResponse {
|
|||
message SuggestSwapsRequest {
|
||||
}
|
||||
|
||||
enum AutoReason {
|
||||
AUTO_REASON_UNKNOWN = 0;
|
||||
|
||||
/*
|
||||
Budget not started indicates that we do not recommend any swaps because
|
||||
the start time for our budget has not arrived yet.
|
||||
*/
|
||||
AUTO_REASON_BUDGET_NOT_STARTED = 1;
|
||||
|
||||
/*
|
||||
Sweep fees indicates that the estimated fees to sweep swaps are too high
|
||||
right now.
|
||||
*/
|
||||
AUTO_REASON_SWEEP_FEES = 2;
|
||||
|
||||
/*
|
||||
Budget elapsed indicates that the autoloop budget for the period has been
|
||||
elapsed.
|
||||
*/
|
||||
AUTO_REASON_BUDGET_ELAPSED = 3;
|
||||
|
||||
/*
|
||||
In flight indicates that the limit on in-flight automatically dispatched
|
||||
swaps has already been reached.
|
||||
*/
|
||||
AUTO_REASON_IN_FLIGHT = 4;
|
||||
|
||||
/*
|
||||
Swap fee indicates that the server fee for a specific swap is too high.
|
||||
*/
|
||||
AUTO_REASON_SWAP_FEE = 5;
|
||||
|
||||
/*
|
||||
Miner fee indicates that the miner fee for a specific swap is to high.
|
||||
*/
|
||||
AUTO_REASON_MINER_FEE = 6;
|
||||
|
||||
/*
|
||||
Prepay indicates that the prepay fee for a specific swap is too high.
|
||||
*/
|
||||
AUTO_REASON_PREPAY = 7;
|
||||
|
||||
/*
|
||||
Failure backoff indicates that a swap has recently failed for this target,
|
||||
and the backoff period has not yet passed.
|
||||
*/
|
||||
AUTO_REASON_FAILURE_BACKOFF = 8;
|
||||
|
||||
/*
|
||||
Loop out indicates that a loop out swap is currently utilizing the channel,
|
||||
so it is not eligible.
|
||||
*/
|
||||
AUTO_REASON_LOOP_OUT = 9;
|
||||
|
||||
/*
|
||||
Loop In indicates that a loop in swap is currently in flight for the peer,
|
||||
so it is not eligible.
|
||||
*/
|
||||
AUTO_REASON_LOOP_IN = 10;
|
||||
|
||||
/*
|
||||
Liquidity ok indicates that a target meets the liquidity balance expressed
|
||||
in its rule, so no swap is needed.
|
||||
*/
|
||||
AUTO_REASON_LIQUIDITY_OK = 11;
|
||||
|
||||
/*
|
||||
Budget insufficient indicates that we cannot perform a swap because we do
|
||||
not have enough pending budget available. This differs from budget elapsed,
|
||||
because we still have some budget available, but we have allocated it to
|
||||
other swaps.
|
||||
*/
|
||||
AUTO_REASON_BUDGET_INSUFFICIENT = 12;
|
||||
}
|
||||
|
||||
message Disqualified {
|
||||
/*
|
||||
The short channel ID of the channel that was excluded from our suggestions.
|
||||
*/
|
||||
uint64 channel_id = 1;
|
||||
|
||||
/*
|
||||
The reason that we excluded the channel from the our suggestions.
|
||||
*/
|
||||
AutoReason reason = 2;
|
||||
}
|
||||
|
||||
message SuggestSwapsResponse {
|
||||
/*
|
||||
The set of recommended loop outs.
|
||||
*/
|
||||
repeated LoopOutRequest loop_out = 1;
|
||||
|
||||
/*
|
||||
Disqualified contains the set of channels that swaps are not recommended
|
||||
for.
|
||||
*/
|
||||
repeated Disqualified disqualified = 2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -395,6 +395,40 @@
|
|||
}
|
||||
},
|
||||
"definitions": {
|
||||
"looprpcAutoReason": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"AUTO_REASON_UNKNOWN",
|
||||
"AUTO_REASON_BUDGET_NOT_STARTED",
|
||||
"AUTO_REASON_SWEEP_FEES",
|
||||
"AUTO_REASON_BUDGET_ELAPSED",
|
||||
"AUTO_REASON_IN_FLIGHT",
|
||||
"AUTO_REASON_SWAP_FEE",
|
||||
"AUTO_REASON_MINER_FEE",
|
||||
"AUTO_REASON_PREPAY",
|
||||
"AUTO_REASON_FAILURE_BACKOFF",
|
||||
"AUTO_REASON_LOOP_OUT",
|
||||
"AUTO_REASON_LOOP_IN",
|
||||
"AUTO_REASON_LIQUIDITY_OK",
|
||||
"AUTO_REASON_BUDGET_INSUFFICIENT"
|
||||
],
|
||||
"default": "AUTO_REASON_UNKNOWN",
|
||||
"description": " - AUTO_REASON_BUDGET_NOT_STARTED: Budget not started indicates that we do not recommend any swaps because \nthe start time for our budget has not arrived yet.\n - AUTO_REASON_SWEEP_FEES: Sweep fees indicates that the estimated fees to sweep swaps are too high \nright now.\n - AUTO_REASON_BUDGET_ELAPSED: Budget elapsed indicates that the autoloop budget for the period has been \nelapsed.\n - AUTO_REASON_IN_FLIGHT: In flight indicates that the limit on in-flight automatically dispatched \nswaps has already been reached.\n - AUTO_REASON_SWAP_FEE: Swap fee indicates that the server fee for a specific swap is too high.\n - AUTO_REASON_MINER_FEE: Miner fee indicates that the miner fee for a specific swap is to high.\n - AUTO_REASON_PREPAY: Prepay indicates that the prepay fee for a specific swap is too high.\n - AUTO_REASON_FAILURE_BACKOFF: Failure backoff indicates that a swap has recently failed for this target,\nand the backoff period has not yet passed.\n - AUTO_REASON_LOOP_OUT: Loop out indicates that a loop out swap is currently utilizing the channel,\nso it is not eligible.\n - AUTO_REASON_LOOP_IN: Loop In indicates that a loop in swap is currently in flight for the peer, \nso it is not eligible.\n - AUTO_REASON_LIQUIDITY_OK: Liquidity ok indicates that a target meets the liquidity balance expressed \nin its rule, so no swap is needed.\n - AUTO_REASON_BUDGET_INSUFFICIENT: Budget insufficient indicates that we cannot perform a swap because we do \nnot have enough pending budget available. This differs from budget elapsed, \nbecause we still have some budget available, but we have allocated it to \nother swaps."
|
||||
},
|
||||
"looprpcDisqualified": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"channel_id": {
|
||||
"type": "string",
|
||||
"format": "uint64",
|
||||
"description": "The short channel ID of the channel that was excluded from our suggestions."
|
||||
},
|
||||
"reason": {
|
||||
"$ref": "#/definitions/looprpcAutoReason",
|
||||
"description": "The reason that we excluded the channel from the our suggestions."
|
||||
}
|
||||
}
|
||||
},
|
||||
"looprpcFailureReason": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
|
@ -808,6 +842,13 @@
|
|||
"$ref": "#/definitions/looprpcLoopOutRequest"
|
||||
},
|
||||
"description": "The set of recommended loop outs."
|
||||
},
|
||||
"disqualified": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/looprpcDisqualified"
|
||||
},
|
||||
"description": "Disqualified contains the set of channels that swaps are not recommended\nfor."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -24,6 +24,14 @@ This file tracks release notes for the loop client.
|
|||
baked one with the exact permissions needed for Loop. If the now deprecated
|
||||
flag/option `--lnd.macaroondir` is used, it will fall back to use only the
|
||||
`admin.macaroon` from that directory.
|
||||
* The rules used for autoloop have been relaxed to allow autoloop to dispatch
|
||||
swaps even if there are manually initiated swaps that are not limited to a
|
||||
single channel in progress. This change was made to allow autoloop to coexist
|
||||
with manual swaps.
|
||||
* The `SuggestSwaps` endpoint has been updated to include reasons that indicate
|
||||
why the Autolooper is not currently dispatching swaps for the set of rules
|
||||
that the client is configured with. See the [autoloop documentation](docs/autoloop.md) for a
|
||||
detailed explanations of these reasons.
|
||||
|
||||
#### Breaking Changes
|
||||
* The `AutoOut`, `AutoOutBudgetSat` and `AutoOutBudgetStartSec` fields in the
|
||||
|
|
@ -31,5 +39,8 @@ This file tracks release notes for the loop client.
|
|||
been renamed to `Autoloop`, `AutoloopBudgetSat` and `AutoloopBudgetStartSec`.
|
||||
* The `autoout` flag for enabling automatic dispatch of loop out swaps has been
|
||||
renamed to `autoloop` so that it can cover loop out and loop in.
|
||||
* The `SuggestSwaps` rpc call will now fail with a `FailedPrecondition` grpc
|
||||
error code if no rules are configured for the autolooper. Previously the rpc
|
||||
would return an empty response.
|
||||
|
||||
#### Bug Fixes
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue