diff --git a/internal/rpchelp/helpdescs_en_US.go b/internal/rpchelp/helpdescs_en_US.go index 2a7a38261..42b465203 100644 --- a/internal/rpchelp/helpdescs_en_US.go +++ b/internal/rpchelp/helpdescs_en_US.go @@ -541,6 +541,15 @@ var helpDescsEnUS = map[string]string{ "verifymessage-message": "The message to verify", "verifymessage--result0": "Whether the message was signed with the private key of 'address'", + // VerifySeedCmd help. + "verifyseed--synopsis": "Verifys if a seed is the same as the running wallet.", + "verifyseed-seed": "Seed to be inputted to check against the wallets master public key, after derivation.", + "verifyseed-account": "Account number, of potential branch of the master public key, this is an optional input.", + + // VerifySeedResults help. + "verifyseedresult-keyresult": "Whether or not if the inputted seed is the same as the running wallets", + "verifyseedresult-cointype": "Outputs the current cointype of the running wallet.", + // Version help "version--synopsis": "Returns application and API versions (semver) keyed by their names", "version--result0--desc": "Version objects keyed by the program or API name", diff --git a/internal/rpchelp/methods.go b/internal/rpchelp/methods.go index fa05010e4..d0f3e7ad8 100644 --- a/internal/rpchelp/methods.go +++ b/internal/rpchelp/methods.go @@ -76,6 +76,7 @@ var Methods = []struct { {"sweepaccount", []interface{}{(*dcrjson.SweepAccountResult)(nil)}}, {"validateaddress", []interface{}{(*dcrjson.ValidateAddressWalletResult)(nil)}}, {"verifymessage", returnsBool}, + {"verifyseed", []interface{}{(*dcrjson.VerifySeedResult)(nil)}}, {"version", []interface{}{(*map[string]dcrjson.VersionResult)(nil)}}, {"walletlock", nil}, {"walletpassphrase", nil}, diff --git a/rpc/legacyrpc/methods.go b/rpc/legacyrpc/methods.go index fad90d043..fbd025d6a 100644 --- a/rpc/legacyrpc/methods.go +++ b/rpc/legacyrpc/methods.go @@ -35,6 +35,7 @@ import ( "github.com/decred/dcrwallet/wallet" "github.com/decred/dcrwallet/wallet/txrules" "github.com/decred/dcrwallet/wallet/udb" + "github.com/decred/dcrwallet/walletseed" ) // API version constants @@ -122,6 +123,7 @@ var handlers = map[string]handler{ "ticketsforaddress": {fn: ticketsForAddress}, "validateaddress": {fn: validateAddress}, "verifymessage": {fn: verifyMessage}, + "verifyseed": {fn: verifySeed}, "version": {fn: version}, "walletinfo": {fn: walletInfo}, "walletlock": {fn: walletLock}, @@ -3442,6 +3444,107 @@ WrongAddrKind: return nil, rpcErrorf(dcrjson.ErrRPCInvalidParameter, "address must be secp256k1 P2PK or P2PKH") } +func deriveCoinTypeKey(seed []byte, coinType uint32, params *chaincfg.Params) (*hdkeychain.ExtendedKey, error) { + // Create new root from the inputted seed and the current net + root, err := hdkeychain.NewMaster(seed[:], params) + if err != nil { + return nil, err + } + + // BIP0032 hierarchy: m/'/ + // Where purpose = 44 and the ' indicates hardening with the HardenedKeyStart 0x80000000 + purpose, err := root.Child(44 + hdkeychain.HardenedKeyStart) + if err != nil { + return nil, err + } + defer purpose.Zero() + + // BIP0044 hierarchy: m/44'/' + // Where coin type is either the legacy coin type, 20, or the coin type described in SLIP0044, 44. + coinTypePrivKey, err := purpose.Child(coinType + hdkeychain.HardenedKeyStart) + if err != nil { + return nil, err + } + defer coinTypePrivKey.Zero() + + return coinTypePrivKey, nil +} + +// verifySeed checks if a user inputted seed is that of the wallet by comparing their child key derivatied +// public keys. It returns a bool if this the case as well as the current coin type of the wallet. An optional +// parameter is also avalaible that checks beyond default accounts. It returns the result using the RPC api. +func verifySeed(s *Server, icmd interface{}) (interface{}, error) { + cmd := icmd.(*dcrjson.VerifySeedCmd) + w, ok := s.walletLoader.LoadedWallet() + if !ok { + return nil, errUnloadedWallet + } + + coinType, err := w.CoinType() + if err != nil { + return nil, err + } + + decodedSeed, err := walletseed.DecodeUserInput(cmd.Seed) + if err != nil { + return nil, err + } + + // Changed inputted seed, type string, to type byte[] so hdkeychain methods can be utilize using DecodeUserInput + // and run then derivedCoinTypeKey to receive the coin type private key. + coinTypePrivKey, err := deriveCoinTypeKey(decodedSeed, coinType, w.ChainParams()) + if err != nil { + return nil, err + } + defer coinTypePrivKey.Zero() + + // Grab coin type private key from wallet for future comparison to the derived inputted coin type private key + walletCoinTypePrivKey, err := w.CoinTypeKey() + if err != nil { + return nil, err + } + defer walletCoinTypePrivKey.Zero() + + var matches bool + switch { + case cmd.Account != nil: + // Both derivedAccountKey and walletDerivedAccountKey use the BIP044 hierachy: m/44'/'/' + // If the child is a private extended key it is neutered + accountKey, err := coinTypePrivKey.Child(*cmd.Account + hdkeychain.HardenedKeyStart) + if err != nil { + return nil, err + } + defer accountKey.Zero() + + xPubKey, err := accountKey.Neuter() + if err != nil { + return nil, err + } + + walletAccountKey, err := walletCoinTypePrivKey.Child(*cmd.Account + hdkeychain.HardenedKeyStart) + if err != nil { + return nil, err + } + defer walletAccountKey.Zero() + + walletxPubKey, err := walletAccountKey.Neuter() + if err != nil { + return nil, err + } + + // Since the field, key, within the type struct, ExtendedKey, is private - keys must be converted + // to type string for comparison. + matches = xPubKey.String() == walletxPubKey.String() + default: + matches = coinTypePrivKey.String() == walletCoinTypePrivKey.String() + } + + return &dcrjson.VerifySeedResult{ + Result: matches, + CoinType: coinType, + }, nil +} + // version handles the version command by returning the RPC API versions of the // wallet and, optionally, the consensus RPC server as well if it is associated // with the server. The chainClient is optional, and this is simply a helper diff --git a/rpc/legacyrpc/rpcserverhelp.go b/rpc/legacyrpc/rpcserverhelp.go index dc6e0faab..8d2cadf88 100644 --- a/rpc/legacyrpc/rpcserverhelp.go +++ b/rpc/legacyrpc/rpcserverhelp.go @@ -31,13 +31,13 @@ func helpDescsEnUS() map[string]string { "importscript": "importscript \"hex\" (rescan=true scanfrom)\n\nImport a redeem script.\n\nArguments:\n1. hex (string, required) Hex encoded script to import\n2. rescan (boolean, optional, default=true) Rescansfdsfd the blockchain (since the genesis block, or scanfrom block) for outputs controlled by the imported key\n3. scanfrom (numeric, optional) Block number for where to start rescan from\n\nResult:\nNothing\n", "keypoolrefill": "keypoolrefill (newsize=100)\n\nDEPRECATED -- This request does nothing since no keypool is maintained.\n\nArguments:\n1. newsize (numeric, optional, default=100) Unused\n\nResult:\nNothing\n", "listaccounts": "listaccounts (minconf=1)\n\nDEPRECATED -- Returns a JSON object of all accounts and their balances.\n\nArguments:\n1. minconf (numeric, optional, default=1) Minimum number of block confirmations required before an unspent output's value is included in the balance\n\nResult:\n{\n \"The account name\": The account balance valued in decred, (object) JSON object with account names as keys and decred amounts as values\n ...\n}\n", - "listlockunspent": "listlockunspent\n\nReturns a JSON array of outpoints marked as locked (with lockunspent) for this wallet session.\n\nArguments:\nNone\n\nResult:\n[{\n \"amount\": n.nnn, (numeric) The the previous output amount\n \"txid\": \"value\", (string) The transaction hash of the referenced output\n \"vout\": n, (numeric) The output index of the referenced output\n \"tree\": n, (numeric) The tree to generate transaction for\n},...]\n", + "listlockunspent": "listlockunspent\n\nReturns a JSON array of outpoints marked as locked (with lockunspent) for this wallet session.\n\nArguments:\nNone\n\nResult:\n[{\n \"txid\": \"value\", (string) The transaction hash of the referenced output\n \"vout\": n, (numeric) The output index of the referenced output\n \"tree\": n, (numeric) The tree to generate transaction for\n},...]\n", "listreceivedbyaccount": "listreceivedbyaccount (minconf=1 includeempty=false includewatchonly=false)\n\nDEPRECATED -- Returns a JSON array of objects listing all accounts and the total amount received by each account.\n\nArguments:\n1. minconf (numeric, optional, default=1) Minimum number of block confirmations required before a transaction is considered\n2. includeempty (boolean, optional, default=false) Unused\n3. includewatchonly (boolean, optional, default=false) Unused\n\nResult:\n[{\n \"account\": \"value\", (string) The name of the account\n \"amount\": n.nnn, (numeric) Total amount received by payment addresses of the account valued in decred\n \"confirmations\": n, (numeric) Number of block confirmations of the most recent transaction relevant to the account\n},...]\n", "listreceivedbyaddress": "listreceivedbyaddress (minconf=1 includeempty=false includewatchonly=false)\n\nReturns a JSON array of objects listing wallet payment addresses and their total received amounts.\n\nArguments:\n1. minconf (numeric, optional, default=1) Minimum number of block confirmations required before a transaction is considered\n2. includeempty (boolean, optional, default=false) Unused\n3. includewatchonly (boolean, optional, default=false) Unused\n\nResult:\n[{\n \"account\": \"value\", (string) DEPRECATED -- Unset\n \"address\": \"value\", (string) The payment address\n \"amount\": n.nnn, (numeric) Total amount received by the payment address valued in decred\n \"confirmations\": n, (numeric) Number of block confirmations of the most recent transaction relevant to the address\n \"txids\": [\"value\",...], (array of string) Transaction hashes of all transactions involving this address\n \"involvesWatchonly\": true|false, (boolean) Unset\n},...]\n", "listsinceblock": "listsinceblock (\"blockhash\" targetconfirmations=1 includewatchonly=false)\n\nReturns a JSON array of objects listing details of all wallet transactions after some block.\n\nArguments:\n1. blockhash (string, optional) Hash of the parent block of the first block to consider transactions from, or unset to list all transactions\n2. targetconfirmations (numeric, optional, default=1) Minimum number of block confirmations of the last block in the result object. Must be 1 or greater. Note: The transactions array in the result object is not affected by this parameter\n3. includewatchonly (boolean, optional, default=false) Unused\n\nResult:\n{\n \"transactions\": [{ (array of object) JSON array of objects containing verbose details of the each transaction\n \"account\": \"value\", (string) DEPRECATED -- Unset\n \"address\": \"value\", (string) Payment address for a transaction output\n \"amount\": n.nnn, (numeric) The value of the transaction output valued in decred\n \"blockhash\": \"value\", (string) The hash of the block this transaction is mined in, or the empty string if unmined\n \"blockindex\": n, (numeric) Unset\n \"blocktime\": n, (numeric) The Unix time of the block header this transaction is mined in, or 0 if unmined\n \"category\": \"value\", (string) The kind of transaction: \"send\" for sent transactions, \"immature\" for immature coinbase outputs, \"generate\" for mature coinbase outputs, or \"recv\" for all other received outputs. Note: A single output may be included multiple times under different categories\n \"confirmations\": n, (numeric) The number of block confirmations of the transaction\n \"fee\": n.nnn, (numeric) The total input value minus the total output value for sent transactions\n \"generated\": true|false, (boolean) Whether the transaction output is a coinbase output\n \"involveswatchonly\": true|false, (boolean) Unset\n \"time\": n, (numeric) The earliest Unix time this transaction was known to exist\n \"timereceived\": n, (numeric) The earliest Unix time this transaction was known to exist\n \"txid\": \"value\", (string) The hash of the transaction\n \"txtype\": \"value\", (string) The type of tx (regular tx, stake tx)\n \"vout\": n, (numeric) The transaction output index\n \"walletconflicts\": [\"value\",...], (array of string) Unset\n \"comment\": \"value\", (string) Unset\n \"otheraccount\": \"value\", (string) Unset\n },...], \n \"lastblock\": \"value\", (string) Hash of the latest-synced block to be used in later calls to listsinceblock\n} \n", "listtransactions": "listtransactions (\"account\" count=10 from=0 includewatchonly=false)\n\nReturns a JSON array of objects containing verbose details for wallet transactions.\n\nArguments:\n1. account (string, optional) DEPRECATED -- Unused (must be unset or \"*\")\n2. count (numeric, optional, default=10) Maximum number of transactions to create results from\n3. from (numeric, optional, default=0) Number of transactions to skip before results are created\n4. includewatchonly (boolean, optional, default=false) Unused\n\nResult:\n[{\n \"account\": \"value\", (string) DEPRECATED -- Unset\n \"address\": \"value\", (string) Payment address for a transaction output\n \"amount\": n.nnn, (numeric) The value of the transaction output valued in decred\n \"blockhash\": \"value\", (string) The hash of the block this transaction is mined in, or the empty string if unmined\n \"blockindex\": n, (numeric) Unset\n \"blocktime\": n, (numeric) The Unix time of the block header this transaction is mined in, or 0 if unmined\n \"category\": \"value\", (string) The kind of transaction: \"send\" for sent transactions, \"immature\" for immature coinbase outputs, \"generate\" for mature coinbase outputs, or \"recv\" for all other received outputs. Note: A single output may be included multiple times under different categories\n \"confirmations\": n, (numeric) The number of block confirmations of the transaction\n \"fee\": n.nnn, (numeric) The total input value minus the total output value for sent transactions\n \"generated\": true|false, (boolean) Whether the transaction output is a coinbase output\n \"involveswatchonly\": true|false, (boolean) Unset\n \"time\": n, (numeric) The earliest Unix time this transaction was known to exist\n \"timereceived\": n, (numeric) The earliest Unix time this transaction was known to exist\n \"txid\": \"value\", (string) The hash of the transaction\n \"txtype\": \"value\", (string) The type of tx (regular tx, stake tx)\n \"vout\": n, (numeric) The transaction output index\n \"walletconflicts\": [\"value\",...], (array of string) Unset\n \"comment\": \"value\", (string) Unset\n \"otheraccount\": \"value\", (string) Unset\n},...]\n", "listunspent": "listunspent (minconf=1 maxconf=9999999 [\"address\",...])\n\nReturns a JSON array of objects representing unlocked unspent outputs controlled by wallet keys.\n\nArguments:\n1. minconf (numeric, optional, default=1) Minimum number of block confirmations required before a transaction output is considered\n2. maxconf (numeric, optional, default=9999999) Maximum number of block confirmations required before a transaction output is excluded\n3. addresses (array of string, optional) If set, limits the returned details to unspent outputs received by any of these payment addresses\n\nResult:\n{\n \"txid\": \"value\", (string) The transaction hash of the referenced output\n \"vout\": n, (numeric) The output index of the referenced output\n \"tree\": n, (numeric) The tree the transaction comes from\n \"txtype\": n, (numeric) The type of the transaction\n \"address\": \"value\", (string) The payment address that received the output\n \"account\": \"value\", (string) The account associated with the receiving payment address\n \"scriptPubKey\": \"value\", (string) The output script encoded as a hexadecimal string\n \"redeemScript\": \"value\", (string) Unset\n \"amount\": n.nnn, (numeric) The amount of the output valued in decred\n \"confirmations\": n, (numeric) The number of block confirmations of the transaction\n \"spendable\": true|false, (boolean) Whether the output is entirely controlled by wallet keys/scripts (false for partially controlled multisig outputs or outputs to watch-only addresses)\n} \n", - "lockunspent": "lockunspent unlock [{\"amount\":n.nnn,\"txid\":\"value\",\"vout\":n,\"tree\":n},...]\n\nLocks or unlocks an unspent output.\nLocked outputs are not chosen for transaction inputs of authored transactions and are not included in 'listunspent' results.\nLocked outputs are volatile and are not saved across wallet restarts.\nIf unlock is true and no transaction outputs are specified, all locked outputs are marked unlocked.\n\nArguments:\n1. unlock (boolean, required) True to unlock outputs, false to lock\n2. transactions (array of object, required) Transaction outputs to lock or unlock\n[{\n \"amount\": n.nnn, (numeric) The the previous output amount\n \"txid\": \"value\", (string) The transaction hash of the referenced output\n \"vout\": n, (numeric) The output index of the referenced output\n \"tree\": n, (numeric) The tree to generate transaction for\n},...]\n\nResult:\ntrue|false (boolean) The boolean 'true'\n", + "lockunspent": "lockunspent unlock [{\"txid\":\"value\",\"vout\":n,\"tree\":n},...]\n\nLocks or unlocks an unspent output.\nLocked outputs are not chosen for transaction inputs of authored transactions and are not included in 'listunspent' results.\nLocked outputs are volatile and are not saved across wallet restarts.\nIf unlock is true and no transaction outputs are specified, all locked outputs are marked unlocked.\n\nArguments:\n1. unlock (boolean, required) True to unlock outputs, false to lock\n2. transactions (array of object, required) Transaction outputs to lock or unlock\n[{\n \"txid\": \"value\", (string) The transaction hash of the referenced output\n \"vout\": n, (numeric) The output index of the referenced output\n \"tree\": n, (numeric) The tree to generate transaction for\n},...]\n\nResult:\ntrue|false (boolean) The boolean 'true'\n", "redeemmultisigout": "redeemmultisigout \"hash\" index tree (\"address\")\n\nTakes the input and constructs a P2PKH paying to the specified address.\n\nArguments:\n1. hash (string, required) Hash of the input transaction\n2. index (numeric, required) Idx of the input transaction\n3. tree (numeric, required) Tree the transaction is on.\n4. address (string, optional) Address to pay to.\n\nResult:\n{\n \"hex\": \"value\", (string) Resulting hash.\n \"complete\": true|false, (boolean) Shows if opperation was completed.\n \"errors\": [{ (array of object) Any errors generated.\n \"txid\": \"value\", (string) The transaction hash of the referenced previous output\n \"vout\": n, (numeric) The output index of the referenced previous output\n \"scriptSig\": \"value\", (string) The hex-encoded signature script\n \"sequence\": n, (numeric) Script sequence number\n \"error\": \"value\", (string) Verification or signing error related to the input\n },...], \n} \n", "redeemmultisigouts": "redeemmultisigouts \"fromscraddress\" (\"toaddress\" number)\n\nTakes a hash, looks up all unspent outpoints and generates list artially signed transactions spending to either an address specified or internal addresses\n\nArguments:\n1. fromscraddress (string, required) Input script hash address.\n2. toaddress (string, optional) Address to look for (if not internal addresses).\n3. number (numeric, optional) Number of outpoints found.\n\nResult:\n{\n \"hex\": \"value\", (string) Resulting hash.\n \"complete\": true|false, (boolean) Shows if opperation was completed.\n \"errors\": [{ (array of object) Any errors generated.\n \"txid\": \"value\", (string) The transaction hash of the referenced previous output\n \"vout\": n, (numeric) The output index of the referenced previous output\n \"scriptSig\": \"value\", (string) The hex-encoded signature script\n \"sequence\": n, (numeric) Script sequence number\n \"error\": \"value\", (string) Verification or signing error related to the input\n },...], \n} \n", "rescanwallet": "rescanwallet (beginheight=0)\n\nRescan the block chain for wallet data, blocking until the rescan completes or exits with an error\n\nArguments:\n1. beginheight (numeric, optional, default=0) The height of the first block to begin the rescan from\n\nResult:\nNothing\n", @@ -56,6 +56,7 @@ func helpDescsEnUS() map[string]string { "sweepaccount": "sweepaccount \"sourceaccount\" \"destinationaddress\" (requiredconfirmations feeperkb)\n\nMoves as much value as possible in a transaction from an account.\n\n\nArguments:\n1. sourceaccount (string, required) The account to be swept.\n2. destinationaddress (string, required) The destination address to pay to.\n3. requiredconfirmations (numeric, optional) The minimum utxo confirmation requirement (optional).\n4. feeperkb (numeric, optional) The minimum relay fee policy (optional).\n\nResult:\n{\n \"unsignedtransaction\": \"value\", (string) The hex encoded string of the unsigned transaction\n \"totalpreviousoutputamount\": n.nnn, (numeric) The total transaction input amount.\n \"totaloutputamount\": n.nnn, (numeric) The total transaction output amount.\n \"estimatedsignedsize\": n, (numeric) The estimated size of the transaction when signed\n} \n", "validateaddress": "validateaddress \"address\"\n\nVerify that an address is valid.\nExtra details are returned if the address is controlled by this wallet.\nThe following fields are valid only when the address is controlled by this wallet (ismine=true): isscript, pubkey, iscompressed, account, addresses, hex, script, and sigsrequired.\nThe following fields are only valid when address has an associated public key: pubkey, iscompressed.\nThe following fields are only valid when address is a pay-to-script-hash address: addresses, hex, and script.\nIf the address is a multisig address controlled by this wallet, the multisig fields will be left unset if the wallet is locked since the redeem script cannot be decrypted.\n\nArguments:\n1. address (string, required) Address to validate\n\nResult:\n{\n \"isvalid\": true|false, (boolean) Whether or not the address is valid\n \"address\": \"value\", (string) The payment address (only when isvalid is true)\n \"ismine\": true|false, (boolean) Whether this address is controlled by the wallet (only when isvalid is true)\n \"iswatchonly\": true|false, (boolean) Unset\n \"isscript\": true|false, (boolean) Whether the payment address is a pay-to-script-hash address (only when isvalid is true)\n \"pubkeyaddr\": \"value\", (string) The pubkey for this payment address (only when isvalid is true)\n \"pubkey\": \"value\", (string) The associated public key of the payment address, if any (only when isvalid is true)\n \"iscompressed\": true|false, (boolean) Whether the address was created by hashing a compressed public key, if any (only when isvalid is true)\n \"account\": \"value\", (string) The account this payment address belongs to (only when isvalid is true)\n \"addresses\": [\"value\",...], (array of string) All associated payment addresses of the script if address is a multisig address (only when isvalid is true)\n \"hex\": \"value\", (string) The redeem script \n \"script\": \"value\", (string) The class of redeem script for a multisig address\n \"sigsrequired\": n, (numeric) The number of required signatures to redeem outputs to the multisig address\n} \n", "verifymessage": "verifymessage \"address\" \"signature\" \"message\"\n\nVerify a message was signed with the associated private key of some address.\n\nArguments:\n1. address (string, required) Address used to sign message\n2. signature (string, required) The signature to verify\n3. message (string, required) The message to verify\n\nResult:\ntrue|false (boolean) Whether the message was signed with the private key of 'address'\n", + "verifyseed": "verifyseed \"seed\" (account)\n\nVerifys if a seed is the same as the running wallet.\n\nArguments:\n1. seed (string, required) Seed to be inputted to check against the wallets master public key, after derivation.\n2. account (numeric, optional) Account number, of potential branch of the master public key, this is an optional input.\n\nResult:\n{\n \"keyresult\": true|false, (boolean) Whether or not if the inputted seed is the same as the running wallets\n \"cointype\": n, (numeric) Outputs the current cointype of the running wallet.\n} \n", "version": "version\n\nReturns application and API versions (semver) keyed by their names\n\nArguments:\nNone\n\nResult:\n{\n \"Program or API name\": Object containing the semantic version, (object) Version objects keyed by the program or API name\n ...\n}\n", "walletlock": "walletlock\n\nLock the wallet.\n\nArguments:\nNone\n\nResult:\nNothing\n", "walletpassphrase": "walletpassphrase \"passphrase\" timeout\n\nUnlock the wallet.\n\nArguments:\n1. passphrase (string, required) The wallet passphrase\n2. timeout (numeric, required) The number of seconds to wait before the wallet automatically locks\n\nResult:\nNothing\n", @@ -69,21 +70,5 @@ func helpDescsEnUS() map[string]string { "renameaccount": "renameaccount \"oldaccount\" \"newaccount\"\n\nRenames an account.\n\nArguments:\n1. oldaccount (string, required) The old account name to rename\n2. newaccount (string, required) The new name for the account\n\nResult:\nNothing\n", "walletislocked": "walletislocked\n\nReturns whether or not the wallet is locked.\n\nArguments:\nNone\n\nResult:\ntrue|false (boolean) Whether the wallet is locked\n", "walletinfo": "walletinfo\n\nReturns global information about the wallet\n\nArguments:\nNone\n\nResult:\n{\n \"daemonconnected\": true|false, (boolean) Whether or not the wallet is currently connected to the daemon RPC\n \"unlocked\": true|false, (boolean) Whether or not the wallet is unlocked\n \"txfee\": n.nnn, (numeric) Transaction fee per kB of the serialized tx size in coins\n \"ticketfee\": n.nnn, (numeric) Ticket fee per kB of the serialized tx size in coins\n \"ticketpurchasing\": true|false, (boolean) Whether or not the wallet is currently purchasing tickets\n \"votebits\": n, (numeric) Vote bits setting\n \"votebitsextended\": \"value\", (string) Extended vote bits setting\n \"voteversion\": n, (numeric) Version of votes that will be generated\n \"voting\": true|false, (boolean) Whether or not the wallet is currently voting tickets\n} \n", - "purchaseticket": "purchaseticket \"fromaccount\" spendlimit (minconf=1 \"ticketaddress\" numtickets \"pooladdress\" poolfees expiry \"comment\" ticketfee)\n\nPurchase ticket using available funds.\n\nArguments:\n1. fromaccount (string, required) The account to use for purchase (default=\"default\")\n2. spendlimit (numeric, required) Limit on the amount to spend on ticket\n3. minconf (numeric, optional, default=1) Minimum number of block confirmations required\n4. ticketaddress (string, optional) Override the ticket address to which voting rights are given\n5. numtickets (numeric, optional) The number of tickets to purchase\n6. pooladdress (string, optional) The address to pay stake pool fees to\n7. poolfees (numeric, optional) The amount of fees to pay to the stake pool\n8. expiry (numeric, optional) Height at which the purchase tickets expire\n9. comment (string, optional) Unused\n10. ticketfee (numeric, optional) The transaction fee rate (DCR/kB) to use (overrides fees set by the wallet config or settxfee RPC)\n\nResult:\n\"value\" (string) Hash of the resulting ticket\n", - "generatevote": "generatevote \"blockhash\" height \"tickethash\" votebits \"votebitsext\"\n\nReturns the vote transaction encoded as a hexadecimal string\n\nArguments:\n1. blockhash (string, required) Block hash for the ticket\n2. height (numeric, required) Block height for the ticket\n3. tickethash (string, required) The hash of the ticket\n4. votebits (numeric, required) The voteBits to set for the ticket\n5. votebitsext (string, required) The extended voteBits to set for the ticket\n\nResult:\n{\n \"hex\": \"value\", (string) The hex encoded transaction\n} \n", - "getstakeinfo": "getstakeinfo\n\nReturns statistics about staking from the wallet.\n\nArguments:\nNone\n\nResult:\n{\n \"blockheight\": n, (numeric) Current block height for stake info.\n \"difficulty\": n.nnn, (numeric) Current stake difficulty.\n \"totalsubsidy\": n.nnn, (numeric) Total amount of coins earned by stake mining\n \"ownmempooltix\": n, (numeric) Number of tickets submitted by this wallet currently in mempool\n \"immature\": n, (numeric) Number of tickets from this wallet that are in the blockchain but which are not yet mature\n \"unspent\": n, (numeric) Number of unspent tickets\n \"voted\": n, (numeric) Number of votes cast by this wallet\n \"revoked\": n, (numeric) Number of missed tickets that were missed and then revoked\n \"unspentexpired\": n, (numeric) Number of unspent tickets which are past expiry\n \"poolsize\": n, (numeric) Number of live tickets in the ticket pool.\n \"allmempooltix\": n, (numeric) Number of tickets currently in the mempool\n \"live\": n, (numeric) Number of mature, active tickets owned by this wallet\n \"proportionlive\": n.nnn, (numeric) (Live / PoolSize)\n \"missed\": n, (numeric) Number of missed tickets (failure to vote, not including expired)\n \"proportionmissed\": n.nnn, (numeric) (Missed / (Missed + Voted))\n \"expired\": n, (numeric) Number of tickets that have expired\n} \n", - "getticketfee": "getticketfee\n\nGet the current fee per kB of the serialized tx size used for an authored stake transaction.\n\nArguments:\nNone\n\nResult:\nn.nnn (numeric) The current fee\n", - "setticketfee": "setticketfee fee\n\nModify the fee per kB of the serialized tx size used each time more fee is required for an authored stake transaction.\n\nArguments:\n1. fee (numeric, required) The new fee per kB of the serialized tx size valued in decred\n\nResult:\ntrue|false (boolean) The boolean 'true'\n", - "getwalletfee": "getwalletfee\n\nGet currently set transaction fee for the wallet\n\nArguments:\nNone\n\nResult:\nn.nnn (numeric) Current tx fee (in DCR)\n", - "addticket": "addticket \"tickethex\"\n\nAdd a ticket to the wallet for vote and revocation creation. Added tickets are auxiliary to transaction history and do not appear in getstakeinfo stats.\n\nArguments:\n1. tickethex (string, required) Hex-encoded serialized transaction\n\nResult:\nNothing\n", - "listscripts": "listscripts\n\nList all scripts that have been added to wallet\n\nArguments:\nNone\n\nResult:\n{\n \"scripts\": [{ (array of object) A list of the imported scripts\n \"hash160\": \"value\", (string) The script hash\n \"address\": \"value\", (string) The script address\n \"redeemscript\": \"value\", (string) The redeem script\n },...], \n} \n", - "stakepooluserinfo": "stakepooluserinfo \"user\"\n\nGet user info for stakepool\n\nArguments:\n1. user (string, required) The id of the user to be looked up\n\nResult:\n{\n \"tickets\": [{ (array of object) A list of valid tickets that the user has added\n \"status\": \"value\", (string) The current status of the added ticket\n \"ticket\": \"value\", (string) The hash of the added ticket\n \"ticketheight\": n, (numeric) The height in which the ticket was added\n \"spentby\": \"value\", (string) The vote in which the ticket was spent\n \"spentbyheight\": n, (numeric) The height in which the ticket was spent\n },...], \n \"invalid\": [\"value\",...], (array of string) A list of invalid tickets that the user has added\n} \n", - "ticketsforaddress": "ticketsforaddress \"address\"\n\nRequest all the tickets for an address.\n\nArguments:\n1. address (string, required) Address to look for.\n\nResult:\ntrue|false (boolean) Tickets owned by the specified address.\n", } } - -var localeHelpDescs = map[string]func() map[string]string{ - "en_US": helpDescsEnUS, -} - -var requestUsages = "accountaddressindex \"account\" branch\naccountsyncaddressindex \"account\" branch index\naddmultisigaddress nrequired [\"key\",...] (\"account\")\nconsolidate inputs (\"account\" \"address\")\ncreatemultisig nrequired [\"key\",...]\ndumpprivkey \"address\"\ngetaccount \"address\"\ngetaccountaddress \"account\"\ngetaddressesbyaccount \"account\"\ngetbalance (\"account\" minconf=1)\ngetbestblockhash\ngetblockcount\ngetinfo\ngetmasterpubkey (\"account\")\ngetmultisigoutinfo \"hash\" index\ngetnewaddress (\"account\" \"gappolicy\")\ngetrawchangeaddress (\"account\")\ngetreceivedbyaccount \"account\" (minconf=1)\ngetreceivedbyaddress \"address\" (minconf=1)\ngettickets includeimmature\ngettransaction \"txid\" (includewatchonly=false)\ngetvotechoices\nhelp (\"command\")\nimportprivkey \"privkey\" (\"label\" rescan=true scanfrom)\nimportscript \"hex\" (rescan=true scanfrom)\nkeypoolrefill (newsize=100)\nlistaccounts (minconf=1)\nlistlockunspent\nlistreceivedbyaccount (minconf=1 includeempty=false includewatchonly=false)\nlistreceivedbyaddress (minconf=1 includeempty=false includewatchonly=false)\nlistsinceblock (\"blockhash\" targetconfirmations=1 includewatchonly=false)\nlisttransactions (\"account\" count=10 from=0 includewatchonly=false)\nlistunspent (minconf=1 maxconf=9999999 [\"address\",...])\nlockunspent unlock [{\"amount\":n.nnn,\"txid\":\"value\",\"vout\":n,\"tree\":n},...]\nredeemmultisigout \"hash\" index tree (\"address\")\nredeemmultisigouts \"fromscraddress\" (\"toaddress\" number)\nrescanwallet (beginheight=0)\nrevoketickets\nsendfrom \"fromaccount\" \"toaddress\" amount (minconf=1 \"comment\" \"commentto\")\nsendmany \"fromaccount\" {\"address\":amount,...} (minconf=1 \"comment\")\nsendtoaddress \"address\" amount (\"comment\" \"commentto\")\nsendtomultisig \"fromaccount\" amount [\"pubkey\",...] (nrequired=1 minconf=1 \"comment\")\nsettxfee amount\nsetvotechoice \"agendaid\" \"choiceid\"\nsignmessage \"address\" \"message\"\nsignrawtransaction \"rawtx\" ([{\"txid\":\"value\",\"vout\":n,\"tree\":n,\"scriptpubkey\":\"value\",\"redeemscript\":\"value\"},...] [\"privkey\",...] flags=\"ALL\")\nsignrawtransactions [\"rawtx\",...] (send=true)\nstartautobuyer \"account\" \"passphrase\" (balancetomaintain maxfeeperkb maxpricerelative maxpriceabsolute \"votingaddress\" \"pooladdress\" poolfees maxperblock)\nstopautobuyer\nsweepaccount \"sourceaccount\" \"destinationaddress\" (requiredconfirmations feeperkb)\nvalidateaddress \"address\"\nverifymessage \"address\" \"signature\" \"message\"\nversion\nwalletlock\nwalletpassphrase \"passphrase\" timeout\nwalletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\ncreatenewaccount \"account\"\nexportwatchingwallet (\"account\" download=false)\ngetbestblock\ngetunconfirmedbalance (\"account\")\nlistaddresstransactions [\"address\",...] (\"account\")\nlistalltransactions (\"account\")\nrenameaccount \"oldaccount\" \"newaccount\"\nwalletislocked\nwalletinfo\npurchaseticket \"fromaccount\" spendlimit (minconf=1 \"ticketaddress\" numtickets \"pooladdress\" poolfees expiry \"comment\" ticketfee)\ngeneratevote \"blockhash\" height \"tickethash\" votebits \"votebitsext\"\ngetstakeinfo\ngetticketfee\nsetticketfee fee\ngetwalletfee\naddticket \"tickethex\"\nlistscripts\nstakepooluserinfo \"user\"\nticketsforaddress \"address\"" diff --git a/wallet/wallet.go b/wallet/wallet.go index cdb9179b9..9077b308d 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -1848,35 +1848,6 @@ func (w *Wallet) MasterPubKey(account uint32) (*hdkeychain.ExtendedKey, error) { return extKey, nil } -// GetTransactionsByHashes returns all known transactions identified by a slice -// of transaction hashes. It is possible that not all transactions are found, -// and in this case the known results will be returned along with an inventory -// vector of all missing transactions and an error with code -// NotExist. -func (w *Wallet) GetTransactionsByHashes(txHashes []*chainhash.Hash) (txs []*wire.MsgTx, notFound []*wire.InvVect, err error) { - err = walletdb.View(w.db, func(dbtx walletdb.ReadTx) error { - ns := dbtx.ReadBucket(wtxmgrNamespaceKey) - for _, hash := range txHashes { - tx, err := w.TxStore.Tx(ns, hash) - if err != nil { - return err - } - if tx == nil { - notFound = append(notFound, wire.NewInvVect(wire.InvTypeTx, hash)) - } else { - txs = append(txs, tx) - } - } - return nil - }) - if err != nil { - return - } - if len(notFound) != 0 { - err = errors.E(errors.NotExist, "transaction(s) not found") - } - return -======= // CoinTypeKey returns the BIP0044 coin type private key for the passed account. func (w *Wallet) CoinTypeKey() (*hdkeychain.ExtendedKey, error) { const op errors.Op = "wallet.CoinTypeKey" @@ -1905,7 +1876,36 @@ func (w *Wallet) CoinType() (uint32, error) { return 0, errors.E(op, err) } return coinType, nil ->>>>>>> wallet: Add CoinTypeKey and CoinType functions +} + +// GetTransactionsByHashes returns all known transactions identified by a slice +// of transaction hashes. It is possible that not all transactions are found, +// and in this case the known results will be returned along with an inventory +// vector of all missing transactions and an error with code +// NotExist. +func (w *Wallet) GetTransactionsByHashes(txHashes []*chainhash.Hash) (txs []*wire.MsgTx, notFound []*wire.InvVect, err error) { + err = walletdb.View(w.db, func(dbtx walletdb.ReadTx) error { + ns := dbtx.ReadBucket(wtxmgrNamespaceKey) + for _, hash := range txHashes { + tx, err := w.TxStore.Tx(ns, hash) + if err != nil { + return err + } + if tx == nil { + notFound = append(notFound, wire.NewInvVect(wire.InvTypeTx, hash)) + } else { + txs = append(txs, tx) + } + } + return nil + }) + if err != nil { + return + } + if len(notFound) != 0 { + err = errors.E(errors.NotExist, "transaction(s) not found") + } + return } // CreditCategory describes the type of wallet transaction output. The category