lnwallet: switch to using channeldb
This commit is contained in:
parent
ff92efe7df
commit
b4e33587b1
@ -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)
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user