wallet: move DB access from rescan ntfns into correct goroutine

This commit is contained in:
Alex 2017-09-21 15:14:55 -06:00 committed by Olaoluwa Osuntokun
parent 81a9bb67c1
commit 8e2c741f88
2 changed files with 51 additions and 96 deletions

View file

@ -33,6 +33,47 @@ func (w *Wallet) handleChainNotifications() {
}
}
catchUpHashes := func(w *Wallet, client chain.Interface,
height int32) error {
// TODO(aakselrod): There's a race conditon here, which
// happens when a reorg occurs between the
// rescanProgress notification and the last GetBlockHash
// call. The solution when using btcd is to make btcd
// send blockconnected notifications with each block
// the way Neutrino does, and get rid of the loop. The
// other alternative is to check the final hash and,
// if it doesn't match the original hash returned by
// the notification, to roll back and restart the
// rescan.
log.Infof("Catching up block hashes to height %d, this"+
" might take a while", height)
err := walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
startBlock := w.Manager.SyncedTo()
for i := startBlock.Height + 1; i <= height; i++ {
hash, err := client.GetBlockHash(int64(i))
if err != nil {
return err
}
bs := waddrmgr.BlockStamp{
Height: i,
Hash: *hash,
}
err = w.Manager.SetSyncedTo(ns, &bs)
if err != nil {
return err
}
}
return nil
})
if err != nil {
log.Errorf("Failed to update address manager "+
"sync state for height %d: %v", height, err)
}
log.Info("Done catching up block hashes")
return err
}
for n := range chainClient.Notifications() {
var notificationName string
var err error
@ -72,9 +113,16 @@ func (w *Wallet) handleChainNotifications() {
}
notificationName = "filteredblockconnected"
// The following are handled by the wallet's rescan
// goroutines, so just pass them there.
case *chain.RescanProgress, *chain.RescanFinished:
// The following require some database maintenance, but also
// need to be reported to the wallet's rescan goroutine.
case *chain.RescanProgress:
err = catchUpHashes(w, chainClient, n.Height)
notificationName = "rescanprogress"
w.rescanNotifications <- n
case *chain.RescanFinished:
err = catchUpHashes(w, chainClient, n.Height)
notificationName = "rescanprogress"
w.SetChainSynced(true)
w.rescanNotifications <- n
}
if err != nil {

View file

@ -9,7 +9,6 @@ import (
"github.com/roasbeef/btcutil"
"github.com/roasbeef/btcwallet/chain"
"github.com/roasbeef/btcwallet/waddrmgr"
"github.com/roasbeef/btcwallet/walletdb"
"github.com/roasbeef/btcwallet/wtxmgr"
)
@ -175,51 +174,6 @@ out:
log.Infof("Rescanned through block %v (height %d)",
n.Hash, n.Height)
client := w.ChainClient()
// Since btcd rescans don't send blockconnected
// notifications, we need to cycle through all of the
// rescanned blocks and write the hashes to the
// database. Neutrino rescans do send the notifications,
// which means this loop won't actually cycle.
//
// TODO(aakselrod): There's a race conditon here, which
// happens when a reorg occurs between the
// rescanProgress notification and the last GetBlockHash
// call. The solution when using btcd is to make btcd
// send blockconnected notifications with each block
// the way Neutrino does, and get rid of the loop. The
// other alternative is to check the final hash and,
// if it doesn't match the original hash returned by
// the notification, to roll back and restart the
// rescan.
log.Infof("Catching up block hashes to height %d, this"+
" might take a while", n.Height)
err := walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
startBlock := w.Manager.SyncedTo()
for i := startBlock.Height + 1; i <= n.Height; i++ {
hash, err := client.GetBlockHash(int64(i))
if err != nil {
return err
}
bs := waddrmgr.BlockStamp{
Height: i,
Hash: *hash,
}
err = w.Manager.SetSyncedTo(ns, &bs)
if err != nil {
return err
}
}
return nil
})
if err != nil {
log.Errorf("Failed to update address manager "+
"sync state for hash %v (height %d): %v",
n.Hash, n.Height, err)
}
log.Info("Done catching up block hashes")
case msg := <-w.rescanFinished:
n := msg.Notification
addrs := msg.Addresses
@ -228,53 +182,6 @@ out:
"%s, height %d)", len(addrs), noun, n.Hash,
n.Height)
client := w.ChainClient()
// Since btcd rescans don't send blockconnected
// notifications, we need to cycle through all of the
// rescanned blocks and write the hashes to the
// database. Neutrino rescans do send the notifications,
// which means this loop won't actually cycle.
//
// TODO(aakselrod): There's a race conditon here, which
// happens when a reorg occurs between the
// rescanFinished notification and the last GetBlockHash
// call. The solution when using btcd is to make btcd
// send blockconnected notifications with each block
// the way Neutrino does, and get rid of the loop. The
// other alternative is to check the final hash and,
// if it doesn't match the original hash returned by
// the notification, to roll back and restart the
// rescan.
log.Infof("Catching up block hashes to height %d, this"+
" might take a while", n.Height)
err := walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
startBlock := w.Manager.SyncedTo()
for i := startBlock.Height + 1; i <= n.Height; i++ {
hash, err := client.GetBlockHash(int64(i))
if err != nil {
return err
}
bs := waddrmgr.BlockStamp{
Height: i,
Hash: *hash,
}
err = w.Manager.SetSyncedTo(ns, &bs)
if err != nil {
return err
}
}
return nil
})
if err != nil {
log.Errorf("Failed to update address manager "+
"sync state for hash %v (height %d): %v",
n.Hash, n.Height, err)
continue
}
w.SetChainSynced(true)
log.Info("Done catching up block hashes")
go w.resendUnminedTxs()
case <-quit: