Skip to content

Commit

Permalink
legacyrpc: add address type arg to getNewAddress and getRawChangeAddress
Browse files Browse the repository at this point in the history
This handles the AddressType argument in the getNewAddress RPC handler.
It recognizes "legacy", "p2sh-segwit", and "bech32" to match Bitcoin
Core's RPC options.  These correspond to bip44, bip49 "plus", and bip84.

These are the waddrmgr.DefaultKeyScopes.

The validateaddress RPC is already able to recognize these addresses,
and it may be used to verify the addresses returned by getnewaddress.

This adds btcjson.ErrRPCWalletInvalidAddressType with a code (-5) and
message ("unknown address type") to match Bitcoin Core's v22.
  • Loading branch information
chappjc committed Apr 27, 2022
1 parent 8d8315d commit 6f4158e
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 19 deletions.
5 changes: 1 addition & 4 deletions cmd/sweepaccount/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,8 @@ func makeInputSource(outputs []btcjson.ListUnspentResult) txauthor.InputSource {
// all correlated previous input value. A non-change address is created by this
// function.
func makeDestinationScriptSource(rpcClient *rpcclient.Client, accountName string) *txauthor.ChangeSource {

// GetNewAddress always returns a P2PKH address since it assumes
// BIP-0044.
newChangeScript := func() ([]byte, error) {
destinationAddress, err := rpcClient.GetNewAddress(accountName)
destinationAddress, err := rpcClient.GetNewAddress(accountName, "legacy")
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module github.com/btcsuite/btcwallet

require (
github.com/btcsuite/btcd v0.22.0-beta.0.20220316175102-8d5c75c28923
github.com/btcsuite/btcd v0.22.0-beta.0.20220409120200-3986702b97d3
github.com/btcsuite/btcd/btcec/v2 v2.1.3
github.com/btcsuite/btcd/btcutil v1.1.1
github.com/btcsuite/btcd/btcutil/psbt v1.1.1
Expand Down
3 changes: 2 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13P
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
github.com/btcsuite/btcd v0.22.0-beta.0.20220204213055-eaf0459ff879/go.mod h1:osu7EoKiL36UThEgzYPqdRaxeo0NU8VoXqgcnwpey0g=
github.com/btcsuite/btcd v0.22.0-beta.0.20220207191057-4dc4ff7963b4/go.mod h1:7alexyj/lHlOtr2PJK7L/+HDJZpcGDn/pAU98r7DY08=
github.com/btcsuite/btcd v0.22.0-beta.0.20220316175102-8d5c75c28923 h1:6H47xWODLXYDuzHapvx4dauPqFjegX4+rHgUkFQPvfw=
github.com/btcsuite/btcd v0.22.0-beta.0.20220316175102-8d5c75c28923/go.mod h1:taIcYprAW2g6Z9S0gGUxyR+zDwimyDMK5ePOX+iJ2ds=
github.com/btcsuite/btcd v0.22.0-beta.0.20220409120200-3986702b97d3 h1:TlpcjYEfupqYtQB5lz2LpGPLQ0saF1XoTn5T5796Ubc=
github.com/btcsuite/btcd v0.22.0-beta.0.20220409120200-3986702b97d3/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=
github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA=
github.com/btcsuite/btcd/btcec/v2 v2.1.1/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE=
Expand Down
14 changes: 8 additions & 6 deletions internal/rpchelp/helpdescs_en_US.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,16 @@ var helpDescsEnUS = map[string]string{
"infowalletresult-keypoololdest": "Unset",

// GetNewAddressCmd help.
"getnewaddress--synopsis": "Generates and returns a new payment address.",
"getnewaddress-account": "DEPRECATED -- Account name the new address will belong to (default=\"default\")",
"getnewaddress--result0": "The payment address",
"getnewaddress--synopsis": "Generates and returns a new payment address.",
"getnewaddress-account": "DEPRECATED -- Account name the new address will belong to (default=\"default\")",
"getnewaddress-addresstype": "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\".(default=\"legacy\")",
"getnewaddress--result0": "The payment address",

// GetRawChangeAddressCmd help.
"getrawchangeaddress--synopsis": "Generates and returns a new internal payment address for use as a change address in raw transactions.",
"getrawchangeaddress-account": "Account name the new internal address will belong to (default=\"default\")",
"getrawchangeaddress--result0": "The internal payment address",
"getrawchangeaddress--synopsis": "Generates and returns a new internal payment address for use as a change address in raw transactions.",
"getrawchangeaddress-account": "Account name the new internal address will belong to (default=\"default\")",
"getrawchangeaddress-addresstype": "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\".(default=\"legacy\")",
"getrawchangeaddress--result0": "The internal payment address",

// GetReceivedByAccountCmd help.
"getreceivedbyaccount--synopsis": "DEPRECATED -- Returns the total amount received by addresses of some account, including spent outputs.",
Expand Down
5 changes: 5 additions & 0 deletions rpc/legacyrpc/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ var (
Message: "address not found in wallet",
}

ErrAddressTypeUnknown = btcjson.RPCError{
Code: btcjson.ErrRPCWalletInvalidAddressType,
Message: "unknown address type",
}

ErrAccountNameNotFound = btcjson.RPCError{
Code: btcjson.ErrRPCWalletInvalidAccountName,
Message: "account name not found",
Expand Down
32 changes: 28 additions & 4 deletions rpc/legacyrpc/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -685,11 +685,23 @@ func getNewAddress(icmd interface{}, w *wallet.Wallet) (interface{}, error) {
if cmd.Account != nil {
acctName = *cmd.Account
}
account, err := w.AccountNumber(waddrmgr.KeyScopeBIP0044, acctName)
keyScope := waddrmgr.KeyScopeBIP0044
if cmd.AddressType != nil {
switch *cmd.AddressType {
case "p2sh-segwit":
keyScope = waddrmgr.KeyScopeBIP0049Plus
case "bech32":
keyScope = waddrmgr.KeyScopeBIP0084
case "legacy": // default if unset
default:
return nil, &ErrAddressTypeUnknown
}
}
account, err := w.AccountNumber(keyScope, acctName)
if err != nil {
return nil, err
}
addr, err := w.NewAddress(account, waddrmgr.KeyScopeBIP0044)
addr, err := w.NewAddress(account, keyScope)
if err != nil {
return nil, err
}
Expand All @@ -710,11 +722,23 @@ func getRawChangeAddress(icmd interface{}, w *wallet.Wallet) (interface{}, error
if cmd.Account != nil {
acctName = *cmd.Account
}
account, err := w.AccountNumber(waddrmgr.KeyScopeBIP0044, acctName)
keyScope := waddrmgr.KeyScopeBIP0044
if cmd.AddressType != nil {
switch *cmd.AddressType {
case "p2sh-segwit":
keyScope = waddrmgr.KeyScopeBIP0049Plus
case "bech32":
keyScope = waddrmgr.KeyScopeBIP0084
case "legacy": // default if unset
default:
return nil, &ErrAddressTypeUnknown
}
}
account, err := w.AccountNumber(keyScope, acctName)
if err != nil {
return nil, err
}
addr, err := w.NewChangeAddress(account, waddrmgr.KeyScopeBIP0044)
addr, err := w.NewChangeAddress(account, keyScope)
if err != nil {
return nil, err
}
Expand Down
6 changes: 3 additions & 3 deletions rpc/legacyrpc/rpcserverhelp.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ func helpDescsEnUS() map[string]string {
"getbestblockhash": "getbestblockhash\n\nReturns the hash of the newest block in the best chain that wallet has finished syncing with.\n\nArguments:\nNone\n\nResult:\n\"value\" (string) The hash of the most recent synced-to block\n",
"getblockcount": "getblockcount\n\nReturns the blockchain height of the newest block in the best chain that wallet has finished syncing with.\n\nArguments:\nNone\n\nResult:\nn.nnn (numeric) The blockchain height of the most recent synced-to block\n",
"getinfo": "getinfo\n\nReturns a JSON object containing various state info.\n\nArguments:\nNone\n\nResult:\n{\n \"version\": n, (numeric) The version of the server\n \"protocolversion\": n, (numeric) The latest supported protocol version\n \"walletversion\": n, (numeric) The version of the address manager database\n \"balance\": n.nnn, (numeric) The balance of all accounts calculated with one block confirmation\n \"blocks\": n, (numeric) The number of blocks processed\n \"timeoffset\": n, (numeric) The time offset\n \"connections\": n, (numeric) The number of connected peers\n \"proxy\": \"value\", (string) The proxy used by the server\n \"difficulty\": n.nnn, (numeric) The current target difficulty\n \"testnet\": true|false, (boolean) Whether or not server is using testnet\n \"keypoololdest\": n, (numeric) Unset\n \"keypoolsize\": n, (numeric) Unset\n \"unlocked_until\": n, (numeric) Unset\n \"paytxfee\": n.nnn, (numeric) The increment used each time more fee is required for an authored transaction\n \"relayfee\": n.nnn, (numeric) The minimum relay fee for non-free transactions in BTC/KB\n \"errors\": \"value\", (string) Any current errors\n} \n",
"getnewaddress": "getnewaddress (\"account\")\n\nGenerates and returns a new payment address.\n\nArguments:\n1. account (string, optional) DEPRECATED -- Account name the new address will belong to (default=\"default\")\n\nResult:\n\"value\" (string) The payment address\n",
"getrawchangeaddress": "getrawchangeaddress (\"account\")\n\nGenerates and returns a new internal payment address for use as a change address in raw transactions.\n\nArguments:\n1. account (string, optional) Account name the new internal address will belong to (default=\"default\")\n\nResult:\n\"value\" (string) The internal payment address\n",
"getnewaddress": "getnewaddress (\"account\" \"addresstype\")\n\nGenerates and returns a new payment address.\n\nArguments:\n1. account (string, optional) DEPRECATED -- Account name the new address will belong to (default=\"default\")\n2. addresstype (string, optional) The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\".(default=\"legacy\")\n\nResult:\n\"value\" (string) The payment address\n",
"getrawchangeaddress": "getrawchangeaddress (\"account\" \"addresstype\")\n\nGenerates and returns a new internal payment address for use as a change address in raw transactions.\n\nArguments:\n1. account (string, optional) Account name the new internal address will belong to (default=\"default\")\n2. addresstype (string, optional) The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\".(default=\"legacy\")\n\nResult:\n\"value\" (string) The internal payment address\n",
"getreceivedbyaccount": "getreceivedbyaccount \"account\" (minconf=1)\n\nDEPRECATED -- Returns the total amount received by addresses of some account, including spent outputs.\n\nArguments:\n1. account (string, required) Account name to query total received amount for\n2. minconf (numeric, optional, default=1) Minimum number of block confirmations required before an output's value is included in the total\n\nResult:\nn.nnn (numeric) The total received amount valued in bitcoin\n",
"getreceivedbyaddress": "getreceivedbyaddress \"address\" (minconf=1)\n\nReturns the total amount received by a single address, including spent outputs.\n\nArguments:\n1. address (string, required) Payment address which received outputs to include in total\n2. minconf (numeric, optional, default=1) Minimum number of block confirmations required before an output's value is included in the total\n\nResult:\nn.nnn (numeric) The total received amount valued in bitcoin\n",
"gettransaction": "gettransaction \"txid\" (includewatchonly=false)\n\nReturns a JSON object with details regarding a transaction relevant to this wallet.\n\nArguments:\n1. txid (string, required) Hash of the transaction to query\n2. includewatchonly (boolean, optional, default=false) Also consider transactions involving watched addresses\n\nResult:\n{\n \"amount\": n.nnn, (numeric) The total amount this transaction credits to the wallet, valued in bitcoin\n \"fee\": n.nnn, (numeric) The total input value minus the total output value, or 0 if 'txid' is not a sent transaction\n \"confirmations\": n, (numeric) The number of block confirmations of the transaction\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 \"txid\": \"value\", (string) The transaction hash\n \"walletconflicts\": [\"value\",...], (array of string) 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 \"details\": [{ (array of object) Additional details for each recorded wallet credit and debit\n \"account\": \"value\", (string) DEPRECATED -- Unset\n \"address\": \"value\", (string) The address an output was paid to, or the empty string if the output is nonstandard or this detail is regarding a transaction input\n \"amount\": n.nnn, (numeric) The amount of a received output\n \"category\": \"value\", (string) The kind of detail: \"send\" for sent transactions, \"immature\" for immature coinbase outputs, \"generate\" for mature coinbase outputs, or \"recv\" for all other received outputs\n \"involveswatchonly\": true|false, (boolean) Unset\n \"fee\": n.nnn, (numeric) The included fee for a sent transaction\n \"vout\": n, (numeric) The transaction output index\n },...], \n \"hex\": \"value\", (string) The transaction encoded as a hexadecimal string\n} \n",
Expand Down Expand Up @@ -56,4 +56,4 @@ var localeHelpDescs = map[string]func() map[string]string{
"en_US": helpDescsEnUS,
}

var requestUsages = "addmultisigaddress nrequired [\"key\",...] (\"account\")\ncreatemultisig nrequired [\"key\",...]\ndumpprivkey \"address\"\ngetaccount \"address\"\ngetaccountaddress \"account\"\ngetaddressesbyaccount \"account\"\ngetbalance (\"account\" minconf=1)\ngetbestblockhash\ngetblockcount\ngetinfo\ngetnewaddress (\"account\")\ngetrawchangeaddress (\"account\")\ngetreceivedbyaccount \"account\" (minconf=1)\ngetreceivedbyaddress \"address\" (minconf=1)\ngettransaction \"txid\" (includewatchonly=false)\nhelp (\"command\")\nimportprivkey \"privkey\" (\"label\" rescan=true)\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 [{\"txid\":\"value\",\"vout\":n},...]\nsendfrom \"fromaccount\" \"toaddress\" amount (minconf=1 \"comment\" \"commentto\")\nsendmany \"fromaccount\" {\"address\":amount,...} (minconf=1 \"comment\")\nsendtoaddress \"address\" amount (\"comment\" \"commentto\")\nsettxfee amount\nsignmessage \"address\" \"message\"\nsignrawtransaction \"rawtx\" ([{\"txid\":\"value\",\"vout\":n,\"scriptpubkey\":\"value\",\"redeemscript\":\"value\"},...] [\"privkey\",...] flags=\"ALL\")\nvalidateaddress \"address\"\nverifymessage \"address\" \"signature\" \"message\"\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"
var requestUsages = "addmultisigaddress nrequired [\"key\",...] (\"account\")\ncreatemultisig nrequired [\"key\",...]\ndumpprivkey \"address\"\ngetaccount \"address\"\ngetaccountaddress \"account\"\ngetaddressesbyaccount \"account\"\ngetbalance (\"account\" minconf=1)\ngetbestblockhash\ngetblockcount\ngetinfo\ngetnewaddress (\"account\" \"addresstype\")\ngetrawchangeaddress (\"account\" \"addresstype\")\ngetreceivedbyaccount \"account\" (minconf=1)\ngetreceivedbyaddress \"address\" (minconf=1)\ngettransaction \"txid\" (includewatchonly=false)\nhelp (\"command\")\nimportprivkey \"privkey\" (\"label\" rescan=true)\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 [{\"txid\":\"value\",\"vout\":n},...]\nsendfrom \"fromaccount\" \"toaddress\" amount (minconf=1 \"comment\" \"commentto\")\nsendmany \"fromaccount\" {\"address\":amount,...} (minconf=1 \"comment\")\nsendtoaddress \"address\" amount (\"comment\" \"commentto\")\nsettxfee amount\nsignmessage \"address\" \"message\"\nsignrawtransaction \"rawtx\" ([{\"txid\":\"value\",\"vout\":n,\"scriptpubkey\":\"value\",\"redeemscript\":\"value\"},...] [\"privkey\",...] flags=\"ALL\")\nvalidateaddress \"address\"\nverifymessage \"address\" \"signature\" \"message\"\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"

0 comments on commit 6f4158e

Please sign in to comment.