config: make total payment timeout and retries configurable

pull/439/head
Andras Banki-Horvath 2 years ago
parent 1943edfd78
commit 1d1354d2cb
No known key found for this signature in database
GPG Key ID: 80E5375C094198D8

@ -108,6 +108,14 @@ type ClientConfig struct {
// for a loop out swap. When greater than one, a multi-part payment may // for a loop out swap. When greater than one, a multi-part payment may
// be attempted. // be attempted.
LoopOutMaxParts uint32 LoopOutMaxParts uint32
// TotalPaymentTimeout is the total amount of time until we time out
// off-chain payments (used in loop out).
TotalPaymentTimeout time.Duration
// MaxPaymentRetries is the maximum times we retry an off-chain payment
// (used in loop out).
MaxPaymentRetries int
} }
// NewClient returns a new instance to initiate swaps with. // NewClient returns a new instance to initiate swaps with.
@ -142,12 +150,14 @@ func NewClient(dbDir string, cfg *ClientConfig) (*Client, func(), error) {
} }
executor := newExecutor(&executorConfig{ executor := newExecutor(&executorConfig{
lnd: cfg.Lnd, lnd: cfg.Lnd,
store: store, store: store,
sweeper: sweeper, sweeper: sweeper,
createExpiryTimer: config.CreateExpiryTimer, createExpiryTimer: config.CreateExpiryTimer,
loopOutMaxParts: cfg.LoopOutMaxParts, loopOutMaxParts: cfg.LoopOutMaxParts,
cancelSwap: swapServerClient.CancelLoopOutSwap, totalPaymentTimeout: cfg.TotalPaymentTimeout,
maxPaymentRetries: cfg.MaxPaymentRetries,
cancelSwap: swapServerClient.CancelLoopOutSwap,
}) })
client := &Client{ client := &Client{

@ -26,6 +26,10 @@ type executorConfig struct {
loopOutMaxParts uint32 loopOutMaxParts uint32
totalPaymentTimeout time.Duration
maxPaymentRetries int
cancelSwap func(ctx context.Context, details *outCancelDetails) error cancelSwap func(ctx context.Context, details *outCancelDetails) error
} }
@ -141,12 +145,14 @@ func (s *executor) run(mainCtx context.Context,
defer s.wg.Done() defer s.wg.Done()
err := newSwap.execute(mainCtx, &executeConfig{ err := newSwap.execute(mainCtx, &executeConfig{
statusChan: statusChan, statusChan: statusChan,
sweeper: s.sweeper, sweeper: s.sweeper,
blockEpochChan: queue.ChanOut(), blockEpochChan: queue.ChanOut(),
timerFactory: s.executorConfig.createExpiryTimer, timerFactory: s.executorConfig.createExpiryTimer,
loopOutMaxParts: s.executorConfig.loopOutMaxParts, loopOutMaxParts: s.executorConfig.loopOutMaxParts,
cancelSwap: s.executorConfig.cancelSwap, totalPaymentTimout: s.executorConfig.totalPaymentTimeout,
maxPaymentRetries: s.executorConfig.maxPaymentRetries,
cancelSwap: s.executorConfig.cancelSwap,
}, height) }, height)
if err != nil && err != context.Canceled { if err != nil && err != context.Canceled {
log.Errorf("Execute error: %v", err) log.Errorf("Execute error: %v", err)

@ -33,9 +33,11 @@ var (
LoopDirBase, DefaultNetwork, defaultConfigFilename, LoopDirBase, DefaultNetwork, defaultConfigFilename,
) )
defaultMaxLogFiles = 3 defaultMaxLogFiles = 3
defaultMaxLogFileSize = 10 defaultMaxLogFileSize = 10
defaultLoopOutMaxParts = uint32(5) defaultLoopOutMaxParts = uint32(5)
defaultTotalPaymentTimeout = time.Minute * 60
defaultMaxPaymentRetries = 3
// DefaultTLSCertFilename is the default file name for the autogenerated // DefaultTLSCertFilename is the default file name for the autogenerated
// TLS certificate. // TLS certificate.
@ -144,6 +146,9 @@ type Config struct {
LoopOutMaxParts uint32 `long:"loopoutmaxparts" description:"The maximum number of payment parts that may be used for a loop out swap."` LoopOutMaxParts uint32 `long:"loopoutmaxparts" description:"The maximum number of payment parts that may be used for a loop out swap."`
TotalPaymentTimeout time.Duration `long:"totalpaymenttimeout" description:"The timeout to use for off-chain payments."`
MaxPaymentRetries int `long:"maxpaymentretries" description:"The maximum number of times an off-chain payment may be retried."`
Lnd *lndConfig `group:"lnd" namespace:"lnd"` Lnd *lndConfig `group:"lnd" namespace:"lnd"`
Server *loopServerConfig `group:"server" namespace:"server"` Server *loopServerConfig `group:"server" namespace:"server"`
@ -165,19 +170,21 @@ func DefaultConfig() Config {
Server: &loopServerConfig{ Server: &loopServerConfig{
NoTLS: false, NoTLS: false,
}, },
LoopDir: LoopDirBase, LoopDir: LoopDirBase,
ConfigFile: defaultConfigFile, ConfigFile: defaultConfigFile,
DataDir: LoopDirBase, DataDir: LoopDirBase,
LogDir: defaultLogDir, LogDir: defaultLogDir,
MaxLogFiles: defaultMaxLogFiles, MaxLogFiles: defaultMaxLogFiles,
MaxLogFileSize: defaultMaxLogFileSize, MaxLogFileSize: defaultMaxLogFileSize,
DebugLevel: defaultLogLevel, DebugLevel: defaultLogLevel,
TLSCertPath: DefaultTLSCertPath, TLSCertPath: DefaultTLSCertPath,
TLSKeyPath: DefaultTLSKeyPath, TLSKeyPath: DefaultTLSKeyPath,
MacaroonPath: DefaultMacaroonPath, MacaroonPath: DefaultMacaroonPath,
MaxLSATCost: lsat.DefaultMaxCostSats, MaxLSATCost: lsat.DefaultMaxCostSats,
MaxLSATFee: lsat.DefaultMaxRoutingFeeSats, MaxLSATFee: lsat.DefaultMaxRoutingFeeSats,
LoopOutMaxParts: defaultLoopOutMaxParts, LoopOutMaxParts: defaultLoopOutMaxParts,
TotalPaymentTimeout: defaultTotalPaymentTimeout,
MaxPaymentRetries: defaultMaxPaymentRetries,
Lnd: &lndConfig{ Lnd: &lndConfig{
Host: "localhost:10009", Host: "localhost:10009",
MacaroonPath: DefaultLndMacaroonPath, MacaroonPath: DefaultLndMacaroonPath,
@ -299,6 +306,17 @@ func Validate(cfg *Config) error {
return fmt.Errorf("must specify --lnd.macaroonpath") return fmt.Errorf("must specify --lnd.macaroonpath")
} }
// Allow at most 2x the default total payment timeout.
if cfg.TotalPaymentTimeout > 2*defaultTotalPaymentTimeout {
return fmt.Errorf("max total payment timeout allowed is at "+
"most %v", 2*defaultTotalPaymentTimeout)
}
// At least one retry.
if cfg.MaxPaymentRetries < 1 {
return fmt.Errorf("max payment retries must be positive")
}
return nil return nil
} }

@ -17,14 +17,16 @@ func getClient(config *Config, lnd *lndclient.LndServices) (*loop.Client,
func(), error) { func(), error) {
clientConfig := &loop.ClientConfig{ clientConfig := &loop.ClientConfig{
ServerAddress: config.Server.Host, ServerAddress: config.Server.Host,
ProxyAddress: config.Server.Proxy, ProxyAddress: config.Server.Proxy,
SwapServerNoTLS: config.Server.NoTLS, SwapServerNoTLS: config.Server.NoTLS,
TLSPathServer: config.Server.TLSPath, TLSPathServer: config.Server.TLSPath,
Lnd: lnd, Lnd: lnd,
MaxLsatCost: btcutil.Amount(config.MaxLSATCost), MaxLsatCost: btcutil.Amount(config.MaxLSATCost),
MaxLsatFee: btcutil.Amount(config.MaxLSATFee), MaxLsatFee: btcutil.Amount(config.MaxLSATFee),
LoopOutMaxParts: config.LoopOutMaxParts, LoopOutMaxParts: config.LoopOutMaxParts,
TotalPaymentTimeout: config.TotalPaymentTimeout,
MaxPaymentRetries: config.MaxPaymentRetries,
} }
swapClient, cleanUp, err := loop.NewClient(config.DataDir, clientConfig) swapClient, cleanUp, err := loop.NewClient(config.DataDir, clientConfig)

@ -52,15 +52,6 @@ var (
// //
// TODO(wilmer): tune? // TODO(wilmer): tune?
DefaultSweepConfTargetDelta = DefaultSweepConfTarget * 2 DefaultSweepConfTargetDelta = DefaultSweepConfTarget * 2
// totalPaymentTimeout is the total timeout used for the loop out
// offchain payment.
totalPaymentTimeout = time.Minute * 60
// maxPaymentRetries is the maximum number of times the client will
// attempt to pay the invoice before failing the swap. This retry limit
// only applies to when the client uses a routing helper plugin.
maxPaymentRetries = 3
) )
// loopOutSwap contains all the in-memory state related to a pending loop out // loopOutSwap contains all the in-memory state related to a pending loop out
@ -87,12 +78,14 @@ type loopOutSwap struct {
// executeConfig contains extra configuration to execute the swap. // executeConfig contains extra configuration to execute the swap.
type executeConfig struct { type executeConfig struct {
sweeper *sweep.Sweeper sweeper *sweep.Sweeper
statusChan chan<- SwapInfo statusChan chan<- SwapInfo
blockEpochChan <-chan interface{} blockEpochChan <-chan interface{}
timerFactory func(d time.Duration) <-chan time.Time timerFactory func(d time.Duration) <-chan time.Time
loopOutMaxParts uint32 loopOutMaxParts uint32
cancelSwap func(context.Context, *outCancelDetails) error totalPaymentTimout time.Duration
maxPaymentRetries int
cancelSwap func(context.Context, *outCancelDetails) error
} }
// loopOutInitResult contains information about a just-initiated loop out swap. // loopOutInitResult contains information about a just-initiated loop out swap.
@ -683,6 +676,8 @@ func (s *loopOutSwap) payInvoiceAsync(ctx context.Context,
} }
maxRetries := 1 maxRetries := 1
paymentTimeout := s.executeConfig.totalPaymentTimout
// Attempt to acquire and initialize the routing plugin. // Attempt to acquire and initialize the routing plugin.
routingPlugin, err := AcquireRoutingPlugin( routingPlugin, err := AcquireRoutingPlugin(
ctx, pluginType, *s.lnd, target, nil, amt, ctx, pluginType, *s.lnd, target, nil, amt,
@ -695,11 +690,11 @@ func (s *loopOutSwap) payInvoiceAsync(ctx context.Context,
s.log.Infof("Acquired routing plugin %v for payment %v", s.log.Infof("Acquired routing plugin %v for payment %v",
pluginType, hash.String()) pluginType, hash.String())
maxRetries = maxPaymentRetries maxRetries = s.executeConfig.maxPaymentRetries
paymentTimeout /= time.Duration(maxRetries)
defer ReleaseRoutingPlugin(ctx) defer ReleaseRoutingPlugin(ctx)
} }
paymentTimeout := totalPaymentTimeout / time.Duration(maxRetries)
req := lndclient.SendPaymentRequest{ req := lndclient.SendPaymentRequest{
MaxFee: maxFee, MaxFee: maxFee,
Invoice: invoice, Invoice: invoice,

Loading…
Cancel
Save