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.
16 "github.com/btcsuite/btcd/btcjson"
17 "github.com/btcsuite/btcd/chaincfg/chainhash"
18 "github.com/btcsuite/btcd/wire"
19 "github.com/btcsuite/btcutil"
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")
31 // notificationState is used to track the current state of successfuly
32 // registered notification so the state can be automatically re-established on
34 type notificationState struct {
37 notifyNewTxVerbose bool
38 notifyReceived map[string]struct{}
39 notifySpent map[btcjson.OutPoint]struct{}
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{}{}
52 stateCopy.notifySpent = make(map[btcjson.OutPoint]struct{})
53 for op := range s.notifySpent {
54 stateCopy.notifySpent[op] = struct{}{}
60 // newNotificationState returns a new notification state ready to be populated.
61 func newNotificationState() *notificationState {
62 return ¬ificationState{
63 notifyReceived: make(map[string]struct{}),
64 notifySpent: make(map[btcjson.OutPoint]struct{}),
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}
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
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
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()
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.
98 // NOTE: Deprecated. Use OnFilteredBlockConnected instead.
99 OnBlockConnected func(hash *chainhash.Hash, height int32, t time.Time)
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,
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.
114 // NOTE: Deprecated. Use OnFilteredBlockDisconnected instead.
115 OnBlockDisconnected func(hash *chainhash.Hash, height int32, t time.Time)
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)
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.
130 // NOTE: Deprecated. Use OnRelevantTxAccepted instead.
131 OnRecvTx func(transaction *btcutil.Tx, details *btcjson.BlockDetails)
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.
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.
144 // NOTE: Deprecated. Use OnRelevantTxAccepted instead.
145 OnRedeemingTx func(transaction *btcutil.Tx, details *btcjson.BlockDetails)
147 // OnRelevantTxAccepted is invoked when an unmined transaction passes
148 // the client's transaction filter.
150 // NOTE: This is a btcsuite extension ported from
151 // github.com/decred/dcrrpcclient.
152 OnRelevantTxAccepted func(transaction []byte)
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.
160 // NOTE: Deprecated. Not used with RescanBlocks.
161 OnRescanFinished func(hash *chainhash.Hash, height int32, blkTime time.Time)
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.
167 // NOTE: Deprecated. Not used with RescanBlocks.
168 OnRescanProgress func(hash *chainhash.Hash, height int32, blkTime time.Time)
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 btcutil.Amount)
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)
182 // OnBtcdConnected is invoked when a wallet connects or disconnects from
185 // This will only be available when client is connected to a wallet
186 // server such as btcwallet.
187 OnBtcdConnected func(connected bool)
189 // OnAccountBalance is invoked with account balance updates.
191 // This will only be available when speaking to a wallet server
192 // such as btcwallet.
193 OnAccountBalance func(account string, balance btcutil.Amount, confirmed bool)
195 // OnWalletLockState is invoked when a wallet is locked or unlocked.
197 // This will only be available when client is connected to a wallet
198 // server such as btcwallet.
199 OnWalletLockState func(locked bool)
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
206 OnUnknownNotification func(method string, params []json.RawMessage)
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
213 func (c *Client) handleNotification(ntfn *rawNotification) {
214 // Ignore the notification if the client is not interested in any
216 if c.ntfnHandlers == nil {
222 case btcjson.BlockConnectedNtfnMethod:
223 // Ignore the notification if the client is not interested in
225 if c.ntfnHandlers.OnBlockConnected == nil {
229 blockHash, blockHeight, blockTime, err := parseChainNtfnParams(ntfn.Params)
231 log.Warnf("Received invalid block connected "+
232 "notification: %v", err)
236 c.ntfnHandlers.OnBlockConnected(blockHash, blockHeight, blockTime)
238 // OnFilteredBlockConnected
239 case btcjson.FilteredBlockConnectedNtfnMethod:
240 // Ignore the notification if the client is not interested in
242 if c.ntfnHandlers.OnFilteredBlockConnected == nil {
246 blockHeight, blockHeader, transactions, err :=
247 parseFilteredBlockConnectedParams(ntfn.Params)
249 log.Warnf("Received invalid filtered block "+
250 "connected notification: %v", err)
254 c.ntfnHandlers.OnFilteredBlockConnected(blockHeight,
255 blockHeader, transactions)
257 // OnBlockDisconnected
258 case btcjson.BlockDisconnectedNtfnMethod:
259 // Ignore the notification if the client is not interested in
261 if c.ntfnHandlers.OnBlockDisconnected == nil {
265 blockHash, blockHeight, blockTime, err := parseChainNtfnParams(ntfn.Params)
267 log.Warnf("Received invalid block connected "+
268 "notification: %v", err)
272 c.ntfnHandlers.OnBlockDisconnected(blockHash, blockHeight, blockTime)
274 // OnFilteredBlockDisconnected
275 case btcjson.FilteredBlockDisconnectedNtfnMethod:
276 // Ignore the notification if the client is not interested in
278 if c.ntfnHandlers.OnFilteredBlockDisconnected == nil {
282 blockHeight, blockHeader, err :=
283 parseFilteredBlockDisconnectedParams(ntfn.Params)
285 log.Warnf("Received invalid filtered block "+
286 "disconnected notification: %v", err)
290 c.ntfnHandlers.OnFilteredBlockDisconnected(blockHeight,
294 case btcjson.RecvTxNtfnMethod:
295 // Ignore the notification if the client is not interested in
297 if c.ntfnHandlers.OnRecvTx == nil {
301 tx, block, err := parseChainTxNtfnParams(ntfn.Params)
303 log.Warnf("Received invalid recvtx notification: %v",
308 c.ntfnHandlers.OnRecvTx(tx, block)
311 case btcjson.RedeemingTxNtfnMethod:
312 // Ignore the notification if the client is not interested in
314 if c.ntfnHandlers.OnRedeemingTx == nil {
318 tx, block, err := parseChainTxNtfnParams(ntfn.Params)
320 log.Warnf("Received invalid redeemingtx "+
321 "notification: %v", err)
325 c.ntfnHandlers.OnRedeemingTx(tx, block)
327 // OnRelevantTxAccepted
328 case btcjson.RelevantTxAcceptedNtfnMethod:
329 // Ignore the notification if the client is not interested in
331 if c.ntfnHandlers.OnRelevantTxAccepted == nil {
335 transaction, err := parseRelevantTxAcceptedParams(ntfn.Params)
337 log.Warnf("Received invalid relevanttxaccepted "+
338 "notification: %v", err)
342 c.ntfnHandlers.OnRelevantTxAccepted(transaction)
345 case btcjson.RescanFinishedNtfnMethod:
346 // Ignore the notification if the client is not interested in
348 if c.ntfnHandlers.OnRescanFinished == nil {
352 hash, height, blkTime, err := parseRescanProgressParams(ntfn.Params)
354 log.Warnf("Received invalid rescanfinished "+
355 "notification: %v", err)
359 c.ntfnHandlers.OnRescanFinished(hash, height, blkTime)
362 case btcjson.RescanProgressNtfnMethod:
363 // Ignore the notification if the client is not interested in
365 if c.ntfnHandlers.OnRescanProgress == nil {
369 hash, height, blkTime, err := parseRescanProgressParams(ntfn.Params)
371 log.Warnf("Received invalid rescanprogress "+
372 "notification: %v", err)
376 c.ntfnHandlers.OnRescanProgress(hash, height, blkTime)
379 case btcjson.TxAcceptedNtfnMethod:
380 // Ignore the notification if the client is not interested in
382 if c.ntfnHandlers.OnTxAccepted == nil {
386 hash, amt, err := parseTxAcceptedNtfnParams(ntfn.Params)
388 log.Warnf("Received invalid tx accepted "+
389 "notification: %v", err)
393 c.ntfnHandlers.OnTxAccepted(hash, amt)
395 // OnTxAcceptedVerbose
396 case btcjson.TxAcceptedVerboseNtfnMethod:
397 // Ignore the notification if the client is not interested in
399 if c.ntfnHandlers.OnTxAcceptedVerbose == nil {
403 rawTx, err := parseTxAcceptedVerboseNtfnParams(ntfn.Params)
405 log.Warnf("Received invalid tx accepted verbose "+
406 "notification: %v", err)
410 c.ntfnHandlers.OnTxAcceptedVerbose(rawTx)
413 case btcjson.BtcdConnectedNtfnMethod:
414 // Ignore the notification if the client is not interested in
416 if c.ntfnHandlers.OnBtcdConnected == nil {
420 connected, err := parseBtcdConnectedNtfnParams(ntfn.Params)
422 log.Warnf("Received invalid btcd connected "+
423 "notification: %v", err)
427 c.ntfnHandlers.OnBtcdConnected(connected)
430 case btcjson.AccountBalanceNtfnMethod:
431 // Ignore the notification if the client is not interested in
433 if c.ntfnHandlers.OnAccountBalance == nil {
437 account, bal, conf, err := parseAccountBalanceNtfnParams(ntfn.Params)
439 log.Warnf("Received invalid account balance "+
440 "notification: %v", err)
444 c.ntfnHandlers.OnAccountBalance(account, bal, conf)
447 case btcjson.WalletLockStateNtfnMethod:
448 // Ignore the notification if the client is not interested in
450 if c.ntfnHandlers.OnWalletLockState == nil {
454 // The account name is not notified, so the return value is
456 _, locked, err := parseWalletLockStateNtfnParams(ntfn.Params)
458 log.Warnf("Received invalid wallet lock state "+
459 "notification: %v", err)
463 c.ntfnHandlers.OnWalletLockState(locked)
465 // OnUnknownNotification
467 if c.ntfnHandlers.OnUnknownNotification == nil {
471 c.ntfnHandlers.OnUnknownNotification(ntfn.Method, ntfn.Params)
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
481 // Error satisifies the builtin error interface.
482 func (e wrongNumParams) Error() string {
483 return fmt.Sprintf("wrong number of parameters (%d)", e)
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) {
491 if len(params) != 3 {
492 return nil, 0, time.Time{}, wrongNumParams(len(params))
495 // Unmarshal first parameter as a string.
496 var blockHashStr string
497 err := json.Unmarshal(params[0], &blockHashStr)
499 return nil, 0, time.Time{}, err
502 // Unmarshal second parameter as an integer.
503 var blockHeight int32
504 err = json.Unmarshal(params[1], &blockHeight)
506 return nil, 0, time.Time{}, err
509 // Unmarshal third parameter as unix time.
510 var blockTimeUnix int64
511 err = json.Unmarshal(params[2], &blockTimeUnix)
513 return nil, 0, time.Time{}, err
516 // Create hash from block hash string.
517 blockHash, err := chainhash.NewHashFromStr(blockHashStr)
519 return nil, 0, time.Time{}, err
522 // Create time.Time from unix time.
523 blockTime := time.Unix(blockTimeUnix, 0)
525 return blockHash, blockHeight, blockTime, nil
528 // parseFilteredBlockConnectedParams parses out the parameters included in a
529 // filteredblockconnected notification.
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, []*btcutil.Tx, error) {
537 return 0, nil, nil, wrongNumParams(len(params))
540 // Unmarshal first parameter as an integer.
541 var blockHeight int32
542 err := json.Unmarshal(params[0], &blockHeight)
544 return 0, nil, nil, err
547 // Unmarshal second parameter as a slice of bytes.
548 blockHeaderBytes, err := parseHexParam(params[1])
550 return 0, nil, nil, err
553 // Deserialize block header from slice of bytes.
554 var blockHeader wire.BlockHeader
555 err = blockHeader.Deserialize(bytes.NewReader(blockHeaderBytes))
557 return 0, nil, nil, err
560 // Unmarshal third parameter as a slice of hex-encoded strings.
561 var hexTransactions []string
562 err = json.Unmarshal(params[2], &hexTransactions)
564 return 0, nil, nil, err
567 // Create slice of transactions from slice of strings by hex-decoding.
568 transactions := make([]*btcutil.Tx, len(hexTransactions))
569 for i, hexTx := range hexTransactions {
570 transaction, err := hex.DecodeString(hexTx)
572 return 0, nil, nil, err
575 transactions[i], err = btcutil.NewTxFromBytes(transaction)
577 return 0, nil, nil, err
581 return blockHeight, &blockHeader, transactions, nil
584 // parseFilteredBlockDisconnectedParams parses out the parameters included in a
585 // filteredblockdisconnected notification.
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) {
592 return 0, nil, wrongNumParams(len(params))
595 // Unmarshal first parameter as an integer.
596 var blockHeight int32
597 err := json.Unmarshal(params[0], &blockHeight)
602 // Unmarshal second parmeter as a slice of bytes.
603 blockHeaderBytes, err := parseHexParam(params[1])
608 // Deserialize block header from slice of bytes.
609 var blockHeader wire.BlockHeader
610 err = blockHeader.Deserialize(bytes.NewReader(blockHeaderBytes))
615 return blockHeight, &blockHeader, nil
618 func parseHexParam(param json.RawMessage) ([]byte, error) {
620 err := json.Unmarshal(param, &s)
624 return hex.DecodeString(s)
627 // parseRelevantTxAcceptedParams parses out the parameter included in a
628 // relevanttxaccepted notification.
629 func parseRelevantTxAcceptedParams(params []json.RawMessage) (transaction []byte, err error) {
631 return nil, wrongNumParams(len(params))
634 return parseHexParam(params[0])
637 // parseChainTxNtfnParams parses out the transaction and optional details about
638 // the block it's mined in from the parameters of recvtx and redeemingtx
640 func parseChainTxNtfnParams(params []json.RawMessage) (*btcutil.Tx,
641 *btcjson.BlockDetails, error) {
643 if len(params) == 0 || len(params) > 2 {
644 return nil, nil, wrongNumParams(len(params))
647 // Unmarshal first parameter as a string.
649 err := json.Unmarshal(params[0], &txHex)
654 // If present, unmarshal second optional parameter as the block details
656 var block *btcjson.BlockDetails
658 err = json.Unmarshal(params[1], &block)
664 // Hex decode and deserialize the transaction.
665 serializedTx, err := hex.DecodeString(txHex)
670 err = msgTx.Deserialize(bytes.NewReader(serializedTx))
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 btcutil.NewTx(&msgTx), block, nil
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))
688 // Unmarshal first parameter as an string.
690 err := json.Unmarshal(params[0], &hashStr)
692 return nil, 0, time.Time{}, err
695 // Unmarshal second parameter as an integer.
697 err = json.Unmarshal(params[1], &height)
699 return nil, 0, time.Time{}, err
702 // Unmarshal third parameter as an integer.
704 err = json.Unmarshal(params[2], &blkTime)
706 return nil, 0, time.Time{}, err
709 // Decode string encoding of block hash.
710 hash, err := chainhash.NewHashFromStr(hashStr)
712 return nil, 0, time.Time{}, err
715 return hash, height, time.Unix(blkTime, 0), nil
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 btcutil.Amount, error) {
723 if len(params) != 2 {
724 return nil, 0, wrongNumParams(len(params))
727 // Unmarshal first parameter as a string.
729 err := json.Unmarshal(params[0], &txHashStr)
734 // Unmarshal second parameter as a floating point number.
736 err = json.Unmarshal(params[1], &famt)
741 // Bounds check amount.
742 amt, err := btcutil.NewAmount(famt)
747 // Decode string encoding of transaction sha.
748 txHash, err := chainhash.NewHashFromStr(txHashStr)
753 return txHash, amt, nil
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,
761 if len(params) != 1 {
762 return nil, wrongNumParams(len(params))
765 // Unmarshal first parameter as a raw transaction result object.
766 var rawTx btcjson.TxRawResult
767 err := json.Unmarshal(params[0], &rawTx)
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).
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))
785 // Unmarshal first parameter as a boolean.
787 err := json.Unmarshal(params[0], &connected)
792 return connected, nil
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 btcutil.Amount, confirmed bool, err error) {
801 if len(params) != 3 {
802 return "", 0, false, wrongNumParams(len(params))
805 // Unmarshal first parameter as a string.
806 err = json.Unmarshal(params[0], &account)
808 return "", 0, false, err
811 // Unmarshal second parameter as a floating point number.
813 err = json.Unmarshal(params[1], &fbal)
815 return "", 0, false, err
818 // Unmarshal third parameter as a boolean.
819 err = json.Unmarshal(params[2], &confirmed)
821 return "", 0, false, err
824 // Bounds check amount.
825 bal, err := btcutil.NewAmount(fbal)
827 return "", 0, false, err
830 return account, bal, confirmed, nil
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) {
838 if len(params) != 2 {
839 return "", false, wrongNumParams(len(params))
842 // Unmarshal first parameter as a string.
843 err = json.Unmarshal(params[0], &account)
845 return "", false, err
848 // Unmarshal second parameter as a boolean.
849 err = json.Unmarshal(params[1], &locked)
851 return "", false, err
854 return account, locked, nil
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
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)
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.
872 // See NotifyBlocks for the blocking version and more details.
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)
881 // Ignore the notification if the client is not interested in
883 if c.ntfnHandlers == nil {
884 return newNilFutureResult()
887 cmd := btcjson.NewNotifyBlocksCmd()
888 return c.sendCmd(cmd)
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.
897 // The notifications delivered as a result of this call will be via one of
898 // OnBlockConnected or OnBlockDisconnected.
900 // NOTE: This is a btcd extension and requires a websocket connection.
901 func (c *Client) NotifyBlocks() error {
902 return c.NotifyBlocksAsync().Receive()
905 // FutureNotifySpentResult is a future promise to deliver the result of a
906 // NotifySpentAsync RPC invocation (or an applicable error).
908 // NOTE: Deprecated. Use FutureLoadTxFilterResult instead.
909 type FutureNotifySpentResult chan *response
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)
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)
927 // Ignore the notification if the client is not interested in
929 if c.ntfnHandlers == nil {
930 return newNilFutureResult()
933 cmd := btcjson.NewNotifySpentCmd(outpoints)
934 return c.sendCmd(cmd)
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(),
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.
950 // See NotifySpent for the blocking version and more details.
952 // NOTE: This is a btcd extension and requires a websocket connection.
954 // NOTE: 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)
961 // Ignore the notification if the client is not interested in
963 if c.ntfnHandlers == nil {
964 return newNilFutureResult()
967 ops := make([]btcjson.OutPoint, 0, len(outpoints))
968 for _, outpoint := range outpoints {
969 ops = append(ops, newOutPointFromWire(outpoint))
971 cmd := btcjson.NewNotifySpentCmd(ops)
972 return c.sendCmd(cmd)
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.
981 // The notifications delivered as a result of this call will be via
984 // NOTE: This is a btcd extension and requires a websocket connection.
986 // NOTE: Deprecated. Use LoadTxFilter instead.
987 func (c *Client) NotifySpent(outpoints []*wire.OutPoint) error {
988 return c.NotifySpentAsync(outpoints).Receive()
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
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)
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.
1006 // See NotifyNewTransactionsAsync for the blocking version and more details.
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)
1015 // Ignore the notification if the client is not interested in
1017 if c.ntfnHandlers == nil {
1018 return newNilFutureResult()
1021 cmd := btcjson.NewNotifyNewTransactionsCmd(&verbose)
1022 return c.sendCmd(cmd)
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.
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
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()
1040 // FutureNotifyReceivedResult is a future promise to deliver the result of a
1041 // NotifyReceivedAsync RPC invocation (or an applicable error).
1043 // NOTE: Deprecated. Use FutureLoadTxFilterResult instead.
1044 type FutureNotifyReceivedResult chan *response
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)
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)
1062 // Ignore the notification if the client is not interested in
1064 if c.ntfnHandlers == nil {
1065 return newNilFutureResult()
1068 // Convert addresses to strings.
1069 cmd := btcjson.NewNotifyReceivedCmd(addresses)
1070 return c.sendCmd(cmd)
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.
1077 // See NotifyReceived for the blocking version and more details.
1079 // NOTE: This is a btcd extension and requires a websocket connection.
1081 // NOTE: Deprecated. Use LoadTxFilterAsync instead.
1082 func (c *Client) NotifyReceivedAsync(addresses []btcutil.Address) FutureNotifyReceivedResult {
1083 // Not supported in HTTP POST mode.
1084 if c.config.HTTPPostMode {
1085 return newFutureError(ErrWebsocketsRequired)
1088 // Ignore the notification if the client is not interested in
1090 if c.ntfnHandlers == nil {
1091 return newNilFutureResult()
1094 // Convert addresses to strings.
1095 addrs := make([]string, 0, len(addresses))
1096 for _, addr := range addresses {
1097 addrs = append(addrs, addr.String())
1099 cmd := btcjson.NewNotifyReceivedCmd(addrs)
1100 return c.sendCmd(cmd)
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.
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
1119 // NOTE: This is a btcd extension and requires a websocket connection.
1121 // NOTE: Deprecated. Use LoadTxFilter instead.
1122 func (c *Client) NotifyReceived(addresses []btcutil.Address) error {
1123 return c.NotifyReceivedAsync(addresses).Receive()
1126 // FutureRescanResult is a future promise to deliver the result of a RescanAsync
1127 // or RescanEndHeightAsync RPC invocation (or an applicable error).
1129 // NOTE: Deprecated. Use FutureRescanBlocksResult instead.
1130 type FutureRescanResult chan *response
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)
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.
1143 // See Rescan for the blocking version and more details.
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
1151 // NOTE: This is a btcd extension and requires a websocket connection.
1153 // NOTE: Deprecated. Use RescanBlocksAsync instead.
1154 func (c *Client) RescanAsync(startBlock *chainhash.Hash,
1155 addresses []btcutil.Address,
1156 outpoints []*wire.OutPoint) FutureRescanResult {
1158 // Not supported in HTTP POST mode.
1159 if c.config.HTTPPostMode {
1160 return newFutureError(ErrWebsocketsRequired)
1163 // Ignore the notification if the client is not interested in
1165 if c.ntfnHandlers == nil {
1166 return newNilFutureResult()
1169 // Convert block hashes to strings.
1170 var startBlockHashStr string
1171 if startBlock != nil {
1172 startBlockHashStr = startBlock.String()
1175 // Convert addresses to strings.
1176 addrs := make([]string, 0, len(addresses))
1177 for _, addr := range addresses {
1178 addrs = append(addrs, addr.String())
1181 // Convert outpoints.
1182 ops := make([]btcjson.OutPoint, 0, len(outpoints))
1183 for _, op := range outpoints {
1184 ops = append(ops, newOutPointFromWire(op))
1187 cmd := btcjson.NewRescanCmd(startBlockHashStr, addrs, ops, nil)
1188 return c.sendCmd(cmd)
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.
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.
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
1207 // See RescanEndBlock to also specify an ending block to finish the rescan
1208 // without continuing through the best block on the main chain.
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
1216 // NOTE: This is a btcd extension and requires a websocket connection.
1218 // NOTE: Deprecated. Use RescanBlocks instead.
1219 func (c *Client) Rescan(startBlock *chainhash.Hash,
1220 addresses []btcutil.Address,
1221 outpoints []*wire.OutPoint) error {
1223 return c.RescanAsync(startBlock, addresses, outpoints).Receive()
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.
1230 // See RescanEndBlock for the blocking version and more details.
1232 // NOTE: This is a btcd extension and requires a websocket connection.
1234 // NOTE: Deprecated. Use RescanBlocksAsync instead.
1235 func (c *Client) RescanEndBlockAsync(startBlock *chainhash.Hash,
1236 addresses []btcutil.Address, outpoints []*wire.OutPoint,
1237 endBlock *chainhash.Hash) FutureRescanResult {
1239 // Not supported in HTTP POST mode.
1240 if c.config.HTTPPostMode {
1241 return newFutureError(ErrWebsocketsRequired)
1244 // Ignore the notification if the client is not interested in
1246 if c.ntfnHandlers == nil {
1247 return newNilFutureResult()
1250 // Convert block hashes to strings.
1251 var startBlockHashStr, endBlockHashStr string
1252 if startBlock != nil {
1253 startBlockHashStr = startBlock.String()
1255 if endBlock != nil {
1256 endBlockHashStr = endBlock.String()
1259 // Convert addresses to strings.
1260 addrs := make([]string, 0, len(addresses))
1261 for _, addr := range addresses {
1262 addrs = append(addrs, addr.String())
1265 // Convert outpoints.
1266 ops := make([]btcjson.OutPoint, 0, len(outpoints))
1267 for _, op := range outpoints {
1268 ops = append(ops, newOutPointFromWire(op))
1271 cmd := btcjson.NewRescanCmd(startBlockHashStr, addrs, ops,
1273 return c.sendCmd(cmd)
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.
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.
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
1292 // See Rescan to also perform a rescan through current end of the longest chain.
1294 // NOTE: This is a btcd extension and requires a websocket connection.
1296 // NOTE: Deprecated. Use RescanBlocks instead.
1297 func (c *Client) RescanEndHeight(startBlock *chainhash.Hash,
1298 addresses []btcutil.Address, outpoints []*wire.OutPoint,
1299 endBlock *chainhash.Hash) error {
1301 return c.RescanEndBlockAsync(startBlock, addresses, outpoints,
1305 // FutureLoadTxFilterResult is a future promise to deliver the result
1306 // of a LoadTxFilterAsync RPC invocation (or an applicable error).
1308 // NOTE: This is a btcd extension ported from github.com/decred/dcrrpcclient
1309 // and requires a websocket connection.
1310 type FutureLoadTxFilterResult chan *response
1312 // Receive waits for the response promised by the future and returns an error
1313 // if the registration was not successful.
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)
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.
1326 // See LoadTxFilter for the blocking version and more details.
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 []btcutil.Address,
1331 outPoints []wire.OutPoint) FutureLoadTxFilterResult {
1333 addrStrs := make([]string, len(addresses))
1334 for i, a := range addresses {
1335 addrStrs[i] = a.EncodeAddress()
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,
1345 cmd := btcjson.NewLoadTxFilterCmd(reload, addrStrs, outPointObjects)
1346 return c.sendCmd(cmd)
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.
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 []btcutil.Address, outPoints []wire.OutPoint) error {
1356 return c.LoadTxFilterAsync(reload, addresses, outPoints).Receive()