methods.go raw

   1  package wallet
   2  
   3  import (
   4  	"bytes"
   5  	"encoding/base64"
   6  	"encoding/hex"
   7  	js "encoding/json"
   8  	"errors"
   9  	"fmt"
  10  	"sync"
  11  	"time"
  12  
  13  	"github.com/p9c/p9/pkg/amt"
  14  	"github.com/p9c/p9/pkg/btcaddr"
  15  	"github.com/p9c/p9/pkg/chaincfg"
  16  
  17  	"github.com/p9c/p9/pkg/btcjson"
  18  	"github.com/p9c/p9/pkg/chainclient"
  19  	"github.com/p9c/p9/pkg/chainhash"
  20  	"github.com/p9c/p9/pkg/ecc"
  21  	"github.com/p9c/p9/pkg/interrupt"
  22  	"github.com/p9c/p9/pkg/rpcclient"
  23  	"github.com/p9c/p9/pkg/txrules"
  24  	"github.com/p9c/p9/pkg/txscript"
  25  	"github.com/p9c/p9/pkg/util"
  26  	"github.com/p9c/p9/pkg/waddrmgr"
  27  	"github.com/p9c/p9/pkg/wire"
  28  	"github.com/p9c/p9/pkg/wtxmgr"
  29  )
  30  
  31  // // confirmed checks whether a transaction at height txHeight has met minconf
  32  // // confirmations for a blockchain at height curHeight.
  33  // func confirmed(// 	minconf, txHeight, curHeight int32) bool {
  34  // 	return confirms(txHeight, curHeight) >= minconf
  35  // }
  36  
  37  // Confirms returns the number of confirmations for a transaction in a block at height txHeight (or -1 for an
  38  // unconfirmed tx) given the chain height curHeight.
  39  func Confirms(txHeight, curHeight int32) int32 {
  40  	switch {
  41  	case txHeight == -1, txHeight > curHeight:
  42  		return 0
  43  	default:
  44  		return curHeight - txHeight + 1
  45  	}
  46  }
  47  
  48  // var RPCHandlers = map[string]struct {
  49  // 	Handler          RequestHandler
  50  // 	HandlerWithChain RequestHandlerChainRequired
  51  // 	// Function variables cannot be compared against anything but nil, so
  52  // 	// use a boolean to record whether help generation is necessary.  This
  53  // 	// is used by the tests to ensure that help can be generated for every
  54  // 	// implemented method.
  55  // 	//
  56  // 	// A single map and this bool is here is used rather than several maps
  57  // 	// for the unimplemented handlers so every method has exactly one
  58  // 	// handler function.
  59  // 	//
  60  // 	// The Return field returns a new channel of the type returned by this function. This makes it possible to
  61  // 	// use this for callers to receive a response in the `cpc` library which implements the functions as channel pipes
  62  // 	NoHelp bool
  63  // 	Params interface{}
  64  // 	Return func() interface{}
  65  // }{
  66  // 	// Reference implementation wallet methods (implemented)
  67  // 	"addmultisigaddress": {
  68  // 		Handler: AddMultiSigAddress,
  69  // 		Params:  make(chan btcjson.AddMultisigAddressCmd),
  70  // 		Return:  func() interface{} { return make(chan AddMultiSigAddressRes) },
  71  // 	},
  72  // 	"createmultisig": {
  73  // 		Handler: CreateMultiSig,
  74  // 		Params:  make(chan btcjson.CreateMultisigCmd),
  75  // 		Return:  func() interface{} { return make(chan CreateMultiSigRes) },
  76  // 	},
  77  // 	"dumpprivkey": {
  78  // 		Handler: DumpPrivKey,
  79  // 		Params:  make(chan btcjson.DumpPrivKeyCmd),
  80  // 		Return:  func() interface{} { return make(chan DumpPrivKeyRes) },
  81  // 	},
  82  // 	"getaccount": {
  83  // 		Handler: GetAccount,
  84  // 		Params:  make(chan btcjson.GetAccountCmd),
  85  // 		Return:  func() interface{} { return make(chan GetAccountRes) },
  86  // 	},
  87  // 	"getaccountaddress": {
  88  // 		Handler: GetAccountAddress,
  89  // 		Params:  make(chan btcjson.GetAccountAddressCmd),
  90  // 		Return:  func() interface{} { return make(chan GetAccountAddressRes) },
  91  // 	},
  92  // 	"getaddressesbyaccount": {
  93  // 		Handler: GetAddressesByAccount,
  94  // 		Params:  make(chan btcjson.GetAddressesByAccountCmd),
  95  // 		Return:  func() interface{} { return make(chan GetAddressesByAccountRes) },
  96  // 	},
  97  // 	"getbalance": {
  98  // 		Handler: GetBalance,
  99  // 		Params:  make(chan btcjson.GetBalanceCmd),
 100  // 		Return:  func() interface{} { return make(chan GetBalanceRes) },
 101  // 	},
 102  // 	"getbestblockhash": {
 103  // 		Handler: GetBestBlockHash,
 104  // 		Return:  func() interface{} { return make(chan GetBestBlockHashRes) },
 105  // 	},
 106  // 	"getblockcount": {
 107  // 		Handler: GetBlockCount,
 108  // 		Return:  func() interface{} { return make(chan GetBlockCountRes) },
 109  // 	},
 110  // 	"getinfo": {
 111  // 		HandlerWithChain: GetInfo,
 112  // 		Return:           func() interface{} { return make(chan GetInfoRes) },
 113  // 	},
 114  // 	"getnewaddress": {
 115  // 		Handler: GetNewAddress,
 116  // 		Params:  make(chan btcjson.GetNewAddressCmd),
 117  // 		Return:  func() interface{} { return make(chan GetNewAddressRes) },
 118  // 	},
 119  // 	"getrawchangeaddress": {
 120  // 		Handler: GetRawChangeAddress,
 121  // 		Params:  make(chan btcjson.GetRawChangeAddressCmd),
 122  // 		Return:  func() interface{} { return make(chan GetRawChangeAddressRes) },
 123  // 	},
 124  // 	"getreceivedbyaccount": {
 125  // 		Handler: GetReceivedByAccount,
 126  // 		Params:  make(chan btcjson.GetReceivedByAccountCmd),
 127  // 		Return:  func() interface{} { return make(chan GetReceivedByAccountRes) },
 128  // 	},
 129  // 	"getreceivedbyaddress": {
 130  // 		Handler: GetReceivedByAddress,
 131  // 		Params:  make(chan btcjson.GetReceivedByAddressCmd),
 132  // 		Return:  func() interface{} { return make(chan GetReceivedByAddressRes) },
 133  // 	},
 134  // 	"gettransaction": {
 135  // 		Handler: GetTransaction,
 136  // 		Params:  make(chan btcjson.GetTransactionCmd),
 137  // 		Return:  func() interface{} { return make(chan GetTransactionRes) },
 138  // 	},
 139  // 	"help": {
 140  // 		Handler:          HelpNoChainRPC,
 141  // 		HandlerWithChain: HelpWithChainRPC,
 142  // 		Params:           make(chan btcjson.HelpCmd),
 143  // 		Return:           func() interface{} { return make(chan HelpNoChainRPCRes) },
 144  // 	},
 145  // 	"importprivkey": {
 146  // 		Handler: ImportPrivKey,
 147  // 		Params:  make(chan btcjson.ImportPrivKeyCmd),
 148  // 		Return:  func() interface{} { return make(chan ImportPrivKeyRes) },
 149  // 	},
 150  // 	"keypoolrefill": {
 151  // 		Handler: KeypoolRefill,
 152  // 		Params:  qu.T(),
 153  // 		Return:  func() interface{} { return make(chan KeypoolRefillRes) },
 154  // 	},
 155  // 	"listaccounts": {
 156  // 		Handler: ListAccounts,
 157  // 		Params:  make(chan btcjson.ListAccountsCmd),
 158  // 		Return:  func() interface{} { return make(chan ListAccountsRes) },
 159  // 	},
 160  // 	"listlockunspent": {
 161  // 		Handler: ListLockUnspent,
 162  // 		Params:  qu.T(),
 163  // 		Return:  func() interface{} { return make(chan ListLockUnspentRes) },
 164  // 	},
 165  // 	"listreceivedbyaccount": {
 166  // 		Handler: ListReceivedByAccount,
 167  // 		Params:  make(chan btcjson.ListReceivedByAccountCmd),
 168  // 		Return:  func() interface{} { return make(chan ListReceivedByAccountRes) },
 169  // 	},
 170  // 	"listreceivedbyaddress": {
 171  // 		Handler: ListReceivedByAddress,
 172  // 		Params:  make(chan btcjson.ListReceivedByAddressCmd),
 173  // 		Return:  func() interface{} { return make(chan ListReceivedByAddressRes) },
 174  // 	},
 175  // 	"listsinceblock": {
 176  // 		HandlerWithChain: ListSinceBlock,
 177  // 		Params:           make(chan btcjson.ListSinceBlockCmd),
 178  // 		Return:           func() interface{} { return make(chan ListSinceBlockRes) },
 179  // 	},
 180  // 	"listtransactions": {
 181  // 		Handler: ListTransactions,
 182  // 		Params:  make(chan btcjson.ListTransactionsCmd),
 183  // 		Return:  func() interface{} { return make(chan ListTransactionsRes) },
 184  // 	},
 185  // 	"listunspent": {
 186  // 		Handler: ListUnspent,
 187  // 		Params:  make(chan btcjson.ListUnspentCmd),
 188  // 		Return:  func() interface{} { return make(chan ListUnspentRes) },
 189  // 	},
 190  // 	"lockunspent": {
 191  // 		Handler: LockUnspent,
 192  // 		Params:  make(chan btcjson.LockUnspentCmd),
 193  // 		Return:  func() interface{} { return make(chan LockUnspentRes) },
 194  // 	},
 195  // 	"sendfrom": {
 196  // 		HandlerWithChain: SendFrom,
 197  // 		Params:           make(chan btcjson.SendFromCmd),
 198  // 		Return:           func() interface{} { return make(chan SendFromRes) },
 199  // 	},
 200  // 	"sendmany": {
 201  // 		Handler: SendMany,
 202  // 		Params:  make(chan btcjson.SendManyCmd),
 203  // 		Return:  func() interface{} { return make(chan SendManyRes) },
 204  // 	},
 205  // 	"sendtoaddress": {
 206  // 		Handler: SendToAddress,
 207  // 		Params:  make(chan btcjson.SendToAddressCmd),
 208  // 		Return:  func() interface{} { return make(chan SendToAddressRes) },
 209  // 	},
 210  // 	"settxfee": {
 211  // 		Handler: SetTxFee,
 212  // 		Params:  make(chan btcjson.SetTxFeeCmd),
 213  // 		Return:  func() interface{} { return make(chan SetTxFeeRes) },
 214  // 	},
 215  // 	"signmessage": {
 216  // 		Handler: SignMessage,
 217  // 		Params:  make(chan btcjson.SignMessageCmd),
 218  // 		Return:  func() interface{} { return make(chan SignMessageRes) },
 219  // 	},
 220  // 	"signrawtransaction": {
 221  // 		HandlerWithChain: SignRawTransaction,
 222  // 		Params:           make(chan btcjson.SignRawTransactionCmd),
 223  // 		Return:           func() interface{} { return make(chan SignRawTransactionRes) },
 224  // 	},
 225  // 	"validateaddress": {
 226  // 		Handler: ValidateAddress,
 227  // 		Params:  make(chan btcjson.ValidateAddressCmd),
 228  // 		Return:  func() interface{} { return make(chan ValidateAddressRes) },
 229  // 	},
 230  // 	"verifymessage": {
 231  // 		Handler: VerifyMessage,
 232  // 		Params:  make(chan btcjson.VerifyMessageCmd),
 233  // 		Return:  func() interface{} { return make(chan VerifyMessageRes) },
 234  // 	},
 235  // 	"walletlock": {
 236  // 		Handler: WalletLock,
 237  // 		Params:  qu.T(),
 238  // 		Return:  func() interface{} { return make(chan WalletLockRes) },
 239  // 	},
 240  // 	"walletpassphrase": {
 241  // 		Handler: WalletPassphrase,
 242  // 		Params:  make(chan btcjson.WalletPassphraseCmd),
 243  // 		Return:  func() interface{} { return make(chan WalletPassphraseRes) },
 244  // 	},
 245  // 	"walletpassphrasechange": {
 246  // 		Handler: WalletPassphraseChange,
 247  // 		Params:  make(chan btcjson.WalletPassphraseChangeCmd),
 248  // 		Return:  func() interface{} { return make(chan WalletPassphraseChangeRes) },
 249  // 	},
 250  // 	// Reference implementation methods (still unimplemented)
 251  // 	"backupwallet":         {Handler: Unimplemented, NoHelp: true},
 252  // 	"dumpwallet":           {Handler: Unimplemented, NoHelp: true},
 253  // 	"getwalletinfo":        {Handler: Unimplemented, NoHelp: true},
 254  // 	"importwallet":         {Handler: Unimplemented, NoHelp: true},
 255  // 	"listaddressgroupings": {Handler: Unimplemented, NoHelp: true},
 256  // 	// Reference methods which can't be implemented by btcwallet due to
 257  // 	// design decision differences
 258  // 	"encryptwallet": {Handler: Unsupported, NoHelp: true},
 259  // 	"move":          {Handler: Unsupported, NoHelp: true},
 260  // 	"setaccount":    {Handler: Unsupported, NoHelp: true},
 261  // 	// Extensions to the reference client JSON-RPC API
 262  // 	"createnewaccount": {
 263  // 		Handler: CreateNewAccount,
 264  // 		Params:  make(chan btcjson.CreateNewAccountCmd),
 265  // 		Return:  func() interface{} { return make(chan CreateNewAccountRes) },
 266  // 	},
 267  // 	"getbestblock": {
 268  // 		Handler: GetBestBlock,
 269  // 		Params:  qu.T(),
 270  // 		Return:  func() interface{} { return make(chan GetBestBlockRes) },
 271  // 	},
 272  // 	// This was an extension but the reference implementation added it as
 273  // 	// well, but with a different API (no account parameter).  It's listed
 274  // 	// here because it hasn't been update to use the reference
 275  // 	// implemenation's API.
 276  // 	"getunconfirmedbalance": {
 277  // 		Handler: GetUnconfirmedBalance,
 278  // 		Params:  make(chan btcjson.GetUnconfirmedBalanceCmd),
 279  // 		Return:  func() interface{} { return make(chan GetUnconfirmedBalanceRes) },
 280  // 	},
 281  // 	"listaddresstransactions": {
 282  // 		Handler: ListAddressTransactions,
 283  // 		Params:  make(chan btcjson.ListAddressTransactionsCmd),
 284  // 		Return:  func() interface{} { return make(chan ListAddressTransactionsRes) },
 285  // 	},
 286  // 	"listalltransactions": {
 287  // 		Handler: ListAllTransactions,
 288  // 		Params:  make(chan btcjson.ListAllTransactionsCmd),
 289  // 		Return:  func() interface{} { return make(chan ListAllTransactionsRes) },
 290  // 	},
 291  // 	"renameaccount": {
 292  // 		Handler: RenameAccount,
 293  // 		Params:  make(chan btcjson.RenameAccountCmd),
 294  // 		Return:  func() interface{} { return make(chan RenameAccountRes) },
 295  // 	},
 296  // 	"walletislocked": {
 297  // 		Handler: WalletIsLocked,
 298  // 		Params:  qu.T(),
 299  // 		Return:  func() interface{} { return make(chan WalletIsLockedRes) },
 300  // 	},
 301  // 	"dropwallethistory": {
 302  // 		Handler: HandleDropWalletHistory,
 303  // 		Params:  qu.T(),
 304  // 		Return:  func() interface{} { return make(chan DropWalletHistoryRes) },
 305  // 	},
 306  // }
 307  
 308  // Unimplemented handles an Unimplemented RPC request with the
 309  // appropiate error.
 310  func Unimplemented(interface{}, *Wallet) (interface{}, error) {
 311  	return nil, &btcjson.RPCError{
 312  		Code:    btcjson.ErrRPCUnimplemented,
 313  		Message: "Method unimplemented",
 314  	}
 315  }
 316  
 317  // Unsupported handles a standard bitcoind RPC request which is Unsupported by btcwallet due to design differences.
 318  func Unsupported(interface{}, *Wallet) (interface{}, error) {
 319  	return nil, &btcjson.RPCError{
 320  		Code:    -1,
 321  		Message: "Request unsupported by wallet",
 322  	}
 323  }
 324  
 325  // LazyHandler is a closure over a requestHandler or passthrough request with the RPC server's wallet and chain server
 326  // variables as part of the closure context.
 327  type LazyHandler func() (interface{}, *btcjson.RPCError)
 328  
 329  // LazyApplyHandler looks up the best request handler func for the method, returning a closure that will execute it with
 330  // the (required) wallet and (optional) consensus RPC server. If no handlers are found and the chainClient is not nil,
 331  // the returned handler performs RPC passthrough.
 332  func LazyApplyHandler(request *btcjson.Request, w *Wallet, chainClient chainclient.Interface) LazyHandler {
 333  	handlerData, ok := RPCHandlers[request.Method]
 334  	D.Ln("LazyApplyHandler >>> >>> >>>", ok, handlerData.Handler != nil, w != nil, chainClient != nil)
 335  	if ok && handlerData.Handler != nil && w != nil && chainClient != nil {
 336  		D.Ln("found handler for call")
 337  		// D.S(request)
 338  		return func() (interface{}, *btcjson.RPCError) {
 339  			cmd, e := btcjson.UnmarshalCmd(request)
 340  			if e != nil {
 341  				return nil, btcjson.ErrRPCInvalidRequest
 342  			}
 343  			switch client := chainClient.(type) {
 344  			case *chainclient.RPCClient:
 345  				D.Ln("client is a chain.RPCClient")
 346  				var resp interface{}
 347  				if resp, e = handlerData.Handler(cmd, w, client); E.Chk(e) {
 348  					return nil, JSONError(e)
 349  				}
 350  				D.Ln("handler call succeeded")
 351  				return resp, nil
 352  			default:
 353  				D.Ln("client is unknown")
 354  				return nil, &btcjson.RPCError{
 355  					Code:    -1,
 356  					Message: "Chain RPC is inactive",
 357  				}
 358  			}
 359  		}
 360  	}
 361  	D.Ln("failed to find handler for call")
 362  	// I.Ln("handler", handlerData.Handler, "wallet", w)
 363  	if ok && handlerData.Handler != nil && w != nil {
 364  		D.Ln("handling", request.Method)
 365  		return func() (interface{}, *btcjson.RPCError) {
 366  			cmd, e := btcjson.UnmarshalCmd(request)
 367  			if e != nil {
 368  				return nil, btcjson.ErrRPCInvalidRequest
 369  			}
 370  			var resp interface{}
 371  			if resp, e = handlerData.Handler(cmd, w); E.Chk(e) {
 372  				return nil, JSONError(e)
 373  			}
 374  			return resp, nil
 375  		}
 376  	}
 377  	// Fallback to RPC passthrough
 378  	return func() (interface{}, *btcjson.RPCError) {
 379  		I.Ln("passing to node", request.Method)
 380  		if chainClient == nil {
 381  			return nil, &btcjson.RPCError{
 382  				Code:    -1,
 383  				Message: "Chain RPC is inactive",
 384  			}
 385  		}
 386  		switch client := chainClient.(type) {
 387  		case *chainclient.RPCClient:
 388  			resp, e := client.RawRequest(
 389  				request.Method,
 390  				request.Params,
 391  			)
 392  			if e != nil {
 393  				return nil, JSONError(e)
 394  			}
 395  			return &resp, nil
 396  		default:
 397  			return nil, &btcjson.RPCError{
 398  				Code:    -1,
 399  				Message: "Chain RPC is inactive",
 400  			}
 401  		}
 402  	}
 403  }
 404  
 405  // MakeResponse makes the JSON-RPC response struct for the result and error returned by a requestHandler. The returned
 406  // response is not ready for marshaling and sending off to a client, but must be
 407  func MakeResponse(id, result interface{}, e error) btcjson.Response {
 408  	idPtr := IDPointer(id)
 409  	if e != nil {
 410  		return btcjson.Response{
 411  			ID:    idPtr,
 412  			Error: JSONError(e),
 413  		}
 414  	}
 415  	var resultBytes []byte
 416  	resultBytes, e = js.Marshal(result)
 417  	if e != nil {
 418  		return btcjson.Response{
 419  			ID: idPtr,
 420  			Error: &btcjson.RPCError{
 421  				Code:    btcjson.ErrRPCInternal.Code,
 422  				Message: "Unexpected error marshalling result",
 423  			},
 424  		}
 425  	}
 426  	return btcjson.Response{
 427  		ID:     idPtr,
 428  		Result: resultBytes,
 429  	}
 430  }
 431  
 432  // JSONError creates a JSON-RPC error from the Go error.
 433  func JSONError(e error) *btcjson.RPCError {
 434  	if e == nil {
 435  		return nil
 436  	}
 437  	code := btcjson.ErrRPCWallet
 438  	switch e := e.(type) {
 439  	case btcjson.RPCError:
 440  		return &e
 441  	case *btcjson.RPCError:
 442  		return e
 443  	case DeserializationError:
 444  		code = btcjson.ErrRPCDeserialization
 445  	case InvalidParameterError:
 446  		code = btcjson.ErrRPCInvalidParameter
 447  	case ParseError:
 448  		code = btcjson.ErrRPCParse.Code
 449  	case waddrmgr.ManagerError:
 450  		switch e.ErrorCode {
 451  		case waddrmgr.ErrWrongPassphrase:
 452  			code = btcjson.ErrRPCWalletPassphraseIncorrect
 453  		}
 454  	}
 455  	return &btcjson.RPCError{
 456  		Code:    code,
 457  		Message: e.Error(),
 458  	}
 459  }
 460  
 461  // MakeMultiSigScript is a helper function to combine common logic for AddMultiSig and CreateMultiSig.
 462  func MakeMultiSigScript(w *Wallet, keys []string, nRequired int) ([]byte, error) {
 463  	keysesPrecious := make([]*btcaddr.PubKey, len(keys))
 464  	// The address list will made up either of addresses (pubkey hash), for which we need to look up the keys in
 465  	// wallet, straight pubkeys, or a mixture of the two.
 466  	for i, a := range keys {
 467  		// try to parse as pubkey address
 468  		a, e := DecodeAddress(a, w.ChainParams())
 469  		if e != nil {
 470  			return nil, e
 471  		}
 472  		switch addr := a.(type) {
 473  		case *btcaddr.PubKey:
 474  			keysesPrecious[i] = addr
 475  		default:
 476  			pubKey, e := w.PubKeyForAddress(addr)
 477  			if e != nil {
 478  				return nil, e
 479  			}
 480  			pubKeyAddr, e := btcaddr.NewPubKey(
 481  				pubKey.SerializeCompressed(), w.ChainParams(),
 482  			)
 483  			if e != nil {
 484  				return nil, e
 485  			}
 486  			keysesPrecious[i] = pubKeyAddr
 487  		}
 488  	}
 489  	return txscript.MultiSigScript(keysesPrecious, nRequired)
 490  }
 491  
 492  // AddMultiSigAddress handles an addmultisigaddress request by adding a
 493  // multisig address to the given wallet.
 494  func AddMultiSigAddress(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (
 495  	interface{},
 496  	error,
 497  ) {
 498  	var msg string
 499  	cmd, ok := icmd.(*btcjson.AddMultisigAddressCmd)
 500  	// cmd, ok := icmd.(*btcjson.ListTransactionsCmd)
 501  	if !ok {
 502  		var h string
 503  		h = HelpDescsEnUS()["addmultisigaddress"]
 504  		msg += h
 505  		return nil, &btcjson.RPCError{
 506  			Code:    btcjson.ErrRPCInvalidParameter,
 507  			Message: msg,
 508  			// "invalid subcommand for addnode",
 509  		}
 510  	}
 511  	// If an account is specified, ensure that is the imported account.
 512  	if cmd.Account != nil && *cmd.Account != waddrmgr.ImportedAddrAccountName {
 513  		return nil, &ErrNotImportedAccount
 514  	}
 515  	secp256k1Addrs := make([]btcaddr.Address, len(cmd.Keys))
 516  	for i, k := range cmd.Keys {
 517  		addr, e := DecodeAddress(k, w.ChainParams())
 518  		if e != nil {
 519  			return nil, ParseError{e}
 520  		}
 521  		secp256k1Addrs[i] = addr
 522  	}
 523  	script, e := w.MakeMultiSigScript(secp256k1Addrs, cmd.NRequired)
 524  	if e != nil {
 525  		return nil, e
 526  	}
 527  	p2shAddr, e := w.ImportP2SHRedeemScript(script)
 528  	if e != nil {
 529  		return nil, e
 530  	}
 531  	return p2shAddr.EncodeAddress(), nil
 532  }
 533  
 534  // CreateMultiSig handles an createmultisig request by returning a multisig address for the given inputs.
 535  func CreateMultiSig(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (interface{}, error) {
 536  	var msg string
 537  	cmd, ok := icmd.(*btcjson.CreateMultisigCmd)
 538  	if !ok {
 539  		var h string
 540  		h = HelpDescsEnUS()["createmultisig"]
 541  		msg += h
 542  		return nil, &btcjson.RPCError{
 543  			Code:    btcjson.ErrRPCInvalidParameter,
 544  			Message: msg,
 545  			// "invalid subcommand for addnode",
 546  		}
 547  	}
 548  	script, e := MakeMultiSigScript(w, cmd.Keys, cmd.NRequired)
 549  	if e != nil {
 550  		return nil, ParseError{e}
 551  	}
 552  	address, e := btcaddr.NewScriptHash(script, w.ChainParams())
 553  	if e != nil {
 554  		// above is a valid script, shouldn't happen.
 555  		return nil, e
 556  	}
 557  	return btcjson.CreateMultiSigResult{
 558  		Address:      address.EncodeAddress(),
 559  		RedeemScript: hex.EncodeToString(script),
 560  	}, nil
 561  }
 562  
 563  // DumpPrivKey handles a dumpprivkey request with the private key for a single address, or an appropriate error if the
 564  // wallet is locked.
 565  func DumpPrivKey(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (interface{}, error) {
 566  	var msg string
 567  	cmd, ok := icmd.(*btcjson.DumpPrivKeyCmd)
 568  	if !ok {
 569  		msg = HelpDescsEnUS()["dumpprivkey"]
 570  		return nil, &btcjson.RPCError{
 571  			Code:    btcjson.ErrRPCInvalidParameter,
 572  			Message: msg,
 573  			// "invalid subcommand for addnode",
 574  		}
 575  	}
 576  	addr, e := DecodeAddress(cmd.Address, w.ChainParams())
 577  	if e != nil {
 578  		return nil, e
 579  	}
 580  	key, e := w.DumpWIFPrivateKey(addr)
 581  	if waddrmgr.IsError(e, waddrmgr.ErrLocked) {
 582  		// Address was found, but the private key isn't accessible.
 583  		return nil, &ErrWalletUnlockNeeded
 584  	}
 585  	return key, e
 586  }
 587  
 588  // // dumpWallet handles a dumpwallet request by returning  all private
 589  // // keys in a wallet, or an appropiate error if the wallet is locked.
 590  // // TODO: finish this to match bitcoind by writing the dump to a file.
 591  // func dumpWallet(// 	icmd interface{}, w *wallet.Wallet) (interface{}, error) {
 592  // 	keys, e := w.DumpPrivKeys()
 593  // 	if waddrmgr.IsError(err, waddrmgr.ErrLocked) {
 594  // 		return nil, &ErrWalletUnlockNeeded
 595  // 	}
 596  // 	return keys, err
 597  // }
 598  
 599  // GetAddressesByAccount handles a getaddressesbyaccount request by returning
 600  // all addresses for an account, or an error if the requested account does not
 601  // exist.
 602  func GetAddressesByAccount(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (
 603  	interface{},
 604  	error,
 605  ) {
 606  	cmd, ok := icmd.(*btcjson.GetAddressesByAccountCmd)
 607  	if !ok {
 608  		return nil, &btcjson.RPCError{
 609  			Code:    btcjson.ErrRPCInvalidParameter,
 610  			Message: HelpDescsEnUS()["dumpprivkey"],
 611  			// "invalid subcommand for addnode",
 612  		}
 613  	}
 614  	account, e := w.AccountNumber(waddrmgr.KeyScopeBIP0044, cmd.Account)
 615  	if e != nil {
 616  		return nil, e
 617  	}
 618  	addrs, e := w.AccountAddresses(account)
 619  	if e != nil {
 620  		return nil, e
 621  	}
 622  	addrStrs := make([]string, len(addrs))
 623  	for i, a := range addrs {
 624  		addrStrs[i] = a.EncodeAddress()
 625  	}
 626  	return addrStrs, nil
 627  }
 628  
 629  // GetBalance handles a getbalance request by returning the balance for an
 630  // account (wallet), or an error if the requested account does not exist.
 631  func GetBalance(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (interface{}, error) {
 632  	cmd, ok := icmd.(*btcjson.GetBalanceCmd)
 633  	if !ok {
 634  		return nil, &btcjson.RPCError{
 635  			Code:    btcjson.ErrRPCInvalidParameter,
 636  			Message: HelpDescsEnUS()["getbalance"],
 637  			// "invalid subcommand for addnode",
 638  		}
 639  	}
 640  	var balance amt.Amount
 641  	var e error
 642  	accountName := "*"
 643  	if cmd.Account != nil {
 644  		accountName = *cmd.Account
 645  	}
 646  	if accountName == "*" {
 647  		balance, e = w.CalculateBalance(int32(*cmd.MinConf))
 648  		if e != nil {
 649  			return nil, e
 650  		}
 651  	} else {
 652  		var account uint32
 653  		account, e = w.AccountNumber(waddrmgr.KeyScopeBIP0044, accountName)
 654  		if e != nil {
 655  			return nil, e
 656  		}
 657  		bals, e := w.CalculateAccountBalances(account, int32(*cmd.MinConf))
 658  		if e != nil {
 659  			return nil, e
 660  		}
 661  		balance = bals.Spendable
 662  	}
 663  	return balance.ToDUO(), nil
 664  }
 665  
 666  // GetBestBlock handles a getbestblock request by returning a JSON object with
 667  // the height and hash of the most recently processed block.
 668  func GetBestBlock(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (interface{}, error) {
 669  	blk := w.Manager.SyncedTo()
 670  	result := &btcjson.GetBestBlockResult{
 671  		Hash:   blk.Hash.String(),
 672  		Height: blk.Height,
 673  	}
 674  	return result, nil
 675  }
 676  
 677  // GetBestBlockHash handles a getbestblockhash request by returning the hash of
 678  // the most recently processed block.
 679  func GetBestBlockHash(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (interface{}, error) {
 680  	blk := w.Manager.SyncedTo()
 681  	return blk.Hash.String(), nil
 682  }
 683  
 684  // GetBlockCount handles a getblockcount request by returning the chain height
 685  // of the most recently processed block.
 686  func GetBlockCount(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (interface{}, error) {
 687  	blk := w.Manager.SyncedTo()
 688  	return blk.Height, nil
 689  }
 690  
 691  // GetInfo handles a getinfo request by returning the a structure containing
 692  // information about the current state of btcwallet. exist.
 693  func GetInfo(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (interface{}, error) {
 694  	if len(chainClient) < 1 || chainClient[0] == nil {
 695  		return nil, &btcjson.RPCError{
 696  			Code:    btcjson.ErrRPCNoChain,
 697  			Message: "there is currently no chain client to get this response",
 698  		}
 699  	}
 700  	// Call down to pod for all of the information in this command known by them.
 701  	var info *btcjson.InfoWalletResult
 702  	var e error
 703  	info, e = chainClient[0].GetInfo()
 704  	if e != nil {
 705  		return nil, e
 706  	}
 707  	var bal amt.Amount
 708  	bal, e = w.CalculateBalance(1)
 709  	if e != nil {
 710  		return nil, e
 711  	}
 712  	// TODO(davec): This should probably have a database version as opposed
 713  	//  to using the manager version.
 714  	info.WalletVersion = int32(waddrmgr.LatestMgrVersion)
 715  	info.Balance = bal.ToDUO()
 716  	info.PaytxFee = float64(txrules.DefaultRelayFeePerKb)
 717  	// We don't set the following since they don't make much sense in the wallet architecture:
 718  	//
 719  	//  - unlocked_until
 720  	//  - errors
 721  	return info, nil
 722  }
 723  
 724  func DecodeAddress(s string, params *chaincfg.Params) (btcaddr.Address, error) {
 725  	addr, e := btcaddr.Decode(s, params)
 726  	if e != nil {
 727  		msg := fmt.Sprintf("Invalid address %q: decode failed with %#q", s, e)
 728  		return nil, &btcjson.RPCError{
 729  			Code:    btcjson.ErrRPCInvalidAddressOrKey,
 730  			Message: msg,
 731  		}
 732  	}
 733  	if !addr.IsForNet(params) {
 734  		msg := fmt.Sprintf(
 735  			"Invalid address %q: not intended for use on %s",
 736  			addr, params.Name,
 737  		)
 738  		return nil, &btcjson.RPCError{
 739  			Code:    btcjson.ErrRPCInvalidAddressOrKey,
 740  			Message: msg,
 741  		}
 742  	}
 743  	return addr, nil
 744  }
 745  
 746  // GetAccount handles a getaccount request by returning the account name
 747  // associated with a single address.
 748  func GetAccount(
 749  	icmd interface{}, w *Wallet,
 750  	chainClient ...*chainclient.RPCClient,
 751  ) (interface{}, error) {
 752  	cmd, ok := icmd.(*btcjson.GetAccountCmd)
 753  	if !ok {
 754  		return nil, &btcjson.RPCError{
 755  			Code:    btcjson.ErrRPCInvalidParameter,
 756  			Message: HelpDescsEnUS()["getaccount"],
 757  			// "invalid subcommand for addnode",
 758  		}
 759  	}
 760  	addr, e := DecodeAddress(cmd.Address, w.ChainParams())
 761  	if e != nil {
 762  		return nil, e
 763  	}
 764  	// Fetch the associated account
 765  	account, e := w.AccountOfAddress(addr)
 766  	if e != nil {
 767  		return nil, &ErrAddressNotInWallet
 768  	}
 769  	acctName, e := w.AccountName(waddrmgr.KeyScopeBIP0044, account)
 770  	if e != nil {
 771  		return nil, &ErrAccountNameNotFound
 772  	}
 773  	return acctName, nil
 774  }
 775  
 776  // GetAccountAddress handles a getaccountaddress by returning the most
 777  // recently-created chained address that has not yet been used (does not yet
 778  // appear in the blockchain, or any tx that has arrived in the pod mempool).
 779  //
 780  // If the most recently-requested address has been used, a new address (the next
 781  // chained address in the keypool) is used. This can fail if the keypool runs
 782  // out (and will return json.ErrRPCWalletKeypoolRanOut if that happens).
 783  func GetAccountAddress(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (interface{}, error) {
 784  	cmd, ok := icmd.(*btcjson.GetAccountAddressCmd)
 785  	if !ok {
 786  		return nil, &btcjson.RPCError{
 787  			Code:    btcjson.ErrRPCInvalidParameter,
 788  			Message: HelpDescsEnUS()["getaccountaddress"],
 789  			// "invalid subcommand for addnode",
 790  		}
 791  	}
 792  	account, e := w.AccountNumber(waddrmgr.KeyScopeBIP0044, cmd.Account)
 793  	if e != nil {
 794  		return nil, e
 795  	}
 796  	addr, e := w.CurrentAddress(account, waddrmgr.KeyScopeBIP0044)
 797  	if e != nil {
 798  		return nil, e
 799  	}
 800  	return addr.EncodeAddress(), e
 801  }
 802  
 803  // GetUnconfirmedBalance handles a getunconfirmedbalance extension request by
 804  // returning the current unconfirmed balance of an account.
 805  func GetUnconfirmedBalance(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (
 806  	interface{},
 807  	error,
 808  ) {
 809  	cmd, ok := icmd.(*btcjson.GetUnconfirmedBalanceCmd)
 810  	if !ok {
 811  		return nil, &btcjson.RPCError{
 812  			Code:    btcjson.ErrRPCInvalidParameter,
 813  			Message: HelpDescsEnUS()["getunconfirmedbalance"],
 814  			// "invalid subcommand for addnode",
 815  		}
 816  	}
 817  	acctName := "default"
 818  	if cmd.Account != nil {
 819  		acctName = *cmd.Account
 820  	}
 821  	account, e := w.AccountNumber(waddrmgr.KeyScopeBIP0044, acctName)
 822  	if e != nil {
 823  		return nil, e
 824  	}
 825  	bals, e := w.CalculateAccountBalances(account, 1)
 826  	if e != nil {
 827  		return nil, e
 828  	}
 829  	return (bals.Total - bals.Spendable).ToDUO(), nil
 830  }
 831  
 832  // ImportPrivKey handles an importprivkey request by parsing a WIF-encoded
 833  // private key and adding it to an account.
 834  func ImportPrivKey(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (interface{}, error) {
 835  	cmd, ok := icmd.(*btcjson.ImportPrivKeyCmd)
 836  	if !ok {
 837  		return nil, &btcjson.RPCError{
 838  			Code:    btcjson.ErrRPCInvalidParameter,
 839  			Message: HelpDescsEnUS()["importprivkey"],
 840  			// "invalid subcommand for addnode",
 841  		}
 842  	}
 843  	// Ensure that private keys are only imported to the correct account.
 844  	//
 845  	// Yes, Label is the account name.
 846  	if cmd.Label != nil && *cmd.Label != waddrmgr.ImportedAddrAccountName {
 847  		return nil, &ErrNotImportedAccount
 848  	}
 849  	wif, e := util.DecodeWIF(cmd.PrivKey)
 850  	if e != nil {
 851  		return nil, &btcjson.RPCError{
 852  			Code:    btcjson.ErrRPCInvalidAddressOrKey,
 853  			Message: "WIF decode failed: " + e.Error(),
 854  		}
 855  	}
 856  	if !wif.IsForNet(w.ChainParams()) {
 857  		return nil, &btcjson.RPCError{
 858  			Code:    btcjson.ErrRPCInvalidAddressOrKey,
 859  			Message: "Key is not intended for " + w.ChainParams().Name,
 860  		}
 861  	}
 862  	// Import the private key, handling any errors.
 863  	_, e = w.ImportPrivateKey(waddrmgr.KeyScopeBIP0044, wif, nil, *cmd.Rescan)
 864  	switch {
 865  	case waddrmgr.IsError(e, waddrmgr.ErrDuplicateAddress):
 866  		// Do not return duplicate key errors to the client.
 867  		return nil, nil
 868  	case waddrmgr.IsError(e, waddrmgr.ErrLocked):
 869  		return nil, &ErrWalletUnlockNeeded
 870  	}
 871  	return nil, e
 872  }
 873  
 874  // KeypoolRefill handles the keypoolrefill command. Since we handle the keypool automatically this does nothing since
 875  // refilling is never manually required.
 876  func KeypoolRefill(
 877  	icmd interface{}, w *Wallet,
 878  	chainClient ...*chainclient.RPCClient,
 879  ) (interface{}, error) {
 880  	return nil, nil
 881  }
 882  
 883  // CreateNewAccount handles a createnewaccount request by creating and returning a new account. If the last account has
 884  // no transaction history as per BIP 0044 a new account cannot be created so an error will be returned.
 885  func CreateNewAccount(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (interface{}, error) {
 886  	cmd, ok := icmd.(*btcjson.CreateNewAccountCmd)
 887  	if !ok {
 888  		return nil, &btcjson.RPCError{
 889  			Code:    btcjson.ErrRPCInvalidParameter,
 890  			Message: HelpDescsEnUS()["createnewaccount"],
 891  			// "invalid subcommand for addnode",
 892  		}
 893  	}
 894  	// The wildcard * is reserved by the rpc server with the special meaning of "all
 895  	// accounts", so disallow naming accounts to this string.
 896  	if cmd.Account == "*" {
 897  		return nil, &ErrReservedAccountName
 898  	}
 899  	_, e := w.NextAccount(waddrmgr.KeyScopeBIP0044, cmd.Account)
 900  	if waddrmgr.IsError(e, waddrmgr.ErrLocked) {
 901  		return nil, &btcjson.RPCError{
 902  			Code: btcjson.ErrRPCWalletUnlockNeeded,
 903  			Message: "Creating an account requires the wallet to be unlocked. " +
 904  				"Enter the wallet passphrase with walletpassphrase to unlock",
 905  		}
 906  	}
 907  	return nil, e
 908  }
 909  
 910  // RenameAccount handles a renameaccount request by renaming an account. If the
 911  // account does not exist an appropiate error will be returned.
 912  func RenameAccount(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (interface{}, error) {
 913  	cmd, ok := icmd.(*btcjson.RenameAccountCmd)
 914  	if !ok {
 915  		return nil, &btcjson.RPCError{
 916  			Code:    btcjson.ErrRPCInvalidParameter,
 917  			Message: HelpDescsEnUS()["renameaccount"],
 918  			// "invalid subcommand for addnode",
 919  		}
 920  	}
 921  	// The wildcard * is reserved by the rpc server with the special meaning of "all
 922  	// accounts", so disallow naming accounts to this string.
 923  	if cmd.NewAccount == "*" {
 924  		return nil, &ErrReservedAccountName
 925  	}
 926  	// Chk that given account exists
 927  	account, e := w.AccountNumber(waddrmgr.KeyScopeBIP0044, cmd.OldAccount)
 928  	if e != nil {
 929  		return nil, e
 930  	}
 931  	return nil, w.RenameAccount(waddrmgr.KeyScopeBIP0044, account, cmd.NewAccount)
 932  }
 933  
 934  // GetNewAddress handles a getnewaddress request by returning a new address for
 935  // an account. If the account does not exist an appropiate error is returned.
 936  //
 937  // TODO: Follow BIP 0044 and warn if number of unused addresses exceeds the gap limit.
 938  func GetNewAddress(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (interface{}, error) {
 939  	cmd, ok := icmd.(*btcjson.GetNewAddressCmd)
 940  	if !ok {
 941  		return nil, &btcjson.RPCError{
 942  			Code:    btcjson.ErrRPCInvalidParameter,
 943  			Message: HelpDescsEnUS()["getnewaddress"],
 944  			// "invalid subcommand for addnode",
 945  		}
 946  	}
 947  	acctName := "default"
 948  	if cmd.Account != nil {
 949  		acctName = *cmd.Account
 950  	}
 951  	account, e := w.AccountNumber(waddrmgr.KeyScopeBIP0044, acctName)
 952  	if e != nil {
 953  		return nil, e
 954  	}
 955  	addr, e := w.NewAddress(account, waddrmgr.KeyScopeBIP0044, false)
 956  	if e != nil {
 957  		return nil, e
 958  	}
 959  	// Return the new payment address string.
 960  	return addr.EncodeAddress(), nil
 961  }
 962  
 963  // GetRawChangeAddress handles a getrawchangeaddress request by creating and
 964  // returning a new change address for an account.
 965  //
 966  // Note: bitcoind allows specifying the account as an optional parameter, but
 967  // ignores the parameter.
 968  func GetRawChangeAddress(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (
 969  	interface{},
 970  	error,
 971  ) {
 972  	cmd, ok := icmd.(*btcjson.GetRawChangeAddressCmd)
 973  	if !ok {
 974  		return nil, &btcjson.RPCError{
 975  			Code:    btcjson.ErrRPCInvalidParameter,
 976  			Message: HelpDescsEnUS()["getrawchangeaddress"],
 977  			// "invalid subcommand for addnode",
 978  		}
 979  	}
 980  	acctName := "default"
 981  	if cmd.Account != nil {
 982  		acctName = *cmd.Account
 983  	}
 984  	account, e := w.AccountNumber(waddrmgr.KeyScopeBIP0044, acctName)
 985  	if e != nil {
 986  		return nil, e
 987  	}
 988  	addr, e := w.NewChangeAddress(account, waddrmgr.KeyScopeBIP0044)
 989  	if e != nil {
 990  		return nil, e
 991  	}
 992  	// Return the new payment address string.
 993  	return addr.EncodeAddress(), nil
 994  }
 995  
 996  // GetReceivedByAccount handles a getreceivedbyaccount request by returning the
 997  // total amount received by addresses of an account.
 998  func GetReceivedByAccount(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (
 999  	ii interface{},
1000  	e error,
1001  ) {
1002  	cmd, ok := icmd.(*btcjson.GetReceivedByAccountCmd)
1003  	if !ok {
1004  		return nil, &btcjson.RPCError{
1005  			Code:    btcjson.ErrRPCInvalidParameter,
1006  			Message: HelpDescsEnUS()["getreceivedbyaccount"],
1007  			// "invalid subcommand for addnode",
1008  		}
1009  	}
1010  	var account uint32
1011  	account, e = w.AccountNumber(waddrmgr.KeyScopeBIP0044, cmd.Account)
1012  	if e != nil {
1013  		return nil, e
1014  	}
1015  	// TODO: This is more inefficient that it could be, but the entire algorithm is
1016  	//  already dominated by reading every transaction in the wallet's history.
1017  	var results []AccountTotalReceivedResult
1018  	results, e = w.TotalReceivedForAccounts(
1019  		waddrmgr.KeyScopeBIP0044, int32(*cmd.MinConf),
1020  	)
1021  	if e != nil {
1022  		return nil, e
1023  	}
1024  	acctIndex := int(account)
1025  	if account == waddrmgr.ImportedAddrAccount {
1026  		acctIndex = len(results) - 1
1027  	}
1028  	return results[acctIndex].TotalReceived.ToDUO(), nil
1029  }
1030  
1031  // GetReceivedByAddress handles a getreceivedbyaddress request by returning the total amount received by a single
1032  // address.
1033  func GetReceivedByAddress(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (
1034  	interface{},
1035  	error,
1036  ) {
1037  	cmd, ok := icmd.(*btcjson.GetReceivedByAddressCmd)
1038  	if !ok {
1039  		return nil, &btcjson.RPCError{
1040  			Code:    btcjson.ErrRPCInvalidParameter,
1041  			Message: HelpDescsEnUS()["getreceivedbyaddress"],
1042  			// "invalid subcommand for addnode",
1043  		}
1044  	}
1045  	addr, e := DecodeAddress(cmd.Address, w.ChainParams())
1046  	if e != nil {
1047  		return nil, e
1048  	}
1049  	total, e := w.TotalReceivedForAddr(addr, int32(*cmd.MinConf))
1050  	if e != nil {
1051  		return nil, e
1052  	}
1053  	return total.ToDUO(), nil
1054  }
1055  
1056  // GetTransaction handles a gettransaction request by returning details about a single transaction saved by wallet.
1057  func GetTransaction(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (interface{}, error) {
1058  	cmd, ok := icmd.(*btcjson.GetTransactionCmd)
1059  	if !ok {
1060  		return nil, &btcjson.RPCError{
1061  			Code:    btcjson.ErrRPCInvalidParameter,
1062  			Message: HelpDescsEnUS()["gettransaction"],
1063  			// "invalid subcommand for addnode",
1064  		}
1065  	}
1066  	txHash, e := chainhash.NewHashFromStr(cmd.Txid)
1067  	if e != nil {
1068  		return nil, &btcjson.RPCError{
1069  			Code:    btcjson.ErrRPCDecodeHexString,
1070  			Message: "Transaction hash string decode failed: " + e.Error(),
1071  		}
1072  	}
1073  	details, e := ExposeUnstableAPI(w).TxDetails(txHash)
1074  	if e != nil {
1075  		return nil, e
1076  	}
1077  	if details == nil {
1078  		return nil, &ErrNoTransactionInfo
1079  	}
1080  	syncBlock := w.Manager.SyncedTo()
1081  	// TODO: The serialized transaction is already in the DB, so
1082  	// reserializing can be avoided here.
1083  	var txBuf bytes.Buffer
1084  	txBuf.Grow(details.MsgTx.SerializeSize())
1085  	e = details.MsgTx.Serialize(&txBuf)
1086  	if e != nil {
1087  		return nil, e
1088  	}
1089  	// TODO: Add a "generated" field to this result type.  "generated":true
1090  	// is only added if the transaction is a coinbase.
1091  	ret := btcjson.GetTransactionResult{
1092  		TxID:            cmd.Txid,
1093  		Hex:             hex.EncodeToString(txBuf.Bytes()),
1094  		Time:            details.Received.Unix(),
1095  		TimeReceived:    details.Received.Unix(),
1096  		WalletConflicts: []string{}, // Not saved
1097  		// Generated:     blockchain.IsCoinBaseTx(&details.MsgTx),
1098  	}
1099  	if details.Block.Height != -1 {
1100  		ret.BlockHash = details.Block.Hash.String()
1101  		ret.BlockTime = details.Block.Time.Unix()
1102  		ret.Confirmations = int64(Confirms(details.Block.Height, syncBlock.Height))
1103  	}
1104  	var (
1105  		debitTotal  amt.Amount
1106  		creditTotal amt.Amount // Excludes change
1107  		fee         amt.Amount
1108  		feeF64      float64
1109  	)
1110  	for _, deb := range details.Debits {
1111  		debitTotal += deb.Amount
1112  	}
1113  	for _, cred := range details.Credits {
1114  		if !cred.Change {
1115  			creditTotal += cred.Amount
1116  		}
1117  	}
1118  	// Fee can only be determined if every input is a debit.
1119  	if len(details.Debits) == len(details.MsgTx.TxIn) {
1120  		var outputTotal amt.Amount
1121  		for _, output := range details.MsgTx.TxOut {
1122  			outputTotal += amt.Amount(output.Value)
1123  		}
1124  		fee = debitTotal - outputTotal
1125  		feeF64 = fee.ToDUO()
1126  	}
1127  	if len(details.Debits) == 0 {
1128  		// Credits must be set later, but since we know the full length
1129  		// of the details slice, allocate it with the correct cap.
1130  		ret.Details = make([]btcjson.GetTransactionDetailsResult, 0, len(details.Credits))
1131  	} else {
1132  		ret.Details = make([]btcjson.GetTransactionDetailsResult, 1, len(details.Credits)+1)
1133  		ret.Details[0] = btcjson.GetTransactionDetailsResult{
1134  			// Fields left zeroed:
1135  			//   InvolvesWatchOnly
1136  			//   Account
1137  			//   Address
1138  			//   VOut
1139  			//
1140  			// TODO(jrick): Address and VOut should always be set,
1141  			//  but we're doing the wrong thing here by not matching
1142  			//  core.  Instead, gettransaction should only be adding
1143  			//  details for transaction outputs, just like
1144  			//  listtransactions (but using the short result format).
1145  			Category: "send",
1146  			Amount:   (-debitTotal).ToDUO(), // negative since it is a send
1147  			Fee:      &feeF64,
1148  		}
1149  		ret.Fee = feeF64
1150  	}
1151  	credCat := RecvCategory(details, syncBlock.Height, w.ChainParams()).String()
1152  	for _, cred := range details.Credits {
1153  		// Change is ignored.
1154  		if cred.Change {
1155  			continue
1156  		}
1157  		var address string
1158  		var accountName string
1159  		var addrs []btcaddr.Address
1160  		_, addrs, _, e = txscript.ExtractPkScriptAddrs(
1161  			details.MsgTx.TxOut[cred.Index].PkScript, w.ChainParams(),
1162  		)
1163  		if e == nil && len(addrs) == 1 {
1164  			addr := addrs[0]
1165  			address = addr.EncodeAddress()
1166  			account, e := w.AccountOfAddress(addr)
1167  			if e == nil {
1168  				name, e := w.AccountName(waddrmgr.KeyScopeBIP0044, account)
1169  				if e == nil {
1170  					accountName = name
1171  				}
1172  			}
1173  		}
1174  		ret.Details = append(
1175  			ret.Details, btcjson.GetTransactionDetailsResult{
1176  				// Fields left zeroed:
1177  				//   InvolvesWatchOnly
1178  				//   Fee
1179  				Account:  accountName,
1180  				Address:  address,
1181  				Category: credCat,
1182  				Amount:   cred.Amount.ToDUO(),
1183  				Vout:     cred.Index,
1184  			},
1185  		)
1186  	}
1187  	ret.Amount = creditTotal.ToDUO()
1188  	return ret, nil
1189  }
1190  
1191  func HandleDropWalletHistory(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (
1192  	out interface{}, e error,
1193  ) {
1194  	D.Ln("dropping wallet history")
1195  	if e = DropWalletHistory(w, w.PodConfig); E.Chk(e) {
1196  	}
1197  	D.Ln("dropped wallet history")
1198  	// go func() {
1199  	// 	rwt, e := w.Database().BeginReadWriteTx()
1200  	// 	if e != nil  {
1201  	// 		L.Script	// 	}
1202  	// 	ns := rwt.ReadWriteBucket([]byte("waddrmgr"))
1203  	// 	w.Manager.SetSyncedTo(ns, nil)
1204  	// 	if e = rwt.Commit(); E.Chk(e) {
1205  	// 	}
1206  	// }()
1207  	defer interrupt.RequestRestart()
1208  	return nil, e
1209  }
1210  
1211  // These generators create the following global variables in this package:
1212  //
1213  //   var localeHelpDescs map[string]func() map[string]string
1214  //   var requestUsages string
1215  //
1216  // localeHelpDescs maps from locale strings (e.g. "en_US") to a function that builds a map of help texts for each RPC
1217  // server method. This prevents help text maps for every locale map from being rooted and created during init. Instead,
1218  // the appropiate function is looked up when help text is first needed using the current locale and saved to the global
1219  // below for futher reuse.
1220  //
1221  // requestUsages contains single line usages for every supported request, separated by newlines. It is set during init.
1222  // These usages are used for all locales.
1223  //
1224  
1225  var HelpDescs map[string]string
1226  var HelpDescsMutex sync.Mutex // Help may execute concurrently, so synchronize access.
1227  
1228  // HelpWithChainRPC handles the help request when the RPC server has been associated with a consensus RPC client. The
1229  // additional RPC client is used to include help messages for methods implemented by the consensus server via RPC
1230  // passthrough.
1231  func HelpWithChainRPC(
1232  	icmd interface{}, w *Wallet,
1233  	chainClient ...*chainclient.RPCClient,
1234  ) (interface{}, error) {
1235  	return Help(icmd, w, chainClient[0])
1236  }
1237  
1238  // HelpNoChainRPC handles the help request when the RPC server has not been associated with a consensus RPC client. No
1239  // help messages are included for passthrough requests.
1240  func HelpNoChainRPC(
1241  	icmd interface{}, w *Wallet,
1242  	chainClient ...*chainclient.RPCClient,
1243  ) (interface{}, error) {
1244  	return Help(icmd, w, nil)
1245  }
1246  
1247  // Help handles the Help request by returning one line usage of all available methods, or full Help for a specific
1248  // method. The chainClient is optional, and this is simply a helper function for the HelpNoChainRPC and HelpWithChainRPC
1249  // handlers.
1250  func Help(icmd interface{}, w *Wallet, chainClient *chainclient.RPCClient) (interface{}, error) {
1251  	cmd := icmd.(*btcjson.HelpCmd)
1252  	// pod returns different help messages depending on the kind of connection the client is using. Only methods
1253  	// availble to HTTP POST clients are available to be used by wallet clients, even though wallet itself is a
1254  	// websocket client to pod. Therefore, create a POST client as needed.
1255  	//
1256  	// Returns nil if chainClient is currently nil or there is an error creating the client.
1257  	//
1258  	// This is hacky and is probably better handled by exposing help usage texts in a non-internal pod package.
1259  	postClient := func() *rpcclient.Client {
1260  		if chainClient == nil {
1261  			return nil
1262  		}
1263  		c, e := chainClient.POSTClient()
1264  		if e != nil {
1265  			return nil
1266  		}
1267  		return c
1268  	}
1269  	if cmd.Command == nil || *cmd.Command == "" {
1270  		// Prepend chain server usage if it is available.
1271  		usages := RequestUsages
1272  		client := postClient()
1273  		if client != nil {
1274  			rawChainUsage, e := client.RawRequest("help", nil)
1275  			var chainUsage string
1276  			if e == nil {
1277  				_ = js.Unmarshal(rawChainUsage, &chainUsage)
1278  			}
1279  			if chainUsage != "" {
1280  				usages = "Chain server usage:\n\n" + chainUsage + "\n\n" +
1281  					"Wallet server usage (overrides chain requests):\n\n" +
1282  					RequestUsages
1283  			}
1284  		}
1285  		return usages, nil
1286  	}
1287  	defer HelpDescsMutex.Unlock()
1288  	HelpDescsMutex.Lock()
1289  	if HelpDescs == nil {
1290  		// TODO: Allow other locales to be set via config or determine this from environment variables. For now,
1291  		//  hardcode US English.
1292  		HelpDescs = LocaleHelpDescs["en_US"]()
1293  	}
1294  	helpText, ok := HelpDescs[*cmd.Command]
1295  	if ok {
1296  		return helpText, nil
1297  	}
1298  	// Return the chain server's detailed help if possible.
1299  	var chainHelp string
1300  	client := postClient()
1301  	if client != nil {
1302  		param := make([]byte, len(*cmd.Command)+2)
1303  		param[0] = '"'
1304  		copy(param[1:], *cmd.Command)
1305  		param[len(param)-1] = '"'
1306  		rawChainHelp, e := client.RawRequest("help", []js.RawMessage{param})
1307  		if e == nil {
1308  			_ = js.Unmarshal(rawChainHelp, &chainHelp)
1309  		}
1310  	}
1311  	if chainHelp != "" {
1312  		return chainHelp, nil
1313  	}
1314  	return nil, &btcjson.RPCError{
1315  		Code:    btcjson.ErrRPCInvalidParameter,
1316  		Message: fmt.Sprintf("No help for method '%s'", *cmd.Command),
1317  	}
1318  }
1319  
1320  // ListAccounts handles a listaccounts request by returning a map of account names to their balances.
1321  func ListAccounts(
1322  	icmd interface{}, w *Wallet,
1323  	chainClient ...*chainclient.RPCClient,
1324  ) (interface{}, error) {
1325  	cmd, ok := icmd.(*btcjson.ListAccountsCmd)
1326  	if !ok {
1327  		return nil, &btcjson.RPCError{
1328  			Code:    btcjson.ErrRPCInvalidParameter,
1329  			Message: HelpDescsEnUS()["listaccounts"],
1330  			// "invalid subcommand for addnode",
1331  		}
1332  	}
1333  	accountBalances := map[string]float64{}
1334  	results, e := w.AccountBalances(waddrmgr.KeyScopeBIP0044, int32(*cmd.MinConf))
1335  	if e != nil {
1336  		return nil, e
1337  	}
1338  	for _, result := range results {
1339  		accountBalances[result.AccountName] = result.AccountBalance.ToDUO()
1340  	}
1341  	// Return the map.  This will be marshaled into a JSON object.
1342  	return accountBalances, nil
1343  }
1344  
1345  // ListLockUnspent handles a listlockunspent request by returning an slice of all locked outpoints.
1346  func ListLockUnspent(
1347  	icmd interface{}, w *Wallet,
1348  	chainClient ...*chainclient.RPCClient,
1349  ) (interface{}, error) {
1350  	return w.LockedOutpoints(), nil
1351  }
1352  
1353  // ListReceivedByAccount handles a listreceivedbyaccount request by returning a slice of objects, each one containing:
1354  //
1355  //  "account": the receiving account;
1356  //
1357  //  "amount": total amount received by the account;
1358  //
1359  //  "confirmations": number of confirmations of the most recent transaction.
1360  //
1361  // It takes two parameters:
1362  //
1363  //  "minconf": minimum number of confirmations to consider a transaction - default: one;
1364  //
1365  //  "includeempty": whether or not to include addresses that have no transactions - default: false.
1366  func ListReceivedByAccount(
1367  	icmd interface{}, w *Wallet,
1368  	chainClient ...*chainclient.RPCClient,
1369  ) (interface{}, error) {
1370  	cmd, ok := icmd.(*btcjson.ListReceivedByAccountCmd)
1371  	if !ok {
1372  		return nil, &btcjson.RPCError{
1373  			Code:    btcjson.ErrRPCInvalidParameter,
1374  			Message: HelpDescsEnUS()["listreceivedbyaccount"],
1375  			// "invalid subcommand for addnode",
1376  		}
1377  	}
1378  	results, e := w.TotalReceivedForAccounts(
1379  		waddrmgr.KeyScopeBIP0044, int32(*cmd.MinConf),
1380  	)
1381  	if e != nil {
1382  		return nil, e
1383  	}
1384  	jsonResults := make([]btcjson.ListReceivedByAccountResult, 0, len(results))
1385  	for _, result := range results {
1386  		jsonResults = append(
1387  			jsonResults, btcjson.ListReceivedByAccountResult{
1388  				Account:       result.AccountName,
1389  				Amount:        result.TotalReceived.ToDUO(),
1390  				Confirmations: uint64(result.LastConfirmation),
1391  			},
1392  		)
1393  	}
1394  	return jsonResults, nil
1395  }
1396  
1397  // ListReceivedByAddress handles a listreceivedbyaddress request by returning
1398  // a slice of objects, each one containing:
1399  //
1400  //  "account": the account of the receiving address;
1401  //
1402  //  "address": the receiving address;
1403  //
1404  //  "amount": total amount received by the address;
1405  //
1406  //  "confirmations": number of confirmations of the most recent transaction.
1407  //
1408  // It takes two parameters:
1409  //
1410  //  "minconf": minimum number of confirmations to consider a transaction - default: one;
1411  //
1412  //  "includeempty": whether or not to include addresses that have no transactions - default: false.
1413  func ListReceivedByAddress(
1414  	icmd interface{}, w *Wallet,
1415  	chainClient ...*chainclient.RPCClient,
1416  ) (interface{}, error) {
1417  	cmd, ok := icmd.(*btcjson.ListReceivedByAddressCmd)
1418  	if !ok {
1419  		return nil, &btcjson.RPCError{
1420  			Code:    btcjson.ErrRPCInvalidParameter,
1421  			Message: HelpDescsEnUS()["listreceivedbyaddress"],
1422  			// "invalid subcommand for addnode",
1423  		}
1424  	}
1425  	// Intermediate data for each address.
1426  	type AddrData struct {
1427  		// Total amount received.
1428  		amount amt.Amount
1429  		// Number of confirmations of the last transaction.
1430  		confirmations int32
1431  		// Merkles of transactions which include an output paying to the address
1432  		tx []string
1433  		// Account which the address belongs to account string
1434  	}
1435  	syncBlock := w.Manager.SyncedTo()
1436  	// Intermediate data for all addresses.
1437  	allAddrData := make(map[string]AddrData)
1438  	// Create an AddrData entry for each active address in the account. Otherwise we'll just get addresses from
1439  	// transactions later.
1440  	sortedAddrs, e := w.SortedActivePaymentAddresses()
1441  	if e != nil {
1442  		return nil, e
1443  	}
1444  	for _, address := range sortedAddrs {
1445  		// There might be duplicates, just overwrite them.
1446  		allAddrData[address] = AddrData{}
1447  	}
1448  	minConf := *cmd.MinConf
1449  	var endHeight int32
1450  	if minConf == 0 {
1451  		endHeight = -1
1452  	} else {
1453  		endHeight = syncBlock.Height - int32(minConf) + 1
1454  	}
1455  	e = ExposeUnstableAPI(w).RangeTransactions(
1456  		0, endHeight, func(details []wtxmgr.TxDetails) (bool, error) {
1457  			confirmations := Confirms(details[0].Block.Height, syncBlock.Height)
1458  			for _, tx := range details {
1459  				for _, cred := range tx.Credits {
1460  					pkScript := tx.MsgTx.TxOut[cred.Index].PkScript
1461  					var addrs []btcaddr.Address
1462  					_, addrs, _, e = txscript.ExtractPkScriptAddrs(
1463  						pkScript, w.ChainParams(),
1464  					)
1465  					if e != nil {
1466  						// Non standard script, skip.
1467  						continue
1468  					}
1469  					for _, addr := range addrs {
1470  						addrStr := addr.EncodeAddress()
1471  						addrData, ok := allAddrData[addrStr]
1472  						if ok {
1473  							addrData.amount += cred.Amount
1474  							// Always overwrite confirmations with newer ones.
1475  							addrData.confirmations = confirmations
1476  						} else {
1477  							addrData = AddrData{
1478  								amount:        cred.Amount,
1479  								confirmations: confirmations,
1480  							}
1481  						}
1482  						addrData.tx = append(addrData.tx, tx.Hash.String())
1483  						allAddrData[addrStr] = addrData
1484  					}
1485  				}
1486  			}
1487  			return false, nil
1488  		},
1489  	)
1490  	if e != nil {
1491  		return nil, e
1492  	}
1493  	// Massage address data into output format.
1494  	numAddresses := len(allAddrData)
1495  	ret := make([]btcjson.ListReceivedByAddressResult, numAddresses)
1496  	idx := 0
1497  	for address, addrData := range allAddrData {
1498  		ret[idx] = btcjson.ListReceivedByAddressResult{
1499  			Address:       address,
1500  			Amount:        addrData.amount.ToDUO(),
1501  			Confirmations: uint64(addrData.confirmations),
1502  			TxIDs:         addrData.tx,
1503  		}
1504  		idx++
1505  	}
1506  	return ret, nil
1507  }
1508  
1509  // ListSinceBlock handles a listsinceblock request by returning an array of maps with details of sent and received
1510  // wallet transactions since the given block.
1511  func ListSinceBlock(
1512  	icmd interface{}, w *Wallet,
1513  	cc ...*chainclient.RPCClient,
1514  ) (interface{}, error) {
1515  	if len(cc) < 1 || cc[0] == nil {
1516  		return nil, &btcjson.RPCError{
1517  			Code:    btcjson.ErrRPCNoChain,
1518  			Message: "there is currently no chain client to get this response",
1519  		}
1520  	}
1521  	chainClient := cc[0]
1522  	cmd, ok := icmd.(*btcjson.ListSinceBlockCmd)
1523  	if !ok {
1524  		return nil, &btcjson.RPCError{
1525  			Code:    btcjson.ErrRPCInvalidParameter,
1526  			Message: HelpDescsEnUS()["listsinceblock"],
1527  			// "invalid subcommand for addnode",
1528  		}
1529  	}
1530  	syncBlock := w.Manager.SyncedTo()
1531  	targetConf := int64(*cmd.TargetConfirmations)
1532  	// For the result we need the block hash for the last block counted in the blockchain due to confirmations. We send
1533  	// this off now so that it can arrive asynchronously while we figure out the rest.
1534  	gbh := chainClient.GetBlockHashAsync(int64(syncBlock.Height) + 1 - targetConf)
1535  	var start int32
1536  	if cmd.BlockHash != nil {
1537  		hash, e := chainhash.NewHashFromStr(*cmd.BlockHash)
1538  		if e != nil {
1539  			return nil, DeserializationError{e}
1540  		}
1541  		block, e := chainClient.GetBlockVerboseTx(hash)
1542  		if e != nil {
1543  			return nil, e
1544  		}
1545  		start = int32(block.Height) + 1
1546  	}
1547  	txInfoList, e := w.ListSinceBlock(start, -1, syncBlock.Height)
1548  	if e != nil {
1549  		return nil, e
1550  	}
1551  	// Done with work, get the response.
1552  	blockHash, e := gbh.Receive()
1553  	if e != nil {
1554  		return nil, e
1555  	}
1556  	res := btcjson.ListSinceBlockResult{
1557  		Transactions: txInfoList,
1558  		LastBlock:    blockHash.String(),
1559  	}
1560  	return res, nil
1561  }
1562  
1563  // ListTransactions handles a listtransactions request by returning an array of maps with details of sent and recevied
1564  // wallet transactions.
1565  func ListTransactions(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (
1566  	txs interface{},
1567  	e error,
1568  ) {
1569  	// D.S(icmd)
1570  	// D.Ln("ListTransactions")
1571  	if len(chainClient) < 1 || chainClient[0] == nil {
1572  		return nil, &btcjson.RPCError{
1573  			Code:    btcjson.ErrRPCNoChain,
1574  			Message: "there is currently no chain client to get this response",
1575  		}
1576  	}
1577  	cmd, ok := icmd.(*btcjson.ListTransactionsCmd)
1578  	if !ok { // || cmd.From == nil || cmd.Count == nil || cmd.Account != nil {
1579  		E.Ln(
1580  			"invalid parameter ok",
1581  			!ok,
1582  			"from",
1583  			cmd.From == nil,
1584  			"count",
1585  			cmd.Count == nil,
1586  			"account",
1587  			cmd.Account != nil,
1588  		)
1589  		return nil, &btcjson.RPCError{
1590  			Code:    btcjson.ErrRPCInvalidParameter,
1591  			Message: HelpDescsEnUS()["listtransactions"],
1592  		}
1593  	}
1594  	// // TODO: ListTransactions does not currently understand the difference
1595  	// //  between transactions pertaining to one account from another.  This
1596  	// //  will be resolved when wtxmgr is combined with the waddrmgr namespace.
1597  	// if *cmd.Account != "*" {
1598  	// 	// For now, don't bother trying to continue if the user specified an account, since this can't be (easily or
1599  	// 	// efficiently) calculated.
1600  	// 	E.Ln("you must use * for account, as transactions are not yet grouped by account")
1601  	// 	return nil, &btcjson.RPCError{
1602  	// 		Code:    btcjson.ErrRPCWallet,
1603  	// 		Message: "Transactions are not yet grouped by account",
1604  	// 	}
1605  	// }
1606  	txs, e = w.ListTransactions(*cmd.From, *cmd.Count)
1607  	return txs, e
1608  }
1609  
1610  // ListAddressTransactions handles a listaddresstransactions request by returning an array of maps with details of spent
1611  // and received wallet transactions.
1612  //
1613  // The form of the reply is identical to listtransactions, but the array elements are limited to transaction details
1614  // which are about the addresess included in the request.
1615  func ListAddressTransactions(
1616  	icmd interface{}, w *Wallet,
1617  	chainClient ...*chainclient.RPCClient,
1618  ) (interface{}, error) {
1619  	cmd, ok := icmd.(*btcjson.ListAddressTransactionsCmd)
1620  	if !ok {
1621  		return nil, &btcjson.RPCError{
1622  			Code:    btcjson.ErrRPCInvalidParameter,
1623  			Message: HelpDescsEnUS()["listaddresstransactions"],
1624  			// "invalid subcommand for addnode",
1625  		}
1626  	}
1627  	if cmd.Account != nil && *cmd.Account != "*" {
1628  		return nil, &btcjson.RPCError{
1629  			Code:    btcjson.ErrRPCInvalidParameter,
1630  			Message: "Listing transactions for addresses may only be done for all accounts",
1631  		}
1632  	}
1633  	// Decode addresses.
1634  	hash160Map := make(map[string]struct{})
1635  	for _, addrStr := range cmd.Addresses {
1636  		addr, e := DecodeAddress(addrStr, w.ChainParams())
1637  		if e != nil {
1638  			return nil, e
1639  		}
1640  		hash160Map[string(addr.ScriptAddress())] = struct{}{}
1641  	}
1642  	return w.ListAddressTransactions(hash160Map)
1643  }
1644  
1645  // ListAllTransactions handles a listalltransactions request by returning a map with details of sent and received wallet
1646  // transactions. This is similar to ListTransactions, except it takes only a single optional argument for the account
1647  // name and replies with all transactions.
1648  func ListAllTransactions(
1649  	icmd interface{}, w *Wallet,
1650  	chainClient ...*chainclient.RPCClient,
1651  ) (interface{}, error) {
1652  	cmd, ok := icmd.(*btcjson.ListAllTransactionsCmd)
1653  	if !ok {
1654  		return nil, &btcjson.RPCError{
1655  			Code:    btcjson.ErrRPCInvalidParameter,
1656  			Message: HelpDescsEnUS()["listalltransactions"],
1657  			// "invalid subcommand for addnode",
1658  		}
1659  	}
1660  	if cmd.Account != nil && *cmd.Account != "*" {
1661  		return nil, &btcjson.RPCError{
1662  			Code:    btcjson.ErrRPCInvalidParameter,
1663  			Message: "Listing all transactions may only be done for all accounts",
1664  		}
1665  	}
1666  	return w.ListAllTransactions()
1667  }
1668  
1669  // ListUnspent handles the listunspent command.
1670  func ListUnspent(
1671  	icmd interface{}, w *Wallet,
1672  	chainClient ...*chainclient.RPCClient,
1673  ) (interface{}, error) {
1674  	cmd, ok := icmd.(*btcjson.ListUnspentCmd)
1675  	if !ok {
1676  		return nil, &btcjson.RPCError{
1677  			Code:    btcjson.ErrRPCInvalidParameter,
1678  			Message: HelpDescsEnUS()["listunspent"],
1679  			// "invalid subcommand for addnode",
1680  		}
1681  	}
1682  	var addresses map[string]struct{}
1683  	if cmd.Addresses != nil {
1684  		addresses = make(map[string]struct{})
1685  		// confirm that all of them are good:
1686  		for _, as := range *cmd.Addresses {
1687  			a, e := DecodeAddress(as, w.ChainParams())
1688  			if e != nil {
1689  				return nil, e
1690  			}
1691  			addresses[a.EncodeAddress()] = struct{}{}
1692  		}
1693  	}
1694  	return w.ListUnspent(int32(*cmd.MinConf), int32(*cmd.MaxConf), addresses)
1695  }
1696  
1697  // LockUnspent handles the lockunspent command.
1698  func LockUnspent(
1699  	icmd interface{}, w *Wallet,
1700  	chainClient ...*chainclient.RPCClient,
1701  ) (interface{}, error) {
1702  	cmd, ok := icmd.(*btcjson.LockUnspentCmd)
1703  	if !ok {
1704  		return nil, &btcjson.RPCError{
1705  			Code:    btcjson.ErrRPCInvalidParameter,
1706  			Message: HelpDescsEnUS()["lockunspent"],
1707  			// "invalid subcommand for addnode",
1708  		}
1709  	}
1710  	switch {
1711  	case cmd.Unlock && len(cmd.Transactions) == 0:
1712  		w.ResetLockedOutpoints()
1713  	default:
1714  		for _, input := range cmd.Transactions {
1715  			txHash, e := chainhash.NewHashFromStr(input.Txid)
1716  			if e != nil {
1717  				return nil, ParseError{e}
1718  			}
1719  			op := wire.OutPoint{Hash: *txHash, Index: input.Vout}
1720  			if cmd.Unlock {
1721  				w.UnlockOutpoint(op)
1722  			} else {
1723  				w.LockOutpoint(op)
1724  			}
1725  		}
1726  	}
1727  	return true, nil
1728  }
1729  
1730  // MakeOutputs creates a slice of transaction outputs from a pair of address strings to amounts. This is used to create
1731  // the outputs to include in newly created transactions from a JSON object describing the output destinations and
1732  // amounts.
1733  func MakeOutputs(pairs map[string]amt.Amount, chainParams *chaincfg.Params) ([]*wire.TxOut, error) {
1734  	outputs := make([]*wire.TxOut, 0, len(pairs))
1735  	for addrStr, amt := range pairs {
1736  		addr, e := btcaddr.Decode(addrStr, chainParams)
1737  		if e != nil {
1738  			return nil, fmt.Errorf("cannot decode address: %s", e)
1739  		}
1740  		pkScript, e := txscript.PayToAddrScript(addr)
1741  		if e != nil {
1742  			return nil, fmt.Errorf("cannot create txout script: %s", e)
1743  		}
1744  		outputs = append(outputs, wire.NewTxOut(int64(amt), pkScript))
1745  	}
1746  	return outputs, nil
1747  }
1748  
1749  // SendPairs creates and sends payment transactions. It returns the transaction hash in string format upon success All
1750  // errors are returned in json.RPCError format
1751  func SendPairs(
1752  	w *Wallet, amounts map[string]amt.Amount,
1753  	account uint32, minconf int32, feeSatPerKb amt.Amount,
1754  ) (string, error) {
1755  	outputs, e := MakeOutputs(amounts, w.ChainParams())
1756  	if e != nil {
1757  		return "", e
1758  	}
1759  	var txHash *chainhash.Hash
1760  	txHash, e = w.SendOutputs(outputs, account, minconf, feeSatPerKb)
1761  	if e != nil {
1762  		if e == txrules.ErrAmountNegative {
1763  			return "", ErrNeedPositiveAmount
1764  		}
1765  		if waddrmgr.IsError(e, waddrmgr.ErrLocked) {
1766  			return "", &ErrWalletUnlockNeeded
1767  		}
1768  		switch e.(type) {
1769  		case btcjson.RPCError:
1770  			return "", e
1771  		}
1772  		return "", &btcjson.RPCError{
1773  			Code:    btcjson.ErrRPCInternal.Code,
1774  			Message: e.Error(),
1775  		}
1776  	}
1777  	txHashStr := txHash.String()
1778  	I.Ln("successfully sent transaction", txHashStr)
1779  	return txHashStr, nil
1780  }
1781  func IsNilOrEmpty(s *string) bool {
1782  	return s == nil || *s == ""
1783  }
1784  
1785  // SendFrom handles a sendfrom RPC request by creating a new transaction spending unspent transaction outputs for a
1786  // wallet to another payment address. Leftover inputs not sent to the payment address or a fee for the miner are sent
1787  // back to a new address in the wallet. Upon success, the TxID for the created transaction is returned.
1788  func SendFrom(icmd interface{}, w *Wallet, chainClient *chainclient.RPCClient) (interface{}, error) {
1789  	cmd, ok := icmd.(*btcjson.SendFromCmd)
1790  	if !ok {
1791  		return nil, &btcjson.RPCError{
1792  			Code:    btcjson.ErrRPCInvalidParameter,
1793  			Message: HelpDescsEnUS()["sendfrom"],
1794  			// "invalid subcommand for addnode",
1795  		}
1796  	}
1797  	// Transaction comments are not yet supported. ScriptError instead of pretending to save them.
1798  	if !IsNilOrEmpty(cmd.Comment) || !IsNilOrEmpty(cmd.CommentTo) {
1799  		return nil, &btcjson.RPCError{
1800  			Code:    btcjson.ErrRPCUnimplemented,
1801  			Message: "Transaction comments are not yet supported",
1802  		}
1803  	}
1804  	account, e := w.AccountNumber(
1805  		waddrmgr.KeyScopeBIP0044, cmd.FromAccount,
1806  	)
1807  	if e != nil {
1808  		return nil, e
1809  	}
1810  	// Chk that signed integer parameters are positive.
1811  	if cmd.Amount < 0 {
1812  		return nil, ErrNeedPositiveAmount
1813  	}
1814  	minConf := int32(*cmd.MinConf)
1815  	if minConf < 0 {
1816  		return nil, ErrNeedPositiveMinconf
1817  	}
1818  	// Create map of address and amount pairs.
1819  	amount, e := amt.NewAmount(cmd.Amount)
1820  	if e != nil {
1821  		return nil, e
1822  	}
1823  	pairs := map[string]amt.Amount{
1824  		cmd.ToAddress: amount,
1825  	}
1826  	return SendPairs(
1827  		w, pairs, account, minConf,
1828  		txrules.DefaultRelayFeePerKb,
1829  	)
1830  }
1831  
1832  // SendMany handles a sendmany RPC request by creating a new transaction spending unspent transaction outputs for a
1833  // wallet to any number of payment addresses.
1834  //
1835  // Leftover inputs not sent to the payment address or a fee for the miner are sent back to a new address in the wallet.
1836  // Upon success, the TxID for the created transaction is returned.
1837  func SendMany(
1838  	icmd interface{}, w *Wallet,
1839  	chainClient ...*chainclient.RPCClient,
1840  ) (interface{}, error) {
1841  	cmd, ok := icmd.(*btcjson.SendManyCmd)
1842  	if !ok {
1843  		return nil, &btcjson.RPCError{
1844  			Code:    btcjson.ErrRPCInvalidParameter,
1845  			Message: HelpDescsEnUS()["sendmany"],
1846  			// "invalid subcommand for addnode",
1847  		}
1848  	}
1849  	// Transaction comments are not yet supported. ScriptError instead of pretending to save them.
1850  	if !IsNilOrEmpty(cmd.Comment) {
1851  		return nil, &btcjson.RPCError{
1852  			Code:    btcjson.ErrRPCUnimplemented,
1853  			Message: "Transaction comments are not yet supported",
1854  		}
1855  	}
1856  	account, e := w.AccountNumber(waddrmgr.KeyScopeBIP0044, cmd.FromAccount)
1857  	if e != nil {
1858  		return nil, e
1859  	}
1860  	// Chk that minconf is positive.
1861  	minConf := int32(*cmd.MinConf)
1862  	if minConf < 0 {
1863  		return nil, ErrNeedPositiveMinconf
1864  	}
1865  	// Recreate address/amount pairs, using dcrutil.Amount.
1866  	pairs := make(map[string]amt.Amount, len(cmd.Amounts))
1867  	for k, v := range cmd.Amounts {
1868  		amt, e := amt.NewAmount(v)
1869  		if e != nil {
1870  			return nil, e
1871  		}
1872  		pairs[k] = amt
1873  	}
1874  	return SendPairs(w, pairs, account, minConf, txrules.DefaultRelayFeePerKb)
1875  }
1876  
1877  // SendToAddress handles a sendtoaddress RPC request by creating a new transaction spending unspent transaction outputs
1878  // for a wallet to another payment address.
1879  //
1880  // Leftover inputs not sent to the payment address or a fee for the miner are sent back to a new address in the wallet.
1881  // Upon success, the TxID for the created transaction is returned.
1882  func SendToAddress(
1883  	icmd interface{}, w *Wallet,
1884  	chainClient ...*chainclient.RPCClient,
1885  ) (interface{}, error) {
1886  	cmd, ok := icmd.(*btcjson.SendToAddressCmd)
1887  	if !ok {
1888  		return nil, &btcjson.RPCError{
1889  			Code:    btcjson.ErrRPCInvalidParameter,
1890  			Message: HelpDescsEnUS()["sendtoaddress"],
1891  			// "invalid subcommand for addnode",
1892  		}
1893  	}
1894  	// Transaction comments are not yet supported.  ScriptError instead of
1895  	// pretending to save them.
1896  	if !IsNilOrEmpty(cmd.Comment) || !IsNilOrEmpty(cmd.CommentTo) {
1897  		return nil, &btcjson.RPCError{
1898  			Code:    btcjson.ErrRPCUnimplemented,
1899  			Message: "Transaction comments are not yet supported",
1900  		}
1901  	}
1902  	amount, e := amt.NewAmount(cmd.Amount)
1903  	if e != nil {
1904  		D.Ln(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", e)
1905  		return nil, e
1906  	}
1907  	// Chk that signed integer parameters are positive.
1908  	if amount < 0 {
1909  		D.Ln(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> need positive amount")
1910  		return nil, ErrNeedPositiveAmount
1911  	}
1912  	// Mock up map of address and amount pairs.
1913  	pairs := map[string]amt.Amount{
1914  		cmd.Address: amount,
1915  	}
1916  	// sendtoaddress always spends from the default account, this matches bitcoind
1917  	return SendPairs(
1918  		w, pairs, waddrmgr.DefaultAccountNum, 1,
1919  		txrules.DefaultRelayFeePerKb,
1920  	)
1921  }
1922  
1923  // SetTxFee sets the transaction fee per kilobyte added to transactions.
1924  func SetTxFee(
1925  	icmd interface{}, w *Wallet,
1926  	chainClient ...*chainclient.RPCClient,
1927  ) (interface{}, error) {
1928  	cmd, ok := icmd.(*btcjson.SetTxFeeCmd)
1929  	if !ok {
1930  		return nil, &btcjson.RPCError{
1931  			Code:    btcjson.ErrRPCInvalidParameter,
1932  			Message: HelpDescsEnUS()["settxfee"],
1933  			// "invalid subcommand for addnode",
1934  		}
1935  	}
1936  	// Chk that amount is not negative.
1937  	if cmd.Amount < 0 {
1938  		return nil, ErrNeedPositiveAmount
1939  	}
1940  	// A boolean true result is returned upon success.
1941  	return true, nil
1942  }
1943  
1944  // SignMessage signs the given message with the private key for the given address
1945  func SignMessage(
1946  	icmd interface{}, w *Wallet,
1947  	chainClient ...*chainclient.RPCClient,
1948  ) (interface{}, error) {
1949  	cmd, ok := icmd.(*btcjson.SignMessageCmd)
1950  	if !ok {
1951  		return nil, &btcjson.RPCError{
1952  			Code:    btcjson.ErrRPCInvalidParameter,
1953  			Message: HelpDescsEnUS()["signmessage"],
1954  			// "invalid subcommand for addnode",
1955  		}
1956  	}
1957  	addr, e := DecodeAddress(cmd.Address, w.ChainParams())
1958  	if e != nil {
1959  		return nil, e
1960  	}
1961  	privKey, e := w.PrivKeyForAddress(addr)
1962  	if e != nil {
1963  		return nil, e
1964  	}
1965  	var buf bytes.Buffer
1966  	e = wire.WriteVarString(&buf, 0, "Bitcoin Signed Message:\n")
1967  	if e != nil {
1968  		D.Ln(e)
1969  	}
1970  	e = wire.WriteVarString(&buf, 0, cmd.Message)
1971  	if e != nil {
1972  		D.Ln(e)
1973  	}
1974  	messageHash := chainhash.DoubleHashB(buf.Bytes())
1975  	sigbytes, e := ecc.SignCompact(
1976  		ecc.S256(), privKey,
1977  		messageHash, true,
1978  	)
1979  	if e != nil {
1980  		return nil, e
1981  	}
1982  	return base64.StdEncoding.EncodeToString(sigbytes), nil
1983  }
1984  
1985  // SignRawTransaction handles the signrawtransaction command.
1986  func SignRawTransaction(
1987  	icmd interface{}, w *Wallet,
1988  	cc ...*chainclient.RPCClient,
1989  ) (interface{}, error) {
1990  	if len(cc) < 1 || cc[0] == nil {
1991  		return nil, &btcjson.RPCError{
1992  			Code:    btcjson.ErrRPCNoChain,
1993  			Message: "there is currently no chain client to get this response",
1994  		}
1995  	}
1996  	chainClient := cc[0]
1997  	cmd, ok := icmd.(*btcjson.SignRawTransactionCmd)
1998  	if !ok {
1999  		return nil, &btcjson.RPCError{
2000  			Code:    btcjson.ErrRPCInvalidParameter,
2001  			Message: HelpDescsEnUS()["signrawtransaction"],
2002  			// "invalid subcommand for addnode",
2003  		}
2004  	}
2005  	serializedTx, e := DecodeHexStr(cmd.RawTx)
2006  	if e != nil {
2007  		return nil, e
2008  	}
2009  	var tx wire.MsgTx
2010  	e = tx.Deserialize(bytes.NewBuffer(serializedTx))
2011  	if e != nil {
2012  		e = errors.New("TX decode failed")
2013  		return nil, DeserializationError{e}
2014  	}
2015  	var hashType txscript.SigHashType
2016  	switch *cmd.Flags {
2017  	case "ALL":
2018  		hashType = txscript.SigHashAll
2019  	case "NONE":
2020  		hashType = txscript.SigHashNone
2021  	case "SINGLE":
2022  		hashType = txscript.SigHashSingle
2023  	case "ALL|ANYONECANPAY":
2024  		hashType = txscript.SigHashAll | txscript.SigHashAnyOneCanPay
2025  	case "NONE|ANYONECANPAY":
2026  		hashType = txscript.SigHashNone | txscript.SigHashAnyOneCanPay
2027  	case "SINGLE|ANYONECANPAY":
2028  		hashType = txscript.SigHashSingle | txscript.SigHashAnyOneCanPay
2029  	default:
2030  		e = errors.New("invalid sighash parameter")
2031  		return nil, InvalidParameterError{e}
2032  	}
2033  	// TODO: really we probably should look these up with pod anyway to
2034  	// make sure that they match the blockchain if present.
2035  	inputs := make(map[wire.OutPoint][]byte)
2036  	scripts := make(map[string][]byte)
2037  	var cmdInputs []btcjson.RawTxInput
2038  	if cmd.Inputs != nil {
2039  		cmdInputs = *cmd.Inputs
2040  	}
2041  	for _, rti := range cmdInputs {
2042  		var inputHash *chainhash.Hash
2043  		inputHash, e = chainhash.NewHashFromStr(rti.Txid)
2044  		if e != nil {
2045  			return nil, DeserializationError{e}
2046  		}
2047  		var script []byte
2048  		script, e = DecodeHexStr(rti.ScriptPubKey)
2049  		if e != nil {
2050  			return nil, e
2051  		}
2052  		// redeemScript is only actually used iff the user provided private keys. In which case, it is used to get the
2053  		// scripts for signing. If the user did not provide keys then we always get scripts from the wallet.
2054  		//
2055  		// Empty strings are ok for this one and hex.DecodeString will DTRT.
2056  		if cmd.PrivKeys != nil && len(*cmd.PrivKeys) != 0 {
2057  			var redeemScript []byte
2058  			redeemScript, e = DecodeHexStr(rti.RedeemScript)
2059  			if e != nil {
2060  				return nil, e
2061  			}
2062  			var addr *btcaddr.ScriptHash
2063  			addr, e = btcaddr.NewScriptHash(
2064  				redeemScript,
2065  				w.ChainParams(),
2066  			)
2067  			if e != nil {
2068  				return nil, DeserializationError{e}
2069  			}
2070  			scripts[addr.String()] = redeemScript
2071  		}
2072  		inputs[wire.OutPoint{
2073  			Hash:  *inputHash,
2074  			Index: rti.Vout,
2075  		}] = script
2076  	}
2077  	// Now we go and look for any inputs that we were not provided by querying pod with getrawtransaction. We queue up a
2078  	// bunch of async requests and will wait for replies after we have checked the rest of the arguments.
2079  	requested := make(map[wire.OutPoint]rpcclient.FutureGetTxOutResult)
2080  	for _, txIn := range tx.TxIn {
2081  		// Did we get this outpoint from the arguments?
2082  		if _, ok := inputs[txIn.PreviousOutPoint]; ok {
2083  			continue
2084  		}
2085  		// Asynchronously request the output script.
2086  		requested[txIn.PreviousOutPoint] = chainClient.GetTxOutAsync(
2087  			&txIn.PreviousOutPoint.Hash, txIn.PreviousOutPoint.Index,
2088  			true,
2089  		)
2090  	}
2091  	// Parse list of private keys, if present. If there are any keys here they are the keys that we may use for signing.
2092  	// If empty we will use any keys known to us already.
2093  	var keys map[string]*util.WIF
2094  	if cmd.PrivKeys != nil {
2095  		keys = make(map[string]*util.WIF)
2096  		for _, key := range *cmd.PrivKeys {
2097  			var wif *util.WIF
2098  			wif, e = util.DecodeWIF(key)
2099  			if e != nil {
2100  				return nil, DeserializationError{e}
2101  			}
2102  			if !wif.IsForNet(w.ChainParams()) {
2103  				s := "key network doesn't match wallet's"
2104  				return nil, DeserializationError{errors.New(s)}
2105  			}
2106  			var addr *btcaddr.PubKey
2107  			addr, e = btcaddr.NewPubKey(
2108  				wif.SerializePubKey(),
2109  				w.ChainParams(),
2110  			)
2111  			if e != nil {
2112  				return nil, DeserializationError{e}
2113  			}
2114  			keys[addr.EncodeAddress()] = wif
2115  		}
2116  	}
2117  	// We have checked the rest of the args. now we can collect the async txs.
2118  	//
2119  	// TODO: If we don't mind the possibility of wasting work we could move waiting to the following loop and be
2120  	//  slightly more asynchronous.
2121  	for outPoint, resp := range requested {
2122  		var result *btcjson.GetTxOutResult
2123  		result, e = resp.Receive()
2124  		if e != nil {
2125  			return nil, e
2126  		}
2127  		var script []byte
2128  		if script, e = hex.DecodeString(result.ScriptPubKey.Hex); E.Chk(e) {
2129  			return nil, e
2130  		}
2131  		inputs[outPoint] = script
2132  	}
2133  	// All args collected. Now we can sign all the inputs that we can. `complete' denotes that we successfully signed
2134  	// all outputs and that all scripts will run to completion. This is returned as part of the reply.
2135  	var signErrs []SignatureError
2136  	signErrs, e = w.SignTransaction(&tx, hashType, inputs, keys, scripts)
2137  	if e != nil {
2138  		return nil, e
2139  	}
2140  	var buf bytes.Buffer
2141  	buf.Grow(tx.SerializeSize())
2142  	// All returned errors (not OOM, which panics) encountered during bytes.Buffer writes are unexpected.
2143  	if e = tx.Serialize(&buf); E.Chk(e) {
2144  		panic(e)
2145  	}
2146  	signErrors := make([]btcjson.SignRawTransactionError, 0, len(signErrs))
2147  	for _, ee := range signErrs {
2148  		input := tx.TxIn[ee.InputIndex]
2149  		signErrors = append(
2150  			signErrors, btcjson.SignRawTransactionError{
2151  				TxID:      input.PreviousOutPoint.Hash.String(),
2152  				Vout:      input.PreviousOutPoint.Index,
2153  				ScriptSig: hex.EncodeToString(input.SignatureScript),
2154  				Sequence:  input.Sequence,
2155  				Error:     e.Error(),
2156  			},
2157  		)
2158  	}
2159  	return btcjson.SignRawTransactionResult{
2160  		Hex:      hex.EncodeToString(buf.Bytes()),
2161  		Complete: len(signErrors) == 0,
2162  		Errors:   signErrors,
2163  	}, nil
2164  }
2165  
2166  // ValidateAddress handles the validateaddress command.
2167  func ValidateAddress(icmd interface{}, w *Wallet, chainClient ...*chainclient.RPCClient) (interface{}, error) {
2168  	cmd, ok := icmd.(*btcjson.ValidateAddressCmd)
2169  	if !ok {
2170  		return nil, &btcjson.RPCError{
2171  			Code:    btcjson.ErrRPCInvalidParameter,
2172  			Message: HelpDescsEnUS()["validateaddress"],
2173  			// "invalid subcommand for addnode",
2174  		}
2175  	}
2176  	result := btcjson.ValidateAddressWalletResult{}
2177  	addr, e := DecodeAddress(cmd.Address, w.ChainParams())
2178  	if e != nil {
2179  		// Use result zero value (IsValid=false).
2180  		return result, nil
2181  	}
2182  	// We could put whether or not the address is a script here, by checking the type of "addr", however, the reference
2183  	// implementation only puts that information if the script is "ismine", and we follow that behaviour.
2184  	result.Address = addr.EncodeAddress()
2185  	result.IsValid = true
2186  	ainfo, e := w.AddressInfo(addr)
2187  	if e != nil {
2188  		if waddrmgr.IsError(e, waddrmgr.ErrAddressNotFound) {
2189  			// No additional information available about the address.
2190  			return result, nil
2191  		}
2192  		return nil, e
2193  	}
2194  	// The address lookup was successful which means there is further information about it available and it is "mine".
2195  	result.IsMine = true
2196  	acctName, e := w.AccountName(waddrmgr.KeyScopeBIP0044, ainfo.Account())
2197  	if e != nil {
2198  		return nil, &ErrAccountNameNotFound
2199  	}
2200  	result.Account = acctName
2201  	switch ma := ainfo.(type) {
2202  	case waddrmgr.ManagedPubKeyAddress:
2203  		result.IsCompressed = ma.Compressed()
2204  		result.PubKey = ma.ExportPubKey()
2205  	case waddrmgr.ManagedScriptAddress:
2206  		result.IsScript = true
2207  		// The script is only available if the manager is unlocked, so just break out now if there is an error.
2208  		script, e := ma.Script()
2209  		if e != nil {
2210  			break
2211  		}
2212  		result.Hex = hex.EncodeToString(script)
2213  		// This typically shouldn't fail unless an invalid script was imported.
2214  		//
2215  		// However, if it fails for any reason, there is no further information available, so just set the script type a
2216  		// non-standard and break out now.
2217  		class, addrs, reqSigs, e := txscript.ExtractPkScriptAddrs(
2218  			script, w.ChainParams(),
2219  		)
2220  		if e != nil {
2221  			result.Script = txscript.NonStandardTy.String()
2222  			break
2223  		}
2224  		addrStrings := make([]string, len(addrs))
2225  		for i, a := range addrs {
2226  			addrStrings[i] = a.EncodeAddress()
2227  		}
2228  		result.Addresses = addrStrings
2229  		// Multi-signature scripts also provide the number of required
2230  		// signatures.
2231  		result.Script = class.String()
2232  		if class == txscript.MultiSigTy {
2233  			result.SigsRequired = int32(reqSigs)
2234  		}
2235  	}
2236  	return result, nil
2237  }
2238  
2239  // VerifyMessage handles the verifymessage command by verifying the provided compact signature for the given address and
2240  // message.
2241  func VerifyMessage(
2242  	icmd interface{}, w *Wallet,
2243  	chainClient ...*chainclient.RPCClient,
2244  ) (interface{}, error) {
2245  	cmd, ok := icmd.(*btcjson.VerifyMessageCmd)
2246  	if !ok {
2247  		return nil, &btcjson.RPCError{
2248  			Code:    btcjson.ErrRPCInvalidParameter,
2249  			Message: HelpDescsEnUS()["verifymessage"],
2250  			// "invalid subcommand for addnode",
2251  		}
2252  	}
2253  	addr, e := DecodeAddress(cmd.Address, w.ChainParams())
2254  	if e != nil {
2255  		return nil, e
2256  	}
2257  	// decode base64 signature
2258  	sig, e := base64.StdEncoding.DecodeString(cmd.Signature)
2259  	if e != nil {
2260  		return nil, e
2261  	}
2262  	// Validate the signature - this just shows that it was valid at all. we will compare it with the key next.
2263  	var buf bytes.Buffer
2264  	e = wire.WriteVarString(&buf, 0, "Parallelcoin Signed Message:\n")
2265  	if e != nil {
2266  		D.Ln(e)
2267  	}
2268  	e = wire.WriteVarString(&buf, 0, cmd.Message)
2269  	if e != nil {
2270  		D.Ln(e)
2271  	}
2272  	expectedMessageHash := chainhash.DoubleHashB(buf.Bytes())
2273  	pk, wasCompressed, e := ecc.RecoverCompact(
2274  		ecc.S256(), sig,
2275  		expectedMessageHash,
2276  	)
2277  	if e != nil {
2278  		return nil, e
2279  	}
2280  	var serializedPubKey []byte
2281  	if wasCompressed {
2282  		serializedPubKey = pk.SerializeCompressed()
2283  	} else {
2284  		serializedPubKey = pk.SerializeUncompressed()
2285  	}
2286  	// Verify that the signed-by address matches the given address
2287  	switch checkAddr := addr.(type) {
2288  	case *btcaddr.PubKeyHash: // ok
2289  		return bytes.Equal(btcaddr.Hash160(serializedPubKey), checkAddr.Hash160()[:]), nil
2290  	case *btcaddr.PubKey: // ok
2291  		return string(serializedPubKey) == checkAddr.String(), nil
2292  	default:
2293  		return nil, errors.New("address type not supported")
2294  	}
2295  }
2296  
2297  // WalletIsLocked handles the walletislocked extension request by returning the current lock state (false for unlocked,
2298  // true for locked) of an account.
2299  func WalletIsLocked(
2300  	icmd interface{}, w *Wallet,
2301  	chainClient ...*chainclient.RPCClient,
2302  ) (interface{}, error) {
2303  	return w.Locked(), nil
2304  }
2305  
2306  // WalletLock handles a walletlock request by locking the all account wallets, returning an error if any wallet is not
2307  // encrypted (for example, a watching-only wallet).
2308  func WalletLock(
2309  	icmd interface{}, w *Wallet,
2310  	chainClient ...*chainclient.RPCClient,
2311  ) (interface{}, error) {
2312  	w.Lock()
2313  	return nil, nil
2314  }
2315  
2316  // WalletPassphrase responds to the walletpassphrase request by unlocking the wallet. The decryption key is saved in the
2317  // wallet until timeout seconds expires, after which the wallet is locked.
2318  func WalletPassphrase(
2319  	icmd interface{}, w *Wallet,
2320  	chainClient ...*chainclient.RPCClient,
2321  ) (interface{}, error) {
2322  	cmd, ok := icmd.(*btcjson.WalletPassphraseCmd)
2323  	if !ok {
2324  		return nil, &btcjson.RPCError{
2325  			Code:    btcjson.ErrRPCInvalidParameter,
2326  			Message: HelpDescsEnUS()["walletpassphrase"],
2327  			// "invalid subcommand for addnode",
2328  		}
2329  	}
2330  	timeout := time.Second * time.Duration(cmd.Timeout)
2331  	var unlockAfter <-chan time.Time
2332  	if timeout != 0 {
2333  		unlockAfter = time.After(timeout)
2334  	}
2335  	e := w.Unlock([]byte(cmd.Passphrase), unlockAfter)
2336  	return nil, e
2337  }
2338  
2339  // WalletPassphraseChange responds to the walletpassphrasechange request by unlocking all accounts with the provided old
2340  // passphrase, and re-encrypting each private key with an AES key derived from the new passphrase.
2341  //
2342  // If the old passphrase is correct and the passphrase is changed, all wallets will be immediately locked.
2343  func WalletPassphraseChange(
2344  	icmd interface{}, w *Wallet,
2345  	chainClient ...*chainclient.RPCClient,
2346  ) (interface{}, error) {
2347  	cmd, ok := icmd.(*btcjson.WalletPassphraseChangeCmd)
2348  	if !ok {
2349  		return nil, &btcjson.RPCError{
2350  			Code:    btcjson.ErrRPCInvalidParameter,
2351  			Message: HelpDescsEnUS()["walletpassphrasechange"],
2352  			// "invalid subcommand for addnode",
2353  		}
2354  	}
2355  	e := w.ChangePrivatePassphrase(
2356  		[]byte(cmd.OldPassphrase),
2357  		[]byte(cmd.NewPassphrase),
2358  	)
2359  	if waddrmgr.IsError(e, waddrmgr.ErrWrongPassphrase) {
2360  		return nil, &btcjson.RPCError{
2361  			Code:    btcjson.ErrRPCWalletPassphraseIncorrect,
2362  			Message: "Incorrect passphrase",
2363  		}
2364  	}
2365  	return nil, e
2366  }
2367  
2368  // DecodeHexStr decodes the hex encoding of a string, possibly prepending a leading '0' character if there is an odd
2369  // number of bytes in the hex string. This is to prevent an error for an invalid hex string when using an odd number of
2370  // bytes when calling hex.Decode.
2371  func DecodeHexStr(hexStr string) ([]byte, error) {
2372  	if len(hexStr)%2 != 0 {
2373  		hexStr = "0" + hexStr
2374  	}
2375  	decoded, e := hex.DecodeString(hexStr)
2376  	if e != nil {
2377  		return nil, &btcjson.RPCError{
2378  			Code:    btcjson.ErrRPCDecodeHexString,
2379  			Message: "Hex string decode failed: " + e.Error(),
2380  		}
2381  	}
2382  	return decoded, nil
2383  }
2384