Skip to content

Commit a244b21

Browse files
committed
staticaddr: refactor methods into utils
1 parent 16d56f1 commit a244b21

File tree

7 files changed

+652
-360
lines changed

7 files changed

+652
-360
lines changed

staticaddr/loopin/actions.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/lightninglabs/loop"
1818
"github.com/lightninglabs/loop/fsm"
1919
"github.com/lightninglabs/loop/staticaddr/deposit"
20+
"github.com/lightninglabs/loop/staticaddr/staticutil"
2021
"github.com/lightninglabs/loop/staticaddr/version"
2122
"github.com/lightninglabs/loop/swap"
2223
"github.com/lightninglabs/loop/swapserverrpc"
@@ -318,8 +319,11 @@ func (f *FSM) SignHtlcTxAction(ctx context.Context,
318319

319320
// Create a musig2 session for each deposit and different htlc tx fee
320321
// rates.
321-
createSession := f.loopIn.createMusig2Sessions
322-
htlcSessions, clientHtlcNonces, err := createSession(ctx, f.cfg.Signer)
322+
createSession := staticutil.CreateMusig2Sessions
323+
htlcSessions, clientHtlcNonces, err := createSession(
324+
ctx, f.cfg.Signer, f.loopIn.Deposits, f.loopIn.AddressParams,
325+
f.loopIn.Address,
326+
)
323327
if err != nil {
324328
err = fmt.Errorf("unable to create musig2 sessions: %w", err)
325329

@@ -328,15 +332,17 @@ func (f *FSM) SignHtlcTxAction(ctx context.Context,
328332
defer f.cleanUpSessions(ctx, htlcSessions)
329333

330334
htlcSessionsHighFee, highFeeNonces, err := createSession(
331-
ctx, f.cfg.Signer,
335+
ctx, f.cfg.Signer, f.loopIn.Deposits, f.loopIn.AddressParams,
336+
f.loopIn.Address,
332337
)
333338
if err != nil {
334339
return f.HandleError(err)
335340
}
336341
defer f.cleanUpSessions(ctx, htlcSessionsHighFee)
337342

338343
htlcSessionsExtremelyHighFee, extremelyHighNonces, err := createSession(
339-
ctx, f.cfg.Signer,
344+
ctx, f.cfg.Signer, f.loopIn.Deposits, f.loopIn.AddressParams,
345+
f.loopIn.Address,
340346
)
341347
if err != nil {
342348
err = fmt.Errorf("unable to convert nonces: %w", err)

staticaddr/loopin/loopin.go

Lines changed: 4 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/lightninglabs/loop/staticaddr/address"
2222
"github.com/lightninglabs/loop/staticaddr/deposit"
2323
"github.com/lightninglabs/loop/staticaddr/script"
24+
"github.com/lightninglabs/loop/staticaddr/staticutil"
2425
"github.com/lightninglabs/loop/staticaddr/version"
2526
"github.com/lightninglabs/loop/swap"
2627
"github.com/lightningnetwork/lnd/input"
@@ -169,55 +170,16 @@ func (l *StaticAddressLoopIn) getHtlc(chainParams *chaincfg.Params) (*swap.Htlc,
169170
)
170171
}
171172

172-
// createMusig2Sessions creates a musig2 session for a number of deposits.
173-
func (l *StaticAddressLoopIn) createMusig2Sessions(ctx context.Context,
174-
signer lndclient.SignerClient) ([]*input.MuSig2SessionInfo, [][]byte,
175-
error) {
176-
177-
musig2Sessions := make([]*input.MuSig2SessionInfo, len(l.Deposits))
178-
clientNonces := make([][]byte, len(l.Deposits))
179-
180-
// Create the sessions and nonces from the deposits.
181-
for i := 0; i < len(l.Deposits); i++ {
182-
session, err := l.createMusig2Session(ctx, signer)
183-
if err != nil {
184-
return nil, nil, err
185-
}
186-
187-
musig2Sessions[i] = session
188-
clientNonces[i] = session.PublicNonce[:]
189-
}
190-
191-
return musig2Sessions, clientNonces, nil
192-
}
193-
194-
// Musig2CreateSession creates a musig2 session for the deposit.
195-
func (l *StaticAddressLoopIn) createMusig2Session(ctx context.Context,
196-
signer lndclient.SignerClient) (*input.MuSig2SessionInfo, error) {
197-
198-
signers := [][]byte{
199-
l.AddressParams.ClientPubkey.SerializeCompressed(),
200-
l.AddressParams.ServerPubkey.SerializeCompressed(),
201-
}
202-
203-
expiryLeaf := l.Address.TimeoutLeaf
204-
205-
rootHash := expiryLeaf.TapHash()
206-
207-
return signer.MuSig2CreateSession(
208-
ctx, input.MuSig2Version100RC2, &l.AddressParams.KeyLocator,
209-
signers, lndclient.MuSig2TaprootTweakOpt(rootHash[:], false),
210-
)
211-
}
212-
213173
// signMusig2Tx adds the server nonces to the musig2 sessions and signs the
214174
// transaction.
215175
func (l *StaticAddressLoopIn) signMusig2Tx(ctx context.Context,
216176
tx *wire.MsgTx, signer lndclient.SignerClient,
217177
musig2sessions []*input.MuSig2SessionInfo,
218178
counterPartyNonces [][musig2.PubNonceSize]byte) ([][]byte, error) {
219179

220-
prevOuts, err := l.toPrevOuts(l.Deposits, l.AddressParams.PkScript)
180+
prevOuts, err := staticutil.ToPrevOuts(
181+
l.Deposits, l.AddressParams.PkScript,
182+
)
221183
if err != nil {
222184
return nil, err
223185
}
@@ -523,29 +485,6 @@ func (l *StaticAddressLoopIn) Outpoints() []wire.OutPoint {
523485
return outpoints
524486
}
525487

526-
func (l *StaticAddressLoopIn) toPrevOuts(deposits []*deposit.Deposit,
527-
pkScript []byte) (map[wire.OutPoint]*wire.TxOut, error) {
528-
529-
prevOuts := make(map[wire.OutPoint]*wire.TxOut, len(deposits))
530-
for _, d := range deposits {
531-
outpoint := wire.OutPoint{
532-
Hash: d.Hash,
533-
Index: d.Index,
534-
}
535-
txOut := &wire.TxOut{
536-
Value: int64(d.Value),
537-
PkScript: pkScript,
538-
}
539-
if _, ok := prevOuts[outpoint]; ok {
540-
return nil, fmt.Errorf("duplicate outpoint %v",
541-
outpoint)
542-
}
543-
prevOuts[outpoint] = txOut
544-
}
545-
546-
return prevOuts, nil
547-
}
548-
549488
// GetState returns the current state of the loop-in swap.
550489
func (l *StaticAddressLoopIn) GetState() fsm.StateType {
551490
l.mu.Lock()

staticaddr/loopin/manager.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/lightninglabs/loop/labels"
2222
"github.com/lightninglabs/loop/staticaddr/address"
2323
"github.com/lightninglabs/loop/staticaddr/deposit"
24+
"github.com/lightninglabs/loop/staticaddr/staticutil"
2425
"github.com/lightninglabs/loop/swapserverrpc"
2526
"github.com/lightningnetwork/lnd/input"
2627
"github.com/lightningnetwork/lnd/lntypes"
@@ -386,8 +387,8 @@ func (m *Manager) handleLoopInSweepReq(ctx context.Context,
386387
)
387388

388389
copy(serverNonce[:], nonce)
389-
musig2Session, err := loopIn.createMusig2Session(
390-
ctx, m.cfg.Signer,
390+
musig2Session, err := staticutil.CreateMusig2Session(
391+
ctx, m.cfg.Signer, loopIn.AddressParams, loopIn.Address,
391392
)
392393
if err != nil {
393394
return err

staticaddr/staticutil/utils.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package staticutil
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"fmt"
7+
"sort"
8+
9+
"github.com/btcsuite/btcd/chaincfg/chainhash"
10+
"github.com/btcsuite/btcd/wire"
11+
"github.com/lightninglabs/lndclient"
12+
"github.com/lightninglabs/loop/staticaddr/address"
13+
"github.com/lightninglabs/loop/staticaddr/deposit"
14+
"github.com/lightninglabs/loop/staticaddr/script"
15+
"github.com/lightninglabs/loop/swapserverrpc"
16+
"github.com/lightningnetwork/lnd/input"
17+
)
18+
19+
// ToPrevOuts converts a slice of deposits to a map of outpoints to TxOuts.
20+
func ToPrevOuts(deposits []*deposit.Deposit,
21+
pkScript []byte) (map[wire.OutPoint]*wire.TxOut, error) {
22+
23+
prevOuts := make(map[wire.OutPoint]*wire.TxOut, len(deposits))
24+
for _, d := range deposits {
25+
outpoint := wire.OutPoint{
26+
Hash: d.Hash,
27+
Index: d.Index,
28+
}
29+
txOut := &wire.TxOut{
30+
Value: int64(d.Value),
31+
PkScript: pkScript,
32+
}
33+
if _, ok := prevOuts[outpoint]; ok {
34+
return nil, fmt.Errorf("duplicate outpoint %v",
35+
outpoint)
36+
}
37+
prevOuts[outpoint] = txOut
38+
}
39+
40+
return prevOuts, nil
41+
}
42+
43+
// CreateMusig2Sessions creates a musig2 session for a number of deposits.
44+
func CreateMusig2Sessions(ctx context.Context,
45+
signer lndclient.SignerClient, deposits []*deposit.Deposit,
46+
addrParams *address.Parameters,
47+
staticAddress *script.StaticAddress) ([]*input.MuSig2SessionInfo,
48+
[][]byte, error) {
49+
50+
musig2Sessions := make([]*input.MuSig2SessionInfo, len(deposits))
51+
clientNonces := make([][]byte, len(deposits))
52+
53+
// Create the sessions and nonces from the deposits.
54+
for i := 0; i < len(deposits); i++ {
55+
session, err := CreateMusig2Session(
56+
ctx, signer, addrParams, staticAddress,
57+
)
58+
if err != nil {
59+
return nil, nil, err
60+
}
61+
62+
musig2Sessions[i] = session
63+
clientNonces[i] = session.PublicNonce[:]
64+
}
65+
66+
return musig2Sessions, clientNonces, nil
67+
}
68+
69+
// CreateMusig2Session creates a musig2 session for the deposit.
70+
func CreateMusig2Session(ctx context.Context,
71+
signer lndclient.SignerClient, addrParams *address.Parameters,
72+
staticAddress *script.StaticAddress) (*input.MuSig2SessionInfo, error) {
73+
74+
signers := [][]byte{
75+
addrParams.ClientPubkey.SerializeCompressed(),
76+
addrParams.ServerPubkey.SerializeCompressed(),
77+
}
78+
79+
expiryLeaf := staticAddress.TimeoutLeaf
80+
81+
rootHash := expiryLeaf.TapHash()
82+
83+
return signer.MuSig2CreateSession(
84+
ctx, input.MuSig2Version100RC2, &addrParams.KeyLocator,
85+
signers, lndclient.MuSig2TaprootTweakOpt(rootHash[:], false),
86+
)
87+
}
88+
89+
// GetPrevoutInfo converts a map of prevOuts to protobuf.
90+
func GetPrevoutInfo(prevOuts map[wire.OutPoint]*wire.TxOut,
91+
) []*swapserverrpc.PrevoutInfo {
92+
93+
prevoutInfos := make([]*swapserverrpc.PrevoutInfo, 0, len(prevOuts))
94+
95+
for outpoint, txOut := range prevOuts {
96+
prevoutInfo := &swapserverrpc.PrevoutInfo{
97+
TxidBytes: outpoint.Hash[:],
98+
OutputIndex: outpoint.Index,
99+
Value: uint64(txOut.Value),
100+
PkScript: txOut.PkScript,
101+
}
102+
prevoutInfos = append(prevoutInfos, prevoutInfo)
103+
}
104+
105+
// Sort UTXOs by txid:index using BIP-0069 rule. The function is used
106+
// in unit tests a lot, and it is useful to make it deterministic.
107+
sort.Slice(prevoutInfos, func(i, j int) bool {
108+
return bip69inputLess(prevoutInfos[i], prevoutInfos[j])
109+
})
110+
111+
return prevoutInfos
112+
}
113+
114+
// bip69inputLess returns true if input1 < input2 according to BIP-0069
115+
// First sort based on input hash (reversed / rpc-style), then index.
116+
// The code is based on btcd/btcutil/txsort/txsort.go.
117+
func bip69inputLess(input1, input2 *swapserverrpc.PrevoutInfo) bool {
118+
// Input hashes are the same, so compare the index.
119+
var ihash, jhash chainhash.Hash
120+
copy(ihash[:], input1.TxidBytes)
121+
copy(jhash[:], input2.TxidBytes)
122+
if ihash == jhash {
123+
return input1.OutputIndex < input2.OutputIndex
124+
}
125+
126+
// At this point, the hashes are not equal, so reverse them to
127+
// big-endian and return the result of the comparison.
128+
const hashSize = chainhash.HashSize
129+
for b := 0; b < hashSize/2; b++ {
130+
ihash[b], ihash[hashSize-1-b] = ihash[hashSize-1-b], ihash[b]
131+
jhash[b], jhash[hashSize-1-b] = jhash[hashSize-1-b], jhash[b]
132+
}
133+
return bytes.Compare(ihash[:], jhash[:]) == -1
134+
}

0 commit comments

Comments
 (0)