diff options
-rw-r--r-- | src/qt/bitcoinstrings.cpp | 9 | ||||
-rw-r--r-- | src/qt/locale/bitcoin_en.ts | 52 | ||||
-rw-r--r-- | src/wallet/coincontrol.h | 4 | ||||
-rw-r--r-- | src/wallet/init.cpp | 8 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 32 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 8 | ||||
-rw-r--r-- | src/wallet/wallet.h | 2 | ||||
-rwxr-xr-x | test/functional/fundrawtransaction.py | 13 | ||||
-rwxr-xr-x | test/functional/nulldummy.py | 2 | ||||
-rwxr-xr-x | test/functional/segwit.py | 5 |
10 files changed, 71 insertions, 64 deletions
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 03aceb4d9e..adf001c968 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -251,13 +251,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Warning: We do not appear to fully agree with our peers! You may need to " "upgrade, or other nodes may need to upgrade."), QT_TRANSLATE_NOOP("bitcoin-core", "" -"What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", " -"default: \"%s\")"), -QT_TRANSLATE_NOOP("bitcoin-core", "" -"What type of change to use (\"legacy\", \"p2sh-segwit\", or \"bech32\"). " -"Default is same as -addresstype, except when -addresstype=p2sh-segwit a " -"native segwit output is used when sending to a native segwit address)"), -QT_TRANSLATE_NOOP("bitcoin-core", "" "Whether to save the mempool on shutdown and load on restart (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "" "Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR " @@ -414,8 +407,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind r QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer. %s is probably already running."), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to generate initial keys"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to start HTTP server. See debug log for details."), -QT_TRANSLATE_NOOP("bitcoin-core", "Unknown address type '%s'"), -QT_TRANSLATE_NOOP("bitcoin-core", "Unknown change type '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -benchmark ignored, use -debug=bench."), QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -debugnet ignored, use -debug=net."), diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index a892da4cbd..2b712b4317 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -4025,7 +4025,7 @@ <context> <name>bitcoin-core</name> <message> - <location filename="../bitcoinstrings.cpp" line="+358"/> + <location filename="../bitcoinstrings.cpp" line="+351"/> <source>Options:</source> <translation>Options:</translation> </message> @@ -4050,7 +4050,7 @@ <translation>Accept command line and JSON-RPC commands</translation> </message> <message> - <location line="-216"/> + <location line="-209"/> <source>Distributed under the MIT software license, see the accompanying file %s or %s</source> <translation type="unfinished"></translation> </message> @@ -4075,7 +4075,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+158"/> + <location line="+151"/> <source>Error: A fatal internal error occurred, see debug.log for details</source> <translation type="unfinished"></translation> </message> @@ -4100,7 +4100,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="-404"/> + <location line="-397"/> <source>Bitcoin Core</source> <translation type="unfinished">Bitcoin Core</translation> </message> @@ -4265,7 +4265,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+10"/> + <location line="+3"/> <source>Whether to save the mempool on shutdown and load on restart (default: %u)</source> <translation type="unfinished"></translation> </message> @@ -4565,7 +4565,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+6"/> + <location line="+4"/> <source>Unsupported argument -benchmark ignored, use -debug=bench.</source> <translation type="unfinished"></translation> </message> @@ -4625,7 +4625,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="-406"/> + <location line="-397"/> <source>Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times</source> <translation type="unfinished"></translation> </message> @@ -4685,7 +4685,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+71"/> + <location line="+64"/> <source>Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway</source> <translation type="unfinished"></translation> </message> @@ -4870,17 +4870,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> - <source>Unknown address type '%s'</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+1"/> - <source>Unknown change type '%s'</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+6"/> + <location line="+7"/> <source>Upgrade wallet to latest format on startup</source> <translation type="unfinished"></translation> </message> @@ -4930,22 +4920,22 @@ <translation type="unfinished"></translation> </message> <message> - <location line="-82"/> + <location line="-80"/> <source>Password for JSON-RPC connections</source> <translation>Password for JSON-RPC connections</translation> </message> <message> - <location line="-270"/> + <location line="-263"/> <source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source> <translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation> </message> <message> - <location line="+192"/> + <location line="+185"/> <source>Allow DNS lookups for -addnode, -seednode and -connect</source> <translation>Allow DNS lookups for -addnode, -seednode and -connect</translation> </message> <message> - <location line="-267"/> + <location line="-260"/> <source>(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source> <translation type="unfinished"></translation> </message> @@ -5085,17 +5075,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> - <source>What type of addresses to use ("legacy", "p2sh-segwit", or "bech32", default: "%s")</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> - <source>What type of change to use ("legacy", "p2sh-segwit", or "bech32"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+6"/> + <location line="+9"/> <source>Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times.</source> <translation type="unfinished"></translation> </message> @@ -5265,12 +5245,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+7"/> <source>Unknown network specified in -onlynet: '%s'</source> <translation>Unknown network specified in -onlynet: '%s'</translation> </message> <message> - <location line="-87"/> + <location line="-85"/> <source>Insufficient funds</source> <translation>Insufficient funds</translation> </message> diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h index e1afa2de03..458e770e03 100644 --- a/src/wallet/coincontrol.h +++ b/src/wallet/coincontrol.h @@ -16,7 +16,10 @@ class CCoinControl { public: + //! Custom change destination, if not set an address is generated CTxDestination destChange; + //! Custom change type, ignored if destChange is set, defaults to g_change_type + OutputType change_type; //! If false, allows unselected inputs, but requires all selected inputs be used bool fAllowOtherInputs; //! Includes watch only addresses which match the ISMINE_WATCH_SOLVABLE criteria @@ -40,6 +43,7 @@ public: void SetNull() { destChange = CNoDestination(); + change_type = g_change_type; fAllowOtherInputs = false; fAllowWatchOnly = false; setSelected.clear(); diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index c7f19bc90a..ace95204b8 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -16,8 +16,8 @@ std::string GetWalletHelpString(bool showDebug) { std::string strUsage = HelpMessageGroup(_("Wallet options:")); - strUsage += HelpMessageOpt("-addresstype", strprintf(_("What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", default: \"%s\")"), FormatOutputType(OUTPUT_TYPE_DEFAULT))); - strUsage += HelpMessageOpt("-changetype", _("What type of change to use (\"legacy\", \"p2sh-segwit\", or \"bech32\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)")); + strUsage += HelpMessageOpt("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", default: \"%s\")", FormatOutputType(OUTPUT_TYPE_DEFAULT))); + strUsage += HelpMessageOpt("-changetype", "What type of change to use (\"legacy\", \"p2sh-segwit\", or \"bech32\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)"); strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE)); strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"), @@ -179,14 +179,14 @@ bool WalletParameterInteraction() g_address_type = ParseOutputType(gArgs.GetArg("-addresstype", "")); if (g_address_type == OUTPUT_TYPE_NONE) { - return InitError(strprintf(_("Unknown address type '%s'"), gArgs.GetArg("-addresstype", ""))); + return InitError(strprintf("Unknown address type '%s'", gArgs.GetArg("-addresstype", ""))); } // If changetype is set in config file or parameter, check that it's valid. // Default to OUTPUT_TYPE_NONE if not set. g_change_type = ParseOutputType(gArgs.GetArg("-changetype", ""), OUTPUT_TYPE_NONE); if (g_change_type == OUTPUT_TYPE_NONE && !gArgs.GetArg("-changetype", "").empty()) { - return InitError(strprintf(_("Unknown change type '%s'"), gArgs.GetArg("-changetype", ""))); + return InitError(strprintf("Unknown change type '%s'", gArgs.GetArg("-changetype", ""))); } return true; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 6849671dcf..fcee22a14a 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1169,9 +1169,8 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) - { - std::string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n" + if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) { + std::string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" \"address_type\" )\n" "\nAdd a nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.\n" "Each key is a Bitcoin address or hex-encoded public key.\n" "This functionality is only intended for use with non-watchonly addresses.\n" @@ -1186,6 +1185,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) " ...,\n" " ]\n" "3. \"account\" (string, optional) DEPRECATED. An account to assign the addresses to.\n" + "4. \"address_type\" (string, optional) The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -addresstype.\n" "\nResult:\n" "{\n" @@ -1224,10 +1224,18 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) } } + OutputType output_type = g_address_type; + if (!request.params[3].isNull()) { + output_type = ParseOutputType(request.params[3].get_str(), output_type); + if (output_type == OUTPUT_TYPE_NONE) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[3].get_str())); + } + } + // Construct using pay-to-script-hash: CScript inner = CreateMultisigRedeemscript(required, pubkeys); pwallet->AddCScript(inner); - CTxDestination dest = pwallet->AddAndGetDestinationForScript(inner, g_address_type); + CTxDestination dest = pwallet->AddAndGetDestinationForScript(inner, output_type); pwallet->SetAddressBook(dest, strAccount, "send"); // Return old style interface @@ -3057,6 +3065,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) " {\n" " \"changeAddress\" (string, optional, default pool address) The bitcoin address to receive the change\n" " \"changePosition\" (numeric, optional, default random) The index of the change output\n" + " \"change_type\" (string, optional) The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -changetype.\n" " \"includeWatching\" (boolean, optional, default false) Also select inputs which are watch only\n" " \"lockUnspents\" (boolean, optional, default false) Lock selected unspent outputs\n" " \"feeRate\" (numeric, optional, default not set: makes wallet determine the fee) Set a specific fee rate in " + CURRENCY_UNIT + "/kB\n" @@ -3077,7 +3086,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) " for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}\n" "3. iswitness (boolean, optional) Whether the transaction hex is a serialized witness transaction \n" " If iswitness is not present, heuristic tests will be used in decoding\n" - + "\nResult:\n" "{\n" " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n" @@ -3122,6 +3131,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) { {"changeAddress", UniValueType(UniValue::VSTR)}, {"changePosition", UniValueType(UniValue::VNUM)}, + {"change_type", UniValueType(UniValue::VSTR)}, {"includeWatching", UniValueType(UniValue::VBOOL)}, {"lockUnspents", UniValueType(UniValue::VBOOL)}, {"reserveChangeKey", UniValueType(UniValue::VBOOL)}, // DEPRECATED (and ignored), should be removed in 0.16 or so. @@ -3146,6 +3156,16 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) if (options.exists("changePosition")) changePosition = options["changePosition"].get_int(); + if (options.exists("change_type")) { + if (options.exists("changeAddress")) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both changeAddress and address_type options"); + } + coinControl.change_type = ParseOutputType(options["change_type"].get_str(), coinControl.change_type); + if (coinControl.change_type == OUTPUT_TYPE_NONE) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str())); + } + } + if (options.exists("includeWatching")) coinControl.fAllowWatchOnly = options["includeWatching"].get_bool(); @@ -3519,7 +3539,7 @@ static const CRPCCommand commands[] = { "hidden", "resendwallettransactions", &resendwallettransactions, {} }, { "wallet", "abandontransaction", &abandontransaction, {"txid"} }, { "wallet", "abortrescan", &abortrescan, {} }, - { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","account"} }, + { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","account","address_type"} }, { "hidden", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} }, { "wallet", "backupwallet", &backupwallet, {"destination"} }, { "wallet", "bumpfee", &bumpfee, {"txid", "options"} }, diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 7fb26900e1..07a23ce249 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2674,11 +2674,11 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC return true; } -OutputType CWallet::TransactionChangeType(const std::vector<CRecipient>& vecSend) +OutputType CWallet::TransactionChangeType(OutputType change_type, const std::vector<CRecipient>& vecSend) { // If -changetype is specified, always use that change type. - if (g_change_type != OUTPUT_TYPE_NONE) { - return g_change_type; + if (change_type != OUTPUT_TYPE_NONE) { + return change_type; } // if g_address_type is legacy, use legacy address as change (even @@ -2797,7 +2797,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT return false; } - const OutputType change_type = TransactionChangeType(vecSend); + const OutputType change_type = TransactionChangeType(coin_control.change_type, vecSend); LearnRelatedScripts(vchPubKey, change_type); scriptChange = GetScriptForDestination(GetDestinationForKey(vchPubKey, change_type)); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index e8f536634e..a4684c2935 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -965,7 +965,7 @@ public: CAmount GetLegacyBalance(const isminefilter& filter, int minDepth, const std::string* account) const; CAmount GetAvailableBalance(const CCoinControl* coinControl = nullptr) const; - OutputType TransactionChangeType(const std::vector<CRecipient>& vecSend); + OutputType TransactionChangeType(OutputType change_type, const std::vector<CRecipient>& vecSend); /** * Insert additional inputs into the transaction by diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py index b3d6549229..5f7a0586e0 100755 --- a/test/functional/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -212,6 +212,19 @@ class RawTransactionsTest(BitcoinTestFramework): out = dec_tx['vout'][0] assert_equal(change, out['scriptPubKey']['addresses'][0]) + ######################################################### + # test a fundrawtransaction with a provided change type # + ######################################################### + utx = get_unspent(self.nodes[2].listunspent(), 5) + + inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ] + outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[2].fundrawtransaction, rawtx, {'change_type': None}) + assert_raises_rpc_error(-5, "Unknown change type", self.nodes[2].fundrawtransaction, rawtx, {'change_type': ''}) + rawtx = self.nodes[2].fundrawtransaction(rawtx, {'change_type': 'bech32'}) + tx = self.nodes[2].decoderawtransaction(rawtx['hex']) + assert_equal('witness_v0_keyhash', tx['vout'][rawtx['changepos']]['scriptPubKey']['type']) ######################################################################### # test a fundrawtransaction with a VIN smaller than the required amount # diff --git a/test/functional/nulldummy.py b/test/functional/nulldummy.py index fac620bc8d..e4f413cc2a 100755 --- a/test/functional/nulldummy.py +++ b/test/functional/nulldummy.py @@ -48,7 +48,7 @@ class NULLDUMMYTest(BitcoinTestFramework): self.address = self.nodes[0].getnewaddress() self.ms_address = self.nodes[0].addmultisigaddress(1,[self.address])['address'] self.wit_address = self.nodes[0].addwitnessaddress(self.address) - self.wit_ms_address = self.nodes[0].addwitnessaddress(self.ms_address) + self.wit_ms_address = self.nodes[0].addmultisigaddress(1, [self.address], '', 'p2sh-segwit')['address'] network_thread_start() self.coinbase_blocks = self.nodes[0].generate(2) # Block 2 diff --git a/test/functional/segwit.py b/test/functional/segwit.py index 931ebdea39..ba6373fa33 100755 --- a/test/functional/segwit.py +++ b/test/functional/segwit.py @@ -95,12 +95,11 @@ class SegWitTest(BitcoinTestFramework): for i in range(3): newaddress = self.nodes[i].getnewaddress() self.pubkey.append(self.nodes[i].validateaddress(newaddress)["pubkey"]) - multiaddress = self.nodes[i].addmultisigaddress(1, [self.pubkey[-1]])['address'] multiscript = CScript([OP_1, hex_str_to_bytes(self.pubkey[-1]), OP_1, OP_CHECKMULTISIG]) p2sh_addr = self.nodes[i].addwitnessaddress(newaddress) bip173_addr = self.nodes[i].addwitnessaddress(newaddress, False) - p2sh_ms_addr = self.nodes[i].addwitnessaddress(multiaddress) - bip173_ms_addr = self.nodes[i].addwitnessaddress(multiaddress, False) + p2sh_ms_addr = self.nodes[i].addmultisigaddress(1, [self.pubkey[-1]], '', 'p2sh-segwit')['address'] + bip173_ms_addr = self.nodes[i].addmultisigaddress(1, [self.pubkey[-1]], '', 'bech32')['address'] assert_equal(p2sh_addr, key_to_p2sh_p2wpkh(self.pubkey[-1])) assert_equal(bip173_addr, key_to_p2wpkh(self.pubkey[-1])) assert_equal(p2sh_ms_addr, script_to_p2sh_p2wsh(multiscript)) |