From 1d7a1ac0eeceaf16b00f7a7362ad88c4d723bf27 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Tue, 16 Jan 2018 18:38:49 -0800 Subject: [PATCH] lnwallet: update channel state machine tests to use distinct keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- lnwallet/channel_test.go | 97 +++++++++++++++++++++++------------ lnwallet/common_test.go | 39 ++++++++++++-- lnwallet/script_utils_test.go | 8 +-- 3 files changed, 105 insertions(+), 39 deletions(-) diff --git a/lnwallet/channel_test.go b/lnwallet/channel_test.go index 4fe5bcd0..d668c2c2 100644 --- a/lnwallet/channel_test.go +++ b/lnwallet/channel_test.go @@ -141,7 +141,7 @@ func forceStateTransition(chanA, chanB *LightningChannel) error { return err } - bobRevocation, err := chanB.RevokeCurrentCommitment() + bobRevocation, _, err := chanB.RevokeCurrentCommitment() if err != nil { return err } @@ -157,7 +157,7 @@ func forceStateTransition(chanA, chanB *LightningChannel) error { return err } - aliceRevocation, err := chanA.RevokeCurrentCommitment() + aliceRevocation, _, err := chanA.RevokeCurrentCommitment() if err != nil { return err } @@ -198,11 +198,6 @@ func createTestChannelsWithNotifier(revocationWindow int, notifier chainntnfs.ChainNotifier) (*LightningChannel, *LightningChannel, func(), error) { - aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(btcec.S256(), - testWalletPrivKey) - bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(btcec.S256(), - bobsPrivKey) - channelCapacity := btcutil.Amount(10 * 1e8) channelBal := channelCapacity / 2 aliceDustLimit := btcutil.Amount(200) @@ -216,7 +211,28 @@ func createTestChannelsWithNotifier(revocationWindow int, } 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{ ChannelConstraints: channeldb.ChannelConstraints{ DustLimit: aliceDustLimit, @@ -226,11 +242,11 @@ func createTestChannelsWithNotifier(revocationWindow int, MaxAcceptedHtlcs: uint16(rand.Int31()), }, CsvDelay: uint16(csvTimeoutAlice), - MultiSigKey: aliceKeyPub, - RevocationBasePoint: aliceKeyPub, - PaymentBasePoint: aliceKeyPub, - DelayBasePoint: aliceKeyPub, - HtlcBasePoint: aliceKeyPub, + MultiSigKey: aliceKeys[0].PubKey(), + RevocationBasePoint: aliceKeys[1].PubKey(), + PaymentBasePoint: aliceKeys[2].PubKey(), + DelayBasePoint: aliceKeys[3].PubKey(), + HtlcBasePoint: aliceKeys[4].PubKey(), } bobCfg := channeldb.ChannelConfig{ ChannelConstraints: channeldb.ChannelConstraints{ @@ -241,14 +257,16 @@ func createTestChannelsWithNotifier(revocationWindow int, MaxAcceptedHtlcs: uint16(rand.Int31()), }, CsvDelay: uint16(csvTimeoutBob), - MultiSigKey: bobKeyPub, - RevocationBasePoint: bobKeyPub, - PaymentBasePoint: bobKeyPub, - DelayBasePoint: bobKeyPub, - HtlcBasePoint: bobKeyPub, + MultiSigKey: bobKeys[0].PubKey(), + RevocationBasePoint: bobKeys[1].PubKey(), + PaymentBasePoint: bobKeys[2].PubKey(), + DelayBasePoint: bobKeys[3].PubKey(), + HtlcBasePoint: bobKeys[4].PubKey(), } - bobRoot := DeriveRevocationRoot(bobKeyPriv, testHdSeed, aliceKeyPub) + bobRoot := DeriveRevocationRoot( + bobKeys[0], testHdSeed, aliceKeys[0].PubKey(), + ) bobPreimageProducer := shachain.NewRevocationProducer(bobRoot) bobFirstRevoke, err := bobPreimageProducer.AtIndex(0) if err != nil { @@ -256,7 +274,9 @@ func createTestChannelsWithNotifier(revocationWindow int, } bobCommitPoint := ComputeCommitmentPoint(bobFirstRevoke[:]) - aliceRoot := DeriveRevocationRoot(aliceKeyPriv, testHdSeed, bobKeyPub) + aliceRoot := DeriveRevocationRoot( + aliceKeys[0], testHdSeed, bobKeys[0].PubKey(), + ) alicePreimageProducer := shachain.NewRevocationProducer(aliceRoot) aliceFirstRevoke, err := alicePreimageProducer.AtIndex(0) if err != nil { @@ -313,7 +333,7 @@ func createTestChannelsWithNotifier(revocationWindow int, aliceChannelState := &channeldb.OpenChannel{ LocalChanCfg: aliceCfg, RemoteChanCfg: bobCfg, - IdentityPub: aliceKeyPub, + IdentityPub: aliceKeys[0].PubKey(), FundingOutpoint: *prevOut, ChanType: channeldb.SingleFunder, IsInitiator: true, @@ -328,7 +348,7 @@ func createTestChannelsWithNotifier(revocationWindow int, bobChannelState := &channeldb.OpenChannel{ LocalChanCfg: bobCfg, RemoteChanCfg: aliceCfg, - IdentityPub: bobKeyPub, + IdentityPub: bobKeys[0].PubKey(), FundingOutpoint: *prevOut, ChanType: channeldb.SingleFunder, IsInitiator: false, @@ -341,16 +361,29 @@ func createTestChannelsWithNotifier(revocationWindow int, Db: dbBob, } - aliceSigner := &mockSigner{privkeys: []*btcec.PrivateKey{aliceKeyPriv}} - bobSigner := &mockSigner{privkeys: []*btcec.PrivateKey{bobKeyPriv}} + aliceSigner := &mockSigner{privkeys: aliceKeys} + bobSigner := &mockSigner{privkeys: bobKeys} - channelAlice, err := NewLightningChannel(aliceSigner, notifier, - estimator, aliceChannelState) + aliceNotifier := &mockNotfier{ + 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 { return nil, nil, nil, err } - channelBob, err := NewLightningChannel(bobSigner, notifier, - estimator, bobChannelState) + channelBob, err := NewLightningChannel(bobSigner, bobNotifier, + pCache, bobChannelState) if err != nil { 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 // has a valid signature for a newer commitment. - bobRevocation, err := bobChannel.RevokeCurrentCommitment() + bobRevocation, _, err := bobChannel.RevokeCurrentCommitment() if err != nil { 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. - aliceRevocation, err := aliceChannel.RevokeCurrentCommitment() + aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment() if err != nil { 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) } - aliceRevocation2, err := aliceChannel.RevokeCurrentCommitment() + aliceRevocation2, _, err := aliceChannel.RevokeCurrentCommitment() if err != nil { 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) } - bobRevocation2, err := bobChannel.RevokeCurrentCommitment() + bobRevocation2, _, err := bobChannel.RevokeCurrentCommitment() if err != nil { t.Fatalf("bob unable to revoke commitment: %v", err) } diff --git a/lnwallet/common_test.go b/lnwallet/common_test.go index ef1f179e..5693a718 100644 --- a/lnwallet/common_test.go +++ b/lnwallet/common_test.go @@ -2,7 +2,9 @@ package lnwallet import ( "bytes" + "crypto/sha256" "fmt" + "sync" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/roasbeef/btcd/btcec" @@ -124,9 +126,11 @@ func (m *mockSigner) findKey(needleHash160 []byte, singleTweak []byte, } 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 } func (m *mockNotfier) RegisterBlockEpochNtfn() (*chainntnfs.BlockEpochEvent, error) { @@ -140,9 +144,38 @@ func (m *mockNotfier) Start() error { func (m *mockNotfier) Stop() error { 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{ - Spend: make(chan *chainntnfs.SpendDetail), + Spend: spendChan, Cancel: func() {}, }, 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 +} diff --git a/lnwallet/script_utils_test.go b/lnwallet/script_utils_test.go index 748ab127..fd5a4769 100644 --- a/lnwallet/script_utils_test.go +++ b/lnwallet/script_utils_test.go @@ -443,7 +443,7 @@ func TestHTLCSenderSpendValidation(t *testing.T) { InputIndex: 0, } - return senderHtlcSpendRedeem(bobSigner, signDesc, + return SenderHtlcSpendRedeem(bobSigner, signDesc, sweepTx, // Invalid preimage length bytes.Repeat([]byte{1}, 45)) @@ -464,7 +464,7 @@ func TestHTLCSenderSpendValidation(t *testing.T) { InputIndex: 0, } - return senderHtlcSpendRedeem(bobSigner, signDesc, + return SenderHtlcSpendRedeem(bobSigner, signDesc, sweepTx, paymentPreimage) }), true, @@ -728,7 +728,7 @@ func TestHTLCReceiverSpendValidation(t *testing.T) { } return receiverHtlcSpendTimeout(aliceSigner, signDesc, - sweepTx, cltvTimeout-2) + sweepTx, int32(cltvTimeout-2)) }), false, }, @@ -746,7 +746,7 @@ func TestHTLCReceiverSpendValidation(t *testing.T) { } return receiverHtlcSpendTimeout(aliceSigner, signDesc, - sweepTx, cltvTimeout) + sweepTx, int32(cltvTimeout)) }), true, },