Bitcoin Core  0.18.99
P2P Digital Currency
keystore.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2018 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 <keystore.h>
7 
8 #include <util/system.h>
9 
11 {
13  CKeyID key_id = pubkey.GetID();
14  // We must actually know about this key already.
15  assert(HaveKey(key_id) || mapWatchKeys.count(key_id));
16  // This adds the redeemscripts necessary to detect P2WPKH and P2SH-P2WPKH
17  // outputs. Technically P2WPKH outputs don't have a redeemscript to be
18  // spent. However, our current IsMine logic requires the corresponding
19  // P2SH-P2WPKH redeemscript to be present in the wallet in order to accept
20  // payment even to P2WPKH outputs.
21  // Also note that having superfluous scripts in the keystore never hurts.
22  // They're only used to guide recursion in signing and IsMine logic - if
23  // a script is present but we can't do anything with it, it has no effect.
24  // "Implicitly" refers to fact that scripts are derived automatically from
25  // existing keys, and are present in memory, even without being explicitly
26  // loaded (e.g. from a file).
27  if (pubkey.IsCompressed()) {
29  // This does not use AddCScript, as it may be overridden.
30  CScriptID id(script);
31  mapScripts[id] = std::move(script);
32  }
33 }
34 
35 bool CBasicKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
36 {
37  CKey key;
38  if (!GetKey(address, key)) {
40  WatchKeyMap::const_iterator it = mapWatchKeys.find(address);
41  if (it != mapWatchKeys.end()) {
42  vchPubKeyOut = it->second;
43  return true;
44  }
45  return false;
46  }
47  vchPubKeyOut = key.GetPubKey();
48  return true;
49 }
50 
51 bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
52 {
54  mapKeys[pubkey.GetID()] = key;
56  return true;
57 }
58 
59 bool CBasicKeyStore::HaveKey(const CKeyID &address) const
60 {
62  return mapKeys.count(address) > 0;
63 }
64 
65 std::set<CKeyID> CBasicKeyStore::GetKeys() const
66 {
68  std::set<CKeyID> set_address;
69  for (const auto& mi : mapKeys) {
70  set_address.insert(mi.first);
71  }
72  return set_address;
73 }
74 
75 bool CBasicKeyStore::GetKey(const CKeyID &address, CKey &keyOut) const
76 {
78  KeyMap::const_iterator mi = mapKeys.find(address);
79  if (mi != mapKeys.end()) {
80  keyOut = mi->second;
81  return true;
82  }
83  return false;
84 }
85 
86 bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
87 {
88  if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
89  return error("CBasicKeyStore::AddCScript(): redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE);
90 
92  mapScripts[CScriptID(redeemScript)] = redeemScript;
93  return true;
94 }
95 
96 bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const
97 {
99  return mapScripts.count(hash) > 0;
100 }
101 
102 std::set<CScriptID> CBasicKeyStore::GetCScripts() const
103 {
104  LOCK(cs_KeyStore);
105  std::set<CScriptID> set_script;
106  for (const auto& mi : mapScripts) {
107  set_script.insert(mi.first);
108  }
109  return set_script;
110 }
111 
112 bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
113 {
114  LOCK(cs_KeyStore);
115  ScriptMap::const_iterator mi = mapScripts.find(hash);
116  if (mi != mapScripts.end())
117  {
118  redeemScriptOut = (*mi).second;
119  return true;
120  }
121  return false;
122 }
123 
124 static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)
125 {
126  //TODO: Use Solver to extract this?
127  CScript::const_iterator pc = dest.begin();
128  opcodetype opcode;
129  std::vector<unsigned char> vch;
130  if (!dest.GetOp(pc, opcode, vch) || !CPubKey::ValidSize(vch))
131  return false;
132  pubKeyOut = CPubKey(vch);
133  if (!pubKeyOut.IsFullyValid())
134  return false;
135  if (!dest.GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG || dest.GetOp(pc, opcode, vch))
136  return false;
137  return true;
138 }
139 
141 {
142  LOCK(cs_KeyStore);
143  setWatchOnly.insert(dest);
144  CPubKey pubKey;
145  if (ExtractPubKey(dest, pubKey)) {
146  mapWatchKeys[pubKey.GetID()] = pubKey;
148  }
149  return true;
150 }
151 
153 {
154  LOCK(cs_KeyStore);
155  setWatchOnly.erase(dest);
156  CPubKey pubKey;
157  if (ExtractPubKey(dest, pubKey)) {
158  mapWatchKeys.erase(pubKey.GetID());
159  }
160  // Related CScripts are not removed; having superfluous scripts around is
161  // harmless (see comment in ImplicitlyLearnRelatedKeyScripts).
162  return true;
163 }
164 
165 bool CBasicKeyStore::HaveWatchOnly(const CScript &dest) const
166 {
167  LOCK(cs_KeyStore);
168  return setWatchOnly.count(dest) > 0;
169 }
170 
172 {
173  LOCK(cs_KeyStore);
174  return (!setWatchOnly.empty());
175 }
176 
178 {
179  // Only supports destinations which map to single public keys, i.e. P2PKH,
180  // P2WPKH, and P2SH-P2WPKH.
181  if (auto id = boost::get<PKHash>(&dest)) {
182  return CKeyID(*id);
183  }
184  if (auto witness_id = boost::get<WitnessV0KeyHash>(&dest)) {
185  return CKeyID(*witness_id);
186  }
187  if (auto script_hash = boost::get<ScriptHash>(&dest)) {
188  CScript script;
189  CScriptID script_id(*script_hash);
190  CTxDestination inner_dest;
191  if (store.GetCScript(script_id, script) && ExtractDestination(script, inner_dest)) {
192  if (auto inner_witness_id = boost::get<WitnessV0KeyHash>(&inner_dest)) {
193  return CKeyID(*inner_witness_id);
194  }
195  }
196  }
197  return CKeyID();
198 }
199 
200 bool HaveKey(const CKeyStore& store, const CKey& key)
201 {
202  CKey key2;
203  key2.Set(key.begin(), key.end(), !key.IsCompressed());
204  return store.HaveKey(key.GetPubKey().GetID()) || store.HaveKey(key2.GetPubKey().GetID());
205 }
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:157
bool GetOp(const_iterator &pc, opcodetype &opcodeRet, std::vector< unsigned char > &vchRet) const
Definition: script.h:497
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:184
bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const override
Definition: keystore.cpp:35
CCriticalSection cs_KeyStore
Definition: keystore.h:45
bool HaveCScript(const CScriptID &hash) const override
Definition: keystore.cpp:96
std::set< CScriptID > GetCScripts() const override
Definition: keystore.cpp:102
bool GetCScript(const CScriptID &hash, CScript &redeemScriptOut) const override
Definition: keystore.cpp:112
void ImplicitlyLearnRelatedKeyScripts(const CPubKey &pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore)
Definition: keystore.cpp:10
std::set< CKeyID > GetKeys() const override
Definition: keystore.cpp:65
bool AddCScript(const CScript &redeemScript) override
Support for BIP 0013 : see https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki.
Definition: keystore.cpp:86
CKeyID GetKeyForDestination(const CKeyStore &store, const CTxDestination &dest)
Return the CKeyID of the key involved in a script (if there is a unique one).
Definition: keystore.cpp:177
const unsigned char * begin() const
Definition: key.h:89
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:155
static bool ValidSize(const std::vector< unsigned char > &vch)
Definition: pubkey.h:74
opcodetype
Script opcodes.
Definition: script.h:54
bool IsFullyValid() const
fully validate whether this is a valid public key (more expensive than IsValid()) ...
Definition: pubkey.cpp:206
#define LOCK(cs)
Definition: sync.h:182
virtual bool HaveKey(const CKeyID &address) const =0
Check whether a key corresponding to a given address is present in the store.
An encapsulated public key.
Definition: pubkey.h:30
bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) override
Add a key to the store.
Definition: keystore.cpp:51
bool GetKey(const CKeyID &address, CKey &keyOut) const override
Definition: keystore.cpp:75
bool IsCompressed() const
Check whether the public key corresponding to this private key is (to be) compressed.
Definition: key.h:96
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:290
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:74
bool RemoveWatchOnly(const CScript &dest) override
Definition: keystore.cpp:152
virtual bool GetCScript(const CScriptID &scriptid, CScript &script) const
Definition: sign.h:53
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:390
const unsigned char * end() const
Definition: key.h:90
A virtual base class for key stores.
Definition: keystore.h:19
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:20
iterator begin()
Definition: prevector.h:285
A reference to a CScript: the Hash160 of its serialization (see script.h)
Definition: standard.h:22
size_type size() const
Definition: prevector.h:277
An encapsulated private key.
Definition: key.h:27
bool HaveWatchOnly() const override
Definition: keystore.cpp:171
boost::variant< CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:139
AssertLockHeld(g_cs_orphans)
bool HaveKey(const CKeyID &address) const override
Check whether a key corresponding to a given address is present in the store.
Definition: keystore.cpp:59
bool error(const char *fmt, const Args &... args)
Definition: system.h:61
bool AddWatchOnly(const CScript &dest) override
Support for Watch-only addresses.
Definition: keystore.cpp:140
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:180