lnwallet: refactor all wallet/channel interaction to use the WalletController.

This commit performs a major refactor of the current wallet,
reservation, and channel code in order to call into a WalletController
implementation rather than directly into btcwallet.

The current set of wallets tests have been modified in order to test
against *all* registered WalletController implementations rather than
only btcwallet. As a result, all future WalletControllers primary need
to ensure that their implementation passes the current set of tests
(which will be expanded into the future), providing an easy path of
integration assurance.

Rather than directly holding the private keys throughout funding and
channel creation, the burden of securing keys has been shifted to the
specified WalletController and Signer interfaces. All signing is done
via the Signer interface rather than directly, increasing flexibility
dramatically.

During channel funding, rather than creating a txscript.Engine to
verify commitment signatures, regular ECDSA sig verification is now
used instead. This is faster and more efficient.

Finally certain fields/methods within ChannelReservation and
LightningChannel have been exposed publicly in order to restrict the
amount of modifications the prior tests needed to undergo in order to
support testing directly agains the WalletController interface.
This commit is contained in:
Olaoluwa Osuntokun committed 2016-09-08 12:25:54 -07:00
1 parent 99fdb3a3a9
commit 671098325d
5 files changed
+538 -575

No files matched your search

+71 -30
View File
@@ -13,27 +13,64 @@ import (
"github.com/lightningnetwork/lnd/lnwire"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/chaincfg"
"github.com/roasbeef/btcd/txscript"
"github.com/roasbeef/btcd/wire"
"github.com/roasbeef/btcutil"
)
// MockEncryptorDecryptor is a mock implementation of EncryptorDecryptor that
// simply returns the passed bytes without encrypting or decrypting. This is
// used for testing purposes to be able to create a channldb instance which
// doesn't use encryption.
type MockEncryptorDecryptor struct {
var (
privPass = []byte("private-test")
// For simplicity a single priv key controls all of our test outputs.
testWalletPrivKey = []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,
}
// We're alice :)
bobsPrivKey = []byte{
0x81, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
0x63, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
0xd, 0xe7, 0x95, 0xe4, 0xb7, 0x25, 0xb8, 0x4d,
0x1e, 0xb, 0x4c, 0xfd, 0x9e, 0xc5, 0x8c, 0xe9,
}
// Use a hard-coded HD seed.
testHdSeed = [32]byte{
0xb7, 0x94, 0x38, 0x5f, 0x2d, 0x1e, 0xf7, 0xab,
0x4d, 0x92, 0x73, 0xd1, 0x90, 0x63, 0x81, 0xb4,
0x4f, 0x2f, 0x6f, 0x25, 0x88, 0xa3, 0xef, 0xb9,
0x6a, 0x49, 0x18, 0x83, 0x31, 0x98, 0x47, 0x53,
}
// The number of confirmations required to consider any created channel
// open.
numReqConfs = uint16(1)
)
type mockSigner struct {
key *btcec.PrivateKey
}
func (m *MockEncryptorDecryptor) Encrypt(n []byte) ([]byte, error) {
return n, nil
func (m *mockSigner) SignOutputRaw(tx *wire.MsgTx, signDesc *SignDescriptor) ([]byte, error) {
amt := signDesc.Output.Value
redeemScript := signDesc.RedeemScript
privKey := m.key
sig, err := txscript.RawTxInWitnessSignature(tx, signDesc.SigHashes,
signDesc.InputIndex, amt, redeemScript, txscript.SigHashAll, privKey)
if err != nil {
return nil, err
}
return sig[:len(sig)-1], nil
}
func (m *MockEncryptorDecryptor) Decrypt(n []byte) ([]byte, error) {
return n, nil
}
func (m *MockEncryptorDecryptor) OverheadSize() uint32 {
return 0
// ComputeInputScript...
func (m *mockSigner) ComputeInputScript(tx *wire.MsgTx, signDesc *SignDescriptor) (*InputScript, error) {
return nil, nil
}
// createTestChannels creates two test channels funded with 10 BTC, with 5 BTC
@@ -49,7 +86,7 @@ func createTestChannels() (*LightningChannel, *LightningChannel, func(), error)
csvTimeoutAlice := uint32(5)
csvTimeoutBob := uint32(4)
redeemScript, _, err := genFundingPkScript(aliceKeyPub.SerializeCompressed(),
redeemScript, _, err := GenFundingPkScript(aliceKeyPub.SerializeCompressed(),
bobKeyPub.SerializeCompressed(), int64(channelCapacity))
if err != nil {
return nil, nil, nil, err
@@ -61,26 +98,26 @@ func createTestChannels() (*LightningChannel, *LightningChannel, func(), error)
}
fundingTxIn := wire.NewTxIn(prevOut, nil, nil)
bobElkrem := elkrem.NewElkremSender(deriveElkremRoot(bobKeyPriv, aliceKeyPub))
bobElkrem := elkrem.NewElkremSender(deriveElkremRoot(bobKeyPriv, bobKeyPub, aliceKeyPub))
bobFirstRevoke, err := bobElkrem.AtIndex(0)
if err != nil {
return nil, nil, nil, err
}
bobRevokeKey := deriveRevocationPubkey(aliceKeyPub, bobFirstRevoke[:])
bobRevokeKey := DeriveRevocationPubkey(aliceKeyPub, bobFirstRevoke[:])
aliceElkrem := elkrem.NewElkremSender(deriveElkremRoot(aliceKeyPriv, bobKeyPub))
aliceElkrem := elkrem.NewElkremSender(deriveElkremRoot(aliceKeyPriv, aliceKeyPub, bobKeyPub))
aliceFirstRevoke, err := aliceElkrem.AtIndex(0)
if err != nil {
return nil, nil, nil, err
}
aliceRevokeKey := deriveRevocationPubkey(bobKeyPub, aliceFirstRevoke[:])
aliceRevokeKey := DeriveRevocationPubkey(bobKeyPub, aliceFirstRevoke[:])
aliceCommitTx, err := createCommitTx(fundingTxIn, aliceKeyPub,
aliceCommitTx, err := CreateCommitTx(fundingTxIn, aliceKeyPub,
bobKeyPub, aliceRevokeKey, csvTimeoutAlice, channelBal, channelBal)
if err != nil {
return nil, nil, nil, err
}
bobCommitTx, err := createCommitTx(fundingTxIn, bobKeyPub,
bobCommitTx, err := CreateCommitTx(fundingTxIn, bobKeyPub,
aliceKeyPub, bobRevokeKey, csvTimeoutBob, channelBal, channelBal)
if err != nil {
return nil, nil, nil, err
@@ -91,25 +128,24 @@ func createTestChannels() (*LightningChannel, *LightningChannel, func(), error)
if err != nil {
return nil, nil, nil, err
}
dbAlice.RegisterCryptoSystem(&MockEncryptorDecryptor{})
bobPath, err := ioutil.TempDir("", "bobdb")
dbBob, err := channeldb.Open(bobPath, &chaincfg.TestNet3Params)
if err != nil {
return nil, nil, nil, err
}
dbBob.RegisterCryptoSystem(&MockEncryptorDecryptor{})
aliceChannelState := &channeldb.OpenChannel{
TheirLNID: testHdSeed,
ChanID: prevOut,
OurCommitKey: aliceKeyPriv,
OurCommitKey: aliceKeyPub,
TheirCommitKey: bobKeyPub,
Capacity: channelCapacity,
OurBalance: channelBal,
TheirBalance: channelBal,
OurCommitTx: aliceCommitTx,
FundingOutpoint: prevOut,
OurMultiSigKey: aliceKeyPriv,
OurMultiSigKey: aliceKeyPub,
TheirMultiSigKey: bobKeyPub,
FundingRedeemScript: redeemScript,
LocalCsvDelay: csvTimeoutAlice,
@@ -122,14 +158,14 @@ func createTestChannels() (*LightningChannel, *LightningChannel, func(), error)
bobChannelState := &channeldb.OpenChannel{
TheirLNID: testHdSeed,
ChanID: prevOut,
OurCommitKey: bobKeyPriv,
OurCommitKey: bobKeyPub,
TheirCommitKey: aliceKeyPub,
Capacity: channelCapacity,
OurBalance: channelBal,
TheirBalance: channelBal,
OurCommitTx: bobCommitTx,
FundingOutpoint: prevOut,
OurMultiSigKey: bobKeyPriv,
OurMultiSigKey: bobKeyPub,
TheirMultiSigKey: aliceKeyPub,
FundingRedeemScript: redeemScript,
LocalCsvDelay: csvTimeoutBob,
@@ -145,11 +181,14 @@ func createTestChannels() (*LightningChannel, *LightningChannel, func(), error)
os.RemoveAll(alicePath)
}
channelAlice, err := NewLightningChannel(nil, nil, dbAlice, aliceChannelState)
aliceSigner := &mockSigner{aliceKeyPriv}
bobSigner := &mockSigner{bobKeyPriv}
channelAlice, err := NewLightningChannel(aliceSigner, nil, nil, aliceChannelState)
if err != nil {
return nil, nil, nil, err
}
channelBob, err := NewLightningChannel(nil, nil, dbBob, bobChannelState)
channelBob, err := NewLightningChannel(bobSigner, nil, nil, bobChannelState)
if err != nil {
return nil, nil, nil, err
}
@@ -456,7 +495,8 @@ func TestCooperativeChannelClosure(t *testing.T) {
if err != nil {
t.Fatalf("unable to initiate alice cooperative close: %v", err)
}
closeTx, err := bobChannel.CompleteCooperativeClose(sig)
finalSig := append(sig, byte(txscript.SigHashAll))
closeTx, err := bobChannel.CompleteCooperativeClose(finalSig)
if err != nil {
t.Fatalf("unable to complete alice cooperative close: %v", err)
}
@@ -475,7 +515,8 @@ func TestCooperativeChannelClosure(t *testing.T) {
if err != nil {
t.Fatalf("unable to initiate bob cooperative close: %v", err)
}
closeTx, err = aliceChannel.CompleteCooperativeClose(sig)
finalSig = append(sig, byte(txscript.SigHashAll))
closeTx, err = aliceChannel.CompleteCooperativeClose(finalSig)
if err != nil {
t.Fatalf("unable to complete bob cooperative close: %v", err)
}