OpenBazaar / multiwallet

API based multi-cryptocurrency wallet
MIT License
75 stars 41 forks source link

Watched addresses are not re-subscribed on Blockbook when websocket connection is restarted #106

Closed placer14 closed 4 years ago

placer14 commented 4 years ago

When the websocket connection from multiwallet to blockbook is restarted by the websocket watchdog, we are not re-subscribing to watched addresses. This causes the multiwallet to ignore new transactions reported by the network for addresses of interest and the internal wallet state cannot be updated until a manual restart of the multiwallet is triggered.

Acceptance criteria for a fix:

hoffmabc commented 4 years ago

https://github.com/OpenBazaar/openbazaar-go/issues/1919 tracks the multiwallet AddWatchedAddresses optimization @placer14 .

hoffmabc commented 4 years ago

This does in fact seem to be the authoritative source when spinning up the node https://github.com/OpenBazaar/openbazaar-go/blob/f3499105bfdb834cddf365e140f391ffac0033f8/vendor/github.com/OpenBazaar/multiwallet/service/wallet_service.go#L569

func (ws *WalletService) listen() {
    var (
        addrs     = ws.getStoredAddresses()
        txChan    = ws.client.TransactionNotify()
        blockChan = ws.client.BlockNotify()
    )

Can you verify @cpacia ?

hoffmabc commented 4 years ago

It seems as though addresses are re-subscribed in the code already on socket disconnection @placer14. I'm confused.

On disconnect we bark the watchdog

i.SocketClient.On(gosocketio.OnDisconnection, func(c *gosocketio.Channel) {
        Log.Warningf("websocket disconnected (%s)", i.String())
        i.websocketWatchdog.bark()
    })

which triggers a setupListeners() call that reconnects the subscription.

func (w *wsWatchdog) guardWebsocket() {
    var t = time.NewTicker(1 * time.Second)
    defer t.Stop()
    for range t.C {
        select {
        case <-w.wsStopped:
            Log.Warningf("reconnecting stopped websocket (%s)", w.client.String())
            w.client.socketMutex.Lock()
            if w.client.SocketClient != nil {
                w.client.SocketClient.Close()
                w.client.SocketClient = nil
            }
            w.drainAndRollover()
            if err := w.client.setupListeners(); err != nil {
                Log.Warningf("failed reconnecting websocket (%s)", w.client.String())
                w.client.socketMutex.Unlock()
                w.client.sendAndDiscardCloseChan(fmt.Errorf("websocket unavailable (%s): %s", w.client.String(), err.Error()))
                go w.putAway()
                return
            }
            w.client.socketMutex.Unlock()
        case <-w.done:
            return
        }
    }
}

setupListeners() executes:

for _, addr := range i.listenQueue {
        var args []interface{}
        args = append(args, "bitcoind/addresstxid")
        args = append(args, []string{addr})
        i.SocketClient.Emit("subscribe", args)
    }

which subscribes to those in the listenQueue again.

hoffmabc commented 4 years ago

I can make this subscribe obviously a bulk one but that doesn't change the reconnect behavior.

placer14 commented 4 years ago

Closing as resolved by https://github.com/OpenBazaar/openbazaar-go/issues/1918.