Skip to content

Commit 914bc6d

Browse files
committed
fixup! staticaddr/loopin: add listening for sweep request
1 parent b243f38 commit 914bc6d

File tree

2 files changed

+123
-80
lines changed

2 files changed

+123
-80
lines changed

staticaddr/loopin/interface.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,5 +84,5 @@ type NotificationManager interface {
8484
// sweep requests. These are sent by the server to the client to request
8585
// a sweep of a static loop in that has been finished.
8686
SubscribeStaticLoopInSweepRequests(ctx context.Context,
87-
) <-chan *swapserverrpc.ServerStaticLoopInSweepRequest
87+
) <-chan *swapserverrpc.ServerStaticLoopInSweepNotification
8888
}

staticaddr/loopin/manager.go

Lines changed: 122 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ import (
2424
"github.com/lightningnetwork/lnd/routing/route"
2525
)
2626

27+
var (
28+
// errSwapNotFinished is returned when a swap is not finished.
29+
errSwapNotFinished = fmt.Errorf("swap not finished")
30+
)
31+
2732
// Config contains the services required for the loop-in manager.
2833
type Config struct {
2934
// Server is the client that is used to communicate with the static
@@ -219,11 +224,23 @@ func (m *Manager) Run(ctx context.Context, currentHeight uint32) error {
219224
}
220225
}
221226

227+
// notifyNotFinished notifies the server that a swap is not finished by
228+
// sending an empty signature map.
229+
func (m *Manager) notifyNotFinished(ctx context.Context, swapHash lntypes.Hash,
230+
txId chainhash.Hash) error {
231+
_, err := m.cfg.Server.PushStaticAddressSweeplessSigs(
232+
ctx, &looprpc.PushStaticAddressSweeplessSigsRequest{
233+
SwapHash: swapHash[:],
234+
Txid: txId[:],
235+
})
236+
return err
237+
}
238+
222239
// handleLoopInSweepReq handles a loop-in sweep request from the server.
223240
// It first checks if the requested loop-in is finished as expected and if
224241
// yes will send signature to the server for the provided psbt.
225242
func (m *Manager) handleLoopInSweepReq(ctx context.Context,
226-
req *swapserverrpc.ServerStaticLoopInSweepRequest) error {
243+
req *swapserverrpc.ServerStaticLoopInSweepNotification) error {
227244

228245
// First we'll check if the loop-ins are known to us and in
229246
// the expected state.
@@ -238,11 +255,18 @@ func (m *Manager) handleLoopInSweepReq(ctx context.Context,
238255
return err
239256
}
240257

241-
// If the loop-in is not in the Succeeded state we return an
242-
// error.
243-
if loopIn.state != Succeeded {
244-
return fmt.Errorf("loop-in %v not in Succeeded state",
245-
swapHash)
258+
loopIn.AddressParams, err =
259+
m.cfg.AddressManager.GetStaticAddressParameters(ctx)
260+
261+
if err != nil {
262+
return err
263+
}
264+
265+
loopIn.Address, err = m.cfg.AddressManager.GetStaticAddress(
266+
ctx,
267+
)
268+
if err != nil {
269+
return err
246270
}
247271

248272
reader := bytes.NewReader(req.SweepTxPsbt)
@@ -253,16 +277,58 @@ func (m *Manager) handleLoopInSweepReq(ctx context.Context,
253277

254278
sweepTx := sweepPacket.UnsignedTx
255279

280+
// If the loop-in is not in the Succeeded state we return an
281+
// error.
282+
if loopIn.state != Succeeded {
283+
// We'll notify the server that we don't consider the swap
284+
// finished yet, so it can retry later.
285+
_ = m.notifyNotFinished(ctx, swapHash, sweepTx.TxHash())
286+
return fmt.Errorf("loop-in %v not in Succeeded state",
287+
swapHash)
288+
}
289+
256290
// Perform a sanity check on the number of unsigned tx inputs and
257291
// prevout info.
258292
if len(sweepTx.TxIn) != len(req.PrevoutInfo) {
259293
return fmt.Errorf("expected %v inputs, got %v",
260294
len(req.PrevoutInfo), len(sweepTx.TxIn))
261295
}
262296

297+
// Check if all the deposits requested are part of the loop-in and
298+
// find them in the requested sweep.
299+
depositToIdxMap := make(map[string]int)
300+
for reqOutpoint := range req.DepositToNonces {
301+
hasDeposit := false
302+
for _, depositOutpoint := range loopIn.DepositOutpoints {
303+
if depositOutpoint == reqOutpoint {
304+
hasDeposit = true
305+
break
306+
}
307+
}
308+
if !hasDeposit {
309+
return fmt.Errorf("deposit outpoint not part of " +
310+
"loop-in")
311+
}
312+
313+
foundDepositInTx := false
314+
315+
for i, txIn := range sweepTx.TxIn {
316+
if txIn.PreviousOutPoint.String() == reqOutpoint {
317+
depositToIdxMap[reqOutpoint] = i
318+
foundDepositInTx = true
319+
break
320+
}
321+
}
322+
323+
if !foundDepositInTx {
324+
return fmt.Errorf("deposit outpoint not part of " +
325+
"sweep tx")
326+
}
327+
}
328+
263329
prevoutMap := make(map[wire.OutPoint]*wire.TxOut)
264-
var depositOutpoint *wire.OutPoint
265330

331+
// Set all the prevouts in the prevout map.
266332
for i := range req.PrevoutInfo {
267333
prevout := req.PrevoutInfo[i]
268334

@@ -271,13 +337,6 @@ func (m *Manager) handleLoopInSweepReq(ctx context.Context,
271337
return err
272338
}
273339

274-
if i == int(req.OutputIndex) {
275-
depositOutpoint = &wire.OutPoint{
276-
Hash: *txid,
277-
Index: prevout.OutputIndex,
278-
}
279-
}
280-
281340
prevoutMap[wire.OutPoint{
282341
Hash: *txid,
283342
Index: prevout.OutputIndex,
@@ -287,24 +346,6 @@ func (m *Manager) handleLoopInSweepReq(ctx context.Context,
287346
}
288347
}
289348

290-
// Check if the deposit outpoint is part of the loop-in.
291-
if depositOutpoint == nil {
292-
return fmt.Errorf("deposit outpoint not part of loop-in")
293-
}
294-
295-
foundDeposit := false
296-
for _, loopInDeposit := range loopIn.DepositOutpoints {
297-
if loopInDeposit == fmt.Sprintf("%v:%v",
298-
depositOutpoint.Hash, depositOutpoint.Index) {
299-
300-
foundDeposit = true
301-
}
302-
}
303-
304-
if !foundDeposit {
305-
return fmt.Errorf("deposit outpoint not part of loop-in")
306-
}
307-
308349
prevOutputFetcher := txscript.NewMultiPrevOutFetcher(
309350
prevoutMap,
310351
)
@@ -313,65 +354,67 @@ func (m *Manager) handleLoopInSweepReq(ctx context.Context,
313354
sweepPacket.UnsignedTx, prevOutputFetcher,
314355
)
315356

316-
taprootSigHash, err := txscript.CalcTaprootSignatureHash(
317-
sigHashes, txscript.SigHashDefault, sweepPacket.UnsignedTx,
318-
int(req.OutputIndex), prevOutputFetcher,
319-
)
320-
if err != nil {
321-
return err
322-
}
357+
// We'll now sign for every deposit that is part of the loop-in.
358+
responseMap := make(map[string]*looprpc.ClientSweeplessSigningInfo)
359+
for depositOutpoint, nonce := range req.DepositToNonces {
360+
taprootSigHash, err := txscript.CalcTaprootSignatureHash(
361+
sigHashes, txscript.SigHashDefault, sweepPacket.UnsignedTx,
362+
depositToIdxMap[depositOutpoint], prevOutputFetcher,
363+
)
364+
if err != nil {
365+
return err
366+
}
323367

324-
var (
325-
serverNonce [musig2.PubNonceSize]byte
326-
sigHash [32]byte
327-
)
368+
var (
369+
serverNonce [musig2.PubNonceSize]byte
370+
sigHash [32]byte
371+
)
328372

329-
copy(serverNonce[:], req.Nonce)
330-
musig2Session, err := loopIn.createMusig2Session(ctx, m.cfg.Signer)
331-
if err != nil {
332-
return err
333-
}
373+
copy(serverNonce[:], nonce)
374+
musig2Session, err := loopIn.createMusig2Session(
375+
ctx, m.cfg.Signer,
376+
)
377+
if err != nil {
378+
return err
379+
}
334380

335-
haveAllNonces, err := m.cfg.Signer.MuSig2RegisterNonces(
336-
ctx, musig2Session.SessionID,
337-
[][musig2.PubNonceSize]byte{serverNonce},
338-
)
339-
if err != nil {
340-
return err
341-
}
381+
haveAllNonces, err := m.cfg.Signer.MuSig2RegisterNonces(
382+
ctx, musig2Session.SessionID,
383+
[][musig2.PubNonceSize]byte{serverNonce},
384+
)
385+
if err != nil {
386+
return err
387+
}
342388

343-
if !haveAllNonces {
344-
return fmt.Errorf("expected all nonces to be registered")
345-
}
389+
if !haveAllNonces {
390+
return fmt.Errorf("expected all nonces to be " +
391+
"registered")
392+
}
346393

347-
copy(sigHash[:], taprootSigHash)
394+
copy(sigHash[:], taprootSigHash)
348395

349-
// Since our MuSig2 session has all nonces, we can now create
350-
// the local partial signature by signing the sig hash.
351-
sig, err := m.cfg.Signer.MuSig2Sign(
352-
ctx, musig2Session.SessionID, sigHash, false,
353-
)
354-
if err != nil {
355-
return err
396+
// Since our MuSig2 session has all nonces, we can now create
397+
// the local partial signature by signing the sig hash.
398+
sig, err := m.cfg.Signer.MuSig2Sign(
399+
ctx, musig2Session.SessionID, sigHash, true,
400+
)
401+
if err != nil {
402+
return err
403+
}
404+
405+
responseMap[depositOutpoint] = &looprpc.ClientSweeplessSigningInfo{ //nolint:lll
406+
Nonce: musig2Session.PublicNonce[:],
407+
Sig: sig,
408+
}
356409
}
357410

358411
txHash := sweepTx.TxHash()
359412

360-
// We'll now push the signature to the server.
361-
msg := &looprpc.PushSingleDepositVersion{
362-
TxHash: txHash[:],
363-
OutputIndex: req.OutputIndex,
364-
Nonce: musig2Session.PublicNonce[:],
365-
Sig: sig,
366-
}
367-
368413
_, err = m.cfg.Server.PushStaticAddressSweeplessSigs(
369414
ctx, &looprpc.PushStaticAddressSweeplessSigsRequest{
370-
371-
SwapHash: loopIn.SwapHash[:],
372-
Message: &looprpc.PushStaticAddressSweeplessSigsRequest_SingleDepositVersion{ //nolint:lll
373-
SingleDepositVersion: msg,
374-
},
415+
SwapHash: loopIn.SwapHash[:],
416+
Txid: txHash[:],
417+
SigningInfo: responseMap,
375418
},
376419
)
377420
return err

0 commit comments

Comments
 (0)