lnd version, "hacked" to enable seedless restore from xprv + scb
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

469 lines
12 KiB

package migration21
import (
"bytes"
"fmt"
"math/big"
"reflect"
"testing"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/davecgh/go-spew/spew"
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
"github.com/lightningnetwork/lnd/channeldb/migration21/common"
"github.com/lightningnetwork/lnd/channeldb/migration21/current"
"github.com/lightningnetwork/lnd/channeldb/migration21/legacy"
"github.com/lightningnetwork/lnd/channeldb/migtest"
"github.com/lightningnetwork/lnd/kvdb"
)
var (
key = [chainhash.HashSize]byte{
0x81, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
0x68, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
0xd, 0xe7, 0x93, 0xe4, 0xb7, 0x25, 0xb8, 0x4d,
0x1e, 0xb, 0x4c, 0xf9, 0x9e, 0xc5, 0x8c, 0xe9,
}
_, pubKey = btcec.PrivKeyFromBytes(btcec.S256(), key[:])
wireSig, _ = lnwire.NewSigFromSignature(testSig)
testSig = &btcec.Signature{
R: new(big.Int),
S: new(big.Int),
}
_, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10)
_, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10)
testTx = &wire.MsgTx{
Version: 1,
TxIn: []*wire.TxIn{
{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{},
Index: 0xffffffff,
},
SignatureScript: []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62},
Sequence: 0xffffffff,
},
},
TxOut: []*wire.TxOut{
{
Value: 5000000000,
PkScript: []byte{
0x41, // OP_DATA_65
0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5,
0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42,
0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1,
0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24,
0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97,
0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20,
0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63,
0xa6, // 65-byte signature
0xac, // OP_CHECKSIG
},
},
},
LockTime: 5,
}
testCommitDiff = &common.CommitDiff{
Commitment: common.ChannelCommitment{
CommitTx: testTx,
CommitSig: make([]byte, 0),
},
CommitSig: &lnwire.CommitSig{
ChanID: lnwire.ChannelID(key),
CommitSig: wireSig,
HtlcSigs: []lnwire.Sig{
wireSig,
wireSig,
},
},
LogUpdates: []common.LogUpdate{
{
LogIndex: 1,
UpdateMsg: &lnwire.UpdateAddHTLC{
ID: 1,
Amount: lnwire.NewMSatFromSatoshis(100),
Expiry: 25,
},
},
{
LogIndex: 2,
UpdateMsg: &lnwire.UpdateAddHTLC{
ID: 2,
Amount: lnwire.NewMSatFromSatoshis(200),
Expiry: 50,
},
},
},
OpenedCircuitKeys: []common.CircuitKey{},
ClosedCircuitKeys: []common.CircuitKey{},
}
testNetworkResult = &common.NetworkResult{
Msg: testCommitDiff.CommitSig,
Unencrypted: true,
IsResolution: true,
}
testChanCloseSummary = &common.ChannelCloseSummary{
RemotePub: pubKey,
Capacity: 9,
RemoteCurrentRevocation: pubKey,
RemoteNextRevocation: pubKey,
LastChanSyncMsg: &lnwire.ChannelReestablish{
LocalUnrevokedCommitPoint: pubKey,
},
}
netResultKey = []byte{3}
chanID = lnwire.NewChanIDFromOutPoint(&wire.OutPoint{})
adds = []common.LogUpdate{
{
LogIndex: 0,
UpdateMsg: &lnwire.UpdateAddHTLC{
ChanID: chanID,
ID: 1,
Amount: 100,
Expiry: 1000,
PaymentHash: [32]byte{0},
},
},
{
LogIndex: 1,
UpdateMsg: &lnwire.UpdateAddHTLC{
ChanID: chanID,
ID: 1,
Amount: 101,
Expiry: 1001,
PaymentHash: [32]byte{1},
},
},
}
settleFails = []common.LogUpdate{
{
LogIndex: 2,
UpdateMsg: &lnwire.UpdateFulfillHTLC{
ChanID: chanID,
ID: 0,
PaymentPreimage: [32]byte{0},
},
},
{
LogIndex: 3,
UpdateMsg: &lnwire.UpdateFailHTLC{
ChanID: chanID,
ID: 1,
Reason: []byte{},
},
},
}
)
// TestMigrateDatabaseWireMessages tests that we're able to properly migrate
// all the wire messages in the database which are written without a length
// prefix in front of them. At the time this test was written we need to
// migrate three areas: open channel commit diffs, open channel unacked updates,
// and network results in the switch.
func TestMigrateDatabaseWireMessages(t *testing.T) {
var pub [33]byte
copy(pub[:], key[:])
migtest.ApplyMigration(
t,
func(tx kvdb.RwTx) error {
t.Helper()
// First, we'll insert a new fake channel (well just
// the commitment diff) at the expected location
// on-disk.
openChanBucket, err := tx.CreateTopLevelBucket(
openChannelBucket,
)
if err != nil {
return err
}
nodeBucket, err := openChanBucket.CreateBucket(pub[:])
if err != nil {
return err
}
chainBucket, err := nodeBucket.CreateBucket(key[:])
if err != nil {
return err
}
chanBucket, err := chainBucket.CreateBucket(key[:])
if err != nil {
return err
}
var b bytes.Buffer
err = legacy.SerializeCommitDiff(&b, testCommitDiff)
if err != nil {
return err
}
err = chanBucket.Put(commitDiffKey, b.Bytes())
if err != nil {
return err
}
var logUpdateBuf bytes.Buffer
err = legacy.SerializeLogUpdates(
&logUpdateBuf, testCommitDiff.LogUpdates,
)
if err != nil {
return err
}
// We'll re-use the same log updates to insert as a set
// of un-acked and unsigned pending log updateas as well.
err = chanBucket.Put(
unsignedAckedUpdatesKey, logUpdateBuf.Bytes(),
)
if err != nil {
return err
}
err = chanBucket.Put(
remoteUnsignedLocalUpdatesKey, logUpdateBuf.Bytes(),
)
if err != nil {
return err
}
// Next, we'll insert a sample closed channel summary
// for the 2nd part of our migration.
closedChanBucket, err := tx.CreateTopLevelBucket(
closedChannelBucket,
)
if err != nil {
return err
}
var summaryBuf bytes.Buffer
err = legacy.SerializeChannelCloseSummary(
&summaryBuf, testChanCloseSummary,
)
if err != nil {
return err
}
err = closedChanBucket.Put(key[:], summaryBuf.Bytes())
if err != nil {
return err
}
// Create a few forwarding packages to migrate.
for i := uint64(100); i < 200; i++ {
shortChanID := lnwire.NewShortChanIDFromInt(i)
packager := legacy.NewChannelPackager(shortChanID)
fwdPkg := common.NewFwdPkg(shortChanID, 0, adds, settleFails)
if err := packager.AddFwdPkg(tx, fwdPkg); err != nil {
return err
}
}
// Finally, we need to insert a sample network result
// as well for the final component of our migration.
var netResBuf bytes.Buffer
err = legacy.SerializeNetworkResult(
&netResBuf, testNetworkResult,
)
if err != nil {
return err
}
networkResults, err := tx.CreateTopLevelBucket(
networkResultStoreBucketKey,
)
if err != nil {
return err
}
return networkResults.Put(
netResultKey, netResBuf.Bytes(),
)
},
func(tx kvdb.RwTx) error {
t.Helper()
// We'll now read the commit diff from disk using the
// _new_ decoding method. This should match the commit
// diff we inserted in the pre-migration step.
openChanBucket := tx.ReadWriteBucket(openChannelBucket)
nodeBucket := openChanBucket.NestedReadWriteBucket(
pub[:],
)
chainBucket := nodeBucket.NestedReadWriteBucket(key[:])
chanBucket := chainBucket.NestedReadWriteBucket(key[:])
commitDiffBytes := chanBucket.Get(commitDiffKey)
if commitDiffBytes == nil {
return fmt.Errorf("no commit diff found")
}
newCommitDiff, err := current.DeserializeCommitDiff(
bytes.NewReader(commitDiffBytes),
)
if err != nil {
return fmt.Errorf("unable to decode commit "+
"diff: %v", err)
}
if !reflect.DeepEqual(newCommitDiff, testCommitDiff) {
return fmt.Errorf("diff mismatch: expected "+
"%v, got %v", spew.Sdump(testCommitDiff),
spew.Sdump(newCommitDiff))
}
// Next, we'll ensure that the un-acked updates match
// up as well.
updateBytes := chanBucket.Get(unsignedAckedUpdatesKey)
if updateBytes == nil {
return fmt.Errorf("no update bytes found")
}
newUpdates, err := current.DeserializeLogUpdates(
bytes.NewReader(updateBytes),
)
if err != nil {
return err
}
if !reflect.DeepEqual(
newUpdates, testCommitDiff.LogUpdates,
) {
return fmt.Errorf("updates mismatch: expected "+
"%v, got %v",
spew.Sdump(testCommitDiff.LogUpdates),
spew.Sdump(newUpdates))
}
updateBytes = chanBucket.Get(remoteUnsignedLocalUpdatesKey)
if updateBytes == nil {
return fmt.Errorf("no update bytes found")
}
newUpdates, err = current.DeserializeLogUpdates(
bytes.NewReader(updateBytes),
)
if err != nil {
return err
}
if !reflect.DeepEqual(
newUpdates, testCommitDiff.LogUpdates,
) {
return fmt.Errorf("updates mismatch: expected "+
"%v, got %v",
spew.Sdump(testCommitDiff.LogUpdates),
spew.Sdump(newUpdates))
}
// Next, we'll ensure that the inserted close channel
// summary bytes also mach up with what we inserted in
// the prior step.
closedChanBucket := tx.ReadWriteBucket(
closedChannelBucket,
)
if closedChannelBucket == nil {
return fmt.Errorf("no closed channels found")
}
chanSummaryBytes := closedChanBucket.Get(key[:])
newChanCloseSummary, err := current.DeserializeCloseChannelSummary(
bytes.NewReader(chanSummaryBytes),
)
if err != nil {
return err
}
testChanCloseSummary.RemotePub.Curve = nil
testChanCloseSummary.RemoteCurrentRevocation.Curve = nil
testChanCloseSummary.RemoteNextRevocation.Curve = nil
testChanCloseSummary.LastChanSyncMsg.LocalUnrevokedCommitPoint.Curve = nil
newChanCloseSummary.RemotePub.Curve = nil
newChanCloseSummary.RemoteCurrentRevocation.Curve = nil
newChanCloseSummary.RemoteNextRevocation.Curve = nil
newChanCloseSummary.LastChanSyncMsg.LocalUnrevokedCommitPoint.Curve = nil
if !reflect.DeepEqual(
newChanCloseSummary, testChanCloseSummary,
) {
return fmt.Errorf("summary mismatch: expected "+
"%v, got %v",
spew.Sdump(testChanCloseSummary),
spew.Sdump(newChanCloseSummary))
}
// Fetch all forwarding packages.
for i := uint64(100); i < 200; i++ {
shortChanID := lnwire.NewShortChanIDFromInt(i)
packager := current.NewChannelPackager(shortChanID)
fwdPkgs, err := packager.LoadFwdPkgs(tx)
if err != nil {
return err
}
if len(fwdPkgs) != 1 {
return fmt.Errorf("expected 1 pkg")
}
og := common.NewFwdPkg(shortChanID, 0, adds, settleFails)
// Check that we deserialized the packages correctly.
if !reflect.DeepEqual(fwdPkgs[0], og) {
return fmt.Errorf("res mismatch: expected "+
"%v, got %v",
spew.Sdump(fwdPkgs[0]),
spew.Sdump(og))
}
}
// Finally, we'll check the network results to ensure
// that was migrated properly as well.
networkResults := tx.ReadBucket(
networkResultStoreBucketKey,
)
if networkResults == nil {
return fmt.Errorf("no net results found")
}
netResBytes := networkResults.Get(netResultKey)
if netResBytes == nil {
return fmt.Errorf("no network res found")
}
newNetRes, err := current.DeserializeNetworkResult(
bytes.NewReader(netResBytes),
)
if err != nil {
return err
}
if !reflect.DeepEqual(newNetRes, testNetworkResult) {
return fmt.Errorf("res mismatch: expected "+
"%v, got %v",
spew.Sdump(testNetworkResult),
spew.Sdump(newNetRes))
}
return nil
},
MigrateDatabaseWireMessages,
false,
)
}