github.com/palcoin-project/palcd@v1.0.0/rpcwebsocket.go (about)

     1  // Copyright (c) 2013-2017 The btcsuite developers
     2  // Copyright (c) 2015-2017 The Decred developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package main
     7  
     8  import (
     9  	"bytes"
    10  	"container/list"
    11  	"crypto/sha256"
    12  	"crypto/subtle"
    13  	"encoding/base64"
    14  	"encoding/hex"
    15  	"encoding/json"
    16  	"errors"
    17  	"fmt"
    18  	"io"
    19  	"math"
    20  	"sync"
    21  	"time"
    22  
    23  	"github.com/btcsuite/websocket"
    24  	"github.com/palcoin-project/palcd/blockchain"
    25  	"github.com/palcoin-project/palcd/btcjson"
    26  	"github.com/palcoin-project/palcd/chaincfg"
    27  	"github.com/palcoin-project/palcd/chaincfg/chainhash"
    28  	"github.com/palcoin-project/palcd/database"
    29  	"github.com/palcoin-project/palcd/txscript"
    30  	"github.com/palcoin-project/palcd/wire"
    31  	"github.com/palcoin-project/palcutil"
    32  	"golang.org/x/crypto/ripemd160"
    33  )
    34  
    35  const (
    36  	// websocketSendBufferSize is the number of elements the send channel
    37  	// can queue before blocking.  Note that this only applies to requests
    38  	// handled directly in the websocket client input handler or the async
    39  	// handler since notifications have their own queuing mechanism
    40  	// independent of the send channel buffer.
    41  	websocketSendBufferSize = 50
    42  )
    43  
    44  type semaphore chan struct{}
    45  
    46  func makeSemaphore(n int) semaphore {
    47  	return make(chan struct{}, n)
    48  }
    49  
    50  func (s semaphore) acquire() { s <- struct{}{} }
    51  func (s semaphore) release() { <-s }
    52  
    53  // timeZeroVal is simply the zero value for a time.Time and is used to avoid
    54  // creating multiple instances.
    55  var timeZeroVal time.Time
    56  
    57  // wsCommandHandler describes a callback function used to handle a specific
    58  // command.
    59  type wsCommandHandler func(*wsClient, interface{}) (interface{}, error)
    60  
    61  // wsHandlers maps RPC command strings to appropriate websocket handler
    62  // functions.  This is set by init because help references wsHandlers and thus
    63  // causes a dependency loop.
    64  var wsHandlers map[string]wsCommandHandler
    65  var wsHandlersBeforeInit = map[string]wsCommandHandler{
    66  	"loadtxfilter":              handleLoadTxFilter,
    67  	"help":                      handleWebsocketHelp,
    68  	"notifyblocks":              handleNotifyBlocks,
    69  	"notifynewtransactions":     handleNotifyNewTransactions,
    70  	"notifyreceived":            handleNotifyReceived,
    71  	"notifyspent":               handleNotifySpent,
    72  	"session":                   handleSession,
    73  	"stopnotifyblocks":          handleStopNotifyBlocks,
    74  	"stopnotifynewtransactions": handleStopNotifyNewTransactions,
    75  	"stopnotifyspent":           handleStopNotifySpent,
    76  	"stopnotifyreceived":        handleStopNotifyReceived,
    77  	"rescan":                    handleRescan,
    78  	"rescanblocks":              handleRescanBlocks,
    79  }
    80  
    81  // WebsocketHandler handles a new websocket client by creating a new wsClient,
    82  // starting it, and blocking until the connection closes.  Since it blocks, it
    83  // must be run in a separate goroutine.  It should be invoked from the websocket
    84  // server handler which runs each new connection in a new goroutine thereby
    85  // satisfying the requirement.
    86  func (s *rpcServer) WebsocketHandler(conn *websocket.Conn, remoteAddr string,
    87  	authenticated bool, isAdmin bool) {
    88  
    89  	// Clear the read deadline that was set before the websocket hijacked
    90  	// the connection.
    91  	conn.SetReadDeadline(timeZeroVal)
    92  
    93  	// Limit max number of websocket clients.
    94  	rpcsLog.Infof("New websocket client %s", remoteAddr)
    95  	if s.ntfnMgr.NumClients()+1 > cfg.RPCMaxWebsockets {
    96  		rpcsLog.Infof("Max websocket clients exceeded [%d] - "+
    97  			"disconnecting client %s", cfg.RPCMaxWebsockets,
    98  			remoteAddr)
    99  		conn.Close()
   100  		return
   101  	}
   102  
   103  	// Create a new websocket client to handle the new websocket connection
   104  	// and wait for it to shutdown.  Once it has shutdown (and hence
   105  	// disconnected), remove it and any notifications it registered for.
   106  	client, err := newWebsocketClient(s, conn, remoteAddr, authenticated, isAdmin)
   107  	if err != nil {
   108  		rpcsLog.Errorf("Failed to serve client %s: %v", remoteAddr, err)
   109  		conn.Close()
   110  		return
   111  	}
   112  	s.ntfnMgr.AddClient(client)
   113  	client.Start()
   114  	client.WaitForShutdown()
   115  	s.ntfnMgr.RemoveClient(client)
   116  	rpcsLog.Infof("Disconnected websocket client %s", remoteAddr)
   117  }
   118  
   119  // wsNotificationManager is a connection and notification manager used for
   120  // websockets.  It allows websocket clients to register for notifications they
   121  // are interested in.  When an event happens elsewhere in the code such as
   122  // transactions being added to the memory pool or block connects/disconnects,
   123  // the notification manager is provided with the relevant details needed to
   124  // figure out which websocket clients need to be notified based on what they
   125  // have registered for and notifies them accordingly.  It is also used to keep
   126  // track of all connected websocket clients.
   127  type wsNotificationManager struct {
   128  	// server is the RPC server the notification manager is associated with.
   129  	server *rpcServer
   130  
   131  	// queueNotification queues a notification for handling.
   132  	queueNotification chan interface{}
   133  
   134  	// notificationMsgs feeds notificationHandler with notifications
   135  	// and client (un)registeration requests from a queue as well as
   136  	// registeration and unregisteration requests from clients.
   137  	notificationMsgs chan interface{}
   138  
   139  	// Access channel for current number of connected clients.
   140  	numClients chan int
   141  
   142  	// Shutdown handling
   143  	wg   sync.WaitGroup
   144  	quit chan struct{}
   145  }
   146  
   147  // queueHandler manages a queue of empty interfaces, reading from in and
   148  // sending the oldest unsent to out.  This handler stops when either of the
   149  // in or quit channels are closed, and closes out before returning, without
   150  // waiting to send any variables still remaining in the queue.
   151  func queueHandler(in <-chan interface{}, out chan<- interface{}, quit <-chan struct{}) {
   152  	var q []interface{}
   153  	var dequeue chan<- interface{}
   154  	skipQueue := out
   155  	var next interface{}
   156  out:
   157  	for {
   158  		select {
   159  		case n, ok := <-in:
   160  			if !ok {
   161  				// Sender closed input channel.
   162  				break out
   163  			}
   164  
   165  			// Either send to out immediately if skipQueue is
   166  			// non-nil (queue is empty) and reader is ready,
   167  			// or append to the queue and send later.
   168  			select {
   169  			case skipQueue <- n:
   170  			default:
   171  				q = append(q, n)
   172  				dequeue = out
   173  				skipQueue = nil
   174  				next = q[0]
   175  			}
   176  
   177  		case dequeue <- next:
   178  			copy(q, q[1:])
   179  			q[len(q)-1] = nil // avoid leak
   180  			q = q[:len(q)-1]
   181  			if len(q) == 0 {
   182  				dequeue = nil
   183  				skipQueue = out
   184  			} else {
   185  				next = q[0]
   186  			}
   187  
   188  		case <-quit:
   189  			break out
   190  		}
   191  	}
   192  	close(out)
   193  }
   194  
   195  // queueHandler maintains a queue of notifications and notification handler
   196  // control messages.
   197  func (m *wsNotificationManager) queueHandler() {
   198  	queueHandler(m.queueNotification, m.notificationMsgs, m.quit)
   199  	m.wg.Done()
   200  }
   201  
   202  // NotifyBlockConnected passes a block newly-connected to the best chain
   203  // to the notification manager for block and transaction notification
   204  // processing.
   205  func (m *wsNotificationManager) NotifyBlockConnected(block *palcutil.Block) {
   206  	// As NotifyBlockConnected will be called by the block manager
   207  	// and the RPC server may no longer be running, use a select
   208  	// statement to unblock enqueuing the notification once the RPC
   209  	// server has begun shutting down.
   210  	select {
   211  	case m.queueNotification <- (*notificationBlockConnected)(block):
   212  	case <-m.quit:
   213  	}
   214  }
   215  
   216  // NotifyBlockDisconnected passes a block disconnected from the best chain
   217  // to the notification manager for block notification processing.
   218  func (m *wsNotificationManager) NotifyBlockDisconnected(block *palcutil.Block) {
   219  	// As NotifyBlockDisconnected will be called by the block manager
   220  	// and the RPC server may no longer be running, use a select
   221  	// statement to unblock enqueuing the notification once the RPC
   222  	// server has begun shutting down.
   223  	select {
   224  	case m.queueNotification <- (*notificationBlockDisconnected)(block):
   225  	case <-m.quit:
   226  	}
   227  }
   228  
   229  // NotifyMempoolTx passes a transaction accepted by mempool to the
   230  // notification manager for transaction notification processing.  If
   231  // isNew is true, the tx is is a new transaction, rather than one
   232  // added to the mempool during a reorg.
   233  func (m *wsNotificationManager) NotifyMempoolTx(tx *palcutil.Tx, isNew bool) {
   234  	n := &notificationTxAcceptedByMempool{
   235  		isNew: isNew,
   236  		tx:    tx,
   237  	}
   238  
   239  	// As NotifyMempoolTx will be called by mempool and the RPC server
   240  	// may no longer be running, use a select statement to unblock
   241  	// enqueuing the notification once the RPC server has begun
   242  	// shutting down.
   243  	select {
   244  	case m.queueNotification <- n:
   245  	case <-m.quit:
   246  	}
   247  }
   248  
   249  // wsClientFilter tracks relevant addresses for each websocket client for
   250  // the `rescanblocks` extension. It is modified by the `loadtxfilter` command.
   251  //
   252  // NOTE: This extension was ported from github.com/decred/dcrd
   253  type wsClientFilter struct {
   254  	mu sync.Mutex
   255  
   256  	// Implemented fast paths for address lookup.
   257  	pubKeyHashes        map[[ripemd160.Size]byte]struct{}
   258  	scriptHashes        map[[ripemd160.Size]byte]struct{}
   259  	compressedPubKeys   map[[33]byte]struct{}
   260  	uncompressedPubKeys map[[65]byte]struct{}
   261  
   262  	// A fallback address lookup map in case a fast path doesn't exist.
   263  	// Only exists for completeness.  If using this shows up in a profile,
   264  	// there's a good chance a fast path should be added.
   265  	otherAddresses map[string]struct{}
   266  
   267  	// Outpoints of unspent outputs.
   268  	unspent map[wire.OutPoint]struct{}
   269  }
   270  
   271  // newWSClientFilter creates a new, empty wsClientFilter struct to be used
   272  // for a websocket client.
   273  //
   274  // NOTE: This extension was ported from github.com/decred/dcrd
   275  func newWSClientFilter(addresses []string, unspentOutPoints []wire.OutPoint, params *chaincfg.Params) *wsClientFilter {
   276  	filter := &wsClientFilter{
   277  		pubKeyHashes:        map[[ripemd160.Size]byte]struct{}{},
   278  		scriptHashes:        map[[ripemd160.Size]byte]struct{}{},
   279  		compressedPubKeys:   map[[33]byte]struct{}{},
   280  		uncompressedPubKeys: map[[65]byte]struct{}{},
   281  		otherAddresses:      map[string]struct{}{},
   282  		unspent:             make(map[wire.OutPoint]struct{}, len(unspentOutPoints)),
   283  	}
   284  
   285  	for _, s := range addresses {
   286  		filter.addAddressStr(s, params)
   287  	}
   288  	for i := range unspentOutPoints {
   289  		filter.addUnspentOutPoint(&unspentOutPoints[i])
   290  	}
   291  
   292  	return filter
   293  }
   294  
   295  // addAddress adds an address to a wsClientFilter, treating it correctly based
   296  // on the type of address passed as an argument.
   297  //
   298  // NOTE: This extension was ported from github.com/decred/dcrd
   299  func (f *wsClientFilter) addAddress(a palcutil.Address) {
   300  	switch a := a.(type) {
   301  	case *palcutil.AddressPubKeyHash:
   302  		f.pubKeyHashes[*a.Hash160()] = struct{}{}
   303  		return
   304  	case *palcutil.AddressScriptHash:
   305  		f.scriptHashes[*a.Hash160()] = struct{}{}
   306  		return
   307  	case *palcutil.AddressPubKey:
   308  		serializedPubKey := a.ScriptAddress()
   309  		switch len(serializedPubKey) {
   310  		case 33: // compressed
   311  			var compressedPubKey [33]byte
   312  			copy(compressedPubKey[:], serializedPubKey)
   313  			f.compressedPubKeys[compressedPubKey] = struct{}{}
   314  			return
   315  		case 65: // uncompressed
   316  			var uncompressedPubKey [65]byte
   317  			copy(uncompressedPubKey[:], serializedPubKey)
   318  			f.uncompressedPubKeys[uncompressedPubKey] = struct{}{}
   319  			return
   320  		}
   321  	}
   322  
   323  	f.otherAddresses[a.EncodeAddress()] = struct{}{}
   324  }
   325  
   326  // addAddressStr parses an address from a string and then adds it to the
   327  // wsClientFilter using addAddress.
   328  //
   329  // NOTE: This extension was ported from github.com/decred/dcrd
   330  func (f *wsClientFilter) addAddressStr(s string, params *chaincfg.Params) {
   331  	// If address can't be decoded, no point in saving it since it should also
   332  	// impossible to create the address from an inspected transaction output
   333  	// script.
   334  	a, err := palcutil.DecodeAddress(s, params)
   335  	if err != nil {
   336  		return
   337  	}
   338  	f.addAddress(a)
   339  }
   340  
   341  // existsAddress returns true if the passed address has been added to the
   342  // wsClientFilter.
   343  //
   344  // NOTE: This extension was ported from github.com/decred/dcrd
   345  func (f *wsClientFilter) existsAddress(a palcutil.Address) bool {
   346  	switch a := a.(type) {
   347  	case *palcutil.AddressPubKeyHash:
   348  		_, ok := f.pubKeyHashes[*a.Hash160()]
   349  		return ok
   350  	case *palcutil.AddressScriptHash:
   351  		_, ok := f.scriptHashes[*a.Hash160()]
   352  		return ok
   353  	case *palcutil.AddressPubKey:
   354  		serializedPubKey := a.ScriptAddress()
   355  		switch len(serializedPubKey) {
   356  		case 33: // compressed
   357  			var compressedPubKey [33]byte
   358  			copy(compressedPubKey[:], serializedPubKey)
   359  			_, ok := f.compressedPubKeys[compressedPubKey]
   360  			if !ok {
   361  				_, ok = f.pubKeyHashes[*a.AddressPubKeyHash().Hash160()]
   362  			}
   363  			return ok
   364  		case 65: // uncompressed
   365  			var uncompressedPubKey [65]byte
   366  			copy(uncompressedPubKey[:], serializedPubKey)
   367  			_, ok := f.uncompressedPubKeys[uncompressedPubKey]
   368  			if !ok {
   369  				_, ok = f.pubKeyHashes[*a.AddressPubKeyHash().Hash160()]
   370  			}
   371  			return ok
   372  		}
   373  	}
   374  
   375  	_, ok := f.otherAddresses[a.EncodeAddress()]
   376  	return ok
   377  }
   378  
   379  // removeAddress removes the passed address, if it exists, from the
   380  // wsClientFilter.
   381  //
   382  // NOTE: This extension was ported from github.com/decred/dcrd
   383  func (f *wsClientFilter) removeAddress(a palcutil.Address) {
   384  	switch a := a.(type) {
   385  	case *palcutil.AddressPubKeyHash:
   386  		delete(f.pubKeyHashes, *a.Hash160())
   387  		return
   388  	case *palcutil.AddressScriptHash:
   389  		delete(f.scriptHashes, *a.Hash160())
   390  		return
   391  	case *palcutil.AddressPubKey:
   392  		serializedPubKey := a.ScriptAddress()
   393  		switch len(serializedPubKey) {
   394  		case 33: // compressed
   395  			var compressedPubKey [33]byte
   396  			copy(compressedPubKey[:], serializedPubKey)
   397  			delete(f.compressedPubKeys, compressedPubKey)
   398  			return
   399  		case 65: // uncompressed
   400  			var uncompressedPubKey [65]byte
   401  			copy(uncompressedPubKey[:], serializedPubKey)
   402  			delete(f.uncompressedPubKeys, uncompressedPubKey)
   403  			return
   404  		}
   405  	}
   406  
   407  	delete(f.otherAddresses, a.EncodeAddress())
   408  }
   409  
   410  // removeAddressStr parses an address from a string and then removes it from the
   411  // wsClientFilter using removeAddress.
   412  //
   413  // NOTE: This extension was ported from github.com/decred/dcrd
   414  func (f *wsClientFilter) removeAddressStr(s string, params *chaincfg.Params) {
   415  	a, err := palcutil.DecodeAddress(s, params)
   416  	if err == nil {
   417  		f.removeAddress(a)
   418  	} else {
   419  		delete(f.otherAddresses, s)
   420  	}
   421  }
   422  
   423  // addUnspentOutPoint adds an outpoint to the wsClientFilter.
   424  //
   425  // NOTE: This extension was ported from github.com/decred/dcrd
   426  func (f *wsClientFilter) addUnspentOutPoint(op *wire.OutPoint) {
   427  	f.unspent[*op] = struct{}{}
   428  }
   429  
   430  // existsUnspentOutPoint returns true if the passed outpoint has been added to
   431  // the wsClientFilter.
   432  //
   433  // NOTE: This extension was ported from github.com/decred/dcrd
   434  func (f *wsClientFilter) existsUnspentOutPoint(op *wire.OutPoint) bool {
   435  	_, ok := f.unspent[*op]
   436  	return ok
   437  }
   438  
   439  // removeUnspentOutPoint removes the passed outpoint, if it exists, from the
   440  // wsClientFilter.
   441  //
   442  // NOTE: This extension was ported from github.com/decred/dcrd
   443  func (f *wsClientFilter) removeUnspentOutPoint(op *wire.OutPoint) {
   444  	delete(f.unspent, *op)
   445  }
   446  
   447  // Notification types
   448  type notificationBlockConnected palcutil.Block
   449  type notificationBlockDisconnected palcutil.Block
   450  type notificationTxAcceptedByMempool struct {
   451  	isNew bool
   452  	tx    *palcutil.Tx
   453  }
   454  
   455  // Notification control requests
   456  type notificationRegisterClient wsClient
   457  type notificationUnregisterClient wsClient
   458  type notificationRegisterBlocks wsClient
   459  type notificationUnregisterBlocks wsClient
   460  type notificationRegisterNewMempoolTxs wsClient
   461  type notificationUnregisterNewMempoolTxs wsClient
   462  type notificationRegisterSpent struct {
   463  	wsc *wsClient
   464  	ops []*wire.OutPoint
   465  }
   466  type notificationUnregisterSpent struct {
   467  	wsc *wsClient
   468  	op  *wire.OutPoint
   469  }
   470  type notificationRegisterAddr struct {
   471  	wsc   *wsClient
   472  	addrs []string
   473  }
   474  type notificationUnregisterAddr struct {
   475  	wsc  *wsClient
   476  	addr string
   477  }
   478  
   479  // notificationHandler reads notifications and control messages from the queue
   480  // handler and processes one at a time.
   481  func (m *wsNotificationManager) notificationHandler() {
   482  	// clients is a map of all currently connected websocket clients.
   483  	clients := make(map[chan struct{}]*wsClient)
   484  
   485  	// Maps used to hold lists of websocket clients to be notified on
   486  	// certain events.  Each websocket client also keeps maps for the events
   487  	// which have multiple triggers to make removal from these lists on
   488  	// connection close less horrendously expensive.
   489  	//
   490  	// Where possible, the quit channel is used as the unique id for a client
   491  	// since it is quite a bit more efficient than using the entire struct.
   492  	blockNotifications := make(map[chan struct{}]*wsClient)
   493  	txNotifications := make(map[chan struct{}]*wsClient)
   494  	watchedOutPoints := make(map[wire.OutPoint]map[chan struct{}]*wsClient)
   495  	watchedAddrs := make(map[string]map[chan struct{}]*wsClient)
   496  
   497  out:
   498  	for {
   499  		select {
   500  		case n, ok := <-m.notificationMsgs:
   501  			if !ok {
   502  				// queueHandler quit.
   503  				break out
   504  			}
   505  			switch n := n.(type) {
   506  			case *notificationBlockConnected:
   507  				block := (*palcutil.Block)(n)
   508  
   509  				// Skip iterating through all txs if no
   510  				// tx notification requests exist.
   511  				if len(watchedOutPoints) != 0 || len(watchedAddrs) != 0 {
   512  					for _, tx := range block.Transactions() {
   513  						m.notifyForTx(watchedOutPoints,
   514  							watchedAddrs, tx, block)
   515  					}
   516  				}
   517  
   518  				if len(blockNotifications) != 0 {
   519  					m.notifyBlockConnected(blockNotifications,
   520  						block)
   521  					m.notifyFilteredBlockConnected(blockNotifications,
   522  						block)
   523  				}
   524  
   525  			case *notificationBlockDisconnected:
   526  				block := (*palcutil.Block)(n)
   527  
   528  				if len(blockNotifications) != 0 {
   529  					m.notifyBlockDisconnected(blockNotifications,
   530  						block)
   531  					m.notifyFilteredBlockDisconnected(blockNotifications,
   532  						block)
   533  				}
   534  
   535  			case *notificationTxAcceptedByMempool:
   536  				if n.isNew && len(txNotifications) != 0 {
   537  					m.notifyForNewTx(txNotifications, n.tx)
   538  				}
   539  				m.notifyForTx(watchedOutPoints, watchedAddrs, n.tx, nil)
   540  				m.notifyRelevantTxAccepted(n.tx, clients)
   541  
   542  			case *notificationRegisterBlocks:
   543  				wsc := (*wsClient)(n)
   544  				blockNotifications[wsc.quit] = wsc
   545  
   546  			case *notificationUnregisterBlocks:
   547  				wsc := (*wsClient)(n)
   548  				delete(blockNotifications, wsc.quit)
   549  
   550  			case *notificationRegisterClient:
   551  				wsc := (*wsClient)(n)
   552  				clients[wsc.quit] = wsc
   553  
   554  			case *notificationUnregisterClient:
   555  				wsc := (*wsClient)(n)
   556  				// Remove any requests made by the client as well as
   557  				// the client itself.
   558  				delete(blockNotifications, wsc.quit)
   559  				delete(txNotifications, wsc.quit)
   560  				for k := range wsc.spentRequests {
   561  					op := k
   562  					m.removeSpentRequest(watchedOutPoints, wsc, &op)
   563  				}
   564  				for addr := range wsc.addrRequests {
   565  					m.removeAddrRequest(watchedAddrs, wsc, addr)
   566  				}
   567  				delete(clients, wsc.quit)
   568  
   569  			case *notificationRegisterSpent:
   570  				m.addSpentRequests(watchedOutPoints, n.wsc, n.ops)
   571  
   572  			case *notificationUnregisterSpent:
   573  				m.removeSpentRequest(watchedOutPoints, n.wsc, n.op)
   574  
   575  			case *notificationRegisterAddr:
   576  				m.addAddrRequests(watchedAddrs, n.wsc, n.addrs)
   577  
   578  			case *notificationUnregisterAddr:
   579  				m.removeAddrRequest(watchedAddrs, n.wsc, n.addr)
   580  
   581  			case *notificationRegisterNewMempoolTxs:
   582  				wsc := (*wsClient)(n)
   583  				txNotifications[wsc.quit] = wsc
   584  
   585  			case *notificationUnregisterNewMempoolTxs:
   586  				wsc := (*wsClient)(n)
   587  				delete(txNotifications, wsc.quit)
   588  
   589  			default:
   590  				rpcsLog.Warn("Unhandled notification type")
   591  			}
   592  
   593  		case m.numClients <- len(clients):
   594  
   595  		case <-m.quit:
   596  			// RPC server shutting down.
   597  			break out
   598  		}
   599  	}
   600  
   601  	for _, c := range clients {
   602  		c.Disconnect()
   603  	}
   604  	m.wg.Done()
   605  }
   606  
   607  // NumClients returns the number of clients actively being served.
   608  func (m *wsNotificationManager) NumClients() (n int) {
   609  	select {
   610  	case n = <-m.numClients:
   611  	case <-m.quit: // Use default n (0) if server has shut down.
   612  	}
   613  	return
   614  }
   615  
   616  // RegisterBlockUpdates requests block update notifications to the passed
   617  // websocket client.
   618  func (m *wsNotificationManager) RegisterBlockUpdates(wsc *wsClient) {
   619  	m.queueNotification <- (*notificationRegisterBlocks)(wsc)
   620  }
   621  
   622  // UnregisterBlockUpdates removes block update notifications for the passed
   623  // websocket client.
   624  func (m *wsNotificationManager) UnregisterBlockUpdates(wsc *wsClient) {
   625  	m.queueNotification <- (*notificationUnregisterBlocks)(wsc)
   626  }
   627  
   628  // subscribedClients returns the set of all websocket client quit channels that
   629  // are registered to receive notifications regarding tx, either due to tx
   630  // spending a watched output or outputting to a watched address.  Matching
   631  // client's filters are updated based on this transaction's outputs and output
   632  // addresses that may be relevant for a client.
   633  func (m *wsNotificationManager) subscribedClients(tx *palcutil.Tx,
   634  	clients map[chan struct{}]*wsClient) map[chan struct{}]struct{} {
   635  
   636  	// Use a map of client quit channels as keys to prevent duplicates when
   637  	// multiple inputs and/or outputs are relevant to the client.
   638  	subscribed := make(map[chan struct{}]struct{})
   639  
   640  	msgTx := tx.MsgTx()
   641  	for _, input := range msgTx.TxIn {
   642  		for quitChan, wsc := range clients {
   643  			wsc.Lock()
   644  			filter := wsc.filterData
   645  			wsc.Unlock()
   646  			if filter == nil {
   647  				continue
   648  			}
   649  			filter.mu.Lock()
   650  			if filter.existsUnspentOutPoint(&input.PreviousOutPoint) {
   651  				subscribed[quitChan] = struct{}{}
   652  			}
   653  			filter.mu.Unlock()
   654  		}
   655  	}
   656  
   657  	for i, output := range msgTx.TxOut {
   658  		_, addrs, _, err := txscript.ExtractPkScriptAddrs(
   659  			output.PkScript, m.server.cfg.ChainParams)
   660  		if err != nil {
   661  			// Clients are not able to subscribe to
   662  			// nonstandard or non-address outputs.
   663  			continue
   664  		}
   665  		for quitChan, wsc := range clients {
   666  			wsc.Lock()
   667  			filter := wsc.filterData
   668  			wsc.Unlock()
   669  			if filter == nil {
   670  				continue
   671  			}
   672  			filter.mu.Lock()
   673  			for _, a := range addrs {
   674  				if filter.existsAddress(a) {
   675  					subscribed[quitChan] = struct{}{}
   676  					op := wire.OutPoint{
   677  						Hash:  *tx.Hash(),
   678  						Index: uint32(i),
   679  					}
   680  					filter.addUnspentOutPoint(&op)
   681  				}
   682  			}
   683  			filter.mu.Unlock()
   684  		}
   685  	}
   686  
   687  	return subscribed
   688  }
   689  
   690  // notifyBlockConnected notifies websocket clients that have registered for
   691  // block updates when a block is connected to the main chain.
   692  func (*wsNotificationManager) notifyBlockConnected(clients map[chan struct{}]*wsClient,
   693  	block *palcutil.Block) {
   694  
   695  	// Notify interested websocket clients about the connected block.
   696  	ntfn := btcjson.NewBlockConnectedNtfn(block.Hash().String(), block.Height(),
   697  		block.MsgBlock().Header.Timestamp.Unix())
   698  	marshalledJSON, err := btcjson.MarshalCmd(btcjson.RpcVersion1, nil, ntfn)
   699  	if err != nil {
   700  		rpcsLog.Errorf("Failed to marshal block connected notification: "+
   701  			"%v", err)
   702  		return
   703  	}
   704  	for _, wsc := range clients {
   705  		wsc.QueueNotification(marshalledJSON)
   706  	}
   707  }
   708  
   709  // notifyBlockDisconnected notifies websocket clients that have registered for
   710  // block updates when a block is disconnected from the main chain (due to a
   711  // reorganize).
   712  func (*wsNotificationManager) notifyBlockDisconnected(clients map[chan struct{}]*wsClient, block *palcutil.Block) {
   713  	// Skip notification creation if no clients have requested block
   714  	// connected/disconnected notifications.
   715  	if len(clients) == 0 {
   716  		return
   717  	}
   718  
   719  	// Notify interested websocket clients about the disconnected block.
   720  	ntfn := btcjson.NewBlockDisconnectedNtfn(block.Hash().String(),
   721  		block.Height(), block.MsgBlock().Header.Timestamp.Unix())
   722  	marshalledJSON, err := btcjson.MarshalCmd(btcjson.RpcVersion1, nil, ntfn)
   723  	if err != nil {
   724  		rpcsLog.Errorf("Failed to marshal block disconnected "+
   725  			"notification: %v", err)
   726  		return
   727  	}
   728  	for _, wsc := range clients {
   729  		wsc.QueueNotification(marshalledJSON)
   730  	}
   731  }
   732  
   733  // notifyFilteredBlockConnected notifies websocket clients that have registered for
   734  // block updates when a block is connected to the main chain.
   735  func (m *wsNotificationManager) notifyFilteredBlockConnected(clients map[chan struct{}]*wsClient,
   736  	block *palcutil.Block) {
   737  
   738  	// Create the common portion of the notification that is the same for
   739  	// every client.
   740  	var w bytes.Buffer
   741  	err := block.MsgBlock().Header.Serialize(&w)
   742  	if err != nil {
   743  		rpcsLog.Errorf("Failed to serialize header for filtered block "+
   744  			"connected notification: %v", err)
   745  		return
   746  	}
   747  	ntfn := btcjson.NewFilteredBlockConnectedNtfn(block.Height(),
   748  		hex.EncodeToString(w.Bytes()), nil)
   749  
   750  	// Search for relevant transactions for each client and save them
   751  	// serialized in hex encoding for the notification.
   752  	subscribedTxs := make(map[chan struct{}][]string)
   753  	for _, tx := range block.Transactions() {
   754  		var txHex string
   755  		for quitChan := range m.subscribedClients(tx, clients) {
   756  			if txHex == "" {
   757  				txHex = txHexString(tx.MsgTx())
   758  			}
   759  			subscribedTxs[quitChan] = append(subscribedTxs[quitChan], txHex)
   760  		}
   761  	}
   762  	for quitChan, wsc := range clients {
   763  		// Add all discovered transactions for this client. For clients
   764  		// that have no new-style filter, add the empty string slice.
   765  		ntfn.SubscribedTxs = subscribedTxs[quitChan]
   766  
   767  		// Marshal and queue notification.
   768  		marshalledJSON, err := btcjson.MarshalCmd(btcjson.RpcVersion1, nil, ntfn)
   769  		if err != nil {
   770  			rpcsLog.Errorf("Failed to marshal filtered block "+
   771  				"connected notification: %v", err)
   772  			return
   773  		}
   774  		wsc.QueueNotification(marshalledJSON)
   775  	}
   776  }
   777  
   778  // notifyFilteredBlockDisconnected notifies websocket clients that have registered for
   779  // block updates when a block is disconnected from the main chain (due to a
   780  // reorganize).
   781  func (*wsNotificationManager) notifyFilteredBlockDisconnected(clients map[chan struct{}]*wsClient,
   782  	block *palcutil.Block) {
   783  	// Skip notification creation if no clients have requested block
   784  	// connected/disconnected notifications.
   785  	if len(clients) == 0 {
   786  		return
   787  	}
   788  
   789  	// Notify interested websocket clients about the disconnected block.
   790  	var w bytes.Buffer
   791  	err := block.MsgBlock().Header.Serialize(&w)
   792  	if err != nil {
   793  		rpcsLog.Errorf("Failed to serialize header for filtered block "+
   794  			"disconnected notification: %v", err)
   795  		return
   796  	}
   797  	ntfn := btcjson.NewFilteredBlockDisconnectedNtfn(block.Height(),
   798  		hex.EncodeToString(w.Bytes()))
   799  	marshalledJSON, err := btcjson.MarshalCmd(btcjson.RpcVersion1, nil, ntfn)
   800  	if err != nil {
   801  		rpcsLog.Errorf("Failed to marshal filtered block disconnected "+
   802  			"notification: %v", err)
   803  		return
   804  	}
   805  	for _, wsc := range clients {
   806  		wsc.QueueNotification(marshalledJSON)
   807  	}
   808  }
   809  
   810  // RegisterNewMempoolTxsUpdates requests notifications to the passed websocket
   811  // client when new transactions are added to the memory pool.
   812  func (m *wsNotificationManager) RegisterNewMempoolTxsUpdates(wsc *wsClient) {
   813  	m.queueNotification <- (*notificationRegisterNewMempoolTxs)(wsc)
   814  }
   815  
   816  // UnregisterNewMempoolTxsUpdates removes notifications to the passed websocket
   817  // client when new transaction are added to the memory pool.
   818  func (m *wsNotificationManager) UnregisterNewMempoolTxsUpdates(wsc *wsClient) {
   819  	m.queueNotification <- (*notificationUnregisterNewMempoolTxs)(wsc)
   820  }
   821  
   822  // notifyForNewTx notifies websocket clients that have registered for updates
   823  // when a new transaction is added to the memory pool.
   824  func (m *wsNotificationManager) notifyForNewTx(clients map[chan struct{}]*wsClient, tx *palcutil.Tx) {
   825  	txHashStr := tx.Hash().String()
   826  	mtx := tx.MsgTx()
   827  
   828  	var amount int64
   829  	for _, txOut := range mtx.TxOut {
   830  		amount += txOut.Value
   831  	}
   832  
   833  	ntfn := btcjson.NewTxAcceptedNtfn(txHashStr, palcutil.Amount(amount).ToBTC())
   834  	marshalledJSON, err := btcjson.MarshalCmd(btcjson.RpcVersion1, nil, ntfn)
   835  	if err != nil {
   836  		rpcsLog.Errorf("Failed to marshal tx notification: %s", err.Error())
   837  		return
   838  	}
   839  
   840  	var verboseNtfn *btcjson.TxAcceptedVerboseNtfn
   841  	var marshalledJSONVerbose []byte
   842  	for _, wsc := range clients {
   843  		if wsc.verboseTxUpdates {
   844  			if marshalledJSONVerbose != nil {
   845  				wsc.QueueNotification(marshalledJSONVerbose)
   846  				continue
   847  			}
   848  
   849  			net := m.server.cfg.ChainParams
   850  			rawTx, err := createTxRawResult(net, mtx, txHashStr, nil,
   851  				"", 0, 0)
   852  			if err != nil {
   853  				return
   854  			}
   855  
   856  			verboseNtfn = btcjson.NewTxAcceptedVerboseNtfn(*rawTx)
   857  			marshalledJSONVerbose, err = btcjson.MarshalCmd(btcjson.RpcVersion1, nil,
   858  				verboseNtfn)
   859  			if err != nil {
   860  				rpcsLog.Errorf("Failed to marshal verbose tx "+
   861  					"notification: %s", err.Error())
   862  				return
   863  			}
   864  			wsc.QueueNotification(marshalledJSONVerbose)
   865  		} else {
   866  			wsc.QueueNotification(marshalledJSON)
   867  		}
   868  	}
   869  }
   870  
   871  // RegisterSpentRequests requests a notification when each of the passed
   872  // outpoints is confirmed spent (contained in a block connected to the main
   873  // chain) for the passed websocket client.  The request is automatically
   874  // removed once the notification has been sent.
   875  func (m *wsNotificationManager) RegisterSpentRequests(wsc *wsClient, ops []*wire.OutPoint) {
   876  	m.queueNotification <- &notificationRegisterSpent{
   877  		wsc: wsc,
   878  		ops: ops,
   879  	}
   880  }
   881  
   882  // addSpentRequests modifies a map of watched outpoints to sets of websocket
   883  // clients to add a new request watch all of the outpoints in ops and create
   884  // and send a notification when spent to the websocket client wsc.
   885  func (m *wsNotificationManager) addSpentRequests(opMap map[wire.OutPoint]map[chan struct{}]*wsClient,
   886  	wsc *wsClient, ops []*wire.OutPoint) {
   887  
   888  	for _, op := range ops {
   889  		// Track the request in the client as well so it can be quickly
   890  		// be removed on disconnect.
   891  		wsc.spentRequests[*op] = struct{}{}
   892  
   893  		// Add the client to the list to notify when the outpoint is seen.
   894  		// Create the list as needed.
   895  		cmap, ok := opMap[*op]
   896  		if !ok {
   897  			cmap = make(map[chan struct{}]*wsClient)
   898  			opMap[*op] = cmap
   899  		}
   900  		cmap[wsc.quit] = wsc
   901  	}
   902  
   903  	// Check if any transactions spending these outputs already exists in
   904  	// the mempool, if so send the notification immediately.
   905  	spends := make(map[chainhash.Hash]*palcutil.Tx)
   906  	for _, op := range ops {
   907  		spend := m.server.cfg.TxMemPool.CheckSpend(*op)
   908  		if spend != nil {
   909  			rpcsLog.Debugf("Found existing mempool spend for "+
   910  				"outpoint<%v>: %v", op, spend.Hash())
   911  			spends[*spend.Hash()] = spend
   912  		}
   913  	}
   914  
   915  	for _, spend := range spends {
   916  		m.notifyForTx(opMap, nil, spend, nil)
   917  	}
   918  }
   919  
   920  // UnregisterSpentRequest removes a request from the passed websocket client
   921  // to be notified when the passed outpoint is confirmed spent (contained in a
   922  // block connected to the main chain).
   923  func (m *wsNotificationManager) UnregisterSpentRequest(wsc *wsClient, op *wire.OutPoint) {
   924  	m.queueNotification <- &notificationUnregisterSpent{
   925  		wsc: wsc,
   926  		op:  op,
   927  	}
   928  }
   929  
   930  // removeSpentRequest modifies a map of watched outpoints to remove the
   931  // websocket client wsc from the set of clients to be notified when a
   932  // watched outpoint is spent.  If wsc is the last client, the outpoint
   933  // key is removed from the map.
   934  func (*wsNotificationManager) removeSpentRequest(ops map[wire.OutPoint]map[chan struct{}]*wsClient,
   935  	wsc *wsClient, op *wire.OutPoint) {
   936  
   937  	// Remove the request tracking from the client.
   938  	delete(wsc.spentRequests, *op)
   939  
   940  	// Remove the client from the list to notify.
   941  	notifyMap, ok := ops[*op]
   942  	if !ok {
   943  		rpcsLog.Warnf("Attempt to remove nonexistent spent request "+
   944  			"for websocket client %s", wsc.addr)
   945  		return
   946  	}
   947  	delete(notifyMap, wsc.quit)
   948  
   949  	// Remove the map entry altogether if there are
   950  	// no more clients interested in it.
   951  	if len(notifyMap) == 0 {
   952  		delete(ops, *op)
   953  	}
   954  }
   955  
   956  // txHexString returns the serialized transaction encoded in hexadecimal.
   957  func txHexString(tx *wire.MsgTx) string {
   958  	buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize()))
   959  	// Ignore Serialize's error, as writing to a bytes.buffer cannot fail.
   960  	tx.Serialize(buf)
   961  	return hex.EncodeToString(buf.Bytes())
   962  }
   963  
   964  // blockDetails creates a BlockDetails struct to include in btcws notifications
   965  // from a block and a transaction's block index.
   966  func blockDetails(block *palcutil.Block, txIndex int) *btcjson.BlockDetails {
   967  	if block == nil {
   968  		return nil
   969  	}
   970  	return &btcjson.BlockDetails{
   971  		Height: block.Height(),
   972  		Hash:   block.Hash().String(),
   973  		Index:  txIndex,
   974  		Time:   block.MsgBlock().Header.Timestamp.Unix(),
   975  	}
   976  }
   977  
   978  // newRedeemingTxNotification returns a new marshalled redeemingtx notification
   979  // with the passed parameters.
   980  func newRedeemingTxNotification(txHex string, index int, block *palcutil.Block) ([]byte, error) {
   981  	// Create and marshal the notification.
   982  	ntfn := btcjson.NewRedeemingTxNtfn(txHex, blockDetails(block, index))
   983  	return btcjson.MarshalCmd(btcjson.RpcVersion1, nil, ntfn)
   984  }
   985  
   986  // notifyForTxOuts examines each transaction output, notifying interested
   987  // websocket clients of the transaction if an output spends to a watched
   988  // address.  A spent notification request is automatically registered for
   989  // the client for each matching output.
   990  func (m *wsNotificationManager) notifyForTxOuts(ops map[wire.OutPoint]map[chan struct{}]*wsClient,
   991  	addrs map[string]map[chan struct{}]*wsClient, tx *palcutil.Tx, block *palcutil.Block) {
   992  
   993  	// Nothing to do if nobody is listening for address notifications.
   994  	if len(addrs) == 0 {
   995  		return
   996  	}
   997  
   998  	txHex := ""
   999  	wscNotified := make(map[chan struct{}]struct{})
  1000  	for i, txOut := range tx.MsgTx().TxOut {
  1001  		_, txAddrs, _, err := txscript.ExtractPkScriptAddrs(
  1002  			txOut.PkScript, m.server.cfg.ChainParams)
  1003  		if err != nil {
  1004  			continue
  1005  		}
  1006  
  1007  		for _, txAddr := range txAddrs {
  1008  			cmap, ok := addrs[txAddr.EncodeAddress()]
  1009  			if !ok {
  1010  				continue
  1011  			}
  1012  
  1013  			if txHex == "" {
  1014  				txHex = txHexString(tx.MsgTx())
  1015  			}
  1016  			ntfn := btcjson.NewRecvTxNtfn(txHex, blockDetails(block,
  1017  				tx.Index()))
  1018  
  1019  			marshalledJSON, err := btcjson.MarshalCmd(btcjson.RpcVersion1, nil, ntfn)
  1020  			if err != nil {
  1021  				rpcsLog.Errorf("Failed to marshal processedtx notification: %v", err)
  1022  				continue
  1023  			}
  1024  
  1025  			op := []*wire.OutPoint{wire.NewOutPoint(tx.Hash(), uint32(i))}
  1026  			for wscQuit, wsc := range cmap {
  1027  				m.addSpentRequests(ops, wsc, op)
  1028  
  1029  				if _, ok := wscNotified[wscQuit]; !ok {
  1030  					wscNotified[wscQuit] = struct{}{}
  1031  					wsc.QueueNotification(marshalledJSON)
  1032  				}
  1033  			}
  1034  		}
  1035  	}
  1036  }
  1037  
  1038  // notifyRelevantTxAccepted examines the inputs and outputs of the passed
  1039  // transaction, notifying websocket clients of outputs spending to a watched
  1040  // address and inputs spending a watched outpoint.  Any outputs paying to a
  1041  // watched address result in the output being watched as well for future
  1042  // notifications.
  1043  func (m *wsNotificationManager) notifyRelevantTxAccepted(tx *palcutil.Tx,
  1044  	clients map[chan struct{}]*wsClient) {
  1045  
  1046  	clientsToNotify := m.subscribedClients(tx, clients)
  1047  
  1048  	if len(clientsToNotify) != 0 {
  1049  		n := btcjson.NewRelevantTxAcceptedNtfn(txHexString(tx.MsgTx()))
  1050  		marshalled, err := btcjson.MarshalCmd(btcjson.RpcVersion1, nil, n)
  1051  		if err != nil {
  1052  			rpcsLog.Errorf("Failed to marshal notification: %v", err)
  1053  			return
  1054  		}
  1055  		for quitChan := range clientsToNotify {
  1056  			clients[quitChan].QueueNotification(marshalled)
  1057  		}
  1058  	}
  1059  }
  1060  
  1061  // notifyForTx examines the inputs and outputs of the passed transaction,
  1062  // notifying websocket clients of outputs spending to a watched address
  1063  // and inputs spending a watched outpoint.
  1064  func (m *wsNotificationManager) notifyForTx(ops map[wire.OutPoint]map[chan struct{}]*wsClient,
  1065  	addrs map[string]map[chan struct{}]*wsClient, tx *palcutil.Tx, block *palcutil.Block) {
  1066  
  1067  	if len(ops) != 0 {
  1068  		m.notifyForTxIns(ops, tx, block)
  1069  	}
  1070  	if len(addrs) != 0 {
  1071  		m.notifyForTxOuts(ops, addrs, tx, block)
  1072  	}
  1073  }
  1074  
  1075  // notifyForTxIns examines the inputs of the passed transaction and sends
  1076  // interested websocket clients a redeemingtx notification if any inputs
  1077  // spend a watched output.  If block is non-nil, any matching spent
  1078  // requests are removed.
  1079  func (m *wsNotificationManager) notifyForTxIns(ops map[wire.OutPoint]map[chan struct{}]*wsClient,
  1080  	tx *palcutil.Tx, block *palcutil.Block) {
  1081  
  1082  	// Nothing to do if nobody is watching outpoints.
  1083  	if len(ops) == 0 {
  1084  		return
  1085  	}
  1086  
  1087  	txHex := ""
  1088  	wscNotified := make(map[chan struct{}]struct{})
  1089  	for _, txIn := range tx.MsgTx().TxIn {
  1090  		prevOut := &txIn.PreviousOutPoint
  1091  		if cmap, ok := ops[*prevOut]; ok {
  1092  			if txHex == "" {
  1093  				txHex = txHexString(tx.MsgTx())
  1094  			}
  1095  			marshalledJSON, err := newRedeemingTxNotification(txHex, tx.Index(), block)
  1096  			if err != nil {
  1097  				rpcsLog.Warnf("Failed to marshal redeemingtx notification: %v", err)
  1098  				continue
  1099  			}
  1100  			for wscQuit, wsc := range cmap {
  1101  				if block != nil {
  1102  					m.removeSpentRequest(ops, wsc, prevOut)
  1103  				}
  1104  
  1105  				if _, ok := wscNotified[wscQuit]; !ok {
  1106  					wscNotified[wscQuit] = struct{}{}
  1107  					wsc.QueueNotification(marshalledJSON)
  1108  				}
  1109  			}
  1110  		}
  1111  	}
  1112  }
  1113  
  1114  // RegisterTxOutAddressRequests requests notifications to the passed websocket
  1115  // client when a transaction output spends to the passed address.
  1116  func (m *wsNotificationManager) RegisterTxOutAddressRequests(wsc *wsClient, addrs []string) {
  1117  	m.queueNotification <- &notificationRegisterAddr{
  1118  		wsc:   wsc,
  1119  		addrs: addrs,
  1120  	}
  1121  }
  1122  
  1123  // addAddrRequests adds the websocket client wsc to the address to client set
  1124  // addrMap so wsc will be notified for any mempool or block transaction outputs
  1125  // spending to any of the addresses in addrs.
  1126  func (*wsNotificationManager) addAddrRequests(addrMap map[string]map[chan struct{}]*wsClient,
  1127  	wsc *wsClient, addrs []string) {
  1128  
  1129  	for _, addr := range addrs {
  1130  		// Track the request in the client as well so it can be quickly be
  1131  		// removed on disconnect.
  1132  		wsc.addrRequests[addr] = struct{}{}
  1133  
  1134  		// Add the client to the set of clients to notify when the
  1135  		// outpoint is seen.  Create map as needed.
  1136  		cmap, ok := addrMap[addr]
  1137  		if !ok {
  1138  			cmap = make(map[chan struct{}]*wsClient)
  1139  			addrMap[addr] = cmap
  1140  		}
  1141  		cmap[wsc.quit] = wsc
  1142  	}
  1143  }
  1144  
  1145  // UnregisterTxOutAddressRequest removes a request from the passed websocket
  1146  // client to be notified when a transaction spends to the passed address.
  1147  func (m *wsNotificationManager) UnregisterTxOutAddressRequest(wsc *wsClient, addr string) {
  1148  	m.queueNotification <- &notificationUnregisterAddr{
  1149  		wsc:  wsc,
  1150  		addr: addr,
  1151  	}
  1152  }
  1153  
  1154  // removeAddrRequest removes the websocket client wsc from the address to
  1155  // client set addrs so it will no longer receive notification updates for
  1156  // any transaction outputs send to addr.
  1157  func (*wsNotificationManager) removeAddrRequest(addrs map[string]map[chan struct{}]*wsClient,
  1158  	wsc *wsClient, addr string) {
  1159  
  1160  	// Remove the request tracking from the client.
  1161  	delete(wsc.addrRequests, addr)
  1162  
  1163  	// Remove the client from the list to notify.
  1164  	cmap, ok := addrs[addr]
  1165  	if !ok {
  1166  		rpcsLog.Warnf("Attempt to remove nonexistent addr request "+
  1167  			"<%s> for websocket client %s", addr, wsc.addr)
  1168  		return
  1169  	}
  1170  	delete(cmap, wsc.quit)
  1171  
  1172  	// Remove the map entry altogether if there are no more clients
  1173  	// interested in it.
  1174  	if len(cmap) == 0 {
  1175  		delete(addrs, addr)
  1176  	}
  1177  }
  1178  
  1179  // AddClient adds the passed websocket client to the notification manager.
  1180  func (m *wsNotificationManager) AddClient(wsc *wsClient) {
  1181  	m.queueNotification <- (*notificationRegisterClient)(wsc)
  1182  }
  1183  
  1184  // RemoveClient removes the passed websocket client and all notifications
  1185  // registered for it.
  1186  func (m *wsNotificationManager) RemoveClient(wsc *wsClient) {
  1187  	select {
  1188  	case m.queueNotification <- (*notificationUnregisterClient)(wsc):
  1189  	case <-m.quit:
  1190  	}
  1191  }
  1192  
  1193  // Start starts the goroutines required for the manager to queue and process
  1194  // websocket client notifications.
  1195  func (m *wsNotificationManager) Start() {
  1196  	m.wg.Add(2)
  1197  	go m.queueHandler()
  1198  	go m.notificationHandler()
  1199  }
  1200  
  1201  // WaitForShutdown blocks until all notification manager goroutines have
  1202  // finished.
  1203  func (m *wsNotificationManager) WaitForShutdown() {
  1204  	m.wg.Wait()
  1205  }
  1206  
  1207  // Shutdown shuts down the manager, stopping the notification queue and
  1208  // notification handler goroutines.
  1209  func (m *wsNotificationManager) Shutdown() {
  1210  	close(m.quit)
  1211  }
  1212  
  1213  // newWsNotificationManager returns a new notification manager ready for use.
  1214  // See wsNotificationManager for more details.
  1215  func newWsNotificationManager(server *rpcServer) *wsNotificationManager {
  1216  	return &wsNotificationManager{
  1217  		server:            server,
  1218  		queueNotification: make(chan interface{}),
  1219  		notificationMsgs:  make(chan interface{}),
  1220  		numClients:        make(chan int),
  1221  		quit:              make(chan struct{}),
  1222  	}
  1223  }
  1224  
  1225  // wsResponse houses a message to send to a connected websocket client as
  1226  // well as a channel to reply on when the message is sent.
  1227  type wsResponse struct {
  1228  	msg      []byte
  1229  	doneChan chan bool
  1230  }
  1231  
  1232  // wsClient provides an abstraction for handling a websocket client.  The
  1233  // overall data flow is split into 3 main goroutines, a possible 4th goroutine
  1234  // for long-running operations (only started if request is made), and a
  1235  // websocket manager which is used to allow things such as broadcasting
  1236  // requested notifications to all connected websocket clients.   Inbound
  1237  // messages are read via the inHandler goroutine and generally dispatched to
  1238  // their own handler.  However, certain potentially long-running operations such
  1239  // as rescans, are sent to the asyncHander goroutine and are limited to one at a
  1240  // time.  There are two outbound message types - one for responding to client
  1241  // requests and another for async notifications.  Responses to client requests
  1242  // use SendMessage which employs a buffered channel thereby limiting the number
  1243  // of outstanding requests that can be made.  Notifications are sent via
  1244  // QueueNotification which implements a queue via notificationQueueHandler to
  1245  // ensure sending notifications from other subsystems can't block.  Ultimately,
  1246  // all messages are sent via the outHandler.
  1247  type wsClient struct {
  1248  	sync.Mutex
  1249  
  1250  	// server is the RPC server that is servicing the client.
  1251  	server *rpcServer
  1252  
  1253  	// conn is the underlying websocket connection.
  1254  	conn *websocket.Conn
  1255  
  1256  	// disconnected indicated whether or not the websocket client is
  1257  	// disconnected.
  1258  	disconnected bool
  1259  
  1260  	// addr is the remote address of the client.
  1261  	addr string
  1262  
  1263  	// authenticated specifies whether a client has been authenticated
  1264  	// and therefore is allowed to communicated over the websocket.
  1265  	authenticated bool
  1266  
  1267  	// isAdmin specifies whether a client may change the state of the server;
  1268  	// false means its access is only to the limited set of RPC calls.
  1269  	isAdmin bool
  1270  
  1271  	// sessionID is a random ID generated for each client when connected.
  1272  	// These IDs may be queried by a client using the session RPC.  A change
  1273  	// to the session ID indicates that the client reconnected.
  1274  	sessionID uint64
  1275  
  1276  	// verboseTxUpdates specifies whether a client has requested verbose
  1277  	// information about all new transactions.
  1278  	verboseTxUpdates bool
  1279  
  1280  	// addrRequests is a set of addresses the caller has requested to be
  1281  	// notified about.  It is maintained here so all requests can be removed
  1282  	// when a wallet disconnects.  Owned by the notification manager.
  1283  	addrRequests map[string]struct{}
  1284  
  1285  	// spentRequests is a set of unspent Outpoints a wallet has requested
  1286  	// notifications for when they are spent by a processed transaction.
  1287  	// Owned by the notification manager.
  1288  	spentRequests map[wire.OutPoint]struct{}
  1289  
  1290  	// filterData is the new generation transaction filter backported from
  1291  	// github.com/decred/dcrd for the new backported `loadtxfilter` and
  1292  	// `rescanblocks` methods.
  1293  	filterData *wsClientFilter
  1294  
  1295  	// Networking infrastructure.
  1296  	serviceRequestSem semaphore
  1297  	ntfnChan          chan []byte
  1298  	sendChan          chan wsResponse
  1299  	quit              chan struct{}
  1300  	wg                sync.WaitGroup
  1301  }
  1302  
  1303  // inHandler handles all incoming messages for the websocket connection.  It
  1304  // must be run as a goroutine.
  1305  func (c *wsClient) inHandler() {
  1306  out:
  1307  	for {
  1308  		// Break out of the loop once the quit channel has been closed.
  1309  		// Use a non-blocking select here so we fall through otherwise.
  1310  		select {
  1311  		case <-c.quit:
  1312  			break out
  1313  		default:
  1314  		}
  1315  
  1316  		_, msg, err := c.conn.ReadMessage()
  1317  		if err != nil {
  1318  			// Log the error if it's not due to disconnecting.
  1319  			if err != io.EOF {
  1320  				rpcsLog.Errorf("Websocket receive error from "+
  1321  					"%s: %v", c.addr, err)
  1322  			}
  1323  			break out
  1324  		}
  1325  
  1326  		var batchedRequest bool
  1327  
  1328  		// Determine request type
  1329  		if bytes.HasPrefix(msg, batchedRequestPrefix) {
  1330  			batchedRequest = true
  1331  		}
  1332  
  1333  		if !batchedRequest {
  1334  			var req btcjson.Request
  1335  			var reply json.RawMessage
  1336  			err = json.Unmarshal(msg, &req)
  1337  			if err != nil {
  1338  				// only process requests from authenticated clients
  1339  				if !c.authenticated {
  1340  					break out
  1341  				}
  1342  
  1343  				jsonErr := &btcjson.RPCError{
  1344  					Code:    btcjson.ErrRPCParse.Code,
  1345  					Message: "Failed to parse request: " + err.Error(),
  1346  				}
  1347  				reply, err = createMarshalledReply(btcjson.RpcVersion1, nil, nil, jsonErr)
  1348  				if err != nil {
  1349  					rpcsLog.Errorf("Failed to marshal reply: %v", err)
  1350  					continue
  1351  				}
  1352  				c.SendMessage(reply, nil)
  1353  				continue
  1354  			}
  1355  
  1356  			if req.Method == "" || req.Params == nil {
  1357  				jsonErr := &btcjson.RPCError{
  1358  					Code:    btcjson.ErrRPCInvalidRequest.Code,
  1359  					Message: "Invalid request: malformed",
  1360  				}
  1361  				reply, err := createMarshalledReply(req.Jsonrpc, req.ID, nil, jsonErr)
  1362  				if err != nil {
  1363  					rpcsLog.Errorf("Failed to marshal reply: %v", err)
  1364  					continue
  1365  				}
  1366  				c.SendMessage(reply, nil)
  1367  				continue
  1368  			}
  1369  
  1370  			// Valid requests with no ID (notifications) must not have a response
  1371  			// per the JSON-RPC spec.
  1372  			if req.ID == nil {
  1373  				if !c.authenticated {
  1374  					break out
  1375  				}
  1376  				continue
  1377  			}
  1378  
  1379  			cmd := parseCmd(&req)
  1380  			if cmd.err != nil {
  1381  				// Only process requests from authenticated clients
  1382  				if !c.authenticated {
  1383  					break out
  1384  				}
  1385  
  1386  				reply, err = createMarshalledReply(cmd.jsonrpc, cmd.id, nil, cmd.err)
  1387  				if err != nil {
  1388  					rpcsLog.Errorf("Failed to marshal reply: %v", err)
  1389  					continue
  1390  				}
  1391  				c.SendMessage(reply, nil)
  1392  				continue
  1393  			}
  1394  
  1395  			rpcsLog.Debugf("Received command <%s> from %s", cmd.method, c.addr)
  1396  
  1397  			// Check auth.  The client is immediately disconnected if the
  1398  			// first request of an unauthentiated websocket client is not
  1399  			// the authenticate request, an authenticate request is received
  1400  			// when the client is already authenticated, or incorrect
  1401  			// authentication credentials are provided in the request.
  1402  			switch authCmd, ok := cmd.cmd.(*btcjson.AuthenticateCmd); {
  1403  			case c.authenticated && ok:
  1404  				rpcsLog.Warnf("Websocket client %s is already authenticated",
  1405  					c.addr)
  1406  				break out
  1407  			case !c.authenticated && !ok:
  1408  				rpcsLog.Warnf("Unauthenticated websocket message " +
  1409  					"received")
  1410  				break out
  1411  			case !c.authenticated:
  1412  				// Check credentials.
  1413  				login := authCmd.Username + ":" + authCmd.Passphrase
  1414  				auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(login))
  1415  				authSha := sha256.Sum256([]byte(auth))
  1416  				cmp := subtle.ConstantTimeCompare(authSha[:], c.server.authsha[:])
  1417  				limitcmp := subtle.ConstantTimeCompare(authSha[:], c.server.limitauthsha[:])
  1418  				if cmp != 1 && limitcmp != 1 {
  1419  					rpcsLog.Warnf("Auth failure.")
  1420  					break out
  1421  				}
  1422  				c.authenticated = true
  1423  				c.isAdmin = cmp == 1
  1424  
  1425  				// Marshal and send response.
  1426  				reply, err = createMarshalledReply(cmd.jsonrpc, cmd.id, nil, nil)
  1427  				if err != nil {
  1428  					rpcsLog.Errorf("Failed to marshal authenticate reply: "+
  1429  						"%v", err.Error())
  1430  					continue
  1431  				}
  1432  				c.SendMessage(reply, nil)
  1433  				continue
  1434  			}
  1435  
  1436  			// Check if the client is using limited RPC credentials and
  1437  			// error when not authorized to call the supplied RPC.
  1438  			if !c.isAdmin {
  1439  				if _, ok := rpcLimited[req.Method]; !ok {
  1440  					jsonErr := &btcjson.RPCError{
  1441  						Code:    btcjson.ErrRPCInvalidParams.Code,
  1442  						Message: "limited user not authorized for this method",
  1443  					}
  1444  					// Marshal and send response.
  1445  					reply, err = createMarshalledReply("", req.ID, nil, jsonErr)
  1446  					if err != nil {
  1447  						rpcsLog.Errorf("Failed to marshal parse failure "+
  1448  							"reply: %v", err)
  1449  						continue
  1450  					}
  1451  					c.SendMessage(reply, nil)
  1452  					continue
  1453  				}
  1454  			}
  1455  
  1456  			// Asynchronously handle the request.  A semaphore is used to
  1457  			// limit the number of concurrent requests currently being
  1458  			// serviced.  If the semaphore can not be acquired, simply wait
  1459  			// until a request finished before reading the next RPC request
  1460  			// from the websocket client.
  1461  			//
  1462  			// This could be a little fancier by timing out and erroring
  1463  			// when it takes too long to service the request, but if that is
  1464  			// done, the read of the next request should not be blocked by
  1465  			// this semaphore, otherwise the next request will be read and
  1466  			// will probably sit here for another few seconds before timing
  1467  			// out as well.  This will cause the total timeout duration for
  1468  			// later requests to be much longer than the check here would
  1469  			// imply.
  1470  			//
  1471  			// If a timeout is added, the semaphore acquiring should be
  1472  			// moved inside of the new goroutine with a select statement
  1473  			// that also reads a time.After channel.  This will unblock the
  1474  			// read of the next request from the websocket client and allow
  1475  			// many requests to be waited on concurrently.
  1476  			c.serviceRequestSem.acquire()
  1477  			go func() {
  1478  				c.serviceRequest(cmd)
  1479  				c.serviceRequestSem.release()
  1480  			}()
  1481  		}
  1482  
  1483  		// Process a batched request
  1484  		if batchedRequest {
  1485  			var batchedRequests []interface{}
  1486  			var results []json.RawMessage
  1487  			var batchSize int
  1488  			var reply json.RawMessage
  1489  			c.serviceRequestSem.acquire()
  1490  			err = json.Unmarshal(msg, &batchedRequests)
  1491  			if err != nil {
  1492  				// Only process requests from authenticated clients
  1493  				if !c.authenticated {
  1494  					break out
  1495  				}
  1496  
  1497  				jsonErr := &btcjson.RPCError{
  1498  					Code: btcjson.ErrRPCParse.Code,
  1499  					Message: fmt.Sprintf("Failed to parse request: %v",
  1500  						err),
  1501  				}
  1502  				reply, err = btcjson.MarshalResponse(btcjson.RpcVersion2, nil, nil, jsonErr)
  1503  				if err != nil {
  1504  					rpcsLog.Errorf("Failed to create reply: %v", err)
  1505  				}
  1506  
  1507  				if reply != nil {
  1508  					results = append(results, reply)
  1509  				}
  1510  			}
  1511  
  1512  			if err == nil {
  1513  				// Response with an empty batch error if the batch size is zero
  1514  				if len(batchedRequests) == 0 {
  1515  					if !c.authenticated {
  1516  						break out
  1517  					}
  1518  
  1519  					jsonErr := &btcjson.RPCError{
  1520  						Code:    btcjson.ErrRPCInvalidRequest.Code,
  1521  						Message: "Invalid request: empty batch",
  1522  					}
  1523  					reply, err = btcjson.MarshalResponse(btcjson.RpcVersion2, nil, nil, jsonErr)
  1524  					if err != nil {
  1525  						rpcsLog.Errorf("Failed to marshal reply: %v", err)
  1526  					}
  1527  
  1528  					if reply != nil {
  1529  						results = append(results, reply)
  1530  					}
  1531  				}
  1532  
  1533  				// Process each batch entry individually
  1534  				if len(batchedRequests) > 0 {
  1535  					batchSize = len(batchedRequests)
  1536  					for _, entry := range batchedRequests {
  1537  						var reqBytes []byte
  1538  						reqBytes, err = json.Marshal(entry)
  1539  						if err != nil {
  1540  							// Only process requests from authenticated clients
  1541  							if !c.authenticated {
  1542  								break out
  1543  							}
  1544  
  1545  							jsonErr := &btcjson.RPCError{
  1546  								Code: btcjson.ErrRPCInvalidRequest.Code,
  1547  								Message: fmt.Sprintf("Invalid request: %v",
  1548  									err),
  1549  							}
  1550  							reply, err = btcjson.MarshalResponse(btcjson.RpcVersion2, nil, nil, jsonErr)
  1551  							if err != nil {
  1552  								rpcsLog.Errorf("Failed to create reply: %v", err)
  1553  								continue
  1554  							}
  1555  
  1556  							if reply != nil {
  1557  								results = append(results, reply)
  1558  							}
  1559  							continue
  1560  						}
  1561  
  1562  						var req btcjson.Request
  1563  						err := json.Unmarshal(reqBytes, &req)
  1564  						if err != nil {
  1565  							// Only process requests from authenticated clients
  1566  							if !c.authenticated {
  1567  								break out
  1568  							}
  1569  
  1570  							jsonErr := &btcjson.RPCError{
  1571  								Code: btcjson.ErrRPCInvalidRequest.Code,
  1572  								Message: fmt.Sprintf("Invalid request: %v",
  1573  									err),
  1574  							}
  1575  							reply, err = btcjson.MarshalResponse(btcjson.RpcVersion2, nil, nil, jsonErr)
  1576  							if err != nil {
  1577  								rpcsLog.Errorf("Failed to create reply: %v", err)
  1578  								continue
  1579  							}
  1580  
  1581  							if reply != nil {
  1582  								results = append(results, reply)
  1583  							}
  1584  							continue
  1585  						}
  1586  
  1587  						if req.Method == "" || req.Params == nil {
  1588  							jsonErr := &btcjson.RPCError{
  1589  								Code:    btcjson.ErrRPCInvalidRequest.Code,
  1590  								Message: "Invalid request: malformed",
  1591  							}
  1592  							reply, err := createMarshalledReply(req.Jsonrpc, req.ID, nil, jsonErr)
  1593  							if err != nil {
  1594  								rpcsLog.Errorf("Failed to marshal reply: %v", err)
  1595  								continue
  1596  							}
  1597  
  1598  							if reply != nil {
  1599  								results = append(results, reply)
  1600  							}
  1601  							continue
  1602  						}
  1603  
  1604  						// Valid requests with no ID (notifications) must not have a response
  1605  						// per the JSON-RPC spec.
  1606  						if req.ID == nil {
  1607  							if !c.authenticated {
  1608  								break out
  1609  							}
  1610  							continue
  1611  						}
  1612  
  1613  						cmd := parseCmd(&req)
  1614  						if cmd.err != nil {
  1615  							// Only process requests from authenticated clients
  1616  							if !c.authenticated {
  1617  								break out
  1618  							}
  1619  
  1620  							reply, err = createMarshalledReply(cmd.jsonrpc, cmd.id, nil, cmd.err)
  1621  							if err != nil {
  1622  								rpcsLog.Errorf("Failed to marshal reply: %v", err)
  1623  								continue
  1624  							}
  1625  
  1626  							if reply != nil {
  1627  								results = append(results, reply)
  1628  							}
  1629  							continue
  1630  						}
  1631  
  1632  						rpcsLog.Debugf("Received command <%s> from %s", cmd.method, c.addr)
  1633  
  1634  						// Check auth.  The client is immediately disconnected if the
  1635  						// first request of an unauthentiated websocket client is not
  1636  						// the authenticate request, an authenticate request is received
  1637  						// when the client is already authenticated, or incorrect
  1638  						// authentication credentials are provided in the request.
  1639  						switch authCmd, ok := cmd.cmd.(*btcjson.AuthenticateCmd); {
  1640  						case c.authenticated && ok:
  1641  							rpcsLog.Warnf("Websocket client %s is already authenticated",
  1642  								c.addr)
  1643  							break out
  1644  						case !c.authenticated && !ok:
  1645  							rpcsLog.Warnf("Unauthenticated websocket message " +
  1646  								"received")
  1647  							break out
  1648  						case !c.authenticated:
  1649  							// Check credentials.
  1650  							login := authCmd.Username + ":" + authCmd.Passphrase
  1651  							auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(login))
  1652  							authSha := sha256.Sum256([]byte(auth))
  1653  							cmp := subtle.ConstantTimeCompare(authSha[:], c.server.authsha[:])
  1654  							limitcmp := subtle.ConstantTimeCompare(authSha[:], c.server.limitauthsha[:])
  1655  							if cmp != 1 && limitcmp != 1 {
  1656  								rpcsLog.Warnf("Auth failure.")
  1657  								break out
  1658  							}
  1659  
  1660  							c.authenticated = true
  1661  							c.isAdmin = cmp == 1
  1662  
  1663  							// Marshal and send response.
  1664  							reply, err = createMarshalledReply(cmd.jsonrpc, cmd.id, nil, nil)
  1665  							if err != nil {
  1666  								rpcsLog.Errorf("Failed to marshal authenticate reply: "+
  1667  									"%v", err.Error())
  1668  								continue
  1669  							}
  1670  
  1671  							if reply != nil {
  1672  								results = append(results, reply)
  1673  							}
  1674  							continue
  1675  						}
  1676  
  1677  						// Check if the client is using limited RPC credentials and
  1678  						// error when not authorized to call the supplied RPC.
  1679  						if !c.isAdmin {
  1680  							if _, ok := rpcLimited[req.Method]; !ok {
  1681  								jsonErr := &btcjson.RPCError{
  1682  									Code:    btcjson.ErrRPCInvalidParams.Code,
  1683  									Message: "limited user not authorized for this method",
  1684  								}
  1685  								// Marshal and send response.
  1686  								reply, err = createMarshalledReply(req.Jsonrpc, req.ID, nil, jsonErr)
  1687  								if err != nil {
  1688  									rpcsLog.Errorf("Failed to marshal parse failure "+
  1689  										"reply: %v", err)
  1690  									continue
  1691  								}
  1692  
  1693  								if reply != nil {
  1694  									results = append(results, reply)
  1695  								}
  1696  								continue
  1697  							}
  1698  						}
  1699  
  1700  						// Lookup the websocket extension for the command, if it doesn't
  1701  						// exist fallback to handling the command as a standard command.
  1702  						var resp interface{}
  1703  						wsHandler, ok := wsHandlers[cmd.method]
  1704  						if ok {
  1705  							resp, err = wsHandler(c, cmd.cmd)
  1706  						} else {
  1707  							resp, err = c.server.standardCmdResult(cmd, nil)
  1708  						}
  1709  
  1710  						// Marshal request output.
  1711  						reply, err := createMarshalledReply(cmd.jsonrpc, cmd.id, resp, err)
  1712  						if err != nil {
  1713  							rpcsLog.Errorf("Failed to marshal reply for <%s> "+
  1714  								"command: %v", cmd.method, err)
  1715  							return
  1716  						}
  1717  
  1718  						if reply != nil {
  1719  							results = append(results, reply)
  1720  						}
  1721  					}
  1722  				}
  1723  			}
  1724  
  1725  			// generate reply
  1726  			var payload = []byte{}
  1727  			if batchedRequest && batchSize > 0 {
  1728  				if len(results) > 0 {
  1729  					// Form the batched response json
  1730  					var buffer bytes.Buffer
  1731  					buffer.WriteByte('[')
  1732  					for idx, marshalledReply := range results {
  1733  						if idx == len(results)-1 {
  1734  							buffer.Write(marshalledReply)
  1735  							buffer.WriteByte(']')
  1736  							break
  1737  						}
  1738  						buffer.Write(marshalledReply)
  1739  						buffer.WriteByte(',')
  1740  					}
  1741  					payload = buffer.Bytes()
  1742  				}
  1743  			}
  1744  
  1745  			if !batchedRequest || batchSize == 0 {
  1746  				// Respond with the first results entry for single requests
  1747  				if len(results) > 0 {
  1748  					payload = results[0]
  1749  				}
  1750  			}
  1751  
  1752  			c.SendMessage(payload, nil)
  1753  			c.serviceRequestSem.release()
  1754  		}
  1755  	}
  1756  
  1757  	// Ensure the connection is closed.
  1758  	c.Disconnect()
  1759  	c.wg.Done()
  1760  	rpcsLog.Tracef("Websocket client input handler done for %s", c.addr)
  1761  }
  1762  
  1763  // serviceRequest services a parsed RPC request by looking up and executing the
  1764  // appropriate RPC handler.  The response is marshalled and sent to the
  1765  // websocket client.
  1766  func (c *wsClient) serviceRequest(r *parsedRPCCmd) {
  1767  	var (
  1768  		result interface{}
  1769  		err    error
  1770  	)
  1771  
  1772  	// Lookup the websocket extension for the command and if it doesn't
  1773  	// exist fallback to handling the command as a standard command.
  1774  	wsHandler, ok := wsHandlers[r.method]
  1775  	if ok {
  1776  		result, err = wsHandler(c, r.cmd)
  1777  	} else {
  1778  		result, err = c.server.standardCmdResult(r, nil)
  1779  	}
  1780  	reply, err := createMarshalledReply(r.jsonrpc, r.id, result, err)
  1781  	if err != nil {
  1782  		rpcsLog.Errorf("Failed to marshal reply for <%s> "+
  1783  			"command: %v", r.method, err)
  1784  		return
  1785  	}
  1786  	c.SendMessage(reply, nil)
  1787  }
  1788  
  1789  // notificationQueueHandler handles the queuing of outgoing notifications for
  1790  // the websocket client.  This runs as a muxer for various sources of input to
  1791  // ensure that queuing up notifications to be sent will not block.  Otherwise,
  1792  // slow clients could bog down the other systems (such as the mempool or block
  1793  // manager) which are queuing the data.  The data is passed on to outHandler to
  1794  // actually be written.  It must be run as a goroutine.
  1795  func (c *wsClient) notificationQueueHandler() {
  1796  	ntfnSentChan := make(chan bool, 1) // nonblocking sync
  1797  
  1798  	// pendingNtfns is used as a queue for notifications that are ready to
  1799  	// be sent once there are no outstanding notifications currently being
  1800  	// sent.  The waiting flag is used over simply checking for items in the
  1801  	// pending list to ensure cleanup knows what has and hasn't been sent
  1802  	// to the outHandler.  Currently no special cleanup is needed, however
  1803  	// if something like a done channel is added to notifications in the
  1804  	// future, not knowing what has and hasn't been sent to the outHandler
  1805  	// (and thus who should respond to the done channel) would be
  1806  	// problematic without using this approach.
  1807  	pendingNtfns := list.New()
  1808  	waiting := false
  1809  out:
  1810  	for {
  1811  		select {
  1812  		// This channel is notified when a message is being queued to
  1813  		// be sent across the network socket.  It will either send the
  1814  		// message immediately if a send is not already in progress, or
  1815  		// queue the message to be sent once the other pending messages
  1816  		// are sent.
  1817  		case msg := <-c.ntfnChan:
  1818  			if !waiting {
  1819  				c.SendMessage(msg, ntfnSentChan)
  1820  			} else {
  1821  				pendingNtfns.PushBack(msg)
  1822  			}
  1823  			waiting = true
  1824  
  1825  		// This channel is notified when a notification has been sent
  1826  		// across the network socket.
  1827  		case <-ntfnSentChan:
  1828  			// No longer waiting if there are no more messages in
  1829  			// the pending messages queue.
  1830  			next := pendingNtfns.Front()
  1831  			if next == nil {
  1832  				waiting = false
  1833  				continue
  1834  			}
  1835  
  1836  			// Notify the outHandler about the next item to
  1837  			// asynchronously send.
  1838  			msg := pendingNtfns.Remove(next).([]byte)
  1839  			c.SendMessage(msg, ntfnSentChan)
  1840  
  1841  		case <-c.quit:
  1842  			break out
  1843  		}
  1844  	}
  1845  
  1846  	// Drain any wait channels before exiting so nothing is left waiting
  1847  	// around to send.
  1848  cleanup:
  1849  	for {
  1850  		select {
  1851  		case <-c.ntfnChan:
  1852  		case <-ntfnSentChan:
  1853  		default:
  1854  			break cleanup
  1855  		}
  1856  	}
  1857  	c.wg.Done()
  1858  	rpcsLog.Tracef("Websocket client notification queue handler done "+
  1859  		"for %s", c.addr)
  1860  }
  1861  
  1862  // outHandler handles all outgoing messages for the websocket connection.  It
  1863  // must be run as a goroutine.  It uses a buffered channel to serialize output
  1864  // messages while allowing the sender to continue running asynchronously.  It
  1865  // must be run as a goroutine.
  1866  func (c *wsClient) outHandler() {
  1867  out:
  1868  	for {
  1869  		// Send any messages ready for send until the quit channel is
  1870  		// closed.
  1871  		select {
  1872  		case r := <-c.sendChan:
  1873  			err := c.conn.WriteMessage(websocket.TextMessage, r.msg)
  1874  			if err != nil {
  1875  				c.Disconnect()
  1876  				break out
  1877  			}
  1878  			if r.doneChan != nil {
  1879  				r.doneChan <- true
  1880  			}
  1881  
  1882  		case <-c.quit:
  1883  			break out
  1884  		}
  1885  	}
  1886  
  1887  	// Drain any wait channels before exiting so nothing is left waiting
  1888  	// around to send.
  1889  cleanup:
  1890  	for {
  1891  		select {
  1892  		case r := <-c.sendChan:
  1893  			if r.doneChan != nil {
  1894  				r.doneChan <- false
  1895  			}
  1896  		default:
  1897  			break cleanup
  1898  		}
  1899  	}
  1900  	c.wg.Done()
  1901  	rpcsLog.Tracef("Websocket client output handler done for %s", c.addr)
  1902  }
  1903  
  1904  // SendMessage sends the passed json to the websocket client.  It is backed
  1905  // by a buffered channel, so it will not block until the send channel is full.
  1906  // Note however that QueueNotification must be used for sending async
  1907  // notifications instead of the this function.  This approach allows a limit to
  1908  // the number of outstanding requests a client can make without preventing or
  1909  // blocking on async notifications.
  1910  func (c *wsClient) SendMessage(marshalledJSON []byte, doneChan chan bool) {
  1911  	// Don't send the message if disconnected.
  1912  	if c.Disconnected() {
  1913  		if doneChan != nil {
  1914  			doneChan <- false
  1915  		}
  1916  		return
  1917  	}
  1918  
  1919  	c.sendChan <- wsResponse{msg: marshalledJSON, doneChan: doneChan}
  1920  }
  1921  
  1922  // ErrClientQuit describes the error where a client send is not processed due
  1923  // to the client having already been disconnected or dropped.
  1924  var ErrClientQuit = errors.New("client quit")
  1925  
  1926  // QueueNotification queues the passed notification to be sent to the websocket
  1927  // client.  This function, as the name implies, is only intended for
  1928  // notifications since it has additional logic to prevent other subsystems, such
  1929  // as the memory pool and block manager, from blocking even when the send
  1930  // channel is full.
  1931  //
  1932  // If the client is in the process of shutting down, this function returns
  1933  // ErrClientQuit.  This is intended to be checked by long-running notification
  1934  // handlers to stop processing if there is no more work needed to be done.
  1935  func (c *wsClient) QueueNotification(marshalledJSON []byte) error {
  1936  	// Don't queue the message if disconnected.
  1937  	if c.Disconnected() {
  1938  		return ErrClientQuit
  1939  	}
  1940  
  1941  	c.ntfnChan <- marshalledJSON
  1942  	return nil
  1943  }
  1944  
  1945  // Disconnected returns whether or not the websocket client is disconnected.
  1946  func (c *wsClient) Disconnected() bool {
  1947  	c.Lock()
  1948  	isDisconnected := c.disconnected
  1949  	c.Unlock()
  1950  
  1951  	return isDisconnected
  1952  }
  1953  
  1954  // Disconnect disconnects the websocket client.
  1955  func (c *wsClient) Disconnect() {
  1956  	c.Lock()
  1957  	defer c.Unlock()
  1958  
  1959  	// Nothing to do if already disconnected.
  1960  	if c.disconnected {
  1961  		return
  1962  	}
  1963  
  1964  	rpcsLog.Tracef("Disconnecting websocket client %s", c.addr)
  1965  	close(c.quit)
  1966  	c.conn.Close()
  1967  	c.disconnected = true
  1968  }
  1969  
  1970  // Start begins processing input and output messages.
  1971  func (c *wsClient) Start() {
  1972  	rpcsLog.Tracef("Starting websocket client %s", c.addr)
  1973  
  1974  	// Start processing input and output.
  1975  	c.wg.Add(3)
  1976  	go c.inHandler()
  1977  	go c.notificationQueueHandler()
  1978  	go c.outHandler()
  1979  }
  1980  
  1981  // WaitForShutdown blocks until the websocket client goroutines are stopped
  1982  // and the connection is closed.
  1983  func (c *wsClient) WaitForShutdown() {
  1984  	c.wg.Wait()
  1985  }
  1986  
  1987  // newWebsocketClient returns a new websocket client given the notification
  1988  // manager, websocket connection, remote address, and whether or not the client
  1989  // has already been authenticated (via HTTP Basic access authentication).  The
  1990  // returned client is ready to start.  Once started, the client will process
  1991  // incoming and outgoing messages in separate goroutines complete with queuing
  1992  // and asynchrous handling for long-running operations.
  1993  func newWebsocketClient(server *rpcServer, conn *websocket.Conn,
  1994  	remoteAddr string, authenticated bool, isAdmin bool) (*wsClient, error) {
  1995  
  1996  	sessionID, err := wire.RandomUint64()
  1997  	if err != nil {
  1998  		return nil, err
  1999  	}
  2000  
  2001  	client := &wsClient{
  2002  		conn:              conn,
  2003  		addr:              remoteAddr,
  2004  		authenticated:     authenticated,
  2005  		isAdmin:           isAdmin,
  2006  		sessionID:         sessionID,
  2007  		server:            server,
  2008  		addrRequests:      make(map[string]struct{}),
  2009  		spentRequests:     make(map[wire.OutPoint]struct{}),
  2010  		serviceRequestSem: makeSemaphore(cfg.RPCMaxConcurrentReqs),
  2011  		ntfnChan:          make(chan []byte, 1), // nonblocking sync
  2012  		sendChan:          make(chan wsResponse, websocketSendBufferSize),
  2013  		quit:              make(chan struct{}),
  2014  	}
  2015  	return client, nil
  2016  }
  2017  
  2018  // handleWebsocketHelp implements the help command for websocket connections.
  2019  func handleWebsocketHelp(wsc *wsClient, icmd interface{}) (interface{}, error) {
  2020  	cmd, ok := icmd.(*btcjson.HelpCmd)
  2021  	if !ok {
  2022  		return nil, btcjson.ErrRPCInternal
  2023  	}
  2024  
  2025  	// Provide a usage overview of all commands when no specific command
  2026  	// was specified.
  2027  	var command string
  2028  	if cmd.Command != nil {
  2029  		command = *cmd.Command
  2030  	}
  2031  	if command == "" {
  2032  		usage, err := wsc.server.helpCacher.rpcUsage(true)
  2033  		if err != nil {
  2034  			context := "Failed to generate RPC usage"
  2035  			return nil, internalRPCError(err.Error(), context)
  2036  		}
  2037  		return usage, nil
  2038  	}
  2039  
  2040  	// Check that the command asked for is supported and implemented.
  2041  	// Search the list of websocket handlers as well as the main list of
  2042  	// handlers since help should only be provided for those cases.
  2043  	valid := true
  2044  	if _, ok := rpcHandlers[command]; !ok {
  2045  		if _, ok := wsHandlers[command]; !ok {
  2046  			valid = false
  2047  		}
  2048  	}
  2049  	if !valid {
  2050  		return nil, &btcjson.RPCError{
  2051  			Code:    btcjson.ErrRPCInvalidParameter,
  2052  			Message: "Unknown command: " + command,
  2053  		}
  2054  	}
  2055  
  2056  	// Get the help for the command.
  2057  	help, err := wsc.server.helpCacher.rpcMethodHelp(command)
  2058  	if err != nil {
  2059  		context := "Failed to generate help"
  2060  		return nil, internalRPCError(err.Error(), context)
  2061  	}
  2062  	return help, nil
  2063  }
  2064  
  2065  // handleLoadTxFilter implements the loadtxfilter command extension for
  2066  // websocket connections.
  2067  //
  2068  // NOTE: This extension is ported from github.com/decred/dcrd
  2069  func handleLoadTxFilter(wsc *wsClient, icmd interface{}) (interface{}, error) {
  2070  	cmd := icmd.(*btcjson.LoadTxFilterCmd)
  2071  
  2072  	outPoints := make([]wire.OutPoint, len(cmd.OutPoints))
  2073  	for i := range cmd.OutPoints {
  2074  		hash, err := chainhash.NewHashFromStr(cmd.OutPoints[i].Hash)
  2075  		if err != nil {
  2076  			return nil, &btcjson.RPCError{
  2077  				Code:    btcjson.ErrRPCInvalidParameter,
  2078  				Message: err.Error(),
  2079  			}
  2080  		}
  2081  		outPoints[i] = wire.OutPoint{
  2082  			Hash:  *hash,
  2083  			Index: cmd.OutPoints[i].Index,
  2084  		}
  2085  	}
  2086  
  2087  	params := wsc.server.cfg.ChainParams
  2088  
  2089  	wsc.Lock()
  2090  	if cmd.Reload || wsc.filterData == nil {
  2091  		wsc.filterData = newWSClientFilter(cmd.Addresses, outPoints,
  2092  			params)
  2093  		wsc.Unlock()
  2094  	} else {
  2095  		wsc.Unlock()
  2096  
  2097  		wsc.filterData.mu.Lock()
  2098  		for _, a := range cmd.Addresses {
  2099  			wsc.filterData.addAddressStr(a, params)
  2100  		}
  2101  		for i := range outPoints {
  2102  			wsc.filterData.addUnspentOutPoint(&outPoints[i])
  2103  		}
  2104  		wsc.filterData.mu.Unlock()
  2105  	}
  2106  
  2107  	return nil, nil
  2108  }
  2109  
  2110  // handleNotifyBlocks implements the notifyblocks command extension for
  2111  // websocket connections.
  2112  func handleNotifyBlocks(wsc *wsClient, icmd interface{}) (interface{}, error) {
  2113  	wsc.server.ntfnMgr.RegisterBlockUpdates(wsc)
  2114  	return nil, nil
  2115  }
  2116  
  2117  // handleSession implements the session command extension for websocket
  2118  // connections.
  2119  func handleSession(wsc *wsClient, icmd interface{}) (interface{}, error) {
  2120  	return &btcjson.SessionResult{SessionID: wsc.sessionID}, nil
  2121  }
  2122  
  2123  // handleStopNotifyBlocks implements the stopnotifyblocks command extension for
  2124  // websocket connections.
  2125  func handleStopNotifyBlocks(wsc *wsClient, icmd interface{}) (interface{}, error) {
  2126  	wsc.server.ntfnMgr.UnregisterBlockUpdates(wsc)
  2127  	return nil, nil
  2128  }
  2129  
  2130  // handleNotifySpent implements the notifyspent command extension for
  2131  // websocket connections.
  2132  func handleNotifySpent(wsc *wsClient, icmd interface{}) (interface{}, error) {
  2133  	cmd, ok := icmd.(*btcjson.NotifySpentCmd)
  2134  	if !ok {
  2135  		return nil, btcjson.ErrRPCInternal
  2136  	}
  2137  
  2138  	outpoints, err := deserializeOutpoints(cmd.OutPoints)
  2139  	if err != nil {
  2140  		return nil, err
  2141  	}
  2142  
  2143  	wsc.server.ntfnMgr.RegisterSpentRequests(wsc, outpoints)
  2144  	return nil, nil
  2145  }
  2146  
  2147  // handleNotifyNewTransations implements the notifynewtransactions command
  2148  // extension for websocket connections.
  2149  func handleNotifyNewTransactions(wsc *wsClient, icmd interface{}) (interface{}, error) {
  2150  	cmd, ok := icmd.(*btcjson.NotifyNewTransactionsCmd)
  2151  	if !ok {
  2152  		return nil, btcjson.ErrRPCInternal
  2153  	}
  2154  
  2155  	wsc.verboseTxUpdates = cmd.Verbose != nil && *cmd.Verbose
  2156  	wsc.server.ntfnMgr.RegisterNewMempoolTxsUpdates(wsc)
  2157  	return nil, nil
  2158  }
  2159  
  2160  // handleStopNotifyNewTransations implements the stopnotifynewtransactions
  2161  // command extension for websocket connections.
  2162  func handleStopNotifyNewTransactions(wsc *wsClient, icmd interface{}) (interface{}, error) {
  2163  	wsc.server.ntfnMgr.UnregisterNewMempoolTxsUpdates(wsc)
  2164  	return nil, nil
  2165  }
  2166  
  2167  // handleNotifyReceived implements the notifyreceived command extension for
  2168  // websocket connections.
  2169  func handleNotifyReceived(wsc *wsClient, icmd interface{}) (interface{}, error) {
  2170  	cmd, ok := icmd.(*btcjson.NotifyReceivedCmd)
  2171  	if !ok {
  2172  		return nil, btcjson.ErrRPCInternal
  2173  	}
  2174  
  2175  	// Decode addresses to validate input, but the strings slice is used
  2176  	// directly if these are all ok.
  2177  	err := checkAddressValidity(cmd.Addresses, wsc.server.cfg.ChainParams)
  2178  	if err != nil {
  2179  		return nil, err
  2180  	}
  2181  
  2182  	wsc.server.ntfnMgr.RegisterTxOutAddressRequests(wsc, cmd.Addresses)
  2183  	return nil, nil
  2184  }
  2185  
  2186  // handleStopNotifySpent implements the stopnotifyspent command extension for
  2187  // websocket connections.
  2188  func handleStopNotifySpent(wsc *wsClient, icmd interface{}) (interface{}, error) {
  2189  	cmd, ok := icmd.(*btcjson.StopNotifySpentCmd)
  2190  	if !ok {
  2191  		return nil, btcjson.ErrRPCInternal
  2192  	}
  2193  
  2194  	outpoints, err := deserializeOutpoints(cmd.OutPoints)
  2195  	if err != nil {
  2196  		return nil, err
  2197  	}
  2198  
  2199  	for _, outpoint := range outpoints {
  2200  		wsc.server.ntfnMgr.UnregisterSpentRequest(wsc, outpoint)
  2201  	}
  2202  
  2203  	return nil, nil
  2204  }
  2205  
  2206  // handleStopNotifyReceived implements the stopnotifyreceived command extension
  2207  // for websocket connections.
  2208  func handleStopNotifyReceived(wsc *wsClient, icmd interface{}) (interface{}, error) {
  2209  	cmd, ok := icmd.(*btcjson.StopNotifyReceivedCmd)
  2210  	if !ok {
  2211  		return nil, btcjson.ErrRPCInternal
  2212  	}
  2213  
  2214  	// Decode addresses to validate input, but the strings slice is used
  2215  	// directly if these are all ok.
  2216  	err := checkAddressValidity(cmd.Addresses, wsc.server.cfg.ChainParams)
  2217  	if err != nil {
  2218  		return nil, err
  2219  	}
  2220  
  2221  	for _, addr := range cmd.Addresses {
  2222  		wsc.server.ntfnMgr.UnregisterTxOutAddressRequest(wsc, addr)
  2223  	}
  2224  
  2225  	return nil, nil
  2226  }
  2227  
  2228  // checkAddressValidity checks the validity of each address in the passed
  2229  // string slice. It does this by attempting to decode each address using the
  2230  // current active network parameters. If any single address fails to decode
  2231  // properly, the function returns an error. Otherwise, nil is returned.
  2232  func checkAddressValidity(addrs []string, params *chaincfg.Params) error {
  2233  	for _, addr := range addrs {
  2234  		_, err := palcutil.DecodeAddress(addr, params)
  2235  		if err != nil {
  2236  			return &btcjson.RPCError{
  2237  				Code: btcjson.ErrRPCInvalidAddressOrKey,
  2238  				Message: fmt.Sprintf("Invalid address or key: %v",
  2239  					addr),
  2240  			}
  2241  		}
  2242  	}
  2243  	return nil
  2244  }
  2245  
  2246  // deserializeOutpoints deserializes each serialized outpoint.
  2247  func deserializeOutpoints(serializedOuts []btcjson.OutPoint) ([]*wire.OutPoint, error) {
  2248  	outpoints := make([]*wire.OutPoint, 0, len(serializedOuts))
  2249  	for i := range serializedOuts {
  2250  		blockHash, err := chainhash.NewHashFromStr(serializedOuts[i].Hash)
  2251  		if err != nil {
  2252  			return nil, rpcDecodeHexError(serializedOuts[i].Hash)
  2253  		}
  2254  		index := serializedOuts[i].Index
  2255  		outpoints = append(outpoints, wire.NewOutPoint(blockHash, index))
  2256  	}
  2257  
  2258  	return outpoints, nil
  2259  }
  2260  
  2261  type rescanKeys struct {
  2262  	addrs   map[string]struct{}
  2263  	unspent map[wire.OutPoint]struct{}
  2264  }
  2265  
  2266  // unspentSlice returns a slice of currently-unspent outpoints for the rescan
  2267  // lookup keys.  This is primarily intended to be used to register outpoints
  2268  // for continuous notifications after a rescan has completed.
  2269  func (r *rescanKeys) unspentSlice() []*wire.OutPoint {
  2270  	ops := make([]*wire.OutPoint, 0, len(r.unspent))
  2271  	for op := range r.unspent {
  2272  		opCopy := op
  2273  		ops = append(ops, &opCopy)
  2274  	}
  2275  	return ops
  2276  }
  2277  
  2278  // ErrRescanReorg defines the error that is returned when an unrecoverable
  2279  // reorganize is detected during a rescan.
  2280  var ErrRescanReorg = btcjson.RPCError{
  2281  	Code:    btcjson.ErrRPCDatabase,
  2282  	Message: "Reorganize",
  2283  }
  2284  
  2285  // rescanBlock rescans all transactions in a single block.  This is a helper
  2286  // function for handleRescan.
  2287  func rescanBlock(wsc *wsClient, lookups *rescanKeys, blk *palcutil.Block) {
  2288  	for _, tx := range blk.Transactions() {
  2289  		// Hexadecimal representation of this tx.  Only created if
  2290  		// needed, and reused for later notifications if already made.
  2291  		var txHex string
  2292  
  2293  		// All inputs and outputs must be iterated through to correctly
  2294  		// modify the unspent map, however, just a single notification
  2295  		// for any matching transaction inputs or outputs should be
  2296  		// created and sent.
  2297  		spentNotified := false
  2298  		recvNotified := false
  2299  
  2300  		// notifySpend is a closure we'll use when we first detect that
  2301  		// a transactions spends an outpoint/script in our filter list.
  2302  		notifySpend := func() error {
  2303  			if txHex == "" {
  2304  				txHex = txHexString(tx.MsgTx())
  2305  			}
  2306  			marshalledJSON, err := newRedeemingTxNotification(
  2307  				txHex, tx.Index(), blk,
  2308  			)
  2309  			if err != nil {
  2310  				return fmt.Errorf("unable to marshal "+
  2311  					"btcjson.RedeeminTxNtfn: %v", err)
  2312  			}
  2313  
  2314  			return wsc.QueueNotification(marshalledJSON)
  2315  		}
  2316  
  2317  		// We'll start by iterating over the transaction's inputs to
  2318  		// determine if it spends an outpoint/script in our filter list.
  2319  		for _, txin := range tx.MsgTx().TxIn {
  2320  			// If it spends an outpoint, we'll dispatch a spend
  2321  			// notification for the transaction.
  2322  			if _, ok := lookups.unspent[txin.PreviousOutPoint]; ok {
  2323  				delete(lookups.unspent, txin.PreviousOutPoint)
  2324  
  2325  				if spentNotified {
  2326  					continue
  2327  				}
  2328  
  2329  				err := notifySpend()
  2330  
  2331  				// Stop the rescan early if the websocket client
  2332  				// disconnected.
  2333  				if err == ErrClientQuit {
  2334  					return
  2335  				}
  2336  				if err != nil {
  2337  					rpcsLog.Errorf("Unable to notify "+
  2338  						"redeeming transaction %v: %v",
  2339  						tx.Hash(), err)
  2340  					continue
  2341  				}
  2342  
  2343  				spentNotified = true
  2344  			}
  2345  
  2346  			// We'll also recompute the pkScript the input is
  2347  			// attempting to spend to determine whether it is
  2348  			// relevant to us.
  2349  			pkScript, err := txscript.ComputePkScript(
  2350  				txin.SignatureScript, txin.Witness,
  2351  			)
  2352  			if err != nil {
  2353  				continue
  2354  			}
  2355  			addr, err := pkScript.Address(wsc.server.cfg.ChainParams)
  2356  			if err != nil {
  2357  				continue
  2358  			}
  2359  
  2360  			// If it is, we'll also dispatch a spend notification
  2361  			// for this transaction if we haven't already.
  2362  			if _, ok := lookups.addrs[addr.String()]; ok {
  2363  				if spentNotified {
  2364  					continue
  2365  				}
  2366  
  2367  				err := notifySpend()
  2368  
  2369  				// Stop the rescan early if the websocket client
  2370  				// disconnected.
  2371  				if err == ErrClientQuit {
  2372  					return
  2373  				}
  2374  				if err != nil {
  2375  					rpcsLog.Errorf("Unable to notify "+
  2376  						"redeeming transaction %v: %v",
  2377  						tx.Hash(), err)
  2378  					continue
  2379  				}
  2380  
  2381  				spentNotified = true
  2382  			}
  2383  		}
  2384  
  2385  		for txOutIdx, txout := range tx.MsgTx().TxOut {
  2386  			_, addrs, _, _ := txscript.ExtractPkScriptAddrs(
  2387  				txout.PkScript, wsc.server.cfg.ChainParams)
  2388  
  2389  			for _, addr := range addrs {
  2390  				if _, ok := lookups.addrs[addr.String()]; !ok {
  2391  					continue
  2392  				}
  2393  
  2394  				outpoint := wire.OutPoint{
  2395  					Hash:  *tx.Hash(),
  2396  					Index: uint32(txOutIdx),
  2397  				}
  2398  				lookups.unspent[outpoint] = struct{}{}
  2399  
  2400  				if recvNotified {
  2401  					continue
  2402  				}
  2403  
  2404  				if txHex == "" {
  2405  					txHex = txHexString(tx.MsgTx())
  2406  				}
  2407  				ntfn := btcjson.NewRecvTxNtfn(txHex,
  2408  					blockDetails(blk, tx.Index()))
  2409  
  2410  				marshalledJSON, err := btcjson.MarshalCmd(btcjson.RpcVersion1, nil, ntfn)
  2411  				if err != nil {
  2412  					rpcsLog.Errorf("Failed to marshal recvtx notification: %v", err)
  2413  					return
  2414  				}
  2415  
  2416  				err = wsc.QueueNotification(marshalledJSON)
  2417  				// Stop the rescan early if the websocket client
  2418  				// disconnected.
  2419  				if err == ErrClientQuit {
  2420  					return
  2421  				}
  2422  				recvNotified = true
  2423  			}
  2424  		}
  2425  	}
  2426  }
  2427  
  2428  // rescanBlockFilter rescans a block for any relevant transactions for the
  2429  // passed lookup keys. Any discovered transactions are returned hex encoded as
  2430  // a string slice.
  2431  //
  2432  // NOTE: This extension is ported from github.com/decred/dcrd
  2433  func rescanBlockFilter(filter *wsClientFilter, block *palcutil.Block, params *chaincfg.Params) []string {
  2434  	var transactions []string
  2435  
  2436  	filter.mu.Lock()
  2437  	for _, tx := range block.Transactions() {
  2438  		msgTx := tx.MsgTx()
  2439  
  2440  		// Keep track of whether the transaction has already been added
  2441  		// to the result.  It shouldn't be added twice.
  2442  		added := false
  2443  
  2444  		// Scan inputs if not a coinbase transaction.
  2445  		if !blockchain.IsCoinBaseTx(msgTx) {
  2446  			for _, input := range msgTx.TxIn {
  2447  				if !filter.existsUnspentOutPoint(&input.PreviousOutPoint) {
  2448  					continue
  2449  				}
  2450  				if !added {
  2451  					transactions = append(
  2452  						transactions,
  2453  						txHexString(msgTx))
  2454  					added = true
  2455  				}
  2456  			}
  2457  		}
  2458  
  2459  		// Scan outputs.
  2460  		for i, output := range msgTx.TxOut {
  2461  			_, addrs, _, err := txscript.ExtractPkScriptAddrs(
  2462  				output.PkScript, params)
  2463  			if err != nil {
  2464  				continue
  2465  			}
  2466  			for _, a := range addrs {
  2467  				if !filter.existsAddress(a) {
  2468  					continue
  2469  				}
  2470  
  2471  				op := wire.OutPoint{
  2472  					Hash:  *tx.Hash(),
  2473  					Index: uint32(i),
  2474  				}
  2475  				filter.addUnspentOutPoint(&op)
  2476  
  2477  				if !added {
  2478  					transactions = append(
  2479  						transactions,
  2480  						txHexString(msgTx))
  2481  					added = true
  2482  				}
  2483  			}
  2484  		}
  2485  	}
  2486  	filter.mu.Unlock()
  2487  
  2488  	return transactions
  2489  }
  2490  
  2491  // handleRescanBlocks implements the rescanblocks command extension for
  2492  // websocket connections.
  2493  //
  2494  // NOTE: This extension is ported from github.com/decred/dcrd
  2495  func handleRescanBlocks(wsc *wsClient, icmd interface{}) (interface{}, error) {
  2496  	cmd, ok := icmd.(*btcjson.RescanBlocksCmd)
  2497  	if !ok {
  2498  		return nil, btcjson.ErrRPCInternal
  2499  	}
  2500  
  2501  	// Load client's transaction filter.  Must exist in order to continue.
  2502  	wsc.Lock()
  2503  	filter := wsc.filterData
  2504  	wsc.Unlock()
  2505  	if filter == nil {
  2506  		return nil, &btcjson.RPCError{
  2507  			Code:    btcjson.ErrRPCMisc,
  2508  			Message: "Transaction filter must be loaded before rescanning",
  2509  		}
  2510  	}
  2511  
  2512  	blockHashes := make([]*chainhash.Hash, len(cmd.BlockHashes))
  2513  
  2514  	for i := range cmd.BlockHashes {
  2515  		hash, err := chainhash.NewHashFromStr(cmd.BlockHashes[i])
  2516  		if err != nil {
  2517  			return nil, err
  2518  		}
  2519  		blockHashes[i] = hash
  2520  	}
  2521  
  2522  	discoveredData := make([]btcjson.RescannedBlock, 0, len(blockHashes))
  2523  
  2524  	// Iterate over each block in the request and rescan.  When a block
  2525  	// contains relevant transactions, add it to the response.
  2526  	bc := wsc.server.cfg.Chain
  2527  	params := wsc.server.cfg.ChainParams
  2528  	var lastBlockHash *chainhash.Hash
  2529  	for i := range blockHashes {
  2530  		block, err := bc.BlockByHash(blockHashes[i])
  2531  		if err != nil {
  2532  			return nil, &btcjson.RPCError{
  2533  				Code:    btcjson.ErrRPCBlockNotFound,
  2534  				Message: "Failed to fetch block: " + err.Error(),
  2535  			}
  2536  		}
  2537  		if lastBlockHash != nil && block.MsgBlock().Header.PrevBlock != *lastBlockHash {
  2538  			return nil, &btcjson.RPCError{
  2539  				Code: btcjson.ErrRPCInvalidParameter,
  2540  				Message: fmt.Sprintf("Block %v is not a child of %v",
  2541  					blockHashes[i], lastBlockHash),
  2542  			}
  2543  		}
  2544  		lastBlockHash = blockHashes[i]
  2545  
  2546  		transactions := rescanBlockFilter(filter, block, params)
  2547  		if len(transactions) != 0 {
  2548  			discoveredData = append(discoveredData, btcjson.RescannedBlock{
  2549  				Hash:         cmd.BlockHashes[i],
  2550  				Transactions: transactions,
  2551  			})
  2552  		}
  2553  	}
  2554  
  2555  	return &discoveredData, nil
  2556  }
  2557  
  2558  // recoverFromReorg attempts to recover from a detected reorganize during a
  2559  // rescan.  It fetches a new range of block shas from the database and
  2560  // verifies that the new range of blocks is on the same fork as a previous
  2561  // range of blocks.  If this condition does not hold true, the JSON-RPC error
  2562  // for an unrecoverable reorganize is returned.
  2563  func recoverFromReorg(chain *blockchain.BlockChain, minBlock, maxBlock int32,
  2564  	lastBlock *chainhash.Hash) ([]chainhash.Hash, error) {
  2565  
  2566  	hashList, err := chain.HeightRange(minBlock, maxBlock)
  2567  	if err != nil {
  2568  		rpcsLog.Errorf("Error looking up block range: %v", err)
  2569  		return nil, &btcjson.RPCError{
  2570  			Code:    btcjson.ErrRPCDatabase,
  2571  			Message: "Database error: " + err.Error(),
  2572  		}
  2573  	}
  2574  	if lastBlock == nil || len(hashList) == 0 {
  2575  		return hashList, nil
  2576  	}
  2577  
  2578  	blk, err := chain.BlockByHash(&hashList[0])
  2579  	if err != nil {
  2580  		rpcsLog.Errorf("Error looking up possibly reorged block: %v",
  2581  			err)
  2582  		return nil, &btcjson.RPCError{
  2583  			Code:    btcjson.ErrRPCDatabase,
  2584  			Message: "Database error: " + err.Error(),
  2585  		}
  2586  	}
  2587  	jsonErr := descendantBlock(lastBlock, blk)
  2588  	if jsonErr != nil {
  2589  		return nil, jsonErr
  2590  	}
  2591  	return hashList, nil
  2592  }
  2593  
  2594  // descendantBlock returns the appropriate JSON-RPC error if a current block
  2595  // fetched during a reorganize is not a direct child of the parent block hash.
  2596  func descendantBlock(prevHash *chainhash.Hash, curBlock *palcutil.Block) error {
  2597  	curHash := &curBlock.MsgBlock().Header.PrevBlock
  2598  	if !prevHash.IsEqual(curHash) {
  2599  		rpcsLog.Errorf("Stopping rescan for reorged block %v "+
  2600  			"(replaced by block %v)", prevHash, curHash)
  2601  		return &ErrRescanReorg
  2602  	}
  2603  	return nil
  2604  }
  2605  
  2606  // scanBlockChunks executes a rescan in chunked stages. We do this to limit the
  2607  // amount of memory that we'll allocate to a given rescan. Every so often,
  2608  // we'll send back a rescan progress notification to the websockets client. The
  2609  // final block and block hash that we've scanned will be returned.
  2610  func scanBlockChunks(wsc *wsClient, cmd *btcjson.RescanCmd, lookups *rescanKeys, minBlock,
  2611  	maxBlock int32, chain *blockchain.BlockChain) (
  2612  	*palcutil.Block, *chainhash.Hash, error) {
  2613  
  2614  	// lastBlock and lastBlockHash track the previously-rescanned block.
  2615  	// They equal nil when no previous blocks have been rescanned.
  2616  	var (
  2617  		lastBlock     *palcutil.Block
  2618  		lastBlockHash *chainhash.Hash
  2619  	)
  2620  
  2621  	// A ticker is created to wait at least 10 seconds before notifying the
  2622  	// websocket client of the current progress completed by the rescan.
  2623  	ticker := time.NewTicker(10 * time.Second)
  2624  	defer ticker.Stop()
  2625  
  2626  	// Instead of fetching all block shas at once, fetch in smaller chunks
  2627  	// to ensure large rescans consume a limited amount of memory.
  2628  fetchRange:
  2629  	for minBlock < maxBlock {
  2630  		// Limit the max number of hashes to fetch at once to the
  2631  		// maximum number of items allowed in a single inventory.
  2632  		// This value could be higher since it's not creating inventory
  2633  		// messages, but this mirrors the limiting logic used in the
  2634  		// peer-to-peer protocol.
  2635  		maxLoopBlock := maxBlock
  2636  		if maxLoopBlock-minBlock > wire.MaxInvPerMsg {
  2637  			maxLoopBlock = minBlock + wire.MaxInvPerMsg
  2638  		}
  2639  		hashList, err := chain.HeightRange(minBlock, maxLoopBlock)
  2640  		if err != nil {
  2641  			rpcsLog.Errorf("Error looking up block range: %v", err)
  2642  			return nil, nil, &btcjson.RPCError{
  2643  				Code:    btcjson.ErrRPCDatabase,
  2644  				Message: "Database error: " + err.Error(),
  2645  			}
  2646  		}
  2647  		if len(hashList) == 0 {
  2648  			// The rescan is finished if no blocks hashes for this
  2649  			// range were successfully fetched and a stop block
  2650  			// was provided.
  2651  			if maxBlock != math.MaxInt32 {
  2652  				break
  2653  			}
  2654  
  2655  			// If the rescan is through the current block, set up
  2656  			// the client to continue to receive notifications
  2657  			// regarding all rescanned addresses and the current set
  2658  			// of unspent outputs.
  2659  			//
  2660  			// This is done safely by temporarily grabbing exclusive
  2661  			// access of the block manager.  If no more blocks have
  2662  			// been attached between this pause and the fetch above,
  2663  			// then it is safe to register the websocket client for
  2664  			// continuous notifications if necessary.  Otherwise,
  2665  			// continue the fetch loop again to rescan the new
  2666  			// blocks (or error due to an irrecoverable reorganize).
  2667  			pauseGuard := wsc.server.cfg.SyncMgr.Pause()
  2668  			best := wsc.server.cfg.Chain.BestSnapshot()
  2669  			curHash := &best.Hash
  2670  			again := true
  2671  			if lastBlockHash == nil || *lastBlockHash == *curHash {
  2672  				again = false
  2673  				n := wsc.server.ntfnMgr
  2674  				n.RegisterSpentRequests(wsc, lookups.unspentSlice())
  2675  				n.RegisterTxOutAddressRequests(wsc, cmd.Addresses)
  2676  			}
  2677  			close(pauseGuard)
  2678  			if err != nil {
  2679  				rpcsLog.Errorf("Error fetching best block "+
  2680  					"hash: %v", err)
  2681  				return nil, nil, &btcjson.RPCError{
  2682  					Code: btcjson.ErrRPCDatabase,
  2683  					Message: "Database error: " +
  2684  						err.Error(),
  2685  				}
  2686  			}
  2687  			if again {
  2688  				continue
  2689  			}
  2690  			break
  2691  		}
  2692  
  2693  	loopHashList:
  2694  		for i := range hashList {
  2695  			blk, err := chain.BlockByHash(&hashList[i])
  2696  			if err != nil {
  2697  				// Only handle reorgs if a block could not be
  2698  				// found for the hash.
  2699  				if dbErr, ok := err.(database.Error); !ok ||
  2700  					dbErr.ErrorCode != database.ErrBlockNotFound {
  2701  
  2702  					rpcsLog.Errorf("Error looking up "+
  2703  						"block: %v", err)
  2704  					return nil, nil, &btcjson.RPCError{
  2705  						Code: btcjson.ErrRPCDatabase,
  2706  						Message: "Database error: " +
  2707  							err.Error(),
  2708  					}
  2709  				}
  2710  
  2711  				// If an absolute max block was specified, don't
  2712  				// attempt to handle the reorg.
  2713  				if maxBlock != math.MaxInt32 {
  2714  					rpcsLog.Errorf("Stopping rescan for "+
  2715  						"reorged block %v",
  2716  						cmd.EndBlock)
  2717  					return nil, nil, &ErrRescanReorg
  2718  				}
  2719  
  2720  				// If the lookup for the previously valid block
  2721  				// hash failed, there may have been a reorg.
  2722  				// Fetch a new range of block hashes and verify
  2723  				// that the previously processed block (if there
  2724  				// was any) still exists in the database.  If it
  2725  				// doesn't, we error.
  2726  				//
  2727  				// A goto is used to branch executation back to
  2728  				// before the range was evaluated, as it must be
  2729  				// reevaluated for the new hashList.
  2730  				minBlock += int32(i)
  2731  				hashList, err = recoverFromReorg(
  2732  					chain, minBlock, maxBlock, lastBlockHash,
  2733  				)
  2734  				if err != nil {
  2735  					return nil, nil, err
  2736  				}
  2737  				if len(hashList) == 0 {
  2738  					break fetchRange
  2739  				}
  2740  				goto loopHashList
  2741  			}
  2742  			if i == 0 && lastBlockHash != nil {
  2743  				// Ensure the new hashList is on the same fork
  2744  				// as the last block from the old hashList.
  2745  				jsonErr := descendantBlock(lastBlockHash, blk)
  2746  				if jsonErr != nil {
  2747  					return nil, nil, jsonErr
  2748  				}
  2749  			}
  2750  
  2751  			// A select statement is used to stop rescans if the
  2752  			// client requesting the rescan has disconnected.
  2753  			select {
  2754  			case <-wsc.quit:
  2755  				rpcsLog.Debugf("Stopped rescan at height %v "+
  2756  					"for disconnected client", blk.Height())
  2757  				return nil, nil, nil
  2758  			default:
  2759  				rescanBlock(wsc, lookups, blk)
  2760  				lastBlock = blk
  2761  				lastBlockHash = blk.Hash()
  2762  			}
  2763  
  2764  			// Periodically notify the client of the progress
  2765  			// completed.  Continue with next block if no progress
  2766  			// notification is needed yet.
  2767  			select {
  2768  			case <-ticker.C: // fallthrough
  2769  			default:
  2770  				continue
  2771  			}
  2772  
  2773  			n := btcjson.NewRescanProgressNtfn(
  2774  				hashList[i].String(), blk.Height(),
  2775  				blk.MsgBlock().Header.Timestamp.Unix(),
  2776  			)
  2777  			mn, err := btcjson.MarshalCmd(btcjson.RpcVersion1, nil, n)
  2778  			if err != nil {
  2779  				rpcsLog.Errorf("Failed to marshal rescan "+
  2780  					"progress notification: %v", err)
  2781  				continue
  2782  			}
  2783  
  2784  			if err = wsc.QueueNotification(mn); err == ErrClientQuit {
  2785  				// Finished if the client disconnected.
  2786  				rpcsLog.Debugf("Stopped rescan at height %v "+
  2787  					"for disconnected client", blk.Height())
  2788  				return nil, nil, nil
  2789  			}
  2790  		}
  2791  
  2792  		minBlock += int32(len(hashList))
  2793  	}
  2794  
  2795  	return lastBlock, lastBlockHash, nil
  2796  }
  2797  
  2798  // handleRescan implements the rescan command extension for websocket
  2799  // connections.
  2800  //
  2801  // NOTE: This does not smartly handle reorgs, and fixing requires database
  2802  // changes (for safe, concurrent access to full block ranges, and support
  2803  // for other chains than the best chain).  It will, however, detect whether
  2804  // a reorg removed a block that was previously processed, and result in the
  2805  // handler erroring.  Clients must handle this by finding a block still in
  2806  // the chain (perhaps from a rescanprogress notification) to resume their
  2807  // rescan.
  2808  func handleRescan(wsc *wsClient, icmd interface{}) (interface{}, error) {
  2809  	cmd, ok := icmd.(*btcjson.RescanCmd)
  2810  	if !ok {
  2811  		return nil, btcjson.ErrRPCInternal
  2812  	}
  2813  
  2814  	outpoints := make([]*wire.OutPoint, 0, len(cmd.OutPoints))
  2815  	for i := range cmd.OutPoints {
  2816  		cmdOutpoint := &cmd.OutPoints[i]
  2817  		blockHash, err := chainhash.NewHashFromStr(cmdOutpoint.Hash)
  2818  		if err != nil {
  2819  			return nil, rpcDecodeHexError(cmdOutpoint.Hash)
  2820  		}
  2821  		outpoint := wire.NewOutPoint(blockHash, cmdOutpoint.Index)
  2822  		outpoints = append(outpoints, outpoint)
  2823  	}
  2824  
  2825  	numAddrs := len(cmd.Addresses)
  2826  	if numAddrs == 1 {
  2827  		rpcsLog.Info("Beginning rescan for 1 address")
  2828  	} else {
  2829  		rpcsLog.Infof("Beginning rescan for %d addresses", numAddrs)
  2830  	}
  2831  
  2832  	// Build lookup maps.
  2833  	lookups := rescanKeys{
  2834  		addrs:   map[string]struct{}{},
  2835  		unspent: map[wire.OutPoint]struct{}{},
  2836  	}
  2837  	for _, addrStr := range cmd.Addresses {
  2838  		lookups.addrs[addrStr] = struct{}{}
  2839  	}
  2840  	for _, outpoint := range outpoints {
  2841  		lookups.unspent[*outpoint] = struct{}{}
  2842  	}
  2843  
  2844  	chain := wsc.server.cfg.Chain
  2845  
  2846  	minBlockHash, err := chainhash.NewHashFromStr(cmd.BeginBlock)
  2847  	if err != nil {
  2848  		return nil, rpcDecodeHexError(cmd.BeginBlock)
  2849  	}
  2850  	minBlock, err := chain.BlockHeightByHash(minBlockHash)
  2851  	if err != nil {
  2852  		return nil, &btcjson.RPCError{
  2853  			Code:    btcjson.ErrRPCBlockNotFound,
  2854  			Message: "Error getting block: " + err.Error(),
  2855  		}
  2856  	}
  2857  
  2858  	maxBlock := int32(math.MaxInt32)
  2859  	if cmd.EndBlock != nil {
  2860  		maxBlockHash, err := chainhash.NewHashFromStr(*cmd.EndBlock)
  2861  		if err != nil {
  2862  			return nil, rpcDecodeHexError(*cmd.EndBlock)
  2863  		}
  2864  		maxBlock, err = chain.BlockHeightByHash(maxBlockHash)
  2865  		if err != nil {
  2866  			return nil, &btcjson.RPCError{
  2867  				Code:    btcjson.ErrRPCBlockNotFound,
  2868  				Message: "Error getting block: " + err.Error(),
  2869  			}
  2870  		}
  2871  	}
  2872  
  2873  	var (
  2874  		lastBlock     *palcutil.Block
  2875  		lastBlockHash *chainhash.Hash
  2876  	)
  2877  	if len(lookups.addrs) != 0 || len(lookups.unspent) != 0 {
  2878  		// With all the arguments parsed, we'll execute our chunked rescan
  2879  		// which will notify the clients of any address deposits or output
  2880  		// spends.
  2881  		lastBlock, lastBlockHash, err = scanBlockChunks(
  2882  			wsc, cmd, &lookups, minBlock, maxBlock, chain,
  2883  		)
  2884  		if err != nil {
  2885  			return nil, err
  2886  		}
  2887  
  2888  		// If the last block is nil, then this means that the client
  2889  		// disconnected mid-rescan. As a result, we don't need to send
  2890  		// anything back to them.
  2891  		if lastBlock == nil {
  2892  			return nil, nil
  2893  		}
  2894  	} else {
  2895  		rpcsLog.Infof("Skipping rescan as client has no addrs/utxos")
  2896  
  2897  		// If we didn't actually do a rescan, then we'll give the
  2898  		// client our best known block within the final rescan finished
  2899  		// notification.
  2900  		chainTip := chain.BestSnapshot()
  2901  		lastBlockHash = &chainTip.Hash
  2902  		lastBlock, err = chain.BlockByHash(lastBlockHash)
  2903  		if err != nil {
  2904  			return nil, &btcjson.RPCError{
  2905  				Code:    btcjson.ErrRPCBlockNotFound,
  2906  				Message: "Error getting block: " + err.Error(),
  2907  			}
  2908  		}
  2909  	}
  2910  
  2911  	// Notify websocket client of the finished rescan.  Due to how btcd
  2912  	// asynchronously queues notifications to not block calling code,
  2913  	// there is no guarantee that any of the notifications created during
  2914  	// rescan (such as rescanprogress, recvtx and redeemingtx) will be
  2915  	// received before the rescan RPC returns.  Therefore, another method
  2916  	// is needed to safely inform clients that all rescan notifications have
  2917  	// been sent.
  2918  	n := btcjson.NewRescanFinishedNtfn(
  2919  		lastBlockHash.String(), lastBlock.Height(),
  2920  		lastBlock.MsgBlock().Header.Timestamp.Unix(),
  2921  	)
  2922  	if mn, err := btcjson.MarshalCmd(btcjson.RpcVersion1, nil, n); err != nil {
  2923  		rpcsLog.Errorf("Failed to marshal rescan finished "+
  2924  			"notification: %v", err)
  2925  	} else {
  2926  		// The rescan is finished, so we don't care whether the client
  2927  		// has disconnected at this point, so discard error.
  2928  		_ = wsc.QueueNotification(mn)
  2929  	}
  2930  
  2931  	rpcsLog.Info("Finished rescan")
  2932  	return nil, nil
  2933  }
  2934  
  2935  func init() {
  2936  	wsHandlers = wsHandlersBeforeInit
  2937  }