Skip to content

Commit daef549

Browse files
committed
loopd: wire recovery service into daemon startup
Register a recovery gRPC endpoint, attach the new recovery package to the swap client server, and have daemon startup write an encrypted backup file whenever recoverable static-address or l402 state already exists locally.
1 parent 58a0da8 commit daef549

File tree

2 files changed

+94
-1
lines changed

2 files changed

+94
-1
lines changed

loopd/daemon.go

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/lightninglabs/loop/loopdb"
2323
loop_looprpc "github.com/lightninglabs/loop/looprpc"
2424
"github.com/lightninglabs/loop/notifications"
25+
"github.com/lightninglabs/loop/recovery"
2526
"github.com/lightninglabs/loop/staticaddr/address"
2627
"github.com/lightninglabs/loop/staticaddr/deposit"
2728
"github.com/lightninglabs/loop/staticaddr/loopin"
@@ -577,17 +578,47 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
577578
withdrawalManager *withdraw.Manager
578579
openChannelManager *openchannel.Manager
579580
staticLoopInManager *loopin.Manager
581+
recoveryService *recovery.Service
580582
)
581583

584+
writeRecoveryBackup := func(ctx context.Context, source string) error {
585+
if recoveryService == nil {
586+
return nil
587+
}
588+
589+
backupFile, err := recoveryService.WriteBackup(ctx)
590+
if err != nil {
591+
return err
592+
}
593+
if backupFile != "" {
594+
infof("Wrote encrypted recovery backup to %s after %s",
595+
backupFile, source)
596+
}
597+
598+
return nil
599+
}
600+
582601
// Static address manager setup.
583602
staticAddressStore := address.NewSqlStore(baseDb)
584603
addrCfg := &address.ManagerConfig{
585604
AddressClient: staticAddressClient,
586-
FetchL402: swapClient.Server.FetchL402,
605+
FetchL402: func(ctx context.Context) error {
606+
err := swapClient.Server.FetchL402(ctx)
607+
if err != nil {
608+
return err
609+
}
610+
611+
return writeRecoveryBackup(ctx, "retrieving a paid L402")
612+
},
587613
Store: staticAddressStore,
588614
WalletKit: d.lnd.WalletKit,
589615
ChainParams: d.lnd.ChainParams,
590616
ChainNotifier: d.lnd.ChainNotifier,
617+
OnStaticAddressCreated: func(ctx context.Context) error {
618+
return writeRecoveryBackup(
619+
ctx, "creating a static address",
620+
)
621+
},
591622
}
592623
staticAddressManager, err = address.NewManager(
593624
addrCfg, int32(blockHeight),
@@ -689,6 +720,15 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
689720
return fmt.Errorf("unable to create loop-in manager: %w", err)
690721
}
691722

723+
recoveryService = recovery.NewService(
724+
d.cfg.DataDir, d.cfg.Network, d.lnd.Signer, d.lnd.WalletKit,
725+
staticAddressManager, depositManager,
726+
)
727+
err = writeRecoveryBackup(d.mainCtx, "startup")
728+
if err != nil {
729+
return fmt.Errorf("unable to write backup file: %w", err)
730+
}
731+
692732
var (
693733
reservationManager *reservation.Manager
694734
instantOutManager *instantout.Manager
@@ -753,6 +793,7 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
753793
staticLoopInManager: staticLoopInManager,
754794
openChannelManager: openChannelManager,
755795
assetClient: d.assetClient,
796+
recoveryService: recoveryService,
756797
stopDaemon: d.Stop,
757798
}
758799

loopd/swapclient_server.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/lightninglabs/loop/liquidity"
3030
"github.com/lightninglabs/loop/loopdb"
3131
"github.com/lightninglabs/loop/looprpc"
32+
"github.com/lightninglabs/loop/recovery"
3233
"github.com/lightninglabs/loop/staticaddr/address"
3334
"github.com/lightninglabs/loop/staticaddr/deposit"
3435
"github.com/lightninglabs/loop/staticaddr/loopin"
@@ -101,6 +102,7 @@ type swapClientServer struct {
101102
staticLoopInManager *loopin.Manager
102103
openChannelManager *openchannel.Manager
103104
assetClient *assets.TapdClient
105+
recoveryService *recovery.Service
104106
swaps map[lntypes.Hash]loop.SwapInfo
105107
subscribers map[int]chan<- any
106108
statusChan chan loop.SwapInfo
@@ -1265,9 +1267,59 @@ func (s *swapClientServer) FetchL402Token(ctx context.Context,
12651267
return nil, err
12661268
}
12671269

1270+
err = s.writeRecoveryBackup(ctx, "retrieving a paid L402")
1271+
if err != nil {
1272+
return nil, err
1273+
}
1274+
12681275
return &looprpc.FetchL402TokenResponse{}, nil
12691276
}
12701277

1278+
// Recover restores the local paid L402 token material and static-address state
1279+
// from an encrypted backup file.
1280+
func (s *swapClientServer) Recover(ctx context.Context,
1281+
req *looprpc.RecoverRequest) (*looprpc.RecoverResponse, error) {
1282+
1283+
if s.recoveryService == nil {
1284+
return nil, status.Error(
1285+
codes.Unavailable, "recovery service not configured",
1286+
)
1287+
}
1288+
1289+
result, err := s.recoveryService.Restore(ctx, req.GetBackupFile())
1290+
if err != nil {
1291+
return nil, err
1292+
}
1293+
1294+
return &looprpc.RecoverResponse{
1295+
BackupFile: result.BackupFile,
1296+
RestoredL402: result.RestoredL402,
1297+
RestoredStaticAddress: result.RestoredStaticAddress,
1298+
StaticAddress: result.StaticAddress,
1299+
NumDepositsFound: uint32(result.NumDepositsFound),
1300+
DepositReconciliationError: result.DepositReconciliationError,
1301+
}, nil
1302+
}
1303+
1304+
func (s *swapClientServer) writeRecoveryBackup(ctx context.Context,
1305+
source string) error {
1306+
1307+
if s.recoveryService == nil {
1308+
return nil
1309+
}
1310+
1311+
backupFile, err := s.recoveryService.WriteBackup(ctx)
1312+
if err != nil {
1313+
return err
1314+
}
1315+
if backupFile != "" {
1316+
infof("Wrote encrypted recovery backup to %s after %s",
1317+
backupFile, source)
1318+
}
1319+
1320+
return nil
1321+
}
1322+
12711323
// GetInfo returns basic information about the loop daemon and details to swaps
12721324
// from the swap store.
12731325
func (s *swapClientServer) GetInfo(ctx context.Context,

0 commit comments

Comments
 (0)