lnwallet: update channel state machine tests to use distinct keys
In this commit, we update the channel state machine tests to use a new key for each purpose. Before this commit, the same key would be used the entire time. As a result, a few bugs slipped by that would’ve been detected if we used fresh keys for each purpose. Additionally, this reflect the real world case as we always use distinct keys for each purpose to avoid key re-use.
This commit is contained in:
parent
b5496c52a2
commit
1d7a1ac0ee
@ -141,7 +141,7 @@ func forceStateTransition(chanA, chanB *LightningChannel) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
bobRevocation, err := chanB.RevokeCurrentCommitment()
|
bobRevocation, _, err := chanB.RevokeCurrentCommitment()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -157,7 +157,7 @@ func forceStateTransition(chanA, chanB *LightningChannel) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
aliceRevocation, err := chanA.RevokeCurrentCommitment()
|
aliceRevocation, _, err := chanA.RevokeCurrentCommitment()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -198,11 +198,6 @@ func createTestChannelsWithNotifier(revocationWindow int,
|
|||||||
notifier chainntnfs.ChainNotifier) (*LightningChannel,
|
notifier chainntnfs.ChainNotifier) (*LightningChannel,
|
||||||
*LightningChannel, func(), error) {
|
*LightningChannel, func(), error) {
|
||||||
|
|
||||||
aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
|
||||||
testWalletPrivKey)
|
|
||||||
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
|
||||||
bobsPrivKey)
|
|
||||||
|
|
||||||
channelCapacity := btcutil.Amount(10 * 1e8)
|
channelCapacity := btcutil.Amount(10 * 1e8)
|
||||||
channelBal := channelCapacity / 2
|
channelBal := channelCapacity / 2
|
||||||
aliceDustLimit := btcutil.Amount(200)
|
aliceDustLimit := btcutil.Amount(200)
|
||||||
@ -216,7 +211,28 @@ func createTestChannelsWithNotifier(revocationWindow int,
|
|||||||
}
|
}
|
||||||
fundingTxIn := wire.NewTxIn(prevOut, nil, nil)
|
fundingTxIn := wire.NewTxIn(prevOut, nil, nil)
|
||||||
|
|
||||||
// TODO(roasbeef): use distinct keys
|
// For each party, we'll create a distinct set of keys in order to
|
||||||
|
// emulate the typical set up with live channels.
|
||||||
|
var (
|
||||||
|
aliceKeys []*btcec.PrivateKey
|
||||||
|
bobKeys []*btcec.PrivateKey
|
||||||
|
)
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
key := make([]byte, len(testWalletPrivKey))
|
||||||
|
copy(key[:], testWalletPrivKey[:])
|
||||||
|
key[0] ^= byte(i + 1)
|
||||||
|
|
||||||
|
aliceKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), key)
|
||||||
|
aliceKeys = append(aliceKeys, aliceKey)
|
||||||
|
|
||||||
|
key = make([]byte, len(bobsPrivKey))
|
||||||
|
copy(key[:], bobsPrivKey)
|
||||||
|
key[0] ^= byte(i + 1)
|
||||||
|
|
||||||
|
bobKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), key)
|
||||||
|
bobKeys = append(bobKeys, bobKey)
|
||||||
|
}
|
||||||
|
|
||||||
aliceCfg := channeldb.ChannelConfig{
|
aliceCfg := channeldb.ChannelConfig{
|
||||||
ChannelConstraints: channeldb.ChannelConstraints{
|
ChannelConstraints: channeldb.ChannelConstraints{
|
||||||
DustLimit: aliceDustLimit,
|
DustLimit: aliceDustLimit,
|
||||||
@ -226,11 +242,11 @@ func createTestChannelsWithNotifier(revocationWindow int,
|
|||||||
MaxAcceptedHtlcs: uint16(rand.Int31()),
|
MaxAcceptedHtlcs: uint16(rand.Int31()),
|
||||||
},
|
},
|
||||||
CsvDelay: uint16(csvTimeoutAlice),
|
CsvDelay: uint16(csvTimeoutAlice),
|
||||||
MultiSigKey: aliceKeyPub,
|
MultiSigKey: aliceKeys[0].PubKey(),
|
||||||
RevocationBasePoint: aliceKeyPub,
|
RevocationBasePoint: aliceKeys[1].PubKey(),
|
||||||
PaymentBasePoint: aliceKeyPub,
|
PaymentBasePoint: aliceKeys[2].PubKey(),
|
||||||
DelayBasePoint: aliceKeyPub,
|
DelayBasePoint: aliceKeys[3].PubKey(),
|
||||||
HtlcBasePoint: aliceKeyPub,
|
HtlcBasePoint: aliceKeys[4].PubKey(),
|
||||||
}
|
}
|
||||||
bobCfg := channeldb.ChannelConfig{
|
bobCfg := channeldb.ChannelConfig{
|
||||||
ChannelConstraints: channeldb.ChannelConstraints{
|
ChannelConstraints: channeldb.ChannelConstraints{
|
||||||
@ -241,14 +257,16 @@ func createTestChannelsWithNotifier(revocationWindow int,
|
|||||||
MaxAcceptedHtlcs: uint16(rand.Int31()),
|
MaxAcceptedHtlcs: uint16(rand.Int31()),
|
||||||
},
|
},
|
||||||
CsvDelay: uint16(csvTimeoutBob),
|
CsvDelay: uint16(csvTimeoutBob),
|
||||||
MultiSigKey: bobKeyPub,
|
MultiSigKey: bobKeys[0].PubKey(),
|
||||||
RevocationBasePoint: bobKeyPub,
|
RevocationBasePoint: bobKeys[1].PubKey(),
|
||||||
PaymentBasePoint: bobKeyPub,
|
PaymentBasePoint: bobKeys[2].PubKey(),
|
||||||
DelayBasePoint: bobKeyPub,
|
DelayBasePoint: bobKeys[3].PubKey(),
|
||||||
HtlcBasePoint: bobKeyPub,
|
HtlcBasePoint: bobKeys[4].PubKey(),
|
||||||
}
|
}
|
||||||
|
|
||||||
bobRoot := DeriveRevocationRoot(bobKeyPriv, testHdSeed, aliceKeyPub)
|
bobRoot := DeriveRevocationRoot(
|
||||||
|
bobKeys[0], testHdSeed, aliceKeys[0].PubKey(),
|
||||||
|
)
|
||||||
bobPreimageProducer := shachain.NewRevocationProducer(bobRoot)
|
bobPreimageProducer := shachain.NewRevocationProducer(bobRoot)
|
||||||
bobFirstRevoke, err := bobPreimageProducer.AtIndex(0)
|
bobFirstRevoke, err := bobPreimageProducer.AtIndex(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -256,7 +274,9 @@ func createTestChannelsWithNotifier(revocationWindow int,
|
|||||||
}
|
}
|
||||||
bobCommitPoint := ComputeCommitmentPoint(bobFirstRevoke[:])
|
bobCommitPoint := ComputeCommitmentPoint(bobFirstRevoke[:])
|
||||||
|
|
||||||
aliceRoot := DeriveRevocationRoot(aliceKeyPriv, testHdSeed, bobKeyPub)
|
aliceRoot := DeriveRevocationRoot(
|
||||||
|
aliceKeys[0], testHdSeed, bobKeys[0].PubKey(),
|
||||||
|
)
|
||||||
alicePreimageProducer := shachain.NewRevocationProducer(aliceRoot)
|
alicePreimageProducer := shachain.NewRevocationProducer(aliceRoot)
|
||||||
aliceFirstRevoke, err := alicePreimageProducer.AtIndex(0)
|
aliceFirstRevoke, err := alicePreimageProducer.AtIndex(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -313,7 +333,7 @@ func createTestChannelsWithNotifier(revocationWindow int,
|
|||||||
aliceChannelState := &channeldb.OpenChannel{
|
aliceChannelState := &channeldb.OpenChannel{
|
||||||
LocalChanCfg: aliceCfg,
|
LocalChanCfg: aliceCfg,
|
||||||
RemoteChanCfg: bobCfg,
|
RemoteChanCfg: bobCfg,
|
||||||
IdentityPub: aliceKeyPub,
|
IdentityPub: aliceKeys[0].PubKey(),
|
||||||
FundingOutpoint: *prevOut,
|
FundingOutpoint: *prevOut,
|
||||||
ChanType: channeldb.SingleFunder,
|
ChanType: channeldb.SingleFunder,
|
||||||
IsInitiator: true,
|
IsInitiator: true,
|
||||||
@ -328,7 +348,7 @@ func createTestChannelsWithNotifier(revocationWindow int,
|
|||||||
bobChannelState := &channeldb.OpenChannel{
|
bobChannelState := &channeldb.OpenChannel{
|
||||||
LocalChanCfg: bobCfg,
|
LocalChanCfg: bobCfg,
|
||||||
RemoteChanCfg: aliceCfg,
|
RemoteChanCfg: aliceCfg,
|
||||||
IdentityPub: bobKeyPub,
|
IdentityPub: bobKeys[0].PubKey(),
|
||||||
FundingOutpoint: *prevOut,
|
FundingOutpoint: *prevOut,
|
||||||
ChanType: channeldb.SingleFunder,
|
ChanType: channeldb.SingleFunder,
|
||||||
IsInitiator: false,
|
IsInitiator: false,
|
||||||
@ -341,16 +361,29 @@ func createTestChannelsWithNotifier(revocationWindow int,
|
|||||||
Db: dbBob,
|
Db: dbBob,
|
||||||
}
|
}
|
||||||
|
|
||||||
aliceSigner := &mockSigner{privkeys: []*btcec.PrivateKey{aliceKeyPriv}}
|
aliceSigner := &mockSigner{privkeys: aliceKeys}
|
||||||
bobSigner := &mockSigner{privkeys: []*btcec.PrivateKey{bobKeyPriv}}
|
bobSigner := &mockSigner{privkeys: bobKeys}
|
||||||
|
|
||||||
channelAlice, err := NewLightningChannel(aliceSigner, notifier,
|
aliceNotifier := &mockNotfier{
|
||||||
estimator, aliceChannelState)
|
activeSpendNtfn: make(chan *chainntnfs.SpendDetail),
|
||||||
|
}
|
||||||
|
bobNotifier := &mockNotfier{
|
||||||
|
activeSpendNtfn: make(chan *chainntnfs.SpendDetail),
|
||||||
|
}
|
||||||
|
|
||||||
|
pCache := &mockPreimageCache{
|
||||||
|
// hash -> preimage
|
||||||
|
preimageMap: make(map[[32]byte][]byte),
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(roasbeef): make mock version of pre-image store
|
||||||
|
channelAlice, err := NewLightningChannel(aliceSigner, aliceNotifier,
|
||||||
|
pCache, aliceChannelState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
channelBob, err := NewLightningChannel(bobSigner, notifier,
|
channelBob, err := NewLightningChannel(bobSigner, bobNotifier,
|
||||||
estimator, bobChannelState)
|
pCache, bobChannelState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
@ -487,7 +520,7 @@ func TestSimpleAddSettleWorkflow(t *testing.T) {
|
|||||||
|
|
||||||
// Bob revokes his prior commitment given to him by Alice, since he now
|
// Bob revokes his prior commitment given to him by Alice, since he now
|
||||||
// has a valid signature for a newer commitment.
|
// has a valid signature for a newer commitment.
|
||||||
bobRevocation, err := bobChannel.RevokeCurrentCommitment()
|
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to generate bob revocation: %v", err)
|
t.Fatalf("unable to generate bob revocation: %v", err)
|
||||||
}
|
}
|
||||||
@ -519,7 +552,7 @@ func TestSimpleAddSettleWorkflow(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Alice then generates a revocation for bob.
|
// Alice then generates a revocation for bob.
|
||||||
aliceRevocation, err := aliceChannel.RevokeCurrentCommitment()
|
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to revoke alice channel: %v", err)
|
t.Fatalf("unable to revoke alice channel: %v", err)
|
||||||
}
|
}
|
||||||
@ -608,7 +641,7 @@ func TestSimpleAddSettleWorkflow(t *testing.T) {
|
|||||||
t.Fatalf("alice unable to process bob's new commitment: %v", err)
|
t.Fatalf("alice unable to process bob's new commitment: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
aliceRevocation2, err := aliceChannel.RevokeCurrentCommitment()
|
aliceRevocation2, _, err := aliceChannel.RevokeCurrentCommitment()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("alice unable to generate revocation: %v", err)
|
t.Fatalf("alice unable to generate revocation: %v", err)
|
||||||
}
|
}
|
||||||
@ -628,7 +661,7 @@ func TestSimpleAddSettleWorkflow(t *testing.T) {
|
|||||||
t.Fatalf("bob unable to process alice's new commitment: %v", err)
|
t.Fatalf("bob unable to process alice's new commitment: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bobRevocation2, err := bobChannel.RevokeCurrentCommitment()
|
bobRevocation2, _, err := bobChannel.RevokeCurrentCommitment()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("bob unable to revoke commitment: %v", err)
|
t.Fatalf("bob unable to revoke commitment: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,9 @@ package lnwallet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/roasbeef/btcd/btcec"
|
"github.com/roasbeef/btcd/btcec"
|
||||||
@ -124,9 +126,11 @@ func (m *mockSigner) findKey(needleHash160 []byte, singleTweak []byte,
|
|||||||
}
|
}
|
||||||
|
|
||||||
type mockNotfier struct {
|
type mockNotfier struct {
|
||||||
|
activeSpendNtfn chan *chainntnfs.SpendDetail
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockNotfier) RegisterConfirmationsNtfn(txid *chainhash.Hash, numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) {
|
func (m *mockNotfier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
|
||||||
|
numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
func (m *mockNotfier) RegisterBlockEpochNtfn() (*chainntnfs.BlockEpochEvent, error) {
|
func (m *mockNotfier) RegisterBlockEpochNtfn() (*chainntnfs.BlockEpochEvent, error) {
|
||||||
@ -140,9 +144,38 @@ func (m *mockNotfier) Start() error {
|
|||||||
func (m *mockNotfier) Stop() error {
|
func (m *mockNotfier) Stop() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (m *mockNotfier) RegisterSpendNtfn(outpoint *wire.OutPoint, heightHint uint32) (*chainntnfs.SpendEvent, error) {
|
func (m *mockNotfier) RegisterSpendNtfn(outpoint *wire.OutPoint,
|
||||||
|
heightHint uint32) (*chainntnfs.SpendEvent, error) {
|
||||||
|
|
||||||
|
spendChan := make(chan *chainntnfs.SpendDetail)
|
||||||
|
m.activeSpendNtfn = spendChan
|
||||||
return &chainntnfs.SpendEvent{
|
return &chainntnfs.SpendEvent{
|
||||||
Spend: make(chan *chainntnfs.SpendDetail),
|
Spend: spendChan,
|
||||||
Cancel: func() {},
|
Cancel: func() {},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockPreimageCache struct {
|
||||||
|
sync.Mutex
|
||||||
|
preimageMap map[[32]byte][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockPreimageCache) LookupPreimage(hash []byte) ([]byte, bool) {
|
||||||
|
m.Lock()
|
||||||
|
defer m.Unlock()
|
||||||
|
|
||||||
|
var h [32]byte
|
||||||
|
copy(h[:], hash)
|
||||||
|
|
||||||
|
p, ok := m.preimageMap[h]
|
||||||
|
return p, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockPreimageCache) AddPreimage(preimage []byte) error {
|
||||||
|
m.Lock()
|
||||||
|
defer m.Unlock()
|
||||||
|
|
||||||
|
m.preimageMap[sha256.Sum256(preimage[:])] = preimage
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -443,7 +443,7 @@ func TestHTLCSenderSpendValidation(t *testing.T) {
|
|||||||
InputIndex: 0,
|
InputIndex: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
return senderHtlcSpendRedeem(bobSigner, signDesc,
|
return SenderHtlcSpendRedeem(bobSigner, signDesc,
|
||||||
sweepTx,
|
sweepTx,
|
||||||
// Invalid preimage length
|
// Invalid preimage length
|
||||||
bytes.Repeat([]byte{1}, 45))
|
bytes.Repeat([]byte{1}, 45))
|
||||||
@ -464,7 +464,7 @@ func TestHTLCSenderSpendValidation(t *testing.T) {
|
|||||||
InputIndex: 0,
|
InputIndex: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
return senderHtlcSpendRedeem(bobSigner, signDesc,
|
return SenderHtlcSpendRedeem(bobSigner, signDesc,
|
||||||
sweepTx, paymentPreimage)
|
sweepTx, paymentPreimage)
|
||||||
}),
|
}),
|
||||||
true,
|
true,
|
||||||
@ -728,7 +728,7 @@ func TestHTLCReceiverSpendValidation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return receiverHtlcSpendTimeout(aliceSigner, signDesc,
|
return receiverHtlcSpendTimeout(aliceSigner, signDesc,
|
||||||
sweepTx, cltvTimeout-2)
|
sweepTx, int32(cltvTimeout-2))
|
||||||
}),
|
}),
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
@ -746,7 +746,7 @@ func TestHTLCReceiverSpendValidation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return receiverHtlcSpendTimeout(aliceSigner, signDesc,
|
return receiverHtlcSpendTimeout(aliceSigner, signDesc,
|
||||||
sweepTx, cltvTimeout)
|
sweepTx, int32(cltvTimeout))
|
||||||
}),
|
}),
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user