From 0f459d868d85053f1cc066ea9099793f88cbd655 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Thu, 15 Nov 2018 17:21:28 -0800 Subject: [PATCH 001/364] fix an undefined behavior in uint::SetHex Decrementing psz beyond the beginning of the string is UB, even though the out-of-bounds pointer is never dereferenced. --- src/uint256.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/uint256.cpp b/src/uint256.cpp index d9da66803604..b164e8678b49 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -37,16 +37,15 @@ void base_blob::SetHex(const char* psz) psz += 2; // hex string to uint - const char* pbegin = psz; - while (::HexDigit(*psz) != -1) - psz++; - psz--; + size_t digits = 0; + while (::HexDigit(psz[digits]) != -1) + digits++; unsigned char* p1 = (unsigned char*)data; unsigned char* pend = p1 + WIDTH; - while (psz >= pbegin && p1 < pend) { - *p1 = ::HexDigit(*psz--); - if (psz >= pbegin) { - *p1 |= ((unsigned char)::HexDigit(*psz--) << 4); + while (digits > 0 && p1 < pend) { + *p1 = ::HexDigit(psz[--digits]); + if (digits > 0) { + *p1 |= ((unsigned char)::HexDigit(psz[--digits]) << 4); p1++; } } From 2290269759ad10cc2e35958c7b0a63f3a7608621 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Wed, 12 Dec 2018 09:45:55 +0100 Subject: [PATCH 002/364] scripted-diff: rename DescriptorImpl m_script_arg to m_subdescriptor_arg -BEGIN VERIFY SCRIPT- sed -i -e 's/m_script_arg/m_subdescriptor_arg/g' src/script/descriptor.cpp -END VERIFY SCRIPT- --- src/script/descriptor.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index a702be5b780e..5f758ab42d4d 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -210,7 +210,7 @@ class DescriptorImpl : public Descriptor //! Public key arguments for this descriptor (size 1 for PK, PKH, WPKH; any size of Multisig). const std::vector> m_pubkey_args; //! The sub-descriptor argument (nullptr for everything but SH and WSH). - const std::unique_ptr m_script_arg; + const std::unique_ptr m_subdescriptor_arg; //! The string name of the descriptor function. const std::string m_name; @@ -221,10 +221,10 @@ class DescriptorImpl : public Descriptor /** A helper function to construct the scripts for this descriptor. * * This function is invoked once for every CScript produced by evaluating - * m_script_arg, or just once in case m_script_arg is nullptr. + * m_subdescriptor_arg, or just once in case m_subdescriptor_arg is nullptr. * @param pubkeys The evaluations of the m_pubkey_args field. - * @param script The evaluation of m_script_arg (or nullptr when m_script_arg is nullptr). + * @param script The evaluation of m_subdescriptor_arg (or nullptr when m_subdescriptor_arg is nullptr). * @param out A FlatSigningProvider to put scripts or public keys in that are necessary to the solver. * The script and pubkeys argument to this function are automatically added. * @return A vector with scriptPubKeys for this descriptor. @@ -232,12 +232,12 @@ class DescriptorImpl : public Descriptor virtual std::vector MakeScripts(const std::vector& pubkeys, const CScript* script, FlatSigningProvider& out) const = 0; public: - DescriptorImpl(std::vector> pubkeys, std::unique_ptr script, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_script_arg(std::move(script)), m_name(name) {} + DescriptorImpl(std::vector> pubkeys, std::unique_ptr script, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_subdescriptor_arg(std::move(script)), m_name(name) {} bool IsSolvable() const override { - if (m_script_arg) { - if (!m_script_arg->IsSolvable()) return false; + if (m_subdescriptor_arg) { + if (!m_subdescriptor_arg->IsSolvable()) return false; } return true; } @@ -247,8 +247,8 @@ class DescriptorImpl : public Descriptor for (const auto& pubkey : m_pubkey_args) { if (pubkey->IsRange()) return true; } - if (m_script_arg) { - if (m_script_arg->IsRange()) return true; + if (m_subdescriptor_arg) { + if (m_subdescriptor_arg->IsRange()) return true; } return false; } @@ -268,10 +268,10 @@ class DescriptorImpl : public Descriptor } ret += std::move(tmp); } - if (m_script_arg) { + if (m_subdescriptor_arg) { if (pos++) ret += ","; std::string tmp; - if (!m_script_arg->ToStringHelper(arg, tmp, priv)) return false; + if (!m_subdescriptor_arg->ToStringHelper(arg, tmp, priv)) return false; ret += std::move(tmp); } out = std::move(ret) + ")"; @@ -311,9 +311,9 @@ class DescriptorImpl : public Descriptor } } std::vector subscripts; - if (m_script_arg) { + if (m_subdescriptor_arg) { FlatSigningProvider subprovider; - if (!m_script_arg->ExpandHelper(pos, arg, cache_read, subscripts, subprovider, cache_write)) return false; + if (!m_subdescriptor_arg->ExpandHelper(pos, arg, cache_read, subscripts, subprovider, cache_write)) return false; out = Merge(out, subprovider); } @@ -324,7 +324,7 @@ class DescriptorImpl : public Descriptor out.origins.emplace(entry.first.GetID(), std::move(entry.second)); out.pubkeys.emplace(entry.first.GetID(), entry.first); } - if (m_script_arg) { + if (m_subdescriptor_arg) { for (const auto& subscript : subscripts) { out.scripts.emplace(CScriptID(subscript), subscript); std::vector addscripts = MakeScripts(pubkeys, &subscript, out); From 2e68ffaf205866e4cea71f64e79bbfb89e17280a Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Wed, 12 Dec 2018 10:08:08 +0100 Subject: [PATCH 003/364] [doc] descriptor: explain GetPubKey() usage with cached public key Plus a few typo fixes. --- src/script/descriptor.cpp | 6 +++++- src/script/descriptor.h | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 5f758ab42d4d..96cd93df5a59 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -207,9 +207,11 @@ class BIP32PubkeyProvider final : public PubkeyProvider /** Base class for all Descriptor implementations. */ class DescriptorImpl : public Descriptor { - //! Public key arguments for this descriptor (size 1 for PK, PKH, WPKH; any size of Multisig). + //! Public key arguments for this descriptor (size 1 for PK, PKH, WPKH; any size for Multisig). const std::vector> m_pubkey_args; //! The sub-descriptor argument (nullptr for everything but SH and WSH). + //! In doc/descriptors.m this is referred to as SCRIPT expressions sh(SCRIPT) + //! and wsh(SCRIPT), and distinct from KEY expressions and ADDR expressions. const std::unique_ptr m_subdescriptor_arg; //! The string name of the descriptor function. const std::string m_name; @@ -295,6 +297,8 @@ class DescriptorImpl : public Descriptor // Construct temporary data in `entries` and `subscripts`, to avoid producing output in case of failure. for (const auto& p : m_pubkey_args) { entries.emplace_back(); + // If we have a cache, we don't need GetPubKey to compute the public key. + // Pass in nullptr to signify only origin info is desired. if (!p->GetPubKey(pos, arg, cache_read ? nullptr : &entries.back().first, entries.back().second)) return false; if (cache_read) { // Cached expanded public key exists, use it. diff --git a/src/script/descriptor.h b/src/script/descriptor.h index 44f0efca03e9..2be157b86174 100644 --- a/src/script/descriptor.h +++ b/src/script/descriptor.h @@ -46,9 +46,9 @@ struct Descriptor { * * pos: the position at which to expand the descriptor. If IsRange() is false, this is ignored. * provider: the provider to query for private keys in case of hardened derivation. - * output_script: the expanded scriptPubKeys will be put here. + * output_scripts: the expanded scriptPubKeys will be put here. * out: scripts and public keys necessary for solving the expanded scriptPubKeys will be put here (may be equal to provider). - * cache: vector which will be overwritten with cache data necessary to-evaluate the descriptor at this point without access to private keys. + * cache: vector which will be overwritten with cache data necessary to evaluate the descriptor at this point without access to private keys. */ virtual bool Expand(int pos, const SigningProvider& provider, std::vector& output_scripts, FlatSigningProvider& out, std::vector* cache = nullptr) const = 0; @@ -56,7 +56,7 @@ struct Descriptor { * * pos: the position at which to expand the descriptor. If IsRange() is false, this is ignored. * cache: vector from which cached expansion data will be read. - * output_script: the expanded scriptPubKeys will be put here. + * output_scripts: the expanded scriptPubKeys will be put here. * out: scripts and public keys necessary for solving the expanded scriptPubKeys will be put here (may be equal to provider). */ virtual bool ExpandFromCache(int pos, const std::vector& cache, std::vector& output_scripts, FlatSigningProvider& out) const = 0; From 276972cb95ba944a7a4b1858a08d333962261396 Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Tue, 5 Mar 2019 11:04:32 -0500 Subject: [PATCH 004/364] wallet_bumpfee.py: Make sure coin selection produces change --- test/functional/wallet_bumpfee.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index 7d3d9b61e276..3bef70f0a06a 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -260,7 +260,9 @@ def test_unconfirmed_not_spendable(rbf_node, rbf_node_address): def test_bumpfee_metadata(rbf_node, dest_address): - rbfid = rbf_node.sendtoaddress(dest_address, Decimal("0.00100000"), "comment value", "to value") + assert(rbf_node.getbalance() < 49) + rbf_node.generatetoaddress(101, rbf_node.getnewaddress()) + rbfid = rbf_node.sendtoaddress(dest_address, 49, "comment value", "to value") bumped_tx = rbf_node.bumpfee(rbfid) bumped_wtx = rbf_node.gettransaction(bumped_tx["txid"]) assert_equal(bumped_wtx["comment"], "comment value") From eaf4f887348a08c620732125ad4430e1a133d434 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 16 Feb 2019 14:18:54 -0800 Subject: [PATCH 005/364] Abstract out IsSegWitOutput from utxoupdatepsbt This is not a pure refactor; additional functionality is added in IsSegWitOutput which lets it recurse into P2SH when a SigningProvider is provided that knows about the inner script. --- src/rpc/rawtransaction.cpp | 4 +--- src/script/sign.cpp | 16 ++++++++++++++++ src/script/sign.h | 3 +++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index b3926786db43..7675ad010907 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1540,9 +1540,7 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request) const Coin& coin = view.AccessCoin(psbtx.tx->vin[i].prevout); - std::vector> solutions_data; - txnouttype which_type = Solver(coin.out.scriptPubKey, solutions_data); - if (which_type == TX_WITNESS_V0_SCRIPTHASH || which_type == TX_WITNESS_V0_KEYHASH || which_type == TX_WITNESS_UNKNOWN) { + if (IsSegWitOutput(DUMMY_SIGNING_PROVIDER, coin.out.scriptPubKey)) { input.witness_utxo = coin.out; } } diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 36dd68a3d8b1..5320dc08766c 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -505,3 +505,19 @@ FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvide ret.origins.insert(b.origins.begin(), b.origins.end()); return ret; } + +bool IsSegWitOutput(const SigningProvider& provider, const CScript& script) +{ + std::vector solutions; + auto whichtype = Solver(script, solutions); + if (whichtype == TX_WITNESS_V0_SCRIPTHASH || whichtype == TX_WITNESS_V0_KEYHASH || whichtype == TX_WITNESS_UNKNOWN) return true; + if (whichtype == TX_SCRIPTHASH) { + auto h160 = uint160(solutions[0]); + CScript subscript; + if (provider.GetCScript(h160, subscript)) { + whichtype = Solver(subscript, solutions); + if (whichtype == TX_WITNESS_V0_SCRIPTHASH || whichtype == TX_WITNESS_V0_KEYHASH || whichtype == TX_WITNESS_UNKNOWN) return true; + } + } + return false; +} diff --git a/src/script/sign.h b/src/script/sign.h index f746325b90e7..e5c0329a6109 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -232,4 +232,7 @@ void UpdateInput(CTxIn& input, const SignatureData& data); * Solvability is unrelated to whether we consider this output to be ours. */ bool IsSolvable(const SigningProvider& provider, const CScript& script); +/** Check whether a scriptPubKey is known to be segwit. */ +bool IsSegWitOutput(const SigningProvider& provider, const CScript& script); + #endif // BITCOIN_SCRIPT_SIGN_H From fb90ec3c33e824f5abb6a68452c683d6ce8b3e4a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 16 Feb 2019 15:24:15 -0800 Subject: [PATCH 006/364] Abstract out EvalDescriptorStringOrObject from scantxoutset --- src/rpc/blockchain.cpp | 39 +++++---------------------------------- src/rpc/util.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/rpc/util.h | 5 +++++ 3 files changed, 48 insertions(+), 34 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index b8ef75866149..01c32656566b 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -2241,41 +2241,12 @@ UniValue scantxoutset(const JSONRPCRequest& request) // loop through the scan objects for (const UniValue& scanobject : request.params[1].get_array().getValues()) { - std::string desc_str; - std::pair range = {0, 1000}; - if (scanobject.isStr()) { - desc_str = scanobject.get_str(); - } else if (scanobject.isObject()) { - UniValue desc_uni = find_value(scanobject, "desc"); - if (desc_uni.isNull()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor needs to be provided in scan object"); - desc_str = desc_uni.get_str(); - UniValue range_uni = find_value(scanobject, "range"); - if (!range_uni.isNull()) { - range = ParseDescriptorRange(range_uni); - } - } else { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan object needs to be either a string or an object"); - } - FlatSigningProvider provider; - auto desc = Parse(desc_str, provider); - if (!desc) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid descriptor '%s'", desc_str)); - } - if (!desc->IsRange()) { - range.first = 0; - range.second = 0; - } - for (int i = range.first; i <= range.second; ++i) { - std::vector scripts; - if (!desc->Expand(i, provider, scripts, provider)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys: '%s'", desc_str)); - } - for (const auto& script : scripts) { - std::string inferred = InferDescriptor(script, provider)->ToString(); - needles.emplace(script); - descriptors.emplace(std::move(script), std::move(inferred)); - } + auto scripts = EvalDescriptorStringOrObject(scanobject, provider); + for (const auto& script : scripts) { + std::string inferred = InferDescriptor(script, provider)->ToString(); + needles.emplace(script); + descriptors.emplace(std::move(script), std::move(inferred)); } } diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 9cdb22001fd9..7a9312aa0372 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -5,6 +5,7 @@ #include #include #include +#include