Skip to content

Commit 47f4826

Browse files
committed
staticaddr: refactor methods into utils
� Conflicts: � staticaddr/utils.go
1 parent 8ef7584 commit 47f4826

File tree

2 files changed

+146
-57
lines changed

2 files changed

+146
-57
lines changed

staticaddr/staticutil/utils.go

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

staticaddr/withdraw/manager.go

+13-57
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"github.com/lightninglabs/loop/staticaddr/staticutil"
78
"reflect"
89
"strings"
910
"sync"
@@ -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)