Skip to content

Commit 1d1354d

Browse files
committed
config: make total payment timeout and retries configurable
1 parent 1943edf commit 1d1354d

File tree

5 files changed

+84
-53
lines changed

5 files changed

+84
-53
lines changed

client.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ type ClientConfig struct {
108108
// for a loop out swap. When greater than one, a multi-part payment may
109109
// be attempted.
110110
LoopOutMaxParts uint32
111+
112+
// TotalPaymentTimeout is the total amount of time until we time out
113+
// off-chain payments (used in loop out).
114+
TotalPaymentTimeout time.Duration
115+
116+
// MaxPaymentRetries is the maximum times we retry an off-chain payment
117+
// (used in loop out).
118+
MaxPaymentRetries int
111119
}
112120

113121
// NewClient returns a new instance to initiate swaps with.
@@ -142,12 +150,14 @@ func NewClient(dbDir string, cfg *ClientConfig) (*Client, func(), error) {
142150
}
143151

144152
executor := newExecutor(&executorConfig{
145-
lnd: cfg.Lnd,
146-
store: store,
147-
sweeper: sweeper,
148-
createExpiryTimer: config.CreateExpiryTimer,
149-
loopOutMaxParts: cfg.LoopOutMaxParts,
150-
cancelSwap: swapServerClient.CancelLoopOutSwap,
153+
lnd: cfg.Lnd,
154+
store: store,
155+
sweeper: sweeper,
156+
createExpiryTimer: config.CreateExpiryTimer,
157+
loopOutMaxParts: cfg.LoopOutMaxParts,
158+
totalPaymentTimeout: cfg.TotalPaymentTimeout,
159+
maxPaymentRetries: cfg.MaxPaymentRetries,
160+
cancelSwap: swapServerClient.CancelLoopOutSwap,
151161
})
152162

153163
client := &Client{

executor.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ type executorConfig struct {
2626

2727
loopOutMaxParts uint32
2828

29+
totalPaymentTimeout time.Duration
30+
31+
maxPaymentRetries int
32+
2933
cancelSwap func(ctx context.Context, details *outCancelDetails) error
3034
}
3135

@@ -141,12 +145,14 @@ func (s *executor) run(mainCtx context.Context,
141145
defer s.wg.Done()
142146

143147
err := newSwap.execute(mainCtx, &executeConfig{
144-
statusChan: statusChan,
145-
sweeper: s.sweeper,
146-
blockEpochChan: queue.ChanOut(),
147-
timerFactory: s.executorConfig.createExpiryTimer,
148-
loopOutMaxParts: s.executorConfig.loopOutMaxParts,
149-
cancelSwap: s.executorConfig.cancelSwap,
148+
statusChan: statusChan,
149+
sweeper: s.sweeper,
150+
blockEpochChan: queue.ChanOut(),
151+
timerFactory: s.executorConfig.createExpiryTimer,
152+
loopOutMaxParts: s.executorConfig.loopOutMaxParts,
153+
totalPaymentTimout: s.executorConfig.totalPaymentTimeout,
154+
maxPaymentRetries: s.executorConfig.maxPaymentRetries,
155+
cancelSwap: s.executorConfig.cancelSwap,
150156
}, height)
151157
if err != nil && err != context.Canceled {
152158
log.Errorf("Execute error: %v", err)

loopd/config.go

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ var (
3333
LoopDirBase, DefaultNetwork, defaultConfigFilename,
3434
)
3535

36-
defaultMaxLogFiles = 3
37-
defaultMaxLogFileSize = 10
38-
defaultLoopOutMaxParts = uint32(5)
36+
defaultMaxLogFiles = 3
37+
defaultMaxLogFileSize = 10
38+
defaultLoopOutMaxParts = uint32(5)
39+
defaultTotalPaymentTimeout = time.Minute * 60
40+
defaultMaxPaymentRetries = 3
3941

4042
// DefaultTLSCertFilename is the default file name for the autogenerated
4143
// TLS certificate.
@@ -144,6 +146,9 @@ type Config struct {
144146

145147
LoopOutMaxParts uint32 `long:"loopoutmaxparts" description:"The maximum number of payment parts that may be used for a loop out swap."`
146148

149+
TotalPaymentTimeout time.Duration `long:"totalpaymenttimeout" description:"The timeout to use for off-chain payments."`
150+
MaxPaymentRetries int `long:"maxpaymentretries" description:"The maximum number of times an off-chain payment may be retried."`
151+
147152
Lnd *lndConfig `group:"lnd" namespace:"lnd"`
148153

149154
Server *loopServerConfig `group:"server" namespace:"server"`
@@ -165,19 +170,21 @@ func DefaultConfig() Config {
165170
Server: &loopServerConfig{
166171
NoTLS: false,
167172
},
168-
LoopDir: LoopDirBase,
169-
ConfigFile: defaultConfigFile,
170-
DataDir: LoopDirBase,
171-
LogDir: defaultLogDir,
172-
MaxLogFiles: defaultMaxLogFiles,
173-
MaxLogFileSize: defaultMaxLogFileSize,
174-
DebugLevel: defaultLogLevel,
175-
TLSCertPath: DefaultTLSCertPath,
176-
TLSKeyPath: DefaultTLSKeyPath,
177-
MacaroonPath: DefaultMacaroonPath,
178-
MaxLSATCost: lsat.DefaultMaxCostSats,
179-
MaxLSATFee: lsat.DefaultMaxRoutingFeeSats,
180-
LoopOutMaxParts: defaultLoopOutMaxParts,
173+
LoopDir: LoopDirBase,
174+
ConfigFile: defaultConfigFile,
175+
DataDir: LoopDirBase,
176+
LogDir: defaultLogDir,
177+
MaxLogFiles: defaultMaxLogFiles,
178+
MaxLogFileSize: defaultMaxLogFileSize,
179+
DebugLevel: defaultLogLevel,
180+
TLSCertPath: DefaultTLSCertPath,
181+
TLSKeyPath: DefaultTLSKeyPath,
182+
MacaroonPath: DefaultMacaroonPath,
183+
MaxLSATCost: lsat.DefaultMaxCostSats,
184+
MaxLSATFee: lsat.DefaultMaxRoutingFeeSats,
185+
LoopOutMaxParts: defaultLoopOutMaxParts,
186+
TotalPaymentTimeout: defaultTotalPaymentTimeout,
187+
MaxPaymentRetries: defaultMaxPaymentRetries,
181188
Lnd: &lndConfig{
182189
Host: "localhost:10009",
183190
MacaroonPath: DefaultLndMacaroonPath,
@@ -299,6 +306,17 @@ func Validate(cfg *Config) error {
299306
return fmt.Errorf("must specify --lnd.macaroonpath")
300307
}
301308

309+
// Allow at most 2x the default total payment timeout.
310+
if cfg.TotalPaymentTimeout > 2*defaultTotalPaymentTimeout {
311+
return fmt.Errorf("max total payment timeout allowed is at "+
312+
"most %v", 2*defaultTotalPaymentTimeout)
313+
}
314+
315+
// At least one retry.
316+
if cfg.MaxPaymentRetries < 1 {
317+
return fmt.Errorf("max payment retries must be positive")
318+
}
319+
302320
return nil
303321
}
304322

loopd/utils.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@ func getClient(config *Config, lnd *lndclient.LndServices) (*loop.Client,
1717
func(), error) {
1818

1919
clientConfig := &loop.ClientConfig{
20-
ServerAddress: config.Server.Host,
21-
ProxyAddress: config.Server.Proxy,
22-
SwapServerNoTLS: config.Server.NoTLS,
23-
TLSPathServer: config.Server.TLSPath,
24-
Lnd: lnd,
25-
MaxLsatCost: btcutil.Amount(config.MaxLSATCost),
26-
MaxLsatFee: btcutil.Amount(config.MaxLSATFee),
27-
LoopOutMaxParts: config.LoopOutMaxParts,
20+
ServerAddress: config.Server.Host,
21+
ProxyAddress: config.Server.Proxy,
22+
SwapServerNoTLS: config.Server.NoTLS,
23+
TLSPathServer: config.Server.TLSPath,
24+
Lnd: lnd,
25+
MaxLsatCost: btcutil.Amount(config.MaxLSATCost),
26+
MaxLsatFee: btcutil.Amount(config.MaxLSATFee),
27+
LoopOutMaxParts: config.LoopOutMaxParts,
28+
TotalPaymentTimeout: config.TotalPaymentTimeout,
29+
MaxPaymentRetries: config.MaxPaymentRetries,
2830
}
2931

3032
swapClient, cleanUp, err := loop.NewClient(config.DataDir, clientConfig)

loopout.go

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,6 @@ var (
5252
//
5353
// TODO(wilmer): tune?
5454
DefaultSweepConfTargetDelta = DefaultSweepConfTarget * 2
55-
56-
// totalPaymentTimeout is the total timeout used for the loop out
57-
// offchain payment.
58-
totalPaymentTimeout = time.Minute * 60
59-
60-
// maxPaymentRetries is the maximum number of times the client will
61-
// attempt to pay the invoice before failing the swap. This retry limit
62-
// only applies to when the client uses a routing helper plugin.
63-
maxPaymentRetries = 3
6455
)
6556

6657
// loopOutSwap contains all the in-memory state related to a pending loop out
@@ -87,12 +78,14 @@ type loopOutSwap struct {
8778

8879
// executeConfig contains extra configuration to execute the swap.
8980
type executeConfig struct {
90-
sweeper *sweep.Sweeper
91-
statusChan chan<- SwapInfo
92-
blockEpochChan <-chan interface{}
93-
timerFactory func(d time.Duration) <-chan time.Time
94-
loopOutMaxParts uint32
95-
cancelSwap func(context.Context, *outCancelDetails) error
81+
sweeper *sweep.Sweeper
82+
statusChan chan<- SwapInfo
83+
blockEpochChan <-chan interface{}
84+
timerFactory func(d time.Duration) <-chan time.Time
85+
loopOutMaxParts uint32
86+
totalPaymentTimout time.Duration
87+
maxPaymentRetries int
88+
cancelSwap func(context.Context, *outCancelDetails) error
9689
}
9790

9891
// loopOutInitResult contains information about a just-initiated loop out swap.
@@ -683,6 +676,8 @@ func (s *loopOutSwap) payInvoiceAsync(ctx context.Context,
683676
}
684677

685678
maxRetries := 1
679+
paymentTimeout := s.executeConfig.totalPaymentTimout
680+
686681
// Attempt to acquire and initialize the routing plugin.
687682
routingPlugin, err := AcquireRoutingPlugin(
688683
ctx, pluginType, *s.lnd, target, nil, amt,
@@ -695,11 +690,11 @@ func (s *loopOutSwap) payInvoiceAsync(ctx context.Context,
695690
s.log.Infof("Acquired routing plugin %v for payment %v",
696691
pluginType, hash.String())
697692

698-
maxRetries = maxPaymentRetries
693+
maxRetries = s.executeConfig.maxPaymentRetries
694+
paymentTimeout /= time.Duration(maxRetries)
699695
defer ReleaseRoutingPlugin(ctx)
700696
}
701697

702-
paymentTimeout := totalPaymentTimeout / time.Duration(maxRetries)
703698
req := lndclient.SendPaymentRequest{
704699
MaxFee: maxFee,
705700
Invoice: invoice,

0 commit comments

Comments
 (0)