mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-16 13:01:19 +02:00
Merge UP TO 48174c0f28 into merged_master (UP TO Bitcoin PR bitcoin/bitcoin#26240)
FIXME in wallet_taproot.py functional test 1668424146 2022-11-14T12:09:06+01:0048174c0f28Bitcoin Merge bitcoin/bitcoin#26240: rpc: Adjust RPCTypeCheckObj error string 1668417474 2022-11-14T10:17:54+01:0059e00c7e03Bitcoin Merge bitcoin/bitcoin#25714: univalue: Avoid std::string copies 1668111238 2022-11-10T15:13:58-05:007ef730ca84Bitcoin Merge bitcoin/bitcoin#26483: test: Don't pass add_to_wallet option to walletcreatefundedpsbt 1668004459 2022-11-09T15:34:19+01:009dce30194bBitcoin Merge bitcoin/bitcoin#26472: test: add missing bech32m / BIP86 test-cases to wallet_descriptor.py 1667992471 2022-11-09T12:14:31+01:0044ca5d5e87Bitcoin Merge bitcoin/bitcoin#26473: test: Avoid collision with valid path names in `getarg_tests/logargs` 1667640759 2022-11-05T10:32:39+01:0050422b770aBitcoin Merge bitcoin/bitcoin#26419: log: mempool: log removal reason in validation interface 1667636699 2022-11-05T09:24:59+01:00ce57dbac90Bitcoin Merge bitcoin/bitcoin#26449: rpc: doc: add missing option "bech32m" for `change_type` parameters 1667577253 2022-11-04T15:54:13+00:00ae6bb6e71eBitcoin Merge bitcoin/bitcoin#26418: Fix signing of multi_a and rawtr scripts with wallets that only have corresponding keys
This commit is contained in:
commit
7ea69ff0d8
18 changed files with 193 additions and 114 deletions
|
|
@ -70,11 +70,8 @@ void RPCTypeCheckObj(const UniValue& o,
|
|||
if (!fAllowNull && v.isNull())
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
|
||||
|
||||
if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) {
|
||||
std::string err = strprintf("Expected type %s for %s, got %s",
|
||||
uvTypeName(t.second.type), t.first, uvTypeName(v.type()));
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, err);
|
||||
}
|
||||
if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull())))
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("JSON value of type %s for field %s is not of expected type %s", uvTypeName(v.type()), t.first, uvTypeName(t.second.type)));
|
||||
}
|
||||
|
||||
if (fStrict)
|
||||
|
|
|
|||
|
|
@ -150,6 +150,16 @@ static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdat
|
|||
|
||||
static bool CreateTaprootScriptSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector<unsigned char>& sig_out, const XOnlyPubKey& pubkey, const uint256& leaf_hash, SigVersion sigversion)
|
||||
{
|
||||
KeyOriginInfo info;
|
||||
if (provider.GetKeyOriginByXOnly(pubkey, info)) {
|
||||
auto it = sigdata.taproot_misc_pubkeys.find(pubkey);
|
||||
if (it == sigdata.taproot_misc_pubkeys.end()) {
|
||||
sigdata.taproot_misc_pubkeys.emplace(pubkey, std::make_pair(std::set<uint256>({leaf_hash}), info));
|
||||
} else {
|
||||
it->second.first.insert(leaf_hash);
|
||||
}
|
||||
}
|
||||
|
||||
auto lookup_key = std::make_pair(pubkey, leaf_hash);
|
||||
auto it = sigdata.taproot_script_sigs.find(lookup_key);
|
||||
if (it != sigdata.taproot_script_sigs.end()) {
|
||||
|
|
@ -174,17 +184,6 @@ static bool SignTaprootScript(const SigningProvider& provider, const BaseSignatu
|
|||
// <xonly pubkey> OP_CHECKSIG
|
||||
if (script.size() == 34 && script[33] == OP_CHECKSIG && script[0] == 0x20) {
|
||||
XOnlyPubKey pubkey{Span{script}.subspan(1, 32)};
|
||||
|
||||
KeyOriginInfo info;
|
||||
if (provider.GetKeyOriginByXOnly(pubkey, info)) {
|
||||
auto it = sigdata.taproot_misc_pubkeys.find(pubkey);
|
||||
if (it == sigdata.taproot_misc_pubkeys.end()) {
|
||||
sigdata.taproot_misc_pubkeys.emplace(pubkey, std::make_pair(std::set<uint256>({leaf_hash}), info));
|
||||
} else {
|
||||
it->second.first.insert(leaf_hash);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned char> sig;
|
||||
if (CreateTaprootScriptSig(creator, sigdata, provider, sig, pubkey, leaf_hash, sigversion)) {
|
||||
result = Vector(std::move(sig));
|
||||
|
|
|
|||
|
|
@ -429,7 +429,7 @@ BOOST_AUTO_TEST_CASE(logargs)
|
|||
const auto okaylog = std::make_pair("-okaylog", ArgsManager::ALLOW_ANY);
|
||||
const auto dontlog = std::make_pair("-dontlog", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE);
|
||||
SetupArgs(local_args, {okaylog_bool, okaylog_negbool, okaylog, dontlog});
|
||||
ResetArgs(local_args, "-okaylog-bool -nookaylog-negbool -okaylog=public -dontlog=private");
|
||||
ResetArgs(local_args, "-okaylog-bool -nookaylog-negbool -okaylog=public -dontlog=private42");
|
||||
|
||||
// Everything logged to debug.log will also append to str
|
||||
std::string str;
|
||||
|
|
@ -447,7 +447,7 @@ BOOST_AUTO_TEST_CASE(logargs)
|
|||
BOOST_CHECK(str.find("Command-line arg: okaylog-negbool=false") != std::string::npos);
|
||||
BOOST_CHECK(str.find("Command-line arg: okaylog=\"public\"") != std::string::npos);
|
||||
BOOST_CHECK(str.find("dontlog=****") != std::string::npos);
|
||||
BOOST_CHECK(str.find("private") == std::string::npos);
|
||||
BOOST_CHECK(str.find("private42") == std::string::npos);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
|||
|
|
@ -1281,3 +1281,17 @@ void CTxMemPool::SetLoadTried(bool load_tried)
|
|||
LOCK(cs);
|
||||
m_load_tried = load_tried;
|
||||
}
|
||||
|
||||
|
||||
const std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept
|
||||
{
|
||||
switch (r) {
|
||||
case MemPoolRemovalReason::EXPIRY: return "expiry";
|
||||
case MemPoolRemovalReason::SIZELIMIT: return "sizelimit";
|
||||
case MemPoolRemovalReason::REORG: return "reorg";
|
||||
case MemPoolRemovalReason::BLOCK: return "block";
|
||||
case MemPoolRemovalReason::CONFLICT: return "conflict";
|
||||
case MemPoolRemovalReason::REPLACED: return "replaced";
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -412,6 +412,8 @@ enum class MemPoolRemovalReason {
|
|||
REPLACED, //!< Removed for replacement
|
||||
};
|
||||
|
||||
const std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept;
|
||||
|
||||
/**
|
||||
* CTxMemPool stores valid-according-to-the-current-best-chain transactions
|
||||
* that may be included in the next block.
|
||||
|
|
|
|||
|
|
@ -25,10 +25,7 @@ public:
|
|||
};
|
||||
|
||||
UniValue() { typ = VNULL; }
|
||||
UniValue(UniValue::VType initialType, const std::string& initialStr = "") {
|
||||
typ = initialType;
|
||||
val = initialStr;
|
||||
}
|
||||
UniValue(UniValue::VType type, std::string str = {}) : typ{type}, val{std::move(str)} {}
|
||||
template <typename Ref, typename T = std::remove_cv_t<std::remove_reference_t<Ref>>,
|
||||
std::enable_if_t<std::is_floating_point_v<T> || // setFloat
|
||||
std::is_same_v<bool, T> || // setBool
|
||||
|
|
@ -54,12 +51,12 @@ public:
|
|||
|
||||
void setNull();
|
||||
void setBool(bool val);
|
||||
void setNumStr(const std::string& val);
|
||||
void setNumStr(std::string str);
|
||||
void setInt(uint64_t val);
|
||||
void setInt(int64_t val);
|
||||
void setInt(int val_) { return setInt(int64_t{val_}); }
|
||||
void setFloat(double val);
|
||||
void setStr(const std::string& val);
|
||||
void setStr(std::string str);
|
||||
void setArray();
|
||||
void setObject();
|
||||
|
||||
|
|
|
|||
|
|
@ -44,15 +44,15 @@ static bool validNumStr(const std::string& s)
|
|||
return (tt == JTOK_NUMBER);
|
||||
}
|
||||
|
||||
void UniValue::setNumStr(const std::string& val_)
|
||||
void UniValue::setNumStr(std::string str)
|
||||
{
|
||||
if (!validNumStr(val_)) {
|
||||
throw std::runtime_error{"The string '" + val_ + "' is not a valid JSON number"};
|
||||
if (!validNumStr(str)) {
|
||||
throw std::runtime_error{"The string '" + str + "' is not a valid JSON number"};
|
||||
}
|
||||
|
||||
clear();
|
||||
typ = VNUM;
|
||||
val = val_;
|
||||
val = std::move(str);
|
||||
}
|
||||
|
||||
void UniValue::setInt(uint64_t val_)
|
||||
|
|
@ -82,11 +82,11 @@ void UniValue::setFloat(double val_)
|
|||
return setNumStr(oss.str());
|
||||
}
|
||||
|
||||
void UniValue::setStr(const std::string& val_)
|
||||
void UniValue::setStr(std::string str)
|
||||
{
|
||||
clear();
|
||||
typ = VSTR;
|
||||
val = val_;
|
||||
val = std::move(str);
|
||||
}
|
||||
|
||||
void UniValue::setArray()
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#define BOOST_CHECK(expr) assert(expr)
|
||||
|
|
@ -160,6 +161,14 @@ void univalue_set()
|
|||
BOOST_CHECK(v.isStr());
|
||||
BOOST_CHECK_EQUAL(v.getValStr(), "zum");
|
||||
|
||||
{
|
||||
std::string_view sv{"ab\0c", 4};
|
||||
UniValue j{sv};
|
||||
BOOST_CHECK(j.isStr());
|
||||
BOOST_CHECK_EQUAL(j.getValStr(), sv);
|
||||
BOOST_CHECK_EQUAL(j.write(), "\"ab\\u0000c\"");
|
||||
}
|
||||
|
||||
v.setFloat(-1.01);
|
||||
BOOST_CHECK(v.isNum());
|
||||
BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
const std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept;
|
||||
|
||||
/**
|
||||
* MainSignalsImpl manages a list of shared_ptr<CValidationInterface> callbacks.
|
||||
*
|
||||
|
|
@ -215,9 +217,10 @@ void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef& tx, MemP
|
|||
auto event = [tx, reason, mempool_sequence, this] {
|
||||
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionRemovedFromMempool(tx, reason, mempool_sequence); });
|
||||
};
|
||||
ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
|
||||
ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s reason=%s", __func__,
|
||||
tx->GetHash().ToString(),
|
||||
tx->GetWitnessHash().ToString());
|
||||
tx->GetWitnessHash().ToString(),
|
||||
RemovalReasonToString(reason));
|
||||
}
|
||||
|
||||
void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
|
||||
|
|
|
|||
|
|
@ -828,7 +828,7 @@ RPCHelpMan fundrawtransaction()
|
|||
"If that happens, you will need to fund the transaction with different inputs and republish it."},
|
||||
{"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The 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\", and \"bech32\"."},
|
||||
{"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 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
|
||||
|
|
@ -1247,7 +1247,7 @@ RPCHelpMan send()
|
|||
{"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns a serialized transaction which will not be added to the wallet or broadcast"},
|
||||
{"change_address", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The address to receive the change"},
|
||||
{"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\", and \"bech32\"."},
|
||||
{"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."},
|
||||
{"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"
|
||||
|
|
@ -1752,7 +1752,7 @@ RPCHelpMan walletcreatefundedpsbt()
|
|||
"If that happens, you will need to fund the transaction with different inputs and republish it."},
|
||||
{"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The 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\", and \"bech32\"."},
|
||||
{"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"},
|
||||
{"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."},
|
||||
|
|
|
|||
|
|
@ -2509,14 +2509,23 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction&
|
|||
keys->Merge(std::move(*script_keys));
|
||||
} else {
|
||||
// Maybe there are pubkeys listed that we can sign for
|
||||
script_keys = std::make_unique<FlatSigningProvider>();
|
||||
for (const auto& pk_pair : input.hd_keypaths) {
|
||||
const CPubKey& pubkey = pk_pair.first;
|
||||
std::unique_ptr<FlatSigningProvider> pk_keys = GetSigningProvider(pubkey);
|
||||
if (pk_keys) {
|
||||
keys->Merge(std::move(*pk_keys));
|
||||
}
|
||||
std::vector<CPubKey> pubkeys;
|
||||
|
||||
// ECDSA Pubkeys
|
||||
for (const auto& [pk, _] : input.hd_keypaths) {
|
||||
pubkeys.push_back(pk);
|
||||
}
|
||||
|
||||
// Taproot output pubkey
|
||||
std::vector<std::vector<unsigned char>> sols;
|
||||
if (Solver(script, sols) == TxoutType::WITNESS_V1_TAPROOT) {
|
||||
sols[0].insert(sols[0].begin(), 0x02);
|
||||
pubkeys.emplace_back(sols[0]);
|
||||
sols[0][0] = 0x03;
|
||||
pubkeys.emplace_back(sols[0]);
|
||||
}
|
||||
|
||||
// Taproot pubkeys
|
||||
for (const auto& pk_pair : input.m_tap_bip32_paths) {
|
||||
const XOnlyPubKey& pubkey = pk_pair.first;
|
||||
for (unsigned char prefix : {0x02, 0x03}) {
|
||||
|
|
@ -2524,10 +2533,14 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction&
|
|||
std::copy(pubkey.begin(), pubkey.end(), b + 1);
|
||||
CPubKey fullpubkey;
|
||||
fullpubkey.Set(b, b + 33);
|
||||
std::unique_ptr<FlatSigningProvider> pk_keys = GetSigningProvider(fullpubkey);
|
||||
if (pk_keys) {
|
||||
keys->Merge(std::move(*pk_keys));
|
||||
}
|
||||
pubkeys.push_back(fullpubkey);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& pubkey : pubkeys) {
|
||||
std::unique_ptr<FlatSigningProvider> pk_keys = GetSigningProvider(pubkey);
|
||||
if (pk_keys) {
|
||||
keys->Merge(std::move(*pk_keys));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue