Skip to content

Commit 6807201

Browse files
committed
loopd: add reservation handling
1 parent 4c2a533 commit 6807201

File tree

4 files changed

+144
-24
lines changed

4 files changed

+144
-24
lines changed

loopd/daemon.go

Lines changed: 67 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ import (
1818
"github.com/lightninglabs/loop"
1919
"github.com/lightninglabs/loop/loopd/perms"
2020
"github.com/lightninglabs/loop/loopdb"
21-
"github.com/lightninglabs/loop/looprpc"
21+
22+
loop_looprpc "github.com/lightninglabs/loop/looprpc"
23+
"github.com/lightninglabs/loop/reservation"
24+
25+
loop_swaprpc "github.com/lightninglabs/loop/swapserverrpc"
2226
"github.com/lightningnetwork/lnd/lntypes"
2327
"github.com/lightningnetwork/lnd/macaroons"
2428
"google.golang.org/grpc"
@@ -62,6 +66,10 @@ type Daemon struct {
6266
// same process.
6367
swapClientServer
6468

69+
// reservationManager is the manager that handles all reservation state
70+
// machines.
71+
reservationManager *reservation.Manager
72+
6573
// ErrChan is an error channel that users of the Daemon struct must use
6674
// to detect runtime errors and also whether a shutdown is fully
6775
// completed.
@@ -226,7 +234,7 @@ func (d *Daemon) startWebServers() error {
226234
grpc.UnaryInterceptor(unaryInterceptor),
227235
grpc.StreamInterceptor(streamInterceptor),
228236
)
229-
looprpc.RegisterSwapClientServer(d.grpcServer, d)
237+
loop_looprpc.RegisterSwapClientServer(d.grpcServer, d)
230238

231239
// Register our debug server if it is compiled in.
232240
d.registerDebugServer()
@@ -286,7 +294,7 @@ func (d *Daemon) startWebServers() error {
286294
restProxyDest, "[::]", "[::1]", 1,
287295
)
288296
}
289-
err = looprpc.RegisterSwapClientHandlerFromEndpoint(
297+
err = loop_looprpc.RegisterSwapClientHandlerFromEndpoint(
290298
ctx, mux, restProxyDest, proxyOpts,
291299
)
292300
if err != nil {
@@ -399,7 +407,7 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
399407
return err
400408
}
401409

402-
swapDb, _, err := openDatabase(d.cfg, chainParams)
410+
swapDb, baseDb, err := openDatabase(d.cfg, chainParams)
403411
if err != nil {
404412
return err
405413
}
@@ -413,6 +421,15 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
413421
}
414422
d.clientCleanup = clientCleanup
415423

424+
// Create a reservation server client.
425+
reservationClient := loop_swaprpc.NewReservationServiceClient(
426+
swapClient.Conn,
427+
)
428+
429+
// Both the client RPC server and the swap server client should stop
430+
// on main context cancel. So we create it early and pass it down.
431+
d.mainCtx, d.mainCtxCancel = context.WithCancel(context.Background())
432+
416433
// Add our debug permissions to our main set of required permissions
417434
// if compiled in.
418435
for endpoint, perm := range debugRequiredPermissions {
@@ -466,17 +483,31 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
466483
}
467484
}
468485

486+
// Create the reservation rpc server.
487+
reservationStore := reservation.NewSQLStore(baseDb)
488+
reservationConfig := &reservation.Config{
489+
Store: reservationStore,
490+
Wallet: d.lnd.WalletKit,
491+
ChainNotifier: d.lnd.ChainNotifier,
492+
ReservationClient: reservationClient,
493+
}
494+
495+
d.reservationManager = reservation.NewReservationManager(
496+
reservationConfig,
497+
)
498+
469499
// Now finally fully initialize the swap client RPC server instance.
470500
d.swapClientServer = swapClientServer{
471-
config: d.cfg,
472-
network: lndclient.Network(d.cfg.Network),
473-
impl: swapClient,
474-
liquidityMgr: getLiquidityManager(swapClient),
475-
lnd: &d.lnd.LndServices,
476-
swaps: make(map[lntypes.Hash]loop.SwapInfo),
477-
subscribers: make(map[int]chan<- interface{}),
478-
statusChan: make(chan loop.SwapInfo),
479-
mainCtx: d.mainCtx,
501+
config: d.cfg,
502+
network: lndclient.Network(d.cfg.Network),
503+
impl: swapClient,
504+
liquidityMgr: getLiquidityManager(swapClient),
505+
lnd: &d.lnd.LndServices,
506+
swaps: make(map[lntypes.Hash]loop.SwapInfo),
507+
subscribers: make(map[int]chan<- interface{}),
508+
statusChan: make(chan loop.SwapInfo),
509+
mainCtx: d.mainCtx,
510+
reservationManager: d.reservationManager,
480511
}
481512

482513
// Retrieve all currently existing swaps from the database.
@@ -543,6 +574,29 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
543574
log.Info("Liquidity manager stopped")
544575
}()
545576

577+
// Start the reservation manager.
578+
d.wg.Add(1)
579+
go func() {
580+
defer d.wg.Done()
581+
582+
getInfo, err := d.lnd.Client.GetInfo(d.mainCtx)
583+
if err != nil {
584+
d.internalErrChan <- err
585+
return
586+
}
587+
588+
log.Info("Starting reservation manager")
589+
defer log.Info("Reservation manager stopped")
590+
591+
err = d.reservationManager.Run(
592+
d.mainCtx, int32(getInfo.BlockHeight),
593+
)
594+
if err != nil && !errors.Is(err, context.Canceled) {
595+
d.internalErrChan <- err
596+
}
597+
598+
}()
599+
546600
// Last, start our internal error handler. This will return exactly one
547601
// error or nil on the main error channel to inform the caller that
548602
// something went wrong or that shutdown is complete. We don't add to

loopd/log.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/lightninglabs/loop/fsm"
99
"github.com/lightninglabs/loop/liquidity"
1010
"github.com/lightninglabs/loop/loopdb"
11+
"github.com/lightninglabs/loop/reservation"
1112
"github.com/lightningnetwork/lnd"
1213
"github.com/lightningnetwork/lnd/build"
1314
"github.com/lightningnetwork/lnd/signal"
@@ -38,6 +39,9 @@ func SetupLoggers(root *build.RotatingLogWriter, intercept signal.Interceptor) {
3839
root, liquidity.Subsystem, intercept, liquidity.UseLogger,
3940
)
4041
lnd.AddSubLogger(root, fsm.Subsystem, intercept, fsm.UseLogger)
42+
lnd.AddSubLogger(
43+
root, reservation.Subsystem, intercept, reservation.UseLogger,
44+
)
4145
}
4246

4347
// genSubLogger creates a logger for a subsystem. We provide an instance of

loopd/perms/perms.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,8 @@ var RequiredPermissions = map[string][]bakery.Op{
8686
Entity: "loop",
8787
Action: "in",
8888
}},
89+
"/looprpc.SwapClient/ListReservations": {{
90+
Entity: "reservation",
91+
Action: "read",
92+
}},
8993
}

loopd/swapclient_server.go

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/lightninglabs/loop/liquidity"
2121
"github.com/lightninglabs/loop/loopdb"
2222
clientrpc "github.com/lightninglabs/loop/looprpc"
23+
"github.com/lightninglabs/loop/reservation"
2324
"github.com/lightninglabs/loop/swap"
2425
looprpc "github.com/lightninglabs/loop/swapserverrpc"
2526
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
@@ -72,17 +73,18 @@ type swapClientServer struct {
7273
clientrpc.UnimplementedSwapClientServer
7374
clientrpc.UnimplementedDebugServer
7475

75-
config *Config
76-
network lndclient.Network
77-
impl *loop.Client
78-
liquidityMgr *liquidity.Manager
79-
lnd *lndclient.LndServices
80-
swaps map[lntypes.Hash]loop.SwapInfo
81-
subscribers map[int]chan<- interface{}
82-
statusChan chan loop.SwapInfo
83-
nextSubscriberID int
84-
swapsLock sync.Mutex
85-
mainCtx context.Context
76+
config *Config
77+
network lndclient.Network
78+
impl *loop.Client
79+
liquidityMgr *liquidity.Manager
80+
lnd *lndclient.LndServices
81+
reservationManager *reservation.Manager
82+
swaps map[lntypes.Hash]loop.SwapInfo
83+
subscribers map[int]chan<- interface{}
84+
statusChan chan loop.SwapInfo
85+
nextSubscriberID int
86+
swapsLock sync.Mutex
87+
mainCtx context.Context
8688
}
8789

8890
// LoopOut initiates a loop out swap with the given parameters. The call returns
@@ -1008,6 +1010,25 @@ func (s *swapClientServer) SuggestSwaps(ctx context.Context,
10081010
return resp, nil
10091011
}
10101012

1013+
// ListReservations lists all existing reservations the client has ever made.
1014+
func (s *swapClientServer) ListReservations(ctx context.Context,
1015+
_ *clientrpc.ListReservationsRequest) (
1016+
*clientrpc.ListReservationsResponse, error) {
1017+
1018+
reservations, err := s.reservationManager.GetReservations(
1019+
ctx,
1020+
)
1021+
if err != nil {
1022+
return nil, err
1023+
}
1024+
1025+
return &clientrpc.ListReservationsResponse{
1026+
Reservations: ToClientReservations(
1027+
reservations,
1028+
),
1029+
}, nil
1030+
}
1031+
10111032
func rpcAutoloopReason(reason liquidity.Reason) (clientrpc.AutoReason, error) {
10121033
switch reason {
10131034
case liquidity.ReasonNone:
@@ -1267,3 +1288,40 @@ func getPublicationDeadline(unixTimestamp uint64) time.Time {
12671288
return time.Unix(int64(unixTimestamp), 0)
12681289
}
12691290
}
1291+
1292+
// ToClientReservations converts a slice of server
1293+
// reservations to a slice of client reservations.
1294+
func ToClientReservations(
1295+
res []*reservation.Reservation) []*clientrpc.ClientReservation {
1296+
1297+
var result []*clientrpc.ClientReservation
1298+
for _, r := range res {
1299+
result = append(result, toClientReservation(r))
1300+
}
1301+
1302+
return result
1303+
}
1304+
1305+
// toClientReservation converts a server reservation to a
1306+
// client reservation.
1307+
func toClientReservation(
1308+
res *reservation.Reservation) *clientrpc.ClientReservation {
1309+
1310+
var (
1311+
txid []byte
1312+
vout uint32
1313+
)
1314+
if res.Outpoint != nil {
1315+
txid = res.Outpoint.Hash[:]
1316+
vout = res.Outpoint.Index
1317+
}
1318+
1319+
return &clientrpc.ClientReservation{
1320+
ReservationId: res.ID[:],
1321+
State: string(res.State),
1322+
Amount: uint64(res.Value),
1323+
TxId: txid,
1324+
Vout: vout,
1325+
Expiry: res.Expiry,
1326+
}
1327+
}

0 commit comments

Comments
 (0)