d89f51d1d0
Similarly as with kvdb.View this commits adds a reset closure to the kvdb.Update call in order to be able to reset external state if the underlying db backend needs to retry the transaction.
185 lines
4.1 KiB
Go
185 lines
4.1 KiB
Go
package migration_01_to_11
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/btcsuite/btcd/btcec"
|
|
bitcoinCfg "github.com/btcsuite/btcd/chaincfg"
|
|
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
|
"github.com/lightningnetwork/lnd/zpay32"
|
|
litecoinCfg "github.com/ltcsuite/ltcd/chaincfg"
|
|
)
|
|
|
|
var (
|
|
testPrivKeyBytes = []byte{
|
|
0x2b, 0xd8, 0x06, 0xc9, 0x7f, 0x0e, 0x00, 0xaf,
|
|
0x1a, 0x1f, 0xc3, 0x32, 0x8f, 0xa7, 0x63, 0xa9,
|
|
0x26, 0x97, 0x23, 0xc8, 0xdb, 0x8f, 0xac, 0x4f,
|
|
0x93, 0xaf, 0x71, 0xdb, 0x18, 0x6d, 0x6e, 0x90,
|
|
}
|
|
|
|
testCltvDelta = int32(50)
|
|
)
|
|
|
|
// beforeMigrationFuncV11 insert the test invoices in the database.
|
|
func beforeMigrationFuncV11(t *testing.T, d *DB, invoices []Invoice) {
|
|
err := kvdb.Update(d, func(tx kvdb.RwTx) error {
|
|
invoicesBucket, err := tx.CreateTopLevelBucket(
|
|
invoiceBucket,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
invoiceNum := uint32(1)
|
|
for _, invoice := range invoices {
|
|
var invoiceKey [4]byte
|
|
byteOrder.PutUint32(invoiceKey[:], invoiceNum)
|
|
invoiceNum++
|
|
|
|
var buf bytes.Buffer
|
|
err := serializeInvoiceLegacy(&buf, &invoice) // nolint:scopelint
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = invoicesBucket.Put(
|
|
invoiceKey[:], buf.Bytes(),
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}, func() {})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// TestMigrateInvoices checks that invoices are migrated correctly.
|
|
func TestMigrateInvoices(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
payReqBtc, err := getPayReq(&bitcoinCfg.MainNetParams)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var ltcNetParams bitcoinCfg.Params
|
|
ltcNetParams.Bech32HRPSegwit = litecoinCfg.MainNetParams.Bech32HRPSegwit
|
|
payReqLtc, err := getPayReq(<cNetParams)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
invoices := []Invoice{
|
|
{
|
|
PaymentRequest: []byte(payReqBtc),
|
|
},
|
|
{
|
|
PaymentRequest: []byte(payReqLtc),
|
|
},
|
|
}
|
|
|
|
// Verify that all invoices were migrated.
|
|
afterMigrationFunc := func(d *DB) {
|
|
dbInvoices, err := d.FetchAllInvoices(false)
|
|
if err != nil {
|
|
t.Fatalf("unable to fetch invoices: %v", err)
|
|
}
|
|
|
|
if len(invoices) != len(dbInvoices) {
|
|
t.Fatalf("expected %d invoices, got %d", len(invoices),
|
|
len(dbInvoices))
|
|
}
|
|
|
|
for _, dbInvoice := range dbInvoices {
|
|
if dbInvoice.FinalCltvDelta != testCltvDelta {
|
|
t.Fatal("incorrect final cltv delta")
|
|
}
|
|
if dbInvoice.Expiry != 3600*time.Second {
|
|
t.Fatal("incorrect expiry")
|
|
}
|
|
if len(dbInvoice.Htlcs) != 0 {
|
|
t.Fatal("expected no htlcs after migration")
|
|
}
|
|
}
|
|
}
|
|
|
|
applyMigration(t,
|
|
func(d *DB) { beforeMigrationFuncV11(t, d, invoices) },
|
|
afterMigrationFunc,
|
|
MigrateInvoices,
|
|
false)
|
|
}
|
|
|
|
// TestMigrateInvoicesHodl checks that a hodl invoice in the accepted state
|
|
// fails the migration.
|
|
func TestMigrateInvoicesHodl(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
payReqBtc, err := getPayReq(&bitcoinCfg.MainNetParams)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
invoices := []Invoice{
|
|
{
|
|
PaymentRequest: []byte(payReqBtc),
|
|
Terms: ContractTerm{
|
|
State: ContractAccepted,
|
|
},
|
|
},
|
|
}
|
|
|
|
applyMigration(t,
|
|
func(d *DB) { beforeMigrationFuncV11(t, d, invoices) },
|
|
func(d *DB) {},
|
|
MigrateInvoices,
|
|
true)
|
|
}
|
|
|
|
// signDigestCompact generates a test signature to be used in the generation of
|
|
// test payment requests.
|
|
func signDigestCompact(hash []byte) ([]byte, error) {
|
|
// Should the signature reference a compressed public key or not.
|
|
isCompressedKey := true
|
|
|
|
privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), testPrivKeyBytes)
|
|
|
|
// btcec.SignCompact returns a pubkey-recoverable signature
|
|
sig, err := btcec.SignCompact(
|
|
btcec.S256(), privKey, hash, isCompressedKey,
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("can't sign the hash: %v", err)
|
|
}
|
|
|
|
return sig, nil
|
|
}
|
|
|
|
// getPayReq creates a payment request for the given net.
|
|
func getPayReq(net *bitcoinCfg.Params) (string, error) {
|
|
options := []func(*zpay32.Invoice){
|
|
zpay32.CLTVExpiry(uint64(testCltvDelta)),
|
|
zpay32.Description("test"),
|
|
}
|
|
|
|
payReq, err := zpay32.NewInvoice(
|
|
net, [32]byte{}, time.Unix(1, 0), options...,
|
|
)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return payReq.Encode(
|
|
zpay32.MessageSigner{
|
|
SignCompact: signDigestCompact,
|
|
},
|
|
)
|
|
}
|