Skip to content

Commit 7c99951

Browse files
committed
channeldb: prep waiting proof store for taproot proofs
With a migration to migrate existing entries in the waiting proof store to use a type byte prefix.
1 parent f26bf2c commit 7c99951

File tree

9 files changed

+528
-40
lines changed

9 files changed

+528
-40
lines changed

channeldb/db.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/lightningnetwork/lnd/channeldb/migration29"
2727
"github.com/lightningnetwork/lnd/channeldb/migration30"
2828
"github.com/lightningnetwork/lnd/channeldb/migration31"
29+
"github.com/lightningnetwork/lnd/channeldb/migration32"
2930
"github.com/lightningnetwork/lnd/channeldb/migration_01_to_11"
3031
"github.com/lightningnetwork/lnd/clock"
3132
"github.com/lightningnetwork/lnd/invoices"
@@ -286,6 +287,10 @@ var (
286287
number: 31,
287288
migration: migration31.DeleteLastPublishedTxTLB,
288289
},
290+
{
291+
number: 32,
292+
migration: migration32.MigrateWaitingProofStore,
293+
},
289294
}
290295

291296
// optionalVersions stores all optional migrations that are applied

channeldb/log.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/lightningnetwork/lnd/channeldb/migration24"
1111
"github.com/lightningnetwork/lnd/channeldb/migration30"
1212
"github.com/lightningnetwork/lnd/channeldb/migration31"
13+
"github.com/lightningnetwork/lnd/channeldb/migration32"
1314
"github.com/lightningnetwork/lnd/channeldb/migration_01_to_11"
1415
"github.com/lightningnetwork/lnd/kvdb"
1516
)
@@ -42,5 +43,6 @@ func UseLogger(logger btclog.Logger) {
4243
migration24.UseLogger(logger)
4344
migration30.UseLogger(logger)
4445
migration31.UseLogger(logger)
46+
migration32.UseLogger(logger)
4547
kvdb.UseLogger(logger)
4648
}

channeldb/migration32/log.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package migration32
2+
3+
import (
4+
"github.com/btcsuite/btclog"
5+
)
6+
7+
// log is a logger that is initialized as disabled. This means the package will
8+
// not perform any logging by default until a logger is set.
9+
var log = btclog.Disabled
10+
11+
// UseLogger uses a specified Logger to output package logging info.
12+
func UseLogger(logger btclog.Logger) {
13+
log = logger
14+
}

channeldb/migration32/migration.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package migration32
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
7+
"github.com/lightningnetwork/lnd/kvdb"
8+
)
9+
10+
// waitingProofsBucketKey byte string name of the waiting proofs store.
11+
var waitingProofsBucketKey = []byte("waitingproofs")
12+
13+
// MigrateWaitingProofStore migrates the waiting proof store so that all entries
14+
// are prefixed with a type byte.
15+
func MigrateWaitingProofStore(tx kvdb.RwTx) error {
16+
log.Infof("Migrating waiting proof store")
17+
18+
bucket := tx.ReadWriteBucket(waitingProofsBucketKey)
19+
20+
// If the bucket does not exist yet, then there are no entries to
21+
// migrate.
22+
if bucket == nil {
23+
return nil
24+
}
25+
26+
return bucket.ForEach(func(k, v []byte) error {
27+
// Skip buckets fields.
28+
if v == nil {
29+
return nil
30+
}
31+
32+
// Read in the waiting proof using the legacy decoding method.
33+
var proof WaitingProof
34+
if err := proof.LegacyDecode(bytes.NewReader(v)); err != nil {
35+
return err
36+
}
37+
38+
// Do sanity check to ensure that the proof key is the same as
39+
// the key used to store the proof.
40+
key := proof.Key()
41+
if !bytes.Equal(key[:], k) {
42+
return fmt.Errorf("proof key (%x) does not match "+
43+
"the key used to store the proof: %x", key, k)
44+
}
45+
46+
// Re-encode the proof using the new, type-prefixed encoding.
47+
var b bytes.Buffer
48+
err := proof.UpdatedEncode(&b)
49+
if err != nil {
50+
return err
51+
}
52+
53+
return bucket.Put(k, b.Bytes())
54+
})
55+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package migration32
2+
3+
import (
4+
"bytes"
5+
"encoding/hex"
6+
"testing"
7+
8+
"github.com/btcsuite/btcd/btcec/v2"
9+
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
10+
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
11+
"github.com/lightningnetwork/lnd/channeldb/migtest"
12+
"github.com/lightningnetwork/lnd/kvdb"
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
var (
17+
testRBytes, _ = hex.DecodeString("8ce2bc69281ce27da07e6683571" +
18+
"319d18e949ddfa2965fb6caa1bf0314f882d7")
19+
testSBytes, _ = hex.DecodeString("299105481d63e0f4bc2a" +
20+
"88121167221b6700d72a0ead154c03be696a292d24ae")
21+
testRScalar = new(btcec.ModNScalar)
22+
testSScalar = new(btcec.ModNScalar)
23+
_ = testRScalar.SetByteSlice(testRBytes)
24+
_ = testSScalar.SetByteSlice(testSBytes)
25+
testSig = ecdsa.NewSignature(testRScalar, testSScalar)
26+
27+
sig, _ = lnwire.NewSigFromSignature(testSig)
28+
29+
wp1 = &WaitingProof{
30+
AnnounceSignatures: &lnwire.AnnounceSignatures{
31+
ChannelID: lnwire.ChannelID{1},
32+
ShortChannelID: lnwire.NewShortChanIDFromInt(1),
33+
NodeSignature: sig,
34+
BitcoinSignature: sig,
35+
ExtraOpaqueData: []byte{1, 2, 3, 4},
36+
},
37+
isRemote: false,
38+
}
39+
40+
wp2 = &WaitingProof{
41+
AnnounceSignatures: &lnwire.AnnounceSignatures{
42+
ChannelID: lnwire.ChannelID{2},
43+
ShortChannelID: lnwire.NewShortChanIDFromInt(2),
44+
NodeSignature: sig,
45+
BitcoinSignature: sig,
46+
},
47+
isRemote: true,
48+
}
49+
)
50+
51+
// TestMigrationWaitingProofStore tests that the MigrateWaitingProofStore
52+
// function works as expected.
53+
func TestMigrateWaitingProofStore(t *testing.T) {
54+
var (
55+
key1 = wp1.Key()
56+
key2 = wp2.Key()
57+
wp1BytesBefore bytes.Buffer
58+
wp2BytesBefore bytes.Buffer
59+
wp1BytesAfter bytes.Buffer
60+
wp2BytesAfter bytes.Buffer
61+
)
62+
63+
err := wp1.LegacyEncode(&wp1BytesBefore)
64+
require.NoError(t, err)
65+
66+
err = wp2.LegacyEncode(&wp2BytesBefore)
67+
require.NoError(t, err)
68+
69+
wpStoreBefore := map[string]interface{}{
70+
string(key1[:]): wp1BytesBefore.String(),
71+
string(key2[:]): wp2BytesBefore.String(),
72+
}
73+
74+
err = wp1.UpdatedEncode(&wp1BytesAfter)
75+
require.NoError(t, err)
76+
77+
err = wp2.UpdatedEncode(&wp2BytesAfter)
78+
require.NoError(t, err)
79+
80+
wpStoreAfter := map[string]interface{}{
81+
string(key1[:]): wp1BytesAfter.String(),
82+
string(key2[:]): wp2BytesAfter.String(),
83+
}
84+
85+
before := func(tx kvdb.RwTx) error {
86+
return migtest.RestoreDB(
87+
tx, waitingProofsBucketKey, wpStoreBefore,
88+
)
89+
}
90+
91+
after := func(tx kvdb.RwTx) error {
92+
return migtest.VerifyDB(
93+
tx, waitingProofsBucketKey, wpStoreAfter,
94+
)
95+
}
96+
97+
migtest.ApplyMigration(
98+
t, before, after, MigrateWaitingProofStore, false,
99+
)
100+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package migration32
2+
3+
import (
4+
"bytes"
5+
"encoding/binary"
6+
"fmt"
7+
"io"
8+
9+
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
10+
)
11+
12+
var byteOrder = binary.BigEndian
13+
14+
// WaitingProofType represents the type of the encoded waiting proof.
15+
type WaitingProofType uint8
16+
17+
const (
18+
// WaitingProofTypeLegacy represents a waiting proof for legacy P2WSH
19+
// channels.
20+
WaitingProofTypeLegacy WaitingProofType = 0
21+
)
22+
23+
// WaitingProofKey is the proof key which uniquely identifies the waiting
24+
// proof object. The goal of this key is distinguish the local and remote
25+
// proof for the same channel id.
26+
type WaitingProofKey [9]byte
27+
28+
// WaitingProof is the storable object, which encapsulate the half proof and
29+
// the information about from which side this proof came. This structure is
30+
// needed to make channel proof exchange persistent, so that after client
31+
// restart we may receive remote/local half proof and process it.
32+
type WaitingProof struct {
33+
*lnwire.AnnounceSignatures
34+
isRemote bool
35+
}
36+
37+
// Key returns the key which uniquely identifies waiting proof.
38+
func (p *WaitingProof) Key() WaitingProofKey {
39+
var key [9]byte
40+
binary.BigEndian.PutUint64(key[:8], p.ShortChannelID.ToUint64())
41+
42+
if p.isRemote {
43+
key[8] = 1
44+
}
45+
46+
return key
47+
}
48+
49+
// UpdatedEncode writes the internal representation of waiting proof in byte
50+
// stream using the new format that is prefixed with a type byte.
51+
func (p *WaitingProof) UpdatedEncode(w io.Writer) error {
52+
// Write the type byte.
53+
err := binary.Write(w, byteOrder, WaitingProofTypeLegacy)
54+
if err != nil {
55+
return err
56+
}
57+
58+
if err := binary.Write(w, byteOrder, p.isRemote); err != nil {
59+
return err
60+
}
61+
62+
buf, ok := w.(*bytes.Buffer)
63+
if !ok {
64+
return fmt.Errorf("expect io.Writer to be *bytes.Buffer")
65+
}
66+
67+
return p.AnnounceSignatures.Encode(buf, 0)
68+
}
69+
70+
// LegacyEncode writes the internal representation of waiting proof in byte
71+
// stream using the legacy format.
72+
func (p *WaitingProof) LegacyEncode(w io.Writer) error {
73+
if err := binary.Write(w, byteOrder, p.isRemote); err != nil {
74+
return err
75+
}
76+
77+
buf, ok := w.(*bytes.Buffer)
78+
if !ok {
79+
return fmt.Errorf("expect io.Writer to be *bytes.Buffer")
80+
}
81+
82+
return p.AnnounceSignatures.Encode(buf, 0)
83+
}
84+
85+
// LegacyDecode reads the data from the byte stream and initializes the
86+
// waiting proof object with it.
87+
func (p *WaitingProof) LegacyDecode(r io.Reader) error {
88+
if err := binary.Read(r, byteOrder, &p.isRemote); err != nil {
89+
return err
90+
}
91+
92+
msg := &lnwire.AnnounceSignatures{}
93+
if err := msg.Decode(r, 0); err != nil {
94+
return err
95+
}
96+
97+
p.AnnounceSignatures = msg
98+
99+
return nil
100+
}

0 commit comments

Comments
 (0)