From 082a8a34e3cf1409dc975f8181816a3ccb3c0fe9 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Thu, 24 Mar 2016 00:01:35 -0700 Subject: [PATCH] lnwallet: update tests and workflow to new OpenChannel struct --- lnwallet/wallet.go | 76 ++++++++++++++++++++++++++++++++--------- lnwallet/wallet_test.go | 44 ++++++++++++++---------- 2 files changed, 85 insertions(+), 35 deletions(-) diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index 1a985bc8..fdcdf16f 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -8,10 +8,10 @@ import ( "sync" "sync/atomic" + "github.com/LightningNetwork/lnd/elkrem" "github.com/lightningnetwork/lnd/chainntfs" "github.com/lightningnetwork/lnd/chainntfs/btcdnotify" "github.com/lightningnetwork/lnd/channeldb" - "github.com/lightningnetwork/lnd/shachain" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/txscript" @@ -477,6 +477,7 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg reservation.partialState.TheirLNID = req.nodeID ourContribution := reservation.ourContribution ourContribution.CsvDelay = req.csvDelay + reservation.partialState.LocalCsvDelay = req.csvDelay // We hold the coin select mutex while querying for outputs, and // performing coin selection in order to avoid inadvertent double spends @@ -602,21 +603,30 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg req.resp <- nil return } - reservation.partialState.OurDeliveryAddress = deliveryAddress - ourContribution.DeliveryAddress = deliveryAddress - - // Create a new shaChain for verifiable transaction revocations. This - // will be used to generate revocation hashes for our past/current - // commitment transactions once we start to make payments within the - // channel. - shaChain, err := shachain.NewFromSeed(nil, 0) + deliveryScript, err := txscript.PayToAddrScript(deliveryAddress) if err != nil { req.err <- err req.resp <- nil return } - reservation.partialState.OurShaChain = shaChain - copy(ourContribution.RevocationHash[:], shaChain.CurrentRevocationHash()) + reservation.partialState.OurDeliveryScript = deliveryScript + ourContribution.DeliveryAddress = deliveryAddress + + // Create a new elkrem for verifiable transaction revocations. This + // will be used to generate revocation hashes for our past/current + // commitment transactions once we start to make payments within the + // channel. + // TODO(roabeef): should be HMAC based...REMOVE BEFORE ALPHA + var zero wire.ShaHash + elkremSender := elkrem.NewElkremSender(63, zero) + reservation.partialState.LocalElkrem = &elkremSender + firstPrimage, err := elkremSender.AtIndex(0) + if err != nil { + req.err <- err + req.resp <- nil + return + } + copy(ourContribution.RevocationHash[:], btcutil.Hash160(firstPrimage[:])) // Funding reservation request succesfully handled. The funding inputs // will be marked as unavailable until the reservation is either @@ -793,7 +803,15 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) { // Initialize an empty sha-chain for them, tracking the current pending // revocation hash (we don't yet know the pre-image so we can't add it // to the chain). - pendingReservation.partialState.TheirShaChain = shachain.New() + e := elkrem.NewElkremReceiver(63) + // TODO(roasbeef): this is incorrect!! fix before lnstate integration + var zero wire.ShaHash + if err := e.AddNext(&zero); err != nil { + req.err <- nil + return + } + + pendingReservation.partialState.RemoteElkrem = &e pendingReservation.partialState.TheirCurrentRevocation = theirContribution.RevocationHash // Grab the hash of the current pre-image in our chain, this is needed @@ -834,9 +852,15 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) { txsort.InPlaceSort(ourCommitTx) txsort.InPlaceSort(theirCommitTx) + deliveryScript, err := txscript.PayToAddrScript(theirContribution.DeliveryAddress) + if err != nil { + req.err <- err + return + } + // Record newly available information witin the open channel state. - pendingReservation.partialState.CsvDelay = theirContribution.CsvDelay - pendingReservation.partialState.TheirDeliveryAddress = theirContribution.DeliveryAddress + pendingReservation.partialState.RemoteCsvDelay = theirContribution.CsvDelay + pendingReservation.partialState.TheirDeliveryScript = deliveryScript pendingReservation.partialState.ChanID = fundingNTxid pendingReservation.partialState.TheirCommitKey = theirCommitKey pendingReservation.partialState.TheirCommitTx = theirCommitTx @@ -979,14 +1003,16 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs // Add the complete funding transaction to the DB, in it's open bucket // which will be used for the lifetime of this channel. - err = l.channelDB.PutOpenChannel(pendingReservation.partialState) + if err := pendingReservation.partialState.FullSync(); err != nil { + msg.err <- err + return + } // Create a goroutine to watch the chain so we can open the channel once // the funding tx has enough confirmations. // TODO(roasbeef): add number of confs to the confi go l.openChannelAfterConfirmations(pendingReservation, 3) - - msg.err <- err + msg.err <- nil } // openChannelAfterConfirmations creates, and opens a payment channel after @@ -1033,3 +1059,19 @@ func (l *LightningWallet) getNextRawKey() (*btcec.PrivateKey, error) { return pkAddr.PrivKey() } + +type waddrmgrEncryptorDecryptor struct { + m *waddrmgr.Manager +} + +func (w *waddrmgrEncryptorDecryptor) Encrypt(p []byte) ([]byte, error) { + return w.m.Encrypt(waddrmgr.CKTPrivate, p) +} + +func (w *waddrmgrEncryptorDecryptor) Decrypt(c []byte) ([]byte, error) { + return w.m.Decrypt(waddrmgr.CKTPrivate, c) +} + +func (w *waddrmgrEncryptorDecryptor) OverheadSize() uint32 { + return 24 +} diff --git a/lnwallet/wallet_test.go b/lnwallet/wallet_test.go index 6ea406f2..e20b8359 100644 --- a/lnwallet/wallet_test.go +++ b/lnwallet/wallet_test.go @@ -5,10 +5,12 @@ import ( "fmt" "io/ioutil" "os" + "path/filepath" "testing" "time" "github.com/btcsuite/btcd/chaincfg" + "github.com/lightningnetwork/lnd/channeldb" "github.com/Roasbeef/btcd/rpctest" "github.com/btcsuite/btcd/btcec" @@ -17,7 +19,6 @@ import ( "github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil/coinset" "github.com/btcsuite/btcwallet/waddrmgr" - "github.com/btcsuite/btcwallet/walletdb" ) var ( @@ -147,10 +148,8 @@ func newBobNode(miner *rpctest.Harness) (*bobNode, error) { } // Give bobNode one 7 BTC output for use in creating channels. - outputMap := map[string]btcutil.Amount{ - bobAddr.String(): btcutil.Amount(7e8), - } - mainTxid, err := miner.CoinbaseSpend(outputMap) + output := &wire.TxOut{7e8, bobAddrScript} + mainTxid, err := miner.CoinbaseSpend([]*wire.TxOut{output}) if err != nil { return nil, err } @@ -175,7 +174,7 @@ func newBobNode(miner *rpctest.Harness) (*bobNode, error) { prevOut := wire.NewOutPoint(mainTxid, index) // TODO(roasbeef): When the chain rpc is hooked in, assert bob's output // actually exists and it unspent in the chain. - bobTxIn := wire.NewTxIn(prevOut, nil) + bobTxIn := wire.NewTxIn(prevOut, nil, nil) // Using bobs priv key above, create a change output he can spend. bobChangeOutput := wire.NewTxOut(2*1e8, bobAddrScript) @@ -205,7 +204,7 @@ func newBobNode(miner *rpctest.Harness) (*bobNode, error) { func loadTestCredits(miner *rpctest.Harness, w *LightningWallet, numOutputs, btcPerOutput int) error { // Using the mining node, spend from a coinbase output numOutputs to // give us btcPerOutput with each output. - satoshiPerOutput := btcutil.Amount(btcPerOutput * 1e8) + satoshiPerOutput := int64(btcPerOutput * 1e8) addrs := make([]btcutil.Address, 0, numOutputs) for i := 0; i < numOutputs; i++ { // Grab a fresh address from the wallet to house this output. @@ -214,10 +213,15 @@ func loadTestCredits(miner *rpctest.Harness, w *LightningWallet, numOutputs, btc return err } + script, err := txscript.PayToAddrScript(walletAddr) + if err != nil { + return err + } + addrs = append(addrs, walletAddr) - outputMap := map[string]btcutil.Amount{walletAddr.String(): satoshiPerOutput} - if _, err := miner.CoinbaseSpend(outputMap); err != nil { + output := &wire.TxOut{satoshiPerOutput, script} + if _, err := miner.CoinbaseSpend([]*wire.TxOut{output}); err != nil { return err } } @@ -279,7 +283,13 @@ func createTestWallet(miningNode *rpctest.Harness, netParams *chaincfg.Params) ( CACert: rpcConfig.Certificates, } - wallet, _, err := NewLightningWallet(config) + dbDir := filepath.Join(tempTestDir, "cdb") + cdb, err := channeldb.Create(dbDir) + if err != nil { + return "", nil, err + } + + wallet, err := NewLightningWallet(config, cdb) if err != nil { return "", nil, err } @@ -287,6 +297,8 @@ func createTestWallet(miningNode *rpctest.Harness, netParams *chaincfg.Params) ( return "", nil, err } + cdb.RegisterCryptoSystem(&waddrmgrEncryptorDecryptor{wallet.Manager}) + // Load our test wallet with 5 outputs each holding 4BTC. if err := loadTestCredits(miningNode, wallet, 5, 4); err != nil { return "", nil, err @@ -406,7 +418,7 @@ func testBasicWalletReservationWorkFlow(miner *rpctest.Harness, lnwallet *Lightn // The resulting active channel state should have been persisted to the DB. fundingTx := chanReservation.FinalFundingTx() - channel, err := lnwallet.ChannelDB.FetchOpenChannel(bobNode.id) + channel, err := lnwallet.channelDB.FetchOpenChannel(bobNode.id) if err != nil { t.Fatalf("unable to retrieve channel from DB: %v", err) } @@ -557,11 +569,10 @@ type testLnWallet struct { cleanUpFunc func() } -func clearWalletState(w *LightningWallet) error { +func clearWalletState(w *LightningWallet) { w.nextFundingID = 0 w.fundingLimbo = make(map[uint64]*ChannelReservation) w.ResetLockedOutpoints() - return w.ChannelDB.Wipe() } func TestLightningWallet(t *testing.T) { @@ -597,11 +608,8 @@ func TestLightningWallet(t *testing.T) { for _, walletTest := range walletTests { walletTest(miningNode, lnwallet, t) - if err := clearWalletState(lnwallet); err != nil && err != walletdb.ErrBucketNotFound { - t.Fatalf("unable to clear wallet state: %v", err) - } - // TODO(roasbeef): possible reset mining node's chainstate to - // initial level + // initial level, cleanly wipe buckets + clearWalletState(lnwallet) } }