diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index 6a90875c..57b11c40 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -133,11 +133,11 @@ type LightningWallet struct { // abstract out in order to accomodate zeroMQ/BitcoinCore lmtx sync.RWMutex - db walletdb.DB + DB walletdb.DB - // A namespace within boltdb reserved for ln-based wallet meta-data. - // TODO(roasbeef): which possible other namespaces are relevant? - lnNamespace walletdb.Namespace + // A wrapper around a namespace within boltdb reserved for ln-based + // wallet meta-data. + channelDB *ChannelDB wallet *btcwallet.Wallet rpc *chain.Client @@ -198,7 +198,8 @@ func NewLightningWallet(privWalletPass, pubWalletPass, hdSeed []byte, dataDir st } // Create a special namespace for our unique payment channel related - // meta-data. + // meta-data. Subsequently initializing the channeldb around the + // created namespace. lnNamespace, err := db.Namespace(lightningNamespaceKey) if err != nil { return nil, err @@ -207,10 +208,10 @@ func NewLightningWallet(privWalletPass, pubWalletPass, hdSeed []byte, dataDir st // TODO(roasbeef): logging return &LightningWallet{ - db: db, - wallet: wallet, - lnNamespace: lnNamespace, - msgChan: make(chan interface{}, msgBufferSize), + DB: db, + wallet: wallet, + channelDB: NewChannelDB(wallet.Manager, lnNamespace), + msgChan: make(chan interface{}, msgBufferSize), // TODO(roasbeef): make this atomic.Uint32 instead? Which is // faster, locks or CAS? I'm guessing CAS because assembly: // * https://golang.org/src/sync/atomic/asm_amd64.s @@ -738,31 +739,7 @@ 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. - // TODO(roasbeef): serialize OpenChannelState state to disk instead now - writeErr := l.lnNamespace.Update(func(tx walletdb.Tx) error { - // Get the bucket dedicated to storing the meta-data for open - // channels. - // TODO(roasbeef): CHECKSUMS, REDUNDANCY, etc etc. - rootBucket := tx.RootBucket() - openChanBucket, err := rootBucket.CreateBucketIfNotExists(openChannelBucket) - if err != nil { - return err - } - - // Create a new sub-bucket within the open channel bucket - // specifically for this channel. - // TODO(roasbeef): should def be indexed by LNID, cuz mal etc. - txID := fundingTx.TxSha() - chanBucket, err := openChanBucket.CreateBucketIfNotExists(txID.Bytes()) - if err != nil { - return err - } - - // TODO(roasbeef): sync.Pool of buffers in the future. - var buf bytes.Buffer - fundingTx.Serialize(&buf) - return chanBucket.Put(fundingTxKey, buf.Bytes()) - }) + err := l.channelDB.PutOpenChannel(pendingReservation.partialState) // TODO(roasbeef): broadcast now? // * create goroutine, listens on blockconnected+blockdisconnected channels @@ -773,7 +750,8 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs // * use NotifySpent in order to catch non-cooperative spends of revoked // * NotifySpent(outpoints []*wire.OutPoint) // commitment txns. Hmm using p2sh or bare multi-sig? - msg.err <- writeErr + // * record partialState.CreationTime once tx is 'open' + msg.err <- err } // nextMultiSigKey... diff --git a/lnwallet/wallet_test.go b/lnwallet/wallet_test.go index e55a955a..311b4501 100644 --- a/lnwallet/wallet_test.go +++ b/lnwallet/wallet_test.go @@ -308,7 +308,6 @@ func testBasicWalletReservationWorkFlow(lnwallet *LightningWallet, t *testing.T) // Bob initiates a channel funded with 5 BTC for each side, so 10 // BTC total. He also generates 2 BTC in change. fundingAmount := btcutil.Amount(5 * 1e8) - fmt.Println("init res") // TODO(roasbeef): include csv delay? chanReservation, err := lnwallet.InitChannelReservation(fundingAmount, SIGHASH, bobNode.id) @@ -340,18 +339,17 @@ func testBasicWalletReservationWorkFlow(lnwallet *LightningWallet, t *testing.T) if bytes.Equal(ourContribution.RevocationHash[:], zeroHash) { t.Fatalf("alice's revocation hash not found") } + // TODO(roasbeef): //if ourContribution.CsvDelay == 0 { - //t.Fatalf("csv delay not set") + // t.Fatalf("csv delay not set") //} // Bob sends over his output, change addr, pub keys, initial revocation, // final delivery address, and his accepted csv delay for the commitmen // t transactions. - fmt.Println("init reset") if err := chanReservation.ProcessContribution(bobNode.Contribution()); err != nil { t.Fatalf("unable to add bob's funds to the funding tx: %v", err) } - fmt.Println("fin reset") // At this point, the reservation should have our signatures, and a // partial funding transaction (missing bob's sigs). @@ -397,54 +395,29 @@ func testBasicWalletReservationWorkFlow(lnwallet *LightningWallet, t *testing.T) if err != nil { t.Fatalf("unable to sign inputs for bob: %v", err) } - var fakeCommitSig []byte - fmt.Println("complete res") + fakeCommitSig := bytes.Repeat([]byte{1}, 64) if err := chanReservation.CompleteReservation(bobsSigs, fakeCommitSig); err != nil { t.Fatalf("unable to complete funding tx: %v", err) } - fmt.Println("fin complete res") // At this point, the channel can be considered "open" when the funding // txn hits a "comfortable" depth. - // A bucket should have been created for this pending channel, and the - // state commited. - err = lnwallet.lnNamespace.View(func(tx walletdb.Tx) error { - // The open channel bucket should have been created. - rootBucket := tx.RootBucket() - openChanBucket := rootBucket.Bucket(openChannelBucket) - if openChanBucket == nil { - t.Fatalf("openChanBucket should be created, but isn't") - } + fundingTx := chanReservation.FinalFundingTx() - // The sub-bucket for this channel, keyed by the txid of the - // funding transaction - txid := chanReservation.partialState.FundingTx.TxSha() - bobChanBucket := openChanBucket.Bucket(txid[:]) - if bobChanBucket == nil { - t.Fatalf("bucket for the alice-bob channe should exist, " + - "but doesn't") - } - - var storedTx wire.MsgTx - b := bytes.NewReader(bobChanBucket.Get(fundingTxKey)) - storedTx.Deserialize(b) - - // The hash of the stored tx should be indentical to our funding tx. - storedTxId := storedTx.TxSha() - actualTxId := chanReservation.partialState.FundingTx.TxSha() - if !bytes.Equal(storedTxId.Bytes(), actualTxId.Bytes()) { - t.Fatalf("stored funding tx doesn't match actual") - } - - return nil - }) + // The resulting active channel state should have been persisted to the DB> + channel, err := lnwallet.channelDB.FetchOpenChannel(bobNode.id) + if err != nil { + t.Fatalf("unable to retrieve channel from DB: %v", err) + } + if channel.FundingTx.TxSha() != fundingTx.TxSha() { + t.Fatalf("channel state not properly saved") + } // The funding tx should now be valid and complete. // Check each input and ensure all scripts are fully valid. // TODO(roasbeef): remove this loop after nodetest hooked up. var zeroHash wire.ShaHash - fundingTx := chanReservation.FinalFundingTx() for i, input := range fundingTx.TxIn { var pkscript []byte // Bob's txin @@ -618,7 +591,7 @@ func clearWalletState(w *LightningWallet) error { w.nextFundingID = 0 w.fundingLimbo = make(map[uint64]*ChannelReservation) w.wallet.ResetLockedOutpoints() - return w.lnNamespace.Update(func(tx walletdb.Tx) error { + return w.channelDB.namespace.Update(func(tx walletdb.Tx) error { rootBucket := tx.RootBucket() return rootBucket.DeleteBucket(openChannelBucket) })