diff options
author | Sjors Provoost <sjors@sprovoost.nl> | 2018-01-23 17:56:15 +0100 |
---|---|---|
committer | Sjors Provoost <sjors@sprovoost.nl> | 2018-01-23 17:56:15 +0100 |
commit | 596c44633fd03e76cc12f2fd37452e223ba43115 (patch) | |
tree | 44646cccab6cd1dd47b1a4036d6260d517d066cd /src | |
parent | 44080a90a29292df96e92f22242785c5040000a1 (diff) |
[wallet] use P2WPKH change output if any destination is P2WPKH or P2WSH
Only if -changetype is not set and -addresstype is not "legacy".
Diffstat (limited to 'src')
-rw-r--r-- | src/qt/paymentserver.cpp | 5 | ||||
-rw-r--r-- | src/wallet/init.cpp | 8 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 4 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 34 | ||||
-rw-r--r-- | src/wallet/wallet.h | 2 |
5 files changed, 44 insertions, 9 deletions
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index dc729649b8..bc69d4f945 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -643,8 +643,9 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, const SendCoinsRecipient& r // use for change. Despite an actual payment and not change, this is a close match: // it's the output type we use subject to privacy issues, but not restricted by what // other software supports. - wallet->LearnRelatedScripts(newKey, g_change_type); - CTxDestination dest = GetDestinationForKey(newKey, g_change_type); + const OutputType change_type = g_change_type != OUTPUT_TYPE_NONE ? g_change_type : g_address_type; + wallet->LearnRelatedScripts(newKey, change_type); + CTxDestination dest = GetDestinationForKey(newKey, change_type); wallet->SetAddressBook(dest, strAccount, "refund"); CScript s = GetScriptForDestination(dest); diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 0f453f154f..7d61d708a1 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -17,7 +17,7 @@ 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)")); + 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)"), @@ -182,8 +182,10 @@ bool WalletParameterInteraction() return InitError(strprintf(_("Unknown address type '%s'"), gArgs.GetArg("-addresstype", ""))); } - g_change_type = ParseOutputType(gArgs.GetArg("-changetype", ""), g_address_type); - if (g_change_type == OUTPUT_TYPE_NONE) { + // 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", ""))); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index e307623fd5..59653721c3 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -256,9 +256,9 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request) pwallet->TopUpKeyPool(); } - OutputType output_type = g_change_type; + OutputType output_type = g_change_type != OUTPUT_TYPE_NONE ? g_change_type : g_address_type; if (!request.params[0].isNull()) { - output_type = ParseOutputType(request.params[0].get_str(), g_change_type); + output_type = ParseOutputType(request.params[0].get_str(), output_type); if (output_type == OUTPUT_TYPE_NONE) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str())); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index da721ea008..c804338952 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2644,6 +2644,34 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC return true; } +OutputType CWallet::TransactionChangeType(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 g_address_type is legacy, use legacy address as change (even + // if some of the outputs are P2WPKH or P2WSH). + if (g_address_type == OUTPUT_TYPE_LEGACY) { + return OUTPUT_TYPE_LEGACY; + } + + // if any destination is P2WPKH or P2WSH, use P2WPKH for the change + // output. + for (const auto& recipient : vecSend) { + // Check if any destination contains a witness program: + int witnessversion = 0; + std::vector<unsigned char> witnessprogram; + if (recipient.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) { + return OUTPUT_TYPE_BECH32; + } + } + + // else use g_address_type for change + return g_address_type; +} + bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign) { @@ -2739,8 +2767,10 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT return false; } - LearnRelatedScripts(vchPubKey, g_change_type); - scriptChange = GetScriptForDestination(GetDestinationForKey(vchPubKey, g_change_type)); + const OutputType change_type = TransactionChangeType(vecSend); + + LearnRelatedScripts(vchPubKey, change_type); + scriptChange = GetScriptForDestination(GetDestinationForKey(vchPubKey, change_type)); } CTxOut change_prototype_txout(0, scriptChange); size_t change_prototype_size = GetSerializeSize(change_prototype_txout, SER_DISK, 0); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 53a2c6b9d5..cc350853ea 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -961,6 +961,8 @@ 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); + /** * Insert additional inputs into the transaction by * calling CreateTransaction(); |