Skip to content

Commit a252e2c

Browse files
committed
loopdb: add the local pubkey's keylocator to the persisted contract
1 parent ce3026d commit a252e2c

File tree

6 files changed

+153
-0
lines changed

6 files changed

+153
-0
lines changed

loopdb/codec.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package loopdb
22

33
import (
4+
"bytes"
45
"fmt"
6+
7+
"github.com/lightningnetwork/lnd/channeldb"
8+
"github.com/lightningnetwork/lnd/keychain"
59
)
610

711
// itob returns an 8-byte big endian representation of v.
@@ -40,3 +44,39 @@ func MarshalProtocolVersion(version ProtocolVersion) []byte {
4044

4145
return versionBytes[:]
4246
}
47+
48+
// MarshalKeyLocator marshals a keychain.KeyLocator to a byte slice.
49+
func MarshalKeyLocator(keyLocator keychain.KeyLocator) ([]byte, error) {
50+
var (
51+
scratch [8]byte
52+
buf bytes.Buffer
53+
)
54+
55+
err := channeldb.EKeyLocator(&buf, &keyLocator, &scratch)
56+
if err != nil {
57+
return nil, err
58+
}
59+
60+
return buf.Bytes(), nil
61+
}
62+
63+
// UnmarshalKeyLocator unmarshals a keychain.KeyLocator from a byte slice.
64+
func UnmarshalKeyLocator(data []byte) (keychain.KeyLocator, error) {
65+
if data == nil {
66+
return keychain.KeyLocator{}, nil
67+
}
68+
69+
var (
70+
scratch [8]byte
71+
keyLocator keychain.KeyLocator
72+
)
73+
74+
err := channeldb.DKeyLocator(
75+
bytes.NewReader(data), &keyLocator, &scratch, 8,
76+
)
77+
if err != nil {
78+
return keychain.KeyLocator{}, err
79+
}
80+
81+
return keyLocator, nil
82+
}

loopdb/codec_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package loopdb
22

33
import (
4+
"math"
45
"testing"
56

7+
"github.com/lightningnetwork/lnd/keychain"
68
"github.com/stretchr/testify/require"
79
)
810

@@ -51,3 +53,46 @@ func TestProtocolVersionMarshalUnMarshal(t *testing.T) {
5153
require.Equal(t, ProtocolVersionUnrecorded, version)
5254
}
5355
}
56+
57+
// TestKeyLocatorMarshalUnMarshal tests that marshalling and unmarshalling
58+
// keychain.KeyLocator works correctly.
59+
func TestKeyLocatorMarshalUnMarshal(t *testing.T) {
60+
t.Parallel()
61+
62+
tests := []struct {
63+
keyLoc keychain.KeyLocator
64+
}{
65+
{
66+
// Test that an empty keylocator is serialized and
67+
// deserialized correctly.
68+
keyLoc: keychain.KeyLocator{},
69+
},
70+
{
71+
// Test that the max value keylocator is serialized and
72+
// deserialized correctly.
73+
keyLoc: keychain.KeyLocator{
74+
Family: keychain.KeyFamily(math.MaxUint32),
75+
Index: math.MaxUint32,
76+
},
77+
},
78+
{
79+
// Test that an arbitrary keylocator is serialized and
80+
// deserialized correctly.
81+
keyLoc: keychain.KeyLocator{
82+
Family: keychain.KeyFamily(5),
83+
Index: 7,
84+
},
85+
},
86+
}
87+
88+
for _, test := range tests {
89+
test := test
90+
91+
buf, err := MarshalKeyLocator(test.keyLoc)
92+
require.NoError(t, err)
93+
94+
keyLoc, err := UnmarshalKeyLocator(buf)
95+
require.NoError(t, err)
96+
require.Equal(t, test.keyLoc, keyLoc)
97+
}
98+
}

loopdb/loop.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"time"
77

88
"github.com/btcsuite/btcd/btcutil"
9+
"github.com/lightningnetwork/lnd/keychain"
910
"github.com/lightningnetwork/lnd/lntypes"
1011
)
1112

@@ -26,6 +27,11 @@ type SwapContract struct {
2627
// HTLC.
2728
ReceiverKey [33]byte
2829

30+
// ClientKeyLocator is the key locator (family and index) for the client
31+
// key. It is for the receiver key if this is a loop out contract, or
32+
// the sender key if this is a loop in contract.
33+
ClientKeyLocator keychain.KeyLocator
34+
2935
// CltvExpiry is the total absolute CLTV expiry of the swap.
3036
CltvExpiry int32
3137

loopdb/store.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,16 @@ var (
102102
// parameters.
103103
liquidtyParamsKey = []byte("params")
104104

105+
// keyLocatorKey is the key that stores the receiver key's locator info
106+
// for loop outs or the sender key's locator info for loop ins. This is
107+
// required for MuSig2 swaps. Only serialized/deserialized for swaps
108+
// that have protocol version >= ProtocolVersionHtlcV3.
109+
//
110+
// path: loopInBucket/loopOutBucket -> swapBucket[hash] -> keyLocatorKey
111+
//
112+
// value: concatenation of uint32 values [family, index].
113+
keyLocatorKey = []byte("keylocator")
114+
105115
byteOrder = binary.BigEndian
106116

107117
keyLength = 33
@@ -327,6 +337,16 @@ func (s *boltSwapStore) FetchLoopOutSwaps() ([]*LoopOut, error) {
327337
return err
328338
}
329339

340+
// Try to unmarshal the key locator.
341+
if contract.ProtocolVersion >= ProtocolVersionHtlcV3 {
342+
contract.ClientKeyLocator, err = UnmarshalKeyLocator(
343+
swapBucket.Get(keyLocatorKey),
344+
)
345+
if err != nil {
346+
return err
347+
}
348+
}
349+
330350
loop := LoopOut{
331351
Loop: Loop{
332352
Events: updates,
@@ -464,6 +484,16 @@ func (s *boltSwapStore) FetchLoopInSwaps() ([]*LoopIn, error) {
464484
return err
465485
}
466486

487+
// Try to unmarshal the key locator.
488+
if contract.ProtocolVersion >= ProtocolVersionHtlcV3 {
489+
contract.ClientKeyLocator, err = UnmarshalKeyLocator(
490+
swapBucket.Get(keyLocatorKey),
491+
)
492+
if err != nil {
493+
return err
494+
}
495+
}
496+
467497
loop := LoopIn{
468498
Loop: Loop{
469499
Events: updates,
@@ -583,6 +613,21 @@ func (s *boltSwapStore) CreateLoopOut(hash lntypes.Hash,
583613
return err
584614
}
585615

616+
// Store the key locator for swaps with taproot htlc.
617+
if swap.ProtocolVersion >= ProtocolVersionHtlcV3 {
618+
keyLocator, err := MarshalKeyLocator(
619+
swap.ClientKeyLocator,
620+
)
621+
if err != nil {
622+
return err
623+
}
624+
625+
err = swapBucket.Put(keyLocatorKey, keyLocator)
626+
if err != nil {
627+
return err
628+
}
629+
}
630+
586631
// Finally, we'll create an empty updates bucket for this swap
587632
// to track any future updates to the swap itself.
588633
_, err = swapBucket.CreateBucket(updatesBucketKey)
@@ -634,6 +679,21 @@ func (s *boltSwapStore) CreateLoopIn(hash lntypes.Hash,
634679
return err
635680
}
636681

682+
// Store the key locator for swaps with taproot htlc.
683+
if swap.ProtocolVersion >= ProtocolVersionHtlcV3 {
684+
keyLocator, err := MarshalKeyLocator(
685+
swap.ClientKeyLocator,
686+
)
687+
if err != nil {
688+
return err
689+
}
690+
691+
err = swapBucket.Put(keyLocatorKey, keyLocator)
692+
if err != nil {
693+
return err
694+
}
695+
}
696+
637697
// Finally, we'll create an empty updates bucket for this swap
638698
// to track any future updates to the swap itself.
639699
_, err = swapBucket.CreateBucket(updatesBucketKey)

loopin.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
240240
InitiationTime: initiationTime,
241241
ReceiverKey: swapResp.receiverKey,
242242
SenderKey: senderKey,
243+
ClientKeyLocator: keyDesc.KeyLocator,
243244
Preimage: swapPreimage,
244245
AmountRequested: request.Amount,
245246
CltvExpiry: swapResp.expiry,

loopout.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig,
171171
InitiationTime: initiationTime,
172172
ReceiverKey: receiverKey,
173173
SenderKey: swapResp.senderKey,
174+
ClientKeyLocator: keyDesc.KeyLocator,
174175
Preimage: swapPreimage,
175176
AmountRequested: request.Amount,
176177
CltvExpiry: request.Expiry,

0 commit comments

Comments
 (0)