diff options
Diffstat (limited to 'src/script')
-rw-r--r-- | src/script/bitcoinconsensus.cpp | 6 | ||||
-rw-r--r-- | src/script/bitcoinconsensus.h | 2 | ||||
-rw-r--r-- | src/script/descriptor.cpp | 566 | ||||
-rw-r--r-- | src/script/descriptor.h | 55 | ||||
-rw-r--r-- | src/script/interpreter.cpp | 62 | ||||
-rw-r--r-- | src/script/interpreter.h | 27 | ||||
-rw-r--r-- | src/script/ismine.cpp | 103 | ||||
-rw-r--r-- | src/script/ismine.h | 16 | ||||
-rw-r--r-- | src/script/script.cpp | 7 | ||||
-rw-r--r-- | src/script/script.h | 9 | ||||
-rw-r--r-- | src/script/script_error.cpp | 2 | ||||
-rw-r--r-- | src/script/script_error.h | 2 | ||||
-rw-r--r-- | src/script/sigcache.cpp | 2 | ||||
-rw-r--r-- | src/script/sigcache.h | 2 | ||||
-rw-r--r-- | src/script/sign.cpp | 705 | ||||
-rw-r--r-- | src/script/sign.h | 673 | ||||
-rw-r--r-- | src/script/standard.cpp | 205 | ||||
-rw-r--r-- | src/script/standard.h | 8 |
18 files changed, 1966 insertions, 486 deletions
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp index 8cc44b675f..15e204062f 100644 --- a/src/script/bitcoinconsensus.cpp +++ b/src/script/bitcoinconsensus.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// 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. @@ -81,14 +81,14 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err) { if (!verify_flags(flags)) { - return bitcoinconsensus_ERR_INVALID_FLAGS; + return set_error(err, bitcoinconsensus_ERR_INVALID_FLAGS); } try { TxInputStream stream(SER_NETWORK, PROTOCOL_VERSION, txTo, txToLen); CTransaction tx(deserialize, stream); if (nIn >= tx.vin.size()) return set_error(err, bitcoinconsensus_ERR_TX_INDEX); - if (GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) != txToLen) + if (GetSerializeSize(tx, PROTOCOL_VERSION) != txToLen) return set_error(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH); // Regardless of the verification result, the tx did not error. diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h index 5973808fa5..c5dceac848 100644 --- a/src/script/bitcoinconsensus.h +++ b/src/script/bitcoinconsensus.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// 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. diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp new file mode 100644 index 0000000000..45b097dde6 --- /dev/null +++ b/src/script/descriptor.cpp @@ -0,0 +1,566 @@ +// Copyright (c) 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/descriptor.h> + +#include <key_io.h> +#include <pubkey.h> +#include <script/script.h> +#include <script/standard.h> + +#include <span.h> +#include <util.h> +#include <utilstrencodings.h> + +#include <memory> +#include <string> +#include <vector> + +namespace { + +//////////////////////////////////////////////////////////////////////////// +// Internal representation // +//////////////////////////////////////////////////////////////////////////// + +typedef std::vector<uint32_t> KeyPath; + +std::string FormatKeyPath(const KeyPath& path) +{ + std::string ret; + for (auto i : path) { + ret += strprintf("/%i", (i << 1) >> 1); + if (i >> 31) ret += '\''; + } + return ret; +} + +/** Interface for public key objects in descriptors. */ +struct PubkeyProvider +{ + virtual ~PubkeyProvider() = default; + + /** Derive a public key. */ + virtual bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& out) const = 0; + + /** Whether this represent multiple public keys at different positions. */ + virtual bool IsRange() const = 0; + + /** Get the size of the generated public key(s) in bytes (33 or 65). */ + virtual size_t GetSize() const = 0; + + /** Get the descriptor string form. */ + virtual std::string ToString() const = 0; + + /** Get the descriptor string form including private data (if available in arg). */ + virtual bool ToPrivateString(const SigningProvider& arg, std::string& out) const = 0; +}; + +/** An object representing a parsed constant public key in a descriptor. */ +class ConstPubkeyProvider final : public PubkeyProvider +{ + CPubKey m_pubkey; + +public: + ConstPubkeyProvider(const CPubKey& pubkey) : m_pubkey(pubkey) {} + bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& out) const override + { + out = m_pubkey; + return true; + } + bool IsRange() const override { return false; } + size_t GetSize() const override { return m_pubkey.size(); } + std::string ToString() const override { return HexStr(m_pubkey.begin(), m_pubkey.end()); } + bool ToPrivateString(const SigningProvider& arg, std::string& ret) const override + { + CKey key; + if (!arg.GetKey(m_pubkey.GetID(), key)) return false; + ret = EncodeSecret(key); + return true; + } +}; + +enum class DeriveType { + NO, + UNHARDENED, + HARDENED, +}; + +/** An object representing a parsed extended public key in a descriptor. */ +class BIP32PubkeyProvider final : public PubkeyProvider +{ + CExtPubKey m_extkey; + KeyPath m_path; + DeriveType m_derive; + + bool GetExtKey(const SigningProvider& arg, CExtKey& ret) const + { + CKey key; + if (!arg.GetKey(m_extkey.pubkey.GetID(), key)) return false; + ret.nDepth = m_extkey.nDepth; + std::copy(m_extkey.vchFingerprint, m_extkey.vchFingerprint + 4, ret.vchFingerprint); + ret.nChild = m_extkey.nChild; + ret.chaincode = m_extkey.chaincode; + ret.key = key; + return true; + } + + bool IsHardened() const + { + if (m_derive == DeriveType::HARDENED) return true; + for (auto entry : m_path) { + if (entry >> 31) return true; + } + return false; + } + +public: + BIP32PubkeyProvider(const CExtPubKey& extkey, KeyPath path, DeriveType derive) : m_extkey(extkey), m_path(std::move(path)), m_derive(derive) {} + bool IsRange() const override { return m_derive != DeriveType::NO; } + size_t GetSize() const override { return 33; } + bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& out) const override + { + if (IsHardened()) { + CExtKey key; + if (!GetExtKey(arg, key)) return false; + for (auto entry : m_path) { + key.Derive(key, entry); + } + if (m_derive == DeriveType::UNHARDENED) key.Derive(key, pos); + if (m_derive == DeriveType::HARDENED) key.Derive(key, pos | 0x80000000UL); + out = key.Neuter().pubkey; + } else { + // TODO: optimize by caching + CExtPubKey key = m_extkey; + for (auto entry : m_path) { + key.Derive(key, entry); + } + if (m_derive == DeriveType::UNHARDENED) key.Derive(key, pos); + assert(m_derive != DeriveType::HARDENED); + out = key.pubkey; + } + return true; + } + std::string ToString() const override + { + std::string ret = EncodeExtPubKey(m_extkey) + FormatKeyPath(m_path); + if (IsRange()) { + ret += "/*"; + if (m_derive == DeriveType::HARDENED) ret += '\''; + } + return ret; + } + bool ToPrivateString(const SigningProvider& arg, std::string& out) const override + { + CExtKey key; + if (!GetExtKey(arg, key)) return false; + out = EncodeExtKey(key) + FormatKeyPath(m_path); + if (IsRange()) { + out += "/*"; + if (m_derive == DeriveType::HARDENED) out += '\''; + } + return true; + } +}; + +/** A parsed addr(A) descriptor. */ +class AddressDescriptor final : public Descriptor +{ + CTxDestination m_destination; + +public: + AddressDescriptor(CTxDestination destination) : m_destination(std::move(destination)) {} + + bool IsRange() const override { return false; } + std::string ToString() const override { return "addr(" + EncodeDestination(m_destination) + ")"; } + bool ToPrivateString(const SigningProvider& arg, std::string& out) const override { out = ToString(); return true; } + bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override + { + output_scripts = std::vector<CScript>{GetScriptForDestination(m_destination)}; + return true; + } +}; + +/** A parsed raw(H) descriptor. */ +class RawDescriptor final : public Descriptor +{ + CScript m_script; + +public: + RawDescriptor(CScript script) : m_script(std::move(script)) {} + + bool IsRange() const override { return false; } + std::string ToString() const override { return "raw(" + HexStr(m_script.begin(), m_script.end()) + ")"; } + bool ToPrivateString(const SigningProvider& arg, std::string& out) const override { out = ToString(); return true; } + bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override + { + output_scripts = std::vector<CScript>{m_script}; + return true; + } +}; + +/** A parsed pk(P), pkh(P), or wpkh(P) descriptor. */ +class SingleKeyDescriptor final : public Descriptor +{ + const std::function<CScript(const CPubKey&)> m_script_fn; + const std::string m_fn_name; + std::unique_ptr<PubkeyProvider> m_provider; + +public: + SingleKeyDescriptor(std::unique_ptr<PubkeyProvider> prov, const std::function<CScript(const CPubKey&)>& fn, const std::string& name) : m_script_fn(fn), m_fn_name(name), m_provider(std::move(prov)) {} + + bool IsRange() const override { return m_provider->IsRange(); } + std::string ToString() const override { return m_fn_name + "(" + m_provider->ToString() + ")"; } + bool ToPrivateString(const SigningProvider& arg, std::string& out) const override + { + std::string ret; + if (!m_provider->ToPrivateString(arg, ret)) return false; + out = m_fn_name + "(" + std::move(ret) + ")"; + return true; + } + bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override + { + CPubKey key; + if (!m_provider->GetPubKey(pos, arg, key)) return false; + output_scripts = std::vector<CScript>{m_script_fn(key)}; + out.pubkeys.emplace(key.GetID(), std::move(key)); + return true; + } +}; + +CScript P2PKHGetScript(const CPubKey& pubkey) { return GetScriptForDestination(pubkey.GetID()); } +CScript P2PKGetScript(const CPubKey& pubkey) { return GetScriptForRawPubKey(pubkey); } +CScript P2WPKHGetScript(const CPubKey& pubkey) { return GetScriptForDestination(WitnessV0KeyHash(pubkey.GetID())); } + +/** A parsed multi(...) descriptor. */ +class MultisigDescriptor : public Descriptor +{ + int m_threshold; + std::vector<std::unique_ptr<PubkeyProvider>> m_providers; + +public: + MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers) : m_threshold(threshold), m_providers(std::move(providers)) {} + + bool IsRange() const override + { + for (const auto& p : m_providers) { + if (p->IsRange()) return true; + } + return false; + } + + std::string ToString() const override + { + std::string ret = strprintf("multi(%i", m_threshold); + for (const auto& p : m_providers) { + ret += "," + p->ToString(); + } + return std::move(ret) + ")"; + } + + bool ToPrivateString(const SigningProvider& arg, std::string& out) const override + { + std::string ret = strprintf("multi(%i", m_threshold); + for (const auto& p : m_providers) { + std::string sub; + if (!p->ToPrivateString(arg, sub)) return false; + ret += "," + std::move(sub); + } + out = std::move(ret) + ")"; + return true; + } + + bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override + { + std::vector<CPubKey> pubkeys; + pubkeys.reserve(m_providers.size()); + for (const auto& p : m_providers) { + CPubKey key; + if (!p->GetPubKey(pos, arg, key)) return false; + pubkeys.push_back(key); + } + for (const CPubKey& key : pubkeys) { + out.pubkeys.emplace(key.GetID(), std::move(key)); + } + output_scripts = std::vector<CScript>{GetScriptForMultisig(m_threshold, pubkeys)}; + return true; + } +}; + +/** A parsed sh(S) or wsh(S) descriptor. */ +class ConvertorDescriptor : public Descriptor +{ + const std::function<CScript(const CScript&)> m_convert_fn; + const std::string m_fn_name; + std::unique_ptr<Descriptor> m_descriptor; + +public: + ConvertorDescriptor(std::unique_ptr<Descriptor> descriptor, const std::function<CScript(const CScript&)>& fn, const std::string& name) : m_convert_fn(fn), m_fn_name(name), m_descriptor(std::move(descriptor)) {} + + bool IsRange() const override { return m_descriptor->IsRange(); } + std::string ToString() const override { return m_fn_name + "(" + m_descriptor->ToString() + ")"; } + bool ToPrivateString(const SigningProvider& arg, std::string& out) const override + { + std::string ret; + if (!m_descriptor->ToPrivateString(arg, ret)) return false; + out = m_fn_name + "(" + std::move(ret) + ")"; + return true; + } + bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override + { + std::vector<CScript> sub; + if (!m_descriptor->Expand(pos, arg, sub, out)) return false; + output_scripts.clear(); + for (const auto& script : sub) { + CScriptID id(script); + out.scripts.emplace(CScriptID(script), script); + output_scripts.push_back(m_convert_fn(script)); + } + return true; + } +}; + +CScript ConvertP2SH(const CScript& script) { return GetScriptForDestination(CScriptID(script)); } +CScript ConvertP2WSH(const CScript& script) { return GetScriptForDestination(WitnessV0ScriptHash(script)); } + +/** A parsed combo(P) descriptor. */ +class ComboDescriptor final : public Descriptor +{ + std::unique_ptr<PubkeyProvider> m_provider; + +public: + ComboDescriptor(std::unique_ptr<PubkeyProvider> provider) : m_provider(std::move(provider)) {} + + bool IsRange() const override { return m_provider->IsRange(); } + std::string ToString() const override { return "combo(" + m_provider->ToString() + ")"; } + bool ToPrivateString(const SigningProvider& arg, std::string& out) const override + { + std::string ret; + if (!m_provider->ToPrivateString(arg, ret)) return false; + out = "combo(" + std::move(ret) + ")"; + return true; + } + bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override + { + CPubKey key; + if (!m_provider->GetPubKey(pos, arg, key)) return false; + CKeyID keyid = key.GetID(); + { + CScript p2pk = GetScriptForRawPubKey(key); + CScript p2pkh = GetScriptForDestination(keyid); + output_scripts = std::vector<CScript>{std::move(p2pk), std::move(p2pkh)}; + out.pubkeys.emplace(keyid, key); + } + if (key.IsCompressed()) { + CScript p2wpkh = GetScriptForDestination(WitnessV0KeyHash(keyid)); + CScriptID p2wpkh_id(p2wpkh); + CScript p2sh_p2wpkh = GetScriptForDestination(p2wpkh_id); + out.scripts.emplace(p2wpkh_id, p2wpkh); + output_scripts.push_back(std::move(p2wpkh)); + output_scripts.push_back(std::move(p2sh_p2wpkh)); + } + return true; + } +}; + +//////////////////////////////////////////////////////////////////////////// +// Parser // +//////////////////////////////////////////////////////////////////////////// + +enum class ParseScriptContext { + TOP, + P2SH, + P2WSH, +}; + +/** Parse a constant. If successful, sp is updated to skip the constant and return true. */ +bool Const(const std::string& str, Span<const char>& sp) +{ + if ((size_t)sp.size() >= str.size() && std::equal(str.begin(), str.end(), sp.begin())) { + sp = sp.subspan(str.size()); + return true; + } + return false; +} + +/** Parse a function call. If successful, sp is updated to be the function's argument(s). */ +bool Func(const std::string& str, Span<const char>& sp) +{ + if ((size_t)sp.size() >= str.size() + 2 && sp[str.size()] == '(' && sp[sp.size() - 1] == ')' && std::equal(str.begin(), str.end(), sp.begin())) { + sp = sp.subspan(str.size() + 1, sp.size() - str.size() - 2); + return true; + } + return false; +} + +/** Return the expression that sp begins with, and update sp to skip it. */ +Span<const char> Expr(Span<const char>& sp) +{ + int level = 0; + auto it = sp.begin(); + while (it != sp.end()) { + if (*it == '(') { + ++level; + } else if (level && *it == ')') { + --level; + } else if (level == 0 && (*it == ')' || *it == ',')) { + break; + } + ++it; + } + Span<const char> ret = sp.first(it - sp.begin()); + sp = sp.subspan(it - sp.begin()); + return ret; +} + +/** Split a string on every instance of sep, returning a vector. */ +std::vector<Span<const char>> Split(const Span<const char>& sp, char sep) +{ + std::vector<Span<const char>> ret; + auto it = sp.begin(); + auto start = it; + while (it != sp.end()) { + if (*it == sep) { + ret.emplace_back(start, it); + start = it + 1; + } + ++it; + } + ret.emplace_back(start, it); + return ret; +} + +/** Parse a key path, being passed a split list of elements (the first element is ignored). */ +bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out) +{ + for (size_t i = 1; i < split.size(); ++i) { + Span<const char> elem = split[i]; + bool hardened = false; + if (elem.size() > 0 && (elem[elem.size() - 1] == '\'' || elem[elem.size() - 1] == 'h')) { + elem = elem.first(elem.size() - 1); + hardened = true; + } + uint32_t p; + if (!ParseUInt32(std::string(elem.begin(), elem.end()), &p) || p > 0x7FFFFFFFUL) return false; + out.push_back(p | (((uint32_t)hardened) << 31)); + } + return true; +} + +std::unique_ptr<PubkeyProvider> ParsePubkey(const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out) +{ + auto split = Split(sp, '/'); + std::string str(split[0].begin(), split[0].end()); + if (split.size() == 1) { + if (IsHex(str)) { + std::vector<unsigned char> data = ParseHex(str); + CPubKey pubkey(data); + if (pubkey.IsFullyValid() && (permit_uncompressed || pubkey.IsCompressed())) return MakeUnique<ConstPubkeyProvider>(pubkey); + } + CKey key = DecodeSecret(str); + if (key.IsValid() && (permit_uncompressed || key.IsCompressed())) { + CPubKey pubkey = key.GetPubKey(); + out.keys.emplace(pubkey.GetID(), key); + return MakeUnique<ConstPubkeyProvider>(pubkey); + } + } + CExtKey extkey = DecodeExtKey(str); + CExtPubKey extpubkey = DecodeExtPubKey(str); + if (!extkey.key.IsValid() && !extpubkey.pubkey.IsValid()) return nullptr; + KeyPath path; + DeriveType type = DeriveType::NO; + if (split.back() == MakeSpan("*").first(1)) { + split.pop_back(); + type = DeriveType::UNHARDENED; + } else if (split.back() == MakeSpan("*'").first(2) || split.back() == MakeSpan("*h").first(2)) { + split.pop_back(); + type = DeriveType::HARDENED; + } + if (!ParseKeyPath(split, path)) return nullptr; + if (extkey.key.IsValid()) { + extpubkey = extkey.Neuter(); + out.keys.emplace(extpubkey.pubkey.GetID(), extkey.key); + } + return MakeUnique<BIP32PubkeyProvider>(extpubkey, std::move(path), type); +} + +/** Parse a script in a particular context. */ +std::unique_ptr<Descriptor> ParseScript(Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out) +{ + auto expr = Expr(sp); + if (Func("pk", expr)) { + auto pubkey = ParsePubkey(expr, ctx != ParseScriptContext::P2WSH, out); + if (!pubkey) return nullptr; + return MakeUnique<SingleKeyDescriptor>(std::move(pubkey), P2PKGetScript, "pk"); + } + if (Func("pkh", expr)) { + auto pubkey = ParsePubkey(expr, ctx != ParseScriptContext::P2WSH, out); + if (!pubkey) return nullptr; + return MakeUnique<SingleKeyDescriptor>(std::move(pubkey), P2PKHGetScript, "pkh"); + } + if (ctx == ParseScriptContext::TOP && Func("combo", expr)) { + auto pubkey = ParsePubkey(expr, true, out); + if (!pubkey) return nullptr; + return MakeUnique<ComboDescriptor>(std::move(pubkey)); + } + if (Func("multi", expr)) { + auto threshold = Expr(expr); + uint32_t thres; + std::vector<std::unique_ptr<PubkeyProvider>> providers; + if (!ParseUInt32(std::string(threshold.begin(), threshold.end()), &thres)) return nullptr; + size_t script_size = 0; + while (expr.size()) { + if (!Const(",", expr)) return nullptr; + auto arg = Expr(expr); + auto pk = ParsePubkey(arg, ctx != ParseScriptContext::P2WSH, out); + if (!pk) return nullptr; + script_size += pk->GetSize() + 1; + providers.emplace_back(std::move(pk)); + } + if (providers.size() < 1 || providers.size() > 16 || thres < 1 || thres > providers.size()) return nullptr; + if (ctx == ParseScriptContext::TOP) { + if (providers.size() > 3) return nullptr; // Not more than 3 pubkeys for raw multisig + } + if (ctx == ParseScriptContext::P2SH) { + if (script_size + 3 > 520) return nullptr; // Enforce P2SH script size limit + } + return MakeUnique<MultisigDescriptor>(thres, std::move(providers)); + } + if (ctx != ParseScriptContext::P2WSH && Func("wpkh", expr)) { + auto pubkey = ParsePubkey(expr, false, out); + if (!pubkey) return nullptr; + return MakeUnique<SingleKeyDescriptor>(std::move(pubkey), P2WPKHGetScript, "wpkh"); + } + if (ctx == ParseScriptContext::TOP && Func("sh", expr)) { + auto desc = ParseScript(expr, ParseScriptContext::P2SH, out); + if (!desc || expr.size()) return nullptr; + return MakeUnique<ConvertorDescriptor>(std::move(desc), ConvertP2SH, "sh"); + } + if (ctx != ParseScriptContext::P2WSH && Func("wsh", expr)) { + auto desc = ParseScript(expr, ParseScriptContext::P2WSH, out); + if (!desc || expr.size()) return nullptr; + return MakeUnique<ConvertorDescriptor>(std::move(desc), ConvertP2WSH, "wsh"); + } + if (ctx == ParseScriptContext::TOP && Func("addr", expr)) { + CTxDestination dest = DecodeDestination(std::string(expr.begin(), expr.end())); + if (!IsValidDestination(dest)) return nullptr; + return MakeUnique<AddressDescriptor>(std::move(dest)); + } + if (ctx == ParseScriptContext::TOP && Func("raw", expr)) { + std::string str(expr.begin(), expr.end()); + if (!IsHex(str)) return nullptr; + auto bytes = ParseHex(str); + return MakeUnique<RawDescriptor>(CScript(bytes.begin(), bytes.end())); + } + return nullptr; +} + +} // namespace + +std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out) +{ + Span<const char> sp(descriptor.data(), descriptor.size()); + auto ret = ParseScript(sp, ParseScriptContext::TOP, out); + if (sp.size() == 0 && ret) return ret; + return nullptr; +} diff --git a/src/script/descriptor.h b/src/script/descriptor.h new file mode 100644 index 0000000000..87e07369c7 --- /dev/null +++ b/src/script/descriptor.h @@ -0,0 +1,55 @@ +// Copyright (c) 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_DESCRIPTOR_H +#define BITCOIN_SCRIPT_DESCRIPTOR_H + +#include <script/script.h> +#include <script/sign.h> + +#include <vector> + +// Descriptors are strings that describe a set of scriptPubKeys, together with +// all information necessary to solve them. By combining all information into +// one, they avoid the need to separately import keys and scripts. +// +// Descriptors may be ranged, which occurs when the public keys inside are +// specified in the form of HD chains (xpubs). +// +// Descriptors always represent public information - public keys and scripts - +// but in cases where private keys need to be conveyed along with a descriptor, +// they can be included inside by changing public keys to private keys (WIF +// format), and changing xpubs by xprvs. +// +// Reference documentation about the descriptor language can be found in +// doc/descriptors.md. + +/** Interface for parsed descriptor objects. */ +struct Descriptor { + virtual ~Descriptor() = default; + + /** Whether the expansion of this descriptor depends on the position. */ + virtual bool IsRange() const = 0; + + /** Convert the descriptor back to a string, undoing parsing. */ + virtual std::string ToString() const = 0; + + /** Convert the descriptor to a private string. This fails if the provided provider does not have the relevant private keys. */ + virtual bool ToPrivateString(const SigningProvider& provider, std::string& out) const = 0; + + /** Expand a descriptor at a specified position. + * + * 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. + * out: scripts and public keys necessary for solving the expanded scriptPubKeys will be put here (may be equal to provider). + */ + virtual bool Expand(int pos, const SigningProvider& provider, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const = 0; +}; + +/** Parse a descriptor string. Included private keys are put in out. Returns nullptr if parsing fails. */ +std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out); + +#endif // BITCOIN_SCRIPT_DESCRIPTOR_H + diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 13f41a7cbf..95b25b4911 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// 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. @@ -99,7 +99,7 @@ bool static IsCompressedPubKey(const valtype &vchPubKey) { * Where R and S are not negative (their first byte has its highest bit not set), and not * excessively padded (do not start with a 0 byte, unless an otherwise negative number follows, * in which case a single 0 byte is necessary and even required). - * + * * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 * * This function is consensus-critical since BIP66. @@ -139,7 +139,7 @@ bool static IsValidSignatureEncoding(const std::vector<unsigned char> &sig) { // Verify that the length of the signature matches the sum of the length // of the elements. if ((size_t)(lenR + lenS + 7) != sig.size()) return false; - + // Check whether the R element is an integer. if (sig[2] != 0x02) return false; @@ -899,7 +899,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& popstack(stack); stack.push_back(vchHash); } - break; + break; case OP_CODESEPARATOR: { @@ -1089,9 +1089,11 @@ namespace { * Wrapper that serializes like CTransaction, but with the modifications * required for the signature hash done in-place */ -class CTransactionSignatureSerializer { +template <class T> +class CTransactionSignatureSerializer +{ private: - const CTransaction& txTo; //!< reference to the spending transaction (the one being serialized) + const T& txTo; //!< reference to the spending transaction (the one being serialized) const CScript& scriptCode; //!< output script being consumed const unsigned int nIn; //!< input index of txTo being signed const bool fAnyoneCanPay; //!< whether the hashtype has the SIGHASH_ANYONECANPAY flag set @@ -1099,7 +1101,7 @@ private: const bool fHashNone; //!< whether the hashtype is SIGHASH_NONE public: - CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) : + CTransactionSignatureSerializer(const T& txToIn, const CScript& scriptCodeIn, unsigned int nInIn, int nHashTypeIn) : txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn), fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)), fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE), @@ -1180,7 +1182,9 @@ public: } }; -uint256 GetPrevoutHash(const CTransaction& txTo) { +template <class T> +uint256 GetPrevoutHash(const T& txTo) +{ CHashWriter ss(SER_GETHASH, 0); for (const auto& txin : txTo.vin) { ss << txin.prevout; @@ -1188,7 +1192,9 @@ uint256 GetPrevoutHash(const CTransaction& txTo) { return ss.GetHash(); } -uint256 GetSequenceHash(const CTransaction& txTo) { +template <class T> +uint256 GetSequenceHash(const T& txTo) +{ CHashWriter ss(SER_GETHASH, 0); for (const auto& txin : txTo.vin) { ss << txin.nSequence; @@ -1196,7 +1202,9 @@ uint256 GetSequenceHash(const CTransaction& txTo) { return ss.GetHash(); } -uint256 GetOutputsHash(const CTransaction& txTo) { +template <class T> +uint256 GetOutputsHash(const T& txTo) +{ CHashWriter ss(SER_GETHASH, 0); for (const auto& txout : txTo.vout) { ss << txout; @@ -1206,7 +1214,8 @@ uint256 GetOutputsHash(const CTransaction& txTo) { } // namespace -PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo) +template <class T> +PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo) { // Cache is calculated only for transactions with witness if (txTo.HasWitness()) { @@ -1217,7 +1226,12 @@ PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo) } } -uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) +// explicit instantiation +template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo); +template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo); + +template <class T> +uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) { assert(nIn < txTo.vin.size()); @@ -1278,7 +1292,7 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig } // Wrapper to serialize only the necessary parts of the transaction being signed - CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType); + CTransactionSignatureSerializer<T> txTmp(txTo, scriptCode, nIn, nHashType); // Serialize and hash CHashWriter ss(SER_GETHASH, 0); @@ -1286,12 +1300,14 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig return ss.GetHash(); } -bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const +template <class T> +bool GenericTransactionSignatureChecker<T>::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const { return pubkey.Verify(sighash, vchSig); } -bool TransactionSignatureChecker::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const +template <class T> +bool GenericTransactionSignatureChecker<T>::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const { CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) @@ -1312,7 +1328,8 @@ bool TransactionSignatureChecker::CheckSig(const std::vector<unsigned char>& vch return true; } -bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const +template <class T> +bool GenericTransactionSignatureChecker<T>::CheckLockTime(const CScriptNum& nLockTime) const { // There are two kinds of nLockTime: lock-by-blockheight // and lock-by-blocktime, distinguished by whether @@ -1348,7 +1365,8 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con return true; } -bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) const +template <class T> +bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSequence) const { // Relative lock times are supported by comparing the passed // in operand to the sequence number of the input. @@ -1394,6 +1412,10 @@ bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) con return true; } +// explicit instantiation +template class GenericTransactionSignatureChecker<CTransaction>; +template class GenericTransactionSignatureChecker<CMutableTransaction>; + static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { std::vector<std::vector<unsigned char> > stack; @@ -1566,7 +1588,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C return set_success(serror); } -size_t static WitnessSigOps(int witversion, const std::vector<unsigned char>& witprogram, const CScriptWitness& witness, int flags) +size_t static WitnessSigOps(int witversion, const std::vector<unsigned char>& witprogram, const CScriptWitness& witness) { if (witversion == 0) { if (witprogram.size() == WITNESS_V0_KEYHASH_SIZE) @@ -1594,7 +1616,7 @@ size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, int witnessversion; std::vector<unsigned char> witnessprogram; if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) { - return WitnessSigOps(witnessversion, witnessprogram, witness ? *witness : witnessEmpty, flags); + return WitnessSigOps(witnessversion, witnessprogram, witness ? *witness : witnessEmpty); } if (scriptPubKey.IsPayToScriptHash() && scriptSig.IsPushOnly()) { @@ -1606,7 +1628,7 @@ size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, } CScript subscript(data.begin(), data.end()); if (subscript.IsWitnessProgram(witnessversion, witnessprogram)) { - return WitnessSigOps(witnessversion, witnessprogram, witness ? *witness : witnessEmpty, flags); + return WitnessSigOps(witnessversion, witnessprogram, witness ? *witness : witnessEmpty); } } diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 2800473a68..276ff9a58a 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// 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. @@ -124,7 +124,8 @@ struct PrecomputedTransactionData uint256 hashPrevouts, hashSequence, hashOutputs; bool ready = false; - explicit PrecomputedTransactionData(const CTransaction& tx); + template <class T> + explicit PrecomputedTransactionData(const T& tx); }; enum class SigVersion @@ -137,7 +138,8 @@ enum class SigVersion static constexpr size_t WITNESS_V0_SCRIPTHASH_SIZE = 32; static constexpr size_t WITNESS_V0_KEYHASH_SIZE = 20; -uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr); +template <class T> +uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr); class BaseSignatureChecker { @@ -160,10 +162,11 @@ public: virtual ~BaseSignatureChecker() {} }; -class TransactionSignatureChecker : public BaseSignatureChecker +template <class T> +class GenericTransactionSignatureChecker : public BaseSignatureChecker { private: - const CTransaction* txTo; + const T* txTo; unsigned int nIn; const CAmount amount; const PrecomputedTransactionData* txdata; @@ -172,21 +175,15 @@ protected: virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; public: - TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {} - TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {} + GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {} + GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {} bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override; bool CheckLockTime(const CScriptNum& nLockTime) const override; bool CheckSequence(const CScriptNum& nSequence) const override; }; -class MutableTransactionSignatureChecker : public TransactionSignatureChecker -{ -private: - const CTransaction txTo; - -public: - MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : TransactionSignatureChecker(&txTo, nInIn, amountIn), txTo(*txToIn) {} -}; +using TransactionSignatureChecker = GenericTransactionSignatureChecker<CTransaction>; +using MutableTransactionSignatureChecker = GenericTransactionSignatureChecker<CMutableTransaction>; bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr); bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr); diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index fefa02fdef..1433ebf42f 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// 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. @@ -28,6 +28,19 @@ enum class IsMineSigVersion 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; @@ -42,17 +55,12 @@ bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore) return true; } -isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid, IsMineSigVersion sigversion) +IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion) { - isInvalid = false; + IsMineResult ret = IsMineResult::NO; std::vector<valtype> vSolutions; - txnouttype whichType; - if (!Solver(scriptPubKey, whichType, vSolutions)) { - if (keystore.HaveWatchOnly(scriptPubKey)) - return ISMINE_WATCH_UNSOLVABLE; - return ISMINE_NO; - } + txnouttype whichType = Solver(scriptPubKey, vSolutions); CKeyID keyID; switch (whichType) @@ -64,23 +72,25 @@ isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, b case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) { - isInvalid = true; - return ISMINE_NO; + return IsMineResult::INVALID; + } + if (keystore.HaveKey(keyID)) { + ret = std::max(ret, IsMineResult::SPENDABLE); } - if (keystore.HaveKey(keyID)) - return ISMINE_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; } - isminetype ret = IsMineInner(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), isInvalid, IsMineSigVersion::WITNESS_V0); - if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid)) - return ret; + ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0)); break; } case TX_PUBKEYHASH: @@ -88,26 +98,32 @@ isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, b if (!PermitsUncompressed(sigversion)) { CPubKey pubkey; if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) { - isInvalid = true; - return ISMINE_NO; + return IsMineResult::INVALID; } } - if (keystore.HaveKey(keyID)) - return ISMINE_SPENDABLE; + 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)) { - isminetype ret = IsMineInner(keystore, subscript, isInvalid, IsMineSigVersion::P2SH); - if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid)) - return ret; + 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; } @@ -116,9 +132,7 @@ isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, b CScriptID scriptID = CScriptID(hash); CScript subscript; if (keystore.GetCScript(scriptID, subscript)) { - isminetype ret = IsMineInner(keystore, subscript, isInvalid, IsMineSigVersion::WITNESS_V0); - if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid)) - return ret; + ret = std::max(ret, IsMineInner(keystore, subscript, IsMineSigVersion::WITNESS_V0)); } break; } @@ -126,7 +140,9 @@ isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, b case TX_MULTISIG: { // Never treat bare multisig outputs as ours (they can still be made watchonly-though) - if (sigversion == IsMineSigVersion::TOP) break; + if (sigversion == IsMineSigVersion::TOP) { + break; + } // Only consider transactions "mine" if we own ALL the // keys involved. Multi-signature transactions that are @@ -137,36 +153,37 @@ isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, b if (!PermitsUncompressed(sigversion)) { for (size_t i = 0; i < keys.size(); i++) { if (keys[i].size() != 33) { - isInvalid = true; - return ISMINE_NO; + return IsMineResult::INVALID; } } } - if (HaveKeys(keys, keystore)) - return ISMINE_SPENDABLE; + if (HaveKeys(keys, keystore)) { + ret = std::max(ret, IsMineResult::SPENDABLE); + } break; } } - if (keystore.HaveWatchOnly(scriptPubKey)) { - // TODO: This could be optimized some by doing some work after the above solver - SignatureData sigs; - return ProduceSignature(keystore, DUMMY_SIGNATURE_CREATOR, scriptPubKey, sigs) ? ISMINE_WATCH_SOLVABLE : ISMINE_WATCH_UNSOLVABLE; + if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) { + ret = std::max(ret, IsMineResult::WATCH_ONLY); } - return ISMINE_NO; + return ret; } } // namespace -isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid) -{ - return IsMineInner(keystore, scriptPubKey, isInvalid, IsMineSigVersion::TOP); -} - isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey) { - bool isInvalid = false; - return IsMine(keystore, scriptPubKey, isInvalid); + 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) diff --git a/src/script/ismine.h b/src/script/ismine.h index 8573bdfbd2..601e70f709 100644 --- a/src/script/ismine.h +++ b/src/script/ismine.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// 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. @@ -17,23 +17,13 @@ class CScript; enum isminetype { ISMINE_NO = 0, - //! Indicates that we don't know how to create a scriptSig that would solve this if we were given the appropriate private keys - ISMINE_WATCH_UNSOLVABLE = 1, - //! Indicates that we know how to create a scriptSig that would solve this if we were given the appropriate private keys - ISMINE_WATCH_SOLVABLE = 2, - ISMINE_WATCH_ONLY = ISMINE_WATCH_SOLVABLE | ISMINE_WATCH_UNSOLVABLE, - ISMINE_SPENDABLE = 4, + ISMINE_WATCH_ONLY = 1, + ISMINE_SPENDABLE = 2, ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE }; /** used for bitflags of isminetype */ typedef uint8_t isminefilter; -/* isInvalid becomes true when the script is found invalid by consensus or policy. This will terminate the recursion - * and return ISMINE_NO immediately, as an invalid script should never be considered as "mine". This is needed as - * different SIGVERSION may have different network rules. Currently the only use of isInvalid is indicate uncompressed - * keys in SigVersion::WITNESS_V0 script, but could also be used in similar cases in the future - */ -isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid); isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey); isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest); diff --git a/src/script/script.cpp b/src/script/script.cpp index 7f25d915a8..9bdf3ed808 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// 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. @@ -141,11 +141,6 @@ const char* GetOpName(opcodetype opcode) case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; - // Note: - // The template matching params OP_SMALLINTEGER/etc are defined in opcodetype enum - // as kind of implementation hack, they are *NOT* real opcodes. If found in real - // Script, just let the default: case deal with them. - default: return "OP_UNKNOWN"; } diff --git a/src/script/script.h b/src/script/script.h index d8b7c06013..00065a24be 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// 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. @@ -181,13 +181,6 @@ enum opcodetype OP_NOP9 = 0xb8, OP_NOP10 = 0xb9, - - // template matching params - OP_SMALLINTEGER = 0xfa, - OP_PUBKEYS = 0xfb, - OP_PUBKEYHASH = 0xfd, - OP_PUBKEY = 0xfe, - OP_INVALIDOPCODE = 0xff, }; diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp index ceda740580..9d7deffc78 100644 --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// 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. diff --git a/src/script/script_error.h b/src/script/script_error.h index 6982a087f4..400f63ff0f 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// 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. diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index 9638b12f99..68f0542294 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// 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. diff --git a/src/script/sigcache.h b/src/script/sigcache.h index 1309d57cc6..807b61b542 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// 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. diff --git a/src/script/sign.cpp b/src/script/sign.cpp index ac35f17f3e..d779910425 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// 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. @@ -11,12 +11,11 @@ #include <script/standard.h> #include <uint256.h> - typedef std::vector<unsigned char> valtype; -TransactionSignatureCreator::TransactionSignatureCreator(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} +MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} -bool TransactionSignatureCreator::CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const +bool MutableTransactionSignatureCreator::CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const { CKey key; if (!provider.GetKey(address, key)) @@ -33,27 +32,62 @@ bool TransactionSignatureCreator::CreateSig(const SigningProvider& provider, std return true; } -static bool Sign1(const SigningProvider& provider, const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion) +static bool GetCScript(const SigningProvider& provider, const SignatureData& sigdata, const CScriptID& scriptid, CScript& script) { - std::vector<unsigned char> vchSig; - if (!creator.CreateSig(provider, vchSig, address, scriptCode, sigversion)) - return false; - ret.push_back(vchSig); - return true; + if (provider.GetCScript(scriptid, script)) { + return true; + } + // Look for scripts in SignatureData + if (CScriptID(sigdata.redeem_script) == scriptid) { + script = sigdata.redeem_script; + return true; + } else if (CScriptID(sigdata.witness_script) == scriptid) { + script = sigdata.witness_script; + return true; + } + return false; } -static bool SignN(const SigningProvider& provider, const std::vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion) +static bool GetPubKey(const SigningProvider& provider, SignatureData& sigdata, const CKeyID& address, CPubKey& pubkey) { - int nSigned = 0; - int nRequired = multisigdata.front()[0]; - for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++) - { - const valtype& pubkey = multisigdata[i]; - CKeyID keyID = CPubKey(pubkey).GetID(); - if (Sign1(provider, keyID, creator, scriptCode, ret, sigversion)) - ++nSigned; + // Look for pubkey in all partial sigs + const auto it = sigdata.signatures.find(address); + if (it != sigdata.signatures.end()) { + pubkey = it->second.first; + return true; } - return nSigned==nRequired; + // Look for pubkey in pubkey list + const auto& pk_it = sigdata.misc_pubkeys.find(address); + if (pk_it != sigdata.misc_pubkeys.end()) { + pubkey = pk_it->second.first; + return true; + } + // Query the underlying provider + if (provider.GetPubKey(address, pubkey)) { + KeyOriginInfo info; + if (provider.GetKeyOrigin(address, info)) { + sigdata.misc_pubkeys.emplace(address, std::make_pair(pubkey, std::move(info))); + } + return true; + } + return false; +} + +static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector<unsigned char>& sig_out, const CKeyID& keyid, const CScript& scriptcode, SigVersion sigversion) +{ + const auto it = sigdata.signatures.find(keyid); + if (it != sigdata.signatures.end()) { + sig_out = it->second.second; + return true; + } + CPubKey pubkey; + GetPubKey(provider, sigdata, keyid, pubkey); + if (creator.CreateSig(provider, sig_out, keyid, scriptcode, sigversion)) { + auto i = sigdata.signatures.emplace(keyid, SigPair(pubkey, sig_out)); + assert(i.second); + return true; + } + return false; } /** @@ -63,17 +97,16 @@ static bool SignN(const SigningProvider& provider, const std::vector<valtype>& m * Returns false if scriptPubKey could not be completely satisfied. */ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey, - std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion) + std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion, SignatureData& sigdata) { CScript scriptRet; uint160 h160; ret.clear(); + std::vector<unsigned char> sig; std::vector<valtype> vSolutions; - if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) - return false; + whichTypeRet = Solver(scriptPubKey, vSolutions); - CKeyID keyID; switch (whichTypeRet) { case TX_NONSTANDARD: @@ -81,37 +114,47 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator case TX_WITNESS_UNKNOWN: return false; case TX_PUBKEY: - keyID = CPubKey(vSolutions[0]).GetID(); - return Sign1(provider, keyID, creator, scriptPubKey, ret, sigversion); - case TX_PUBKEYHASH: - keyID = CKeyID(uint160(vSolutions[0])); - if (!Sign1(provider, keyID, creator, scriptPubKey, ret, sigversion)) - return false; - else - { - CPubKey vch; - provider.GetPubKey(keyID, vch); - ret.push_back(ToByteVector(vch)); - } + if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]).GetID(), scriptPubKey, sigversion)) return false; + ret.push_back(std::move(sig)); + return true; + case TX_PUBKEYHASH: { + CKeyID keyID = CKeyID(uint160(vSolutions[0])); + if (!CreateSig(creator, sigdata, provider, sig, keyID, scriptPubKey, sigversion)) return false; + ret.push_back(std::move(sig)); + CPubKey pubkey; + GetPubKey(provider, sigdata, keyID, pubkey); + ret.push_back(ToByteVector(pubkey)); return true; + } case TX_SCRIPTHASH: - if (provider.GetCScript(uint160(vSolutions[0]), scriptRet)) { + if (GetCScript(provider, sigdata, uint160(vSolutions[0]), scriptRet)) { ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end())); return true; } return false; - case TX_MULTISIG: + case TX_MULTISIG: { + size_t required = vSolutions.front()[0]; ret.push_back(valtype()); // workaround CHECKMULTISIG bug - return (SignN(provider, vSolutions, creator, scriptPubKey, ret, sigversion)); - + for (size_t i = 1; i < vSolutions.size() - 1; ++i) { + CPubKey pubkey = CPubKey(vSolutions[i]); + if (ret.size() < required + 1 && CreateSig(creator, sigdata, provider, sig, pubkey.GetID(), scriptPubKey, sigversion)) { + ret.push_back(std::move(sig)); + } + } + bool ok = ret.size() == required + 1; + for (size_t i = 0; i + ret.size() < required + 1; ++i) { + ret.push_back(valtype()); + } + return ok; + } case TX_WITNESS_V0_KEYHASH: ret.push_back(vSolutions[0]); return true; case TX_WITNESS_V0_SCRIPTHASH: CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin()); - if (provider.GetCScript(h160, scriptRet)) { + if (GetCScript(provider, sigdata, h160, scriptRet)) { ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end())); return true; } @@ -139,9 +182,11 @@ static CScript PushAll(const std::vector<valtype>& values) bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata) { + if (sigdata.complete) return true; + std::vector<valtype> result; txnouttype whichType; - bool solved = SignStep(provider, creator, fromPubKey, result, whichType, SigVersion::BASE); + bool solved = SignStep(provider, creator, fromPubKey, result, whichType, SigVersion::BASE, sigdata); bool P2SH = false; CScript subscript; sigdata.scriptWitness.stack.clear(); @@ -152,7 +197,8 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato // the final scriptSig is the signatures from that // and then the serialized subscript: subscript = CScript(result[0].begin(), result[0].end()); - solved = solved && SignStep(provider, creator, subscript, result, whichType, SigVersion::BASE) && whichType != TX_SCRIPTHASH; + sigdata.redeem_script = subscript; + solved = solved && SignStep(provider, creator, subscript, result, whichType, SigVersion::BASE, sigdata) && whichType != TX_SCRIPTHASH; P2SH = true; } @@ -161,18 +207,23 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato CScript witnessscript; witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG; txnouttype subType; - solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0); + solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata); sigdata.scriptWitness.stack = result; + sigdata.witness = true; result.clear(); } else if (solved && whichType == TX_WITNESS_V0_SCRIPTHASH) { CScript witnessscript(result[0].begin(), result[0].end()); + sigdata.witness_script = witnessscript; txnouttype subType; - solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH; + solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH; result.push_back(std::vector<unsigned char>(witnessscript.begin(), witnessscript.end())); sigdata.scriptWitness.stack = result; + sigdata.witness = true; result.clear(); + } else if (solved && whichType == TX_WITNESS_UNKNOWN) { + sigdata.witness = true; } if (P2SH) { @@ -181,15 +232,162 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato sigdata.scriptSig = PushAll(result); // Test solution - return solved && VerifyScript(sigdata.scriptSig, fromPubKey, &sigdata.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()); + sigdata.complete = solved && VerifyScript(sigdata.scriptSig, fromPubKey, &sigdata.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()); + return sigdata.complete; +} + +bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash) +{ + // if this input has a final scriptsig or scriptwitness, don't do anything with it + if (!input.final_script_sig.empty() || !input.final_script_witness.IsNull()) { + return true; + } + + // Fill SignatureData with input info + SignatureData sigdata; + input.FillSignatureData(sigdata); + + // Get UTXO + bool require_witness_sig = false; + CTxOut utxo; + if (input.non_witness_utxo) { + // If we're taking our information from a non-witness UTXO, verify that it matches the prevout. + if (input.non_witness_utxo->GetHash() != tx.vin[index].prevout.hash) return false; + // If both witness and non-witness UTXO are provided, verify that they match. This check shouldn't + // matter, as the PSBT deserializer enforces only one of both is provided, and the only way both + // can be present is when they're added simultaneously by FillPSBT (in which case they always match). + // Still, check in order to not rely on callers to enforce this. + if (!input.witness_utxo.IsNull() && input.non_witness_utxo->vout[tx.vin[index].prevout.n] != input.witness_utxo) return false; + utxo = input.non_witness_utxo->vout[tx.vin[index].prevout.n]; + } else if (!input.witness_utxo.IsNull()) { + utxo = input.witness_utxo; + // When we're taking our information from a witness UTXO, we can't verify it is actually data from + // the output being spent. This is safe in case a witness signature is produced (which includes this + // information directly in the hash), but not for non-witness signatures. Remember that we require + // a witness signature in this situation. + require_witness_sig = true; + } else { + return false; + } + + MutableTransactionSignatureCreator creator(&tx, index, utxo.nValue, sighash); + sigdata.witness = false; + bool sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata); + // Verify that a witness signature was produced in case one was required. + if (require_witness_sig && !sigdata.witness) return false; + input.FromSignatureData(sigdata); + + // If both UTXO types are present, drop the unnecessary one. + if (input.non_witness_utxo && !input.witness_utxo.IsNull()) { + if (sigdata.witness) { + input.non_witness_utxo = nullptr; + } else { + input.witness_utxo.SetNull(); + } + } + + return sig_complete; +} + +class SignatureExtractorChecker final : public BaseSignatureChecker +{ +private: + SignatureData& sigdata; + BaseSignatureChecker& checker; + +public: + SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : sigdata(sigdata), checker(checker) {} + bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override; +}; + +bool SignatureExtractorChecker::CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const +{ + if (checker.CheckSig(scriptSig, vchPubKey, scriptCode, sigversion)) { + CPubKey pubkey(vchPubKey); + sigdata.signatures.emplace(pubkey.GetID(), SigPair(pubkey, scriptSig)); + return true; + } + return false; } -SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn) +namespace +{ +struct Stacks +{ + std::vector<valtype> script; + std::vector<valtype> witness; + + Stacks() = delete; + Stacks(const Stacks&) = delete; + explicit Stacks(const SignatureData& data) : witness(data.scriptWitness.stack) { + EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SigVersion::BASE); + } +}; +} + +// Extracts signatures and scripts from incomplete scriptSigs. Please do not extend this, use PSBT instead +SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout) { SignatureData data; assert(tx.vin.size() > nIn); data.scriptSig = tx.vin[nIn].scriptSig; data.scriptWitness = tx.vin[nIn].scriptWitness; + Stacks stack(data); + + // Get signatures + MutableTransactionSignatureChecker tx_checker(&tx, nIn, txout.nValue); + SignatureExtractorChecker extractor_checker(data, tx_checker); + if (VerifyScript(data.scriptSig, txout.scriptPubKey, &data.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, extractor_checker)) { + data.complete = true; + return data; + } + + // Get scripts + std::vector<std::vector<unsigned char>> solutions; + txnouttype script_type = Solver(txout.scriptPubKey, solutions); + SigVersion sigversion = SigVersion::BASE; + CScript next_script = txout.scriptPubKey; + + if (script_type == TX_SCRIPTHASH && !stack.script.empty() && !stack.script.back().empty()) { + // Get the redeemScript + CScript redeem_script(stack.script.back().begin(), stack.script.back().end()); + data.redeem_script = redeem_script; + next_script = std::move(redeem_script); + + // Get redeemScript type + script_type = Solver(next_script, solutions); + stack.script.pop_back(); + } + if (script_type == TX_WITNESS_V0_SCRIPTHASH && !stack.witness.empty() && !stack.witness.back().empty()) { + // Get the witnessScript + CScript witness_script(stack.witness.back().begin(), stack.witness.back().end()); + data.witness_script = witness_script; + next_script = std::move(witness_script); + + // Get witnessScript type + script_type = Solver(next_script, solutions); + stack.witness.pop_back(); + stack.script = std::move(stack.witness); + stack.witness.clear(); + sigversion = SigVersion::WITNESS_V0; + } + if (script_type == TX_MULTISIG && !stack.script.empty()) { + // Build a map of pubkey -> signature by matching sigs to pubkeys: + assert(solutions.size() > 1); + unsigned int num_pubkeys = solutions.size()-2; + unsigned int last_success_key = 0; + for (const valtype& sig : stack.script) { + for (unsigned int i = last_success_key; i < num_pubkeys; ++i) { + const valtype& pubkey = solutions[i+1]; + // We either have a signature for this pubkey, or we have found a signature and it is valid + if (data.signatures.count(CPubKey(pubkey).GetID()) || extractor_checker.CheckSig(sig, pubkey, next_script, sigversion)) { + last_success_key = i + 1; + break; + } + } + } + } + return data; } @@ -199,22 +397,31 @@ void UpdateInput(CTxIn& input, const SignatureData& data) input.scriptWitness = data.scriptWitness; } -void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data) +void SignatureData::MergeSignatureData(SignatureData sigdata) { - assert(tx.vin.size() > nIn); - UpdateInput(tx.vin[nIn], data); + if (complete) return; + if (sigdata.complete) { + *this = std::move(sigdata); + return; + } + if (redeem_script.empty() && !sigdata.redeem_script.empty()) { + redeem_script = sigdata.redeem_script; + } + if (witness_script.empty() && !sigdata.witness_script.empty()) { + witness_script = sigdata.witness_script; + } + signatures.insert(std::make_move_iterator(sigdata.signatures.begin()), std::make_move_iterator(sigdata.signatures.end())); } bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType) { assert(nIn < txTo.vin.size()); - CTransaction txToConst(txTo); - TransactionSignatureCreator creator(&txToConst, nIn, amount, nHashType); + MutableTransactionSignatureCreator creator(&txTo, nIn, amount, nHashType); SignatureData sigdata; bool ret = ProduceSignature(provider, creator, fromPubKey, sigdata); - UpdateTransaction(txTo, nIn, sigdata); + UpdateInput(txTo.vin.at(nIn), sigdata); return ret; } @@ -228,168 +435,6 @@ bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, return SignSignature(provider, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType); } -static std::vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, - const std::vector<valtype>& vSolutions, - const std::vector<valtype>& sigs1, const std::vector<valtype>& sigs2, SigVersion sigversion) -{ - // Combine all the signatures we've got: - std::set<valtype> allsigs; - for (const valtype& v : sigs1) - { - if (!v.empty()) - allsigs.insert(v); - } - for (const valtype& v : sigs2) - { - if (!v.empty()) - allsigs.insert(v); - } - - // Build a map of pubkey -> signature by matching sigs to pubkeys: - assert(vSolutions.size() > 1); - unsigned int nSigsRequired = vSolutions.front()[0]; - unsigned int nPubKeys = vSolutions.size()-2; - std::map<valtype, valtype> sigs; - for (const valtype& sig : allsigs) - { - for (unsigned int i = 0; i < nPubKeys; i++) - { - const valtype& pubkey = vSolutions[i+1]; - if (sigs.count(pubkey)) - continue; // Already got a sig for this pubkey - - if (checker.CheckSig(sig, pubkey, scriptPubKey, sigversion)) - { - sigs[pubkey] = sig; - break; - } - } - } - // Now build a merged CScript: - unsigned int nSigsHave = 0; - std::vector<valtype> result; result.push_back(valtype()); // pop-one-too-many workaround - for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++) - { - if (sigs.count(vSolutions[i+1])) - { - result.push_back(sigs[vSolutions[i+1]]); - ++nSigsHave; - } - } - // Fill any missing with OP_0: - for (unsigned int i = nSigsHave; i < nSigsRequired; i++) - result.push_back(valtype()); - - return result; -} - -namespace -{ -struct Stacks -{ - std::vector<valtype> script; - std::vector<valtype> witness; - - Stacks() {} - explicit Stacks(const std::vector<valtype>& scriptSigStack_) : script(scriptSigStack_), witness() {} - explicit Stacks(const SignatureData& data) : witness(data.scriptWitness.stack) { - EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SigVersion::BASE); - } - - SignatureData Output() const { - SignatureData result; - result.scriptSig = PushAll(script); - result.scriptWitness.stack = witness; - return result; - } -}; -} - -static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, - const txnouttype txType, const std::vector<valtype>& vSolutions, - Stacks sigs1, Stacks sigs2, SigVersion sigversion) -{ - switch (txType) - { - case TX_NONSTANDARD: - case TX_NULL_DATA: - case TX_WITNESS_UNKNOWN: - // Don't know anything about this, assume bigger one is correct: - if (sigs1.script.size() >= sigs2.script.size()) - return sigs1; - return sigs2; - case TX_PUBKEY: - case TX_PUBKEYHASH: - // Signatures are bigger than placeholders or empty scripts: - if (sigs1.script.empty() || sigs1.script[0].empty()) - return sigs2; - return sigs1; - case TX_WITNESS_V0_KEYHASH: - // Signatures are bigger than placeholders or empty scripts: - if (sigs1.witness.empty() || sigs1.witness[0].empty()) - return sigs2; - return sigs1; - case TX_SCRIPTHASH: - if (sigs1.script.empty() || sigs1.script.back().empty()) - return sigs2; - else if (sigs2.script.empty() || sigs2.script.back().empty()) - return sigs1; - else - { - // Recur to combine: - valtype spk = sigs1.script.back(); - CScript pubKey2(spk.begin(), spk.end()); - - txnouttype txType2; - std::vector<std::vector<unsigned char> > vSolutions2; - Solver(pubKey2, txType2, vSolutions2); - sigs1.script.pop_back(); - sigs2.script.pop_back(); - Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, sigversion); - result.script.push_back(spk); - return result; - } - case TX_MULTISIG: - return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, sigversion)); - case TX_WITNESS_V0_SCRIPTHASH: - if (sigs1.witness.empty() || sigs1.witness.back().empty()) - return sigs2; - else if (sigs2.witness.empty() || sigs2.witness.back().empty()) - return sigs1; - else - { - // Recur to combine: - CScript pubKey2(sigs1.witness.back().begin(), sigs1.witness.back().end()); - txnouttype txType2; - std::vector<valtype> vSolutions2; - Solver(pubKey2, txType2, vSolutions2); - sigs1.witness.pop_back(); - sigs1.script = sigs1.witness; - sigs1.witness.clear(); - sigs2.witness.pop_back(); - sigs2.script = sigs2.witness; - sigs2.witness.clear(); - Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, SigVersion::WITNESS_V0); - result.witness = result.script; - result.script.clear(); - result.witness.push_back(valtype(pubKey2.begin(), pubKey2.end())); - return result; - } - default: - return Stacks(); - } -} - -SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, - const SignatureData& scriptSig1, const SignatureData& scriptSig2) -{ - txnouttype txType; - std::vector<std::vector<unsigned char> > vSolutions; - Solver(scriptPubKey, txType, vSolutions); - - return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SigVersion::BASE).Output(); -} - namespace { /** Dummy signature checker which accepts all signatures. */ class DummySignatureChecker final : public BaseSignatureChecker @@ -401,28 +446,45 @@ public: const DummySignatureChecker DUMMY_CHECKER; class DummySignatureCreator final : public BaseSignatureCreator { +private: + char m_r_len = 32; + char m_s_len = 32; public: - DummySignatureCreator() {} + DummySignatureCreator(char r_len, char s_len) : m_r_len(r_len), m_s_len(s_len) {} const BaseSignatureChecker& Checker() const override { return DUMMY_CHECKER; } bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override { // Create a dummy signature that is a valid DER-encoding - vchSig.assign(72, '\000'); + vchSig.assign(m_r_len + m_s_len + 7, '\000'); vchSig[0] = 0x30; - vchSig[1] = 69; + vchSig[1] = m_r_len + m_s_len + 4; vchSig[2] = 0x02; - vchSig[3] = 33; + vchSig[3] = m_r_len; vchSig[4] = 0x01; - vchSig[4 + 33] = 0x02; - vchSig[5 + 33] = 32; - vchSig[6 + 33] = 0x01; - vchSig[6 + 33 + 32] = SIGHASH_ALL; + vchSig[4 + m_r_len] = 0x02; + vchSig[5 + m_r_len] = m_s_len; + vchSig[6 + m_r_len] = 0x01; + vchSig[6 + m_r_len + m_s_len] = SIGHASH_ALL; return true; } }; + +template<typename M, typename K, typename V> +bool LookupHelper(const M& map, const K& key, V& value) +{ + auto it = map.find(key); + if (it != map.end()) { + value = it->second; + return true; + } + return false; +} + } -const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR = DummySignatureCreator(); +const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR = DummySignatureCreator(32, 32); +const BaseSignatureCreator& DUMMY_MAXIMUM_SIGNATURE_CREATOR = DummySignatureCreator(33, 32); +const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider(); bool IsSolvable(const SigningProvider& provider, const CScript& script) { @@ -436,8 +498,201 @@ bool IsSolvable(const SigningProvider& provider, const CScript& script) static_assert(STANDARD_SCRIPT_VERIFY_FLAGS & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, "IsSolvable requires standard script flags to include WITNESS_PUBKEYTYPE"); if (ProduceSignature(provider, DUMMY_SIGNATURE_CREATOR, script, sigs)) { // VerifyScript check is just defensive, and should never fail. - assert(VerifyScript(sigs.scriptSig, script, &sigs.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, DUMMY_CHECKER)); + bool verified = VerifyScript(sigs.scriptSig, script, &sigs.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, DUMMY_CHECKER); + assert(verified); return true; } return false; } + +bool PartiallySignedTransaction::IsNull() const +{ + return !tx && inputs.empty() && outputs.empty() && unknown.empty(); +} + +void PartiallySignedTransaction::Merge(const PartiallySignedTransaction& psbt) +{ + for (unsigned int i = 0; i < inputs.size(); ++i) { + inputs[i].Merge(psbt.inputs[i]); + } + for (unsigned int i = 0; i < outputs.size(); ++i) { + outputs[i].Merge(psbt.outputs[i]); + } + unknown.insert(psbt.unknown.begin(), psbt.unknown.end()); +} + +bool PartiallySignedTransaction::IsSane() const +{ + for (PSBTInput input : inputs) { + if (!input.IsSane()) return false; + } + return true; +} + +bool PSBTInput::IsNull() const +{ + return !non_witness_utxo && witness_utxo.IsNull() && partial_sigs.empty() && unknown.empty() && hd_keypaths.empty() && redeem_script.empty() && witness_script.empty(); +} + +void PSBTInput::FillSignatureData(SignatureData& sigdata) const +{ + if (!final_script_sig.empty()) { + sigdata.scriptSig = final_script_sig; + sigdata.complete = true; + } + if (!final_script_witness.IsNull()) { + sigdata.scriptWitness = final_script_witness; + sigdata.complete = true; + } + if (sigdata.complete) { + return; + } + + sigdata.signatures.insert(partial_sigs.begin(), partial_sigs.end()); + if (!redeem_script.empty()) { + sigdata.redeem_script = redeem_script; + } + if (!witness_script.empty()) { + sigdata.witness_script = witness_script; + } + for (const auto& key_pair : hd_keypaths) { + sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair); + } +} + +void PSBTInput::FromSignatureData(const SignatureData& sigdata) +{ + if (sigdata.complete) { + partial_sigs.clear(); + hd_keypaths.clear(); + redeem_script.clear(); + witness_script.clear(); + + if (!sigdata.scriptSig.empty()) { + final_script_sig = sigdata.scriptSig; + } + if (!sigdata.scriptWitness.IsNull()) { + final_script_witness = sigdata.scriptWitness; + } + return; + } + + partial_sigs.insert(sigdata.signatures.begin(), sigdata.signatures.end()); + if (redeem_script.empty() && !sigdata.redeem_script.empty()) { + redeem_script = sigdata.redeem_script; + } + if (witness_script.empty() && !sigdata.witness_script.empty()) { + witness_script = sigdata.witness_script; + } + for (const auto& entry : sigdata.misc_pubkeys) { + hd_keypaths.emplace(entry.second); + } +} + +void PSBTInput::Merge(const PSBTInput& input) +{ + if (!non_witness_utxo && input.non_witness_utxo) non_witness_utxo = input.non_witness_utxo; + if (witness_utxo.IsNull() && !input.witness_utxo.IsNull()) { + witness_utxo = input.witness_utxo; + non_witness_utxo = nullptr; // Clear out any non-witness utxo when we set a witness one. + } + + partial_sigs.insert(input.partial_sigs.begin(), input.partial_sigs.end()); + hd_keypaths.insert(input.hd_keypaths.begin(), input.hd_keypaths.end()); + unknown.insert(input.unknown.begin(), input.unknown.end()); + + if (redeem_script.empty() && !input.redeem_script.empty()) redeem_script = input.redeem_script; + if (witness_script.empty() && !input.witness_script.empty()) witness_script = input.witness_script; + if (final_script_sig.empty() && !input.final_script_sig.empty()) final_script_sig = input.final_script_sig; + if (final_script_witness.IsNull() && !input.final_script_witness.IsNull()) final_script_witness = input.final_script_witness; +} + +bool PSBTInput::IsSane() const +{ + // Cannot have both witness and non-witness utxos + if (!witness_utxo.IsNull() && non_witness_utxo) return false; + + // If we have a witness_script or a scriptWitness, we must also have a witness utxo + if (!witness_script.empty() && witness_utxo.IsNull()) return false; + if (!final_script_witness.IsNull() && witness_utxo.IsNull()) return false; + + return true; +} + +void PSBTOutput::FillSignatureData(SignatureData& sigdata) const +{ + if (!redeem_script.empty()) { + sigdata.redeem_script = redeem_script; + } + if (!witness_script.empty()) { + sigdata.witness_script = witness_script; + } + for (const auto& key_pair : hd_keypaths) { + sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair); + } +} + +void PSBTOutput::FromSignatureData(const SignatureData& sigdata) +{ + if (redeem_script.empty() && !sigdata.redeem_script.empty()) { + redeem_script = sigdata.redeem_script; + } + if (witness_script.empty() && !sigdata.witness_script.empty()) { + witness_script = sigdata.witness_script; + } + for (const auto& entry : sigdata.misc_pubkeys) { + hd_keypaths.emplace(entry.second); + } +} + +bool PSBTOutput::IsNull() const +{ + return redeem_script.empty() && witness_script.empty() && hd_keypaths.empty() && unknown.empty(); +} + +void PSBTOutput::Merge(const PSBTOutput& output) +{ + hd_keypaths.insert(output.hd_keypaths.begin(), output.hd_keypaths.end()); + unknown.insert(output.unknown.begin(), output.unknown.end()); + + if (redeem_script.empty() && !output.redeem_script.empty()) redeem_script = output.redeem_script; + if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script; +} + +bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const +{ + return m_provider->GetCScript(scriptid, script); +} + +bool HidingSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const +{ + return m_provider->GetPubKey(keyid, pubkey); +} + +bool HidingSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const +{ + if (m_hide_secret) return false; + return m_provider->GetKey(keyid, key); +} + +bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const +{ + if (m_hide_origin) return false; + return m_provider->GetKeyOrigin(keyid, info); +} + +bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); } +bool FlatSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const { return LookupHelper(pubkeys, keyid, pubkey); } +bool FlatSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const { return LookupHelper(keys, keyid, key); } + +FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b) +{ + FlatSigningProvider ret; + ret.scripts = a.scripts; + ret.scripts.insert(b.scripts.begin(), b.scripts.end()); + ret.pubkeys = a.pubkeys; + ret.pubkeys.insert(b.pubkeys.begin(), b.pubkeys.end()); + ret.keys = a.keys; + ret.keys.insert(b.keys.begin(), b.keys.end()); + return ret; +} diff --git a/src/script/sign.h b/src/script/sign.h index cf3651c1de..2fc4575e59 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -1,12 +1,16 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// 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_SIGN_H #define BITCOIN_SCRIPT_SIGN_H +#include <boost/optional.hpp> +#include <hash.h> +#include <pubkey.h> #include <script/interpreter.h> +#include <streams.h> class CKey; class CKeyID; @@ -16,16 +20,53 @@ class CTransaction; struct CMutableTransaction; +struct KeyOriginInfo +{ + unsigned char fingerprint[4]; + std::vector<uint32_t> path; +}; + /** An interface to be implemented by keystores that support signing. */ class SigningProvider { public: virtual ~SigningProvider() {} - virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const =0; - virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const =0; - virtual bool GetKey(const CKeyID &address, CKey& key) const =0; + virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; } + virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; } + virtual bool GetKey(const CKeyID &address, CKey& key) const { return false; } + virtual bool GetKeyOrigin(const CKeyID& id, KeyOriginInfo& info) const { return false; } +}; + +extern const SigningProvider& DUMMY_SIGNING_PROVIDER; + +class HidingSigningProvider : public SigningProvider +{ +private: + const bool m_hide_secret; + const bool m_hide_origin; + const SigningProvider* m_provider; + +public: + HidingSigningProvider(const SigningProvider* provider, bool hide_secret, bool hide_origin) : m_hide_secret(hide_secret), m_hide_origin(hide_origin), m_provider(provider) {} + bool GetCScript(const CScriptID& scriptid, CScript& script) const override; + bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override; + bool GetKey(const CKeyID& keyid, CKey& key) const override; + bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; +}; + +struct FlatSigningProvider final : public SigningProvider +{ + std::map<CScriptID, CScript> scripts; + std::map<CKeyID, CPubKey> pubkeys; + std::map<CKeyID, CKey> keys; + + bool GetCScript(const CScriptID& scriptid, CScript& script) const override; + bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override; + bool GetKey(const CKeyID& keyid, CKey& key) const override; }; +FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b); + /** Interface for signature creators. */ class BaseSignatureCreator { public: @@ -37,35 +78,622 @@ public: }; /** A signature creator for transactions. */ -class TransactionSignatureCreator : public BaseSignatureCreator { - const CTransaction* txTo; +class MutableTransactionSignatureCreator : public BaseSignatureCreator { + const CMutableTransaction* txTo; unsigned int nIn; int nHashType; CAmount amount; - const TransactionSignatureChecker checker; + const MutableTransactionSignatureChecker checker; public: - TransactionSignatureCreator(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL); + MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn = SIGHASH_ALL); const BaseSignatureChecker& Checker() const override { return checker; } bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override; }; -class MutableTransactionSignatureCreator : public TransactionSignatureCreator { - CTransaction tx; - -public: - MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : TransactionSignatureCreator(&tx, nInIn, amountIn, nHashTypeIn), tx(*txToIn) {} -}; - -/** A signature creator that just produces 72-byte empty signatures. */ +/** A signature creator that just produces 71-byte empty signatures. */ extern const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR; +/** A signature creator that just produces 72-byte empty signatures. */ +extern const BaseSignatureCreator& DUMMY_MAXIMUM_SIGNATURE_CREATOR; + +typedef std::pair<CPubKey, std::vector<unsigned char>> SigPair; +// This struct contains information from a transaction input and also contains signatures for that input. +// The information contained here can be used to create a signature and is also filled by ProduceSignature +// in order to construct final scriptSigs and scriptWitnesses. struct SignatureData { - CScript scriptSig; - CScriptWitness scriptWitness; + bool complete = false; ///< Stores whether the scriptSig and scriptWitness are complete + bool witness = false; ///< Stores whether the input this SigData corresponds to is a witness input + CScript scriptSig; ///< The scriptSig of an input. Contains complete signatures or the traditional partial signatures format + CScript redeem_script; ///< The redeemScript (if any) for the input + CScript witness_script; ///< The witnessScript (if any) for the input. witnessScripts are used in P2WSH outputs. + CScriptWitness scriptWitness; ///< The scriptWitness of an input. Contains complete signatures or the traditional partial signatures format. scriptWitness is part of a transaction input per BIP 144. + std::map<CKeyID, SigPair> signatures; ///< BIP 174 style partial signatures for the input. May contain all signatures necessary for producing a final scriptSig or scriptWitness. + std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> misc_pubkeys; SignatureData() {} explicit SignatureData(const CScript& script) : scriptSig(script) {} + void MergeSignatureData(SignatureData sigdata); +}; + +// Magic bytes +static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff}; + +// Global types +static constexpr uint8_t PSBT_GLOBAL_UNSIGNED_TX = 0x00; + +// Input types +static constexpr uint8_t PSBT_IN_NON_WITNESS_UTXO = 0x00; +static constexpr uint8_t PSBT_IN_WITNESS_UTXO = 0x01; +static constexpr uint8_t PSBT_IN_PARTIAL_SIG = 0x02; +static constexpr uint8_t PSBT_IN_SIGHASH = 0x03; +static constexpr uint8_t PSBT_IN_REDEEMSCRIPT = 0x04; +static constexpr uint8_t PSBT_IN_WITNESSSCRIPT = 0x05; +static constexpr uint8_t PSBT_IN_BIP32_DERIVATION = 0x06; +static constexpr uint8_t PSBT_IN_SCRIPTSIG = 0x07; +static constexpr uint8_t PSBT_IN_SCRIPTWITNESS = 0x08; + +// Output types +static constexpr uint8_t PSBT_OUT_REDEEMSCRIPT = 0x00; +static constexpr uint8_t PSBT_OUT_WITNESSSCRIPT = 0x01; +static constexpr uint8_t PSBT_OUT_BIP32_DERIVATION = 0x02; + +// The separator is 0x00. Reading this in means that the unserializer can interpret it +// as a 0 length key which indicates that this is the separator. The separator has no value. +static constexpr uint8_t PSBT_SEPARATOR = 0x00; + +// Takes a stream and multiple arguments and serializes them as if first serialized into a vector and then into the stream +// The resulting output into the stream has the total serialized length of all of the objects followed by all objects concatenated with each other. +template<typename Stream, typename... X> +void SerializeToVector(Stream& s, const X&... args) +{ + WriteCompactSize(s, GetSerializeSizeMany(s.GetVersion(), args...)); + SerializeMany(s, args...); +} + +// Takes a stream and multiple arguments and unserializes them first as a vector then each object individually in the order provided in the arguments +template<typename Stream, typename... X> +void UnserializeFromVector(Stream& s, X&... args) +{ + size_t expected_size = ReadCompactSize(s); + size_t remaining_before = s.size(); + UnserializeMany(s, args...); + size_t remaining_after = s.size(); + if (remaining_after + expected_size != remaining_before) { + throw std::ios_base::failure("Size of value was not the stated size"); + } +} + +// Deserialize HD keypaths into a map +template<typename Stream> +void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std::map<CPubKey, KeyOriginInfo>& hd_keypaths) +{ + // Make sure that the key is the size of pubkey + 1 + if (key.size() != CPubKey::PUBLIC_KEY_SIZE + 1 && key.size() != CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1) { + throw std::ios_base::failure("Size of key was not the expected size for the type BIP32 keypath"); + } + // Read in the pubkey from key + CPubKey pubkey(key.begin() + 1, key.end()); + if (!pubkey.IsFullyValid()) { + throw std::ios_base::failure("Invalid pubkey"); + } + if (hd_keypaths.count(pubkey) > 0) { + throw std::ios_base::failure("Duplicate Key, pubkey derivation path already provided"); + } + + // Read in key path + uint64_t value_len = ReadCompactSize(s); + if (value_len % 4 || value_len == 0) { + throw std::ios_base::failure("Invalid length for HD key path"); + } + + KeyOriginInfo keypath; + s >> keypath.fingerprint; + for (unsigned int i = 4; i < value_len; i += sizeof(uint32_t)) { + uint32_t index; + s >> index; + keypath.path.push_back(index); + } + + // Add to map + hd_keypaths.emplace(pubkey, std::move(keypath)); +} + +// Serialize HD keypaths to a stream from a map +template<typename Stream> +void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, KeyOriginInfo>& hd_keypaths, uint8_t type) +{ + for (auto keypath_pair : hd_keypaths) { + SerializeToVector(s, type, MakeSpan(keypath_pair.first)); + WriteCompactSize(s, (keypath_pair.second.path.size() + 1) * sizeof(uint32_t)); + s << keypath_pair.second.fingerprint; + for (const auto& path : keypath_pair.second.path) { + s << path; + } + } +} + +/** A structure for PSBTs which contain per-input information */ +struct PSBTInput +{ + CTransactionRef non_witness_utxo; + CTxOut witness_utxo; + CScript redeem_script; + CScript witness_script; + CScript final_script_sig; + CScriptWitness final_script_witness; + std::map<CPubKey, KeyOriginInfo> hd_keypaths; + std::map<CKeyID, SigPair> partial_sigs; + std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown; + int sighash_type = 0; + + bool IsNull() const; + void FillSignatureData(SignatureData& sigdata) const; + void FromSignatureData(const SignatureData& sigdata); + void Merge(const PSBTInput& input); + bool IsSane() const; + PSBTInput() {} + + template <typename Stream> + inline void Serialize(Stream& s) const { + // Write the utxo + // If there is a non-witness utxo, then don't add the witness one. + if (non_witness_utxo) { + SerializeToVector(s, PSBT_IN_NON_WITNESS_UTXO); + OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS); + SerializeToVector(os, non_witness_utxo); + } else if (!witness_utxo.IsNull()) { + SerializeToVector(s, PSBT_IN_WITNESS_UTXO); + SerializeToVector(s, witness_utxo); + } + + if (final_script_sig.empty() && final_script_witness.IsNull()) { + // Write any partial signatures + for (auto sig_pair : partial_sigs) { + SerializeToVector(s, PSBT_IN_PARTIAL_SIG, MakeSpan(sig_pair.second.first)); + s << sig_pair.second.second; + } + + // Write the sighash type + if (sighash_type > 0) { + SerializeToVector(s, PSBT_IN_SIGHASH); + SerializeToVector(s, sighash_type); + } + + // Write the redeem script + if (!redeem_script.empty()) { + SerializeToVector(s, PSBT_IN_REDEEMSCRIPT); + s << redeem_script; + } + + // Write the witness script + if (!witness_script.empty()) { + SerializeToVector(s, PSBT_IN_WITNESSSCRIPT); + s << witness_script; + } + + // Write any hd keypaths + SerializeHDKeypaths(s, hd_keypaths, PSBT_IN_BIP32_DERIVATION); + } + + // Write script sig + if (!final_script_sig.empty()) { + SerializeToVector(s, PSBT_IN_SCRIPTSIG); + s << final_script_sig; + } + // write script witness + if (!final_script_witness.IsNull()) { + SerializeToVector(s, PSBT_IN_SCRIPTWITNESS); + SerializeToVector(s, final_script_witness.stack); + } + + // Write unknown things + for (auto& entry : unknown) { + s << entry.first; + s << entry.second; + } + + s << PSBT_SEPARATOR; + } + + + template <typename Stream> + inline void Unserialize(Stream& s) { + // Read loop + while(!s.empty()) { + // Read + std::vector<unsigned char> key; + s >> key; + + // the key is empty if that was actually a separator byte + // This is a special case for key lengths 0 as those are not allowed (except for separator) + if (key.empty()) return; + + // First byte of key is the type + unsigned char type = key[0]; + + // Do stuff based on type + switch(type) { + case PSBT_IN_NON_WITNESS_UTXO: + { + if (non_witness_utxo) { + throw std::ios_base::failure("Duplicate Key, input non-witness utxo already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Non-witness utxo key is more than one byte type"); + } + // Set the stream to unserialize with witness since this is always a valid network transaction + OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() & ~SERIALIZE_TRANSACTION_NO_WITNESS); + UnserializeFromVector(os, non_witness_utxo); + break; + } + case PSBT_IN_WITNESS_UTXO: + if (!witness_utxo.IsNull()) { + throw std::ios_base::failure("Duplicate Key, input witness utxo already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Witness utxo key is more than one byte type"); + } + UnserializeFromVector(s, witness_utxo); + break; + case PSBT_IN_PARTIAL_SIG: + { + // Make sure that the key is the size of pubkey + 1 + if (key.size() != CPubKey::PUBLIC_KEY_SIZE + 1 && key.size() != CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1) { + throw std::ios_base::failure("Size of key was not the expected size for the type partial signature pubkey"); + } + // Read in the pubkey from key + CPubKey pubkey(key.begin() + 1, key.end()); + if (!pubkey.IsFullyValid()) { + throw std::ios_base::failure("Invalid pubkey"); + } + if (partial_sigs.count(pubkey.GetID()) > 0) { + throw std::ios_base::failure("Duplicate Key, input partial signature for pubkey already provided"); + } + + // Read in the signature from value + std::vector<unsigned char> sig; + s >> sig; + + // Add to list + partial_sigs.emplace(pubkey.GetID(), SigPair(pubkey, std::move(sig))); + break; + } + case PSBT_IN_SIGHASH: + if (sighash_type > 0) { + throw std::ios_base::failure("Duplicate Key, input sighash type already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Sighash type key is more than one byte type"); + } + UnserializeFromVector(s, sighash_type); + break; + case PSBT_IN_REDEEMSCRIPT: + { + if (!redeem_script.empty()) { + throw std::ios_base::failure("Duplicate Key, input redeemScript already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Input redeemScript key is more than one byte type"); + } + s >> redeem_script; + break; + } + case PSBT_IN_WITNESSSCRIPT: + { + if (!witness_script.empty()) { + throw std::ios_base::failure("Duplicate Key, input witnessScript already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Input witnessScript key is more than one byte type"); + } + s >> witness_script; + break; + } + case PSBT_IN_BIP32_DERIVATION: + { + DeserializeHDKeypaths(s, key, hd_keypaths); + break; + } + case PSBT_IN_SCRIPTSIG: + { + if (!final_script_sig.empty()) { + throw std::ios_base::failure("Duplicate Key, input final scriptSig already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Final scriptSig key is more than one byte type"); + } + s >> final_script_sig; + break; + } + case PSBT_IN_SCRIPTWITNESS: + { + if (!final_script_witness.IsNull()) { + throw std::ios_base::failure("Duplicate Key, input final scriptWitness already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Final scriptWitness key is more than one byte type"); + } + UnserializeFromVector(s, final_script_witness.stack); + break; + } + // Unknown stuff + default: + if (unknown.count(key) > 0) { + throw std::ios_base::failure("Duplicate Key, key for unknown value already provided"); + } + // Read in the value + std::vector<unsigned char> val_bytes; + s >> val_bytes; + unknown.emplace(std::move(key), std::move(val_bytes)); + break; + } + } + } + + template <typename Stream> + PSBTInput(deserialize_type, Stream& s) { + Unserialize(s); + } +}; + +/** A structure for PSBTs which contains per output information */ +struct PSBTOutput +{ + CScript redeem_script; + CScript witness_script; + std::map<CPubKey, KeyOriginInfo> hd_keypaths; + std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown; + + bool IsNull() const; + void FillSignatureData(SignatureData& sigdata) const; + void FromSignatureData(const SignatureData& sigdata); + void Merge(const PSBTOutput& output); + bool IsSane() const; + PSBTOutput() {} + + template <typename Stream> + inline void Serialize(Stream& s) const { + // Write the redeem script + if (!redeem_script.empty()) { + SerializeToVector(s, PSBT_OUT_REDEEMSCRIPT); + s << redeem_script; + } + + // Write the witness script + if (!witness_script.empty()) { + SerializeToVector(s, PSBT_OUT_WITNESSSCRIPT); + s << witness_script; + } + + // Write any hd keypaths + SerializeHDKeypaths(s, hd_keypaths, PSBT_OUT_BIP32_DERIVATION); + + // Write unknown things + for (auto& entry : unknown) { + s << entry.first; + s << entry.second; + } + + s << PSBT_SEPARATOR; + } + + + template <typename Stream> + inline void Unserialize(Stream& s) { + // Read loop + while(!s.empty()) { + // Read + std::vector<unsigned char> key; + s >> key; + + // the key is empty if that was actually a separator byte + // This is a special case for key lengths 0 as those are not allowed (except for separator) + if (key.empty()) return; + + // First byte of key is the type + unsigned char type = key[0]; + + // Do stuff based on type + switch(type) { + case PSBT_OUT_REDEEMSCRIPT: + { + if (!redeem_script.empty()) { + throw std::ios_base::failure("Duplicate Key, output redeemScript already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Output redeemScript key is more than one byte type"); + } + s >> redeem_script; + break; + } + case PSBT_OUT_WITNESSSCRIPT: + { + if (!witness_script.empty()) { + throw std::ios_base::failure("Duplicate Key, output witnessScript already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Output witnessScript key is more than one byte type"); + } + s >> witness_script; + break; + } + case PSBT_OUT_BIP32_DERIVATION: + { + DeserializeHDKeypaths(s, key, hd_keypaths); + break; + } + // Unknown stuff + default: { + if (unknown.count(key) > 0) { + throw std::ios_base::failure("Duplicate Key, key for unknown value already provided"); + } + // Read in the value + std::vector<unsigned char> val_bytes; + s >> val_bytes; + unknown.emplace(std::move(key), std::move(val_bytes)); + break; + } + } + } + } + + template <typename Stream> + PSBTOutput(deserialize_type, Stream& s) { + Unserialize(s); + } +}; + +/** A version of CTransaction with the PSBT format*/ +struct PartiallySignedTransaction +{ + boost::optional<CMutableTransaction> tx; + std::vector<PSBTInput> inputs; + std::vector<PSBTOutput> outputs; + std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown; + + bool IsNull() const; + void Merge(const PartiallySignedTransaction& psbt); + bool IsSane() const; + PartiallySignedTransaction() {} + PartiallySignedTransaction(const PartiallySignedTransaction& psbt_in) : tx(psbt_in.tx), inputs(psbt_in.inputs), outputs(psbt_in.outputs), unknown(psbt_in.unknown) {} + + // Only checks if they refer to the same transaction + friend bool operator==(const PartiallySignedTransaction& a, const PartiallySignedTransaction &b) + { + return a.tx->GetHash() == b.tx->GetHash(); + } + friend bool operator!=(const PartiallySignedTransaction& a, const PartiallySignedTransaction &b) + { + return !(a == b); + } + + template <typename Stream> + inline void Serialize(Stream& s) const { + + // magic bytes + s << PSBT_MAGIC_BYTES; + + // unsigned tx flag + SerializeToVector(s, PSBT_GLOBAL_UNSIGNED_TX); + + // Write serialized tx to a stream + OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS); + SerializeToVector(os, *tx); + + // Write the unknown things + for (auto& entry : unknown) { + s << entry.first; + s << entry.second; + } + + // Separator + s << PSBT_SEPARATOR; + + // Write inputs + for (const PSBTInput& input : inputs) { + s << input; + } + // Write outputs + for (const PSBTOutput& output : outputs) { + s << output; + } + } + + + template <typename Stream> + inline void Unserialize(Stream& s) { + // Read the magic bytes + uint8_t magic[5]; + s >> magic; + if (!std::equal(magic, magic + 5, PSBT_MAGIC_BYTES)) { + throw std::ios_base::failure("Invalid PSBT magic bytes"); + } + + // Read global data + while(!s.empty()) { + // Read + std::vector<unsigned char> key; + s >> key; + + // the key is empty if that was actually a separator byte + // This is a special case for key lengths 0 as those are not allowed (except for separator) + if (key.empty()) break; + + // First byte of key is the type + unsigned char type = key[0]; + + // Do stuff based on type + switch(type) { + case PSBT_GLOBAL_UNSIGNED_TX: + { + if (tx) { + throw std::ios_base::failure("Duplicate Key, unsigned tx already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Global unsigned tx key is more than one byte type"); + } + CMutableTransaction mtx; + // Set the stream to serialize with non-witness since this should always be non-witness + OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS); + UnserializeFromVector(os, mtx); + tx = std::move(mtx); + // Make sure that all scriptSigs and scriptWitnesses are empty + for (const CTxIn& txin : tx->vin) { + if (!txin.scriptSig.empty() || !txin.scriptWitness.IsNull()) { + throw std::ios_base::failure("Unsigned tx does not have empty scriptSigs and scriptWitnesses."); + } + } + break; + } + // Unknown stuff + default: { + if (unknown.count(key) > 0) { + throw std::ios_base::failure("Duplicate Key, key for unknown value already provided"); + } + // Read in the value + std::vector<unsigned char> val_bytes; + s >> val_bytes; + unknown.emplace(std::move(key), std::move(val_bytes)); + } + } + } + + // Make sure that we got an unsigned tx + if (!tx) { + throw std::ios_base::failure("No unsigned transcation was provided"); + } + + // Read input data + unsigned int i = 0; + while (!s.empty() && i < tx->vin.size()) { + PSBTInput input; + s >> input; + inputs.push_back(input); + + // Make sure the non-witness utxo matches the outpoint + if (input.non_witness_utxo && input.non_witness_utxo->GetHash() != tx->vin[i].prevout.hash) { + throw std::ios_base::failure("Non-witness UTXO does not match outpoint hash"); + } + ++i; + } + // Make sure that the number of inputs matches the number of inputs in the transaction + if (inputs.size() != tx->vin.size()) { + throw std::ios_base::failure("Inputs provided does not match the number of inputs in transaction."); + } + + // Read output data + i = 0; + while (!s.empty() && i < tx->vout.size()) { + PSBTOutput output; + s >> output; + outputs.push_back(output); + ++i; + } + // Make sure that the number of outputs matches the number of outputs in the transaction + if (outputs.size() != tx->vout.size()) { + throw std::ios_base::failure("Outputs provided does not match the number of outputs in transaction."); + } + // Sanity check + if (!IsSane()) { + throw std::ios_base::failure("PSBT is not sane."); + } + } + + template <typename Stream> + PartiallySignedTransaction(deserialize_type, Stream& s) { + Unserialize(s); + } }; /** Produce a script signature using a generic signature creator. */ @@ -75,12 +703,11 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType); bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType); -/** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */ -SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const SignatureData& scriptSig1, const SignatureData& scriptSig2); +/** Signs a PSBTInput, verifying that all provided data matches what is being signed. */ +bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash = SIGHASH_ALL); -/** Extract signature data from a transaction, and insert it. */ -SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn); -void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data); +/** Extract signature data from a transaction input, and insert it. */ +SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout); void UpdateInput(CTxIn& input, const SignatureData& data); /* Check whether we know how to sign for an output like this, assuming we diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 76778112aa..08ba1b1e0f 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -1,10 +1,11 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// 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/standard.h> +#include <crypto/sha256.h> #include <pubkey.h> #include <script/script.h> #include <util.h> @@ -18,6 +19,11 @@ unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY; CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {} +WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in) +{ + CSHA256().Write(in.data(), in.size()).Finalize(begin()); +} + const char* GetTxnOutputType(txnouttype t) { switch (t) @@ -35,54 +41,82 @@ const char* GetTxnOutputType(txnouttype t) return nullptr; } -bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet) +static bool MatchPayToPubkey(const CScript& script, valtype& pubkey) { - // Templates - static std::multimap<txnouttype, CScript> mTemplates; - if (mTemplates.empty()) - { - // Standard tx, sender provides pubkey, receiver adds signature - mTemplates.insert(std::make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); + if (script.size() == CPubKey::PUBLIC_KEY_SIZE + 2 && script[0] == CPubKey::PUBLIC_KEY_SIZE && script.back() == OP_CHECKSIG) { + pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::PUBLIC_KEY_SIZE + 1); + return CPubKey::ValidSize(pubkey); + } + if (script.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 2 && script[0] == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE && script.back() == OP_CHECKSIG) { + pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1); + return CPubKey::ValidSize(pubkey); + } + return false; +} - // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey - mTemplates.insert(std::make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG)); +static bool MatchPayToPubkeyHash(const CScript& script, valtype& pubkeyhash) +{ + if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 && script[2] == 20 && script[23] == OP_EQUALVERIFY && script[24] == OP_CHECKSIG) { + pubkeyhash = valtype(script.begin () + 3, script.begin() + 23); + return true; + } + return false; +} + +/** Test for "small positive integer" script opcodes - OP_1 through OP_16. */ +static constexpr bool IsSmallInteger(opcodetype opcode) +{ + return opcode >= OP_1 && opcode <= OP_16; +} - // Sender provides N pubkeys, receivers provides M signatures - mTemplates.insert(std::make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG)); +static bool MatchMultisig(const CScript& script, unsigned int& required, std::vector<valtype>& pubkeys) +{ + opcodetype opcode; + valtype data; + CScript::const_iterator it = script.begin(); + if (script.size() < 1 || script.back() != OP_CHECKMULTISIG) return false; + + if (!script.GetOp(it, opcode, data) || !IsSmallInteger(opcode)) return false; + required = CScript::DecodeOP_N(opcode); + while (script.GetOp(it, opcode, data) && CPubKey::ValidSize(data)) { + pubkeys.emplace_back(std::move(data)); } + if (!IsSmallInteger(opcode)) return false; + unsigned int keys = CScript::DecodeOP_N(opcode); + if (pubkeys.size() != keys || keys < required) return false; + return (it + 1 == script.end()); +} +txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet) +{ vSolutionsRet.clear(); // Shortcut for pay-to-script-hash, which are more constrained than the other types: // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL if (scriptPubKey.IsPayToScriptHash()) { - typeRet = TX_SCRIPTHASH; std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); vSolutionsRet.push_back(hashBytes); - return true; + return TX_SCRIPTHASH; } int witnessversion; std::vector<unsigned char> witnessprogram; if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) { if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) { - typeRet = TX_WITNESS_V0_KEYHASH; vSolutionsRet.push_back(witnessprogram); - return true; + return TX_WITNESS_V0_KEYHASH; } if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) { - typeRet = TX_WITNESS_V0_SCRIPTHASH; vSolutionsRet.push_back(witnessprogram); - return true; + return TX_WITNESS_V0_SCRIPTHASH; } if (witnessversion != 0) { - typeRet = TX_WITNESS_UNKNOWN; vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion}); vSolutionsRet.push_back(std::move(witnessprogram)); - return true; + return TX_WITNESS_UNKNOWN; } - return false; + return TX_NONSTANDARD; } // Provably prunable, data-carrying output @@ -91,104 +125,39 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v // byte passes the IsPushOnly() test we don't care what exactly is in the // script. if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) { - typeRet = TX_NULL_DATA; - return true; + return TX_NULL_DATA; } - // Scan templates - const CScript& script1 = scriptPubKey; - for (const std::pair<txnouttype, CScript>& tplate : mTemplates) - { - const CScript& script2 = tplate.second; - vSolutionsRet.clear(); + std::vector<unsigned char> data; + if (MatchPayToPubkey(scriptPubKey, data)) { + vSolutionsRet.push_back(std::move(data)); + return TX_PUBKEY; + } - opcodetype opcode1, opcode2; - std::vector<unsigned char> vch1, vch2; + if (MatchPayToPubkeyHash(scriptPubKey, data)) { + vSolutionsRet.push_back(std::move(data)); + return TX_PUBKEYHASH; + } - // Compare - CScript::const_iterator pc1 = script1.begin(); - CScript::const_iterator pc2 = script2.begin(); - while (true) - { - if (pc1 == script1.end() && pc2 == script2.end()) - { - // Found a match - typeRet = tplate.first; - if (typeRet == TX_MULTISIG) - { - // Additional checks for TX_MULTISIG: - unsigned char m = vSolutionsRet.front()[0]; - unsigned char n = vSolutionsRet.back()[0]; - if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n) - return false; - } - return true; - } - if (!script1.GetOp(pc1, opcode1, vch1)) - break; - if (!script2.GetOp(pc2, opcode2, vch2)) - break; - - // Template matching opcodes: - if (opcode2 == OP_PUBKEYS) - { - while (CPubKey::ValidSize(vch1)) - { - vSolutionsRet.push_back(vch1); - if (!script1.GetOp(pc1, opcode1, vch1)) - break; - } - if (!script2.GetOp(pc2, opcode2, vch2)) - break; - // Normal situation is to fall through - // to other if/else statements - } - - if (opcode2 == OP_PUBKEY) - { - if (!CPubKey::ValidSize(vch1)) - break; - vSolutionsRet.push_back(vch1); - } - else if (opcode2 == OP_PUBKEYHASH) - { - if (vch1.size() != sizeof(uint160)) - break; - vSolutionsRet.push_back(vch1); - } - else if (opcode2 == OP_SMALLINTEGER) - { // Single-byte small integer pushed onto vSolutions - if (opcode1 == OP_0 || - (opcode1 >= OP_1 && opcode1 <= OP_16)) - { - char n = (char)CScript::DecodeOP_N(opcode1); - vSolutionsRet.push_back(valtype(1, n)); - } - else - break; - } - else if (opcode1 != opcode2 || vch1 != vch2) - { - // Others must match exactly - break; - } - } + unsigned int required; + std::vector<std::vector<unsigned char>> keys; + if (MatchMultisig(scriptPubKey, required, keys)) { + vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..16 + vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end()); + vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..16 + return TX_MULTISIG; } vSolutionsRet.clear(); - typeRet = TX_NONSTANDARD; - return false; + return TX_NONSTANDARD; } bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { std::vector<valtype> vSolutions; - txnouttype whichType; - if (!Solver(scriptPubKey, whichType, vSolutions)) - return false; + txnouttype whichType = Solver(scriptPubKey, vSolutions); - if (whichType == TX_PUBKEY) - { + if (whichType == TX_PUBKEY) { CPubKey pubKey(vSolutions[0]); if (!pubKey.IsValid()) return false; @@ -230,11 +199,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet) { addressRet.clear(); - typeRet = TX_NONSTANDARD; std::vector<valtype> vSolutions; - if (!Solver(scriptPubKey, typeRet, vSolutions)) + typeRet = Solver(scriptPubKey, vSolutions); + if (typeRet == TX_NONSTANDARD) { return false; - if (typeRet == TX_NULL_DATA){ + } else if (typeRet == TX_NULL_DATA) { // This is data, not addresses return false; } @@ -342,20 +311,14 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys) CScript GetScriptForWitness(const CScript& redeemscript) { - CScript ret; - - txnouttype typ; std::vector<std::vector<unsigned char> > vSolutions; - if (Solver(redeemscript, typ, vSolutions)) { - if (typ == TX_PUBKEY) { - return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end()))); - } else if (typ == TX_PUBKEYHASH) { - return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0])); - } + txnouttype typ = Solver(redeemscript, vSolutions); + if (typ == TX_PUBKEY) { + return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end()))); + } else if (typ == TX_PUBKEYHASH) { + return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0])); } - uint256 hash; - CSHA256().Write(&redeemscript[0], redeemscript.size()).Finalize(hash.begin()); - return GetScriptForDestination(WitnessV0ScriptHash(hash)); + return GetScriptForDestination(WitnessV0ScriptHash(redeemscript)); } bool IsValidDestination(const CTxDestination& dest) { diff --git a/src/script/standard.h b/src/script/standard.h index 4922b7236b..fc20fb6a08 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// 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. @@ -77,6 +77,7 @@ struct WitnessV0ScriptHash : public uint256 { WitnessV0ScriptHash() : uint256() {} explicit WitnessV0ScriptHash(const uint256& hash) : uint256(hash) {} + explicit WitnessV0ScriptHash(const CScript& script); using uint256::uint256; }; @@ -134,11 +135,10 @@ const char* GetTxnOutputType(txnouttype t); * script hash, for P2PKH it will contain the key hash, etc. * * @param[in] scriptPubKey Script to parse - * @param[out] typeRet The script type * @param[out] vSolutionsRet Vector of parsed pubkeys and hashes - * @return True if script matches standard template + * @return The script type. TX_NONSTANDARD represents a failed solve. */ -bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet); +txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet); /** * Parse a standard scriptPubKey for the destination address. Assigns result to |