27 bool hd_upgrade =
false;
29 LogPrintf(
"Upgrading wallet to use HD chain split\n");
45 error =
_(
"Unable to generate keys");
69 bool keypool_has_keys =
false;
70 if (isHDEnabled && type == HDChain::ChangeType::INTERNAL) {
72 }
else if (isHDEnabled && type == HDChain::ChangeType::STAKING) {
79 if (!keypool_has_keys) {
82 return keypool_has_keys;
85 static int64_t GetOldestKeyTimeInPool(
const std::set<int64_t>& setKeyPool,
WalletBatch& batch) {
86 if (setKeyPool.empty()) {
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");
108 oldestKey = std::max(GetOldestKeyTimeInPool(
setStakingKeyPool, batch), oldestKey);
138 LogPrintf(
"%s: Cannot get address, type: %d\n", __func__ ,changeType);
148 LogPrintf(
"%s: Wallet locked, cannot get address\n", __func__);
164 return error(
"%s : Cannot get address for change type %d", __func__, changeType);
167 return error(
"%s : Cannot reserve key from pool for change type %d", __func__, changeType);
180 bool fReturningInternal = type == HDChain::ChangeType::INTERNAL && isHDEnabled;
181 bool fReturningStaking = type == HDChain::ChangeType::STAKING && isHDEnabled;
183 std::set<int64_t>& setKeyPool = use_split_keypool ?
187 if (setKeyPool.empty()) {
193 auto it = setKeyPool.begin();
195 setKeyPool.erase(it);
196 if (!batch.
ReadPool(nIndex, keypool)) {
197 throw std::runtime_error(std::string(__func__) +
": read failed");
201 throw std::runtime_error(std::string(__func__) +
": unknown key in key pool");
204 if (use_split_keypool && keypool.
IsInternal() != fReturningInternal) {
205 throw std::runtime_error(std::string(__func__) +
": keypool internal entry misclassified");
208 if (use_split_keypool && keypool.
IsStaking() != fReturningStaking) {
209 throw std::runtime_error(std::string(__func__) +
": keypool staking entry misclassified");
213 throw std::runtime_error(std::string(__func__) +
": keypool entry invalid");
219 LogPrintf(
"%s: keypool reserve %d\n", __func__, nIndex);
234 LogPrintf(
"keypool keep %d\n", nIndex);
243 if (isHDEnabled && type == HDChain::ChangeType::INTERNAL) {
245 }
else if (isHDEnabled && type == HDChain::ChangeType::STAKING) {
257 LogPrintf(
"%s: keypool return %d\n", __func__, nIndex);
268 auto it = setKeyPool->begin();
271 while (it != std::end(*setKeyPool)) {
272 const int64_t& index = *(it);
273 if (index > keypool_id)
break;
276 if (batch.
ReadPool(index, keypool)) {
286 LogPrintf(
"keypool index %d removed\n", index);
287 it = setKeyPool->erase(it);
298 LogPrintf(
"%s: Detected a used keypool key, mark all keypool key up to this key as used\n", __func__);
302 LogPrintf(
"%s: Topping up keypool failed (locked wallet)\n", __func__);
314 if (!batch.
ReadPool(index, keypool)) {
315 throw std::runtime_error(std::string(__func__) +
": read keypool entry failed");
319 throw std::runtime_error(std::string(__func__) +
": writing modified keypool entry failed");
360 LogPrintf(
"ScriptPubKeyMan::NewKeyPool rewrote keypool\n");
378 unsigned int nTargetSize;
380 nTargetSize = kpSize;
382 nTargetSize = std::max(
gArgs.
GetArg(
"-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0);
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);
397 GeneratePool(batch, missingExternal, HDChain::ChangeType::EXTERNAL);
398 GeneratePool(batch, missingInternal, HDChain::ChangeType::INTERNAL);
399 GeneratePool(batch, missingStaking, HDChain::ChangeType::STAKING);
401 if (missingInternal + missingExternal > 0) {
404 if (missingStaking > 0) {
415 for (int64_t i = targetSize; i--;) {
427 throw std::runtime_error(std::string(__func__) +
": writing imported pubkey failed");
431 if (isHDEnabled && type == HDChain::ChangeType::INTERNAL) {
433 }
else if (isHDEnabled && type == HDChain::ChangeType::STAKING) {
453 int64_t nCreationTime =
GetTime();
475 throw std::runtime_error(std::string(__func__) +
": AddKey failed");
493 int nAccountNumber = 0;
497 throw std::runtime_error(std::string(__func__) +
": seed not found");
503 masterKey.
Derive(purposeKey, 44 | BIP32_HARDENED_KEY_LIMIT);
505 purposeKey.
Derive(cointypeKey, 119 | BIP32_HARDENED_KEY_LIMIT);
507 cointypeKey.
Derive(accountKey, nAccountNumber | BIP32_HARDENED_KEY_LIMIT);
509 accountKey.
Derive(changeKey, changeType | BIP32_HARDENED_KEY_LIMIT);
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);
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);
530 secret = childKey.
key;
536 throw std::runtime_error(std::string(__func__) +
": Writing HD chain model failed");
551 throw std::runtime_error(std::string(__func__) +
": invalid CKeypool type");
571 if (nCreateTime <= 1) {
613 std::vector<unsigned char> vchCryptedSecret;
636 int64_t nCreationTime =
GetTime();
654 throw std::runtime_error(std::string(__func__) +
": AddKeyPubKey failed");
666 throw std::runtime_error(std::string(__func__) +
": trying to set a hd seed on an already created chain");
674 throw std::runtime_error(std::string(__func__) +
": set hd seed failed");
686 throw std::runtime_error(std::string(__func__) +
": writing chain failed");
692 throw std::runtime_error(std::string(__func__) +
": Not found seed in wallet");
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
bool GetKey(const CKeyID &address, CKey &keyOut) const override
bool HaveKey(const CKeyID &address) const override
Check whether a key corresponding to a given address is present in the store.
bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const override
bool SetSeed(const CKeyID &seedId)
uint32_t & GetChainCounter(const uint8_t &type=HDChain::ChangeType::EXTERNAL)
An encapsulated private key.
const unsigned char * end() const
unsigned int size() const
Simple read-only vector-like interface.
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
CPubKey GetPubKey() const
Compute the public key from a private key.
const unsigned char * begin() const
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
A reference to a CKey: the Hash160 of its serialized public key.
CPubKey vchPubKey
The public key.
int64_t nTime
The time at which the key was generated. Set in AddKeypoolPubKeyWithDB.
bool m_pre_split
Whether this key was generated for a keypool before the wallet was upgraded to HD-split.
RecursiveMutex cs_KeyStore
An encapsulated public key.
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
uint256 GetHash() const
Get the 256-bit hash of this public key.
Serialized script, used inside transaction inputs and outputs.
int GetVersion()
get the current wallet format (the oldest client version guaranteed to understand this wallet)
bool CanSupportFeature(enum WalletFeature wf)
check whether we are allowed to upgrade (or already support) to the named feature
std::map< CKeyID, CKeyMetadata > mapKeyMetadata
WalletDatabase & GetDBHandle() const
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)
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.
bool ErasePool(int64_t nPool)
bool ReadPool(int64_t nPool, CKeyPool &keypool)
bool WriteHDChain(const CHDChain &chain)
write the hdchain model (external/internal chain child index counter)
bool WritePool(int64_t nPool, const CKeyPool &keypool)
bool EncryptSecret(const CKeyingMaterial &vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256 &nIV, std::vector< unsigned char > &vchCiphertext)
std::vector< unsigned char, secure_allocator< unsigned char > > CKeyingMaterial
bool HasAddressBook(const CWDestination &address) const
bool SetAddressBook(const CWDestination &address, const std::string &strName, const std::string &purpose)
std::vector< CKeyID > GetAffectedKeys(const CScript &spk)
const CKeyingMaterial & GetEncryptionKey() const
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...
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret) override
Adds an encrypted key to the store, and saves it to disk.
bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) override
Adds a key to the store, and saves it to disk.
bool HasEncryptionKeys() const
const std::string RECEIVE
const std::string COLD_STAKING
boost::variant< CNoDestination, CKeyID, CScriptID, CExchangeKeyID > CTxDestination
A txout script template with a specific destination.
bool Derive(CExtKey &out, unsigned int nChild) const
void SetSeed(const unsigned char *seed, unsigned int nSeedLen)
unsigned char fingerprint[4]
First 32 bits of the Hash160 of the public key at the root of the path.
std::vector< uint32_t > path
#define AssertLockHeld(cs)
bool error(const char *fmt, const Args &... args)
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a Optional result.
int64_t GetTime()
DEPRECATED Use either GetSystemTimeInSeconds (not mockable) or GetTime<T> (mockable)
@ FEATURE_PRE_SPLIT_KEYPOOL