wallet, rpc: Remove watchonly from RPCs
Descriptor wallets don't have a conception of watchonly within a wallet, so remove all of these options and results from the RPCs
This commit is contained in:
1 parent
e81d95d435
commit
1337c72198
14 files changed
+135
-242
No files matched your search
@@ -380,7 +380,7 @@ RPCHelpMan getaddressinfo()
|
|||||||
{RPCResult::Type::STR, "address", "The bitcoin address validated."},
|
{RPCResult::Type::STR, "address", "The bitcoin address validated."},
|
||||||
{RPCResult::Type::STR_HEX, "scriptPubKey", "The hex-encoded output script generated by the address."},
|
{RPCResult::Type::STR_HEX, "scriptPubKey", "The hex-encoded output script generated by the address."},
|
||||||
{RPCResult::Type::BOOL, "ismine", "If the address is yours."},
|
{RPCResult::Type::BOOL, "ismine", "If the address is yours."},
|
||||||
{RPCResult::Type::BOOL, "iswatchonly", "If the address is watchonly."},
|
{RPCResult::Type::BOOL, "iswatchonly", "(DEPRECATED) Always false."},
|
||||||
{RPCResult::Type::BOOL, "solvable", "If we know how to spend coins sent to this address, ignoring the possible lack of private keys."},
|
{RPCResult::Type::BOOL, "solvable", "If we know how to spend coins sent to this address, ignoring the possible lack of private keys."},
|
||||||
{RPCResult::Type::STR, "desc", /*optional=*/true, "A descriptor for spending coins sent to this address (only when solvable)."},
|
{RPCResult::Type::STR, "desc", /*optional=*/true, "A descriptor for spending coins sent to this address (only when solvable)."},
|
||||||
{RPCResult::Type::STR, "parent_desc", /*optional=*/true, "The descriptor used to derive this address if this is a descriptor wallet"},
|
{RPCResult::Type::STR, "parent_desc", /*optional=*/true, "The descriptor used to derive this address if this is a descriptor wallet"},
|
||||||
@@ -402,7 +402,7 @@ RPCHelpMan getaddressinfo()
|
|||||||
{RPCResult::Type::OBJ, "embedded", /*optional=*/true, "Information about the address embedded in P2SH or P2WSH, if relevant and known.",
|
{RPCResult::Type::OBJ, "embedded", /*optional=*/true, "Information about the address embedded in P2SH or P2WSH, if relevant and known.",
|
||||||
{
|
{
|
||||||
{RPCResult::Type::ELISION, "", "Includes all getaddressinfo output fields for the embedded address, excluding metadata (timestamp, hdkeypath, hdseedid)\n"
|
{RPCResult::Type::ELISION, "", "Includes all getaddressinfo output fields for the embedded address, excluding metadata (timestamp, hdkeypath, hdseedid)\n"
|
||||||
"and relation to the wallet (ismine, iswatchonly)."},
|
"and relation to the wallet (ismine)."},
|
||||||
}},
|
}},
|
||||||
{RPCResult::Type::BOOL, "iscompressed", /*optional=*/true, "If the pubkey is compressed."},
|
{RPCResult::Type::BOOL, "iscompressed", /*optional=*/true, "If the pubkey is compressed."},
|
||||||
{RPCResult::Type::NUM_TIME, "timestamp", /*optional=*/true, "The creation time of the key, if available, expressed in " + UNIX_EPOCH_TIME + "."},
|
{RPCResult::Type::NUM_TIME, "timestamp", /*optional=*/true, "The creation time of the key, if available, expressed in " + UNIX_EPOCH_TIME + "."},
|
||||||
@@ -475,7 +475,7 @@ RPCHelpMan getaddressinfo()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY));
|
ret.pushKV("iswatchonly", false);
|
||||||
|
|
||||||
UniValue detail = DescribeWalletAddress(*pwallet, dest);
|
UniValue detail = DescribeWalletAddress(*pwallet, dest);
|
||||||
ret.pushKVs(std::move(detail));
|
ret.pushKVs(std::move(detail));
|
||||||
|
|||||||
+103
-123
@@ -146,9 +146,6 @@ static void PreventOutdatedOptions(const UniValue& options)
|
|||||||
if (options.exists("changePosition")) {
|
if (options.exists("changePosition")) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Use change_position instead of changePosition");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Use change_position instead of changePosition");
|
||||||
}
|
}
|
||||||
if (options.exists("includeWatching")) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Use include_watching instead of includeWatching");
|
|
||||||
}
|
|
||||||
if (options.exists("lockUnspents")) {
|
if (options.exists("lockUnspents")) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Use lock_unspents instead of lockUnspents");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Use lock_unspents instead of lockUnspents");
|
||||||
}
|
}
|
||||||
@@ -516,126 +513,118 @@ CreatedTransactionResult FundTransaction(CWallet& wallet, const CMutableTransact
|
|||||||
std::optional<unsigned int> change_position;
|
std::optional<unsigned int> change_position;
|
||||||
bool lockUnspents = false;
|
bool lockUnspents = false;
|
||||||
if (!options.isNull()) {
|
if (!options.isNull()) {
|
||||||
if (options.type() == UniValue::VBOOL) {
|
if (options.type() == UniValue::VBOOL) {
|
||||||
// backward compatibility bool only fallback
|
// backward compatibility bool only fallback, does nothing
|
||||||
coinControl.fAllowWatchOnly = options.get_bool();
|
} else {
|
||||||
}
|
RPCTypeCheckObj(options,
|
||||||
else {
|
{
|
||||||
RPCTypeCheckObj(options,
|
{"add_inputs", UniValueType(UniValue::VBOOL)},
|
||||||
{
|
{"include_unsafe", UniValueType(UniValue::VBOOL)},
|
||||||
{"add_inputs", UniValueType(UniValue::VBOOL)},
|
{"add_to_wallet", UniValueType(UniValue::VBOOL)},
|
||||||
{"include_unsafe", UniValueType(UniValue::VBOOL)},
|
{"changeAddress", UniValueType(UniValue::VSTR)},
|
||||||
{"add_to_wallet", UniValueType(UniValue::VBOOL)},
|
{"change_address", UniValueType(UniValue::VSTR)},
|
||||||
{"changeAddress", UniValueType(UniValue::VSTR)},
|
{"changePosition", UniValueType(UniValue::VNUM)},
|
||||||
{"change_address", UniValueType(UniValue::VSTR)},
|
{"change_position", UniValueType(UniValue::VNUM)},
|
||||||
{"changePosition", UniValueType(UniValue::VNUM)},
|
{"change_type", UniValueType(UniValue::VSTR)},
|
||||||
{"change_position", UniValueType(UniValue::VNUM)},
|
{"includeWatching", UniValueType(UniValue::VBOOL)},
|
||||||
{"change_type", UniValueType(UniValue::VSTR)},
|
{"include_watching", UniValueType(UniValue::VBOOL)},
|
||||||
{"includeWatching", UniValueType(UniValue::VBOOL)},
|
{"inputs", UniValueType(UniValue::VARR)},
|
||||||
{"include_watching", UniValueType(UniValue::VBOOL)},
|
{"lockUnspents", UniValueType(UniValue::VBOOL)},
|
||||||
{"inputs", UniValueType(UniValue::VARR)},
|
{"lock_unspents", UniValueType(UniValue::VBOOL)},
|
||||||
{"lockUnspents", UniValueType(UniValue::VBOOL)},
|
{"locktime", UniValueType(UniValue::VNUM)},
|
||||||
{"lock_unspents", UniValueType(UniValue::VBOOL)},
|
{"fee_rate", UniValueType()}, // will be checked by AmountFromValue() in SetFeeEstimateMode()
|
||||||
{"locktime", UniValueType(UniValue::VNUM)},
|
{"feeRate", UniValueType()}, // will be checked by AmountFromValue() below
|
||||||
{"fee_rate", UniValueType()}, // will be checked by AmountFromValue() in SetFeeEstimateMode()
|
{"psbt", UniValueType(UniValue::VBOOL)},
|
||||||
{"feeRate", UniValueType()}, // will be checked by AmountFromValue() below
|
{"solving_data", UniValueType(UniValue::VOBJ)},
|
||||||
{"psbt", UniValueType(UniValue::VBOOL)},
|
{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
|
||||||
{"solving_data", UniValueType(UniValue::VOBJ)},
|
{"subtract_fee_from_outputs", UniValueType(UniValue::VARR)},
|
||||||
{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
|
{"replaceable", UniValueType(UniValue::VBOOL)},
|
||||||
{"subtract_fee_from_outputs", UniValueType(UniValue::VARR)},
|
{"conf_target", UniValueType(UniValue::VNUM)},
|
||||||
{"replaceable", UniValueType(UniValue::VBOOL)},
|
{"estimate_mode", UniValueType(UniValue::VSTR)},
|
||||||
{"conf_target", UniValueType(UniValue::VNUM)},
|
{"minconf", UniValueType(UniValue::VNUM)},
|
||||||
{"estimate_mode", UniValueType(UniValue::VSTR)},
|
{"maxconf", UniValueType(UniValue::VNUM)},
|
||||||
{"minconf", UniValueType(UniValue::VNUM)},
|
{"input_weights", UniValueType(UniValue::VARR)},
|
||||||
{"maxconf", UniValueType(UniValue::VNUM)},
|
{"max_tx_weight", UniValueType(UniValue::VNUM)},
|
||||||
{"input_weights", UniValueType(UniValue::VARR)},
|
},
|
||||||
{"max_tx_weight", UniValueType(UniValue::VNUM)},
|
true, true);
|
||||||
},
|
|
||||||
true, true);
|
|
||||||
|
|
||||||
if (options.exists("add_inputs")) {
|
if (options.exists("add_inputs")) {
|
||||||
coinControl.m_allow_other_inputs = options["add_inputs"].get_bool();
|
coinControl.m_allow_other_inputs = options["add_inputs"].get_bool();
|
||||||
}
|
|
||||||
|
|
||||||
if (options.exists("changeAddress") || options.exists("change_address")) {
|
|
||||||
const std::string change_address_str = (options.exists("change_address") ? options["change_address"] : options["changeAddress"]).get_str();
|
|
||||||
CTxDestination dest = DecodeDestination(change_address_str);
|
|
||||||
|
|
||||||
if (!IsValidDestination(dest)) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Change address must be a valid bitcoin address");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
coinControl.destChange = dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.exists("changePosition") || options.exists("change_position")) {
|
|
||||||
int pos = (options.exists("change_position") ? options["change_position"] : options["changePosition"]).getInt<int>();
|
|
||||||
if (pos < 0 || (unsigned int)pos > recipients.size()) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds");
|
|
||||||
}
|
|
||||||
change_position = (unsigned int)pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.exists("change_type")) {
|
|
||||||
if (options.exists("changeAddress") || options.exists("change_address")) {
|
if (options.exists("changeAddress") || options.exists("change_address")) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both change address and address type options");
|
const std::string change_address_str = (options.exists("change_address") ? options["change_address"] : options["changeAddress"]).get_str();
|
||||||
|
CTxDestination dest = DecodeDestination(change_address_str);
|
||||||
|
|
||||||
|
if (!IsValidDestination(dest)) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Change address must be a valid bitcoin address");
|
||||||
|
}
|
||||||
|
|
||||||
|
coinControl.destChange = dest;
|
||||||
}
|
}
|
||||||
if (std::optional<OutputType> parsed = ParseOutputType(options["change_type"].get_str())) {
|
|
||||||
coinControl.m_change_type.emplace(parsed.value());
|
if (options.exists("changePosition") || options.exists("change_position")) {
|
||||||
} else {
|
int pos = (options.exists("change_position") ? options["change_position"] : options["changePosition"]).getInt<int>();
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str()));
|
if (pos < 0 || (unsigned int)pos > recipients.size()) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds");
|
||||||
|
}
|
||||||
|
change_position = (unsigned int)pos;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const UniValue include_watching_option = options.exists("include_watching") ? options["include_watching"] : options["includeWatching"];
|
if (options.exists("change_type")) {
|
||||||
coinControl.fAllowWatchOnly = ParseIncludeWatchonly(include_watching_option, wallet);
|
if (options.exists("changeAddress") || options.exists("change_address")) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both change address and address type options");
|
||||||
if (options.exists("lockUnspents") || options.exists("lock_unspents")) {
|
}
|
||||||
lockUnspents = (options.exists("lock_unspents") ? options["lock_unspents"] : options["lockUnspents"]).get_bool();
|
if (std::optional<OutputType> parsed = ParseOutputType(options["change_type"].get_str())) {
|
||||||
}
|
coinControl.m_change_type.emplace(parsed.value());
|
||||||
|
} else {
|
||||||
if (options.exists("include_unsafe")) {
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str()));
|
||||||
coinControl.m_include_unsafe_inputs = options["include_unsafe"].get_bool();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (options.exists("feeRate")) {
|
|
||||||
if (options.exists("fee_rate")) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both fee_rate (" + CURRENCY_ATOM + "/vB) and feeRate (" + CURRENCY_UNIT + "/kvB)");
|
|
||||||
}
|
}
|
||||||
if (options.exists("conf_target")) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and feeRate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");
|
if (options.exists("lockUnspents") || options.exists("lock_unspents")) {
|
||||||
|
lockUnspents = (options.exists("lock_unspents") ? options["lock_unspents"] : options["lockUnspents"]).get_bool();
|
||||||
}
|
}
|
||||||
if (options.exists("estimate_mode")) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and feeRate");
|
if (options.exists("include_unsafe")) {
|
||||||
|
coinControl.m_include_unsafe_inputs = options["include_unsafe"].get_bool();
|
||||||
}
|
}
|
||||||
coinControl.m_feerate = CFeeRate(AmountFromValue(options["feeRate"]));
|
|
||||||
coinControl.fOverrideFeeRate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.exists("replaceable")) {
|
if (options.exists("feeRate")) {
|
||||||
coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool();
|
if (options.exists("fee_rate")) {
|
||||||
}
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both fee_rate (" + CURRENCY_ATOM + "/vB) and feeRate (" + CURRENCY_UNIT + "/kvB)");
|
||||||
|
}
|
||||||
if (options.exists("minconf")) {
|
if (options.exists("conf_target")) {
|
||||||
coinControl.m_min_depth = options["minconf"].getInt<int>();
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and feeRate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");
|
||||||
|
}
|
||||||
if (coinControl.m_min_depth < 0) {
|
if (options.exists("estimate_mode")) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative minconf");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and feeRate");
|
||||||
|
}
|
||||||
|
coinControl.m_feerate = CFeeRate(AmountFromValue(options["feeRate"]));
|
||||||
|
coinControl.fOverrideFeeRate = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (options.exists("maxconf")) {
|
if (options.exists("replaceable")) {
|
||||||
coinControl.m_max_depth = options["maxconf"].getInt<int>();
|
coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool();
|
||||||
|
|
||||||
if (coinControl.m_max_depth < coinControl.m_min_depth) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("maxconf can't be lower than minconf: %d < %d", coinControl.m_max_depth, coinControl.m_min_depth));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.exists("minconf")) {
|
||||||
|
coinControl.m_min_depth = options["minconf"].getInt<int>();
|
||||||
|
|
||||||
|
if (coinControl.m_min_depth < 0) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative minconf");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.exists("maxconf")) {
|
||||||
|
coinControl.m_max_depth = options["maxconf"].getInt<int>();
|
||||||
|
|
||||||
|
if (coinControl.m_max_depth < coinControl.m_min_depth) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("maxconf can't be lower than minconf: %d < %d", coinControl.m_max_depth, coinControl.m_min_depth));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetFeeEstimateMode(wallet, coinControl, options["conf_target"], options["estimate_mode"], options["fee_rate"], override_min_fee);
|
||||||
}
|
}
|
||||||
SetFeeEstimateMode(wallet, coinControl, options["conf_target"], options["estimate_mode"], options["fee_rate"], override_min_fee);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if options is null and not a bool
|
|
||||||
coinControl.fAllowWatchOnly = ParseIncludeWatchonly(NullUniValue, wallet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.exists("solving_data")) {
|
if (options.exists("solving_data")) {
|
||||||
@@ -757,13 +746,12 @@ RPCHelpMan fundrawtransaction()
|
|||||||
"Note that all inputs selected must be of standard form and P2SH scripts must be\n"
|
"Note that all inputs selected must be of standard form and P2SH scripts must be\n"
|
||||||
"in the wallet using importdescriptors (to calculate fees).\n"
|
"in the wallet using importdescriptors (to calculate fees).\n"
|
||||||
"You can see whether this is the case by checking the \"solvable\" field in the listunspent output.\n"
|
"You can see whether this is the case by checking the \"solvable\" field in the listunspent output.\n"
|
||||||
"Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only.\n"
|
|
||||||
"Note that if specifying an exact fee rate, the resulting transaction may have a higher fee rate\n"
|
"Note that if specifying an exact fee rate, the resulting transaction may have a higher fee rate\n"
|
||||||
"if the transaction has unconfirmed inputs. This is because the wallet will attempt to make the\n"
|
"if the transaction has unconfirmed inputs. This is because the wallet will attempt to make the\n"
|
||||||
"entire package have the given fee rate, not the resulting transaction.\n",
|
"entire package have the given fee rate, not the resulting transaction.\n",
|
||||||
{
|
{
|
||||||
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
|
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
|
||||||
{"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "For backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
|
{"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
|
||||||
Cat<std::vector<RPCArg>>(
|
Cat<std::vector<RPCArg>>(
|
||||||
{
|
{
|
||||||
{"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{true}, "For a transaction with existing inputs, automatically include more if they are not enough."},
|
{"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{true}, "For a transaction with existing inputs, automatically include more if they are not enough."},
|
||||||
@@ -775,9 +763,7 @@ RPCHelpMan fundrawtransaction()
|
|||||||
{"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"},
|
{"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"},
|
||||||
{"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
|
{"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
|
||||||
{"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
|
{"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
|
||||||
{"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
|
{"includeWatching", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
|
||||||
"Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
|
|
||||||
"e.g. with 'importdescriptors'."},
|
|
||||||
{"lockUnspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
|
{"lockUnspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
|
||||||
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
|
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
|
||||||
{"feeRate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."},
|
{"feeRate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."},
|
||||||
@@ -1240,9 +1226,7 @@ RPCHelpMan send()
|
|||||||
{"change_position", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
|
{"change_position", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
|
||||||
{"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\" and \"bech32m\"."},
|
{"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\" and \"bech32m\"."},
|
||||||
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB.", RPCArgOptions{.also_positional = true}},
|
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB.", RPCArgOptions{.also_positional = true}},
|
||||||
{"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
|
{"include_watching", RPCArg::Type::BOOL, RPCArg::Default{"false"}, "(DEPRECATED) No longer used"},
|
||||||
"Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
|
|
||||||
"e.g. with 'importdescriptors'."},
|
|
||||||
{"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Specify inputs instead of adding them automatically.",
|
{"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Specify inputs instead of adding them automatically.",
|
||||||
{
|
{
|
||||||
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", {
|
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", {
|
||||||
@@ -1360,9 +1344,7 @@ RPCHelpMan sendall()
|
|||||||
{
|
{
|
||||||
{"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns the serialized transaction without broadcasting or adding it to the wallet"},
|
{"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns the serialized transaction without broadcasting or adding it to the wallet"},
|
||||||
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB.", RPCArgOptions{.also_positional = true}},
|
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB.", RPCArgOptions{.also_positional = true}},
|
||||||
{"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch-only.\n"
|
{"include_watching", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
|
||||||
"Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
|
|
||||||
"e.g. with 'importdescriptors'."},
|
|
||||||
{"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Use exactly the specified inputs to build the transaction. Specifying inputs is incompatible with the send_max, minconf, and maxconf options.",
|
{"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Use exactly the specified inputs to build the transaction. Specifying inputs is incompatible with the send_max, minconf, and maxconf options.",
|
||||||
{
|
{
|
||||||
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
|
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
|
||||||
@@ -1443,8 +1425,6 @@ RPCHelpMan sendall()
|
|||||||
|
|
||||||
SetFeeEstimateMode(*pwallet, coin_control, options["conf_target"], options["estimate_mode"], options["fee_rate"], /*override_min_fee=*/false);
|
SetFeeEstimateMode(*pwallet, coin_control, options["conf_target"], options["estimate_mode"], options["fee_rate"], /*override_min_fee=*/false);
|
||||||
|
|
||||||
coin_control.fAllowWatchOnly = ParseIncludeWatchonly(options["include_watching"], *pwallet);
|
|
||||||
|
|
||||||
if (options.exists("minconf")) {
|
if (options.exists("minconf")) {
|
||||||
if (options["minconf"].getInt<int>() < 0)
|
if (options["minconf"].getInt<int>() < 0)
|
||||||
{
|
{
|
||||||
@@ -1491,7 +1471,7 @@ RPCHelpMan sendall()
|
|||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input not available. UTXO (%s:%d) was already spent.", input.prevout.hash.ToString(), input.prevout.n));
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input not available. UTXO (%s:%d) was already spent.", input.prevout.hash.ToString(), input.prevout.n));
|
||||||
}
|
}
|
||||||
const CWalletTx* tx{pwallet->GetWalletTx(input.prevout.hash)};
|
const CWalletTx* tx{pwallet->GetWalletTx(input.prevout.hash)};
|
||||||
if (!tx || input.prevout.n >= tx->tx->vout.size() || !(pwallet->IsMine(tx->tx->vout[input.prevout.n]) & (coin_control.fAllowWatchOnly ? ISMINE_ALL : ISMINE_SPENDABLE))) {
|
if (!tx || input.prevout.n >= tx->tx->vout.size() || !(pwallet->IsMine(tx->tx->vout[input.prevout.n]) & ISMINE_SPENDABLE)) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input not found. UTXO (%s:%d) is not part of wallet.", input.prevout.hash.ToString(), input.prevout.n));
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input not found. UTXO (%s:%d) is not part of wallet.", input.prevout.hash.ToString(), input.prevout.n));
|
||||||
}
|
}
|
||||||
total_input_value += tx->tx->vout[input.prevout.n].nValue;
|
total_input_value += tx->tx->vout[input.prevout.n].nValue;
|
||||||
@@ -1720,7 +1700,7 @@ RPCHelpMan walletcreatefundedpsbt()
|
|||||||
{"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"},
|
{"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"},
|
||||||
{"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
|
{"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
|
||||||
{"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
|
{"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
|
||||||
{"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only"},
|
{"includeWatching", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
|
||||||
{"lockUnspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
|
{"lockUnspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
|
||||||
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
|
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
|
||||||
{"feeRate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."},
|
{"feeRate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."},
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ struct tallyitem
|
|||||||
CAmount nAmount{0};
|
CAmount nAmount{0};
|
||||||
int nConf{std::numeric_limits<int>::max()};
|
int nConf{std::numeric_limits<int>::max()};
|
||||||
std::vector<Txid> txids;
|
std::vector<Txid> txids;
|
||||||
bool fIsWatchonly{false};
|
|
||||||
tallyitem() = default;
|
tallyitem() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -86,10 +85,6 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, cons
|
|||||||
|
|
||||||
isminefilter filter = ISMINE_SPENDABLE;
|
isminefilter filter = ISMINE_SPENDABLE;
|
||||||
|
|
||||||
if (ParseIncludeWatchonly(params[2], wallet)) {
|
|
||||||
filter |= ISMINE_WATCH_ONLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<CTxDestination> filtered_address{std::nullopt};
|
std::optional<CTxDestination> filtered_address{std::nullopt};
|
||||||
if (!by_label && !params[3].isNull() && !params[3].get_str().empty()) {
|
if (!by_label && !params[3].isNull() && !params[3].get_str().empty()) {
|
||||||
if (!IsValidDestinationString(params[3].get_str())) {
|
if (!IsValidDestinationString(params[3].get_str())) {
|
||||||
@@ -129,8 +124,6 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, cons
|
|||||||
item.nAmount += txout.nValue;
|
item.nAmount += txout.nValue;
|
||||||
item.nConf = std::min(item.nConf, nDepth);
|
item.nConf = std::min(item.nConf, nDepth);
|
||||||
item.txids.push_back(wtx.GetHash());
|
item.txids.push_back(wtx.GetHash());
|
||||||
if (mine & ISMINE_WATCH_ONLY)
|
|
||||||
item.fIsWatchonly = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,21 +140,17 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, cons
|
|||||||
|
|
||||||
CAmount nAmount = 0;
|
CAmount nAmount = 0;
|
||||||
int nConf = std::numeric_limits<int>::max();
|
int nConf = std::numeric_limits<int>::max();
|
||||||
bool fIsWatchonly = false;
|
|
||||||
if (it != mapTally.end()) {
|
if (it != mapTally.end()) {
|
||||||
nAmount = (*it).second.nAmount;
|
nAmount = (*it).second.nAmount;
|
||||||
nConf = (*it).second.nConf;
|
nConf = (*it).second.nConf;
|
||||||
fIsWatchonly = (*it).second.fIsWatchonly;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (by_label) {
|
if (by_label) {
|
||||||
tallyitem& _item = label_tally[label];
|
tallyitem& _item = label_tally[label];
|
||||||
_item.nAmount += nAmount;
|
_item.nAmount += nAmount;
|
||||||
_item.nConf = std::min(_item.nConf, nConf);
|
_item.nConf = std::min(_item.nConf, nConf);
|
||||||
_item.fIsWatchonly = fIsWatchonly;
|
|
||||||
} else {
|
} else {
|
||||||
UniValue obj(UniValue::VOBJ);
|
UniValue obj(UniValue::VOBJ);
|
||||||
if (fIsWatchonly) obj.pushKV("involvesWatchonly", true);
|
|
||||||
obj.pushKV("address", EncodeDestination(address));
|
obj.pushKV("address", EncodeDestination(address));
|
||||||
obj.pushKV("amount", ValueFromAmount(nAmount));
|
obj.pushKV("amount", ValueFromAmount(nAmount));
|
||||||
obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
|
obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
|
||||||
@@ -190,8 +179,6 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, cons
|
|||||||
CAmount nAmount = entry.second.nAmount;
|
CAmount nAmount = entry.second.nAmount;
|
||||||
int nConf = entry.second.nConf;
|
int nConf = entry.second.nConf;
|
||||||
UniValue obj(UniValue::VOBJ);
|
UniValue obj(UniValue::VOBJ);
|
||||||
if (entry.second.fIsWatchonly)
|
|
||||||
obj.pushKV("involvesWatchonly", true);
|
|
||||||
obj.pushKV("amount", ValueFromAmount(nAmount));
|
obj.pushKV("amount", ValueFromAmount(nAmount));
|
||||||
obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
|
obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
|
||||||
obj.pushKV("label", entry.first);
|
obj.pushKV("label", entry.first);
|
||||||
@@ -210,7 +197,7 @@ RPCHelpMan listreceivedbyaddress()
|
|||||||
{
|
{
|
||||||
{"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."},
|
{"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."},
|
||||||
{"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include addresses that haven't received any payments."},
|
{"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include addresses that haven't received any payments."},
|
||||||
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see 'importaddress')"},
|
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
|
||||||
{"address_filter", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "If present and non-empty, only return information on this address."},
|
{"address_filter", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "If present and non-empty, only return information on this address."},
|
||||||
{"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."},
|
{"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."},
|
||||||
},
|
},
|
||||||
@@ -219,7 +206,6 @@ RPCHelpMan listreceivedbyaddress()
|
|||||||
{
|
{
|
||||||
{RPCResult::Type::OBJ, "", "",
|
{RPCResult::Type::OBJ, "", "",
|
||||||
{
|
{
|
||||||
{RPCResult::Type::BOOL, "involvesWatchonly", /*optional=*/true, "Only returns true if imported addresses were involved in transaction"},
|
|
||||||
{RPCResult::Type::STR, "address", "The receiving address"},
|
{RPCResult::Type::STR, "address", "The receiving address"},
|
||||||
{RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received by the address"},
|
{RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received by the address"},
|
||||||
{RPCResult::Type::NUM, "confirmations", "The number of confirmations of the most recent transaction included"},
|
{RPCResult::Type::NUM, "confirmations", "The number of confirmations of the most recent transaction included"},
|
||||||
@@ -264,7 +250,7 @@ RPCHelpMan listreceivedbylabel()
|
|||||||
{
|
{
|
||||||
{"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."},
|
{"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."},
|
||||||
{"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include labels that haven't received any payments."},
|
{"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include labels that haven't received any payments."},
|
||||||
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see 'importaddress')"},
|
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
|
||||||
{"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."},
|
{"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."},
|
||||||
},
|
},
|
||||||
RPCResult{
|
RPCResult{
|
||||||
@@ -272,7 +258,6 @@ RPCHelpMan listreceivedbylabel()
|
|||||||
{
|
{
|
||||||
{RPCResult::Type::OBJ, "", "",
|
{RPCResult::Type::OBJ, "", "",
|
||||||
{
|
{
|
||||||
{RPCResult::Type::BOOL, "involvesWatchonly", /*optional=*/true, "Only returns true if imported addresses were involved in transaction"},
|
|
||||||
{RPCResult::Type::STR_AMOUNT, "amount", "The total amount received by addresses with this label"},
|
{RPCResult::Type::STR_AMOUNT, "amount", "The total amount received by addresses with this label"},
|
||||||
{RPCResult::Type::NUM, "confirmations", "The number of confirmations of the most recent transaction included"},
|
{RPCResult::Type::NUM, "confirmations", "The number of confirmations of the most recent transaction included"},
|
||||||
{RPCResult::Type::STR, "label", "The label of the receiving address. The default label is \"\""},
|
{RPCResult::Type::STR, "label", "The label of the receiving address. The default label is \"\""},
|
||||||
@@ -332,17 +317,12 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
|
|||||||
|
|
||||||
CachedTxGetAmounts(wallet, wtx, listReceived, listSent, nFee, filter_ismine, include_change);
|
CachedTxGetAmounts(wallet, wtx, listReceived, listSent, nFee, filter_ismine, include_change);
|
||||||
|
|
||||||
bool involvesWatchonly = CachedTxIsFromMe(wallet, wtx, ISMINE_WATCH_ONLY);
|
|
||||||
|
|
||||||
// Sent
|
// Sent
|
||||||
if (!filter_label.has_value())
|
if (!filter_label.has_value())
|
||||||
{
|
{
|
||||||
for (const COutputEntry& s : listSent)
|
for (const COutputEntry& s : listSent)
|
||||||
{
|
{
|
||||||
UniValue entry(UniValue::VOBJ);
|
UniValue entry(UniValue::VOBJ);
|
||||||
if (involvesWatchonly || (wallet.IsMine(s.destination) & ISMINE_WATCH_ONLY)) {
|
|
||||||
entry.pushKV("involvesWatchonly", true);
|
|
||||||
}
|
|
||||||
MaybePushAddress(entry, s.destination);
|
MaybePushAddress(entry, s.destination);
|
||||||
entry.pushKV("category", "send");
|
entry.pushKV("category", "send");
|
||||||
entry.pushKV("amount", ValueFromAmount(-s.amount));
|
entry.pushKV("amount", ValueFromAmount(-s.amount));
|
||||||
@@ -372,9 +352,6 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
UniValue entry(UniValue::VOBJ);
|
UniValue entry(UniValue::VOBJ);
|
||||||
if (involvesWatchonly || (wallet.IsMine(r.destination) & ISMINE_WATCH_ONLY)) {
|
|
||||||
entry.pushKV("involvesWatchonly", true);
|
|
||||||
}
|
|
||||||
MaybePushAddress(entry, r.destination);
|
MaybePushAddress(entry, r.destination);
|
||||||
PushParentDescriptors(wallet, wtx.tx->vout.at(r.vout).scriptPubKey, entry);
|
PushParentDescriptors(wallet, wtx.tx->vout.at(r.vout).scriptPubKey, entry);
|
||||||
if (wtx.IsCoinBase())
|
if (wtx.IsCoinBase())
|
||||||
@@ -450,14 +427,13 @@ RPCHelpMan listtransactions()
|
|||||||
"with the specified label, or \"*\" to disable filtering and return all transactions."},
|
"with the specified label, or \"*\" to disable filtering and return all transactions."},
|
||||||
{"count", RPCArg::Type::NUM, RPCArg::Default{10}, "The number of transactions to return"},
|
{"count", RPCArg::Type::NUM, RPCArg::Default{10}, "The number of transactions to return"},
|
||||||
{"skip", RPCArg::Type::NUM, RPCArg::Default{0}, "The number of transactions to skip"},
|
{"skip", RPCArg::Type::NUM, RPCArg::Default{0}, "The number of transactions to skip"},
|
||||||
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Include transactions to watch-only addresses (see 'importaddress')"},
|
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
|
||||||
},
|
},
|
||||||
RPCResult{
|
RPCResult{
|
||||||
RPCResult::Type::ARR, "", "",
|
RPCResult::Type::ARR, "", "",
|
||||||
{
|
{
|
||||||
{RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
|
{RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
|
||||||
{
|
{
|
||||||
{RPCResult::Type::BOOL, "involvesWatchonly", /*optional=*/true, "Only returns true if imported addresses were involved in transaction."},
|
|
||||||
{RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address of the transaction (not returned if the output does not have an address, e.g. OP_RETURN null data)."},
|
{RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address of the transaction (not returned if the output does not have an address, e.g. OP_RETURN null data)."},
|
||||||
{RPCResult::Type::STR, "category", "The transaction category.\n"
|
{RPCResult::Type::STR, "category", "The transaction category.\n"
|
||||||
"\"send\" Transactions sent.\n"
|
"\"send\" Transactions sent.\n"
|
||||||
@@ -510,10 +486,6 @@ RPCHelpMan listtransactions()
|
|||||||
nFrom = request.params[2].getInt<int>();
|
nFrom = request.params[2].getInt<int>();
|
||||||
isminefilter filter = ISMINE_SPENDABLE;
|
isminefilter filter = ISMINE_SPENDABLE;
|
||||||
|
|
||||||
if (ParseIncludeWatchonly(request.params[3], *pwallet)) {
|
|
||||||
filter |= ISMINE_WATCH_ONLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nCount < 0)
|
if (nCount < 0)
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
|
||||||
if (nFrom < 0)
|
if (nFrom < 0)
|
||||||
@@ -559,7 +531,7 @@ RPCHelpMan listsinceblock()
|
|||||||
{
|
{
|
||||||
{"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "If set, the block hash to list transactions since, otherwise list all transactions."},
|
{"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "If set, the block hash to list transactions since, otherwise list all transactions."},
|
||||||
{"target_confirmations", RPCArg::Type::NUM, RPCArg::Default{1}, "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"},
|
{"target_confirmations", RPCArg::Type::NUM, RPCArg::Default{1}, "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"},
|
||||||
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Include transactions to watch-only addresses (see 'importaddress')"},
|
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
|
||||||
{"include_removed", RPCArg::Type::BOOL, RPCArg::Default{true}, "Show transactions that were removed due to a reorg in the \"removed\" array\n"
|
{"include_removed", RPCArg::Type::BOOL, RPCArg::Default{true}, "Show transactions that were removed due to a reorg in the \"removed\" array\n"
|
||||||
"(not guaranteed to work on pruned nodes)"},
|
"(not guaranteed to work on pruned nodes)"},
|
||||||
{"include_change", RPCArg::Type::BOOL, RPCArg::Default{false}, "Also add entries for change outputs.\n"},
|
{"include_change", RPCArg::Type::BOOL, RPCArg::Default{false}, "Also add entries for change outputs.\n"},
|
||||||
@@ -572,7 +544,6 @@ RPCHelpMan listsinceblock()
|
|||||||
{
|
{
|
||||||
{RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
|
{RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
|
||||||
{
|
{
|
||||||
{RPCResult::Type::BOOL, "involvesWatchonly", /*optional=*/true, "Only returns true if imported addresses were involved in transaction."},
|
|
||||||
{RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address of the transaction (not returned if the output does not have an address, e.g. OP_RETURN null data)."},
|
{RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address of the transaction (not returned if the output does not have an address, e.g. OP_RETURN null data)."},
|
||||||
{RPCResult::Type::STR, "category", "The transaction category.\n"
|
{RPCResult::Type::STR, "category", "The transaction category.\n"
|
||||||
"\"send\" Transactions sent.\n"
|
"\"send\" Transactions sent.\n"
|
||||||
@@ -638,10 +609,6 @@ RPCHelpMan listsinceblock()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ParseIncludeWatchonly(request.params[2], wallet)) {
|
|
||||||
filter |= ISMINE_WATCH_ONLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
|
bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
|
||||||
bool include_change = (!request.params[4].isNull() && request.params[4].get_bool());
|
bool include_change = (!request.params[4].isNull() && request.params[4].get_bool());
|
||||||
|
|
||||||
@@ -701,8 +668,7 @@ RPCHelpMan gettransaction()
|
|||||||
"Get detailed information about in-wallet transaction <txid>\n",
|
"Get detailed information about in-wallet transaction <txid>\n",
|
||||||
{
|
{
|
||||||
{"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
|
{"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
|
||||||
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"},
|
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
|
||||||
"Whether to include watch-only addresses in balance calculation and details[]"},
|
|
||||||
{"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
|
{"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
|
||||||
"Whether to include a `decoded` field containing the decoded transaction (equivalent to RPC decoderawtransaction)"},
|
"Whether to include a `decoded` field containing the decoded transaction (equivalent to RPC decoderawtransaction)"},
|
||||||
},
|
},
|
||||||
@@ -719,7 +685,6 @@ RPCHelpMan gettransaction()
|
|||||||
{
|
{
|
||||||
{RPCResult::Type::OBJ, "", "",
|
{RPCResult::Type::OBJ, "", "",
|
||||||
{
|
{
|
||||||
{RPCResult::Type::BOOL, "involvesWatchonly", /*optional=*/true, "Only returns true if imported addresses were involved in transaction."},
|
|
||||||
{RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address involved in the transaction."},
|
{RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address involved in the transaction."},
|
||||||
{RPCResult::Type::STR, "category", "The transaction category.\n"
|
{RPCResult::Type::STR, "category", "The transaction category.\n"
|
||||||
"\"send\" Transactions sent.\n"
|
"\"send\" Transactions sent.\n"
|
||||||
@@ -767,10 +732,6 @@ RPCHelpMan gettransaction()
|
|||||||
|
|
||||||
isminefilter filter = ISMINE_SPENDABLE;
|
isminefilter filter = ISMINE_SPENDABLE;
|
||||||
|
|
||||||
if (ParseIncludeWatchonly(request.params[1], *pwallet)) {
|
|
||||||
filter |= ISMINE_WATCH_ONLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool verbose = request.params[2].isNull() ? false : request.params[2].get_bool();
|
bool verbose = request.params[2].isNull() ? false : request.params[2].get_bool();
|
||||||
|
|
||||||
UniValue entry(UniValue::VOBJ);
|
UniValue entry(UniValue::VOBJ);
|
||||||
|
|||||||
@@ -29,21 +29,6 @@ bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
|
|||||||
return avoid_reuse;
|
return avoid_reuse;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Used by RPC commands that have an include_watchonly parameter.
|
|
||||||
* We default to true for watchonly wallets if include_watchonly isn't
|
|
||||||
* explicitly set.
|
|
||||||
*/
|
|
||||||
bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet)
|
|
||||||
{
|
|
||||||
if (include_watchonly.isNull()) {
|
|
||||||
// if include_watchonly isn't explicitly set, then check if we have a watchonly wallet
|
|
||||||
return wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise return whatever include_watchonly was set to
|
|
||||||
return include_watchonly.get_bool();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
|
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
|
||||||
{
|
{
|
||||||
if (request.URI.starts_with(WALLET_ENDPOINT_BASE)) {
|
if (request.URI.starts_with(WALLET_ENDPOINT_BASE)) {
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ void EnsureWalletIsUnlocked(const CWallet&);
|
|||||||
WalletContext& EnsureWalletContext(const std::any& context);
|
WalletContext& EnsureWalletContext(const std::any& context);
|
||||||
|
|
||||||
bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param);
|
bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param);
|
||||||
bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet);
|
|
||||||
std::string LabelFromValue(const UniValue& value);
|
std::string LabelFromValue(const UniValue& value);
|
||||||
//! Fetch parent descriptors of this scriptPubKey.
|
//! Fetch parent descriptors of this scriptPubKey.
|
||||||
void PushParentDescriptors(const CWallet& wallet, const CScript& script_pubkey, UniValue& entry);
|
void PushParentDescriptors(const CWallet& wallet, const CScript& script_pubkey, UniValue& entry);
|
||||||
|
|||||||
@@ -573,7 +573,7 @@ RPCHelpMan simulaterawtransaction()
|
|||||||
},
|
},
|
||||||
{"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
|
{"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
|
||||||
{
|
{
|
||||||
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see RPC importaddress)"},
|
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -595,22 +595,7 @@ RPCHelpMan simulaterawtransaction()
|
|||||||
|
|
||||||
LOCK(wallet.cs_wallet);
|
LOCK(wallet.cs_wallet);
|
||||||
|
|
||||||
UniValue include_watchonly(UniValue::VNULL);
|
|
||||||
if (request.params[1].isObject()) {
|
|
||||||
UniValue options = request.params[1];
|
|
||||||
RPCTypeCheckObj(options,
|
|
||||||
{
|
|
||||||
{"include_watchonly", UniValueType(UniValue::VBOOL)},
|
|
||||||
},
|
|
||||||
true, true);
|
|
||||||
|
|
||||||
include_watchonly = options["include_watchonly"];
|
|
||||||
}
|
|
||||||
|
|
||||||
isminefilter filter = ISMINE_SPENDABLE;
|
isminefilter filter = ISMINE_SPENDABLE;
|
||||||
if (ParseIncludeWatchonly(include_watchonly, wallet)) {
|
|
||||||
filter |= ISMINE_WATCH_ONLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& txs = request.params[0].get_array();
|
const auto& txs = request.params[0].get_array();
|
||||||
CAmount changes{0};
|
CAmount changes{0};
|
||||||
|
|||||||
@@ -828,7 +828,7 @@ class PSBTTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
# Test that psbts with p2pkh outputs are created properly
|
# Test that psbts with p2pkh outputs are created properly
|
||||||
p2pkh = self.nodes[0].getnewaddress(address_type='legacy')
|
p2pkh = self.nodes[0].getnewaddress(address_type='legacy')
|
||||||
psbt = self.nodes[1].walletcreatefundedpsbt([], [{p2pkh : 1}], 0, {"includeWatching" : True}, True)
|
psbt = self.nodes[1].walletcreatefundedpsbt(inputs=[], outputs=[{p2pkh : 1}], bip32derivs=True)
|
||||||
self.nodes[0].decodepsbt(psbt['psbt'])
|
self.nodes[0].decodepsbt(psbt['psbt'])
|
||||||
|
|
||||||
# Test decoding error: invalid base64
|
# Test decoding error: invalid base64
|
||||||
|
|||||||
@@ -83,9 +83,9 @@ class WalletTest(BitcoinTestFramework):
|
|||||||
assert_equal(self.nodes[0].getbalance("*"), 50)
|
assert_equal(self.nodes[0].getbalance("*"), 50)
|
||||||
assert_equal(self.nodes[0].getbalance("*", 1), 50)
|
assert_equal(self.nodes[0].getbalance("*", 1), 50)
|
||||||
assert_equal(self.nodes[0].getbalance(minconf=1), 50)
|
assert_equal(self.nodes[0].getbalance(minconf=1), 50)
|
||||||
assert_equal(self.nodes[0].getbalance(minconf=0, include_watchonly=True), 50)
|
assert_equal(self.nodes[0].getbalance(minconf=0), 50)
|
||||||
assert_equal(self.nodes[0].getbalance("*", 1, True), 50)
|
assert_equal(self.nodes[0].getbalance("*", 1, True), 50)
|
||||||
assert_equal(self.nodes[1].getbalance(minconf=0, include_watchonly=True), 50)
|
assert_equal(self.nodes[1].getbalance(minconf=0), 50)
|
||||||
|
|
||||||
# Send 40 BTC from 0 to 1 and 60 BTC from 1 to 0.
|
# Send 40 BTC from 0 to 1 and 60 BTC from 1 to 0.
|
||||||
txs = create_transactions(self.nodes[0], self.nodes[1].getnewaddress(), 40, [Decimal('0.01')])
|
txs = create_transactions(self.nodes[0], self.nodes[1].getnewaddress(), 40, [Decimal('0.01')])
|
||||||
|
|||||||
@@ -532,7 +532,6 @@ class WalletTest(BitcoinTestFramework):
|
|||||||
assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
|
assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
|
||||||
assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac")
|
assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac")
|
||||||
assert not address_info["ismine"]
|
assert not address_info["ismine"]
|
||||||
assert not address_info["iswatchonly"]
|
|
||||||
assert not address_info["isscript"]
|
assert not address_info["isscript"]
|
||||||
assert not address_info["ischange"]
|
assert not address_info["ischange"]
|
||||||
|
|
||||||
|
|||||||
@@ -781,7 +781,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||||||
self.nodes[3].loadwallet('wwatch')
|
self.nodes[3].loadwallet('wwatch')
|
||||||
wwatch = self.nodes[3].get_wallet_rpc('wwatch')
|
wwatch = self.nodes[3].get_wallet_rpc('wwatch')
|
||||||
w3 = self.nodes[3].get_wallet_rpc(self.default_wallet_name)
|
w3 = self.nodes[3].get_wallet_rpc(self.default_wallet_name)
|
||||||
result = wwatch.fundrawtransaction(rawtx, includeWatching=True, changeAddress=w3.getrawchangeaddress(), subtractFeeFromOutputs=[0])
|
result = wwatch.fundrawtransaction(rawtx, changeAddress=w3.getrawchangeaddress(), subtractFeeFromOutputs=[0])
|
||||||
res_dec = self.nodes[0].decoderawtransaction(result["hex"])
|
res_dec = self.nodes[0].decoderawtransaction(result["hex"])
|
||||||
assert_equal(len(res_dec["vin"]), 1)
|
assert_equal(len(res_dec["vin"]), 1)
|
||||||
assert res_dec["vin"][0]["txid"] == self.watchonly_utxo['txid']
|
assert res_dec["vin"][0]["txid"] == self.watchonly_utxo['txid']
|
||||||
|
|||||||
@@ -52,15 +52,12 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
# Address Test - before import
|
# Address Test - before import
|
||||||
address_info = self.nodes[1].getaddressinfo(address1)
|
address_info = self.nodes[1].getaddressinfo(address1)
|
||||||
assert_equal(address_info['iswatchonly'], False)
|
|
||||||
assert_equal(address_info['ismine'], False)
|
assert_equal(address_info['ismine'], False)
|
||||||
|
|
||||||
address_info = self.nodes[1].getaddressinfo(address2)
|
address_info = self.nodes[1].getaddressinfo(address2)
|
||||||
assert_equal(address_info['iswatchonly'], False)
|
|
||||||
assert_equal(address_info['ismine'], False)
|
assert_equal(address_info['ismine'], False)
|
||||||
|
|
||||||
address_info = self.nodes[1].getaddressinfo(address3)
|
address_info = self.nodes[1].getaddressinfo(address3)
|
||||||
assert_equal(address_info['iswatchonly'], False)
|
|
||||||
assert_equal(address_info['ismine'], False)
|
assert_equal(address_info['ismine'], False)
|
||||||
|
|
||||||
# Send funds to self
|
# Send funds to self
|
||||||
@@ -92,7 +89,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
|
|||||||
wwatch = self.nodes[1].get_wallet_rpc('wwatch')
|
wwatch = self.nodes[1].get_wallet_rpc('wwatch')
|
||||||
wwatch.importdescriptors([{"desc": self.nodes[0].getaddressinfo(address2)["desc"], "timestamp": "now"}])
|
wwatch.importdescriptors([{"desc": self.nodes[0].getaddressinfo(address2)["desc"], "timestamp": "now"}])
|
||||||
wwatch.importprunedfunds(rawtransaction=rawtxn2, txoutproof=proof2)
|
wwatch.importprunedfunds(rawtransaction=rawtxn2, txoutproof=proof2)
|
||||||
assert [tx for tx in wwatch.listtransactions(include_watchonly=True) if tx['txid'] == txnid2]
|
assert [tx for tx in wwatch.listtransactions() if tx['txid'] == txnid2]
|
||||||
|
|
||||||
# Import with private key with no rescan
|
# Import with private key with no rescan
|
||||||
w1 = self.nodes[1].get_wallet_rpc(self.default_wallet_name)
|
w1 = self.nodes[1].get_wallet_rpc(self.default_wallet_name)
|
||||||
@@ -104,24 +101,21 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
# Addresses Test - after import
|
# Addresses Test - after import
|
||||||
address_info = w1.getaddressinfo(address1)
|
address_info = w1.getaddressinfo(address1)
|
||||||
assert_equal(address_info['iswatchonly'], False)
|
|
||||||
assert_equal(address_info['ismine'], False)
|
assert_equal(address_info['ismine'], False)
|
||||||
address_info = wwatch.getaddressinfo(address2)
|
address_info = wwatch.getaddressinfo(address2)
|
||||||
assert_equal(address_info['iswatchonly'], False)
|
|
||||||
assert_equal(address_info['ismine'], True)
|
assert_equal(address_info['ismine'], True)
|
||||||
address_info = w1.getaddressinfo(address3)
|
address_info = w1.getaddressinfo(address3)
|
||||||
assert_equal(address_info['iswatchonly'], False)
|
|
||||||
assert_equal(address_info['ismine'], True)
|
assert_equal(address_info['ismine'], True)
|
||||||
|
|
||||||
# Remove transactions
|
# Remove transactions
|
||||||
assert_raises_rpc_error(-4, f'Transaction {txnid1} does not belong to this wallet', w1.removeprunedfunds, txnid1)
|
assert_raises_rpc_error(-4, f'Transaction {txnid1} does not belong to this wallet', w1.removeprunedfunds, txnid1)
|
||||||
assert not [tx for tx in w1.listtransactions(include_watchonly=True) if tx['txid'] == txnid1]
|
assert not [tx for tx in w1.listtransactions() if tx['txid'] == txnid1]
|
||||||
|
|
||||||
wwatch.removeprunedfunds(txnid2)
|
wwatch.removeprunedfunds(txnid2)
|
||||||
assert not [tx for tx in wwatch.listtransactions(include_watchonly=True) if tx['txid'] == txnid2]
|
assert not [tx for tx in wwatch.listtransactions() if tx['txid'] == txnid2]
|
||||||
|
|
||||||
w1.removeprunedfunds(txnid3)
|
w1.removeprunedfunds(txnid3)
|
||||||
assert not [tx for tx in w1.listtransactions(include_watchonly=True) if tx['txid'] == txnid3]
|
assert not [tx for tx in w1.listtransactions() if tx['txid'] == txnid3]
|
||||||
|
|
||||||
# Check various RPC parameter validation errors
|
# Check various RPC parameter validation errors
|
||||||
assert_raises_rpc_error(-22, "TX decode failed", w1.importprunedfunds, b'invalid tx'.hex(), proof1)
|
assert_raises_rpc_error(-22, "TX decode failed", w1.importprunedfunds, b'invalid tx'.hex(), proof1)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class ReceivedByTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
# save the number of coinbase reward addresses so far
|
# save the number of coinbase reward addresses so far
|
||||||
num_cb_reward_addresses = len(self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, include_watchonly=True))
|
num_cb_reward_addresses = len(self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True))
|
||||||
|
|
||||||
self.log.info("listreceivedbyaddress Test")
|
self.log.info("listreceivedbyaddress Test")
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ class ReceivedByTest(BitcoinTestFramework):
|
|||||||
# Test Address filtering
|
# Test Address filtering
|
||||||
# Only on addr
|
# Only on addr
|
||||||
expected = {"address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [txid, ]}
|
expected = {"address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [txid, ]}
|
||||||
res = self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, include_watchonly=True, address_filter=addr)
|
res = self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, address_filter=addr)
|
||||||
assert_array_result(res, {"address": addr}, expected)
|
assert_array_result(res, {"address": addr}, expected)
|
||||||
assert_equal(len(res), 1)
|
assert_equal(len(res), 1)
|
||||||
# Test for regression on CLI calls with address string (#14173)
|
# Test for regression on CLI calls with address string (#14173)
|
||||||
@@ -75,7 +75,7 @@ class ReceivedByTest(BitcoinTestFramework):
|
|||||||
assert_array_result(cli_res, {"address": addr}, expected)
|
assert_array_result(cli_res, {"address": addr}, expected)
|
||||||
assert_equal(len(cli_res), 1)
|
assert_equal(len(cli_res), 1)
|
||||||
# Error on invalid address
|
# Error on invalid address
|
||||||
assert_raises_rpc_error(-4, "address_filter parameter was invalid", self.nodes[1].listreceivedbyaddress, minconf=0, include_empty=True, include_watchonly=True, address_filter="bamboozling")
|
assert_raises_rpc_error(-4, "address_filter parameter was invalid", self.nodes[1].listreceivedbyaddress, minconf=0, include_empty=True, address_filter="bamboozling")
|
||||||
# Another address receive money
|
# Another address receive money
|
||||||
res = self.nodes[1].listreceivedbyaddress(0, True, True)
|
res = self.nodes[1].listreceivedbyaddress(0, True, True)
|
||||||
assert_equal(len(res), 2 + num_cb_reward_addresses) # Right now 2 entries
|
assert_equal(len(res), 2 + num_cb_reward_addresses) # Right now 2 entries
|
||||||
|
|||||||
@@ -277,7 +277,6 @@ class WalletMigrationTest(BitcoinTestFramework):
|
|||||||
# Transaction to multisig is in multisig1_watchonly and not multisig1
|
# Transaction to multisig is in multisig1_watchonly and not multisig1
|
||||||
_, multisig1 = self.migrate_and_get_rpc("multisig1")
|
_, multisig1 = self.migrate_and_get_rpc("multisig1")
|
||||||
assert_equal(multisig1.getaddressinfo(addr1)["ismine"], False)
|
assert_equal(multisig1.getaddressinfo(addr1)["ismine"], False)
|
||||||
assert_equal(multisig1.getaddressinfo(addr1)["iswatchonly"], False)
|
|
||||||
assert_equal(multisig1.getaddressinfo(addr1)["solvable"], False)
|
assert_equal(multisig1.getaddressinfo(addr1)["solvable"], False)
|
||||||
assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", multisig1.gettransaction, txid)
|
assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", multisig1.gettransaction, txid)
|
||||||
assert_equal(multisig1.getbalance(), 0)
|
assert_equal(multisig1.getbalance(), 0)
|
||||||
@@ -363,7 +362,7 @@ class WalletMigrationTest(BitcoinTestFramework):
|
|||||||
assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", imports0.gettransaction, received_watchonly_txid)
|
assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", imports0.gettransaction, received_watchonly_txid)
|
||||||
assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", imports0.gettransaction, received_sent_watchonly_utxo['txid'])
|
assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", imports0.gettransaction, received_sent_watchonly_utxo['txid'])
|
||||||
assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", imports0.gettransaction, sent_watchonly_txid)
|
assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", imports0.gettransaction, sent_watchonly_txid)
|
||||||
assert_equal(len(imports0.listtransactions(include_watchonly=True)), 2)
|
assert_equal(len(imports0.listtransactions()), 2)
|
||||||
imports0.gettransaction(received_txid)
|
imports0.gettransaction(received_txid)
|
||||||
imports0.gettransaction(watchonly_spendable_txid)
|
imports0.gettransaction(watchonly_spendable_txid)
|
||||||
assert_equal(imports0.getbalance(), spendable_bal)
|
assert_equal(imports0.getbalance(), spendable_bal)
|
||||||
@@ -859,18 +858,14 @@ class WalletMigrationTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
# Both addresses should only appear in the watchonly wallet
|
# Both addresses should only appear in the watchonly wallet
|
||||||
p2pkh_addr_info = wallet.getaddressinfo(p2pkh_addr)
|
p2pkh_addr_info = wallet.getaddressinfo(p2pkh_addr)
|
||||||
assert_equal(p2pkh_addr_info["iswatchonly"], False)
|
|
||||||
assert_equal(p2pkh_addr_info["ismine"], False)
|
assert_equal(p2pkh_addr_info["ismine"], False)
|
||||||
p2wpkh_addr_info = wallet.getaddressinfo(p2wpkh_addr)
|
p2wpkh_addr_info = wallet.getaddressinfo(p2wpkh_addr)
|
||||||
assert_equal(p2wpkh_addr_info["iswatchonly"], False)
|
|
||||||
assert_equal(p2wpkh_addr_info["ismine"], False)
|
assert_equal(p2wpkh_addr_info["ismine"], False)
|
||||||
|
|
||||||
watchonly_wallet = self.master_node.get_wallet_rpc(migrate_info["watchonly_name"])
|
watchonly_wallet = self.master_node.get_wallet_rpc(migrate_info["watchonly_name"])
|
||||||
watchonly_p2pkh_addr_info = watchonly_wallet.getaddressinfo(p2pkh_addr)
|
watchonly_p2pkh_addr_info = watchonly_wallet.getaddressinfo(p2pkh_addr)
|
||||||
assert_equal(watchonly_p2pkh_addr_info["iswatchonly"], False)
|
|
||||||
assert_equal(watchonly_p2pkh_addr_info["ismine"], True)
|
assert_equal(watchonly_p2pkh_addr_info["ismine"], True)
|
||||||
watchonly_p2wpkh_addr_info = watchonly_wallet.getaddressinfo(p2wpkh_addr)
|
watchonly_p2wpkh_addr_info = watchonly_wallet.getaddressinfo(p2wpkh_addr)
|
||||||
assert_equal(watchonly_p2wpkh_addr_info["iswatchonly"], False)
|
|
||||||
assert_equal(watchonly_p2wpkh_addr_info["ismine"], True)
|
assert_equal(watchonly_p2wpkh_addr_info["ismine"], True)
|
||||||
|
|
||||||
# There should only be raw or addr descriptors
|
# There should only be raw or addr descriptors
|
||||||
@@ -1090,7 +1085,6 @@ class WalletMigrationTest(BitcoinTestFramework):
|
|||||||
assert_equal(wallet.getbalances()['mine']['trusted'], 5)
|
assert_equal(wallet.getbalances()['mine']['trusted'], 5)
|
||||||
addr_info = wallet.getaddressinfo(wsh_pkh_addr)
|
addr_info = wallet.getaddressinfo(wsh_pkh_addr)
|
||||||
assert_equal(addr_info["ismine"], True)
|
assert_equal(addr_info["ismine"], True)
|
||||||
assert_equal(addr_info["iswatchonly"], False)
|
|
||||||
assert_equal(addr_info["solvable"], True)
|
assert_equal(addr_info["solvable"], True)
|
||||||
|
|
||||||
wallet.unloadwallet()
|
wallet.unloadwallet()
|
||||||
@@ -1202,7 +1196,6 @@ class WalletMigrationTest(BitcoinTestFramework):
|
|||||||
# information about the witnessScript
|
# information about the witnessScript
|
||||||
comp_wsh_pkh_addr_info = wallet.getaddressinfo(comp_wsh_pkh_addr)
|
comp_wsh_pkh_addr_info = wallet.getaddressinfo(comp_wsh_pkh_addr)
|
||||||
assert_equal(comp_wsh_pkh_addr_info["ismine"], True)
|
assert_equal(comp_wsh_pkh_addr_info["ismine"], True)
|
||||||
assert_equal(comp_wsh_pkh_addr_info["iswatchonly"], False)
|
|
||||||
assert "embedded" in comp_wsh_pkh_addr_info
|
assert "embedded" in comp_wsh_pkh_addr_info
|
||||||
|
|
||||||
# After migration, the invalid addresses should still not be detected as ismine and not watchonly.
|
# After migration, the invalid addresses should still not be detected as ismine and not watchonly.
|
||||||
@@ -1211,7 +1204,6 @@ class WalletMigrationTest(BitcoinTestFramework):
|
|||||||
for addr in invalid_addrs:
|
for addr in invalid_addrs:
|
||||||
addr_info = wallet.getaddressinfo(addr)
|
addr_info = wallet.getaddressinfo(addr)
|
||||||
assert_equal(addr_info["ismine"], False)
|
assert_equal(addr_info["ismine"], False)
|
||||||
assert_equal(addr_info["iswatchonly"], False)
|
|
||||||
assert "embedded" not in addr_info
|
assert "embedded" not in addr_info
|
||||||
|
|
||||||
wallet.unloadwallet()
|
wallet.unloadwallet()
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class WalletSendTest(BitcoinTestFramework):
|
|||||||
arg_conf_target=None, arg_estimate_mode=None, arg_fee_rate=None,
|
arg_conf_target=None, arg_estimate_mode=None, arg_fee_rate=None,
|
||||||
conf_target=None, estimate_mode=None, fee_rate=None, add_to_wallet=None, psbt=None,
|
conf_target=None, estimate_mode=None, fee_rate=None, add_to_wallet=None, psbt=None,
|
||||||
inputs=None, add_inputs=None, include_unsafe=None, change_address=None, change_position=None, change_type=None,
|
inputs=None, add_inputs=None, include_unsafe=None, change_address=None, change_position=None, change_type=None,
|
||||||
include_watching=None, locktime=None, lock_unspents=None, replaceable=None, subtract_fee_from_outputs=None,
|
locktime=None, lock_unspents=None, replaceable=None, subtract_fee_from_outputs=None,
|
||||||
expect_error=None, solving_data=None, minconf=None):
|
expect_error=None, solving_data=None, minconf=None):
|
||||||
assert_not_equal((amount is None), (data is None))
|
assert_not_equal((amount is None), (data is None))
|
||||||
|
|
||||||
@@ -90,8 +90,6 @@ class WalletSendTest(BitcoinTestFramework):
|
|||||||
options["change_position"] = change_position
|
options["change_position"] = change_position
|
||||||
if change_type is not None:
|
if change_type is not None:
|
||||||
options["change_type"] = change_type
|
options["change_type"] = change_type
|
||||||
if include_watching is not None:
|
|
||||||
options["include_watching"] = include_watching
|
|
||||||
if locktime is not None:
|
if locktime is not None:
|
||||||
options["locktime"] = locktime
|
options["locktime"] = locktime
|
||||||
if lock_unspents is not None:
|
if lock_unspents is not None:
|
||||||
@@ -110,6 +108,11 @@ class WalletSendTest(BitcoinTestFramework):
|
|||||||
if len(options.keys()) == 0:
|
if len(options.keys()) == 0:
|
||||||
options = None
|
options = None
|
||||||
|
|
||||||
|
expect_sign = from_wallet.getwalletinfo()["private_keys_enabled"]
|
||||||
|
expect_sign = expect_sign and solving_data is None
|
||||||
|
if inputs is not None:
|
||||||
|
expect_sign = expect_sign and all(["weight" not in i for i in inputs])
|
||||||
|
|
||||||
if expect_error is None:
|
if expect_error is None:
|
||||||
res = from_wallet.send(outputs=outputs, conf_target=arg_conf_target, estimate_mode=arg_estimate_mode, fee_rate=arg_fee_rate, options=options)
|
res = from_wallet.send(outputs=outputs, conf_target=arg_conf_target, estimate_mode=arg_estimate_mode, fee_rate=arg_fee_rate, options=options)
|
||||||
else:
|
else:
|
||||||
@@ -142,7 +145,7 @@ class WalletSendTest(BitcoinTestFramework):
|
|||||||
if locktime:
|
if locktime:
|
||||||
return res
|
return res
|
||||||
|
|
||||||
if from_wallet.getwalletinfo()["private_keys_enabled"] and not include_watching:
|
if expect_sign:
|
||||||
assert_equal(res["complete"], True)
|
assert_equal(res["complete"], True)
|
||||||
assert "txid" in res
|
assert "txid" in res
|
||||||
else:
|
else:
|
||||||
@@ -154,7 +157,7 @@ class WalletSendTest(BitcoinTestFramework):
|
|||||||
if include_unsafe:
|
if include_unsafe:
|
||||||
from_balance += from_wallet.getbalances()["mine"]["untrusted_pending"]
|
from_balance += from_wallet.getbalances()["mine"]["untrusted_pending"]
|
||||||
|
|
||||||
if add_to_wallet and not include_watching:
|
if add_to_wallet:
|
||||||
# Ensure transaction exists in the wallet:
|
# Ensure transaction exists in the wallet:
|
||||||
tx = from_wallet.gettransaction(res["txid"])
|
tx = from_wallet.gettransaction(res["txid"])
|
||||||
assert tx
|
assert tx
|
||||||
@@ -215,17 +218,13 @@ class WalletSendTest(BitcoinTestFramework):
|
|||||||
"desc": descsum_create("wpkh(" + xpub + "/0/0/*)"),
|
"desc": descsum_create("wpkh(" + xpub + "/0/0/*)"),
|
||||||
"timestamp": "now",
|
"timestamp": "now",
|
||||||
"range": [0, 100],
|
"range": [0, 100],
|
||||||
"keypool": True,
|
|
||||||
"active": True,
|
"active": True,
|
||||||
"watchonly": True
|
|
||||||
},{
|
},{
|
||||||
"desc": descsum_create("wpkh(" + xpub + "/0/1/*)"),
|
"desc": descsum_create("wpkh(" + xpub + "/0/1/*)"),
|
||||||
"timestamp": "now",
|
"timestamp": "now",
|
||||||
"range": [0, 100],
|
"range": [0, 100],
|
||||||
"keypool": True,
|
|
||||||
"active": True,
|
"active": True,
|
||||||
"internal": True,
|
"internal": True,
|
||||||
"watchonly": True
|
|
||||||
}])
|
}])
|
||||||
assert_equal(res, [{"success": True}, {"success": True}])
|
assert_equal(res, [{"success": True}, {"success": True}])
|
||||||
|
|
||||||
@@ -469,15 +468,15 @@ class WalletSendTest(BitcoinTestFramework):
|
|||||||
ext_utxo = ext_fund.listunspent(addresses=[addr])[0]
|
ext_utxo = ext_fund.listunspent(addresses=[addr])[0]
|
||||||
|
|
||||||
# An external input without solving data should result in an error
|
# An external input without solving data should result in an error
|
||||||
self.test_send(from_wallet=ext_wallet, to_wallet=self.nodes[0], amount=15, inputs=[ext_utxo], add_inputs=True, psbt=True, include_watching=True, expect_error=(-4, "Not solvable pre-selected input COutPoint(%s, %s)" % (ext_utxo["txid"][0:10], ext_utxo["vout"])))
|
self.test_send(from_wallet=ext_wallet, to_wallet=self.nodes[0], amount=15, inputs=[ext_utxo], add_inputs=True, psbt=True, expect_error=(-4, "Not solvable pre-selected input COutPoint(%s, %s)" % (ext_utxo["txid"][0:10], ext_utxo["vout"])))
|
||||||
|
|
||||||
# But funding should work when the solving data is provided
|
# But funding should work when the solving data is provided
|
||||||
res = self.test_send(from_wallet=ext_wallet, to_wallet=self.nodes[0], amount=15, inputs=[ext_utxo], add_inputs=True, psbt=True, include_watching=True, solving_data={"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"], addr_info["embedded"]["embedded"]["scriptPubKey"]]})
|
res = self.test_send(from_wallet=ext_wallet, to_wallet=self.nodes[0], amount=15, inputs=[ext_utxo], add_inputs=True, psbt=True, solving_data={"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"], addr_info["embedded"]["embedded"]["scriptPubKey"]]})
|
||||||
signed = ext_wallet.walletprocesspsbt(res["psbt"])
|
signed = ext_wallet.walletprocesspsbt(res["psbt"])
|
||||||
signed = ext_fund.walletprocesspsbt(res["psbt"])
|
signed = ext_fund.walletprocesspsbt(res["psbt"])
|
||||||
assert signed["complete"]
|
assert signed["complete"]
|
||||||
|
|
||||||
res = self.test_send(from_wallet=ext_wallet, to_wallet=self.nodes[0], amount=15, inputs=[ext_utxo], add_inputs=True, psbt=True, include_watching=True, solving_data={"descriptors": [desc]})
|
res = self.test_send(from_wallet=ext_wallet, to_wallet=self.nodes[0], amount=15, inputs=[ext_utxo], add_inputs=True, psbt=True, solving_data={"descriptors": [desc]})
|
||||||
signed = ext_wallet.walletprocesspsbt(res["psbt"])
|
signed = ext_wallet.walletprocesspsbt(res["psbt"])
|
||||||
signed = ext_fund.walletprocesspsbt(res["psbt"])
|
signed = ext_fund.walletprocesspsbt(res["psbt"])
|
||||||
assert signed["complete"]
|
assert signed["complete"]
|
||||||
@@ -510,7 +509,6 @@ class WalletSendTest(BitcoinTestFramework):
|
|||||||
inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}],
|
inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}],
|
||||||
add_inputs=True,
|
add_inputs=True,
|
||||||
psbt=True,
|
psbt=True,
|
||||||
include_watching=True,
|
|
||||||
fee_rate=target_fee_rate_sat_vb
|
fee_rate=target_fee_rate_sat_vb
|
||||||
)
|
)
|
||||||
signed = ext_wallet.walletprocesspsbt(res["psbt"])
|
signed = ext_wallet.walletprocesspsbt(res["psbt"])
|
||||||
|
|||||||
Reference in new issue
Block a user