lnwallet: switch to using channeldb

This commit is contained in:
Olaoluwa Osuntokun 2015-12-26 00:05:55 -06:00
parent ff92efe7df
commit b4e33587b1
2 changed files with 26 additions and 75 deletions

@ -133,11 +133,11 @@ type LightningWallet struct {
// abstract out in order to accomodate zeroMQ/BitcoinCore // abstract out in order to accomodate zeroMQ/BitcoinCore
lmtx sync.RWMutex lmtx sync.RWMutex
db walletdb.DB DB walletdb.DB
// A namespace within boltdb reserved for ln-based wallet meta-data. // A wrapper around a namespace within boltdb reserved for ln-based
// TODO(roasbeef): which possible other namespaces are relevant? // wallet meta-data.
lnNamespace walletdb.Namespace channelDB *ChannelDB
wallet *btcwallet.Wallet wallet *btcwallet.Wallet
rpc *chain.Client 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 // 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) lnNamespace, err := db.Namespace(lightningNamespaceKey)
if err != nil { if err != nil {
return nil, err return nil, err
@ -207,10 +208,10 @@ func NewLightningWallet(privWalletPass, pubWalletPass, hdSeed []byte, dataDir st
// TODO(roasbeef): logging // TODO(roasbeef): logging
return &LightningWallet{ return &LightningWallet{
db: db, DB: db,
wallet: wallet, wallet: wallet,
lnNamespace: lnNamespace, channelDB: NewChannelDB(wallet.Manager, lnNamespace),
msgChan: make(chan interface{}, msgBufferSize), msgChan: make(chan interface{}, msgBufferSize),
// TODO(roasbeef): make this atomic.Uint32 instead? Which is // TODO(roasbeef): make this atomic.Uint32 instead? Which is
// faster, locks or CAS? I'm guessing CAS because assembly: // faster, locks or CAS? I'm guessing CAS because assembly:
// * https://golang.org/src/sync/atomic/asm_amd64.s // * 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 // Add the complete funding transaction to the DB, in it's open bucket
// which will be used for the lifetime of this channel. // which will be used for the lifetime of this channel.
// TODO(roasbeef): serialize OpenChannelState state to disk instead now err := l.channelDB.PutOpenChannel(pendingReservation.partialState)
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())
})
// TODO(roasbeef): broadcast now? // TODO(roasbeef): broadcast now?
// * create goroutine, listens on blockconnected+blockdisconnected channels // * 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 // * use NotifySpent in order to catch non-cooperative spends of revoked
// * NotifySpent(outpoints []*wire.OutPoint) // * NotifySpent(outpoints []*wire.OutPoint)
// commitment txns. Hmm using p2sh or bare multi-sig? // commitment txns. Hmm using p2sh or bare multi-sig?
msg.err <- writeErr // * record partialState.CreationTime once tx is 'open'
msg.err <- err
} }
// nextMultiSigKey... // nextMultiSigKey...

@ -308,7 +308,6 @@ func testBasicWalletReservationWorkFlow(lnwallet *LightningWallet, t *testing.T)
// Bob initiates a channel funded with 5 BTC for each side, so 10 // Bob initiates a channel funded with 5 BTC for each side, so 10
// BTC total. He also generates 2 BTC in change. // BTC total. He also generates 2 BTC in change.
fundingAmount := btcutil.Amount(5 * 1e8) fundingAmount := btcutil.Amount(5 * 1e8)
fmt.Println("init res")
// TODO(roasbeef): include csv delay? // TODO(roasbeef): include csv delay?
chanReservation, err := lnwallet.InitChannelReservation(fundingAmount, chanReservation, err := lnwallet.InitChannelReservation(fundingAmount,
SIGHASH, bobNode.id) SIGHASH, bobNode.id)
@ -340,18 +339,17 @@ func testBasicWalletReservationWorkFlow(lnwallet *LightningWallet, t *testing.T)
if bytes.Equal(ourContribution.RevocationHash[:], zeroHash) { if bytes.Equal(ourContribution.RevocationHash[:], zeroHash) {
t.Fatalf("alice's revocation hash not found") t.Fatalf("alice's revocation hash not found")
} }
// TODO(roasbeef):
//if ourContribution.CsvDelay == 0 { //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, // Bob sends over his output, change addr, pub keys, initial revocation,
// final delivery address, and his accepted csv delay for the commitmen // final delivery address, and his accepted csv delay for the commitmen
// t transactions. // t transactions.
fmt.Println("init reset")
if err := chanReservation.ProcessContribution(bobNode.Contribution()); err != nil { if err := chanReservation.ProcessContribution(bobNode.Contribution()); err != nil {
t.Fatalf("unable to add bob's funds to the funding tx: %v", err) 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 // At this point, the reservation should have our signatures, and a
// partial funding transaction (missing bob's sigs). // partial funding transaction (missing bob's sigs).
@ -397,54 +395,29 @@ func testBasicWalletReservationWorkFlow(lnwallet *LightningWallet, t *testing.T)
if err != nil { if err != nil {
t.Fatalf("unable to sign inputs for bob: %v", err) t.Fatalf("unable to sign inputs for bob: %v", err)
} }
var fakeCommitSig []byte fakeCommitSig := bytes.Repeat([]byte{1}, 64)
fmt.Println("complete res")
if err := chanReservation.CompleteReservation(bobsSigs, fakeCommitSig); err != nil { if err := chanReservation.CompleteReservation(bobsSigs, fakeCommitSig); err != nil {
t.Fatalf("unable to complete funding tx: %v", err) 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 // At this point, the channel can be considered "open" when the funding
// txn hits a "comfortable" depth. // txn hits a "comfortable" depth.
// A bucket should have been created for this pending channel, and the fundingTx := chanReservation.FinalFundingTx()
// 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")
}
// The sub-bucket for this channel, keyed by the txid of the // The resulting active channel state should have been persisted to the DB>
// funding transaction channel, err := lnwallet.channelDB.FetchOpenChannel(bobNode.id)
txid := chanReservation.partialState.FundingTx.TxSha() if err != nil {
bobChanBucket := openChanBucket.Bucket(txid[:]) t.Fatalf("unable to retrieve channel from DB: %v", err)
if bobChanBucket == nil { }
t.Fatalf("bucket for the alice-bob channe should exist, " + if channel.FundingTx.TxSha() != fundingTx.TxSha() {
"but doesn't") t.Fatalf("channel state not properly saved")
} }
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 funding tx should now be valid and complete. // The funding tx should now be valid and complete.
// Check each input and ensure all scripts are fully valid. // Check each input and ensure all scripts are fully valid.
// TODO(roasbeef): remove this loop after nodetest hooked up. // TODO(roasbeef): remove this loop after nodetest hooked up.
var zeroHash wire.ShaHash var zeroHash wire.ShaHash
fundingTx := chanReservation.FinalFundingTx()
for i, input := range fundingTx.TxIn { for i, input := range fundingTx.TxIn {
var pkscript []byte var pkscript []byte
// Bob's txin // Bob's txin
@ -618,7 +591,7 @@ func clearWalletState(w *LightningWallet) error {
w.nextFundingID = 0 w.nextFundingID = 0
w.fundingLimbo = make(map[uint64]*ChannelReservation) w.fundingLimbo = make(map[uint64]*ChannelReservation)
w.wallet.ResetLockedOutpoints() 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() rootBucket := tx.RootBucket()
return rootBucket.DeleteBucket(openChannelBucket) return rootBucket.DeleteBucket(openChannelBucket)
}) })