mirror of https://github.com/lightninglabs/loop
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
3.3 KiB
Go
117 lines
3.3 KiB
Go
package loop
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/btcsuite/btcutil"
|
|
"github.com/lightninglabs/lndclient"
|
|
"github.com/lightningnetwork/lnd/routing/route"
|
|
"github.com/lightningnetwork/lnd/zpay32"
|
|
)
|
|
|
|
var (
|
|
// ErrRoutingPluginNotApplicable means that the selected routing plugin
|
|
// is not able to enhance routing given the current conditions and
|
|
// therefore shouldn't be used.
|
|
ErrRoutingPluginNotApplicable = fmt.Errorf("routing plugin not " +
|
|
"applicable")
|
|
|
|
// ErrRoutingPluginNoMoreRetries means that the routing plugin can't
|
|
// effectively help the payment with more retries.
|
|
ErrRoutingPluginNoMoreRetries = fmt.Errorf("routing plugin can't " +
|
|
"retry more")
|
|
)
|
|
|
|
var (
|
|
routingPluginMx sync.Mutex
|
|
routingPluginInstance RoutingPlugin
|
|
)
|
|
|
|
// RoutingPlugin is a generic interface for off-chain payment helpers.
|
|
type RoutingPlugin interface {
|
|
// Init initializes the routing plugin.
|
|
Init(ctx context.Context, target route.Vertex,
|
|
routeHints [][]zpay32.HopHint, amt btcutil.Amount) error
|
|
|
|
// Done deinitializes the routing plugin (restoring any state the
|
|
// plugin might have changed).
|
|
Done(ctx context.Context) error
|
|
|
|
// BeforePayment is called before each payment. Attempt counter is
|
|
// passed, counting attempts from 1.
|
|
BeforePayment(ctx context.Context, attempt int, maxAttempts int) error
|
|
}
|
|
|
|
// makeRoutingPlugin is a helper to instantiate routing plugins.
|
|
func makeRoutingPlugin(plugin RoutingPluginType,
|
|
_ lndclient.LndServices) RoutingPlugin {
|
|
|
|
return nil
|
|
}
|
|
|
|
// AcquireRoutingPlugin will return a RoutingPlugin instance (or nil). As the
|
|
// LND instance used is a shared resource, currently only one requestor will be
|
|
// able to acquire a RoutingPlugin instance. If someone is already holding the
|
|
// instance a nil is returned.
|
|
func AcquireRoutingPlugin(ctx context.Context, pluginType RoutingPluginType,
|
|
lnd lndclient.LndServices, target route.Vertex,
|
|
routeHints [][]zpay32.HopHint, amt btcutil.Amount) (
|
|
RoutingPlugin, error) {
|
|
|
|
routingPluginMx.Lock()
|
|
defer routingPluginMx.Unlock()
|
|
|
|
// Another swap is already using the routing plugin.
|
|
if routingPluginInstance != nil {
|
|
return nil, nil
|
|
}
|
|
|
|
routingPluginInstance = makeRoutingPlugin(pluginType, lnd)
|
|
if routingPluginInstance == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
// Initialize the plugin with the passed parameters.
|
|
err := routingPluginInstance.Init(ctx, target, routeHints, amt)
|
|
if err != nil {
|
|
if err == ErrRoutingPluginNotApplicable {
|
|
// Since the routing plugin is not applicable for this
|
|
// payment, we can immediately destruct it.
|
|
if err := routingPluginInstance.Done(ctx); err != nil {
|
|
log.Errorf("Error while releasing routing "+
|
|
"plugin: %v", err)
|
|
}
|
|
|
|
// ErrRoutingPluginNotApplicable is non critical, so
|
|
// we're masking this error as we can continue the swap
|
|
// flow without the routing plugin.
|
|
err = nil
|
|
}
|
|
|
|
routingPluginInstance = nil
|
|
return nil, err
|
|
}
|
|
|
|
return routingPluginInstance, nil
|
|
}
|
|
|
|
// ReleaseRoutingPlugin will release the RoutingPlugin, allowing other
|
|
// requestors to acquire the instance.
|
|
func ReleaseRoutingPlugin(ctx context.Context) {
|
|
routingPluginMx.Lock()
|
|
defer routingPluginMx.Unlock()
|
|
|
|
if routingPluginInstance == nil {
|
|
return
|
|
}
|
|
|
|
if err := routingPluginInstance.Done(ctx); err != nil {
|
|
log.Errorf("Error while releasing routing plugin: %v",
|
|
err)
|
|
}
|
|
|
|
routingPluginInstance = nil
|
|
}
|