Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 200 Lines • ▼ Show 20 Lines | void CWallet::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata &metadata, | ||||
// 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) | ||||
CExtKey chainChildKey; | CExtKey chainChildKey; | ||||
// key at m/0'/0'/<n>' | // key at m/0'/0'/<n>' | ||||
CExtKey childKey; | CExtKey childKey; | ||||
// try to get the master key | // try to get the master key | ||||
if (!GetKey(hdChain.masterKeyID, key)) { | if (!GetKey(hdChain.seed_id, key)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": Master key not found"); | ": Master key not found"); | ||||
} | } | ||||
masterKey.SetMaster(key.begin(), key.size()); | masterKey.SetSeed(key.begin(), key.size()); | ||||
// derive m/0' | // derive m/0' | ||||
// use hardened derivation (child keys >= 0x80000000 are hardened after | // use hardened derivation (child keys >= 0x80000000 are hardened after | ||||
// bip32) | // bip32) | ||||
masterKey.Derive(accountKey, BIP32_HARDENED_KEY_LIMIT); | masterKey.Derive(accountKey, BIP32_HARDENED_KEY_LIMIT); | ||||
// derive m/0'/0' (external chain) OR m/0'/1' (internal chain) | // derive m/0'/0' (external chain) OR m/0'/1' (internal chain) | ||||
assert(internal ? CanSupportFeature(FEATURE_HD_SPLIT) : true); | assert(internal ? CanSupportFeature(FEATURE_HD_SPLIT) : true); | ||||
Show All 18 Lines | do { | ||||
BIP32_HARDENED_KEY_LIMIT); | BIP32_HARDENED_KEY_LIMIT); | ||||
metadata.hdKeypath = "m/0'/0'/" + | metadata.hdKeypath = "m/0'/0'/" + | ||||
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.hd_seed_id = hdChain.seed_id; | ||||
// update the chain model in the database | // update the chain model in the database | ||||
if (!batch.WriteHDChain(hdChain)) { | if (!batch.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::AddKeyPubKeyWithDB(WalletBatch &batch, const CKey &secret, | bool CWallet::AddKeyPubKeyWithDB(WalletBatch &batch, const CKey &secret, | ||||
▲ Show 20 Lines • Show All 518 Lines • ▼ Show 20 Lines | if (!crypter.Encrypt(_vMasterKey, kMasterKey.vchCryptedKey)) { | ||||
delete encrypted_batch; | delete encrypted_batch; | ||||
encrypted_batch = nullptr; | encrypted_batch = nullptr; | ||||
Lock(); | Lock(); | ||||
Unlock(strWalletPassphrase); | Unlock(strWalletPassphrase); | ||||
// If we are using HD, replace the HD master key (seed) with a new one. | // If we are using HD, replace the HD master key (seed) with a new one. | ||||
if (IsHDEnabled()) { | if (IsHDEnabled()) { | ||||
SetHDMasterKey(GenerateNewHDMasterKey()); | SetHDSeed(GenerateNewSeed()); | ||||
} | } | ||||
NewKeyPool(); | NewKeyPool(); | ||||
Lock(); | Lock(); | ||||
// Need to completely rewrite the wallet file; if we don't, bdb might | // Need to completely rewrite the wallet file; if we don't, bdb might | ||||
// keep bits of the unencrypted private key in slack space in the | // keep bits of the unencrypted private key in slack space in the | ||||
// database file. | // database file. | ||||
▲ Show 20 Lines • Show All 741 Lines • ▼ Show 20 Lines | for (const CTxOut &txout : tx.vout) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": value out of range"); | ": value out of range"); | ||||
} | } | ||||
} | } | ||||
return nChange; | return nChange; | ||||
} | } | ||||
CPubKey CWallet::GenerateNewHDMasterKey() { | CPubKey CWallet::GenerateNewSeed() { | ||||
CKey key; | CKey key; | ||||
key.MakeNewKey(true); | key.MakeNewKey(true); | ||||
return DeriveNewMasterHDKey(key); | return DeriveNewSeed(key); | ||||
} | } | ||||
CPubKey CWallet::DeriveNewMasterHDKey(const CKey &key) { | CPubKey CWallet::DeriveNewSeed(const CKey &key) { | ||||
int64_t nCreationTime = GetTime(); | int64_t nCreationTime = GetTime(); | ||||
CKeyMetadata metadata(nCreationTime); | CKeyMetadata metadata(nCreationTime); | ||||
// Calculate the pubkey. | // Calculate the pubkey. | ||||
CPubKey pubkey = key.GetPubKey(); | CPubKey pubkey = key.GetPubKey(); | ||||
assert(key.VerifyPubKey(pubkey)); | assert(key.VerifyPubKey(pubkey)); | ||||
// Set the hd keypath to "m" -> Master, refers the masterkeyid to itself. | // Set the hd keypath to "m" -> Master, refers the masterkeyid to itself. | ||||
metadata.hdKeypath = "m"; | metadata.hdKeypath = "m"; | ||||
metadata.hdMasterKeyID = pubkey.GetID(); | metadata.hd_seed_id = pubkey.GetID(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
// mem store the metadata | // mem store the metadata | ||||
mapKeyMetadata[pubkey.GetID()] = metadata; | mapKeyMetadata[pubkey.GetID()] = metadata; | ||||
// Write the key&metadata to the database. | // Write the key&metadata to the database. | ||||
if (!AddKeyPubKey(key, pubkey)) { | if (!AddKeyPubKey(key, pubkey)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": AddKeyPubKey failed"); | ": AddKeyPubKey failed"); | ||||
} | } | ||||
return pubkey; | return pubkey; | ||||
} | } | ||||
void CWallet::SetHDMasterKey(const CPubKey &pubkey) { | void CWallet::SetHDSeed(const CPubKey &seed) { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
// Store the keyid (hash160) together with the child index counter in the | // Store the keyid (hash160) together with the child index counter in the | ||||
// database as a hdchain object. | // database as a hdchain object. | ||||
CHDChain newHdChain; | CHDChain newHdChain; | ||||
newHdChain.nVersion = CanSupportFeature(FEATURE_HD_SPLIT) | newHdChain.nVersion = CanSupportFeature(FEATURE_HD_SPLIT) | ||||
? CHDChain::VERSION_HD_CHAIN_SPLIT | ? CHDChain::VERSION_HD_CHAIN_SPLIT | ||||
: CHDChain::VERSION_HD_BASE; | : CHDChain::VERSION_HD_BASE; | ||||
newHdChain.masterKeyID = pubkey.GetID(); | newHdChain.seed_id = seed.GetID(); | ||||
SetHDChain(newHdChain, false); | SetHDChain(newHdChain, false); | ||||
} | } | ||||
void CWallet::SetHDChain(const CHDChain &chain, bool memonly) { | void CWallet::SetHDChain(const CHDChain &chain, bool memonly) { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
if (!memonly && !WalletBatch(*database).WriteHDChain(chain)) { | if (!memonly && !WalletBatch(*database).WriteHDChain(chain)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": writing chain failed"); | ": writing chain failed"); | ||||
} | } | ||||
hdChain = chain; | hdChain = chain; | ||||
} | } | ||||
bool CWallet::IsHDEnabled() const { | bool CWallet::IsHDEnabled() const { | ||||
return !hdChain.masterKeyID.IsNull(); | return !hdChain.seed_id.IsNull(); | ||||
} | } | ||||
int64_t CWalletTx::GetTxTime() const { | int64_t CWalletTx::GetTxTime() const { | ||||
int64_t n = nTimeSmart; | int64_t n = nTimeSmart; | ||||
return n ? n : nTimeReceived; | return n ? n : nTimeReceived; | ||||
} | } | ||||
// Helper for producing a max-sized low-S signature (eg 72 bytes) | // Helper for producing a max-sized low-S signature (eg 72 bytes) | ||||
▲ Show 20 Lines • Show All 2,832 Lines • ▼ Show 20 Lines | if (gArgs.GetBoolArg("-upgradewallet", false)) { | ||||
bool hd_upgrade = false; | bool hd_upgrade = false; | ||||
bool split_upgrade = false; | bool split_upgrade = false; | ||||
if (walletInstance->CanSupportFeature(FEATURE_HD) && | if (walletInstance->CanSupportFeature(FEATURE_HD) && | ||||
!walletInstance->IsHDEnabled()) { | !walletInstance->IsHDEnabled()) { | ||||
LogPrintf("Upgrading wallet to HD\n"); | LogPrintf("Upgrading wallet to HD\n"); | ||||
walletInstance->SetMinVersion(FEATURE_HD); | walletInstance->SetMinVersion(FEATURE_HD); | ||||
// generate a new master key | // generate a new master key | ||||
CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey(); | CPubKey masterPubKey = walletInstance->GenerateNewSeed(); | ||||
walletInstance->SetHDMasterKey(masterPubKey); | walletInstance->SetHDSeed(masterPubKey); | ||||
hd_upgrade = true; | hd_upgrade = true; | ||||
} | } | ||||
// Upgrade to HD chain split if necessary | // Upgrade to HD chain split if necessary | ||||
if (walletInstance->CanSupportFeature(FEATURE_HD_SPLIT)) { | if (walletInstance->CanSupportFeature(FEATURE_HD_SPLIT)) { | ||||
LogPrintf("Upgrading wallet to use HD chain split\n"); | LogPrintf("Upgrading wallet to use HD chain split\n"); | ||||
walletInstance->SetMinVersion(FEATURE_PRE_SPLIT_KEYPOOL); | walletInstance->SetMinVersion(FEATURE_PRE_SPLIT_KEYPOOL); | ||||
split_upgrade = FEATURE_HD_SPLIT > prev_version; | split_upgrade = FEATURE_HD_SPLIT > prev_version; | ||||
} | } | ||||
Show All 17 Lines | if (fFirstRun) { | ||||
InitError(strprintf(_("Error creating %s: You can't create non-HD " | InitError(strprintf(_("Error creating %s: You can't create non-HD " | ||||
"wallets with this version."), | "wallets with this version."), | ||||
walletFile)); | walletFile)); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
walletInstance->SetMinVersion(FEATURE_LATEST); | walletInstance->SetMinVersion(FEATURE_LATEST); | ||||
// Generate a new master key. | // Generate a new master key. | ||||
CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey(); | CPubKey masterPubKey = walletInstance->GenerateNewSeed(); | ||||
walletInstance->SetHDMasterKey(masterPubKey); | walletInstance->SetHDSeed(masterPubKey); | ||||
// Top up the keypool | // Top up the keypool | ||||
if (!walletInstance->TopUpKeyPool()) { | if (!walletInstance->TopUpKeyPool()) { | ||||
InitError(_("Unable to generate initial keys") += "\n"); | InitError(_("Unable to generate initial keys") += "\n"); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
walletInstance->ChainStateFlushed(chainActive.GetLocator()); | walletInstance->ChainStateFlushed(chainActive.GetLocator()); | ||||
▲ Show 20 Lines • Show All 363 Lines • Show Last 20 Lines |