aboutsummaryrefslogtreecommitdiff
path: root/src/script
diff options
context:
space:
mode:
authorAndrew Chow <achow101-github@achow101.com>2019-06-06 22:52:24 +0200
committerAndrew Chow <achow101-github@achow101.com>2019-07-09 16:20:18 -0400
commit37a79a4fccbf6cd65a933594e24e59d36e674653 (patch)
tree3ef48673c8380a9c7a18cd2e790512177384ca54 /src/script
parent16f8096e911e4d59292240a17e2d4004f0500b9e (diff)
downloadbitcoin-37a79a4fccbf6cd65a933594e24e59d36e674653.tar.xz
Move various SigningProviders to signingprovider.{cpp,h}
Moves all of the various SigningProviders out of sign.{cpp,h} and keystore.{cpp,h}. As such, keystore.{cpp,h} is also removed. Includes and the Makefile are updated to reflect this. Includes were largely changed using: git grep -l "keystore.h" | xargs sed -i -e 's;keystore.h;script/signingprovider.h;g'
Diffstat (limited to 'src/script')
-rw-r--r--src/script/descriptor.h1
-rw-r--r--src/script/sign.cpp60
-rw-r--r--src/script/sign.h46
-rw-r--r--src/script/signingprovider.cpp260
-rw-r--r--src/script/signingprovider.h101
-rw-r--r--src/script/standard.cpp1
6 files changed, 364 insertions, 105 deletions
diff --git a/src/script/descriptor.h b/src/script/descriptor.h
index af7ae229ca..29915c6c92 100644
--- a/src/script/descriptor.h
+++ b/src/script/descriptor.h
@@ -7,6 +7,7 @@
#include <script/script.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
#include <vector>
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 5320dc0876..13481af9c5 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -8,6 +8,7 @@
#include <key.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
+#include <script/signingprovider.h>
#include <script/standard.h>
#include <uint256.h>
@@ -423,22 +424,10 @@ public:
}
};
-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(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)
{
@@ -459,53 +448,6 @@ bool IsSolvable(const SigningProvider& provider, const CScript& script)
return false;
}
-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::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const
-{
- std::pair<CPubKey, KeyOriginInfo> out;
- bool ret = LookupHelper(origins, keyid, out);
- if (ret) info = std::move(out.second);
- return ret;
-}
-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());
- ret.origins = a.origins;
- ret.origins.insert(b.origins.begin(), b.origins.end());
- return ret;
-}
-
bool IsSegWitOutput(const SigningProvider& provider, const CScript& script)
{
std::vector<valtype> solutions;
diff --git a/src/script/sign.h b/src/script/sign.h
index 7b4627cca2..0e751afd3b 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -18,54 +18,10 @@ class CKeyID;
class CScript;
class CScriptID;
class CTransaction;
+class SigningProvider;
struct CMutableTransaction;
-/** An interface to be implemented by keystores that support signing. */
-class SigningProvider
-{
-public:
- virtual ~SigningProvider() {}
- virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; }
- virtual bool HaveCScript(const CScriptID &scriptid) 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 HaveKey(const CKeyID &address) const { return false; }
- virtual bool GetKeyOrigin(const CKeyID& keyid, 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, std::pair<CPubKey, KeyOriginInfo>> origins;
- std::map<CKeyID, CKey> keys;
-
- bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
- bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
- bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) 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:
diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp
new file mode 100644
index 0000000000..a859a41c50
--- /dev/null
+++ b/src/script/signingprovider.cpp
@@ -0,0 +1,260 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2019 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/keyorigin.h>
+#include <script/signingprovider.h>
+#include <script/standard.h>
+
+#include <util/system.h>
+
+const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider();
+
+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;
+}
+
+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::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const
+{
+ std::pair<CPubKey, KeyOriginInfo> out;
+ bool ret = LookupHelper(origins, keyid, out);
+ if (ret) info = std::move(out.second);
+ return ret;
+}
+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());
+ ret.origins = a.origins;
+ ret.origins.insert(b.origins.begin(), b.origins.end());
+ return ret;
+}
+
+void FillableSigningProvider::ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey)
+{
+ AssertLockHeld(cs_KeyStore);
+ CKeyID key_id = pubkey.GetID();
+ // We must actually know about this key already.
+ assert(HaveKey(key_id) || mapWatchKeys.count(key_id));
+ // This adds the redeemscripts necessary to detect P2WPKH and P2SH-P2WPKH
+ // outputs. Technically P2WPKH outputs don't have a redeemscript to be
+ // spent. However, our current IsMine logic requires the corresponding
+ // P2SH-P2WPKH redeemscript to be present in the wallet in order to accept
+ // payment even to P2WPKH outputs.
+ // Also note that having superfluous scripts in the keystore never hurts.
+ // They're only used to guide recursion in signing and IsMine logic - if
+ // a script is present but we can't do anything with it, it has no effect.
+ // "Implicitly" refers to fact that scripts are derived automatically from
+ // existing keys, and are present in memory, even without being explicitly
+ // loaded (e.g. from a file).
+ if (pubkey.IsCompressed()) {
+ CScript script = GetScriptForDestination(WitnessV0KeyHash(key_id));
+ // This does not use AddCScript, as it may be overridden.
+ CScriptID id(script);
+ mapScripts[id] = std::move(script);
+ }
+}
+
+bool FillableSigningProvider::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
+{
+ CKey key;
+ if (!GetKey(address, key)) {
+ LOCK(cs_KeyStore);
+ WatchKeyMap::const_iterator it = mapWatchKeys.find(address);
+ if (it != mapWatchKeys.end()) {
+ vchPubKeyOut = it->second;
+ return true;
+ }
+ return false;
+ }
+ vchPubKeyOut = key.GetPubKey();
+ return true;
+}
+
+bool FillableSigningProvider::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
+{
+ LOCK(cs_KeyStore);
+ mapKeys[pubkey.GetID()] = key;
+ ImplicitlyLearnRelatedKeyScripts(pubkey);
+ return true;
+}
+
+bool FillableSigningProvider::HaveKey(const CKeyID &address) const
+{
+ LOCK(cs_KeyStore);
+ return mapKeys.count(address) > 0;
+}
+
+std::set<CKeyID> FillableSigningProvider::GetKeys() const
+{
+ LOCK(cs_KeyStore);
+ std::set<CKeyID> set_address;
+ for (const auto& mi : mapKeys) {
+ set_address.insert(mi.first);
+ }
+ return set_address;
+}
+
+bool FillableSigningProvider::GetKey(const CKeyID &address, CKey &keyOut) const
+{
+ LOCK(cs_KeyStore);
+ KeyMap::const_iterator mi = mapKeys.find(address);
+ if (mi != mapKeys.end()) {
+ keyOut = mi->second;
+ return true;
+ }
+ return false;
+}
+
+bool FillableSigningProvider::AddCScript(const CScript& redeemScript)
+{
+ if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
+ return error("FillableSigningProvider::AddCScript(): redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE);
+
+ LOCK(cs_KeyStore);
+ mapScripts[CScriptID(redeemScript)] = redeemScript;
+ return true;
+}
+
+bool FillableSigningProvider::HaveCScript(const CScriptID& hash) const
+{
+ LOCK(cs_KeyStore);
+ return mapScripts.count(hash) > 0;
+}
+
+std::set<CScriptID> FillableSigningProvider::GetCScripts() const
+{
+ LOCK(cs_KeyStore);
+ std::set<CScriptID> set_script;
+ for (const auto& mi : mapScripts) {
+ set_script.insert(mi.first);
+ }
+ return set_script;
+}
+
+bool FillableSigningProvider::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
+{
+ LOCK(cs_KeyStore);
+ ScriptMap::const_iterator mi = mapScripts.find(hash);
+ if (mi != mapScripts.end())
+ {
+ redeemScriptOut = (*mi).second;
+ return true;
+ }
+ return false;
+}
+
+static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)
+{
+ //TODO: Use Solver to extract this?
+ CScript::const_iterator pc = dest.begin();
+ opcodetype opcode;
+ std::vector<unsigned char> vch;
+ if (!dest.GetOp(pc, opcode, vch) || !CPubKey::ValidSize(vch))
+ return false;
+ pubKeyOut = CPubKey(vch);
+ if (!pubKeyOut.IsFullyValid())
+ return false;
+ if (!dest.GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG || dest.GetOp(pc, opcode, vch))
+ return false;
+ return true;
+}
+
+bool FillableSigningProvider::AddWatchOnly(const CScript &dest)
+{
+ LOCK(cs_KeyStore);
+ setWatchOnly.insert(dest);
+ CPubKey pubKey;
+ if (ExtractPubKey(dest, pubKey)) {
+ mapWatchKeys[pubKey.GetID()] = pubKey;
+ ImplicitlyLearnRelatedKeyScripts(pubKey);
+ }
+ return true;
+}
+
+bool FillableSigningProvider::RemoveWatchOnly(const CScript &dest)
+{
+ LOCK(cs_KeyStore);
+ setWatchOnly.erase(dest);
+ CPubKey pubKey;
+ if (ExtractPubKey(dest, pubKey)) {
+ mapWatchKeys.erase(pubKey.GetID());
+ }
+ // Related CScripts are not removed; having superfluous scripts around is
+ // harmless (see comment in ImplicitlyLearnRelatedKeyScripts).
+ return true;
+}
+
+bool FillableSigningProvider::HaveWatchOnly(const CScript &dest) const
+{
+ LOCK(cs_KeyStore);
+ return setWatchOnly.count(dest) > 0;
+}
+
+bool FillableSigningProvider::HaveWatchOnly() const
+{
+ LOCK(cs_KeyStore);
+ return (!setWatchOnly.empty());
+}
+
+CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest)
+{
+ // Only supports destinations which map to single public keys, i.e. P2PKH,
+ // P2WPKH, and P2SH-P2WPKH.
+ if (auto id = boost::get<PKHash>(&dest)) {
+ return CKeyID(*id);
+ }
+ if (auto witness_id = boost::get<WitnessV0KeyHash>(&dest)) {
+ return CKeyID(*witness_id);
+ }
+ if (auto script_hash = boost::get<ScriptHash>(&dest)) {
+ CScript script;
+ CScriptID script_id(*script_hash);
+ CTxDestination inner_dest;
+ if (store.GetCScript(script_id, script) && ExtractDestination(script, inner_dest)) {
+ if (auto inner_witness_id = boost::get<WitnessV0KeyHash>(&inner_dest)) {
+ return CKeyID(*inner_witness_id);
+ }
+ }
+ }
+ return CKeyID();
+}
diff --git a/src/script/signingprovider.h b/src/script/signingprovider.h
new file mode 100644
index 0000000000..5ead763826
--- /dev/null
+++ b/src/script/signingprovider.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2019 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_SIGNINGPROVIDER_H
+#define BITCOIN_SCRIPT_SIGNINGPROVIDER_H
+
+#include <key.h>
+#include <pubkey.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <sync.h>
+
+struct KeyOriginInfo;
+
+/** An interface to be implemented by keystores that support signing. */
+class SigningProvider
+{
+public:
+ virtual ~SigningProvider() {}
+ virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; }
+ virtual bool HaveCScript(const CScriptID &scriptid) 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 HaveKey(const CKeyID &address) const { return false; }
+ virtual bool GetKeyOrigin(const CKeyID& keyid, 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, std::pair<CPubKey, KeyOriginInfo>> origins;
+ std::map<CKeyID, CKey> keys;
+
+ bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
+ bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
+ bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
+ bool GetKey(const CKeyID& keyid, CKey& key) const override;
+};
+
+FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b);
+
+/** Fillable signing provider that keeps keys in an address->secret map */
+class FillableSigningProvider : public SigningProvider
+{
+protected:
+ mutable CCriticalSection cs_KeyStore;
+
+ using KeyMap = std::map<CKeyID, CKey>;
+ using WatchKeyMap = std::map<CKeyID, CPubKey>;
+ using ScriptMap = std::map<CScriptID, CScript>;
+ using WatchOnlySet = std::set<CScript>;
+
+ KeyMap mapKeys GUARDED_BY(cs_KeyStore);
+ WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore);
+ ScriptMap mapScripts GUARDED_BY(cs_KeyStore);
+ WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore);
+
+ void ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
+
+public:
+ virtual bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
+ virtual bool AddKey(const CKey &key) { return AddKeyPubKey(key, key.GetPubKey()); }
+ virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
+ virtual bool HaveKey(const CKeyID &address) const override;
+ virtual std::set<CKeyID> GetKeys() const;
+ virtual bool GetKey(const CKeyID &address, CKey &keyOut) const override;
+ virtual bool AddCScript(const CScript& redeemScript);
+ virtual bool HaveCScript(const CScriptID &hash) const override;
+ virtual std::set<CScriptID> GetCScripts() const;
+ virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override;
+
+ virtual bool AddWatchOnly(const CScript &dest);
+ virtual bool RemoveWatchOnly(const CScript &dest);
+ virtual bool HaveWatchOnly(const CScript &dest) const;
+ virtual bool HaveWatchOnly() const;
+};
+
+/** Return the CKeyID of the key involved in a script (if there is a unique one). */
+CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest);
+
+#endif // BITCOIN_SCRIPT_SIGNINGPROVIDER_H
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index b7d6cd925c..fc6898f444 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -9,7 +9,6 @@
#include <pubkey.h>
#include <script/script.h>
-
typedef std::vector<unsigned char> valtype;
bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER;