Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/walletdb.cpp
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Copyright (c) 2017-2020 The Bitcoin developers | // Copyright (c) 2017-2020 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <wallet/walletdb.h> | #include <wallet/walletdb.h> | ||||
#include <chainparams.h> | #include <chainparams.h> | ||||
#include <fs.h> | #include <fs.h> | ||||
#include <key_io.h> | #include <key_io.h> | ||||
#include <protocol.h> | #include <protocol.h> | ||||
#include <serialize.h> | #include <serialize.h> | ||||
#include <sync.h> | #include <sync.h> | ||||
#include <util/bip32.h> | |||||
#include <util/system.h> | #include <util/system.h> | ||||
#include <util/time.h> | #include <util/time.h> | ||||
#include <wallet/wallet.h> | #include <wallet/wallet.h> | ||||
#include <atomic> | #include <atomic> | ||||
namespace DBKeys { | namespace DBKeys { | ||||
const std::string ACENTRY{"acentry"}; | const std::string ACENTRY{"acentry"}; | ||||
▲ Show 20 Lines • Show All 258 Lines • ▼ Show 20 Lines | public: | ||||
std::vector<TxId> vWalletUpgrade; | std::vector<TxId> vWalletUpgrade; | ||||
std::map<OutputType, uint256> m_active_external_spks; | std::map<OutputType, uint256> m_active_external_spks; | ||||
std::map<OutputType, uint256> m_active_internal_spks; | std::map<OutputType, uint256> m_active_internal_spks; | ||||
std::map<uint256, DescriptorCache> m_descriptor_caches; | std::map<uint256, DescriptorCache> m_descriptor_caches; | ||||
std::map<std::pair<uint256, CKeyID>, CKey> m_descriptor_keys; | std::map<std::pair<uint256, CKeyID>, CKey> m_descriptor_keys; | ||||
std::map<std::pair<uint256, CKeyID>, | std::map<std::pair<uint256, CKeyID>, | ||||
std::pair<CPubKey, std::vector<uint8_t>>> | std::pair<CPubKey, std::vector<uint8_t>>> | ||||
m_descriptor_crypt_keys; | m_descriptor_crypt_keys; | ||||
std::map<uint160, CHDChain> m_hd_chains; | |||||
CWalletScanState() {} | CWalletScanState() {} | ||||
}; | }; | ||||
static bool ReadKeyValue(CWallet *pwallet, CDataStream &ssKey, | static bool ReadKeyValue(CWallet *pwallet, CDataStream &ssKey, | ||||
CDataStream &ssValue, CWalletScanState &wss, | CDataStream &ssValue, CWalletScanState &wss, | ||||
std::string &strType, std::string &strErr) | std::string &strType, std::string &strErr) | ||||
EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) { | EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) { | ||||
▲ Show 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | try { | ||||
} else if (strType == DBKeys::KEYMETA) { | } else if (strType == DBKeys::KEYMETA) { | ||||
CPubKey vchPubKey; | CPubKey vchPubKey; | ||||
ssKey >> vchPubKey; | ssKey >> vchPubKey; | ||||
CKeyMetadata keyMeta; | CKeyMetadata keyMeta; | ||||
ssValue >> keyMeta; | ssValue >> keyMeta; | ||||
wss.nKeyMeta++; | wss.nKeyMeta++; | ||||
pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyMetadata( | pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyMetadata( | ||||
vchPubKey.GetID(), keyMeta); | vchPubKey.GetID(), keyMeta); | ||||
// Extract some CHDChain info from this metadata if it has any | |||||
if (keyMeta.nVersion >= CKeyMetadata::VERSION_WITH_HDDATA && | |||||
!keyMeta.hd_seed_id.IsNull() && keyMeta.hdKeypath.size() > 0) { | |||||
// Get the path from the key origin or from the path string | |||||
// Not applicable when path is "s" as that indicates a seed | |||||
bool internal = false; | |||||
uint32_t index = 0; | |||||
if (keyMeta.hdKeypath != "s") { | |||||
std::vector<uint32_t> path; | |||||
if (keyMeta.has_key_origin) { | |||||
// We have a key origin, so pull it from its path vector | |||||
path = keyMeta.key_origin.path; | |||||
} else { | |||||
// No key origin, have to parse the string | |||||
if (!ParseHDKeypath(keyMeta.hdKeypath, path)) { | |||||
strErr = "Error reading wallet database: keymeta " | |||||
"with invalid HD keypath"; | |||||
return false; | |||||
} | |||||
} | |||||
// Extract the index and internal from the path | |||||
// Path string is m/0'/k'/i' | |||||
// Path vector is [0', k', i'] (but as ints OR'd with the | |||||
// hardened bit k == 0 for external, 1 for internal. i is | |||||
// the index | |||||
if (path.size() != 3) { | |||||
strErr = "Error reading wallet database: keymeta found " | |||||
"with unexpected path"; | |||||
return false; | |||||
} | |||||
if (path[0] != 0x80000000) { | |||||
strErr = strprintf( | |||||
"Unexpected path index of 0x%08x (expected " | |||||
"0x80000000) for the element at index 0", | |||||
path[0]); | |||||
return false; | |||||
} | |||||
if (path[1] != 0x80000000 && path[1] != (1 | 0x80000000)) { | |||||
strErr = | |||||
strprintf("Unexpected path index of 0x%08x " | |||||
"(expected 0x80000000 or 0x80000001) for " | |||||
"the element at index 1", | |||||
path[1]); | |||||
return false; | |||||
} | |||||
if ((path[2] & 0x80000000) == 0) { | |||||
strErr = strprintf( | |||||
"Unexpected path index of 0x%08x (expected to be " | |||||
"greater than or equal to 0x80000000)", | |||||
path[2]); | |||||
return false; | |||||
} | |||||
internal = path[1] == (1 | 0x80000000); | |||||
index = path[2] & ~0x80000000; | |||||
} | |||||
// Insert a new CHDChain, or get the one that already exists | |||||
auto ins = | |||||
wss.m_hd_chains.emplace(keyMeta.hd_seed_id, CHDChain()); | |||||
CHDChain &chain = ins.first->second; | |||||
if (ins.second) { | |||||
// For new chains, we want to default to VERSION_HD_BASE | |||||
// until we see an internal | |||||
chain.nVersion = CHDChain::VERSION_HD_BASE; | |||||
chain.seed_id = keyMeta.hd_seed_id; | |||||
} | |||||
if (internal) { | |||||
chain.nVersion = CHDChain::VERSION_HD_CHAIN_SPLIT; | |||||
chain.nInternalChainCounter = | |||||
std::max(chain.nInternalChainCounter, index); | |||||
} else { | |||||
chain.nExternalChainCounter = | |||||
std::max(chain.nExternalChainCounter, index); | |||||
} | |||||
} | |||||
} else if (strType == DBKeys::WATCHMETA) { | } else if (strType == DBKeys::WATCHMETA) { | ||||
CScript script; | CScript script; | ||||
ssKey >> script; | ssKey >> script; | ||||
CKeyMetadata keyMeta; | CKeyMetadata keyMeta; | ||||
ssValue >> keyMeta; | ssValue >> keyMeta; | ||||
wss.nKeyMeta++; | wss.nKeyMeta++; | ||||
pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadScriptMetadata( | pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadScriptMetadata( | ||||
CScriptID(script), keyMeta); | CScriptID(script), keyMeta); | ||||
▲ Show 20 Lines • Show All 350 Lines • ▼ Show 20 Lines | DBErrors WalletBatch::LoadWallet(CWallet *pwallet) { | ||||
// This operation is not atomic, but if it fails, updated entries are still | // This operation is not atomic, but if it fails, updated entries are still | ||||
// backwards compatible with older software | // backwards compatible with older software | ||||
try { | try { | ||||
pwallet->UpgradeKeyMetadata(); | pwallet->UpgradeKeyMetadata(); | ||||
} catch (...) { | } catch (...) { | ||||
result = DBErrors::CORRUPT; | result = DBErrors::CORRUPT; | ||||
} | } | ||||
// Set the inactive chain | |||||
if (wss.m_hd_chains.size() > 0) { | |||||
LegacyScriptPubKeyMan *legacy_spkm = | |||||
pwallet->GetLegacyScriptPubKeyMan(); | |||||
if (!legacy_spkm) { | |||||
pwallet->WalletLogPrintf( | |||||
"Inactive HD Chains found but no Legacy ScriptPubKeyMan\n"); | |||||
return DBErrors::CORRUPT; | |||||
} | |||||
for (const auto &chain_pair : wss.m_hd_chains) { | |||||
if (chain_pair.first != | |||||
pwallet->GetLegacyScriptPubKeyMan()->GetHDChain().seed_id) { | |||||
pwallet->GetLegacyScriptPubKeyMan()->AddInactiveHDChain( | |||||
chain_pair.second); | |||||
} | |||||
} | |||||
} | |||||
return result; | return result; | ||||
} | } | ||||
DBErrors WalletBatch::FindWalletTx(std::vector<TxId> &txIds, | DBErrors WalletBatch::FindWalletTx(std::vector<TxId> &txIds, | ||||
std::list<CWalletTx> &vWtx) { | std::list<CWalletTx> &vWtx) { | ||||
DBErrors result = DBErrors::LOAD_OK; | DBErrors result = DBErrors::LOAD_OK; | ||||
try { | try { | ||||
▲ Show 20 Lines • Show All 179 Lines • Show Last 20 Lines |