Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | const CWalletTx *CWallet::GetWalletTx(const uint256 &hash) const { | ||||
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash); | std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash); | ||||
if (it == mapWallet.end()) { | if (it == mapWallet.end()) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
return &(it->second); | return &(it->second); | ||||
} | } | ||||
CPubKey CWallet::GenerateNewKey(bool internal) { | CPubKey CWallet::GenerateNewKey(CWalletDB &walletdb, bool internal) { | ||||
// mapKeyMetadata | // mapKeyMetadata | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
// default to compressed public keys if we want 0.6.0 wallets | // default to compressed public keys if we want 0.6.0 wallets | ||||
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); | bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); | ||||
CKey secret; | CKey secret; | ||||
// Create new metadata | // Create new metadata | ||||
int64_t nCreationTime = GetTime(); | int64_t nCreationTime = GetTime(); | ||||
CKeyMetadata metadata(nCreationTime); | CKeyMetadata metadata(nCreationTime); | ||||
// use HD key derivation if HD was enabled during wallet creation | // use HD key derivation if HD was enabled during wallet creation | ||||
if (IsHDEnabled()) { | if (IsHDEnabled()) { | ||||
DeriveNewChildKey( | DeriveNewChildKey( | ||||
metadata, secret, | walletdb, metadata, secret, | ||||
(CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false)); | (CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false)); | ||||
} else { | } else { | ||||
secret.MakeNewKey(fCompressed); | secret.MakeNewKey(fCompressed); | ||||
} | } | ||||
// Compressed public keys were introduced in version 0.6.0 | // Compressed public keys were introduced in version 0.6.0 | ||||
if (fCompressed) { | if (fCompressed) { | ||||
SetMinVersion(FEATURE_COMPRPUBKEY); | SetMinVersion(FEATURE_COMPRPUBKEY); | ||||
} | } | ||||
CPubKey pubkey = secret.GetPubKey(); | CPubKey pubkey = secret.GetPubKey(); | ||||
assert(secret.VerifyPubKey(pubkey)); | assert(secret.VerifyPubKey(pubkey)); | ||||
mapKeyMetadata[pubkey.GetID()] = metadata; | mapKeyMetadata[pubkey.GetID()] = metadata; | ||||
UpdateTimeFirstKey(nCreationTime); | UpdateTimeFirstKey(nCreationTime); | ||||
if (!AddKeyPubKey(secret, pubkey)) { | if (!AddKeyPubKeyWithDB(walletdb, secret, pubkey)) { | ||||
throw std::runtime_error(std::string(__func__) + ": AddKey failed"); | throw std::runtime_error(std::string(__func__) + ": AddKey failed"); | ||||
} | } | ||||
return pubkey; | return pubkey; | ||||
} | } | ||||
void CWallet::DeriveNewChildKey(CKeyMetadata &metadata, CKey &secret, | void CWallet::DeriveNewChildKey(CWalletDB &walletdb, CKeyMetadata &metadata, | ||||
bool internal) { | CKey &secret, bool internal) { | ||||
// for now we use a fixed keypath scheme of m/0'/0'/k | // for now we use a fixed keypath scheme of m/0'/0'/k | ||||
// master key seed (256bit) | // master key seed (256bit) | ||||
CKey key; | CKey key; | ||||
// hd master key | // hd master key | ||||
CExtKey masterKey; | CExtKey masterKey; | ||||
// key at m/0' | // key at m/0' | ||||
CExtKey accountKey; | CExtKey accountKey; | ||||
// key at m/0'/0' (external) or m/0'/1' (internal) | // key at m/0'/0' (external) or m/0'/1' (internal) | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | do { | ||||
std::to_string(hdChain.nExternalChainCounter) + | std::to_string(hdChain.nExternalChainCounter) + | ||||
"'"; | "'"; | ||||
hdChain.nExternalChainCounter++; | hdChain.nExternalChainCounter++; | ||||
} | } | ||||
} while (HaveKey(childKey.key.GetPubKey().GetID())); | } while (HaveKey(childKey.key.GetPubKey().GetID())); | ||||
secret = childKey.key; | secret = childKey.key; | ||||
metadata.hdMasterKeyID = hdChain.masterKeyID; | metadata.hdMasterKeyID = hdChain.masterKeyID; | ||||
// update the chain model in the database | // update the chain model in the database | ||||
if (!CWalletDB(*dbw).WriteHDChain(hdChain)) { | if (!walletdb.WriteHDChain(hdChain)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": Writing HD chain model failed"); | ": Writing HD chain model failed"); | ||||
} | } | ||||
} | } | ||||
bool CWallet::AddKeyPubKey(const CKey &secret, const CPubKey &pubkey) { | bool CWallet::AddKeyPubKeyWithDB(CWalletDB &walletdb, const CKey &secret, | ||||
const CPubKey &pubkey) { | |||||
// mapKeyMetadata | // mapKeyMetadata | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
// CCryptoKeyStore has no concept of wallet databases, but calls | |||||
// AddCryptedKey | |||||
// which is overridden below. To avoid flushes, the database handle is | |||||
// tunneled through to it. | |||||
bool needsDB = !pwalletdbEncryption; | |||||
if (needsDB) { | |||||
pwalletdbEncryption = &walletdb; | |||||
} | |||||
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) { | if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) { | ||||
if (needsDB) { | |||||
pwalletdbEncryption = nullptr; | |||||
} | |||||
return false; | return false; | ||||
} | } | ||||
if (needsDB) { | |||||
pwalletdbEncryption = nullptr; | |||||
} | |||||
// Check if we need to remove from watch-only. | // Check if we need to remove from watch-only. | ||||
CScript script; | CScript script; | ||||
script = GetScriptForDestination(pubkey.GetID()); | script = GetScriptForDestination(pubkey.GetID()); | ||||
if (HaveWatchOnly(script)) { | if (HaveWatchOnly(script)) { | ||||
RemoveWatchOnly(script); | RemoveWatchOnly(script); | ||||
} | } | ||||
script = GetScriptForRawPubKey(pubkey); | script = GetScriptForRawPubKey(pubkey); | ||||
if (HaveWatchOnly(script)) { | if (HaveWatchOnly(script)) { | ||||
RemoveWatchOnly(script); | RemoveWatchOnly(script); | ||||
} | } | ||||
if (IsCrypted()) { | if (IsCrypted()) { | ||||
return true; | return true; | ||||
} | } | ||||
return CWalletDB(*dbw).WriteKey(pubkey, secret.GetPrivKey(), | return walletdb.WriteKey(pubkey, secret.GetPrivKey(), | ||||
mapKeyMetadata[pubkey.GetID()]); | mapKeyMetadata[pubkey.GetID()]); | ||||
} | } | ||||
bool CWallet::AddKeyPubKey(const CKey &secret, const CPubKey &pubkey) { | |||||
CWalletDB walletdb(*dbw); | |||||
return CWallet::AddKeyPubKeyWithDB(walletdb, secret, pubkey); | |||||
} | |||||
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, | bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, | ||||
const std::vector<uint8_t> &vchCryptedSecret) { | const std::vector<uint8_t> &vchCryptedSecret) { | ||||
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) { | if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) { | ||||
return false; | return false; | ||||
} | } | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
if (pwalletdbEncryption) { | if (pwalletdbEncryption) { | ||||
▲ Show 20 Lines • Show All 3,043 Lines • ▼ Show 20 Lines | for (int64_t i = missingInternal + missingExternal; i--;) { | ||||
if (!setInternalKeyPool.empty()) { | if (!setInternalKeyPool.empty()) { | ||||
nEnd = *(setInternalKeyPool.rbegin()) + 1; | nEnd = *(setInternalKeyPool.rbegin()) + 1; | ||||
} | } | ||||
if (!setExternalKeyPool.empty()) { | if (!setExternalKeyPool.empty()) { | ||||
nEnd = std::max(nEnd, *(setExternalKeyPool.rbegin()) + 1); | nEnd = std::max(nEnd, *(setExternalKeyPool.rbegin()) + 1); | ||||
} | } | ||||
if (!walletdb.WritePool(nEnd, | if (!walletdb.WritePool( | ||||
CKeyPool(GenerateNewKey(internal), internal))) { | nEnd, CKeyPool(GenerateNewKey(walletdb, internal), internal))) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": writing generated key failed"); | ": writing generated key failed"); | ||||
} | } | ||||
if (internal) { | if (internal) { | ||||
setInternalKeyPool.insert(nEnd); | setInternalKeyPool.insert(nEnd); | ||||
} else { | } else { | ||||
setExternalKeyPool.insert(nEnd); | setExternalKeyPool.insert(nEnd); | ||||
} | } | ||||
} | |||||
if (missingInternal + missingExternal > 0) { | |||||
LogPrintf( | LogPrintf( | ||||
"keypool added key %d, size=%u (%u internal), new key is %s\n", | "keypool added %d keys (%d internal), size=%u (%u internal)\n", | ||||
nEnd, setInternalKeyPool.size() + setExternalKeyPool.size(), | missingInternal + missingExternal, missingInternal, | ||||
setInternalKeyPool.size(), internal ? "internal" : "external"); | setInternalKeyPool.size() + setExternalKeyPool.size(), | ||||
setInternalKeyPool.size()); | |||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
void CWallet::ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool, | void CWallet::ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool, | ||||
bool fRequestedInternal) { | bool fRequestedInternal) { | ||||
nIndex = -1; | nIndex = -1; | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | // Return to key pool | ||||
setExternalKeyPool.insert(nIndex); | setExternalKeyPool.insert(nIndex); | ||||
} | } | ||||
} | } | ||||
LogPrintf("keypool return %d\n", nIndex); | LogPrintf("keypool return %d\n", nIndex); | ||||
} | } | ||||
bool CWallet::GetKeyFromPool(CPubKey &result, bool internal) { | bool CWallet::GetKeyFromPool(CPubKey &result, bool internal) { | ||||
int64_t nIndex = 0; | |||||
CKeyPool keypool; | CKeyPool keypool; | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
int64_t nIndex = 0; | |||||
ReserveKeyFromKeyPool(nIndex, keypool, internal); | ReserveKeyFromKeyPool(nIndex, keypool, internal); | ||||
if (nIndex == -1) { | if (nIndex == -1) { | ||||
if (IsLocked()) { | if (IsLocked()) { | ||||
return false; | return false; | ||||
} | } | ||||
result = GenerateNewKey(internal); | CWalletDB walletdb(*dbw); | ||||
result = GenerateNewKey(walletdb, internal); | |||||
return true; | return true; | ||||
} | } | ||||
KeepKey(nIndex); | KeepKey(nIndex); | ||||
result = keypool.vchPubKey; | result = keypool.vchPubKey; | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,119 Lines • Show Last 20 Lines |