aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/release-notes.md5
-rw-r--r--src/qt/paymentserver.cpp2
-rw-r--r--src/wallet/rpcwallet.cpp15
-rw-r--r--src/wallet/wallet.cpp28
-rw-r--r--src/wallet/wallet.h15
-rwxr-xr-xtest/functional/rpc_fundrawtransaction.py2
-rwxr-xr-xtest/functional/wallet_address_types.py5
7 files changed, 41 insertions, 31 deletions
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 99ef6b2b59..7a9a98bfec 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -104,6 +104,11 @@ Low-level RPC changes
now the empty string `""` instead of `"wallet.dat"`. If bitcoin is started
with any `-wallet=<path>` options, there is no change in behavior, and the
name of any wallet is just its `<path>` string.
+- Passing an empty string (`""`) as the `address_type` parameter to
+ `getnewaddress`, `getrawchangeaddress`, `addmultisigaddress`,
+ `fundrawtransaction` RPCs is now an error. Previously, this would fall back
+ to using the default address type. It is still possible to pass null or leave
+ the parameter unset to use the default address type.
- Bare multisig outputs to our keys are no longer automatically treated as
incoming payments. As this feature was only available for multisig outputs for
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 70cdb3361c..59bb5d5bb6 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -648,7 +648,7 @@ void PaymentServer::fetchPaymentACK(WalletModel* walletModel, const SendCoinsRec
// 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.
- const OutputType change_type = walletModel->wallet().getDefaultChangeType() != OutputType::NONE ? walletModel->wallet().getDefaultChangeType() : walletModel->wallet().getDefaultAddressType();
+ const OutputType change_type = walletModel->wallet().getDefaultChangeType() != OutputType::CHANGE_AUTO ? walletModel->wallet().getDefaultChangeType() : walletModel->wallet().getDefaultAddressType();
walletModel->wallet().learnRelatedScripts(newKey, change_type);
CTxDestination dest = GetDestinationForKey(newKey, change_type);
std::string label = tr("Refund from %1").arg(recipient.authenticatedMerchant).toStdString();
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index a82f069490..bfd9840dfc 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -164,8 +164,7 @@ UniValue getnewaddress(const JSONRPCRequest& request)
OutputType output_type = pwallet->m_default_address_type;
if (!request.params[1].isNull()) {
- output_type = ParseOutputType(request.params[1].get_str(), pwallet->m_default_address_type);
- if (output_type == OutputType::NONE) {
+ if (!ParseOutputType(request.params[1].get_str(), output_type)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[1].get_str()));
}
}
@@ -282,10 +281,9 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request)
pwallet->TopUpKeyPool();
}
- OutputType output_type = pwallet->m_default_change_type != OutputType::NONE ? pwallet->m_default_change_type : pwallet->m_default_address_type;
+ OutputType output_type = pwallet->m_default_change_type != OutputType::CHANGE_AUTO ? pwallet->m_default_change_type : pwallet->m_default_address_type;
if (!request.params[0].isNull()) {
- output_type = ParseOutputType(request.params[0].get_str(), output_type);
- if (output_type == OutputType::NONE) {
+ if (!ParseOutputType(request.params[0].get_str(), output_type)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
}
}
@@ -1317,8 +1315,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
OutputType output_type = pwallet->m_default_address_type;
if (!request.params[3].isNull()) {
- output_type = ParseOutputType(request.params[3].get_str(), output_type);
- if (output_type == OutputType::NONE) {
+ if (!ParseOutputType(request.params[3].get_str(), output_type)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[3].get_str()));
}
}
@@ -3317,8 +3314,8 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
if (options.exists("changeAddress")) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both changeAddress and address_type options");
}
- coinControl.m_change_type = ParseOutputType(options["change_type"].get_str(), pwallet->m_default_change_type);
- if (coinControl.m_change_type == OutputType::NONE) {
+ coinControl.m_change_type = pwallet->m_default_change_type;
+ if (!ParseOutputType(options["change_type"].get_str(), *coinControl.m_change_type)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str()));
}
}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index eeab05fd0f..9533e6ff56 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2674,7 +2674,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
OutputType CWallet::TransactionChangeType(OutputType change_type, const std::vector<CRecipient>& vecSend)
{
// If -changetype is specified, always use that change type.
- if (change_type != OutputType::NONE) {
+ if (change_type != OutputType::CHANGE_AUTO) {
return change_type;
}
@@ -4054,16 +4054,12 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
}
}
- walletInstance->m_default_address_type = ParseOutputType(gArgs.GetArg("-addresstype", ""), DEFAULT_ADDRESS_TYPE);
- if (walletInstance->m_default_address_type == OutputType::NONE) {
+ if (!gArgs.GetArg("-addresstype", "").empty() && !ParseOutputType(gArgs.GetArg("-addresstype", ""), walletInstance->m_default_address_type)) {
InitError(strprintf("Unknown address type '%s'", gArgs.GetArg("-addresstype", "")));
return nullptr;
}
- // If changetype is set in config file or parameter, check that it's valid.
- // Default to OutputType::NONE if not set.
- walletInstance->m_default_change_type = ParseOutputType(gArgs.GetArg("-changetype", ""), OutputType::NONE);
- if (walletInstance->m_default_change_type == OutputType::NONE && !gArgs.GetArg("-changetype", "").empty()) {
+ if (!gArgs.GetArg("-changetype", "").empty() && !ParseOutputType(gArgs.GetArg("-changetype", ""), walletInstance->m_default_change_type)) {
InitError(strprintf("Unknown change type '%s'", gArgs.GetArg("-changetype", "")));
return nullptr;
}
@@ -4311,19 +4307,19 @@ static const std::string OUTPUT_TYPE_STRING_LEGACY = "legacy";
static const std::string OUTPUT_TYPE_STRING_P2SH_SEGWIT = "p2sh-segwit";
static const std::string OUTPUT_TYPE_STRING_BECH32 = "bech32";
-OutputType ParseOutputType(const std::string& type, OutputType default_type)
+bool ParseOutputType(const std::string& type, OutputType& output_type)
{
- if (type.empty()) {
- return default_type;
- } else if (type == OUTPUT_TYPE_STRING_LEGACY) {
- return OutputType::LEGACY;
+ if (type == OUTPUT_TYPE_STRING_LEGACY) {
+ output_type = OutputType::LEGACY;
+ return true;
} else if (type == OUTPUT_TYPE_STRING_P2SH_SEGWIT) {
- return OutputType::P2SH_SEGWIT;
+ output_type = OutputType::P2SH_SEGWIT;
+ return true;
} else if (type == OUTPUT_TYPE_STRING_BECH32) {
- return OutputType::BECH32;
- } else {
- return OutputType::NONE;
+ output_type = OutputType::BECH32;
+ return true;
}
+ return false;
}
const std::string& FormatOutputType(OutputType type)
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index d24ae1186f..3208a20f0f 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -93,15 +93,24 @@ enum WalletFeature
};
enum class OutputType {
- NONE,
LEGACY,
P2SH_SEGWIT,
BECH32,
+
+ /**
+ * Special output type for change outputs only. Automatically choose type
+ * based on address type setting and the types other of non-change outputs
+ * (see -changetype option documentation and implementation in
+ * CWallet::TransactionChangeType for details).
+ */
+ CHANGE_AUTO,
};
//! Default for -addresstype
constexpr OutputType DEFAULT_ADDRESS_TYPE{OutputType::P2SH_SEGWIT};
+//! Default for -changetype
+constexpr OutputType DEFAULT_CHANGE_TYPE{OutputType::CHANGE_AUTO};
/** A key pool entry */
class CKeyPool
@@ -973,7 +982,7 @@ public:
CFeeRate m_fallback_fee{DEFAULT_FALLBACK_FEE};
CFeeRate m_discard_rate{DEFAULT_DISCARD_FEE};
OutputType m_default_address_type{DEFAULT_ADDRESS_TYPE};
- OutputType m_default_change_type{OutputType::NONE}; // Default to OutputType::NONE if not set by -changetype
+ OutputType m_default_change_type{DEFAULT_CHANGE_TYPE};
bool NewKeyPool();
size_t KeypoolCountExternalKeys();
@@ -1218,7 +1227,7 @@ public:
}
};
-OutputType ParseOutputType(const std::string& str, OutputType default_type);
+bool ParseOutputType(const std::string& str, OutputType& output_type);
const std::string& FormatOutputType(OutputType type);
/**
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index 5fb9a361d9..0f09c3c552 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/rpc_fundrawtransaction.py
@@ -224,7 +224,7 @@ class RawTransactionsTest(BitcoinTestFramework):
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': ''})
+ assert_raises_rpc_error(-5, "Unknown change type ''", self.nodes[2].fundrawtransaction, rawtx, {'change_type': ''})
rawtx = self.nodes[2].fundrawtransaction(rawtx, {'change_type': 'bech32'})
dec_tx = self.nodes[2].decoderawtransaction(rawtx['hex'])
assert_equal('witness_v0_keyhash', dec_tx['vout'][rawtx['changepos']]['scriptPubKey']['type'])
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index 5d2428e6ef..7658d78383 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -280,7 +280,10 @@ class AddressTypeTest(BitcoinTestFramework):
self.log.info('getrawchangeaddress defaults to addresstype if -changetype is not set and argument is absent')
self.test_address(3, self.nodes[3].getrawchangeaddress(), multisig=False, typ='bech32')
- self.log.info('getrawchangeaddress fails with invalid changetype argument')
+ self.log.info('test invalid address type arguments')
+ assert_raises_rpc_error(-5, "Unknown address type ''", self.nodes[3].addmultisigaddress, 2, [compressed_1, compressed_2], None, '')
+ assert_raises_rpc_error(-5, "Unknown address type ''", self.nodes[3].getnewaddress, None, '')
+ assert_raises_rpc_error(-5, "Unknown address type ''", self.nodes[3].getrawchangeaddress, '')
assert_raises_rpc_error(-5, "Unknown address type 'bech23'", self.nodes[3].getrawchangeaddress, 'bech23')
self.log.info("Nodes with changetype=p2sh-segwit never use a P2WPKH change output")