PIVX Core  5.6.99
P2P Digital Currency
scriptpubkeyman.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019 The Bitcoin Core developers
2 // Copyright (c) 2020-2021 The PIVX 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 
7 #include "crypter.h"
8 #include "script/standard.h"
9 
10 bool ScriptPubKeyMan::SetupGeneration(bool newKeypool, bool force, bool memOnly)
11 {
12  if (CanGenerateKeys() && !force) {
13  return false;
14  }
15 
16  SetHDSeed(GenerateNewSeed(), force, memOnly);
17  if (newKeypool && !NewKeyPool()) {
18  return false;
19  }
20  return true;
21 }
22 
23 bool ScriptPubKeyMan::Upgrade(const int prev_version, std::string& error)
24 {
26  error = "";
27  bool hd_upgrade = false;
28  if (!IsHDEnabled()) {
29  LogPrintf("Upgrading wallet to use HD chain split\n");
31 
32  // generate a new master key
33  CPubKey masterPubKey = GenerateNewSeed();
34  SetHDSeed(masterPubKey);
35  hd_upgrade = true;
36  }
37 
38  // Regenerate the keypool if upgraded to HD
39  if (hd_upgrade) {
40  // Mark all keys currently in the keypool as pre-split
42 
43  // Fill keypool
44  if (!TopUp()) {
45  error = _("Unable to generate keys");
46  return false;
47  }
48  }
49  return true;
50 }
51 
53 {
54  // A wallet can generate keys if it has an HD seed (IsHDEnabled) or it is a non-HD wallet (pre FEATURE_HD)
57 }
58 
60 {
61  return !hdChain.IsNull();
62 }
63 
64 bool ScriptPubKeyMan::CanGetAddresses(const uint8_t& type)
65 {
67  // Check if the keypool has keys
68  const bool isHDEnabled = IsHDEnabled();
69  bool keypool_has_keys = false;
70  if (isHDEnabled && type == HDChain::ChangeType::INTERNAL) {
71  keypool_has_keys = setInternalKeyPool.size() > 0;
72  } else if (isHDEnabled && type == HDChain::ChangeType::STAKING) {
73  keypool_has_keys = setStakingKeyPool.size() > 0;
74  } else {
75  // either external key was requested or HD is not enabled
76  keypool_has_keys = KeypoolCountExternalKeys() > 0;
77  }
78  // If the keypool doesn't have keys, check if we can generate them
79  if (!keypool_has_keys) {
80  return CanGenerateKeys();
81  }
82  return keypool_has_keys;
83 }
84 
85 static int64_t GetOldestKeyTimeInPool(const std::set<int64_t>& setKeyPool, WalletBatch& batch) {
86  if (setKeyPool.empty()) {
87  return GetTime();
88  }
89 
90  CKeyPool keypool;
91  int64_t nIndex = *(setKeyPool.begin());
92  if (!batch.ReadPool(nIndex, keypool)) {
93  throw std::runtime_error(std::string(__func__) + ": read oldest key in keypool failed");
94  }
95  assert(keypool.vchPubKey.IsValid());
96  return keypool.nTime;
97 }
98 
100 {
102 
103  WalletBatch batch(wallet->GetDBHandle());
104  // load oldest key from keypool, get time and return
105  int64_t oldestKey = GetOldestKeyTimeInPool(setExternalKeyPool, batch);
106  if (IsHDEnabled()) {
107  oldestKey = std::max(GetOldestKeyTimeInPool(setInternalKeyPool, batch), oldestKey);
108  oldestKey = std::max(GetOldestKeyTimeInPool(setStakingKeyPool, batch), oldestKey);
109  if (!set_pre_split_keypool.empty()) {
110  oldestKey = std::max(GetOldestKeyTimeInPool(set_pre_split_keypool, batch), oldestKey);
111  }
112  }
113 
114  return oldestKey;
115 }
116 
118 {
120  return setExternalKeyPool.size() + set_pre_split_keypool.size();
121 }
122 
124 {
126  return setInternalKeyPool.size() + setExternalKeyPool.size() + set_pre_split_keypool.size();
127 }
128 
130 {
132  return setStakingKeyPool.size();
133 }
134 
135 bool ScriptPubKeyMan::GetKeyFromPool(CPubKey& result, const uint8_t& changeType)
136 {
137  if (!CanGetAddresses(changeType)) {
138  LogPrintf("%s: Cannot get address, type: %d\n", __func__ ,changeType);
139  return false;
140  }
141 
142  CKeyPool keypool;
143  {
145  int64_t nIndex;
146  if (!ReserveKeyFromKeyPool(nIndex, keypool, changeType)) {
147  if (wallet->IsLocked()) {
148  LogPrintf("%s: Wallet locked, cannot get address\n", __func__);
149  return false;
150  }
151  WalletBatch batch(wallet->GetDBHandle());
152  result = GenerateNewKey(batch, changeType);
153  return true;
154  }
155  KeepDestination(nIndex);
156  result = keypool.vchPubKey;
157  }
158  return true;
159 }
160 
161 bool ScriptPubKeyMan::GetReservedKey(const uint8_t& changeType, int64_t& index, CKeyPool& keypool)
162 {
163  if (!CanGetAddresses(changeType)) {
164  return error("%s : Cannot get address for change type %d", __func__, changeType);
165  }
166  if (!ReserveKeyFromKeyPool(index, keypool, changeType)) {
167  return error("%s : Cannot reserve key from pool for change type %d", __func__, changeType);
168  }
169  return true;
170 }
171 
172 bool ScriptPubKeyMan::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, const uint8_t& type)
173 {
174  nIndex = -1;
175  keypool.vchPubKey = CPubKey();
176  {
178 
179  bool isHDEnabled = IsHDEnabled();
180  bool fReturningInternal = type == HDChain::ChangeType::INTERNAL && isHDEnabled;
181  bool fReturningStaking = type == HDChain::ChangeType::STAKING && isHDEnabled;
182  bool use_split_keypool = set_pre_split_keypool.empty();
183  std::set<int64_t>& setKeyPool = use_split_keypool ?
184  ( fReturningInternal ? setInternalKeyPool : (fReturningStaking ? setStakingKeyPool : setExternalKeyPool) ) : set_pre_split_keypool;
185 
186  // Get the oldest key
187  if (setKeyPool.empty()) {
188  return false;
189  }
190 
191  WalletBatch batch(wallet->GetDBHandle());
192 
193  auto it = setKeyPool.begin();
194  nIndex = *it;
195  setKeyPool.erase(it);
196  if (!batch.ReadPool(nIndex, keypool)) {
197  throw std::runtime_error(std::string(__func__) + ": read failed");
198  }
199  CPubKey pk;
200  if (!wallet->GetPubKey(keypool.vchPubKey.GetID(), pk)) {
201  throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
202  }
203  // If the key was pre-split keypool, we don't care about what type it is
204  if (use_split_keypool && keypool.IsInternal() != fReturningInternal) {
205  throw std::runtime_error(std::string(__func__) + ": keypool internal entry misclassified");
206  }
207 
208  if (use_split_keypool && keypool.IsStaking() != fReturningStaking) {
209  throw std::runtime_error(std::string(__func__) + ": keypool staking entry misclassified");
210  }
211 
212  if (!keypool.vchPubKey.IsValid()) {
213  throw std::runtime_error(std::string(__func__) + ": keypool entry invalid");
214  }
215 
216  assert(m_index_to_reserved_key.count(nIndex) == 0);
217  m_index_to_reserved_key[nIndex] = keypool.vchPubKey.GetID();
218  m_pool_key_to_index.erase(keypool.vchPubKey.GetID());
219  LogPrintf("%s: keypool reserve %d\n", __func__, nIndex);
220  }
221  //NotifyCanGetAddressesChanged();
222  return true;
223 }
224 
226 {
227  // Remove from key pool
228  WalletBatch batch(wallet->GetDBHandle());
229  batch.ErasePool(nIndex);
230  CPubKey pubkey;
231  bool have_pk = wallet->GetPubKey(m_index_to_reserved_key.at(nIndex), pubkey);
232  assert(have_pk);
233  m_index_to_reserved_key.erase(nIndex);
234  LogPrintf("keypool keep %d\n", nIndex);
235 }
236 
237 void ScriptPubKeyMan::ReturnDestination(int64_t nIndex, const uint8_t& type, const CTxDestination&)
238 {
239  // Return to key pool
240  {
242  const bool isHDEnabled = IsHDEnabled();
243  if (isHDEnabled && type == HDChain::ChangeType::INTERNAL) {
244  setInternalKeyPool.insert(nIndex);
245  } else if (isHDEnabled && type == HDChain::ChangeType::STAKING) {
246  setStakingKeyPool.insert(nIndex);
247  } else if (isHDEnabled && !set_pre_split_keypool.empty()) {
248  set_pre_split_keypool.insert(nIndex);
249  } else {
250  setExternalKeyPool.insert(nIndex);
251  }
252  CKeyID& pubkey_id = m_index_to_reserved_key.at(nIndex);
253  m_pool_key_to_index[pubkey_id] = nIndex;
254  m_index_to_reserved_key.erase(nIndex);
255  //NotifyCanGetAddressesChanged();
256  }
257  LogPrintf("%s: keypool return %d\n", __func__, nIndex);
258 }
259 
261 {
263  bool internal = setInternalKeyPool.count(keypool_id);
264  bool staking = setStakingKeyPool.count(keypool_id);
265  if (!internal) assert(setExternalKeyPool.count(keypool_id) || set_pre_split_keypool.count(keypool_id) || staking);
266  std::set<int64_t> *setKeyPool = internal ? &setInternalKeyPool : (set_pre_split_keypool.empty() ?
268  auto it = setKeyPool->begin();
269 
270  WalletBatch batch(wallet->GetDBHandle());
271  while (it != std::end(*setKeyPool)) {
272  const int64_t& index = *(it);
273  if (index > keypool_id) break; // set*KeyPool is ordered
274 
275  CKeyPool keypool;
276  if (batch.ReadPool(index, keypool)) {
277  const CKeyID& keyid = keypool.vchPubKey.GetID();
278  m_pool_key_to_index.erase(keyid);
279  // add missing receive addresses to the AddressBook
280  if (!internal && !wallet->HasAddressBook(keyid)) {
283  }
284  }
285  batch.ErasePool(index);
286  LogPrintf("keypool index %d removed\n", index);
287  it = setKeyPool->erase(it);
288  }
289 }
290 
292 {
294  // extract addresses and check if they match with an unused keypool key
295  for (const auto& keyid : wallet->GetAffectedKeys(script)) {
296  std::map<CKeyID, int64_t>::const_iterator mi = m_pool_key_to_index.find(keyid);
297  if (mi != m_pool_key_to_index.end()) {
298  LogPrintf("%s: Detected a used keypool key, mark all keypool key up to this key as used\n", __func__);
299  MarkReserveKeysAsUsed(mi->second);
300 
301  if (!TopUp()) {
302  LogPrintf("%s: Topping up keypool failed (locked wallet)\n", __func__);
303  }
304  }
305  }
306 }
307 
309 {
310  WalletBatch batch(wallet->GetDBHandle());
311  for (auto it = setExternalKeyPool.begin(); it != setExternalKeyPool.end();) {
312  int64_t index = *it;
313  CKeyPool keypool;
314  if (!batch.ReadPool(index, keypool)) {
315  throw std::runtime_error(std::string(__func__) + ": read keypool entry failed");
316  }
317  keypool.m_pre_split = true;
318  if (!batch.WritePool(index, keypool)) {
319  throw std::runtime_error(std::string(__func__) + ": writing modified keypool entry failed");
320  }
321  set_pre_split_keypool.insert(index);
322  it = setExternalKeyPool.erase(it);
323  }
324 }
325 
331 {
332  {
334 
335  WalletBatch batch(wallet->GetDBHandle());
336  // Internal
337  for (const int64_t nIndex : setInternalKeyPool) {
338  batch.ErasePool(nIndex);
339  }
340  setInternalKeyPool.clear();
341 
342  // External
343  for (const int64_t nIndex : setExternalKeyPool) {
344  batch.ErasePool(nIndex);
345  }
346  setExternalKeyPool.clear();
347 
348  // Staking
349  for (const int64_t nIndex : setStakingKeyPool) {
350  batch.ErasePool(nIndex);
351  }
352  setStakingKeyPool.clear();
353 
354  // key -> index.
355  m_pool_key_to_index.clear();
356 
357  if (!TopUp()) {
358  return false;
359  }
360  LogPrintf("ScriptPubKeyMan::NewKeyPool rewrote keypool\n");
361  }
362  return true;
363 }
364 
368 bool ScriptPubKeyMan::TopUp(unsigned int kpSize)
369 {
370  if (!CanGenerateKeys()) {
371  return false;
372  }
373  {
375  if (wallet->IsLocked()) return false;
376 
377  // Top up key pool
378  unsigned int nTargetSize;
379  if (kpSize > 0)
380  nTargetSize = kpSize;
381  else
382  nTargetSize = std::max(gArgs.GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0);
383 
384  // Count amount of available keys (internal, external)
385  // make sure the keypool of external and internal keys fits the user selected target (-keypool)
386  int64_t missingExternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - (int64_t)setExternalKeyPool.size(), (int64_t) 0);
387  int64_t missingInternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - (int64_t)setInternalKeyPool.size(), (int64_t) 0);
388  int64_t missingStaking = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - (int64_t)setStakingKeyPool.size(), (int64_t) 0);
389 
390  if (!IsHDEnabled()) {
391  // don't create extra internal or staking keys
392  missingInternal = 0;
393  missingStaking = 0;
394  }
395 
396  WalletBatch batch(wallet->GetDBHandle());
397  GeneratePool(batch, missingExternal, HDChain::ChangeType::EXTERNAL);
398  GeneratePool(batch, missingInternal, HDChain::ChangeType::INTERNAL);
399  GeneratePool(batch, missingStaking, HDChain::ChangeType::STAKING);
400 
401  if (missingInternal + missingExternal > 0) {
402  LogPrintf("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());
403  }
404  if (missingStaking > 0) {
405  LogPrintf("keypool added %d staking keys\n", setStakingKeyPool.size());
406  }
407  }
408  // TODO: Implement this.
409  //NotifyCanGetAddressesChanged();
410  return true;
411 }
412 
413 void ScriptPubKeyMan::GeneratePool(WalletBatch& batch, int64_t targetSize, const uint8_t& type)
414 {
415  for (int64_t i = targetSize; i--;) {
416  CPubKey pubkey(GenerateNewKey(batch, type));
417  AddKeypoolPubkeyWithDB(pubkey, type, batch);
418  }
419 }
420 
421 void ScriptPubKeyMan::AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const uint8_t& type, WalletBatch &batch)
422 {
424  assert(m_max_keypool_index < std::numeric_limits<int64_t>::max()); // How in the hell did you use so many keys?
425  int64_t index = ++m_max_keypool_index;
426  if (!batch.WritePool(index, CKeyPool(pubkey, type))) {
427  throw std::runtime_error(std::string(__func__) + ": writing imported pubkey failed");
428  }
429 
430  const bool isHDEnabled = IsHDEnabled();
431  if (isHDEnabled && type == HDChain::ChangeType::INTERNAL) {
432  setInternalKeyPool.insert(index);
433  } else if (isHDEnabled && type == HDChain::ChangeType::STAKING) {
434  setStakingKeyPool.insert(index);
435  } else {
436  setExternalKeyPool.insert(index);
437  }
438 
439  m_pool_key_to_index[pubkey.GetID()] = index;
440 }
441 
446 {
448  bool fCompressed = wallet->CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
449 
450  CKey secret;
451 
452  // Create new metadata
453  int64_t nCreationTime = GetTime();
454  CKeyMetadata metadata(nCreationTime);
455 
456  // use HD key derivation if HD was enabled during wallet creation and a seed is present
457  if (IsHDEnabled()) {
458  DeriveNewChildKey(batch, metadata, secret, type);
459  } else {
460  secret.MakeNewKey(fCompressed);
461  }
462 
463  // Compressed public keys were introduced in version 0.6.0
464  if (fCompressed) {
466  }
467 
468  CPubKey pubkey = secret.GetPubKey();
469  assert(secret.VerifyPubKey(pubkey));
470 
471  wallet->mapKeyMetadata[pubkey.GetID()] = metadata;
472  UpdateTimeFirstKey(nCreationTime);
473 
474  if (!AddKeyPubKeyWithDB(batch, secret, pubkey)) {
475  throw std::runtime_error(std::string(__func__) + ": AddKey failed");
476  }
477  return pubkey;
478 }
479 
480 void ScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey& secret, const uint8_t& changeType)
481 {
483  // Use BIP44 keypath scheme i.e. m / purpose' / coin_type' / account' / change / address_index
484  CKey seed; //seed (256bit)
485  CExtKey masterKey; //hd master key
486  CExtKey purposeKey; //key at m/purpose' --> key at m/44'
487  CExtKey cointypeKey; //key at m/purpose'/coin_type' --> key at m/44'/119'
488  CExtKey accountKey; //key at m/purpose'/coin_type'/account' ---> key at m/44'/119'/account_num'
489  CExtKey changeKey; //key at m/purpose'/coin_type'/account'/change ---> key at m/44'/119'/account_num'/change', external = 0' or internal = 1'.
490  CExtKey childKey; //key at m/purpose'/coin_type'/account'/change/address_index ---> key at m/44'/119'/account_num'/change'/<n>'
491 
492  // For now only one account.
493  int nAccountNumber = 0;
494 
495  // try to get the seed
496  if (!wallet->GetKey(hdChain.GetID(), seed))
497  throw std::runtime_error(std::string(__func__) + ": seed not found");
498 
499  masterKey.SetSeed(seed.begin(), seed.size());
500 
501  // derive m/0'
502  // use hardened derivation (child keys >= 0x80000000 are hardened after bip32)
503  masterKey.Derive(purposeKey, 44 | BIP32_HARDENED_KEY_LIMIT);
504  // derive m/purpose'/coin_type'
505  purposeKey.Derive(cointypeKey, 119 | BIP32_HARDENED_KEY_LIMIT);
506  // derive m/purpose'/coin_type'/account' // Hardcoded to account 0 for now.
507  cointypeKey.Derive(accountKey, nAccountNumber | BIP32_HARDENED_KEY_LIMIT);
508  // derive m/purpose'/coin_type'/account'/change'
509  accountKey.Derive(changeKey, changeType | BIP32_HARDENED_KEY_LIMIT);
510 
511  // derive child key at next index, skip keys already known to the wallet
512  do {
513  // always derive hardened keys
514  // childIndex | BIP32_HARDENED_KEY_LIMIT = derive childIndex in hardened child-index-range
515  // example: 1 | BIP32_HARDENED_KEY_LIMIT == 0x80000001 == 2147483649
516 
517  // m/44'/119'/account_num/change'/<n>'
518  metadata.key_origin.path.push_back(44 | BIP32_HARDENED_KEY_LIMIT);
519  metadata.key_origin.path.push_back(119 | BIP32_HARDENED_KEY_LIMIT);
520  metadata.key_origin.path.push_back(nAccountNumber | BIP32_HARDENED_KEY_LIMIT);
521  // Child chain counter
522  uint32_t& chainCounter = hdChain.GetChainCounter(changeType);
523  changeKey.Derive(childKey, chainCounter | BIP32_HARDENED_KEY_LIMIT);
524  metadata.key_origin.path.push_back( changeType | BIP32_HARDENED_KEY_LIMIT);
525  metadata.key_origin.path.push_back(chainCounter | BIP32_HARDENED_KEY_LIMIT);
526  chainCounter++;
527 
528  } while (wallet->HaveKey(childKey.key.GetPubKey().GetID()));
529 
530  secret = childKey.key;
531  metadata.hd_seed_id = hdChain.GetID();
532  CKeyID master_id = masterKey.key.GetPubKey().GetID();
533  std::copy(master_id.begin(), master_id.begin() + 4, metadata.key_origin.fingerprint);
534  // update the chain model in the database
535  if (!batch.WriteHDChain(hdChain))
536  throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed");
537 }
538 
539 void ScriptPubKeyMan::LoadKeyPool(int64_t nIndex, const CKeyPool &keypool)
540 {
542  if (keypool.m_pre_split) {
543  set_pre_split_keypool.insert(nIndex);
544  } else if (keypool.IsInternal()) {
545  setInternalKeyPool.insert(nIndex);
546  } else if (keypool.IsExternal()){
547  setExternalKeyPool.insert(nIndex);
548  } else if (keypool.IsStaking()){
549  setStakingKeyPool.insert(nIndex);
550  } else {
551  throw std::runtime_error(std::string(__func__) + ": invalid CKeypool type");
552  }
553  m_max_keypool_index = std::max(m_max_keypool_index, nIndex);
554  m_pool_key_to_index[keypool.vchPubKey.GetID()] = nIndex;
555 
556  // If no metadata exists yet, create a default with the pool key's
557  // creation time. Note that this may be overwritten by actually
558  // stored metadata for that key later, which is fine.
559  CKeyID keyid = keypool.vchPubKey.GetID();
560  if (wallet->mapKeyMetadata.count(keyid) == 0)
561  wallet->mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
562 }
563 
568 void ScriptPubKeyMan::UpdateTimeFirstKey(int64_t nCreateTime)
569 {
571  if (nCreateTime <= 1) {
572  // Cannot determine birthday information, so set the wallet birthday to
573  // the beginning of time.
574  wallet->nTimeFirstKey = 1;
575  } else if (!wallet->nTimeFirstKey || nCreateTime < wallet->nTimeFirstKey) {
576  wallet->nTimeFirstKey = nCreateTime;
577  }
578 }
579 
580 bool ScriptPubKeyMan::AddKeyPubKeyWithDB(WalletBatch& batch, const CKey& secret, const CPubKey& pubkey)
581 {
583 
584  // Make sure we aren't adding private keys to private key disabled wallets
585  //assert(!m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
586 
587  // FillableSigningProvider has no concept of wallet databases, but calls AddCryptedKey
588  // which is overridden below. To avoid flushes, the database handle is
589  // tunneled through to it.
590  bool needsDB = !encrypted_batch;
591  if (needsDB) {
592  encrypted_batch = &batch;
593  }
594  if (!AddKeyPubKeyInner(secret, pubkey)) {
595  if (needsDB) encrypted_batch = nullptr;
596  return false;
597  }
598  if (needsDB) encrypted_batch = nullptr;
599  return true;
600 }
601 
602 bool ScriptPubKeyMan::AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey)
603 {
605  if (!wallet->HasEncryptionKeys()) {
606  return wallet->AddKeyPubKey(key, pubkey);
607  }
608 
609  if (wallet->IsLocked()) {
610  return false;
611  }
612 
613  std::vector<unsigned char> vchCryptedSecret;
614  CKeyingMaterial vchSecret(key.begin(), key.end());
615  if (!EncryptSecret(wallet->GetEncryptionKey(), vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
616  return false;
617  }
618 
619  if (!wallet->AddCryptedKey(pubkey, vchCryptedSecret)) {
620  return false;
621  }
622  return true;
623 }
624 
626 
628 {
629  CKey secret;
630  secret.MakeNewKey(true);
631  return DeriveNewSeed(secret);
632 }
633 
635 {
636  int64_t nCreationTime = GetTime();
637  CKeyMetadata metadata(nCreationTime);
638 
639  // Calculate the seed
640  CPubKey seed = key.GetPubKey();
641  assert(key.VerifyPubKey(seed));
642 
643  // Set seed id
644  metadata.hd_seed_id = seed.GetID();
645 
646  {
648 
649  // mem store the metadata
650  wallet->mapKeyMetadata[seed.GetID()] = metadata;
651 
652  // write the key&metadata to the database
653  if (!wallet->AddKeyPubKey(key, seed))
654  throw std::runtime_error(std::string(__func__) + ": AddKeyPubKey failed");
655  }
656 
657  return seed;
658 }
659 
660 
662 
663 void ScriptPubKeyMan::SetHDSeed(const CPubKey& seed, bool force, bool memOnly)
664 {
665  if (!hdChain.IsNull() && !force)
666  throw std::runtime_error(std::string(__func__) + ": trying to set a hd seed on an already created chain");
667 
669  // store the keyid (hash160) together with
670  // the child index counter in the database
671  // as a hdChain object
672  CHDChain newHdChain;
673  if (!newHdChain.SetSeed(seed.GetID()) ) {
674  throw std::runtime_error(std::string(__func__) + ": set hd seed failed");
675  }
676 
677  SetHDChain(newHdChain, memOnly);
678  // TODO: Connect this if is needed.
679  //NotifyCanGetAddressesChanged();
680 }
681 
682 void ScriptPubKeyMan::SetHDChain(CHDChain& chain, bool memonly)
683 {
685  if (!memonly && !WalletBatch(wallet->GetDBHandle()).WriteHDChain(chain))
686  throw std::runtime_error(std::string(__func__) + ": writing chain failed");
687 
688  hdChain = chain;
689 
690  // Sanity check
691  if (!wallet->HaveKey(hdChain.GetID()))
692  throw std::runtime_error(std::string(__func__) + ": Not found seed in wallet");
693 }
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: system.cpp:449
bool GetKey(const CKeyID &address, CKey &keyOut) const override
Definition: crypter.cpp:199
bool IsLocked() const
Definition: crypter.cpp:148
bool HaveKey(const CKeyID &address) const override
Check whether a key corresponding to a given address is present in the store.
Definition: crypter.cpp:179
bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const override
Definition: crypter.cpp:215
bool SetSeed(const CKeyID &seedId)
Definition: hdchain.cpp:28
bool IsNull() const
Definition: hdchain.cpp:23
CKeyID GetID() const
Definition: hdchain.h:52
uint32_t & GetChainCounter(const uint8_t &type=HDChain::ChangeType::EXTERNAL)
Definition: hdchain.h:54
An encapsulated private key.
Definition: key.h:30
const unsigned char * end() const
Definition: key.h:92
unsigned int size() const
Simple read-only vector-like interface.
Definition: key.h:90
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
Definition: key.cpp:158
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:186
const unsigned char * begin() const
Definition: key.h:91
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
Definition: key.cpp:216
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:21
KeyOriginInfo key_origin
Definition: walletdb.h:71
CKeyID hd_seed_id
Definition: walletdb.h:70
A key pool entry.
Definition: wallet.h:125
bool IsExternal() const
Definition: wallet.h:140
CPubKey vchPubKey
The public key.
Definition: wallet.h:130
bool IsStaking() const
Definition: wallet.h:141
int64_t nTime
The time at which the key was generated. Set in AddKeypoolPubKeyWithDB.
Definition: wallet.h:128
bool m_pre_split
Whether this key was generated for a keypool before the wallet was upgraded to HD-split.
Definition: wallet.h:134
bool IsInternal() const
Definition: wallet.h:139
RecursiveMutex cs_KeyStore
Definition: keystore.h:26
An encapsulated public key.
Definition: pubkey.h:44
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:167
bool IsValid() const
Definition: pubkey.h:183
uint256 GetHash() const
Get the 256-bit hash of this public key.
Definition: pubkey.h:173
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:381
RecursiveMutex cs_wallet
Definition: wallet.h:720
int GetVersion()
get the current wallet format (the oldest client version guaranteed to understand this wallet)
Definition: wallet.cpp:4701
int64_t nTimeFirstKey
Definition: wallet.h:776
bool CanSupportFeature(enum WalletFeature wf)
check whether we are allowed to upgrade (or already support) to the named feature
Definition: wallet.cpp:4584
std::map< CKeyID, CKeyMetadata > mapKeyMetadata
Definition: wallet.h:726
WalletDatabase & GetDBHandle() const
Definition: wallet.h:752
bool TopUp(unsigned int size=0)
Fills internal address pool.
bool AddKeyPubKeyInner(const CKey &key, const CPubKey &pubkey)
CPubKey DeriveNewSeed(const CKey &key)
std::map< CKeyID, int64_t > m_pool_key_to_index
int64_t GetOldestKeyPoolTime()
std::set< int64_t > set_pre_split_keypool
bool NewKeyPool()
Key pool.
void MarkReserveKeysAsUsed(int64_t keypool_id)
Marks all keys in the keypool up to and including reserve_key as used.
void KeepDestination(int64_t index)
void SetHDSeed(const CPubKey &key, bool force=false, bool memOnly=false)
std::set< int64_t > setStakingKeyPool
void SetHDChain(CHDChain &chain, bool memonly)
bool IsHDEnabled() const
void GeneratePool(WalletBatch &batch, int64_t targetSize, const uint8_t &type)
bool SetupGeneration(bool newKeypool=true, bool force=false, bool memOnly=false)
Sets up the key generation stuff, i.e.
void DeriveNewChildKey(WalletBatch &batch, CKeyMetadata &metadata, CKey &secret, const uint8_t &type=HDChain::ChangeType::EXTERNAL)
size_t KeypoolCountExternalKeys()
bool ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool, const uint8_t &type=HDChain::ChangeType::EXTERNAL)
Reserves a key from the keypool and sets nIndex to its index.
unsigned int GetKeyPoolSize() const
std::set< int64_t > setInternalKeyPool
bool CanGetAddresses(const uint8_t &type=HDChain::ChangeType::EXTERNAL)
void MarkPreSplitKeys()
Update pre HD keys in db with the pre-split flag enabled.
unsigned int GetStakingKeyPoolSize() const
void MarkUnusedAddresses(const CScript &script)
Mark unused addresses as being used.
void AddKeypoolPubkeyWithDB(const CPubKey &pubkey, const uint8_t &type, WalletBatch &batch)
WalletBatch * encrypted_batch
int64_t m_max_keypool_index
bool GetReservedKey(const uint8_t &changeType, int64_t &index, CKeyPool &keypool)
Reserve + fetch a key from the keypool.
void ReturnDestination(int64_t index, const uint8_t &type, const CTxDestination &)
bool GetKeyFromPool(CPubKey &key, const uint8_t &changeType=HDChain::ChangeType::EXTERNAL)
Fetches a key from the keypool.
CPubKey GenerateNewSeed()
void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool)
Load a keypool entry.
bool Upgrade(const int prev_version, std::string &error)
Upgrades the wallet to the specified version.
void UpdateTimeFirstKey(int64_t nCreateTime)
First wallet key time.
std::set< int64_t > setExternalKeyPool
bool AddKeyPubKeyWithDB(WalletBatch &batch, const CKey &key, const CPubKey &pubkey)
Adds a key to the store, and saves it to disk.
std::map< int64_t, CKeyID > m_index_to_reserved_key
CPubKey GenerateNewKey(WalletBatch &batch, const uint8_t &type=HDChain::ChangeType::EXTERNAL)
Generate a new key.
Access to the wallet database.
Definition: walletdb.h:112
bool ErasePool(int64_t nPool)
Definition: walletdb.cpp:265
bool ReadPool(int64_t nPool, CKeyPool &keypool)
Definition: walletdb.cpp:255
bool WriteHDChain(const CHDChain &chain)
write the hdchain model (external/internal chain child index counter)
Definition: walletdb.cpp:275
bool WritePool(int64_t nPool, const CKeyPool &keypool)
Definition: walletdb.cpp:260
unsigned char * begin()
Definition: uint256.h:63
bool EncryptSecret(const CKeyingMaterial &vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256 &nIV, std::vector< unsigned char > &vchCiphertext)
Definition: crypter.cpp:104
std::vector< unsigned char, secure_allocator< unsigned char > > CKeyingMaterial
Definition: crypter.h:63
bool HasAddressBook(const CWDestination &address) const
Definition: wallet.cpp:3710
bool SetAddressBook(const CWDestination &address, const std::string &strName, const std::string &purpose)
Definition: wallet.cpp:3642
std::vector< CKeyID > GetAffectedKeys(const CScript &spk)
Definition: wallet.cpp:118
const CKeyingMaterial & GetEncryptionKey() const
Definition: wallet.cpp:691
bool SetMinVersion(enum WalletFeature, WalletBatch *batch_in=nullptr, bool fExplicit=false)
signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVe...
Definition: wallet.cpp:580
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret) override
Adds an encrypted key to the store, and saves it to disk.
Definition: wallet.cpp:279
bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) override
Adds a key to the store, and saves it to disk.
Definition: wallet.cpp:252
bool HasEncryptionKeys() const
Definition: wallet.cpp:696
@ LOCK
Definition: lockunlock.h:16
const std::string COLD_STAKING
Definition: addressbook.cpp:15
boost::variant< CNoDestination, CKeyID, CScriptID, CExchangeKeyID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:72
Definition: key.h:148
bool Derive(CExtKey &out, unsigned int nChild) const
Definition: key.cpp:281
void SetSeed(const unsigned char *seed, unsigned int nSeedLen)
Definition: key.cpp:290
CKey key
Definition: key.h:153
unsigned char fingerprint[4]
First 32 bits of the Hash160 of the public key at the root of the path.
Definition: keyorigin.h:13
std::vector< uint32_t > path
Definition: keyorigin.h:14
#define AssertLockHeld(cs)
Definition: sync.h:75
ArgsManager gArgs
Definition: system.cpp:89
bool error(const char *fmt, const Args &... args)
Definition: system.h:77
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a Optional result.
Definition: system.h:65
int64_t GetTime()
DEPRECATED Use either GetSystemTimeInSeconds (not mockable) or GetTime<T> (mockable)
Definition: utiltime.cpp:27
@ FEATURE_PRE_SPLIT_KEYPOOL
Definition: wallet.h:116
@ FEATURE_COMPRPUBKEY
Definition: wallet.h:108