mirror of https://github.com/bitcoin/bitcoin.git
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:
parent
e81d95d435
commit
1337c72198
|
@ -380,7 +380,7 @@ RPCHelpMan getaddressinfo()
|
|||
{RPCResult::Type::STR, "address", "The bitcoin address validated."},
|
||||
{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, "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::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"},
|
||||
|
@ -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::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::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);
|
||||
ret.pushKVs(std::move(detail));
|
||||
|
|
|
@ -146,9 +146,6 @@ static void PreventOutdatedOptions(const UniValue& options)
|
|||
if (options.exists("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")) {
|
||||
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;
|
||||
bool lockUnspents = false;
|
||||
if (!options.isNull()) {
|
||||
if (options.type() == UniValue::VBOOL) {
|
||||
// backward compatibility bool only fallback
|
||||
coinControl.fAllowWatchOnly = options.get_bool();
|
||||
}
|
||||
else {
|
||||
RPCTypeCheckObj(options,
|
||||
{
|
||||
{"add_inputs", UniValueType(UniValue::VBOOL)},
|
||||
{"include_unsafe", UniValueType(UniValue::VBOOL)},
|
||||
{"add_to_wallet", UniValueType(UniValue::VBOOL)},
|
||||
{"changeAddress", UniValueType(UniValue::VSTR)},
|
||||
{"change_address", UniValueType(UniValue::VSTR)},
|
||||
{"changePosition", UniValueType(UniValue::VNUM)},
|
||||
{"change_position", UniValueType(UniValue::VNUM)},
|
||||
{"change_type", UniValueType(UniValue::VSTR)},
|
||||
{"includeWatching", UniValueType(UniValue::VBOOL)},
|
||||
{"include_watching", UniValueType(UniValue::VBOOL)},
|
||||
{"inputs", UniValueType(UniValue::VARR)},
|
||||
{"lockUnspents", UniValueType(UniValue::VBOOL)},
|
||||
{"lock_unspents", UniValueType(UniValue::VBOOL)},
|
||||
{"locktime", UniValueType(UniValue::VNUM)},
|
||||
{"fee_rate", UniValueType()}, // will be checked by AmountFromValue() in SetFeeEstimateMode()
|
||||
{"feeRate", UniValueType()}, // will be checked by AmountFromValue() below
|
||||
{"psbt", UniValueType(UniValue::VBOOL)},
|
||||
{"solving_data", UniValueType(UniValue::VOBJ)},
|
||||
{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
|
||||
{"subtract_fee_from_outputs", UniValueType(UniValue::VARR)},
|
||||
{"replaceable", UniValueType(UniValue::VBOOL)},
|
||||
{"conf_target", UniValueType(UniValue::VNUM)},
|
||||
{"estimate_mode", UniValueType(UniValue::VSTR)},
|
||||
{"minconf", UniValueType(UniValue::VNUM)},
|
||||
{"maxconf", UniValueType(UniValue::VNUM)},
|
||||
{"input_weights", UniValueType(UniValue::VARR)},
|
||||
{"max_tx_weight", UniValueType(UniValue::VNUM)},
|
||||
},
|
||||
true, true);
|
||||
if (options.type() == UniValue::VBOOL) {
|
||||
// backward compatibility bool only fallback, does nothing
|
||||
} else {
|
||||
RPCTypeCheckObj(options,
|
||||
{
|
||||
{"add_inputs", UniValueType(UniValue::VBOOL)},
|
||||
{"include_unsafe", UniValueType(UniValue::VBOOL)},
|
||||
{"add_to_wallet", UniValueType(UniValue::VBOOL)},
|
||||
{"changeAddress", UniValueType(UniValue::VSTR)},
|
||||
{"change_address", UniValueType(UniValue::VSTR)},
|
||||
{"changePosition", UniValueType(UniValue::VNUM)},
|
||||
{"change_position", UniValueType(UniValue::VNUM)},
|
||||
{"change_type", UniValueType(UniValue::VSTR)},
|
||||
{"includeWatching", UniValueType(UniValue::VBOOL)},
|
||||
{"include_watching", UniValueType(UniValue::VBOOL)},
|
||||
{"inputs", UniValueType(UniValue::VARR)},
|
||||
{"lockUnspents", UniValueType(UniValue::VBOOL)},
|
||||
{"lock_unspents", UniValueType(UniValue::VBOOL)},
|
||||
{"locktime", UniValueType(UniValue::VNUM)},
|
||||
{"fee_rate", UniValueType()}, // will be checked by AmountFromValue() in SetFeeEstimateMode()
|
||||
{"feeRate", UniValueType()}, // will be checked by AmountFromValue() below
|
||||
{"psbt", UniValueType(UniValue::VBOOL)},
|
||||
{"solving_data", UniValueType(UniValue::VOBJ)},
|
||||
{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
|
||||
{"subtract_fee_from_outputs", UniValueType(UniValue::VARR)},
|
||||
{"replaceable", UniValueType(UniValue::VBOOL)},
|
||||
{"conf_target", UniValueType(UniValue::VNUM)},
|
||||
{"estimate_mode", UniValueType(UniValue::VSTR)},
|
||||
{"minconf", UniValueType(UniValue::VNUM)},
|
||||
{"maxconf", UniValueType(UniValue::VNUM)},
|
||||
{"input_weights", UniValueType(UniValue::VARR)},
|
||||
{"max_tx_weight", UniValueType(UniValue::VNUM)},
|
||||
},
|
||||
true, true);
|
||||
|
||||
if (options.exists("add_inputs")) {
|
||||
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");
|
||||
if (options.exists("add_inputs")) {
|
||||
coinControl.m_allow_other_inputs = options["add_inputs"].get_bool();
|
||||
}
|
||||
|
||||
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")) {
|
||||
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());
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str()));
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
const UniValue include_watching_option = options.exists("include_watching") ? options["include_watching"] : options["includeWatching"];
|
||||
coinControl.fAllowWatchOnly = ParseIncludeWatchonly(include_watching_option, wallet);
|
||||
|
||||
if (options.exists("lockUnspents") || options.exists("lock_unspents")) {
|
||||
lockUnspents = (options.exists("lock_unspents") ? options["lock_unspents"] : options["lockUnspents"]).get_bool();
|
||||
}
|
||||
|
||||
if (options.exists("include_unsafe")) {
|
||||
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("change_type")) {
|
||||
if (options.exists("changeAddress") || options.exists("change_address")) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both change address and address type options");
|
||||
}
|
||||
if (std::optional<OutputType> parsed = ParseOutputType(options["change_type"].get_str())) {
|
||||
coinControl.m_change_type.emplace(parsed.value());
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str()));
|
||||
}
|
||||
}
|
||||
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")) {
|
||||
coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool();
|
||||
}
|
||||
|
||||
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("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("estimate_mode")) {
|
||||
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")) {
|
||||
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));
|
||||
if (options.exists("replaceable")) {
|
||||
coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool();
|
||||
}
|
||||
|
||||
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")) {
|
||||
|
@ -757,13 +746,12 @@ RPCHelpMan fundrawtransaction()
|
|||
"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"
|
||||
"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"
|
||||
"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",
|
||||
{
|
||||
{"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>>(
|
||||
{
|
||||
{"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"},
|
||||
{"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\"."},
|
||||
{"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
|
||||
"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'."},
|
||||
{"includeWatching", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
|
||||
{"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."},
|
||||
{"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_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}},
|
||||
{"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
|
||||
"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'."},
|
||||
{"include_watching", RPCArg::Type::BOOL, RPCArg::Default{"false"}, "(DEPRECATED) No longer used"},
|
||||
{"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Specify inputs instead of adding them automatically.",
|
||||
{
|
||||
{"", 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"},
|
||||
{"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"
|
||||
"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'."},
|
||||
{"include_watching", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
|
||||
{"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, "",
|
||||
|
@ -1443,8 +1425,6 @@ RPCHelpMan sendall()
|
|||
|
||||
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["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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
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"},
|
||||
{"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\"."},
|
||||
{"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"},
|
||||
{"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."},
|
||||
|
|
|
@ -68,7 +68,6 @@ struct tallyitem
|
|||
CAmount nAmount{0};
|
||||
int nConf{std::numeric_limits<int>::max()};
|
||||
std::vector<Txid> txids;
|
||||
bool fIsWatchonly{false};
|
||||
tallyitem() = default;
|
||||
};
|
||||
|
||||
|
@ -86,10 +85,6 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, cons
|
|||
|
||||
isminefilter filter = ISMINE_SPENDABLE;
|
||||
|
||||
if (ParseIncludeWatchonly(params[2], wallet)) {
|
||||
filter |= ISMINE_WATCH_ONLY;
|
||||
}
|
||||
|
||||
std::optional<CTxDestination> filtered_address{std::nullopt};
|
||||
if (!by_label && !params[3].isNull() && !params[3].get_str().empty()) {
|
||||
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.nConf = std::min(item.nConf, nDepth);
|
||||
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;
|
||||
int nConf = std::numeric_limits<int>::max();
|
||||
bool fIsWatchonly = false;
|
||||
if (it != mapTally.end()) {
|
||||
nAmount = (*it).second.nAmount;
|
||||
nConf = (*it).second.nConf;
|
||||
fIsWatchonly = (*it).second.fIsWatchonly;
|
||||
}
|
||||
|
||||
if (by_label) {
|
||||
tallyitem& _item = label_tally[label];
|
||||
_item.nAmount += nAmount;
|
||||
_item.nConf = std::min(_item.nConf, nConf);
|
||||
_item.fIsWatchonly = fIsWatchonly;
|
||||
} else {
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
if (fIsWatchonly) obj.pushKV("involvesWatchonly", true);
|
||||
obj.pushKV("address", EncodeDestination(address));
|
||||
obj.pushKV("amount", ValueFromAmount(nAmount));
|
||||
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;
|
||||
int nConf = entry.second.nConf;
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
if (entry.second.fIsWatchonly)
|
||||
obj.pushKV("involvesWatchonly", true);
|
||||
obj.pushKV("amount", ValueFromAmount(nAmount));
|
||||
obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
|
||||
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."},
|
||||
{"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."},
|
||||
{"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."},
|
||||
},
|
||||
|
@ -219,7 +206,6 @@ RPCHelpMan listreceivedbyaddress()
|
|||
{
|
||||
{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_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"},
|
||||
|
@ -264,7 +250,7 @@ RPCHelpMan listreceivedbylabel()
|
|||
{
|
||||
{"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_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."},
|
||||
},
|
||||
RPCResult{
|
||||
|
@ -272,7 +258,6 @@ RPCHelpMan listreceivedbylabel()
|
|||
{
|
||||
{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::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 \"\""},
|
||||
|
@ -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);
|
||||
|
||||
bool involvesWatchonly = CachedTxIsFromMe(wallet, wtx, ISMINE_WATCH_ONLY);
|
||||
|
||||
// Sent
|
||||
if (!filter_label.has_value())
|
||||
{
|
||||
for (const COutputEntry& s : listSent)
|
||||
{
|
||||
UniValue entry(UniValue::VOBJ);
|
||||
if (involvesWatchonly || (wallet.IsMine(s.destination) & ISMINE_WATCH_ONLY)) {
|
||||
entry.pushKV("involvesWatchonly", true);
|
||||
}
|
||||
MaybePushAddress(entry, s.destination);
|
||||
entry.pushKV("category", "send");
|
||||
entry.pushKV("amount", ValueFromAmount(-s.amount));
|
||||
|
@ -372,9 +352,6 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
|
|||
continue;
|
||||
}
|
||||
UniValue entry(UniValue::VOBJ);
|
||||
if (involvesWatchonly || (wallet.IsMine(r.destination) & ISMINE_WATCH_ONLY)) {
|
||||
entry.pushKV("involvesWatchonly", true);
|
||||
}
|
||||
MaybePushAddress(entry, r.destination);
|
||||
PushParentDescriptors(wallet, wtx.tx->vout.at(r.vout).scriptPubKey, entry);
|
||||
if (wtx.IsCoinBase())
|
||||
|
@ -450,14 +427,13 @@ RPCHelpMan listtransactions()
|
|||
"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"},
|
||||
{"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::Type::ARR, "", "",
|
||||
{
|
||||
{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, "category", "The transaction category.\n"
|
||||
"\"send\" Transactions sent.\n"
|
||||
|
@ -510,10 +486,6 @@ RPCHelpMan listtransactions()
|
|||
nFrom = request.params[2].getInt<int>();
|
||||
isminefilter filter = ISMINE_SPENDABLE;
|
||||
|
||||
if (ParseIncludeWatchonly(request.params[3], *pwallet)) {
|
||||
filter |= ISMINE_WATCH_ONLY;
|
||||
}
|
||||
|
||||
if (nCount < 0)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
|
||||
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."},
|
||||
{"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"
|
||||
"(not guaranteed to work on pruned nodes)"},
|
||||
{"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::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, "category", "The transaction category.\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_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",
|
||||
{
|
||||
{"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
|
||||
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"},
|
||||
"Whether to include watch-only addresses in balance calculation and details[]"},
|
||||
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
|
||||
{"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
|
||||
"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::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, "category", "The transaction category.\n"
|
||||
"\"send\" Transactions sent.\n"
|
||||
|
@ -767,10 +732,6 @@ RPCHelpMan gettransaction()
|
|||
|
||||
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();
|
||||
|
||||
UniValue entry(UniValue::VOBJ);
|
||||
|
|
|
@ -29,21 +29,6 @@ bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
|
|||
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)
|
||||
{
|
||||
if (request.URI.starts_with(WALLET_ENDPOINT_BASE)) {
|
||||
|
|
|
@ -43,7 +43,6 @@ void EnsureWalletIsUnlocked(const CWallet&);
|
|||
WalletContext& EnsureWalletContext(const std::any& context);
|
||||
|
||||
bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param);
|
||||
bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet);
|
||||
std::string LabelFromValue(const UniValue& value);
|
||||
//! Fetch parent descriptors of this scriptPubKey.
|
||||
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, "",
|
||||
{
|
||||
{"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);
|
||||
|
||||
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;
|
||||
if (ParseIncludeWatchonly(include_watchonly, wallet)) {
|
||||
filter |= ISMINE_WATCH_ONLY;
|
||||
}
|
||||
|
||||
const auto& txs = request.params[0].get_array();
|
||||
CAmount changes{0};
|
||||
|
|
|
@ -828,7 +828,7 @@ class PSBTTest(BitcoinTestFramework):
|
|||
|
||||
# Test that psbts with p2pkh outputs are created properly
|
||||
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'])
|
||||
|
||||
# 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("*", 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[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.
|
||||
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["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac")
|
||||
assert not address_info["ismine"]
|
||||
assert not address_info["iswatchonly"]
|
||||
assert not address_info["isscript"]
|
||||
assert not address_info["ischange"]
|
||||
|
||||
|
|
|
@ -781,7 +781,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||
self.nodes[3].loadwallet('wwatch')
|
||||
wwatch = self.nodes[3].get_wallet_rpc('wwatch')
|
||||
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"])
|
||||
assert_equal(len(res_dec["vin"]), 1)
|
||||
assert res_dec["vin"][0]["txid"] == self.watchonly_utxo['txid']
|
||||
|
|
|
@ -52,15 +52,12 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
|
|||
|
||||
# Address Test - before import
|
||||
address_info = self.nodes[1].getaddressinfo(address1)
|
||||
assert_equal(address_info['iswatchonly'], False)
|
||||
assert_equal(address_info['ismine'], False)
|
||||
|
||||
address_info = self.nodes[1].getaddressinfo(address2)
|
||||
assert_equal(address_info['iswatchonly'], False)
|
||||
assert_equal(address_info['ismine'], False)
|
||||
|
||||
address_info = self.nodes[1].getaddressinfo(address3)
|
||||
assert_equal(address_info['iswatchonly'], False)
|
||||
assert_equal(address_info['ismine'], False)
|
||||
|
||||
# Send funds to self
|
||||
|
@ -92,7 +89,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
|
|||
wwatch = self.nodes[1].get_wallet_rpc('wwatch')
|
||||
wwatch.importdescriptors([{"desc": self.nodes[0].getaddressinfo(address2)["desc"], "timestamp": "now"}])
|
||||
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
|
||||
w1 = self.nodes[1].get_wallet_rpc(self.default_wallet_name)
|
||||
|
@ -104,24 +101,21 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
|
|||
|
||||
# Addresses Test - after import
|
||||
address_info = w1.getaddressinfo(address1)
|
||||
assert_equal(address_info['iswatchonly'], False)
|
||||
assert_equal(address_info['ismine'], False)
|
||||
address_info = wwatch.getaddressinfo(address2)
|
||||
assert_equal(address_info['iswatchonly'], False)
|
||||
assert_equal(address_info['ismine'], True)
|
||||
address_info = w1.getaddressinfo(address3)
|
||||
assert_equal(address_info['iswatchonly'], False)
|
||||
assert_equal(address_info['ismine'], True)
|
||||
|
||||
# Remove transactions
|
||||
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)
|
||||
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)
|
||||
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
|
||||
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):
|
||||
# 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")
|
||||
|
||||
|
@ -67,7 +67,7 @@ class ReceivedByTest(BitcoinTestFramework):
|
|||
# Test Address filtering
|
||||
# Only on addr
|
||||
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_equal(len(res), 1)
|
||||
# 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_equal(len(cli_res), 1)
|
||||
# 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
|
||||
res = self.nodes[1].listreceivedbyaddress(0, True, True)
|
||||
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
|
||||
_, multisig1 = self.migrate_and_get_rpc("multisig1")
|
||||
assert_equal(multisig1.getaddressinfo(addr1)["ismine"], False)
|
||||
assert_equal(multisig1.getaddressinfo(addr1)["iswatchonly"], False)
|
||||
assert_equal(multisig1.getaddressinfo(addr1)["solvable"], False)
|
||||
assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", multisig1.gettransaction, txid)
|
||||
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_sent_watchonly_utxo['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(watchonly_spendable_txid)
|
||||
assert_equal(imports0.getbalance(), spendable_bal)
|
||||
|
@ -859,18 +858,14 @@ class WalletMigrationTest(BitcoinTestFramework):
|
|||
|
||||
# Both addresses should only appear in the watchonly wallet
|
||||
p2pkh_addr_info = wallet.getaddressinfo(p2pkh_addr)
|
||||
assert_equal(p2pkh_addr_info["iswatchonly"], False)
|
||||
assert_equal(p2pkh_addr_info["ismine"], False)
|
||||
p2wpkh_addr_info = wallet.getaddressinfo(p2wpkh_addr)
|
||||
assert_equal(p2wpkh_addr_info["iswatchonly"], False)
|
||||
assert_equal(p2wpkh_addr_info["ismine"], False)
|
||||
|
||||
watchonly_wallet = self.master_node.get_wallet_rpc(migrate_info["watchonly_name"])
|
||||
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)
|
||||
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)
|
||||
|
||||
# There should only be raw or addr descriptors
|
||||
|
@ -1090,7 +1085,6 @@ class WalletMigrationTest(BitcoinTestFramework):
|
|||
assert_equal(wallet.getbalances()['mine']['trusted'], 5)
|
||||
addr_info = wallet.getaddressinfo(wsh_pkh_addr)
|
||||
assert_equal(addr_info["ismine"], True)
|
||||
assert_equal(addr_info["iswatchonly"], False)
|
||||
assert_equal(addr_info["solvable"], True)
|
||||
|
||||
wallet.unloadwallet()
|
||||
|
@ -1202,7 +1196,6 @@ class WalletMigrationTest(BitcoinTestFramework):
|
|||
# information about the witnessScript
|
||||
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["iswatchonly"], False)
|
||||
assert "embedded" in comp_wsh_pkh_addr_info
|
||||
|
||||
# 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:
|
||||
addr_info = wallet.getaddressinfo(addr)
|
||||
assert_equal(addr_info["ismine"], False)
|
||||
assert_equal(addr_info["iswatchonly"], False)
|
||||
assert "embedded" not in addr_info
|
||||
|
||||
wallet.unloadwallet()
|
||||
|
|
|
@ -42,7 +42,7 @@ class WalletSendTest(BitcoinTestFramework):
|
|||
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,
|
||||
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):
|
||||
assert_not_equal((amount is None), (data is None))
|
||||
|
||||
|
@ -90,8 +90,6 @@ class WalletSendTest(BitcoinTestFramework):
|
|||
options["change_position"] = change_position
|
||||
if change_type is not None:
|
||||
options["change_type"] = change_type
|
||||
if include_watching is not None:
|
||||
options["include_watching"] = include_watching
|
||||
if locktime is not None:
|
||||
options["locktime"] = locktime
|
||||
if lock_unspents is not None:
|
||||
|
@ -110,6 +108,11 @@ class WalletSendTest(BitcoinTestFramework):
|
|||
if len(options.keys()) == 0:
|
||||
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:
|
||||
res = from_wallet.send(outputs=outputs, conf_target=arg_conf_target, estimate_mode=arg_estimate_mode, fee_rate=arg_fee_rate, options=options)
|
||||
else:
|
||||
|
@ -142,7 +145,7 @@ class WalletSendTest(BitcoinTestFramework):
|
|||
if locktime:
|
||||
return res
|
||||
|
||||
if from_wallet.getwalletinfo()["private_keys_enabled"] and not include_watching:
|
||||
if expect_sign:
|
||||
assert_equal(res["complete"], True)
|
||||
assert "txid" in res
|
||||
else:
|
||||
|
@ -154,7 +157,7 @@ class WalletSendTest(BitcoinTestFramework):
|
|||
if include_unsafe:
|
||||
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:
|
||||
tx = from_wallet.gettransaction(res["txid"])
|
||||
assert tx
|
||||
|
@ -215,17 +218,13 @@ class WalletSendTest(BitcoinTestFramework):
|
|||
"desc": descsum_create("wpkh(" + xpub + "/0/0/*)"),
|
||||
"timestamp": "now",
|
||||
"range": [0, 100],
|
||||
"keypool": True,
|
||||
"active": True,
|
||||
"watchonly": True
|
||||
},{
|
||||
"desc": descsum_create("wpkh(" + xpub + "/0/1/*)"),
|
||||
"timestamp": "now",
|
||||
"range": [0, 100],
|
||||
"keypool": True,
|
||||
"active": True,
|
||||
"internal": True,
|
||||
"watchonly": True
|
||||
}])
|
||||
assert_equal(res, [{"success": True}, {"success": True}])
|
||||
|
||||
|
@ -469,15 +468,15 @@ class WalletSendTest(BitcoinTestFramework):
|
|||
ext_utxo = ext_fund.listunspent(addresses=[addr])[0]
|
||||
|
||||
# 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
|
||||
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_fund.walletprocesspsbt(res["psbt"])
|
||||
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_fund.walletprocesspsbt(res["psbt"])
|
||||
assert signed["complete"]
|
||||
|
@ -510,7 +509,6 @@ class WalletSendTest(BitcoinTestFramework):
|
|||
inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}],
|
||||
add_inputs=True,
|
||||
psbt=True,
|
||||
include_watching=True,
|
||||
fee_rate=target_fee_rate_sat_vb
|
||||
)
|
||||
signed = ext_wallet.walletprocesspsbt(res["psbt"])
|
||||
|
|
Loading…
Reference in New Issue