1 // Copyright (c) 2019 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include <key_io.h>
6 #include <outputtype.h>
7 #include <script/descriptor.h>
8 #include <script/sign.h>
9 #include <util/bip32.h>
10 #include <util/strencodings.h>
11 #include <util/string.h>
12 #include <util/translation.h>
13 #include <wallet/scriptpubkeyman.h>
14
GetNewDestination(const OutputType type,CTxDestination & dest,std::string & error)15 bool LegacyScriptPubKeyMan::GetNewDestination(const OutputType type, CTxDestination& dest, std::string& error)
16 {
17 LOCK(cs_KeyStore);
18 error.clear();
19
20 // Generate a new key that is added to wallet
21 CPubKey new_key;
22 if (!GetKeyFromPool(new_key, type)) {
23 error = "Error: Keypool ran out, please call keypoolrefill first";
24 return false;
25 }
26 LearnRelatedScripts(new_key, type);
27 dest = GetDestinationForKey(new_key, type);
28 return true;
29 }
30
31 typedef std::vector<unsigned char> valtype;
32
33 namespace {
34
35 /**
36 * This is an enum that tracks the execution context of a script, similar to
37 * SigVersion in script/interpreter. It is separate however because we want to
38 * distinguish between top-level scriptPubKey execution and P2SH redeemScript
39 * execution (a distinction that has no impact on consensus rules).
40 */
41 enum class IsMineSigVersion
42 {
43 TOP = 0, //!< scriptPubKey execution
44 P2SH = 1, //!< P2SH redeemScript
45 WITNESS_V0 = 2, //!< P2WSH witness script execution
46 };
47
48 /**
49 * This is an internal representation of isminetype + invalidity.
50 * Its order is significant, as we return the max of all explored
51 * possibilities.
52 */
53 enum class IsMineResult
54 {
55 NO = 0, //!< Not ours
56 WATCH_ONLY = 1, //!< Included in watch-only balance
57 SPENDABLE = 2, //!< Included in all balances
58 INVALID = 3, //!< Not spendable by anyone (uncompressed pubkey in segwit, P2SH inside P2SH or witness, witness inside witness)
59 };
60
PermitsUncompressed(IsMineSigVersion sigversion)61 bool PermitsUncompressed(IsMineSigVersion sigversion)
62 {
63 return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH;
64 }
65
HaveKeys(const std::vector<valtype> & pubkeys,const LegacyScriptPubKeyMan & keystore)66 bool HaveKeys(const std::vector<valtype>& pubkeys, const LegacyScriptPubKeyMan& keystore)
67 {
68 for (const valtype& pubkey : pubkeys) {
69 CKeyID keyID = CPubKey(pubkey).GetID();
70 if (!keystore.HaveKey(keyID)) return false;
71 }
72 return true;
73 }
74
75 //! Recursively solve script and return spendable/watchonly/invalid status.
76 //!
77 //! @param keystore legacy key and script store
78 //! @param script script to solve
79 //! @param sigversion script type (top-level / redeemscript / witnessscript)
80 //! @param recurse_scripthash whether to recurse into nested p2sh and p2wsh
81 //! scripts or simply treat any script that has been
82 //! stored in the keystore as spendable
IsMineInner(const LegacyScriptPubKeyMan & keystore,const CScript & scriptPubKey,IsMineSigVersion sigversion,bool recurse_scripthash=true)83 IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion, bool recurse_scripthash=true)
84 {
85 IsMineResult ret = IsMineResult::NO;
86
87 std::vector<valtype> vSolutions;
88 txnouttype whichType = Solver(scriptPubKey, vSolutions);
89
90 CKeyID keyID;
91 switch (whichType)
92 {
93 case TX_NONSTANDARD:
94 case TX_NULL_DATA:
95 case TX_WITNESS_UNKNOWN:
96 break;
97 case TX_PUBKEY:
98 keyID = CPubKey(vSolutions[0]).GetID();
99 if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) {
100 return IsMineResult::INVALID;
101 }
102 if (keystore.HaveKey(keyID)) {
103 ret = std::max(ret, IsMineResult::SPENDABLE);
104 }
105 break;
106 case TX_WITNESS_V0_KEYHASH:
107 {
108 if (sigversion == IsMineSigVersion::WITNESS_V0) {
109 // P2WPKH inside P2WSH is invalid.
110 return IsMineResult::INVALID;
111 }
112 if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
113 // We do not support bare witness outputs unless the P2SH version of it would be
114 // acceptable as well. This protects against matching before segwit activates.
115 // This also applies to the P2WSH case.
116 break;
117 }
118 ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(PKHash(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0));
119 break;
120 }
121 case TX_PUBKEYHASH:
122 keyID = CKeyID(uint160(vSolutions[0]));
123 if (!PermitsUncompressed(sigversion)) {
124 CPubKey pubkey;
125 if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) {
126 return IsMineResult::INVALID;
127 }
128 }
129 if (keystore.HaveKey(keyID)) {
130 ret = std::max(ret, IsMineResult::SPENDABLE);
131 }
132 break;
133 case TX_SCRIPTHASH:
134 {
135 if (sigversion != IsMineSigVersion::TOP) {
136 // P2SH inside P2WSH or P2SH is invalid.
137 return IsMineResult::INVALID;
138 }
139 CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
140 CScript subscript;
141 if (keystore.GetCScript(scriptID, subscript)) {
142 ret = std::max(ret, recurse_scripthash ? IsMineInner(keystore, subscript, IsMineSigVersion::P2SH) : IsMineResult::SPENDABLE);
143 }
144 break;
145 }
146 case TX_WITNESS_V0_SCRIPTHASH:
147 {
148 if (sigversion == IsMineSigVersion::WITNESS_V0) {
149 // P2WSH inside P2WSH is invalid.
150 return IsMineResult::INVALID;
151 }
152 if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
153 break;
154 }
155 uint160 hash;
156 CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(hash.begin());
157 CScriptID scriptID = CScriptID(hash);
158 CScript subscript;
159 if (keystore.GetCScript(scriptID, subscript)) {
160 ret = std::max(ret, recurse_scripthash ? IsMineInner(keystore, subscript, IsMineSigVersion::WITNESS_V0) : IsMineResult::SPENDABLE);
161 }
162 break;
163 }
164
165 case TX_MULTISIG:
166 {
167 // Never treat bare multisig outputs as ours (they can still be made watchonly-though)
168 if (sigversion == IsMineSigVersion::TOP) {
169 break;
170 }
171
172 // Only consider transactions "mine" if we own ALL the
173 // keys involved. Multi-signature transactions that are
174 // partially owned (somebody else has a key that can spend
175 // them) enable spend-out-from-under-you attacks, especially
176 // in shared-wallet situations.
177 std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
178 if (!PermitsUncompressed(sigversion)) {
179 for (size_t i = 0; i < keys.size(); i++) {
180 if (keys[i].size() != 33) {
181 return IsMineResult::INVALID;
182 }
183 }
184 }
185 if (HaveKeys(keys, keystore)) {
186 ret = std::max(ret, IsMineResult::SPENDABLE);
187 }
188 break;
189 }
190
191 default:
192 break;
193 }
194
195 if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) {
196 ret = std::max(ret, IsMineResult::WATCH_ONLY);
197 }
198 return ret;
199 }
200
201 } // namespace
202
IsMine(const CScript & script) const203 isminetype LegacyScriptPubKeyMan::IsMine(const CScript& script) const
204 {
205 switch (IsMineInner(*this, script, IsMineSigVersion::TOP)) {
206 case IsMineResult::INVALID:
207 case IsMineResult::NO:
208 return ISMINE_NO;
209 case IsMineResult::WATCH_ONLY:
210 return ISMINE_WATCH_ONLY;
211 case IsMineResult::SPENDABLE:
212 return ISMINE_SPENDABLE;
213 }
214 assert(false);
215 }
216
CheckDecryptionKey(const CKeyingMaterial & master_key,bool accept_no_keys)217 bool LegacyScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys)
218 {
219 {
220 LOCK(cs_KeyStore);
221 assert(mapKeys.empty());
222
223 bool keyPass = mapCryptedKeys.empty(); // Always pass when there are no encrypted keys
224 bool keyFail = false;
225 CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
226 for (; mi != mapCryptedKeys.end(); ++mi)
227 {
228 const CPubKey &vchPubKey = (*mi).second.first;
229 const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
230 CKey key;
231 if (!DecryptKey(master_key, vchCryptedSecret, vchPubKey, key))
232 {
233 keyFail = true;
234 break;
235 }
236 keyPass = true;
237 if (fDecryptionThoroughlyChecked)
238 break;
239 }
240 if (keyPass && keyFail)
241 {
242 LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
243 throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt.");
244 }
245 if (keyFail || (!keyPass && !accept_no_keys))
246 return false;
247 fDecryptionThoroughlyChecked = true;
248 }
249 return true;
250 }
251
Encrypt(const CKeyingMaterial & master_key,WalletBatch * batch)252 bool LegacyScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch)
253 {
254 LOCK(cs_KeyStore);
255 encrypted_batch = batch;
256 if (!mapCryptedKeys.empty()) {
257 encrypted_batch = nullptr;
258 return false;
259 }
260
261 KeyMap keys_to_encrypt;
262 keys_to_encrypt.swap(mapKeys); // Clear mapKeys so AddCryptedKeyInner will succeed.
263 for (const KeyMap::value_type& mKey : keys_to_encrypt)
264 {
265 const CKey &key = mKey.second;
266 CPubKey vchPubKey = key.GetPubKey();
267 CKeyingMaterial vchSecret(key.begin(), key.end());
268 std::vector<unsigned char> vchCryptedSecret;
269 if (!EncryptSecret(master_key, vchSecret, vchPubKey.GetHash(), vchCryptedSecret)) {
270 encrypted_batch = nullptr;
271 return false;
272 }
273 if (!AddCryptedKey(vchPubKey, vchCryptedSecret)) {
274 encrypted_batch = nullptr;
275 return false;
276 }
277 }
278 encrypted_batch = nullptr;
279 return true;
280 }
281
GetReservedDestination(const OutputType type,bool internal,CTxDestination & address,int64_t & index,CKeyPool & keypool)282 bool LegacyScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool)
283 {
284 LOCK(cs_KeyStore);
285 if (!CanGetAddresses(internal)) {
286 return false;
287 }
288
289 if (!ReserveKeyFromKeyPool(index, keypool, internal)) {
290 return false;
291 }
292 address = GetDestinationForKey(keypool.vchPubKey, type);
293 return true;
294 }
295
MarkUnusedAddresses(const CScript & script)296 void LegacyScriptPubKeyMan::MarkUnusedAddresses(const CScript& script)
297 {
298 LOCK(cs_KeyStore);
299 // extract addresses and check if they match with an unused keypool key
300 for (const auto& keyid : GetAffectedKeys(script, *this)) {
301 std::map<CKeyID, int64_t>::const_iterator mi = m_pool_key_to_index.find(keyid);
302 if (mi != m_pool_key_to_index.end()) {
303 WalletLogPrintf("%s: Detected a used keypool key, mark all keypool key up to this key as used\n", __func__);
304 MarkReserveKeysAsUsed(mi->second);
305
306 if (!TopUp()) {
307 WalletLogPrintf("%s: Topping up keypool failed (locked wallet)\n", __func__);
308 }
309 }
310 }
311 }
312
UpgradeKeyMetadata()313 void LegacyScriptPubKeyMan::UpgradeKeyMetadata()
314 {
315 LOCK(cs_KeyStore);
316 if (m_storage.IsLocked() || m_storage.IsWalletFlagSet(WALLET_FLAG_KEY_ORIGIN_METADATA)) {
317 return;
318 }
319
320 std::unique_ptr<WalletBatch> batch = MakeUnique<WalletBatch>(m_storage.GetDatabase());
321 for (auto& meta_pair : mapKeyMetadata) {
322 CKeyMetadata& meta = meta_pair.second;
323 if (!meta.hd_seed_id.IsNull() && !meta.has_key_origin && meta.hdKeypath != "s") { // If the hdKeypath is "s", that's the seed and it doesn't have a key origin
324 CKey key;
325 GetKey(meta.hd_seed_id, key);
326 CExtKey masterKey;
327 masterKey.SetSeed(key.begin(), key.size());
328 // Add to map
329 CKeyID master_id = masterKey.key.GetPubKey().GetID();
330 std::copy(master_id.begin(), master_id.begin() + 4, meta.key_origin.fingerprint);
331 if (!ParseHDKeypath(meta.hdKeypath, meta.key_origin.path)) {
332 throw std::runtime_error("Invalid stored hdKeypath");
333 }
334 meta.has_key_origin = true;
335 if (meta.nVersion < CKeyMetadata::VERSION_WITH_KEY_ORIGIN) {
336 meta.nVersion = CKeyMetadata::VERSION_WITH_KEY_ORIGIN;
337 }
338
339 // Write meta to wallet
340 CPubKey pubkey;
341 if (GetPubKey(meta_pair.first, pubkey)) {
342 batch->WriteKeyMetadata(meta, pubkey, true);
343 }
344 }
345 }
346 }
347
SetupGeneration(bool force)348 bool LegacyScriptPubKeyMan::SetupGeneration(bool force)
349 {
350 if ((CanGenerateKeys() && !force) || m_storage.IsLocked()) {
351 return false;
352 }
353
354 SetHDSeed(GenerateNewSeed());
355 if (!NewKeyPool()) {
356 return false;
357 }
358 return true;
359 }
360
IsHDEnabled() const361 bool LegacyScriptPubKeyMan::IsHDEnabled() const
362 {
363 return !hdChain.seed_id.IsNull();
364 }
365
CanGetAddresses(bool internal) const366 bool LegacyScriptPubKeyMan::CanGetAddresses(bool internal) const
367 {
368 LOCK(cs_KeyStore);
369 // Check if the keypool has keys
370 bool keypool_has_keys;
371 if (internal && m_storage.CanSupportFeature(FEATURE_HD_SPLIT)) {
372 keypool_has_keys = setInternalKeyPool.size() > 0;
373 } else {
374 keypool_has_keys = KeypoolCountExternalKeys() > 0;
375 }
376 // If the keypool doesn't have keys, check if we can generate them
377 if (!keypool_has_keys) {
378 return CanGenerateKeys();
379 }
380 return keypool_has_keys;
381 }
382
Upgrade(int prev_version,std::string & error)383 bool LegacyScriptPubKeyMan::Upgrade(int prev_version, std::string& error)
384 {
385 LOCK(cs_KeyStore);
386 error = "";
387 bool hd_upgrade = false;
388 bool split_upgrade = false;
389 if (m_storage.CanSupportFeature(FEATURE_HD) && !IsHDEnabled()) {
390 WalletLogPrintf("Upgrading wallet to HD\n");
391 m_storage.SetMinVersion(FEATURE_HD);
392
393 // generate a new master key
394 CPubKey masterPubKey = GenerateNewSeed();
395 SetHDSeed(masterPubKey);
396 hd_upgrade = true;
397 }
398 // Upgrade to HD chain split if necessary
399 if (m_storage.CanSupportFeature(FEATURE_HD_SPLIT) && CHDChain::VERSION_HD_CHAIN_SPLIT) {
400 WalletLogPrintf("Upgrading wallet to use HD chain split\n");
401 m_storage.SetMinVersion(FEATURE_PRE_SPLIT_KEYPOOL);
402 split_upgrade = FEATURE_HD_SPLIT > prev_version;
403 }
404 // Mark all keys currently in the keypool as pre-split
405 if (split_upgrade) {
406 MarkPreSplitKeys();
407 }
408 // Regenerate the keypool if upgraded to HD
409 if (hd_upgrade) {
410 if (!TopUp()) {
411 error = _("Unable to generate keys").translated;
412 return false;
413 }
414 }
415 return true;
416 }
417
HavePrivateKeys() const418 bool LegacyScriptPubKeyMan::HavePrivateKeys() const
419 {
420 LOCK(cs_KeyStore);
421 return !mapKeys.empty() || !mapCryptedKeys.empty();
422 }
423
RewriteDB()424 void LegacyScriptPubKeyMan::RewriteDB()
425 {
426 LOCK(cs_KeyStore);
427 setInternalKeyPool.clear();
428 setExternalKeyPool.clear();
429 m_pool_key_to_index.clear();
430 // Note: can't top-up keypool here, because wallet is locked.
431 // User will be prompted to unlock wallet the next operation
432 // that requires a new key.
433 }
434
GetOldestKeyTimeInPool(const std::set<int64_t> & setKeyPool,WalletBatch & batch)435 static int64_t GetOldestKeyTimeInPool(const std::set<int64_t>& setKeyPool, WalletBatch& batch) {
436 if (setKeyPool.empty()) {
437 return GetTime();
438 }
439
440 CKeyPool keypool;
441 int64_t nIndex = *(setKeyPool.begin());
442 if (!batch.ReadPool(nIndex, keypool)) {
443 throw std::runtime_error(std::string(__func__) + ": read oldest key in keypool failed");
444 }
445 assert(keypool.vchPubKey.IsValid());
446 return keypool.nTime;
447 }
448
GetOldestKeyPoolTime() const449 int64_t LegacyScriptPubKeyMan::GetOldestKeyPoolTime() const
450 {
451 LOCK(cs_KeyStore);
452
453 WalletBatch batch(m_storage.GetDatabase());
454
455 // load oldest key from keypool, get time and return
456 int64_t oldestKey = GetOldestKeyTimeInPool(setExternalKeyPool, batch);
457 if (IsHDEnabled() && m_storage.CanSupportFeature(FEATURE_HD_SPLIT)) {
458 oldestKey = std::max(GetOldestKeyTimeInPool(setInternalKeyPool, batch), oldestKey);
459 if (!set_pre_split_keypool.empty()) {
460 oldestKey = std::max(GetOldestKeyTimeInPool(set_pre_split_keypool, batch), oldestKey);
461 }
462 }
463
464 return oldestKey;
465 }
466
KeypoolCountExternalKeys() const467 size_t LegacyScriptPubKeyMan::KeypoolCountExternalKeys() const
468 {
469 LOCK(cs_KeyStore);
470 return setExternalKeyPool.size() + set_pre_split_keypool.size();
471 }
472
GetKeyPoolSize() const473 unsigned int LegacyScriptPubKeyMan::GetKeyPoolSize() const
474 {
475 LOCK(cs_KeyStore);
476 return setInternalKeyPool.size() + setExternalKeyPool.size() + set_pre_split_keypool.size();
477 }
478
GetTimeFirstKey() const479 int64_t LegacyScriptPubKeyMan::GetTimeFirstKey() const
480 {
481 LOCK(cs_KeyStore);
482 return nTimeFirstKey;
483 }
484
GetSolvingProvider(const CScript & script) const485 std::unique_ptr<SigningProvider> LegacyScriptPubKeyMan::GetSolvingProvider(const CScript& script) const
486 {
487 return MakeUnique<LegacySigningProvider>(*this);
488 }
489
CanProvide(const CScript & script,SignatureData & sigdata)490 bool LegacyScriptPubKeyMan::CanProvide(const CScript& script, SignatureData& sigdata)
491 {
492 IsMineResult ismine = IsMineInner(*this, script, IsMineSigVersion::TOP, /* recurse_scripthash= */ false);
493 if (ismine == IsMineResult::SPENDABLE || ismine == IsMineResult::WATCH_ONLY) {
494 // If ismine, it means we recognize keys or script ids in the script, or
495 // are watching the script itself, and we can at least provide metadata
496 // or solving information, even if not able to sign fully.
497 return true;
498 } else {
499 // If, given the stuff in sigdata, we could make a valid sigature, then we can provide for this script
500 ProduceSignature(*this, DUMMY_SIGNATURE_CREATOR, script, sigdata);
501 if (!sigdata.signatures.empty()) {
502 // If we could make signatures, make sure we have a private key to actually make a signature
503 bool has_privkeys = false;
504 for (const auto& key_sig_pair : sigdata.signatures) {
505 has_privkeys |= HaveKey(key_sig_pair.first);
506 }
507 return has_privkeys;
508 }
509 return false;
510 }
511 }
512
SignTransaction(CMutableTransaction & tx,const std::map<COutPoint,Coin> & coins,int sighash,std::map<int,std::string> & input_errors) const513 bool LegacyScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors) const
514 {
515 return ::SignTransaction(tx, this, coins, sighash, input_errors);
516 }
517
SignMessage(const std::string & message,const PKHash & pkhash,std::string & str_sig) const518 SigningResult LegacyScriptPubKeyMan::SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const
519 {
520 CKeyID key_id(pkhash);
521 CKey key;
522 if (!GetKey(key_id, key)) {
523 return SigningResult::PRIVATE_KEY_NOT_AVAILABLE;
524 }
525
526 if (MessageSign(key, message, str_sig)) {
527 return SigningResult::OK;
528 }
529 return SigningResult::SIGNING_FAILED;
530 }
531
FillPSBT(PartiallySignedTransaction & psbtx,int sighash_type,bool sign,bool bip32derivs) const532 TransactionError LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, int sighash_type, bool sign, bool bip32derivs) const
533 {
534 for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
535 const CTxIn& txin = psbtx.tx->vin[i];
536 PSBTInput& input = psbtx.inputs.at(i);
537
538 if (PSBTInputSigned(input)) {
539 continue;
540 }
541
542 // Get the Sighash type
543 if (sign && input.sighash_type > 0 && input.sighash_type != sighash_type) {
544 return TransactionError::SIGHASH_MISMATCH;
545 }
546
547 // Check non_witness_utxo has specified prevout
548 if (input.non_witness_utxo) {
549 if (txin.prevout.n >= input.non_witness_utxo->vout.size()) {
550 return TransactionError::MISSING_INPUTS;
551 }
552 } else if (input.witness_utxo.IsNull()) {
553 // There's no UTXO so we can just skip this now
554 continue;
555 }
556 SignatureData sigdata;
557 input.FillSignatureData(sigdata);
558 SignPSBTInput(HidingSigningProvider(this, !sign, !bip32derivs), psbtx, i, sighash_type);
559 }
560
561 // Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change
562 for (unsigned int i = 0; i < psbtx.tx->vout.size(); ++i) {
563 UpdatePSBTOutput(HidingSigningProvider(this, true, !bip32derivs), psbtx, i);
564 }
565
566 return TransactionError::OK;
567 }
568
GetMetadata(const CTxDestination & dest) const569 const CKeyMetadata* LegacyScriptPubKeyMan::GetMetadata(const CTxDestination& dest) const
570 {
571 LOCK(cs_KeyStore);
572
573 CKeyID key_id = GetKeyForDestination(*this, dest);
574 if (!key_id.IsNull()) {
575 auto it = mapKeyMetadata.find(key_id);
576 if (it != mapKeyMetadata.end()) {
577 return &it->second;
578 }
579 }
580
581 CScript scriptPubKey = GetScriptForDestination(dest);
582 auto it = m_script_metadata.find(CScriptID(scriptPubKey));
583 if (it != m_script_metadata.end()) {
584 return &it->second;
585 }
586
587 return nullptr;
588 }
589
GetID() const590 uint256 LegacyScriptPubKeyMan::GetID() const
591 {
592 return UINT256_ONE();
593 }
594
595 /**
596 * Update wallet first key creation time. This should be called whenever keys
597 * are added to the wallet, with the oldest key creation time.
598 */
UpdateTimeFirstKey(int64_t nCreateTime)599 void LegacyScriptPubKeyMan::UpdateTimeFirstKey(int64_t nCreateTime)
600 {
601 AssertLockHeld(cs_KeyStore);
602 if (nCreateTime <= 1) {
603 // Cannot determine birthday information, so set the wallet birthday to
604 // the beginning of time.
605 nTimeFirstKey = 1;
606 } else if (!nTimeFirstKey || nCreateTime < nTimeFirstKey) {
607 nTimeFirstKey = nCreateTime;
608 }
609 }
610
LoadKey(const CKey & key,const CPubKey & pubkey)611 bool LegacyScriptPubKeyMan::LoadKey(const CKey& key, const CPubKey &pubkey)
612 {
613 return AddKeyPubKeyInner(key, pubkey);
614 }
615
AddKeyPubKey(const CKey & secret,const CPubKey & pubkey)616 bool LegacyScriptPubKeyMan::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
617 {
618 LOCK(cs_KeyStore);
619 WalletBatch batch(m_storage.GetDatabase());
620 return LegacyScriptPubKeyMan::AddKeyPubKeyWithDB(batch, secret, pubkey);
621 }
622
AddKeyPubKeyWithDB(WalletBatch & batch,const CKey & secret,const CPubKey & pubkey)623 bool LegacyScriptPubKeyMan::AddKeyPubKeyWithDB(WalletBatch& batch, const CKey& secret, const CPubKey& pubkey)
624 {
625 AssertLockHeld(cs_KeyStore);
626
627 // Make sure we aren't adding private keys to private key disabled wallets
628 assert(!m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
629
630 // FillableSigningProvider has no concept of wallet databases, but calls AddCryptedKey
631 // which is overridden below. To avoid flushes, the database handle is
632 // tunneled through to it.
633 bool needsDB = !encrypted_batch;
634 if (needsDB) {
635 encrypted_batch = &batch;
636 }
637 if (!AddKeyPubKeyInner(secret, pubkey)) {
638 if (needsDB) encrypted_batch = nullptr;
639 return false;
640 }
641 if (needsDB) encrypted_batch = nullptr;
642
643 // check if we need to remove from watch-only
644 CScript script;
645 script = GetScriptForDestination(PKHash(pubkey));
646 if (HaveWatchOnly(script)) {
647 RemoveWatchOnly(script);
648 }
649 script = GetScriptForRawPubKey(pubkey);
650 if (HaveWatchOnly(script)) {
651 RemoveWatchOnly(script);
652 }
653
654 if (!m_storage.HasEncryptionKeys()) {
655 return batch.WriteKey(pubkey,
656 secret.GetPrivKey(),
657 mapKeyMetadata[pubkey.GetID()]);
658 }
659 m_storage.UnsetBlankWalletFlag(batch);
660 return true;
661 }
662
LoadCScript(const CScript & redeemScript)663 bool LegacyScriptPubKeyMan::LoadCScript(const CScript& redeemScript)
664 {
665 /* A sanity check was added in pull #3843 to avoid adding redeemScripts
666 * that never can be redeemed. However, old wallets may still contain
667 * these. Do not add them to the wallet and warn. */
668 if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
669 {
670 std::string strAddr = EncodeDestination(ScriptHash(redeemScript));
671 WalletLogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n", __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
672 return true;
673 }
674
675 return FillableSigningProvider::AddCScript(redeemScript);
676 }
677
LoadKeyMetadata(const CKeyID & keyID,const CKeyMetadata & meta)678 void LegacyScriptPubKeyMan::LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata& meta)
679 {
680 LOCK(cs_KeyStore);
681 UpdateTimeFirstKey(meta.nCreateTime);
682 mapKeyMetadata[keyID] = meta;
683 }
684
LoadScriptMetadata(const CScriptID & script_id,const CKeyMetadata & meta)685 void LegacyScriptPubKeyMan::LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata& meta)
686 {
687 LOCK(cs_KeyStore);
688 UpdateTimeFirstKey(meta.nCreateTime);
689 m_script_metadata[script_id] = meta;
690 }
691
AddKeyPubKeyInner(const CKey & key,const CPubKey & pubkey)692 bool LegacyScriptPubKeyMan::AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey)
693 {
694 LOCK(cs_KeyStore);
695 if (!m_storage.HasEncryptionKeys()) {
696 return FillableSigningProvider::AddKeyPubKey(key, pubkey);
697 }
698
699 if (m_storage.IsLocked()) {
700 return false;
701 }
702
703 std::vector<unsigned char> vchCryptedSecret;
704 CKeyingMaterial vchSecret(key.begin(), key.end());
705 if (!EncryptSecret(m_storage.GetEncryptionKey(), vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
706 return false;
707 }
708
709 if (!AddCryptedKey(pubkey, vchCryptedSecret)) {
710 return false;
711 }
712 return true;
713 }
714
LoadCryptedKey(const CPubKey & vchPubKey,const std::vector<unsigned char> & vchCryptedSecret)715 bool LegacyScriptPubKeyMan::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
716 {
717 return AddCryptedKeyInner(vchPubKey, vchCryptedSecret);
718 }
719
AddCryptedKeyInner(const CPubKey & vchPubKey,const std::vector<unsigned char> & vchCryptedSecret)720 bool LegacyScriptPubKeyMan::AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
721 {
722 LOCK(cs_KeyStore);
723 assert(mapKeys.empty());
724
725 mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
726 ImplicitlyLearnRelatedKeyScripts(vchPubKey);
727 return true;
728 }
729
AddCryptedKey(const CPubKey & vchPubKey,const std::vector<unsigned char> & vchCryptedSecret)730 bool LegacyScriptPubKeyMan::AddCryptedKey(const CPubKey &vchPubKey,
731 const std::vector<unsigned char> &vchCryptedSecret)
732 {
733 if (!AddCryptedKeyInner(vchPubKey, vchCryptedSecret))
734 return false;
735 {
736 LOCK(cs_KeyStore);
737 if (encrypted_batch)
738 return encrypted_batch->WriteCryptedKey(vchPubKey,
739 vchCryptedSecret,
740 mapKeyMetadata[vchPubKey.GetID()]);
741 else
742 return WalletBatch(m_storage.GetDatabase()).WriteCryptedKey(vchPubKey,
743 vchCryptedSecret,
744 mapKeyMetadata[vchPubKey.GetID()]);
745 }
746 }
747
HaveWatchOnly(const CScript & dest) const748 bool LegacyScriptPubKeyMan::HaveWatchOnly(const CScript &dest) const
749 {
750 LOCK(cs_KeyStore);
751 return setWatchOnly.count(dest) > 0;
752 }
753
HaveWatchOnly() const754 bool LegacyScriptPubKeyMan::HaveWatchOnly() const
755 {
756 LOCK(cs_KeyStore);
757 return (!setWatchOnly.empty());
758 }
759
ExtractPubKey(const CScript & dest,CPubKey & pubKeyOut)760 static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)
761 {
762 std::vector<std::vector<unsigned char>> solutions;
763 return Solver(dest, solutions) == TX_PUBKEY &&
764 (pubKeyOut = CPubKey(solutions[0])).IsFullyValid();
765 }
766
RemoveWatchOnly(const CScript & dest)767 bool LegacyScriptPubKeyMan::RemoveWatchOnly(const CScript &dest)
768 {
769 {
770 LOCK(cs_KeyStore);
771 setWatchOnly.erase(dest);
772 CPubKey pubKey;
773 if (ExtractPubKey(dest, pubKey)) {
774 mapWatchKeys.erase(pubKey.GetID());
775 }
776 // Related CScripts are not removed; having superfluous scripts around is
777 // harmless (see comment in ImplicitlyLearnRelatedKeyScripts).
778 }
779
780 if (!HaveWatchOnly())
781 NotifyWatchonlyChanged(false);
782 if (!WalletBatch(m_storage.GetDatabase()).EraseWatchOnly(dest))
783 return false;
784
785 return true;
786 }
787
LoadWatchOnly(const CScript & dest)788 bool LegacyScriptPubKeyMan::LoadWatchOnly(const CScript &dest)
789 {
790 return AddWatchOnlyInMem(dest);
791 }
792
AddWatchOnlyInMem(const CScript & dest)793 bool LegacyScriptPubKeyMan::AddWatchOnlyInMem(const CScript &dest)
794 {
795 LOCK(cs_KeyStore);
796 setWatchOnly.insert(dest);
797 CPubKey pubKey;
798 if (ExtractPubKey(dest, pubKey)) {
799 mapWatchKeys[pubKey.GetID()] = pubKey;
800 ImplicitlyLearnRelatedKeyScripts(pubKey);
801 }
802 return true;
803 }
804
AddWatchOnlyWithDB(WalletBatch & batch,const CScript & dest)805 bool LegacyScriptPubKeyMan::AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest)
806 {
807 if (!AddWatchOnlyInMem(dest))
808 return false;
809 const CKeyMetadata& meta = m_script_metadata[CScriptID(dest)];
810 UpdateTimeFirstKey(meta.nCreateTime);
811 NotifyWatchonlyChanged(true);
812 if (batch.WriteWatchOnly(dest, meta)) {
813 m_storage.UnsetBlankWalletFlag(batch);
814 return true;
815 }
816 return false;
817 }
818
AddWatchOnlyWithDB(WalletBatch & batch,const CScript & dest,int64_t create_time)819 bool LegacyScriptPubKeyMan::AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest, int64_t create_time)
820 {
821 m_script_metadata[CScriptID(dest)].nCreateTime = create_time;
822 return AddWatchOnlyWithDB(batch, dest);
823 }
824
AddWatchOnly(const CScript & dest)825 bool LegacyScriptPubKeyMan::AddWatchOnly(const CScript& dest)
826 {
827 WalletBatch batch(m_storage.GetDatabase());
828 return AddWatchOnlyWithDB(batch, dest);
829 }
830
AddWatchOnly(const CScript & dest,int64_t nCreateTime)831 bool LegacyScriptPubKeyMan::AddWatchOnly(const CScript& dest, int64_t nCreateTime)
832 {
833 m_script_metadata[CScriptID(dest)].nCreateTime = nCreateTime;
834 return AddWatchOnly(dest);
835 }
836
SetHDChain(const CHDChain & chain,bool memonly)837 void LegacyScriptPubKeyMan::SetHDChain(const CHDChain& chain, bool memonly)
838 {
839 LOCK(cs_KeyStore);
840 if (!memonly && !WalletBatch(m_storage.GetDatabase()).WriteHDChain(chain))
841 throw std::runtime_error(std::string(__func__) + ": writing chain failed");
842
843 hdChain = chain;
844 }
845
HaveKey(const CKeyID & address) const846 bool LegacyScriptPubKeyMan::HaveKey(const CKeyID &address) const
847 {
848 LOCK(cs_KeyStore);
849 if (!m_storage.HasEncryptionKeys()) {
850 return FillableSigningProvider::HaveKey(address);
851 }
852 return mapCryptedKeys.count(address) > 0;
853 }
854
GetKey(const CKeyID & address,CKey & keyOut) const855 bool LegacyScriptPubKeyMan::GetKey(const CKeyID &address, CKey& keyOut) const
856 {
857 LOCK(cs_KeyStore);
858 if (!m_storage.HasEncryptionKeys()) {
859 return FillableSigningProvider::GetKey(address, keyOut);
860 }
861
862 CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
863 if (mi != mapCryptedKeys.end())
864 {
865 const CPubKey &vchPubKey = (*mi).second.first;
866 const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
867 return DecryptKey(m_storage.GetEncryptionKey(), vchCryptedSecret, vchPubKey, keyOut);
868 }
869 return false;
870 }
871
GetKeyOrigin(const CKeyID & keyID,KeyOriginInfo & info) const872 bool LegacyScriptPubKeyMan::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& info) const
873 {
874 CKeyMetadata meta;
875 {
876 LOCK(cs_KeyStore);
877 auto it = mapKeyMetadata.find(keyID);
878 if (it != mapKeyMetadata.end()) {
879 meta = it->second;
880 }
881 }
882 if (meta.has_key_origin) {
883 std::copy(meta.key_origin.fingerprint, meta.key_origin.fingerprint + 4, info.fingerprint);
884 info.path = meta.key_origin.path;
885 } else { // Single pubkeys get the master fingerprint of themselves
886 std::copy(keyID.begin(), keyID.begin() + 4, info.fingerprint);
887 }
888 return true;
889 }
890
GetWatchPubKey(const CKeyID & address,CPubKey & pubkey_out) const891 bool LegacyScriptPubKeyMan::GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const
892 {
893 LOCK(cs_KeyStore);
894 WatchKeyMap::const_iterator it = mapWatchKeys.find(address);
895 if (it != mapWatchKeys.end()) {
896 pubkey_out = it->second;
897 return true;
898 }
899 return false;
900 }
901
GetPubKey(const CKeyID & address,CPubKey & vchPubKeyOut) const902 bool LegacyScriptPubKeyMan::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
903 {
904 LOCK(cs_KeyStore);
905 if (!m_storage.HasEncryptionKeys()) {
906 if (!FillableSigningProvider::GetPubKey(address, vchPubKeyOut)) {
907 return GetWatchPubKey(address, vchPubKeyOut);
908 }
909 return true;
910 }
911
912 CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
913 if (mi != mapCryptedKeys.end())
914 {
915 vchPubKeyOut = (*mi).second.first;
916 return true;
917 }
918 // Check for watch-only pubkeys
919 return GetWatchPubKey(address, vchPubKeyOut);
920 }
921
GenerateNewKey(WalletBatch & batch,bool internal)922 CPubKey LegacyScriptPubKeyMan::GenerateNewKey(WalletBatch &batch, bool internal)
923 {
924 assert(!m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
925 assert(!m_storage.IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET));
926 AssertLockHeld(cs_KeyStore);
927 bool fCompressed = m_storage.CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
928
929 CKey secret;
930
931 // Create new metadata
932 int64_t nCreationTime = GetTime();
933 CKeyMetadata metadata(nCreationTime);
934
935 // use HD key derivation if HD was enabled during wallet creation and a seed is present
936 if (IsHDEnabled()) {
937 DeriveNewChildKey(batch, metadata, secret, (m_storage.CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false));
938 } else {
939 secret.MakeNewKey(fCompressed);
940 }
941
942 // Compressed public keys were introduced in version 0.6.0
943 if (fCompressed) {
944 m_storage.SetMinVersion(FEATURE_COMPRPUBKEY);
945 }
946
947 CPubKey pubkey = secret.GetPubKey();
948 assert(secret.VerifyPubKey(pubkey));
949
950 mapKeyMetadata[pubkey.GetID()] = metadata;
951 UpdateTimeFirstKey(nCreationTime);
952
953 if (!AddKeyPubKeyWithDB(batch, secret, pubkey)) {
954 throw std::runtime_error(std::string(__func__) + ": AddKey failed");
955 }
956 return pubkey;
957 }
958
959 const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;
960
DeriveNewChildKey(WalletBatch & batch,CKeyMetadata & metadata,CKey & secret,bool internal)961 void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey& secret, bool internal)
962 {
963 // for now we use a fixed keypath scheme of m/88'/0'/k
964 CKey seed; //seed (256bit)
965 CExtKey masterKey; //hd master key
966 CExtKey accountKey; //key at m/88'
967 CExtKey chainChildKey; //key at m/88'/0' (external) or m/88'/1' (internal)
968 CExtKey childKey; //key at m/88'/0'/<n>'
969
970 // try to get the seed
971 if (!GetKey(hdChain.seed_id, seed))
972 throw std::runtime_error(std::string(__func__) + ": seed not found");
973
974 masterKey.SetSeed(seed.begin(), seed.size());
975
976 // derive m/0'
977 // use hardened derivation (child keys >= 0x80000000 are hardened after bip32)
978 masterKey.Derive(accountKey, BIP32_HARDENED_KEY_LIMIT);
979
980 // derive m/0'/0' (external chain) OR m/88'/1' (internal chain)
981 assert(internal ? m_storage.CanSupportFeature(FEATURE_HD_SPLIT) : true);
982 accountKey.Derive(chainChildKey, BIP32_HARDENED_KEY_LIMIT+(internal ? 1 : 0));
983
984 // derive child key at next index, skip keys already known to the wallet
985 do {
986 // always derive hardened keys
987 // childIndex | BIP32_HARDENED_KEY_LIMIT = derive childIndex in hardened child-index-range
988 // example: 1 | BIP32_HARDENED_KEY_LIMIT == 0x80000001 == 2147483649
989 if (internal) {
990 chainChildKey.Derive(childKey, hdChain.nInternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
991 metadata.hdKeypath = "m/88'/1'/" + ToString(hdChain.nInternalChainCounter) + "'";
992 metadata.key_origin.path.push_back(88 | BIP32_HARDENED_KEY_LIMIT);
993 metadata.key_origin.path.push_back(1 | BIP32_HARDENED_KEY_LIMIT);
994 metadata.key_origin.path.push_back(hdChain.nInternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
995 hdChain.nInternalChainCounter++;
996 }
997 else {
998 chainChildKey.Derive(childKey, hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
999 metadata.hdKeypath = "m/88'/0'/" + ToString(hdChain.nExternalChainCounter) + "'";
1000 metadata.key_origin.path.push_back(88 | BIP32_HARDENED_KEY_LIMIT);
1001 metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT);
1002 metadata.key_origin.path.push_back(hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
1003 hdChain.nExternalChainCounter++;
1004 }
1005 } while (HaveKey(childKey.key.GetPubKey().GetID()));
1006 secret = childKey.key;
1007 metadata.hd_seed_id = hdChain.seed_id;
1008 CKeyID master_id = masterKey.key.GetPubKey().GetID();
1009 std::copy(master_id.begin(), master_id.begin() + 4, metadata.key_origin.fingerprint);
1010 metadata.has_key_origin = true;
1011 // update the chain model in the database
1012 if (!batch.WriteHDChain(hdChain))
1013 throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed");
1014 }
1015
LoadKeyPool(int64_t nIndex,const CKeyPool & keypool)1016 void LegacyScriptPubKeyMan::LoadKeyPool(int64_t nIndex, const CKeyPool &keypool)
1017 {
1018 LOCK(cs_KeyStore);
1019 if (keypool.m_pre_split) {
1020 set_pre_split_keypool.insert(nIndex);
1021 } else if (keypool.fInternal) {
1022 setInternalKeyPool.insert(nIndex);
1023 } else {
1024 setExternalKeyPool.insert(nIndex);
1025 }
1026 m_max_keypool_index = std::max(m_max_keypool_index, nIndex);
1027 m_pool_key_to_index[keypool.vchPubKey.GetID()] = nIndex;
1028
1029 // If no metadata exists yet, create a default with the pool key's
1030 // creation time. Note that this may be overwritten by actually
1031 // stored metadata for that key later, which is fine.
1032 CKeyID keyid = keypool.vchPubKey.GetID();
1033 if (mapKeyMetadata.count(keyid) == 0)
1034 mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
1035 }
1036
CanGenerateKeys() const1037 bool LegacyScriptPubKeyMan::CanGenerateKeys() const
1038 {
1039 // A wallet can generate keys if it has an HD seed (IsHDEnabled) or it is a non-HD wallet (pre FEATURE_HD)
1040 LOCK(cs_KeyStore);
1041 return IsHDEnabled() || !m_storage.CanSupportFeature(FEATURE_HD);
1042 }
1043
GenerateNewSeed()1044 CPubKey LegacyScriptPubKeyMan::GenerateNewSeed()
1045 {
1046 assert(!m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
1047 CKey key;
1048 key.MakeNewKey(true);
1049 return DeriveNewSeed(key);
1050 }
1051
DeriveNewSeed(const CKey & key)1052 CPubKey LegacyScriptPubKeyMan::DeriveNewSeed(const CKey& key)
1053 {
1054 int64_t nCreationTime = GetTime();
1055 CKeyMetadata metadata(nCreationTime);
1056
1057 // calculate the seed
1058 CPubKey seed = key.GetPubKey();
1059 assert(key.VerifyPubKey(seed));
1060
1061 // set the hd keypath to "s" -> Seed, refers the seed to itself
1062 metadata.hdKeypath = "s";
1063 metadata.has_key_origin = false;
1064 metadata.hd_seed_id = seed.GetID();
1065
1066 {
1067 LOCK(cs_KeyStore);
1068
1069 // mem store the metadata
1070 mapKeyMetadata[seed.GetID()] = metadata;
1071
1072 // write the key&metadata to the database
1073 if (!AddKeyPubKey(key, seed))
1074 throw std::runtime_error(std::string(__func__) + ": AddKeyPubKey failed");
1075 }
1076
1077 return seed;
1078 }
1079
SetHDSeed(const CPubKey & seed)1080 void LegacyScriptPubKeyMan::SetHDSeed(const CPubKey& seed)
1081 {
1082 LOCK(cs_KeyStore);
1083 // store the keyid (hash160) together with
1084 // the child index counter in the database
1085 // as a hdchain object
1086 CHDChain newHdChain;
1087 newHdChain.nVersion = m_storage.CanSupportFeature(FEATURE_HD_SPLIT) ? CHDChain::VERSION_HD_CHAIN_SPLIT : CHDChain::VERSION_HD_BASE;
1088 newHdChain.seed_id = seed.GetID();
1089 SetHDChain(newHdChain, false);
1090 NotifyCanGetAddressesChanged();
1091 WalletBatch batch(m_storage.GetDatabase());
1092 m_storage.UnsetBlankWalletFlag(batch);
1093 }
1094
1095 /**
1096 * Mark old keypool keys as used,
1097 * and generate all new keys
1098 */
NewKeyPool()1099 bool LegacyScriptPubKeyMan::NewKeyPool()
1100 {
1101 if (m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
1102 return false;
1103 }
1104 {
1105 LOCK(cs_KeyStore);
1106 WalletBatch batch(m_storage.GetDatabase());
1107
1108 for (const int64_t nIndex : setInternalKeyPool) {
1109 batch.ErasePool(nIndex);
1110 }
1111 setInternalKeyPool.clear();
1112
1113 for (const int64_t nIndex : setExternalKeyPool) {
1114 batch.ErasePool(nIndex);
1115 }
1116 setExternalKeyPool.clear();
1117
1118 for (const int64_t nIndex : set_pre_split_keypool) {
1119 batch.ErasePool(nIndex);
1120 }
1121 set_pre_split_keypool.clear();
1122
1123 m_pool_key_to_index.clear();
1124
1125 if (!TopUp()) {
1126 return false;
1127 }
1128 WalletLogPrintf("LegacyScriptPubKeyMan::NewKeyPool rewrote keypool\n");
1129 }
1130 return true;
1131 }
1132
TopUp(unsigned int kpSize)1133 bool LegacyScriptPubKeyMan::TopUp(unsigned int kpSize)
1134 {
1135 if (!CanGenerateKeys()) {
1136 return false;
1137 }
1138 {
1139 LOCK(cs_KeyStore);
1140
1141 if (m_storage.IsLocked()) return false;
1142
1143 // Top up key pool
1144 unsigned int nTargetSize;
1145 if (kpSize > 0)
1146 nTargetSize = kpSize;
1147 else
1148 nTargetSize = std::max(gArgs.GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0);
1149
1150 // count amount of available keys (internal, external)
1151 // make sure the keypool of external and internal keys fits the user selected target (-keypool)
1152 int64_t missingExternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - (int64_t)setExternalKeyPool.size(), (int64_t) 0);
1153 int64_t missingInternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - (int64_t)setInternalKeyPool.size(), (int64_t) 0);
1154
1155 if (!IsHDEnabled() || !m_storage.CanSupportFeature(FEATURE_HD_SPLIT))
1156 {
1157 // don't create extra internal keys
1158 missingInternal = 0;
1159 }
1160 bool internal = false;
1161 WalletBatch batch(m_storage.GetDatabase());
1162 for (int64_t i = missingInternal + missingExternal; i--;)
1163 {
1164 if (i < missingInternal) {
1165 internal = true;
1166 }
1167
1168 CPubKey pubkey(GenerateNewKey(batch, internal));
1169 AddKeypoolPubkeyWithDB(pubkey, internal, batch);
1170 }
1171 if (missingInternal + missingExternal > 0) {
1172 WalletLogPrintf("keypool added %d keys (%d internal), size=%u (%u internal)\n", missingInternal + missingExternal, missingInternal, setInternalKeyPool.size() + setExternalKeyPool.size() + set_pre_split_keypool.size(), setInternalKeyPool.size());
1173 }
1174 }
1175 NotifyCanGetAddressesChanged();
1176 return true;
1177 }
1178
AddKeypoolPubkeyWithDB(const CPubKey & pubkey,const bool internal,WalletBatch & batch)1179 void LegacyScriptPubKeyMan::AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch)
1180 {
1181 LOCK(cs_KeyStore);
1182 assert(m_max_keypool_index < std::numeric_limits<int64_t>::max()); // How in the hell did you use so many keys?
1183 int64_t index = ++m_max_keypool_index;
1184 if (!batch.WritePool(index, CKeyPool(pubkey, internal))) {
1185 throw std::runtime_error(std::string(__func__) + ": writing imported pubkey failed");
1186 }
1187 if (internal) {
1188 setInternalKeyPool.insert(index);
1189 } else {
1190 setExternalKeyPool.insert(index);
1191 }
1192 m_pool_key_to_index[pubkey.GetID()] = index;
1193 }
1194
KeepDestination(int64_t nIndex,const OutputType & type)1195 void LegacyScriptPubKeyMan::KeepDestination(int64_t nIndex, const OutputType& type)
1196 {
1197 // Remove from key pool
1198 WalletBatch batch(m_storage.GetDatabase());
1199 batch.ErasePool(nIndex);
1200 CPubKey pubkey;
1201 bool have_pk = GetPubKey(m_index_to_reserved_key.at(nIndex), pubkey);
1202 assert(have_pk);
1203 LearnRelatedScripts(pubkey, type);
1204 m_index_to_reserved_key.erase(nIndex);
1205 WalletLogPrintf("keypool keep %d\n", nIndex);
1206 }
1207
ReturnDestination(int64_t nIndex,bool fInternal,const CTxDestination &)1208 void LegacyScriptPubKeyMan::ReturnDestination(int64_t nIndex, bool fInternal, const CTxDestination&)
1209 {
1210 // Return to key pool
1211 {
1212 LOCK(cs_KeyStore);
1213 if (fInternal) {
1214 setInternalKeyPool.insert(nIndex);
1215 } else if (!set_pre_split_keypool.empty()) {
1216 set_pre_split_keypool.insert(nIndex);
1217 } else {
1218 setExternalKeyPool.insert(nIndex);
1219 }
1220 CKeyID& pubkey_id = m_index_to_reserved_key.at(nIndex);
1221 m_pool_key_to_index[pubkey_id] = nIndex;
1222 m_index_to_reserved_key.erase(nIndex);
1223 NotifyCanGetAddressesChanged();
1224 }
1225 WalletLogPrintf("keypool return %d\n", nIndex);
1226 }
1227
GetKeyFromPool(CPubKey & result,const OutputType type,bool internal)1228 bool LegacyScriptPubKeyMan::GetKeyFromPool(CPubKey& result, const OutputType type, bool internal)
1229 {
1230 if (!CanGetAddresses(internal)) {
1231 return false;
1232 }
1233
1234 CKeyPool keypool;
1235 {
1236 LOCK(cs_KeyStore);
1237 int64_t nIndex;
1238 if (!ReserveKeyFromKeyPool(nIndex, keypool, internal) && !m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
1239 if (m_storage.IsLocked()) return false;
1240 WalletBatch batch(m_storage.GetDatabase());
1241 result = GenerateNewKey(batch, internal);
1242 return true;
1243 }
1244 KeepDestination(nIndex, type);
1245 result = keypool.vchPubKey;
1246 }
1247 return true;
1248 }
1249
ReserveKeyFromKeyPool(int64_t & nIndex,CKeyPool & keypool,bool fRequestedInternal)1250 bool LegacyScriptPubKeyMan::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal)
1251 {
1252 nIndex = -1;
1253 keypool.vchPubKey = CPubKey();
1254 {
1255 LOCK(cs_KeyStore);
1256
1257 bool fReturningInternal = fRequestedInternal;
1258 fReturningInternal &= (IsHDEnabled() && m_storage.CanSupportFeature(FEATURE_HD_SPLIT)) || m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
1259 bool use_split_keypool = set_pre_split_keypool.empty();
1260 std::set<int64_t>& setKeyPool = use_split_keypool ? (fReturningInternal ? setInternalKeyPool : setExternalKeyPool) : set_pre_split_keypool;
1261
1262 // Get the oldest key
1263 if (setKeyPool.empty()) {
1264 return false;
1265 }
1266
1267 WalletBatch batch(m_storage.GetDatabase());
1268
1269 auto it = setKeyPool.begin();
1270 nIndex = *it;
1271 setKeyPool.erase(it);
1272 if (!batch.ReadPool(nIndex, keypool)) {
1273 throw std::runtime_error(std::string(__func__) + ": read failed");
1274 }
1275 CPubKey pk;
1276 if (!GetPubKey(keypool.vchPubKey.GetID(), pk)) {
1277 throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
1278 }
1279 // If the key was pre-split keypool, we don't care about what type it is
1280 if (use_split_keypool && keypool.fInternal != fReturningInternal) {
1281 throw std::runtime_error(std::string(__func__) + ": keypool entry misclassified");
1282 }
1283 if (!keypool.vchPubKey.IsValid()) {
1284 throw std::runtime_error(std::string(__func__) + ": keypool entry invalid");
1285 }
1286
1287 assert(m_index_to_reserved_key.count(nIndex) == 0);
1288 m_index_to_reserved_key[nIndex] = keypool.vchPubKey.GetID();
1289 m_pool_key_to_index.erase(keypool.vchPubKey.GetID());
1290 WalletLogPrintf("keypool reserve %d\n", nIndex);
1291 }
1292 NotifyCanGetAddressesChanged();
1293 return true;
1294 }
1295
LearnRelatedScripts(const CPubKey & key,OutputType type)1296 void LegacyScriptPubKeyMan::LearnRelatedScripts(const CPubKey& key, OutputType type)
1297 {
1298 if (key.IsCompressed() && (type == OutputType::P2SH_SEGWIT || type == OutputType::BECH32)) {
1299 CTxDestination witdest = WitnessV0KeyHash(key.GetID());
1300 CScript witprog = GetScriptForDestination(witdest);
1301 // Make sure the resulting program is solvable.
1302 assert(IsSolvable(*this, witprog));
1303 AddCScript(witprog);
1304 }
1305 }
1306
LearnAllRelatedScripts(const CPubKey & key)1307 void LegacyScriptPubKeyMan::LearnAllRelatedScripts(const CPubKey& key)
1308 {
1309 // OutputType::P2SH_SEGWIT always adds all necessary scripts for all types.
1310 LearnRelatedScripts(key, OutputType::P2SH_SEGWIT);
1311 }
1312
MarkReserveKeysAsUsed(int64_t keypool_id)1313 void LegacyScriptPubKeyMan::MarkReserveKeysAsUsed(int64_t keypool_id)
1314 {
1315 AssertLockHeld(cs_KeyStore);
1316 bool internal = setInternalKeyPool.count(keypool_id);
1317 if (!internal) assert(setExternalKeyPool.count(keypool_id) || set_pre_split_keypool.count(keypool_id));
1318 std::set<int64_t> *setKeyPool = internal ? &setInternalKeyPool : (set_pre_split_keypool.empty() ? &setExternalKeyPool : &set_pre_split_keypool);
1319 auto it = setKeyPool->begin();
1320
1321 WalletBatch batch(m_storage.GetDatabase());
1322 while (it != std::end(*setKeyPool)) {
1323 const int64_t& index = *(it);
1324 if (index > keypool_id) break; // set*KeyPool is ordered
1325
1326 CKeyPool keypool;
1327 if (batch.ReadPool(index, keypool)) { //TODO: This should be unnecessary
1328 m_pool_key_to_index.erase(keypool.vchPubKey.GetID());
1329 }
1330 LearnAllRelatedScripts(keypool.vchPubKey);
1331 batch.ErasePool(index);
1332 WalletLogPrintf("keypool index %d removed\n", index);
1333 it = setKeyPool->erase(it);
1334 }
1335 }
1336
GetAffectedKeys(const CScript & spk,const SigningProvider & provider)1337 std::vector<CKeyID> GetAffectedKeys(const CScript& spk, const SigningProvider& provider)
1338 {
1339 std::vector<CScript> dummy;
1340 FlatSigningProvider out;
1341 InferDescriptor(spk, provider)->Expand(0, DUMMY_SIGNING_PROVIDER, dummy, out);
1342 std::vector<CKeyID> ret;
1343 for (const auto& entry : out.pubkeys) {
1344 ret.push_back(entry.first);
1345 }
1346 return ret;
1347 }
1348
MarkPreSplitKeys()1349 void LegacyScriptPubKeyMan::MarkPreSplitKeys()
1350 {
1351 WalletBatch batch(m_storage.GetDatabase());
1352 for (auto it = setExternalKeyPool.begin(); it != setExternalKeyPool.end();) {
1353 int64_t index = *it;
1354 CKeyPool keypool;
1355 if (!batch.ReadPool(index, keypool)) {
1356 throw std::runtime_error(std::string(__func__) + ": read keypool entry failed");
1357 }
1358 keypool.m_pre_split = true;
1359 if (!batch.WritePool(index, keypool)) {
1360 throw std::runtime_error(std::string(__func__) + ": writing modified keypool entry failed");
1361 }
1362 set_pre_split_keypool.insert(index);
1363 it = setExternalKeyPool.erase(it);
1364 }
1365 }
1366
AddCScript(const CScript & redeemScript)1367 bool LegacyScriptPubKeyMan::AddCScript(const CScript& redeemScript)
1368 {
1369 WalletBatch batch(m_storage.GetDatabase());
1370 return AddCScriptWithDB(batch, redeemScript);
1371 }
1372
AddCScriptWithDB(WalletBatch & batch,const CScript & redeemScript)1373 bool LegacyScriptPubKeyMan::AddCScriptWithDB(WalletBatch& batch, const CScript& redeemScript)
1374 {
1375 if (!FillableSigningProvider::AddCScript(redeemScript))
1376 return false;
1377 if (batch.WriteCScript(Hash160(redeemScript), redeemScript)) {
1378 m_storage.UnsetBlankWalletFlag(batch);
1379 return true;
1380 }
1381 return false;
1382 }
1383
AddKeyOriginWithDB(WalletBatch & batch,const CPubKey & pubkey,const KeyOriginInfo & info)1384 bool LegacyScriptPubKeyMan::AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info)
1385 {
1386 LOCK(cs_KeyStore);
1387 std::copy(info.fingerprint, info.fingerprint + 4, mapKeyMetadata[pubkey.GetID()].key_origin.fingerprint);
1388 mapKeyMetadata[pubkey.GetID()].key_origin.path = info.path;
1389 mapKeyMetadata[pubkey.GetID()].has_key_origin = true;
1390 mapKeyMetadata[pubkey.GetID()].hdKeypath = WriteHDKeypath(info.path);
1391 return batch.WriteKeyMetadata(mapKeyMetadata[pubkey.GetID()], pubkey, true);
1392 }
1393
ImportScripts(const std::set<CScript> scripts,int64_t timestamp)1394 bool LegacyScriptPubKeyMan::ImportScripts(const std::set<CScript> scripts, int64_t timestamp)
1395 {
1396 WalletBatch batch(m_storage.GetDatabase());
1397 for (const auto& entry : scripts) {
1398 CScriptID id(entry);
1399 if (HaveCScript(id)) {
1400 WalletLogPrintf("Already have script %s, skipping\n", HexStr(entry));
1401 continue;
1402 }
1403 if (!AddCScriptWithDB(batch, entry)) {
1404 return false;
1405 }
1406
1407 if (timestamp > 0) {
1408 m_script_metadata[CScriptID(entry)].nCreateTime = timestamp;
1409 }
1410 }
1411 if (timestamp > 0) {
1412 UpdateTimeFirstKey(timestamp);
1413 }
1414
1415 return true;
1416 }
1417
ImportPrivKeys(const std::map<CKeyID,CKey> & privkey_map,const int64_t timestamp)1418 bool LegacyScriptPubKeyMan::ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp)
1419 {
1420 WalletBatch batch(m_storage.GetDatabase());
1421 for (const auto& entry : privkey_map) {
1422 const CKey& key = entry.second;
1423 CPubKey pubkey = key.GetPubKey();
1424 const CKeyID& id = entry.first;
1425 assert(key.VerifyPubKey(pubkey));
1426 // Skip if we already have the key
1427 if (HaveKey(id)) {
1428 WalletLogPrintf("Already have key with pubkey %s, skipping\n", HexStr(pubkey));
1429 continue;
1430 }
1431 mapKeyMetadata[id].nCreateTime = timestamp;
1432 // If the private key is not present in the wallet, insert it.
1433 if (!AddKeyPubKeyWithDB(batch, key, pubkey)) {
1434 return false;
1435 }
1436 UpdateTimeFirstKey(timestamp);
1437 }
1438 return true;
1439 }
1440
ImportPubKeys(const std::vector<CKeyID> & ordered_pubkeys,const std::map<CKeyID,CPubKey> & pubkey_map,const std::map<CKeyID,std::pair<CPubKey,KeyOriginInfo>> & key_origins,const bool add_keypool,const bool internal,const int64_t timestamp)1441 bool LegacyScriptPubKeyMan::ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp)
1442 {
1443 WalletBatch batch(m_storage.GetDatabase());
1444 for (const auto& entry : key_origins) {
1445 AddKeyOriginWithDB(batch, entry.second.first, entry.second.second);
1446 }
1447 for (const CKeyID& id : ordered_pubkeys) {
1448 auto entry = pubkey_map.find(id);
1449 if (entry == pubkey_map.end()) {
1450 continue;
1451 }
1452 const CPubKey& pubkey = entry->second;
1453 CPubKey temp;
1454 if (GetPubKey(id, temp)) {
1455 // Already have pubkey, skipping
1456 WalletLogPrintf("Already have pubkey %s, skipping\n", HexStr(temp));
1457 continue;
1458 }
1459 if (!AddWatchOnlyWithDB(batch, GetScriptForRawPubKey(pubkey), timestamp)) {
1460 return false;
1461 }
1462 mapKeyMetadata[id].nCreateTime = timestamp;
1463
1464 // Add to keypool only works with pubkeys
1465 if (add_keypool) {
1466 AddKeypoolPubkeyWithDB(pubkey, internal, batch);
1467 NotifyCanGetAddressesChanged();
1468 }
1469 }
1470 return true;
1471 }
1472
ImportScriptPubKeys(const std::set<CScript> & script_pub_keys,const bool have_solving_data,const int64_t timestamp)1473 bool LegacyScriptPubKeyMan::ImportScriptPubKeys(const std::set<CScript>& script_pub_keys, const bool have_solving_data, const int64_t timestamp)
1474 {
1475 WalletBatch batch(m_storage.GetDatabase());
1476 for (const CScript& script : script_pub_keys) {
1477 if (!have_solving_data || !IsMine(script)) { // Always call AddWatchOnly for non-solvable watch-only, so that watch timestamp gets updated
1478 if (!AddWatchOnlyWithDB(batch, script, timestamp)) {
1479 return false;
1480 }
1481 }
1482 }
1483 return true;
1484 }
1485
GetKeys() const1486 std::set<CKeyID> LegacyScriptPubKeyMan::GetKeys() const
1487 {
1488 LOCK(cs_KeyStore);
1489 if (!m_storage.HasEncryptionKeys()) {
1490 return FillableSigningProvider::GetKeys();
1491 }
1492 std::set<CKeyID> set_address;
1493 for (const auto& mi : mapCryptedKeys) {
1494 set_address.insert(mi.first);
1495 }
1496 return set_address;
1497 }
1498