Mark finished rescan from notification.

Fixes #99.
This commit is contained in:
Josh Rickmar 2014-06-16 14:19:32 -05:00
parent 23dca5edfd
commit aa6892a32a
3 changed files with 57 additions and 16 deletions

View file

@ -949,9 +949,15 @@ func (am *AccountManager) ListUnspent(minconf, maxconf int,
} }
// RescanActiveAddresses begins a rescan for all active addresses for // RescanActiveAddresses begins a rescan for all active addresses for
// each account. // each account. If markBestBlock is non-nil, the block described by
func (am *AccountManager) RescanActiveAddresses() error { // the blockstamp is used to mark the synced-with height of the wallet
// just before the rescan is submitted and started. This allows the
// caller to mark the progress that the rescan is expected to complete
// through, if the account otherwise does not contain any recently
// seen blocks.
func (am *AccountManager) RescanActiveAddresses(markBestBlock *wallet.BlockStamp) error {
var job *RescanJob var job *RescanJob
var defaultAcct *Account
for _, a := range am.AllAccounts() { for _, a := range am.AllAccounts() {
acctJob, err := a.RescanActiveJob() acctJob, err := a.RescanActiveJob()
if err != nil { if err != nil {
@ -962,8 +968,16 @@ func (am *AccountManager) RescanActiveAddresses() error {
} else { } else {
job.Merge(acctJob) job.Merge(acctJob)
} }
if a.name == "" {
defaultAcct = a
}
} }
if job != nil { if job != nil {
if markBestBlock != nil {
defaultAcct.SetSyncedWith(markBestBlock)
}
// Submit merged job and block until rescan completes. // Submit merged job and block until rescan completes.
jobFinished := am.rm.SubmitJob(job) jobFinished := am.rm.SubmitJob(job)
<-jobFinished <-jobFinished

View file

@ -140,10 +140,6 @@ func (b *rescanBatch) merge(job *RescanJob) {
} }
} }
type rescanFinished struct {
error
}
// jobHandler runs the RescanManager's for-select loop to manage rescan jobs // jobHandler runs the RescanManager's for-select loop to manage rescan jobs
// and dispatch requests. // and dispatch requests.
func (m *RescanManager) jobHandler() { func (m *RescanManager) jobHandler() {
@ -224,11 +220,13 @@ func (m *RescanManager) rpcHandler() {
} }
client, err := accessClient() client, err := accessClient()
if err != nil { if err != nil {
m.status <- rescanFinished{err} m.MarkFinished(rescanFinished{err})
return return
} }
err = client.Rescan(job.StartHeight, addrs, job.OutPoints) err = client.Rescan(job.StartHeight, addrs, job.OutPoints)
m.status <- rescanFinished{err} if err != nil {
m.MarkFinished(rescanFinished{err})
}
} }
} }
@ -268,3 +266,9 @@ func (m *RescanManager) SubmitJob(job *RescanJob) <-chan struct{} {
func (m *RescanManager) MarkProgress(height rescanProgress) { func (m *RescanManager) MarkProgress(height rescanProgress) {
m.status <- height m.status <- height
} }
// MarkFinished messages the RescanManager that the currently running rescan
// finished, or errored prematurely.
func (m *RescanManager) MarkFinished(finished rescanFinished) {
m.status <- finished
}

View file

@ -61,8 +61,6 @@ const (
maxUnhandledNotifications = 50 maxUnhandledNotifications = 50
) )
type notificationChan chan notification
type blockSummary struct { type blockSummary struct {
hash *btcwire.ShaHash hash *btcwire.ShaHash
height int32 height int32
@ -87,9 +85,14 @@ type (
blockDisconnected blockSummary blockDisconnected blockSummary
recvTx acceptedTx recvTx acceptedTx
redeemingTx acceptedTx redeemingTx acceptedTx
rescanFinished struct {
error
}
rescanProgress int32 rescanProgress int32
) )
type notificationChan chan notification
func (c notificationChan) onBlockConnected(hash *btcwire.ShaHash, height int32) { func (c notificationChan) onBlockConnected(hash *btcwire.ShaHash, height int32) {
c <- (blockConnected)(blockSummary{hash, height}) c <- (blockConnected)(blockSummary{hash, height})
} }
@ -106,6 +109,10 @@ func (c notificationChan) onRedeemingTx(tx *btcutil.Tx, block *btcws.BlockDetail
c <- redeemingTx{tx, block} c <- redeemingTx{tx, block}
} }
func (c notificationChan) onRescanFinished(height int32) {
c <- rescanFinished{error: nil}
}
func (c notificationChan) onRescanProgress(height int32) { func (c notificationChan) onRescanProgress(height int32) {
c <- rescanProgress(height) c <- rescanProgress(height)
} }
@ -133,7 +140,9 @@ func (n blockConnected) handleNotification() error {
wg.Wait() wg.Wait()
NotifyBalanceSyncerChans.remove <- *n.hash NotifyBalanceSyncerChans.remove <- *n.hash
} }
AcctMgr.Grab()
AcctMgr.BlockNotify(bs) AcctMgr.BlockNotify(bs)
AcctMgr.Release()
// Pass notification to wallet clients too. // Pass notification to wallet clients too.
if server != nil { if server != nil {
@ -158,6 +167,9 @@ func (n blockConnected) MarshalJSON() ([]byte, error) {
} }
func (n blockDisconnected) handleNotification() error { func (n blockDisconnected) handleNotification() error {
AcctMgr.Grab()
defer AcctMgr.Release()
// Rollback Utxo and Tx data stores. // Rollback Utxo and Tx data stores.
if err := AcctMgr.Rollback(n.height, n.hash); err != nil { if err := AcctMgr.Rollback(n.height, n.hash); err != nil {
return err return err
@ -233,6 +245,9 @@ func (n recvTx) handleNotification() error {
SendTxHistSyncChans.remove <- *n.tx.Sha() SendTxHistSyncChans.remove <- *n.tx.Sha()
} }
AcctMgr.Grab()
defer AcctMgr.Release()
// For every output, find all accounts handling that output address (if any) // For every output, find all accounts handling that output address (if any)
// and record the received txout. // and record the received txout.
for outIdx, txout := range n.tx.MsgTx().TxOut { for outIdx, txout := range n.tx.MsgTx().TxOut {
@ -301,7 +316,16 @@ func (n redeemingTx) handleNotification() error {
return InvalidNotificationError{err} return InvalidNotificationError{err}
} }
n.tx.SetIndex(txIdx) n.tx.SetIndex(txIdx)
return AcctMgr.RecordSpendingTx(n.tx, block)
AcctMgr.Grab()
err = AcctMgr.RecordSpendingTx(n.tx, block)
AcctMgr.Release()
return err
}
func (n rescanFinished) handleNotification() error {
AcctMgr.rm.MarkFinished(n)
return nil
} }
func (n rescanProgress) handleNotification() error { func (n rescanProgress) handleNotification() error {
@ -339,6 +363,7 @@ func newRPCClient(certs []byte) (*rpcClient, error) {
OnBlockDisconnected: ntfns.onBlockDisconnected, OnBlockDisconnected: ntfns.onBlockDisconnected,
OnRecvTx: ntfns.onRecvTx, OnRecvTx: ntfns.onRecvTx,
OnRedeemingTx: ntfns.onRedeemingTx, OnRedeemingTx: ntfns.onRedeemingTx,
OnRescanFinished: ntfns.onRescanFinished,
OnRescanProgress: ntfns.onRescanProgress, OnRescanProgress: ntfns.onRescanProgress,
} }
conf := btcrpcclient.ConnConfig{ conf := btcrpcclient.ConnConfig{
@ -377,7 +402,6 @@ func (c *rpcClient) WaitForShutdown() {
func (c *rpcClient) handleNotifications() { func (c *rpcClient) handleNotifications() {
for n := range c.chainNotifications { for n := range c.chainNotifications {
AcctMgr.Grab()
err := n.handleNotification() err := n.handleNotification()
if err != nil { if err != nil {
switch e := err.(type) { switch e := err.(type) {
@ -387,7 +411,6 @@ func (c *rpcClient) handleNotifications() {
log.Errorf("Cannot handle notification: %v", e) log.Errorf("Cannot handle notification: %v", e)
} }
} }
AcctMgr.Release()
} }
c.wg.Done() c.wg.Done()
} }
@ -473,7 +496,7 @@ func (c *rpcClient) Handshake() error {
// Begin tracking wallets against this btcd instance. // Begin tracking wallets against this btcd instance.
AcctMgr.Track() AcctMgr.Track()
if err := AcctMgr.RescanActiveAddresses(); err != nil { if err := AcctMgr.RescanActiveAddresses(nil); err != nil {
return err return err
} }
// TODO: Only begin tracking new unspent outputs as a result // TODO: Only begin tracking new unspent outputs as a result
@ -492,7 +515,7 @@ func (c *rpcClient) Handshake() error {
// Iterator was invalid (wallet has never been synced) or there was a // Iterator was invalid (wallet has never been synced) or there was a
// huge chain fork + reorg (more than 20 blocks). // huge chain fork + reorg (more than 20 blocks).
AcctMgr.Track() AcctMgr.Track()
if err := AcctMgr.RescanActiveAddresses(); err != nil { if err := AcctMgr.RescanActiveAddresses(&bs); err != nil {
return err return err
} }
// TODO: only begin tracking new unspent outputs as a result of the // TODO: only begin tracking new unspent outputs as a result of the