func lazyApplyHandler(s *Server, ctx context.Context, request *dcrjson.Request) lazyHandler {
	handlerData, ok := handlers[request.Method]
	if !ok {
		return func() (interface{}, *dcrjson.RPCError) {
			n, ok := s.walletLoader.NetworkBackend()
			if !ok {
				return nil, errRPCClientNotConnected
			}
			rpc, ok := n.(*dcrd.RPC)
			if !ok {
				return nil, rpcErrorf(dcrjson.ErrRPCClientNotConnected, "RPC passthrough requires dcrd RPC synchronization")
			}
			var resp json.RawMessage
			var params = make([]interface{}, len(request.Params))
			for i := range request.Params {
				params[i] = request.Params[i]
			}
			err := rpc.Call(ctx, request.Method, &resp, params...)
			if ctx.Err() != nil {
				log.Warnf("Canceled RPC method %v invoked by %v: %v", request.Method, remoteAddr(ctx), err)
				return nil, &dcrjson.RPCError{
					Code:    dcrjson.ErrRPCMisc,
					Message: ctx.Err().Error(),
				}
			}
			if err != nil {
				return nil, convertError(err)
			}
			return resp, nil
		}
	}
	return func() (interface{}, *dcrjson.RPCError) {
		params, err := dcrjson.ParseParams(types.Method(request.Method), request.Params)
		if err != nil {
			return nil, dcrjson.ErrRPCInvalidRequest
		}
		defer func() {
			if err := ctx.Err(); err != nil {
				log.Warnf("Canceled RPC method %v invoked by %v: %v", request.Method, remoteAddr(ctx), err)
			}
		}()
		resp, err := handlerData.fn(s, ctx, params)
		if err != nil {
			return nil, convertError(err)
		}
		return resp, nil
	}
}
lazyApplyHandler looks up the best request handler func for the method,
returning a closure that will execute it with the (required) wallet and
(optional) consensus RPC server.  If no handlers are found and the
chainClient is not nil, the returned handler performs RPC passthrough.
package jsonrpc
import (
	"bytes"
	"context"
	"crypto/rand"
	"encoding/base64"
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"math/big"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
	"decred.org/dcrwallet/v2/errors"
	"decred.org/dcrwallet/v2/internal/loader"
	"decred.org/dcrwallet/v2/internal/vsp"
	"decred.org/dcrwallet/v2/p2p"
	"decred.org/dcrwallet/v2/rpc/client/dcrd"
	"decred.org/dcrwallet/v2/rpc/jsonrpc/types"
	"decred.org/dcrwallet/v2/spv"
	"decred.org/dcrwallet/v2/version"
	"decred.org/dcrwallet/v2/wallet"
	"decred.org/dcrwallet/v2/wallet/txauthor"
	"decred.org/dcrwallet/v2/wallet/txrules"
	"decred.org/dcrwallet/v2/wallet/txsizes"
	"decred.org/dcrwallet/v2/wallet/udb"
	"github.com/decred/dcrd/blockchain/stake/v4"
	blockchain "github.com/decred/dcrd/blockchain/standalone/v2"
	"github.com/decred/dcrd/chaincfg/chainhash"
	"github.com/decred/dcrd/chaincfg/v3"
	"github.com/decred/dcrd/dcrec"
	"github.com/decred/dcrd/dcrec/secp256k1/v4"
	"github.com/decred/dcrd/dcrjson/v4"
	"github.com/decred/dcrd/dcrutil/v4"
	"github.com/decred/dcrd/hdkeychain/v3"
	dcrdtypes "github.com/decred/dcrd/rpc/jsonrpc/types/v3"
	"github.com/decred/dcrd/txscript/v4"
	"github.com/decred/dcrd/txscript/v4/sign"
	"github.com/decred/dcrd/txscript/v4/stdaddr"
	"github.com/decred/dcrd/wire"
	"golang.org/x/sync/errgroup"
)
const (
	jsonrpcSemverString = "8.8.0"
	jsonrpcSemverMajor  = 8
	jsonrpcSemverMinor  = 8
	jsonrpcSemverPatch  = 0
)
const (
	sstxCommitmentString = "sstxcommitment"
)
func confirms(txHeight, curHeight int32) int32 {
	switch {
	case txHeight == -1, txHeight > curHeight:
		return 0
	default:
		return curHeight - txHeight + 1
	}
}
var handlers = map[string]handler{
	"abandontransaction":      {fn: (*Server).abandonTransaction},
	"accountaddressindex":     {fn: (*Server).accountAddressIndex},
	"accountsyncaddressindex": {fn: (*Server).accountSyncAddressIndex},
	"accountunlocked":         {fn: (*Server).accountUnlocked},
	"addmultisigaddress":      {fn: (*Server).addMultiSigAddress},
	"addtransaction":          {fn: (*Server).addTransaction},
	"auditreuse":              {fn: (*Server).auditReuse},
	"consolidate":             {fn: (*Server).consolidate},
	"createmultisig":          {fn: (*Server).createMultiSig},
	"createnewaccount":        {fn: (*Server).createNewAccount},
	"createrawtransaction":    {fn: (*Server).createRawTransaction},
	"createsignature":         {fn: (*Server).createSignature},
	"disapprovepercent":       {fn: (*Server).disapprovePercent},
	"discoverusage":           {fn: (*Server).discoverUsage},
	"dumpprivkey":             {fn: (*Server).dumpPrivKey},
	"fundrawtransaction":      {fn: (*Server).fundRawTransaction},
	"generatevote":            {fn: (*Server).generateVote},
	"getaccount":              {fn: (*Server).getAccount},
	"getaccountaddress":       {fn: (*Server).getAccountAddress},
	"getaddressesbyaccount":   {fn: (*Server).getAddressesByAccount},
	"getbalance":              {fn: (*Server).getBalance},
	"getbestblock":            {fn: (*Server).getBestBlock},
	"getbestblockhash":        {fn: (*Server).getBestBlockHash},
	"getblockcount":           {fn: (*Server).getBlockCount},
	"getblockhash":            {fn: (*Server).getBlockHash},
	"getblockheader":          {fn: (*Server).getBlockHeader},
	"getblock":                {fn: (*Server).getBlock},
	"getcoinjoinsbyacct":      {fn: (*Server).getcoinjoinsbyacct},
	"getcurrentnet":           {fn: (*Server).getCurrentNet},
	"getinfo":                 {fn: (*Server).getInfo},
	"getmasterpubkey":         {fn: (*Server).getMasterPubkey},
	"getmultisigoutinfo":      {fn: (*Server).getMultisigOutInfo},
	"getnewaddress":           {fn: (*Server).getNewAddress},
	"getpeerinfo":             {fn: (*Server).getPeerInfo},
	"getrawchangeaddress":     {fn: (*Server).getRawChangeAddress},
	"getreceivedbyaccount":    {fn: (*Server).getReceivedByAccount},
	"getreceivedbyaddress":    {fn: (*Server).getReceivedByAddress},
	"getstakeinfo":            {fn: (*Server).getStakeInfo},
	"gettickets":              {fn: (*Server).getTickets},
	"gettransaction":          {fn: (*Server).getTransaction},
	"gettxout":                {fn: (*Server).getTxOut},
	"getunconfirmedbalance":   {fn: (*Server).getUnconfirmedBalance},
	"getvotechoices":          {fn: (*Server).getVoteChoices},
	"getwalletfee":            {fn: (*Server).getWalletFee},
	"help":                    {fn: (*Server).help},
	"getcfilterv2":            {fn: (*Server).getCFilterV2},
	"importcfiltersv2":        {fn: (*Server).importCFiltersV2},
	"importprivkey":           {fn: (*Server).importPrivKey},
	"importscript":            {fn: (*Server).importScript},
	"importxpub":              {fn: (*Server).importXpub},
	"listaccounts":            {fn: (*Server).listAccounts},
	"listaddresstransactions": {fn: (*Server).listAddressTransactions},
	"listalltransactions":     {fn: (*Server).listAllTransactions},
	"listlockunspent":         {fn: (*Server).listLockUnspent},
	"listreceivedbyaccount":   {fn: (*Server).listReceivedByAccount},
	"listreceivedbyaddress":   {fn: (*Server).listReceivedByAddress},
	"listsinceblock":          {fn: (*Server).listSinceBlock},
	"listtransactions":        {fn: (*Server).listTransactions},
	"listunspent":             {fn: (*Server).listUnspent},
	"lockaccount":             {fn: (*Server).lockAccount},
	"lockunspent":             {fn: (*Server).lockUnspent},
	"mixaccount":              {fn: (*Server).mixAccount},
	"mixoutput":               {fn: (*Server).mixOutput},
	"purchaseticket":          {fn: (*Server).purchaseTicket},
	"processunmanagedticket":  {fn: (*Server).processUnmanagedTicket},
	"redeemmultisigout":       {fn: (*Server).redeemMultiSigOut},
	"redeemmultisigouts":      {fn: (*Server).redeemMultiSigOuts},
	"renameaccount":           {fn: (*Server).renameAccount},
	"rescanwallet":            {fn: (*Server).rescanWallet},
	"revoketickets":           {fn: (*Server).revokeTickets},
	"sendfrom":                {fn: (*Server).sendFrom},
	"sendfromtreasury":        {fn: (*Server).sendFromTreasury},
	"sendmany":                {fn: (*Server).sendMany},
	"sendrawtransaction":      {fn: (*Server).sendRawTransaction},
	"sendtoaddress":           {fn: (*Server).sendToAddress},
	"sendtomultisig":          {fn: (*Server).sendToMultiSig},
	"sendtotreasury":          {fn: (*Server).sendToTreasury},
	"setaccountpassphrase":    {fn: (*Server).setAccountPassphrase},
	"setdisapprovepercent":    {fn: (*Server).setDisapprovePercent},
	"settreasurypolicy":       {fn: (*Server).setTreasuryPolicy},
	"settspendpolicy":         {fn: (*Server).setTSpendPolicy},
	"settxfee":                {fn: (*Server).setTxFee},
	"setvotechoice":           {fn: (*Server).setVoteChoice},
	"signmessage":             {fn: (*Server).signMessage},
	"signrawtransaction":      {fn: (*Server).signRawTransaction},
	"signrawtransactions":     {fn: (*Server).signRawTransactions},
	"stakepooluserinfo":       {fn: (*Server).stakePoolUserInfo},
	"sweepaccount":            {fn: (*Server).sweepAccount},
	"syncstatus":              {fn: (*Server).syncStatus},
	"ticketinfo":              {fn: (*Server).ticketInfo},
	"ticketsforaddress":       {fn: (*Server).ticketsForAddress},
	"treasurypolicy":          {fn: (*Server).treasuryPolicy},
	"tspendpolicy":            {fn: (*Server).tspendPolicy},
	"unlockaccount":           {fn: (*Server).unlockAccount},
	"validateaddress":         {fn: (*Server).validateAddress},
	"validatepredcp0005cf":    {fn: (*Server).validatePreDCP0005CF},
	"verifymessage":           {fn: (*Server).verifyMessage},
	"version":                 {fn: (*Server).version},
	"walletinfo":              {fn: (*Server).walletInfo},
	"walletislocked":          {fn: (*Server).walletIsLocked},
	"walletlock":              {fn: (*Server).walletLock},
	"walletpassphrase":        {fn: (*Server).walletPassphrase},
	"walletpassphrasechange":  {fn: (*Server).walletPassphraseChange},
	"backupwallet":         {fn: unimplemented, noHelp: true},
	"getwalletinfo":        {fn: unimplemented, noHelp: true},
	"importwallet":         {fn: unimplemented, noHelp: true},
	"listaddressgroupings": {fn: unimplemented, noHelp: true},
	"dumpwallet":           {fn: unsupported, noHelp: true},
	"encryptwallet":        {fn: unsupported, noHelp: true},
	"move":                 {fn: unsupported, noHelp: true},
	"setaccount":           {fn: unsupported, noHelp: true},
}
func unimplemented(*Server, context.Context, interface{}) (interface{}, error) {
	return nil, &dcrjson.RPCError{
		Code:    dcrjson.ErrRPCUnimplemented,
		Message: "Method unimplemented",
	}
}
func unsupported(*Server, context.Context, interface{}) (interface{}, error) {
	return nil, &dcrjson.RPCError{
		Code:    -1,
		Message: "Request unsupported by dcrwallet",
	}
}
type lazyHandler func() (interface{}, *dcrjson.RPCError)