1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2019 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include <script/keyorigin.h>
7 #include <script/signingprovider.h>
8 #include <script/standard.h>
9
10 #include <util/system.h>
11
12 const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider();
13
14 template<typename M, typename K, typename V>
LookupHelper(const M & map,const K & key,V & value)15 bool LookupHelper(const M& map, const K& key, V& value)
16 {
17 auto it = map.find(key);
18 if (it != map.end()) {
19 value = it->second;
20 return true;
21 }
22 return false;
23 }
24
GetCScript(const CScriptID & scriptid,CScript & script) const25 bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const
26 {
27 return m_provider->GetCScript(scriptid, script);
28 }
29
GetPubKey(const CKeyID & keyid,CPubKey & pubkey) const30 bool HidingSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const
31 {
32 return m_provider->GetPubKey(keyid, pubkey);
33 }
34
GetKey(const CKeyID & keyid,CKey & key) const35 bool HidingSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const
36 {
37 if (m_hide_secret) return false;
38 return m_provider->GetKey(keyid, key);
39 }
40
GetKeyOrigin(const CKeyID & keyid,KeyOriginInfo & info) const41 bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const
42 {
43 if (m_hide_origin) return false;
44 return m_provider->GetKeyOrigin(keyid, info);
45 }
46
GetCScript(const CScriptID & scriptid,CScript & script) const47 bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); }
GetPubKey(const CKeyID & keyid,CPubKey & pubkey) const48 bool FlatSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const { return LookupHelper(pubkeys, keyid, pubkey); }
GetKeyOrigin(const CKeyID & keyid,KeyOriginInfo & info) const49 bool FlatSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const
50 {
51 std::pair<CPubKey, KeyOriginInfo> out;
52 bool ret = LookupHelper(origins, keyid, out);
53 if (ret) info = std::move(out.second);
54 return ret;
55 }
GetKey(const CKeyID & keyid,CKey & key) const56 bool FlatSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const { return LookupHelper(keys, keyid, key); }
57
Merge(const FlatSigningProvider & a,const FlatSigningProvider & b)58 FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b)
59 {
60 FlatSigningProvider ret;
61 ret.scripts = a.scripts;
62 ret.scripts.insert(b.scripts.begin(), b.scripts.end());
63 ret.pubkeys = a.pubkeys;
64 ret.pubkeys.insert(b.pubkeys.begin(), b.pubkeys.end());
65 ret.keys = a.keys;
66 ret.keys.insert(b.keys.begin(), b.keys.end());
67 ret.origins = a.origins;
68 ret.origins.insert(b.origins.begin(), b.origins.end());
69 return ret;
70 }
71
ImplicitlyLearnRelatedKeyScripts(const CPubKey & pubkey)72 void FillableSigningProvider::ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey)
73 {
74 AssertLockHeld(cs_KeyStore);
75 CKeyID key_id = pubkey.GetID();
76 // This adds the redeemscripts necessary to detect P2WPKH and P2SH-P2WPKH
77 // outputs. Technically P2WPKH outputs don't have a redeemscript to be
78 // spent. However, our current IsMine logic requires the corresponding
79 // P2SH-P2WPKH redeemscript to be present in the wallet in order to accept
80 // payment even to P2WPKH outputs.
81 // Also note that having superfluous scripts in the keystore never hurts.
82 // They're only used to guide recursion in signing and IsMine logic - if
83 // a script is present but we can't do anything with it, it has no effect.
84 // "Implicitly" refers to fact that scripts are derived automatically from
85 // existing keys, and are present in memory, even without being explicitly
86 // loaded (e.g. from a file).
87 if (pubkey.IsCompressed()) {
88 CScript script = GetScriptForDestination(WitnessV0KeyHash(key_id));
89 // This does not use AddCScript, as it may be overridden.
90 CScriptID id(script);
91 mapScripts[id] = std::move(script);
92 }
93 }
94
GetPubKey(const CKeyID & address,CPubKey & vchPubKeyOut) const95 bool FillableSigningProvider::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
96 {
97 CKey key;
98 if (!GetKey(address, key)) {
99 return false;
100 }
101 vchPubKeyOut = key.GetPubKey();
102 return true;
103 }
104
AddKeyPubKey(const CKey & key,const CPubKey & pubkey)105 bool FillableSigningProvider::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
106 {
107 LOCK(cs_KeyStore);
108 mapKeys[pubkey.GetID()] = key;
109 ImplicitlyLearnRelatedKeyScripts(pubkey);
110 return true;
111 }
112
HaveKey(const CKeyID & address) const113 bool FillableSigningProvider::HaveKey(const CKeyID &address) const
114 {
115 LOCK(cs_KeyStore);
116 return mapKeys.count(address) > 0;
117 }
118
GetKeys() const119 std::set<CKeyID> FillableSigningProvider::GetKeys() const
120 {
121 LOCK(cs_KeyStore);
122 std::set<CKeyID> set_address;
123 for (const auto& mi : mapKeys) {
124 set_address.insert(mi.first);
125 }
126 return set_address;
127 }
128
GetKey(const CKeyID & address,CKey & keyOut) const129 bool FillableSigningProvider::GetKey(const CKeyID &address, CKey &keyOut) const
130 {
131 LOCK(cs_KeyStore);
132 KeyMap::const_iterator mi = mapKeys.find(address);
133 if (mi != mapKeys.end()) {
134 keyOut = mi->second;
135 return true;
136 }
137 return false;
138 }
139
AddCScript(const CScript & redeemScript)140 bool FillableSigningProvider::AddCScript(const CScript& redeemScript)
141 {
142 if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
143 return error("FillableSigningProvider::AddCScript(): redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE);
144
145 LOCK(cs_KeyStore);
146 mapScripts[CScriptID(redeemScript)] = redeemScript;
147 return true;
148 }
149
HaveCScript(const CScriptID & hash) const150 bool FillableSigningProvider::HaveCScript(const CScriptID& hash) const
151 {
152 LOCK(cs_KeyStore);
153 return mapScripts.count(hash) > 0;
154 }
155
GetCScripts() const156 std::set<CScriptID> FillableSigningProvider::GetCScripts() const
157 {
158 LOCK(cs_KeyStore);
159 std::set<CScriptID> set_script;
160 for (const auto& mi : mapScripts) {
161 set_script.insert(mi.first);
162 }
163 return set_script;
164 }
165
GetCScript(const CScriptID & hash,CScript & redeemScriptOut) const166 bool FillableSigningProvider::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
167 {
168 LOCK(cs_KeyStore);
169 ScriptMap::const_iterator mi = mapScripts.find(hash);
170 if (mi != mapScripts.end())
171 {
172 redeemScriptOut = (*mi).second;
173 return true;
174 }
175 return false;
176 }
177
GetKeyForDestination(const SigningProvider & store,const CTxDestination & dest)178 CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest)
179 {
180 // Only supports destinations which map to single public keys, i.e. P2PKH,
181 // P2WPKH, and P2SH-P2WPKH.
182 if (auto id = boost::get<PKHash>(&dest)) {
183 return ToKeyID(*id);
184 }
185 if (auto witness_id = boost::get<WitnessV0KeyHash>(&dest)) {
186 return ToKeyID(*witness_id);
187 }
188 if (auto script_hash = boost::get<ScriptHash>(&dest)) {
189 CScript script;
190 CScriptID script_id(*script_hash);
191 CTxDestination inner_dest;
192 if (store.GetCScript(script_id, script) && ExtractDestination(script, inner_dest)) {
193 if (auto inner_witness_id = boost::get<WitnessV0KeyHash>(&inner_dest)) {
194 return ToKeyID(*inner_witness_id);
195 }
196 }
197 }
198 return CKeyID();
199 }
200