Skip to content

Commit d5b6fba

Browse files
committed
staticaddr: refactor methods into utils
� Conflicts: � staticaddr/utils.go
1 parent 48a5f46 commit d5b6fba

File tree

2 files changed

+147
-57
lines changed

2 files changed

+147
-57
lines changed

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+
}

staticaddr/withdraw/manager.go

Lines changed: 13 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/btcsuite/btcwallet/chain"
2020
"github.com/lightninglabs/lndclient"
2121
"github.com/lightninglabs/loop/staticaddr/deposit"
22+
"github.com/lightninglabs/loop/staticaddr/staticutil"
2223
staticaddressrpc "github.com/lightninglabs/loop/swapserverrpc"
2324
"github.com/lightningnetwork/lnd/chainntnfs"
2425
"github.com/lightningnetwork/lnd/input"
@@ -466,8 +467,18 @@ func (m *Manager) createFinalizedWithdrawalTx(ctx context.Context,
466467
error) {
467468

468469
// Create a musig2 session for each deposit.
469-
withdrawalSessions, clientNonces, err := m.createMusig2Sessions(
470-
ctx, deposits,
470+
addrParams, err := m.cfg.AddressManager.GetStaticAddressParameters(ctx)
471+
if err != nil {
472+
return nil, err
473+
}
474+
475+
staticAddress, err := m.cfg.AddressManager.GetStaticAddress(ctx)
476+
if err != nil {
477+
return nil, err
478+
}
479+
480+
withdrawalSessions, clientNonces, err := staticutil.CreateMusig2Sessions(
481+
ctx, m.cfg.Signer, deposits, addrParams, staticAddress,
471482
)
472483
if err != nil {
473484
return nil, err
@@ -987,61 +998,6 @@ func toPrevoutInfo(outpoints []wire.OutPoint) []*staticaddressrpc.PrevoutInfo {
987998
return result
988999
}
9891000

990-
// createMusig2Sessions creates a musig2 session for a number of deposits.
991-
func (m *Manager) createMusig2Sessions(ctx context.Context,
992-
deposits []*deposit.Deposit) ([]*input.MuSig2SessionInfo, [][]byte,
993-
error) {
994-
995-
musig2Sessions := make([]*input.MuSig2SessionInfo, len(deposits))
996-
clientNonces := make([][]byte, len(deposits))
997-
998-
// Create the sessions and nonces from the deposits.
999-
for i := 0; i < len(deposits); i++ {
1000-
session, err := m.createMusig2Session(ctx)
1001-
if err != nil {
1002-
return nil, nil, err
1003-
}
1004-
1005-
musig2Sessions[i] = session
1006-
clientNonces[i] = session.PublicNonce[:]
1007-
}
1008-
1009-
return musig2Sessions, clientNonces, nil
1010-
}
1011-
1012-
// Musig2CreateSession creates a musig2 session for the deposit.
1013-
func (m *Manager) createMusig2Session(ctx context.Context) (
1014-
*input.MuSig2SessionInfo, error) {
1015-
1016-
addressParams, err := m.cfg.AddressManager.GetStaticAddressParameters(
1017-
ctx,
1018-
)
1019-
if err != nil {
1020-
return nil, fmt.Errorf("couldn't get confirmation height for "+
1021-
"deposit, %w", err)
1022-
}
1023-
1024-
signers := [][]byte{
1025-
addressParams.ClientPubkey.SerializeCompressed(),
1026-
addressParams.ServerPubkey.SerializeCompressed(),
1027-
}
1028-
1029-
address, err := m.cfg.AddressManager.GetStaticAddress(ctx)
1030-
if err != nil {
1031-
return nil, fmt.Errorf("couldn't get confirmation height for "+
1032-
"deposit, %w", err)
1033-
}
1034-
1035-
expiryLeaf := address.TimeoutLeaf
1036-
1037-
rootHash := expiryLeaf.TapHash()
1038-
1039-
return m.cfg.Signer.MuSig2CreateSession(
1040-
ctx, input.MuSig2Version100RC2, &addressParams.KeyLocator,
1041-
signers, lndclient.MuSig2TaprootTweakOpt(rootHash[:], false),
1042-
)
1043-
}
1044-
10451001
func (m *Manager) toPrevOuts(deposits []*deposit.Deposit,
10461002
pkScript []byte) map[wire.OutPoint]*wire.TxOut {
10471003

0 commit comments

Comments
 (0)