From a16bfd77759b36aa61065c609ba61b31517b6e06 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 11 Jan 2018 03:21:49 -0700 Subject: [PATCH] chain/neutrino: fix data races due to not using pointer for rescan --- chain/neutrino.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/chain/neutrino.go b/chain/neutrino.go index 280ec1e..c9c7bf6 100644 --- a/chain/neutrino.go +++ b/chain/neutrino.go @@ -20,7 +20,7 @@ type NeutrinoClient struct { CS *neutrino.ChainService // We currently support one rescan/notifiction goroutine per client - rescan neutrino.Rescan + rescan *neutrino.Rescan enqueueNotification chan interface{} dequeueNotification chan interface{} @@ -181,6 +181,8 @@ func (s *NeutrinoClient) Rescan(startHash *chainhash.Hash, addrs []btcutil.Addre s.clientMtx.Unlock() s.rescan.WaitForShutdown() s.clientMtx.Lock() + s.rescan = nil + s.rescanErr = nil } s.rescanQuit = make(chan struct{}) s.scanning = true @@ -214,7 +216,7 @@ func (s *NeutrinoClient) Rescan(startHash *chainhash.Hash, addrs []btcutil.Addre } } - s.rescan = s.CS.NewRescan( + newRescan := s.CS.NewRescan( neutrino.NotificationHandlers(rpcclient.NotificationHandlers{ OnBlockConnected: s.onBlockConnected, OnFilteredBlockConnected: s.onFilteredBlockConnected, @@ -226,6 +228,7 @@ func (s *NeutrinoClient) Rescan(startHash *chainhash.Hash, addrs []btcutil.Addre neutrino.WatchAddrs(addrs...), neutrino.WatchOutPoints(watchOutPoints...), ) + s.rescan = &newRescan s.rescanErr = s.rescan.Start() return nil @@ -263,7 +266,7 @@ func (s *NeutrinoClient) NotifyReceived(addrs []btcutil.Address) error { s.lastProgressSent = true // Rescan with just the specified addresses. - s.rescan = s.CS.NewRescan( + newRescan := s.CS.NewRescan( neutrino.NotificationHandlers(rpcclient.NotificationHandlers{ OnBlockConnected: s.onBlockConnected, OnFilteredBlockConnected: s.onFilteredBlockConnected, @@ -273,6 +276,7 @@ func (s *NeutrinoClient) NotifyReceived(addrs []btcutil.Address) error { neutrino.QuitChan(s.rescanQuit), neutrino.WatchAddrs(addrs...), ) + s.rescan = &newRescan s.rescanErr = s.rescan.Start() s.clientMtx.Unlock() return nil @@ -467,6 +471,9 @@ func (s *NeutrinoClient) notificationHandler() { var next interface{} out: for { + s.clientMtx.Lock() + rescanErr := s.rescanErr + s.clientMtx.Unlock() select { case n, ok := <-enqueue: if !ok { @@ -506,7 +513,7 @@ out: dequeue = nil } - case err := <-s.rescanErr: + case err := <-rescanErr: if err != nil { log.Errorf("Neutrino rescan ended with error: %s", err) }