func (e wrongNumParams) Error() string {
	return fmt.Sprintf("wrong number of parameters (%d)", e)
}
Error satisifies the builtin error interface.
package rpcclient
import (
	"bytes"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"time"
	"github.com/soteria-dag/soterd/soterjson"
	"github.com/soteria-dag/soterd/chaincfg/chainhash"
	"github.com/soteria-dag/soterd/wire"
	"github.com/soteria-dag/soterd/soterutil"
)
var (
	ErrWebsocketsRequired = errors.New("a websocket connection is required " +
		"to use this feature")
)
type notificationState struct {
	notifyBlocks       bool
	notifyNewTx        bool
	notifyNewTxVerbose bool
	notifyReceived     map[string]struct{}
	notifySpent        map[soterjson.OutPoint]struct{}
}
func (s *notificationState) Copy() *notificationState {
	var stateCopy notificationState
	stateCopy.notifyBlocks = s.notifyBlocks
	stateCopy.notifyNewTx = s.notifyNewTx
	stateCopy.notifyNewTxVerbose = s.notifyNewTxVerbose
	stateCopy.notifyReceived = make(map[string]struct{})
	for addr := range s.notifyReceived {
		stateCopy.notifyReceived[addr] = struct{}{}
	}
	stateCopy.notifySpent = make(map[soterjson.OutPoint]struct{})
	for op := range s.notifySpent {
		stateCopy.notifySpent[op] = struct{}{}
	}
	return &stateCopy
}
func newNotificationState() *notificationState {
	return &notificationState{
		notifyReceived: make(map[string]struct{}),
		notifySpent:    make(map[soterjson.OutPoint]struct{}),
	}
}
func newNilFutureResult() chan *response {
	responseChan := make(chan *response, 1)
	responseChan <- &response{result: nil, err: nil}
	return responseChan
}
type NotificationHandlers struct {
	OnClientConnected func()
	OnBlockConnected func(hash *chainhash.Hash, height int32, t time.Time)
	OnFilteredBlockConnected func(height int32, header *wire.BlockHeader,
		txs []*soterutil.Tx)
	OnBlockDisconnected func(hash *chainhash.Hash, height int32, t time.Time)
	OnFilteredBlockDisconnected func(height int32, header *wire.BlockHeader)
	OnRecvTx func(transaction *soterutil.Tx, details *soterjson.BlockDetails)
	OnRedeemingTx func(transaction *soterutil.Tx, details *soterjson.BlockDetails)
	OnRelevantTxAccepted func(transaction []byte)
	OnRescanFinished func(hash *chainhash.Hash, height int32, blkTime time.Time)
	OnRescanProgress func(hash *chainhash.Hash, height int32, blkTime time.Time)
	OnTxAccepted func(hash *chainhash.Hash, amount soterutil.Amount)
	OnTxAcceptedVerbose func(txDetails *soterjson.TxRawResult)
	OnSoterdConnected func(connected bool)
	OnAccountBalance func(account string, balance soterutil.Amount, confirmed bool)
	OnWalletLockState func(locked bool)
	OnUnknownNotification func(method string, params []json.RawMessage)
}
func (c *Client) handleNotification(ntfn *rawNotification) {
	if c.ntfnHandlers == nil {
		return
	}
	switch ntfn.Method {
	case soterjson.BlockConnectedNtfnMethod:
		if c.ntfnHandlers.OnBlockConnected == nil {
			return
		}
		blockHash, blockHeight, blockTime, err := parseChainNtfnParams(ntfn.Params)
		if err != nil {
			log.Warnf("Received invalid block connected "+
				"notification: %v", err)
			return
		}
		c.ntfnHandlers.OnBlockConnected(blockHash, blockHeight, blockTime)
	case soterjson.FilteredBlockConnectedNtfnMethod:
		if c.ntfnHandlers.OnFilteredBlockConnected == nil {
			return
		}
		blockHeight, blockHeader, transactions, err :=
			parseFilteredBlockConnectedParams(ntfn.Params)
		if err != nil {
			log.Warnf("Received invalid filtered block "+
				"connected notification: %v", err)
			return
		}
		c.ntfnHandlers.OnFilteredBlockConnected(blockHeight,
			blockHeader, transactions)
	case soterjson.BlockDisconnectedNtfnMethod:
		if c.ntfnHandlers.OnBlockDisconnected == nil {
			return
		}
		blockHash, blockHeight, blockTime, err := parseChainNtfnParams(ntfn.Params)
		if err != nil {
			log.Warnf("Received invalid block connected "+
				"notification: %v", err)
			return
		}
		c.ntfnHandlers.OnBlockDisconnected(blockHash, blockHeight, blockTime)
	case soterjson.FilteredBlockDisconnectedNtfnMethod:
		if c.ntfnHandlers.OnFilteredBlockDisconnected == nil {
			return
		}
		blockHeight, blockHeader, err :=
			parseFilteredBlockDisconnectedParams(ntfn.Params)
		if err != nil {
			log.Warnf("Received invalid filtered block "+
				"disconnected notification: %v", err)
			return
		}
		c.ntfnHandlers.OnFilteredBlockDisconnected(blockHeight,
			blockHeader)
	case soterjson.RecvTxNtfnMethod:
		if c.ntfnHandlers.OnRecvTx == nil {
			return
		}
		tx, block, err := parseChainTxNtfnParams(ntfn.Params)
		if err != nil {
			log.Warnf("Received invalid recvtx notification: %v",
				err)
			return
		}
		c.ntfnHandlers.OnRecvTx(tx, block)
	case soterjson.RedeemingTxNtfnMethod:
		if c.ntfnHandlers.OnRedeemingTx == nil {
			return
		}
		tx, block, err := parseChainTxNtfnParams(ntfn.Params)
		if err != nil {
			log.Warnf("Received invalid redeemingtx "+
				"notification: %v", err)
			return
		}
		c.ntfnHandlers.OnRedeemingTx(tx, block)
	case soterjson.RelevantTxAcceptedNtfnMethod:
		if c.ntfnHandlers.OnRelevantTxAccepted == nil {
			return
		}
		transaction, err := parseRelevantTxAcceptedParams(ntfn.Params)
		if err != nil {
			log.Warnf("Received invalid relevanttxaccepted "+
				"notification: %v", err)
			return
		}
		c.ntfnHandlers.OnRelevantTxAccepted(transaction)
	case soterjson.RescanFinishedNtfnMethod:
		if c.ntfnHandlers.OnRescanFinished == nil {
			return
		}
		hash, height, blkTime, err := parseRescanProgressParams(ntfn.Params)
		if err != nil {
			log.Warnf("Received invalid rescanfinished "+
				"notification: %v", err)
			return
		}
		c.ntfnHandlers.OnRescanFinished(hash, height, blkTime)
	case soterjson.RescanProgressNtfnMethod:
		if c.ntfnHandlers.OnRescanProgress == nil {
			return
		}
		hash, height, blkTime, err := parseRescanProgressParams(ntfn.Params)
		if err != nil {
			log.Warnf("Received invalid rescanprogress "+
				"notification: %v", err)
			return
		}
		c.ntfnHandlers.OnRescanProgress(hash, height, blkTime)
	case soterjson.TxAcceptedNtfnMethod:
		if c.ntfnHandlers.OnTxAccepted == nil {
			return
		}
		hash, amt, err := parseTxAcceptedNtfnParams(ntfn.Params)
		if err != nil {
			log.Warnf("Received invalid tx accepted "+
				"notification: %v", err)
			return
		}
		c.ntfnHandlers.OnTxAccepted(hash, amt)
	case soterjson.TxAcceptedVerboseNtfnMethod:
		if c.ntfnHandlers.OnTxAcceptedVerbose == nil {
			return
		}
		rawTx, err := parseTxAcceptedVerboseNtfnParams(ntfn.Params)
		if err != nil {
			log.Warnf("Received invalid tx accepted verbose "+
				"notification: %v", err)
			return
		}
		c.ntfnHandlers.OnTxAcceptedVerbose(rawTx)
	case soterjson.SoterdConnectedNtfnMethod:
		if c.ntfnHandlers.OnSoterdConnected == nil {
			return
		}
		connected, err := parseSoterdConnectedNtfnParams(ntfn.Params)
		if err != nil {
			log.Warnf("Received invalid soterd connected "+
				"notification: %v", err)
			return
		}
		c.ntfnHandlers.OnSoterdConnected(connected)
	case soterjson.AccountBalanceNtfnMethod:
		if c.ntfnHandlers.OnAccountBalance == nil {
			return
		}
		account, bal, conf, err := parseAccountBalanceNtfnParams(ntfn.Params)
		if err != nil {
			log.Warnf("Received invalid account balance "+
				"notification: %v", err)
			return
		}
		c.ntfnHandlers.OnAccountBalance(account, bal, conf)
	case soterjson.WalletLockStateNtfnMethod:
		if c.ntfnHandlers.OnWalletLockState == nil {
			return
		}
		_, locked, err := parseWalletLockStateNtfnParams(ntfn.Params)
		if err != nil {
			log.Warnf("Received invalid wallet lock state "+
				"notification: %v", err)
			return
		}
		c.ntfnHandlers.OnWalletLockState(locked)
	default:
		if c.ntfnHandlers.OnUnknownNotification == nil {
			return
		}
		c.ntfnHandlers.OnUnknownNotification(ntfn.Method, ntfn.Params)
	}
}
type wrongNumParams int