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

     1  // Copyright (c) 2014-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 rpcclient
     7  
     8  import (
     9  	"bytes"
    10  	"encoding/hex"
    11  	"encoding/json"
    12  	"errors"
    13  	"fmt"
    14  	"time"
    15  
    16  	"github.com/palcoin-project/palcd/btcjson"
    17  	"github.com/palcoin-project/palcd/chaincfg/chainhash"
    18  	"github.com/palcoin-project/palcd/wire"
    19  	"github.com/palcoin-project/palcutil"
    20  )
    21  
    22  var (
    23  	// ErrWebsocketsRequired is an error to describe the condition where the
    24  	// caller is trying to use a websocket-only feature, such as requesting
    25  	// notifications or other websocket requests when the client is
    26  	// configured to run in HTTP POST mode.
    27  	ErrWebsocketsRequired = errors.New("a websocket connection is required " +
    28  		"to use this feature")
    29  )
    30  
    31  // notificationState is used to track the current state of successfully
    32  // registered notification so the state can be automatically re-established on
    33  // reconnect.
    34  type notificationState struct {
    35  	notifyBlocks       bool
    36  	notifyNewTx        bool
    37  	notifyNewTxVerbose bool
    38  	notifyReceived     map[string]struct{}
    39  	notifySpent        map[btcjson.OutPoint]struct{}
    40  }
    41  
    42  // Copy returns a deep copy of the receiver.
    43  func (s *notificationState) Copy() *notificationState {
    44  	var stateCopy notificationState
    45  	stateCopy.notifyBlocks = s.notifyBlocks
    46  	stateCopy.notifyNewTx = s.notifyNewTx
    47  	stateCopy.notifyNewTxVerbose = s.notifyNewTxVerbose
    48  	stateCopy.notifyReceived = make(map[string]struct{})
    49  	for addr := range s.notifyReceived {
    50  		stateCopy.notifyReceived[addr] = struct{}{}
    51  	}
    52  	stateCopy.notifySpent = make(map[btcjson.OutPoint]struct{})
    53  	for op := range s.notifySpent {
    54  		stateCopy.notifySpent[op] = struct{}{}
    55  	}
    56  
    57  	return &stateCopy
    58  }
    59  
    60  // newNotificationState returns a new notification state ready to be populated.
    61  func newNotificationState() *notificationState {
    62  	return &notificationState{
    63  		notifyReceived: make(map[string]struct{}),
    64  		notifySpent:    make(map[btcjson.OutPoint]struct{}),
    65  	}
    66  }
    67  
    68  // newNilFutureResult returns a new future result channel that already has the
    69  // result waiting on the channel with the reply set to nil.  This is useful
    70  // to ignore things such as notifications when the caller didn't specify any
    71  // notification handlers.
    72  func newNilFutureResult() chan *response {
    73  	responseChan := make(chan *response, 1)
    74  	responseChan <- &response{result: nil, err: nil}
    75  	return responseChan
    76  }
    77  
    78  // NotificationHandlers defines callback function pointers to invoke with
    79  // notifications.  Since all of the functions are nil by default, all
    80  // notifications are effectively ignored until their handlers are set to a
    81  // concrete callback.
    82  //
    83  // NOTE: Unless otherwise documented, these handlers must NOT directly call any
    84  // blocking calls on the client instance since the input reader goroutine blocks
    85  // until the callback has completed.  Doing so will result in a deadlock
    86  // situation.
    87  type NotificationHandlers struct {
    88  	// OnClientConnected is invoked when the client connects or reconnects
    89  	// to the RPC server.  This callback is run async with the rest of the
    90  	// notification handlers, and is safe for blocking client requests.
    91  	OnClientConnected func()
    92  
    93  	// OnBlockConnected is invoked when a block is connected to the longest
    94  	// (best) chain.  It will only be invoked if a preceding call to
    95  	// NotifyBlocks has been made to register for the notification and the
    96  	// function is non-nil.
    97  	//
    98  	// Deprecated: Use OnFilteredBlockConnected instead.
    99  	OnBlockConnected func(hash *chainhash.Hash, height int32, t time.Time)
   100  
   101  	// OnFilteredBlockConnected is invoked when a block is connected to the
   102  	// longest (best) chain.  It will only be invoked if a preceding call to
   103  	// NotifyBlocks has been made to register for the notification and the
   104  	// function is non-nil.  Its parameters differ from OnBlockConnected: it
   105  	// receives the block's height, header, and relevant transactions.
   106  	OnFilteredBlockConnected func(height int32, header *wire.BlockHeader,
   107  		txs []*palcutil.Tx)
   108  
   109  	// OnBlockDisconnected is invoked when a block is disconnected from the
   110  	// longest (best) chain.  It will only be invoked if a preceding call to
   111  	// NotifyBlocks has been made to register for the notification and the
   112  	// function is non-nil.
   113  	//
   114  	// Deprecated: Use OnFilteredBlockDisconnected instead.
   115  	OnBlockDisconnected func(hash *chainhash.Hash, height int32, t time.Time)
   116  
   117  	// OnFilteredBlockDisconnected is invoked when a block is disconnected
   118  	// from the longest (best) chain.  It will only be invoked if a
   119  	// preceding NotifyBlocks has been made to register for the notification
   120  	// and the call to function is non-nil.  Its parameters differ from
   121  	// OnBlockDisconnected: it receives the block's height and header.
   122  	OnFilteredBlockDisconnected func(height int32, header *wire.BlockHeader)
   123  
   124  	// OnRecvTx is invoked when a transaction that receives funds to a
   125  	// registered address is received into the memory pool and also
   126  	// connected to the longest (best) chain.  It will only be invoked if a
   127  	// preceding call to NotifyReceived, Rescan, or RescanEndHeight has been
   128  	// made to register for the notification and the function is non-nil.
   129  	//
   130  	// Deprecated: Use OnRelevantTxAccepted instead.
   131  	OnRecvTx func(transaction *palcutil.Tx, details *btcjson.BlockDetails)
   132  
   133  	// OnRedeemingTx is invoked when a transaction that spends a registered
   134  	// outpoint is received into the memory pool and also connected to the
   135  	// longest (best) chain.  It will only be invoked if a preceding call to
   136  	// NotifySpent, Rescan, or RescanEndHeight has been made to register for
   137  	// the notification and the function is non-nil.
   138  	//
   139  	// NOTE: The NotifyReceived will automatically register notifications
   140  	// for the outpoints that are now "owned" as a result of receiving
   141  	// funds to the registered addresses.  This means it is possible for
   142  	// this to invoked indirectly as the result of a NotifyReceived call.
   143  	//
   144  	// Deprecated: Use OnRelevantTxAccepted instead.
   145  	OnRedeemingTx func(transaction *palcutil.Tx, details *btcjson.BlockDetails)
   146  
   147  	// OnRelevantTxAccepted is invoked when an unmined transaction passes
   148  	// the client's transaction filter.
   149  	//
   150  	// NOTE: This is a btcsuite extension ported from
   151  	// github.com/decred/dcrrpcclient.
   152  	OnRelevantTxAccepted func(transaction []byte)
   153  
   154  	// OnRescanFinished is invoked after a rescan finishes due to a previous
   155  	// call to Rescan or RescanEndHeight.  Finished rescans should be
   156  	// signaled on this notification, rather than relying on the return
   157  	// result of a rescan request, due to how btcd may send various rescan
   158  	// notifications after the rescan request has already returned.
   159  	//
   160  	// Deprecated: Not used with RescanBlocks.
   161  	OnRescanFinished func(hash *chainhash.Hash, height int32, blkTime time.Time)
   162  
   163  	// OnRescanProgress is invoked periodically when a rescan is underway.
   164  	// It will only be invoked if a preceding call to Rescan or
   165  	// RescanEndHeight has been made and the function is non-nil.
   166  	//
   167  	// Deprecated: Not used with RescanBlocks.
   168  	OnRescanProgress func(hash *chainhash.Hash, height int32, blkTime time.Time)
   169  
   170  	// OnTxAccepted is invoked when a transaction is accepted into the
   171  	// memory pool.  It will only be invoked if a preceding call to
   172  	// NotifyNewTransactions with the verbose flag set to false has been
   173  	// made to register for the notification and the function is non-nil.
   174  	OnTxAccepted func(hash *chainhash.Hash, amount palcutil.Amount)
   175  
   176  	// OnTxAccepted is invoked when a transaction is accepted into the
   177  	// memory pool.  It will only be invoked if a preceding call to
   178  	// NotifyNewTransactions with the verbose flag set to true has been
   179  	// made to register for the notification and the function is non-nil.
   180  	OnTxAcceptedVerbose func(txDetails *btcjson.TxRawResult)
   181  
   182  	// OnBtcdConnected is invoked when a wallet connects or disconnects from
   183  	// palcd.
   184  	//
   185  	// This will only be available when client is connected to a wallet
   186  	// server such as btcwallet.
   187  	OnBtcdConnected func(connected bool)
   188  
   189  	// OnAccountBalance is invoked with account balance updates.
   190  	//
   191  	// This will only be available when speaking to a wallet server
   192  	// such as btcwallet.
   193  	OnAccountBalance func(account string, balance palcutil.Amount, confirmed bool)
   194  
   195  	// OnWalletLockState is invoked when a wallet is locked or unlocked.
   196  	//
   197  	// This will only be available when client is connected to a wallet
   198  	// server such as btcwallet.
   199  	OnWalletLockState func(locked bool)
   200  
   201  	// OnUnknownNotification is invoked when an unrecognized notification
   202  	// is received.  This typically means the notification handling code
   203  	// for this package needs to be updated for a new notification type or
   204  	// the caller is using a custom notification this package does not know
   205  	// about.
   206  	OnUnknownNotification func(method string, params []json.RawMessage)
   207  }
   208  
   209  // handleNotification examines the passed notification type, performs
   210  // conversions to get the raw notification types into higher level types and
   211  // delivers the notification to the appropriate On<X> handler registered with
   212  // the client.
   213  func (c *Client) handleNotification(ntfn *rawNotification) {
   214  	// Ignore the notification if the client is not interested in any
   215  	// notifications.
   216  	if c.ntfnHandlers == nil {
   217  		return
   218  	}
   219  
   220  	switch ntfn.Method {
   221  	// OnBlockConnected
   222  	case btcjson.BlockConnectedNtfnMethod:
   223  		// Ignore the notification if the client is not interested in
   224  		// it.
   225  		if c.ntfnHandlers.OnBlockConnected == nil {
   226  			return
   227  		}
   228  
   229  		blockHash, blockHeight, blockTime, err := parseChainNtfnParams(ntfn.Params)
   230  		if err != nil {
   231  			log.Warnf("Received invalid block connected "+
   232  				"notification: %v", err)
   233  			return
   234  		}
   235  
   236  		c.ntfnHandlers.OnBlockConnected(blockHash, blockHeight, blockTime)
   237  
   238  	// OnFilteredBlockConnected
   239  	case btcjson.FilteredBlockConnectedNtfnMethod:
   240  		// Ignore the notification if the client is not interested in
   241  		// it.
   242  		if c.ntfnHandlers.OnFilteredBlockConnected == nil {
   243  			return
   244  		}
   245  
   246  		blockHeight, blockHeader, transactions, err :=
   247  			parseFilteredBlockConnectedParams(ntfn.Params)
   248  		if err != nil {
   249  			log.Warnf("Received invalid filtered block "+
   250  				"connected notification: %v", err)
   251  			return
   252  		}
   253  
   254  		c.ntfnHandlers.OnFilteredBlockConnected(blockHeight,
   255  			blockHeader, transactions)
   256  
   257  	// OnBlockDisconnected
   258  	case btcjson.BlockDisconnectedNtfnMethod:
   259  		// Ignore the notification if the client is not interested in
   260  		// it.
   261  		if c.ntfnHandlers.OnBlockDisconnected == nil {
   262  			return
   263  		}
   264  
   265  		blockHash, blockHeight, blockTime, err := parseChainNtfnParams(ntfn.Params)
   266  		if err != nil {
   267  			log.Warnf("Received invalid block connected "+
   268  				"notification: %v", err)
   269  			return
   270  		}
   271  
   272  		c.ntfnHandlers.OnBlockDisconnected(blockHash, blockHeight, blockTime)
   273  
   274  	// OnFilteredBlockDisconnected
   275  	case btcjson.FilteredBlockDisconnectedNtfnMethod:
   276  		// Ignore the notification if the client is not interested in
   277  		// it.
   278  		if c.ntfnHandlers.OnFilteredBlockDisconnected == nil {
   279  			return
   280  		}
   281  
   282  		blockHeight, blockHeader, err :=
   283  			parseFilteredBlockDisconnectedParams(ntfn.Params)
   284  		if err != nil {
   285  			log.Warnf("Received invalid filtered block "+
   286  				"disconnected notification: %v", err)
   287  			return
   288  		}
   289  
   290  		c.ntfnHandlers.OnFilteredBlockDisconnected(blockHeight,
   291  			blockHeader)
   292  
   293  	// OnRecvTx
   294  	case btcjson.RecvTxNtfnMethod:
   295  		// Ignore the notification if the client is not interested in
   296  		// it.
   297  		if c.ntfnHandlers.OnRecvTx == nil {
   298  			return
   299  		}
   300  
   301  		tx, block, err := parseChainTxNtfnParams(ntfn.Params)
   302  		if err != nil {
   303  			log.Warnf("Received invalid recvtx notification: %v",
   304  				err)
   305  			return
   306  		}
   307  
   308  		c.ntfnHandlers.OnRecvTx(tx, block)
   309  
   310  	// OnRedeemingTx
   311  	case btcjson.RedeemingTxNtfnMethod:
   312  		// Ignore the notification if the client is not interested in
   313  		// it.
   314  		if c.ntfnHandlers.OnRedeemingTx == nil {
   315  			return
   316  		}
   317  
   318  		tx, block, err := parseChainTxNtfnParams(ntfn.Params)
   319  		if err != nil {
   320  			log.Warnf("Received invalid redeemingtx "+
   321  				"notification: %v", err)
   322  			return
   323  		}
   324  
   325  		c.ntfnHandlers.OnRedeemingTx(tx, block)
   326  
   327  	// OnRelevantTxAccepted
   328  	case btcjson.RelevantTxAcceptedNtfnMethod:
   329  		// Ignore the notification if the client is not interested in
   330  		// it.
   331  		if c.ntfnHandlers.OnRelevantTxAccepted == nil {
   332  			return
   333  		}
   334  
   335  		transaction, err := parseRelevantTxAcceptedParams(ntfn.Params)
   336  		if err != nil {
   337  			log.Warnf("Received invalid relevanttxaccepted "+
   338  				"notification: %v", err)
   339  			return
   340  		}
   341  
   342  		c.ntfnHandlers.OnRelevantTxAccepted(transaction)
   343  
   344  	// OnRescanFinished
   345  	case btcjson.RescanFinishedNtfnMethod:
   346  		// Ignore the notification if the client is not interested in
   347  		// it.
   348  		if c.ntfnHandlers.OnRescanFinished == nil {
   349  			return
   350  		}
   351  
   352  		hash, height, blkTime, err := parseRescanProgressParams(ntfn.Params)
   353  		if err != nil {
   354  			log.Warnf("Received invalid rescanfinished "+
   355  				"notification: %v", err)
   356  			return
   357  		}
   358  
   359  		c.ntfnHandlers.OnRescanFinished(hash, height, blkTime)
   360  
   361  	// OnRescanProgress
   362  	case btcjson.RescanProgressNtfnMethod:
   363  		// Ignore the notification if the client is not interested in
   364  		// it.
   365  		if c.ntfnHandlers.OnRescanProgress == nil {
   366  			return
   367  		}
   368  
   369  		hash, height, blkTime, err := parseRescanProgressParams(ntfn.Params)
   370  		if err != nil {
   371  			log.Warnf("Received invalid rescanprogress "+
   372  				"notification: %v", err)
   373  			return
   374  		}
   375  
   376  		c.ntfnHandlers.OnRescanProgress(hash, height, blkTime)
   377  
   378  	// OnTxAccepted
   379  	case btcjson.TxAcceptedNtfnMethod:
   380  		// Ignore the notification if the client is not interested in
   381  		// it.
   382  		if c.ntfnHandlers.OnTxAccepted == nil {
   383  			return
   384  		}
   385  
   386  		hash, amt, err := parseTxAcceptedNtfnParams(ntfn.Params)
   387  		if err != nil {
   388  			log.Warnf("Received invalid tx accepted "+
   389  				"notification: %v", err)
   390  			return
   391  		}
   392  
   393  		c.ntfnHandlers.OnTxAccepted(hash, amt)
   394  
   395  	// OnTxAcceptedVerbose
   396  	case btcjson.TxAcceptedVerboseNtfnMethod:
   397  		// Ignore the notification if the client is not interested in
   398  		// it.
   399  		if c.ntfnHandlers.OnTxAcceptedVerbose == nil {
   400  			return
   401  		}
   402  
   403  		rawTx, err := parseTxAcceptedVerboseNtfnParams(ntfn.Params)
   404  		if err != nil {
   405  			log.Warnf("Received invalid tx accepted verbose "+
   406  				"notification: %v", err)
   407  			return
   408  		}
   409  
   410  		c.ntfnHandlers.OnTxAcceptedVerbose(rawTx)
   411  
   412  	// OnBtcdConnected
   413  	case btcjson.BtcdConnectedNtfnMethod:
   414  		// Ignore the notification if the client is not interested in
   415  		// it.
   416  		if c.ntfnHandlers.OnBtcdConnected == nil {
   417  			return
   418  		}
   419  
   420  		connected, err := parseBtcdConnectedNtfnParams(ntfn.Params)
   421  		if err != nil {
   422  			log.Warnf("Received invalid btcd connected "+
   423  				"notification: %v", err)
   424  			return
   425  		}
   426  
   427  		c.ntfnHandlers.OnBtcdConnected(connected)
   428  
   429  	// OnAccountBalance
   430  	case btcjson.AccountBalanceNtfnMethod:
   431  		// Ignore the notification if the client is not interested in
   432  		// it.
   433  		if c.ntfnHandlers.OnAccountBalance == nil {
   434  			return
   435  		}
   436  
   437  		account, bal, conf, err := parseAccountBalanceNtfnParams(ntfn.Params)
   438  		if err != nil {
   439  			log.Warnf("Received invalid account balance "+
   440  				"notification: %v", err)
   441  			return
   442  		}
   443  
   444  		c.ntfnHandlers.OnAccountBalance(account, bal, conf)
   445  
   446  	// OnWalletLockState
   447  	case btcjson.WalletLockStateNtfnMethod:
   448  		// Ignore the notification if the client is not interested in
   449  		// it.
   450  		if c.ntfnHandlers.OnWalletLockState == nil {
   451  			return
   452  		}
   453  
   454  		// The account name is not notified, so the return value is
   455  		// discarded.
   456  		_, locked, err := parseWalletLockStateNtfnParams(ntfn.Params)
   457  		if err != nil {
   458  			log.Warnf("Received invalid wallet lock state "+
   459  				"notification: %v", err)
   460  			return
   461  		}
   462  
   463  		c.ntfnHandlers.OnWalletLockState(locked)
   464  
   465  	// OnUnknownNotification
   466  	default:
   467  		if c.ntfnHandlers.OnUnknownNotification == nil {
   468  			return
   469  		}
   470  
   471  		c.ntfnHandlers.OnUnknownNotification(ntfn.Method, ntfn.Params)
   472  	}
   473  }
   474  
   475  // wrongNumParams is an error type describing an unparseable JSON-RPC
   476  // notificiation due to an incorrect number of parameters for the
   477  // expected notification type.  The value is the number of parameters
   478  // of the invalid notification.
   479  type wrongNumParams int
   480  
   481  // Error satisifies the builtin error interface.
   482  func (e wrongNumParams) Error() string {
   483  	return fmt.Sprintf("wrong number of parameters (%d)", e)
   484  }
   485  
   486  // parseChainNtfnParams parses out the block hash and height from the parameters
   487  // of blockconnected and blockdisconnected notifications.
   488  func parseChainNtfnParams(params []json.RawMessage) (*chainhash.Hash,
   489  	int32, time.Time, error) {
   490  
   491  	if len(params) != 3 {
   492  		return nil, 0, time.Time{}, wrongNumParams(len(params))
   493  	}
   494  
   495  	// Unmarshal first parameter as a string.
   496  	var blockHashStr string
   497  	err := json.Unmarshal(params[0], &blockHashStr)
   498  	if err != nil {
   499  		return nil, 0, time.Time{}, err
   500  	}
   501  
   502  	// Unmarshal second parameter as an integer.
   503  	var blockHeight int32
   504  	err = json.Unmarshal(params[1], &blockHeight)
   505  	if err != nil {
   506  		return nil, 0, time.Time{}, err
   507  	}
   508  
   509  	// Unmarshal third parameter as unix time.
   510  	var blockTimeUnix int64
   511  	err = json.Unmarshal(params[2], &blockTimeUnix)
   512  	if err != nil {
   513  		return nil, 0, time.Time{}, err
   514  	}
   515  
   516  	// Create hash from block hash string.
   517  	blockHash, err := chainhash.NewHashFromStr(blockHashStr)
   518  	if err != nil {
   519  		return nil, 0, time.Time{}, err
   520  	}
   521  
   522  	// Create time.Time from unix time.
   523  	blockTime := time.Unix(blockTimeUnix, 0)
   524  
   525  	return blockHash, blockHeight, blockTime, nil
   526  }
   527  
   528  // parseFilteredBlockConnectedParams parses out the parameters included in a
   529  // filteredblockconnected notification.
   530  //
   531  // NOTE: This is a btcd extension ported from github.com/decred/dcrrpcclient
   532  // and requires a websocket connection.
   533  func parseFilteredBlockConnectedParams(params []json.RawMessage) (int32,
   534  	*wire.BlockHeader, []*palcutil.Tx, error) {
   535  
   536  	if len(params) < 3 {
   537  		return 0, nil, nil, wrongNumParams(len(params))
   538  	}
   539  
   540  	// Unmarshal first parameter as an integer.
   541  	var blockHeight int32
   542  	err := json.Unmarshal(params[0], &blockHeight)
   543  	if err != nil {
   544  		return 0, nil, nil, err
   545  	}
   546  
   547  	// Unmarshal second parameter as a slice of bytes.
   548  	blockHeaderBytes, err := parseHexParam(params[1])
   549  	if err != nil {
   550  		return 0, nil, nil, err
   551  	}
   552  
   553  	// Deserialize block header from slice of bytes.
   554  	var blockHeader wire.BlockHeader
   555  	err = blockHeader.Deserialize(bytes.NewReader(blockHeaderBytes))
   556  	if err != nil {
   557  		return 0, nil, nil, err
   558  	}
   559  
   560  	// Unmarshal third parameter as a slice of hex-encoded strings.
   561  	var hexTransactions []string
   562  	err = json.Unmarshal(params[2], &hexTransactions)
   563  	if err != nil {
   564  		return 0, nil, nil, err
   565  	}
   566  
   567  	// Create slice of transactions from slice of strings by hex-decoding.
   568  	transactions := make([]*palcutil.Tx, len(hexTransactions))
   569  	for i, hexTx := range hexTransactions {
   570  		transaction, err := hex.DecodeString(hexTx)
   571  		if err != nil {
   572  			return 0, nil, nil, err
   573  		}
   574  
   575  		transactions[i], err = palcutil.NewTxFromBytes(transaction)
   576  		if err != nil {
   577  			return 0, nil, nil, err
   578  		}
   579  	}
   580  
   581  	return blockHeight, &blockHeader, transactions, nil
   582  }
   583  
   584  // parseFilteredBlockDisconnectedParams parses out the parameters included in a
   585  // filteredblockdisconnected notification.
   586  //
   587  // NOTE: This is a btcd extension ported from github.com/decred/dcrrpcclient
   588  // and requires a websocket connection.
   589  func parseFilteredBlockDisconnectedParams(params []json.RawMessage) (int32,
   590  	*wire.BlockHeader, error) {
   591  	if len(params) < 2 {
   592  		return 0, nil, wrongNumParams(len(params))
   593  	}
   594  
   595  	// Unmarshal first parameter as an integer.
   596  	var blockHeight int32
   597  	err := json.Unmarshal(params[0], &blockHeight)
   598  	if err != nil {
   599  		return 0, nil, err
   600  	}
   601  
   602  	// Unmarshal second parmeter as a slice of bytes.
   603  	blockHeaderBytes, err := parseHexParam(params[1])
   604  	if err != nil {
   605  		return 0, nil, err
   606  	}
   607  
   608  	// Deserialize block header from slice of bytes.
   609  	var blockHeader wire.BlockHeader
   610  	err = blockHeader.Deserialize(bytes.NewReader(blockHeaderBytes))
   611  	if err != nil {
   612  		return 0, nil, err
   613  	}
   614  
   615  	return blockHeight, &blockHeader, nil
   616  }
   617  
   618  func parseHexParam(param json.RawMessage) ([]byte, error) {
   619  	var s string
   620  	err := json.Unmarshal(param, &s)
   621  	if err != nil {
   622  		return nil, err
   623  	}
   624  	return hex.DecodeString(s)
   625  }
   626  
   627  // parseRelevantTxAcceptedParams parses out the parameter included in a
   628  // relevanttxaccepted notification.
   629  func parseRelevantTxAcceptedParams(params []json.RawMessage) (transaction []byte, err error) {
   630  	if len(params) < 1 {
   631  		return nil, wrongNumParams(len(params))
   632  	}
   633  
   634  	return parseHexParam(params[0])
   635  }
   636  
   637  // parseChainTxNtfnParams parses out the transaction and optional details about
   638  // the block it's mined in from the parameters of recvtx and redeemingtx
   639  // notifications.
   640  func parseChainTxNtfnParams(params []json.RawMessage) (*palcutil.Tx,
   641  	*btcjson.BlockDetails, error) {
   642  
   643  	if len(params) == 0 || len(params) > 2 {
   644  		return nil, nil, wrongNumParams(len(params))
   645  	}
   646  
   647  	// Unmarshal first parameter as a string.
   648  	var txHex string
   649  	err := json.Unmarshal(params[0], &txHex)
   650  	if err != nil {
   651  		return nil, nil, err
   652  	}
   653  
   654  	// If present, unmarshal second optional parameter as the block details
   655  	// JSON object.
   656  	var block *btcjson.BlockDetails
   657  	if len(params) > 1 {
   658  		err = json.Unmarshal(params[1], &block)
   659  		if err != nil {
   660  			return nil, nil, err
   661  		}
   662  	}
   663  
   664  	// Hex decode and deserialize the transaction.
   665  	serializedTx, err := hex.DecodeString(txHex)
   666  	if err != nil {
   667  		return nil, nil, err
   668  	}
   669  	var msgTx wire.MsgTx
   670  	err = msgTx.Deserialize(bytes.NewReader(serializedTx))
   671  	if err != nil {
   672  		return nil, nil, err
   673  	}
   674  
   675  	// TODO: Change recvtx and redeemingtx callback signatures to use
   676  	// nicer types for details about the block (block hash as a
   677  	// chainhash.Hash, block time as a time.Time, etc.).
   678  	return palcutil.NewTx(&msgTx), block, nil
   679  }
   680  
   681  // parseRescanProgressParams parses out the height of the last rescanned block
   682  // from the parameters of rescanfinished and rescanprogress notifications.
   683  func parseRescanProgressParams(params []json.RawMessage) (*chainhash.Hash, int32, time.Time, error) {
   684  	if len(params) != 3 {
   685  		return nil, 0, time.Time{}, wrongNumParams(len(params))
   686  	}
   687  
   688  	// Unmarshal first parameter as an string.
   689  	var hashStr string
   690  	err := json.Unmarshal(params[0], &hashStr)
   691  	if err != nil {
   692  		return nil, 0, time.Time{}, err
   693  	}
   694  
   695  	// Unmarshal second parameter as an integer.
   696  	var height int32
   697  	err = json.Unmarshal(params[1], &height)
   698  	if err != nil {
   699  		return nil, 0, time.Time{}, err
   700  	}
   701  
   702  	// Unmarshal third parameter as an integer.
   703  	var blkTime int64
   704  	err = json.Unmarshal(params[2], &blkTime)
   705  	if err != nil {
   706  		return nil, 0, time.Time{}, err
   707  	}
   708  
   709  	// Decode string encoding of block hash.
   710  	hash, err := chainhash.NewHashFromStr(hashStr)
   711  	if err != nil {
   712  		return nil, 0, time.Time{}, err
   713  	}
   714  
   715  	return hash, height, time.Unix(blkTime, 0), nil
   716  }
   717  
   718  // parseTxAcceptedNtfnParams parses out the transaction hash and total amount
   719  // from the parameters of a txaccepted notification.
   720  func parseTxAcceptedNtfnParams(params []json.RawMessage) (*chainhash.Hash,
   721  	palcutil.Amount, error) {
   722  
   723  	if len(params) != 2 {
   724  		return nil, 0, wrongNumParams(len(params))
   725  	}
   726  
   727  	// Unmarshal first parameter as a string.
   728  	var txHashStr string
   729  	err := json.Unmarshal(params[0], &txHashStr)
   730  	if err != nil {
   731  		return nil, 0, err
   732  	}
   733  
   734  	// Unmarshal second parameter as a floating point number.
   735  	var famt float64
   736  	err = json.Unmarshal(params[1], &famt)
   737  	if err != nil {
   738  		return nil, 0, err
   739  	}
   740  
   741  	// Bounds check amount.
   742  	amt, err := palcutil.NewAmount(famt)
   743  	if err != nil {
   744  		return nil, 0, err
   745  	}
   746  
   747  	// Decode string encoding of transaction sha.
   748  	txHash, err := chainhash.NewHashFromStr(txHashStr)
   749  	if err != nil {
   750  		return nil, 0, err
   751  	}
   752  
   753  	return txHash, amt, nil
   754  }
   755  
   756  // parseTxAcceptedVerboseNtfnParams parses out details about a raw transaction
   757  // from the parameters of a txacceptedverbose notification.
   758  func parseTxAcceptedVerboseNtfnParams(params []json.RawMessage) (*btcjson.TxRawResult,
   759  	error) {
   760  
   761  	if len(params) != 1 {
   762  		return nil, wrongNumParams(len(params))
   763  	}
   764  
   765  	// Unmarshal first parameter as a raw transaction result object.
   766  	var rawTx btcjson.TxRawResult
   767  	err := json.Unmarshal(params[0], &rawTx)
   768  	if err != nil {
   769  		return nil, err
   770  	}
   771  
   772  	// TODO: change txacceptedverbose notification callbacks to use nicer
   773  	// types for all details about the transaction (i.e. decoding hashes
   774  	// from their string encoding).
   775  	return &rawTx, nil
   776  }
   777  
   778  // parseBtcdConnectedNtfnParams parses out the connection status of btcd
   779  // and btcwallet from the parameters of a btcdconnected notification.
   780  func parseBtcdConnectedNtfnParams(params []json.RawMessage) (bool, error) {
   781  	if len(params) != 1 {
   782  		return false, wrongNumParams(len(params))
   783  	}
   784  
   785  	// Unmarshal first parameter as a boolean.
   786  	var connected bool
   787  	err := json.Unmarshal(params[0], &connected)
   788  	if err != nil {
   789  		return false, err
   790  	}
   791  
   792  	return connected, nil
   793  }
   794  
   795  // parseAccountBalanceNtfnParams parses out the account name, total balance,
   796  // and whether or not the balance is confirmed or unconfirmed from the
   797  // parameters of an accountbalance notification.
   798  func parseAccountBalanceNtfnParams(params []json.RawMessage) (account string,
   799  	balance palcutil.Amount, confirmed bool, err error) {
   800  
   801  	if len(params) != 3 {
   802  		return "", 0, false, wrongNumParams(len(params))
   803  	}
   804  
   805  	// Unmarshal first parameter as a string.
   806  	err = json.Unmarshal(params[0], &account)
   807  	if err != nil {
   808  		return "", 0, false, err
   809  	}
   810  
   811  	// Unmarshal second parameter as a floating point number.
   812  	var fbal float64
   813  	err = json.Unmarshal(params[1], &fbal)
   814  	if err != nil {
   815  		return "", 0, false, err
   816  	}
   817  
   818  	// Unmarshal third parameter as a boolean.
   819  	err = json.Unmarshal(params[2], &confirmed)
   820  	if err != nil {
   821  		return "", 0, false, err
   822  	}
   823  
   824  	// Bounds check amount.
   825  	bal, err := palcutil.NewAmount(fbal)
   826  	if err != nil {
   827  		return "", 0, false, err
   828  	}
   829  
   830  	return account, bal, confirmed, nil
   831  }
   832  
   833  // parseWalletLockStateNtfnParams parses out the account name and locked
   834  // state of an account from the parameters of a walletlockstate notification.
   835  func parseWalletLockStateNtfnParams(params []json.RawMessage) (account string,
   836  	locked bool, err error) {
   837  
   838  	if len(params) != 2 {
   839  		return "", false, wrongNumParams(len(params))
   840  	}
   841  
   842  	// Unmarshal first parameter as a string.
   843  	err = json.Unmarshal(params[0], &account)
   844  	if err != nil {
   845  		return "", false, err
   846  	}
   847  
   848  	// Unmarshal second parameter as a boolean.
   849  	err = json.Unmarshal(params[1], &locked)
   850  	if err != nil {
   851  		return "", false, err
   852  	}
   853  
   854  	return account, locked, nil
   855  }
   856  
   857  // FutureNotifyBlocksResult is a future promise to deliver the result of a
   858  // NotifyBlocksAsync RPC invocation (or an applicable error).
   859  type FutureNotifyBlocksResult chan *response
   860  
   861  // Receive waits for the response promised by the future and returns an error
   862  // if the registration was not successful.
   863  func (r FutureNotifyBlocksResult) Receive() error {
   864  	_, err := receiveFuture(r)
   865  	return err
   866  }
   867  
   868  // NotifyBlocksAsync returns an instance of a type that can be used to get the
   869  // result of the RPC at some future time by invoking the Receive function on
   870  // the returned instance.
   871  //
   872  // See NotifyBlocks for the blocking version and more details.
   873  //
   874  // NOTE: This is a btcd extension and requires a websocket connection.
   875  func (c *Client) NotifyBlocksAsync() FutureNotifyBlocksResult {
   876  	// Not supported in HTTP POST mode.
   877  	if c.config.HTTPPostMode {
   878  		return newFutureError(ErrWebsocketsRequired)
   879  	}
   880  
   881  	// Ignore the notification if the client is not interested in
   882  	// notifications.
   883  	if c.ntfnHandlers == nil {
   884  		return newNilFutureResult()
   885  	}
   886  
   887  	cmd := btcjson.NewNotifyBlocksCmd()
   888  	return c.sendCmd(cmd)
   889  }
   890  
   891  // NotifyBlocks registers the client to receive notifications when blocks are
   892  // connected and disconnected from the main chain.  The notifications are
   893  // delivered to the notification handlers associated with the client.  Calling
   894  // this function has no effect if there are no notification handlers and will
   895  // result in an error if the client is configured to run in HTTP POST mode.
   896  //
   897  // The notifications delivered as a result of this call will be via one of
   898  // OnBlockConnected or OnBlockDisconnected.
   899  //
   900  // NOTE: This is a btcd extension and requires a websocket connection.
   901  func (c *Client) NotifyBlocks() error {
   902  	return c.NotifyBlocksAsync().Receive()
   903  }
   904  
   905  // FutureNotifySpentResult is a future promise to deliver the result of a
   906  // NotifySpentAsync RPC invocation (or an applicable error).
   907  //
   908  // Deprecated: Use FutureLoadTxFilterResult instead.
   909  type FutureNotifySpentResult chan *response
   910  
   911  // Receive waits for the response promised by the future and returns an error
   912  // if the registration was not successful.
   913  func (r FutureNotifySpentResult) Receive() error {
   914  	_, err := receiveFuture(r)
   915  	return err
   916  }
   917  
   918  // notifySpentInternal is the same as notifySpentAsync except it accepts
   919  // the converted outpoints as a parameter so the client can more efficiently
   920  // recreate the previous notification state on reconnect.
   921  func (c *Client) notifySpentInternal(outpoints []btcjson.OutPoint) FutureNotifySpentResult {
   922  	// Not supported in HTTP POST mode.
   923  	if c.config.HTTPPostMode {
   924  		return newFutureError(ErrWebsocketsRequired)
   925  	}
   926  
   927  	// Ignore the notification if the client is not interested in
   928  	// notifications.
   929  	if c.ntfnHandlers == nil {
   930  		return newNilFutureResult()
   931  	}
   932  
   933  	cmd := btcjson.NewNotifySpentCmd(outpoints)
   934  	return c.sendCmd(cmd)
   935  }
   936  
   937  // newOutPointFromWire constructs the btcjson representation of a transaction
   938  // outpoint from the wire type.
   939  func newOutPointFromWire(op *wire.OutPoint) btcjson.OutPoint {
   940  	return btcjson.OutPoint{
   941  		Hash:  op.Hash.String(),
   942  		Index: op.Index,
   943  	}
   944  }
   945  
   946  // NotifySpentAsync returns an instance of a type that can be used to get the
   947  // result of the RPC at some future time by invoking the Receive function on
   948  // the returned instance.
   949  //
   950  // See NotifySpent for the blocking version and more details.
   951  //
   952  // NOTE: This is a btcd extension and requires a websocket connection.
   953  //
   954  // Deprecated: Use LoadTxFilterAsync instead.
   955  func (c *Client) NotifySpentAsync(outpoints []*wire.OutPoint) FutureNotifySpentResult {
   956  	// Not supported in HTTP POST mode.
   957  	if c.config.HTTPPostMode {
   958  		return newFutureError(ErrWebsocketsRequired)
   959  	}
   960  
   961  	// Ignore the notification if the client is not interested in
   962  	// notifications.
   963  	if c.ntfnHandlers == nil {
   964  		return newNilFutureResult()
   965  	}
   966  
   967  	ops := make([]btcjson.OutPoint, 0, len(outpoints))
   968  	for _, outpoint := range outpoints {
   969  		ops = append(ops, newOutPointFromWire(outpoint))
   970  	}
   971  	cmd := btcjson.NewNotifySpentCmd(ops)
   972  	return c.sendCmd(cmd)
   973  }
   974  
   975  // NotifySpent registers the client to receive notifications when the passed
   976  // transaction outputs are spent.  The notifications are delivered to the
   977  // notification handlers associated with the client.  Calling this function has
   978  // no effect if there are no notification handlers and will result in an error
   979  // if the client is configured to run in HTTP POST mode.
   980  //
   981  // The notifications delivered as a result of this call will be via
   982  // OnRedeemingTx.
   983  //
   984  // NOTE: This is a btcd extension and requires a websocket connection.
   985  //
   986  // Deprecated: Use LoadTxFilter instead.
   987  func (c *Client) NotifySpent(outpoints []*wire.OutPoint) error {
   988  	return c.NotifySpentAsync(outpoints).Receive()
   989  }
   990  
   991  // FutureNotifyNewTransactionsResult is a future promise to deliver the result
   992  // of a NotifyNewTransactionsAsync RPC invocation (or an applicable error).
   993  type FutureNotifyNewTransactionsResult chan *response
   994  
   995  // Receive waits for the response promised by the future and returns an error
   996  // if the registration was not successful.
   997  func (r FutureNotifyNewTransactionsResult) Receive() error {
   998  	_, err := receiveFuture(r)
   999  	return err
  1000  }
  1001  
  1002  // NotifyNewTransactionsAsync returns an instance of a type that can be used to
  1003  // get the result of the RPC at some future time by invoking the Receive
  1004  // function on the returned instance.
  1005  //
  1006  // See NotifyNewTransactionsAsync for the blocking version and more details.
  1007  //
  1008  // NOTE: This is a btcd extension and requires a websocket connection.
  1009  func (c *Client) NotifyNewTransactionsAsync(verbose bool) FutureNotifyNewTransactionsResult {
  1010  	// Not supported in HTTP POST mode.
  1011  	if c.config.HTTPPostMode {
  1012  		return newFutureError(ErrWebsocketsRequired)
  1013  	}
  1014  
  1015  	// Ignore the notification if the client is not interested in
  1016  	// notifications.
  1017  	if c.ntfnHandlers == nil {
  1018  		return newNilFutureResult()
  1019  	}
  1020  
  1021  	cmd := btcjson.NewNotifyNewTransactionsCmd(&verbose)
  1022  	return c.sendCmd(cmd)
  1023  }
  1024  
  1025  // NotifyNewTransactions registers the client to receive notifications every
  1026  // time a new transaction is accepted to the memory pool.  The notifications are
  1027  // delivered to the notification handlers associated with the client.  Calling
  1028  // this function has no effect if there are no notification handlers and will
  1029  // result in an error if the client is configured to run in HTTP POST mode.
  1030  //
  1031  // The notifications delivered as a result of this call will be via one of
  1032  // OnTxAccepted (when verbose is false) or OnTxAcceptedVerbose (when verbose is
  1033  // true).
  1034  //
  1035  // NOTE: This is a btcd extension and requires a websocket connection.
  1036  func (c *Client) NotifyNewTransactions(verbose bool) error {
  1037  	return c.NotifyNewTransactionsAsync(verbose).Receive()
  1038  }
  1039  
  1040  // FutureNotifyReceivedResult is a future promise to deliver the result of a
  1041  // NotifyReceivedAsync RPC invocation (or an applicable error).
  1042  //
  1043  // Deprecated: Use FutureLoadTxFilterResult instead.
  1044  type FutureNotifyReceivedResult chan *response
  1045  
  1046  // Receive waits for the response promised by the future and returns an error
  1047  // if the registration was not successful.
  1048  func (r FutureNotifyReceivedResult) Receive() error {
  1049  	_, err := receiveFuture(r)
  1050  	return err
  1051  }
  1052  
  1053  // notifyReceivedInternal is the same as notifyReceivedAsync except it accepts
  1054  // the converted addresses as a parameter so the client can more efficiently
  1055  // recreate the previous notification state on reconnect.
  1056  func (c *Client) notifyReceivedInternal(addresses []string) FutureNotifyReceivedResult {
  1057  	// Not supported in HTTP POST mode.
  1058  	if c.config.HTTPPostMode {
  1059  		return newFutureError(ErrWebsocketsRequired)
  1060  	}
  1061  
  1062  	// Ignore the notification if the client is not interested in
  1063  	// notifications.
  1064  	if c.ntfnHandlers == nil {
  1065  		return newNilFutureResult()
  1066  	}
  1067  
  1068  	// Convert addresses to strings.
  1069  	cmd := btcjson.NewNotifyReceivedCmd(addresses)
  1070  	return c.sendCmd(cmd)
  1071  }
  1072  
  1073  // NotifyReceivedAsync returns an instance of a type that can be used to get the
  1074  // result of the RPC at some future time by invoking the Receive function on
  1075  // the returned instance.
  1076  //
  1077  // See NotifyReceived for the blocking version and more details.
  1078  //
  1079  // NOTE: This is a btcd extension and requires a websocket connection.
  1080  //
  1081  // Deprecated: Use LoadTxFilterAsync instead.
  1082  func (c *Client) NotifyReceivedAsync(addresses []palcutil.Address) FutureNotifyReceivedResult {
  1083  	// Not supported in HTTP POST mode.
  1084  	if c.config.HTTPPostMode {
  1085  		return newFutureError(ErrWebsocketsRequired)
  1086  	}
  1087  
  1088  	// Ignore the notification if the client is not interested in
  1089  	// notifications.
  1090  	if c.ntfnHandlers == nil {
  1091  		return newNilFutureResult()
  1092  	}
  1093  
  1094  	// Convert addresses to strings.
  1095  	addrs := make([]string, 0, len(addresses))
  1096  	for _, addr := range addresses {
  1097  		addrs = append(addrs, addr.String())
  1098  	}
  1099  	cmd := btcjson.NewNotifyReceivedCmd(addrs)
  1100  	return c.sendCmd(cmd)
  1101  }
  1102  
  1103  // NotifyReceived registers the client to receive notifications every time a
  1104  // new transaction which pays to one of the passed addresses is accepted to
  1105  // memory pool or in a block connected to the block chain.  In addition, when
  1106  // one of these transactions is detected, the client is also automatically
  1107  // registered for notifications when the new transaction outpoints the address
  1108  // now has available are spent (See NotifySpent).  The notifications are
  1109  // delivered to the notification handlers associated with the client.  Calling
  1110  // this function has no effect if there are no notification handlers and will
  1111  // result in an error if the client is configured to run in HTTP POST mode.
  1112  //
  1113  // The notifications delivered as a result of this call will be via one of
  1114  // *OnRecvTx (for transactions that receive funds to one of the passed
  1115  // addresses) or OnRedeemingTx (for transactions which spend from one
  1116  // of the outpoints which are automatically registered upon receipt of funds to
  1117  // the address).
  1118  //
  1119  // NOTE: This is a btcd extension and requires a websocket connection.
  1120  //
  1121  // Deprecated: Use LoadTxFilter instead.
  1122  func (c *Client) NotifyReceived(addresses []palcutil.Address) error {
  1123  	return c.NotifyReceivedAsync(addresses).Receive()
  1124  }
  1125  
  1126  // FutureRescanResult is a future promise to deliver the result of a RescanAsync
  1127  // or RescanEndHeightAsync RPC invocation (or an applicable error).
  1128  //
  1129  // Deprecated: Use FutureRescanBlocksResult instead.
  1130  type FutureRescanResult chan *response
  1131  
  1132  // Receive waits for the response promised by the future and returns an error
  1133  // if the rescan was not successful.
  1134  func (r FutureRescanResult) Receive() error {
  1135  	_, err := receiveFuture(r)
  1136  	return err
  1137  }
  1138  
  1139  // RescanAsync returns an instance of a type that can be used to get the result
  1140  // of the RPC at some future time by invoking the Receive function on the
  1141  // returned instance.
  1142  //
  1143  // See Rescan for the blocking version and more details.
  1144  //
  1145  // NOTE: Rescan requests are not issued on client reconnect and must be
  1146  // performed manually (ideally with a new start height based on the last
  1147  // rescan progress notification).  See the OnClientConnected notification
  1148  // callback for a good callsite to reissue rescan requests on connect and
  1149  // reconnect.
  1150  //
  1151  // NOTE: This is a btcd extension and requires a websocket connection.
  1152  //
  1153  // Deprecated: Use RescanBlocksAsync instead.
  1154  func (c *Client) RescanAsync(startBlock *chainhash.Hash,
  1155  	addresses []palcutil.Address,
  1156  	outpoints []*wire.OutPoint) FutureRescanResult {
  1157  
  1158  	// Not supported in HTTP POST mode.
  1159  	if c.config.HTTPPostMode {
  1160  		return newFutureError(ErrWebsocketsRequired)
  1161  	}
  1162  
  1163  	// Ignore the notification if the client is not interested in
  1164  	// notifications.
  1165  	if c.ntfnHandlers == nil {
  1166  		return newNilFutureResult()
  1167  	}
  1168  
  1169  	// Convert block hashes to strings.
  1170  	var startBlockHashStr string
  1171  	if startBlock != nil {
  1172  		startBlockHashStr = startBlock.String()
  1173  	}
  1174  
  1175  	// Convert addresses to strings.
  1176  	addrs := make([]string, 0, len(addresses))
  1177  	for _, addr := range addresses {
  1178  		addrs = append(addrs, addr.String())
  1179  	}
  1180  
  1181  	// Convert outpoints.
  1182  	ops := make([]btcjson.OutPoint, 0, len(outpoints))
  1183  	for _, op := range outpoints {
  1184  		ops = append(ops, newOutPointFromWire(op))
  1185  	}
  1186  
  1187  	cmd := btcjson.NewRescanCmd(startBlockHashStr, addrs, ops, nil)
  1188  	return c.sendCmd(cmd)
  1189  }
  1190  
  1191  // Rescan rescans the block chain starting from the provided starting block to
  1192  // the end of the longest chain for transactions that pay to the passed
  1193  // addresses and transactions which spend the passed outpoints.
  1194  //
  1195  // The notifications of found transactions are delivered to the notification
  1196  // handlers associated with client and this call will not return until the
  1197  // rescan has completed.  Calling this function has no effect if there are no
  1198  // notification handlers and will result in an error if the client is configured
  1199  // to run in HTTP POST mode.
  1200  //
  1201  // The notifications delivered as a result of this call will be via one of
  1202  // OnRedeemingTx (for transactions which spend from the one of the
  1203  // passed outpoints), OnRecvTx (for transactions that receive funds
  1204  // to one of the passed addresses), and OnRescanProgress (for rescan progress
  1205  // updates).
  1206  //
  1207  // See RescanEndBlock to also specify an ending block to finish the rescan
  1208  // without continuing through the best block on the main chain.
  1209  //
  1210  // NOTE: Rescan requests are not issued on client reconnect and must be
  1211  // performed manually (ideally with a new start height based on the last
  1212  // rescan progress notification).  See the OnClientConnected notification
  1213  // callback for a good callsite to reissue rescan requests on connect and
  1214  // reconnect.
  1215  //
  1216  // NOTE: This is a btcd extension and requires a websocket connection.
  1217  //
  1218  // Deprecated: Use RescanBlocks instead.
  1219  func (c *Client) Rescan(startBlock *chainhash.Hash,
  1220  	addresses []palcutil.Address,
  1221  	outpoints []*wire.OutPoint) error {
  1222  
  1223  	return c.RescanAsync(startBlock, addresses, outpoints).Receive()
  1224  }
  1225  
  1226  // RescanEndBlockAsync returns an instance of a type that can be used to get
  1227  // the result of the RPC at some future time by invoking the Receive function on
  1228  // the returned instance.
  1229  //
  1230  // See RescanEndBlock for the blocking version and more details.
  1231  //
  1232  // NOTE: This is a btcd extension and requires a websocket connection.
  1233  //
  1234  // Deprecated: Use RescanBlocksAsync instead.
  1235  func (c *Client) RescanEndBlockAsync(startBlock *chainhash.Hash,
  1236  	addresses []palcutil.Address, outpoints []*wire.OutPoint,
  1237  	endBlock *chainhash.Hash) FutureRescanResult {
  1238  
  1239  	// Not supported in HTTP POST mode.
  1240  	if c.config.HTTPPostMode {
  1241  		return newFutureError(ErrWebsocketsRequired)
  1242  	}
  1243  
  1244  	// Ignore the notification if the client is not interested in
  1245  	// notifications.
  1246  	if c.ntfnHandlers == nil {
  1247  		return newNilFutureResult()
  1248  	}
  1249  
  1250  	// Convert block hashes to strings.
  1251  	var startBlockHashStr, endBlockHashStr string
  1252  	if startBlock != nil {
  1253  		startBlockHashStr = startBlock.String()
  1254  	}
  1255  	if endBlock != nil {
  1256  		endBlockHashStr = endBlock.String()
  1257  	}
  1258  
  1259  	// Convert addresses to strings.
  1260  	addrs := make([]string, 0, len(addresses))
  1261  	for _, addr := range addresses {
  1262  		addrs = append(addrs, addr.String())
  1263  	}
  1264  
  1265  	// Convert outpoints.
  1266  	ops := make([]btcjson.OutPoint, 0, len(outpoints))
  1267  	for _, op := range outpoints {
  1268  		ops = append(ops, newOutPointFromWire(op))
  1269  	}
  1270  
  1271  	cmd := btcjson.NewRescanCmd(startBlockHashStr, addrs, ops,
  1272  		&endBlockHashStr)
  1273  	return c.sendCmd(cmd)
  1274  }
  1275  
  1276  // RescanEndHeight rescans the block chain starting from the provided starting
  1277  // block up to the provided ending block for transactions that pay to the
  1278  // passed addresses and transactions which spend the passed outpoints.
  1279  //
  1280  // The notifications of found transactions are delivered to the notification
  1281  // handlers associated with client and this call will not return until the
  1282  // rescan has completed.  Calling this function has no effect if there are no
  1283  // notification handlers and will result in an error if the client is configured
  1284  // to run in HTTP POST mode.
  1285  //
  1286  // The notifications delivered as a result of this call will be via one of
  1287  // OnRedeemingTx (for transactions which spend from the one of the
  1288  // passed outpoints), OnRecvTx (for transactions that receive funds
  1289  // to one of the passed addresses), and OnRescanProgress (for rescan progress
  1290  // updates).
  1291  //
  1292  // See Rescan to also perform a rescan through current end of the longest chain.
  1293  //
  1294  // NOTE: This is a btcd extension and requires a websocket connection.
  1295  //
  1296  // Deprecated: Use RescanBlocks instead.
  1297  func (c *Client) RescanEndHeight(startBlock *chainhash.Hash,
  1298  	addresses []palcutil.Address, outpoints []*wire.OutPoint,
  1299  	endBlock *chainhash.Hash) error {
  1300  
  1301  	return c.RescanEndBlockAsync(startBlock, addresses, outpoints,
  1302  		endBlock).Receive()
  1303  }
  1304  
  1305  // FutureLoadTxFilterResult is a future promise to deliver the result
  1306  // of a LoadTxFilterAsync RPC invocation (or an applicable error).
  1307  //
  1308  // NOTE: This is a btcd extension ported from github.com/decred/dcrrpcclient
  1309  // and requires a websocket connection.
  1310  type FutureLoadTxFilterResult chan *response
  1311  
  1312  // Receive waits for the response promised by the future and returns an error
  1313  // if the registration was not successful.
  1314  //
  1315  // NOTE: This is a btcd extension ported from github.com/decred/dcrrpcclient
  1316  // and requires a websocket connection.
  1317  func (r FutureLoadTxFilterResult) Receive() error {
  1318  	_, err := receiveFuture(r)
  1319  	return err
  1320  }
  1321  
  1322  // LoadTxFilterAsync returns an instance of a type that can be used to
  1323  // get the result of the RPC at some future time by invoking the Receive
  1324  // function on the returned instance.
  1325  //
  1326  // See LoadTxFilter for the blocking version and more details.
  1327  //
  1328  // NOTE: This is a btcd extension ported from github.com/decred/dcrrpcclient
  1329  // and requires a websocket connection.
  1330  func (c *Client) LoadTxFilterAsync(reload bool, addresses []palcutil.Address,
  1331  	outPoints []wire.OutPoint) FutureLoadTxFilterResult {
  1332  
  1333  	addrStrs := make([]string, len(addresses))
  1334  	for i, a := range addresses {
  1335  		addrStrs[i] = a.EncodeAddress()
  1336  	}
  1337  	outPointObjects := make([]btcjson.OutPoint, len(outPoints))
  1338  	for i := range outPoints {
  1339  		outPointObjects[i] = btcjson.OutPoint{
  1340  			Hash:  outPoints[i].Hash.String(),
  1341  			Index: outPoints[i].Index,
  1342  		}
  1343  	}
  1344  
  1345  	cmd := btcjson.NewLoadTxFilterCmd(reload, addrStrs, outPointObjects)
  1346  	return c.sendCmd(cmd)
  1347  }
  1348  
  1349  // LoadTxFilter loads, reloads, or adds data to a websocket client's transaction
  1350  // filter.  The filter is consistently updated based on inspected transactions
  1351  // during mempool acceptance, block acceptance, and for all rescanned blocks.
  1352  //
  1353  // NOTE: This is a btcd extension ported from github.com/decred/dcrrpcclient
  1354  // and requires a websocket connection.
  1355  func (c *Client) LoadTxFilter(reload bool, addresses []palcutil.Address, outPoints []wire.OutPoint) error {
  1356  	return c.LoadTxFilterAsync(reload, addresses, outPoints).Receive()
  1357  }