diff options
Diffstat (limited to 'src/script')
-rw-r--r-- | src/script/descriptor.cpp | 48 | ||||
-rw-r--r-- | src/script/descriptor.h | 8 | ||||
-rw-r--r-- | src/script/ismine.cpp | 193 | ||||
-rw-r--r-- | src/script/ismine.h | 51 | ||||
-rw-r--r-- | src/script/script.cpp | 1 | ||||
-rw-r--r-- | src/script/sigcache.cpp | 1 | ||||
-rw-r--r-- | src/script/standard.cpp | 2 |
7 files changed, 48 insertions, 256 deletions
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 9be87fabb0..50119ba184 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -164,6 +164,9 @@ struct PubkeyProvider /** Get the descriptor string form including private data (if available in arg). */ virtual bool ToPrivateString(const SigningProvider& arg, std::string& out) const = 0; + + /** Derive a private key, if private data is available in arg. */ + virtual bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const = 0; }; class OriginPubkeyProvider final : public PubkeyProvider @@ -195,6 +198,10 @@ public: ret = "[" + OriginString() + "]" + std::move(sub); return true; } + bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override + { + return m_provider->GetPrivKey(pos, arg, key); + } }; /** An object representing a parsed constant public key in a descriptor. */ @@ -222,6 +229,10 @@ public: ret = EncodeSecret(key); return true; } + bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override + { + return arg.GetKey(m_pubkey.GetID(), key); + } }; enum class DeriveType { @@ -266,14 +277,9 @@ public: { if (key) { if (IsHardened()) { - CExtKey extkey; - if (!GetExtKey(arg, extkey)) return false; - for (auto entry : m_path) { - extkey.Derive(extkey, entry); - } - if (m_derive == DeriveType::UNHARDENED) extkey.Derive(extkey, pos); - if (m_derive == DeriveType::HARDENED) extkey.Derive(extkey, pos | 0x80000000UL); - *key = extkey.Neuter().pubkey; + CKey priv_key; + if (!GetPrivKey(pos, arg, priv_key)) return false; + *key = priv_key.GetPubKey(); } else { // TODO: optimize by caching CExtPubKey extkey = m_extkey; @@ -312,6 +318,18 @@ public: } return true; } + bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override + { + CExtKey extkey; + if (!GetExtKey(arg, extkey)) return false; + for (auto entry : m_path) { + extkey.Derive(extkey, entry); + } + if (m_derive == DeriveType::UNHARDENED) extkey.Derive(extkey, pos); + if (m_derive == DeriveType::HARDENED) extkey.Derive(extkey, pos | 0x80000000UL); + key = extkey.key; + return true; + } }; /** Base class for all Descriptor implementations. */ @@ -462,6 +480,20 @@ public: Span<const unsigned char> span = MakeSpan(cache); return ExpandHelper(pos, DUMMY_SIGNING_PROVIDER, &span, output_scripts, out, nullptr) && span.size() == 0; } + + void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const final + { + for (const auto& p : m_pubkey_args) { + CKey key; + if (!p->GetPrivKey(pos, provider, key)) continue; + out.keys.emplace(key.GetPubKey().GetID(), key); + } + if (m_script_arg) { + FlatSigningProvider subprovider; + m_script_arg->ExpandPrivate(pos, provider, subprovider); + out = Merge(out, subprovider); + } + } }; /** Construct a vector with one element, which is moved into it. */ diff --git a/src/script/descriptor.h b/src/script/descriptor.h index 907a102284..af7ae229ca 100644 --- a/src/script/descriptor.h +++ b/src/script/descriptor.h @@ -60,6 +60,14 @@ struct Descriptor { * 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<unsigned char>& cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const = 0; + + /** Expand the private key for a descriptor at a specified position, if possible. + * + * pos: the position at which to expand the descriptor. If IsRange() is false, this is ignored. + * provider: the provider to query for the private keys. + * out: any private keys available for the specified pos will be placed here. + */ + virtual void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const = 0; }; /** Parse a descriptor string. Included private keys are put in out. diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp deleted file mode 100644 index 75fc2e84f1..0000000000 --- a/src/script/ismine.cpp +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include <script/ismine.h> - -#include <key.h> -#include <keystore.h> -#include <script/script.h> -#include <script/sign.h> - - -typedef std::vector<unsigned char> valtype; - -namespace { - -/** - * This is an enum that tracks the execution context of a script, similar to - * SigVersion in script/interpreter. It is separate however because we want to - * distinguish between top-level scriptPubKey execution and P2SH redeemScript - * execution (a distinction that has no impact on consensus rules). - */ -enum class IsMineSigVersion -{ - TOP = 0, //!< scriptPubKey execution - P2SH = 1, //!< P2SH redeemScript - WITNESS_V0 = 2, //!< P2WSH witness script execution -}; - -/** - * This is an internal representation of isminetype + invalidity. - * Its order is significant, as we return the max of all explored - * possibilities. - */ -enum class IsMineResult -{ - NO = 0, //!< Not ours - WATCH_ONLY = 1, //!< Included in watch-only balance - SPENDABLE = 2, //!< Included in all balances - INVALID = 3, //!< Not spendable by anyone (uncompressed pubkey in segwit, P2SH inside P2SH or witness, witness inside witness) -}; - -bool PermitsUncompressed(IsMineSigVersion sigversion) -{ - return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH; -} - -bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore) -{ - for (const valtype& pubkey : pubkeys) { - CKeyID keyID = CPubKey(pubkey).GetID(); - if (!keystore.HaveKey(keyID)) return false; - } - return true; -} - -IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion) -{ - IsMineResult ret = IsMineResult::NO; - - std::vector<valtype> vSolutions; - txnouttype whichType = Solver(scriptPubKey, vSolutions); - - CKeyID keyID; - switch (whichType) - { - case TX_NONSTANDARD: - case TX_NULL_DATA: - case TX_WITNESS_UNKNOWN: - break; - case TX_PUBKEY: - keyID = CPubKey(vSolutions[0]).GetID(); - if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) { - return IsMineResult::INVALID; - } - if (keystore.HaveKey(keyID)) { - ret = std::max(ret, IsMineResult::SPENDABLE); - } - break; - case TX_WITNESS_V0_KEYHASH: - { - if (sigversion == IsMineSigVersion::WITNESS_V0) { - // P2WPKH inside P2WSH is invalid. - return IsMineResult::INVALID; - } - if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) { - // We do not support bare witness outputs unless the P2SH version of it would be - // acceptable as well. This protects against matching before segwit activates. - // This also applies to the P2WSH case. - break; - } - ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(PKHash(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0)); - break; - } - case TX_PUBKEYHASH: - keyID = CKeyID(uint160(vSolutions[0])); - if (!PermitsUncompressed(sigversion)) { - CPubKey pubkey; - if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) { - return IsMineResult::INVALID; - } - } - if (keystore.HaveKey(keyID)) { - ret = std::max(ret, IsMineResult::SPENDABLE); - } - break; - case TX_SCRIPTHASH: - { - if (sigversion != IsMineSigVersion::TOP) { - // P2SH inside P2WSH or P2SH is invalid. - return IsMineResult::INVALID; - } - CScriptID scriptID = CScriptID(uint160(vSolutions[0])); - CScript subscript; - if (keystore.GetCScript(scriptID, subscript)) { - ret = std::max(ret, IsMineInner(keystore, subscript, IsMineSigVersion::P2SH)); - } - break; - } - case TX_WITNESS_V0_SCRIPTHASH: - { - if (sigversion == IsMineSigVersion::WITNESS_V0) { - // P2WSH inside P2WSH is invalid. - return IsMineResult::INVALID; - } - if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) { - break; - } - uint160 hash; - CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(hash.begin()); - CScriptID scriptID = CScriptID(hash); - CScript subscript; - if (keystore.GetCScript(scriptID, subscript)) { - ret = std::max(ret, IsMineInner(keystore, subscript, IsMineSigVersion::WITNESS_V0)); - } - break; - } - - case TX_MULTISIG: - { - // Never treat bare multisig outputs as ours (they can still be made watchonly-though) - if (sigversion == IsMineSigVersion::TOP) { - break; - } - - // Only consider transactions "mine" if we own ALL the - // keys involved. Multi-signature transactions that are - // partially owned (somebody else has a key that can spend - // them) enable spend-out-from-under-you attacks, especially - // in shared-wallet situations. - std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); - if (!PermitsUncompressed(sigversion)) { - for (size_t i = 0; i < keys.size(); i++) { - if (keys[i].size() != 33) { - return IsMineResult::INVALID; - } - } - } - if (HaveKeys(keys, keystore)) { - ret = std::max(ret, IsMineResult::SPENDABLE); - } - break; - } - } - - if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) { - ret = std::max(ret, IsMineResult::WATCH_ONLY); - } - return ret; -} - -} // namespace - -isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey) -{ - switch (IsMineInner(keystore, scriptPubKey, IsMineSigVersion::TOP)) { - case IsMineResult::INVALID: - case IsMineResult::NO: - return ISMINE_NO; - case IsMineResult::WATCH_ONLY: - return ISMINE_WATCH_ONLY; - case IsMineResult::SPENDABLE: - return ISMINE_SPENDABLE; - } - assert(false); -} - -isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest) -{ - CScript script = GetScriptForDestination(dest); - return IsMine(keystore, script); -} diff --git a/src/script/ismine.h b/src/script/ismine.h deleted file mode 100644 index 55e28e225a..0000000000 --- a/src/script/ismine.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_SCRIPT_ISMINE_H -#define BITCOIN_SCRIPT_ISMINE_H - -#include <script/standard.h> - -#include <stdint.h> -#include <bitset> - -class CKeyStore; -class CScript; - -/** IsMine() return codes */ -enum isminetype -{ - ISMINE_NO = 0, - ISMINE_WATCH_ONLY = 1 << 0, - ISMINE_SPENDABLE = 1 << 1, - ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE, - ISMINE_ENUM_ELEMENTS, -}; -/** used for bitflags of isminetype */ -typedef uint8_t isminefilter; - -isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey); -isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest); - -/** - * Cachable amount subdivided into watchonly and spendable parts. - */ -struct CachableAmount -{ - // NO and ALL are never (supposed to be) cached - std::bitset<ISMINE_ENUM_ELEMENTS> m_cached; - CAmount m_value[ISMINE_ENUM_ELEMENTS]; - inline void Reset() - { - m_cached.reset(); - } - void Set(isminefilter filter, CAmount value) - { - m_cached.set(filter); - m_value[filter] = value; - } -}; - -#endif // BITCOIN_SCRIPT_ISMINE_H diff --git a/src/script/script.cpp b/src/script/script.cpp index 982aa241e7..0666a385d1 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -5,7 +5,6 @@ #include <script/script.h> -#include <tinyformat.h> #include <util/strencodings.h> const char* GetOpName(opcodetype opcode) diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index 94005cf6f3..eaf5363bd7 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -5,7 +5,6 @@ #include <script/sigcache.h> -#include <memusage.h> #include <pubkey.h> #include <random.h> #include <uint256.h> diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 91a301bcdf..b7d6cd925c 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -8,8 +8,6 @@ #include <crypto/sha256.h> #include <pubkey.h> #include <script/script.h> -#include <util/system.h> -#include <util/strencodings.h> typedef std::vector<unsigned char> valtype; |