chain/neutrino: fix data races due to not using pointer for rescan

This commit is contained in:
Alex 2018-01-11 03:21:49 -07:00 committed by Olaoluwa Osuntokun
parent 78a69b4802
commit a16bfd7775

View file

@ -20,7 +20,7 @@ type NeutrinoClient struct {
CS *neutrino.ChainService CS *neutrino.ChainService
// We currently support one rescan/notifiction goroutine per client // We currently support one rescan/notifiction goroutine per client
rescan neutrino.Rescan rescan *neutrino.Rescan
enqueueNotification chan interface{} enqueueNotification chan interface{}
dequeueNotification chan interface{} dequeueNotification chan interface{}
@ -181,6 +181,8 @@ func (s *NeutrinoClient) Rescan(startHash *chainhash.Hash, addrs []btcutil.Addre
s.clientMtx.Unlock() s.clientMtx.Unlock()
s.rescan.WaitForShutdown() s.rescan.WaitForShutdown()
s.clientMtx.Lock() s.clientMtx.Lock()
s.rescan = nil
s.rescanErr = nil
} }
s.rescanQuit = make(chan struct{}) s.rescanQuit = make(chan struct{})
s.scanning = true 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{ neutrino.NotificationHandlers(rpcclient.NotificationHandlers{
OnBlockConnected: s.onBlockConnected, OnBlockConnected: s.onBlockConnected,
OnFilteredBlockConnected: s.onFilteredBlockConnected, OnFilteredBlockConnected: s.onFilteredBlockConnected,
@ -226,6 +228,7 @@ func (s *NeutrinoClient) Rescan(startHash *chainhash.Hash, addrs []btcutil.Addre
neutrino.WatchAddrs(addrs...), neutrino.WatchAddrs(addrs...),
neutrino.WatchOutPoints(watchOutPoints...), neutrino.WatchOutPoints(watchOutPoints...),
) )
s.rescan = &newRescan
s.rescanErr = s.rescan.Start() s.rescanErr = s.rescan.Start()
return nil return nil
@ -263,7 +266,7 @@ func (s *NeutrinoClient) NotifyReceived(addrs []btcutil.Address) error {
s.lastProgressSent = true s.lastProgressSent = true
// Rescan with just the specified addresses. // Rescan with just the specified addresses.
s.rescan = s.CS.NewRescan( newRescan := s.CS.NewRescan(
neutrino.NotificationHandlers(rpcclient.NotificationHandlers{ neutrino.NotificationHandlers(rpcclient.NotificationHandlers{
OnBlockConnected: s.onBlockConnected, OnBlockConnected: s.onBlockConnected,
OnFilteredBlockConnected: s.onFilteredBlockConnected, OnFilteredBlockConnected: s.onFilteredBlockConnected,
@ -273,6 +276,7 @@ func (s *NeutrinoClient) NotifyReceived(addrs []btcutil.Address) error {
neutrino.QuitChan(s.rescanQuit), neutrino.QuitChan(s.rescanQuit),
neutrino.WatchAddrs(addrs...), neutrino.WatchAddrs(addrs...),
) )
s.rescan = &newRescan
s.rescanErr = s.rescan.Start() s.rescanErr = s.rescan.Start()
s.clientMtx.Unlock() s.clientMtx.Unlock()
return nil return nil
@ -467,6 +471,9 @@ func (s *NeutrinoClient) notificationHandler() {
var next interface{} var next interface{}
out: out:
for { for {
s.clientMtx.Lock()
rescanErr := s.rescanErr
s.clientMtx.Unlock()
select { select {
case n, ok := <-enqueue: case n, ok := <-enqueue:
if !ok { if !ok {
@ -506,7 +513,7 @@ out:
dequeue = nil dequeue = nil
} }
case err := <-s.rescanErr: case err := <-rescanErr:
if err != nil { if err != nil {
log.Errorf("Neutrino rescan ended with error: %s", err) log.Errorf("Neutrino rescan ended with error: %s", err)
} }