31 const std::string
FLAGS{
"flags"};
34 const std::string
KEY{
"key"};
37 const std::string
NAME{
"name"};
40 const std::string
POOL{
"pool"};
43 const std::string
TX{
"tx"};
58 const std::string &strName) {
79 const std::string &strPurpose) {
101 return EraseIC(std::make_pair(
DBKeys::TX, hash));
106 const bool overwrite) {
107 return WriteIC(std::make_pair(
DBKeys::KEYMETA, pubkey), meta, overwrite);
112 if (!WriteKeyMetadata(keyMeta, vchPubKey,
false)) {
117 std::vector<uint8_t> vchKey;
118 vchKey.reserve(vchPubKey.
size() + vchPrivKey.size());
119 vchKey.insert(vchKey.end(), vchPubKey.
begin(), vchPubKey.
end());
120 vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
124 std::make_pair(vchPrivKey,
Hash(vchKey.begin(), vchKey.end())),
false);
128 const std::vector<uint8_t> &vchCryptedSecret,
130 if (!WriteKeyMetadata(keyMeta, vchPubKey,
true)) {
135 vchCryptedSecret,
false)) {
149 return WriteIC(std::make_pair(
DBKeys::CSCRIPT, hash), redeemScript,
false);
186 return m_batch.Read(std::make_pair(
DBKeys::POOL, nPool), keypool);
190 return WriteIC(std::make_pair(
DBKeys::POOL, nPool), keypool);
205 return WriteIC(make_pair(key, type),
id);
212 std::vector<uint8_t> key;
213 key.reserve(pubkey.
size() + privkey.size());
214 key.insert(key.end(), pubkey.
begin(), pubkey.
end());
215 key.insert(key.end(), privkey.begin(), privkey.end());
218 std::make_pair(desc_id, pubkey)),
219 std::make_pair(privkey,
Hash(key.begin(), key.end())),
225 const std::vector<uint8_t> &secret) {
227 std::make_pair(desc_id, pubkey)),
232 std::make_pair(desc_id, pubkey)));
243 uint32_t key_exp_index,
244 uint32_t der_index) {
246 xpub.
Encode(ser_xpub.data());
249 std::make_pair(key_exp_index, der_index)),
255 uint32_t key_exp_index) {
257 xpub.
Encode(ser_xpub.data());
266 unsigned int nKeys{0};
267 unsigned int nCKeys{0};
268 unsigned int nWatchKeys{0};
269 unsigned int nKeyMeta{0};
270 unsigned int m_unknown_records{0};
271 bool fIsEncrypted{
false};
272 bool fAnyUnordered{
false};
278 std::map<std::pair<uint256, CKeyID>,
279 std::pair<CPubKey, std::vector<uint8_t>>>
287 std::string &strType, std::string &strErr)
295 std::string strAddress;
301 pwallet->GetChainParams())]
304 std::string strAddress;
308 strAddress, pwallet->GetChainParams())]
315 if (wtx.GetId() != txid) {
320 if (31404 <= wtx.fTimeReceivedIsTxTime &&
321 wtx.fTimeReceivedIsTxTime <= 31703) {
322 if (!ssValue.empty()) {
325 std::string unused_string;
326 ssValue >> fTmp >> fUnused >> unused_string;
327 strErr =
strprintf(
"LoadWallet() upgrading tx ver=%d %d %s",
328 wtx.fTimeReceivedIsTxTime, fTmp,
330 wtx.fTimeReceivedIsTxTime = fTmp;
333 strprintf(
"LoadWallet() repairing tx ver=%d %s",
334 wtx.fTimeReceivedIsTxTime, txid.ToString());
335 wtx.fTimeReceivedIsTxTime = 0;
337 wss.vWalletUpgrade.push_back(txid);
340 if (wtx.nOrderPos == -1) {
341 wss.fAnyUnordered =
true;
344 pwallet->LoadToWallet(wtx);
352 pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadWatchOnly(
358 if (!vchPubKey.IsValid()) {
359 strErr =
"Error reading wallet database: CPubKey corrupt";
380 bool fSkipCheck =
false;
384 std::vector<uint8_t> vchKey;
385 vchKey.reserve(vchPubKey.size() + pkey.size());
386 vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
387 vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
389 if (
Hash(vchKey.begin(), vchKey.end()) != hash) {
390 strErr =
"Error reading wallet database: CPubKey/CPrivKey " 398 if (!key.
Load(pkey, vchPubKey, fSkipCheck)) {
399 strErr =
"Error reading wallet database: CPrivKey corrupt";
402 if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKey(
404 strErr =
"Error reading wallet database: " 405 "LegacyScriptPubKeyMan::LoadKey failed";
414 ssValue >> kMasterKey;
415 if (pwallet->mapMasterKeys.count(nID) != 0) {
417 "Error reading wallet database: duplicate CMasterKey id %u",
421 pwallet->mapMasterKeys[nID] = kMasterKey;
422 if (pwallet->nMasterKeyMaxID < nID) {
423 pwallet->nMasterKeyMaxID = nID;
428 if (!vchPubKey.IsValid()) {
429 strErr =
"Error reading wallet database: CPubKey corrupt";
432 std::vector<uint8_t> vchPrivKey;
433 ssValue >> vchPrivKey;
436 if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCryptedKey(
437 vchPubKey, vchPrivKey)) {
438 strErr =
"Error reading wallet database: " 439 "LegacyScriptPubKeyMan::LoadCryptedKey failed";
442 wss.fIsEncrypted =
true;
449 pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyMetadata(
450 vchPubKey.GetID(), keyMeta);
457 pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadScriptMetadata(
464 ssValue >> vchPubKey;
465 if (!vchPubKey.IsValid()) {
466 strErr =
"Error reading wallet database: Default Key corrupt";
475 pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyPool(nIndex,
482 if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCScript(
484 strErr =
"Error reading wallet database: " 485 "LegacyScriptPubKeyMan::LoadCScript failed";
489 ssValue >> pwallet->nOrderPosNext;
491 std::string strAddress, strKey, strValue;
495 pwallet->LoadDestData(
501 pwallet->GetOrCreateLegacyScriptPubKeyMan()->SetHDChain(chain,
506 if (!pwallet->SetWalletFlags(flags,
true)) {
507 strErr =
"Error reading wallet database: Unknown non-tolerable " 508 "wallet flags found";
512 strErr =
"Found unsupported 'wkey' record, try loading with " 523 auto &spk_mans =
internal ? wss.m_active_internal_spks
524 : wss.m_active_external_spks;
525 if (spk_mans.count(static_cast<OutputType>(type)) > 0) {
527 "Multiple ScriptPubKeyMans specified for a single type";
536 if (wss.m_descriptor_caches.count(
id) == 0) {
539 pwallet->LoadDescriptorScriptPubKeyMan(
id, desc);
543 uint32_t key_exp_index;
546 ssKey >> key_exp_index;
558 xpub.
Decode(ser_xpub.data());
559 if (wss.m_descriptor_caches.count(desc_id)) {
563 wss.m_descriptor_caches[desc_id].CacheParentExtPubKey(
564 key_exp_index, xpub);
566 wss.m_descriptor_caches[desc_id].CacheDerivedExtPubKey(
567 key_exp_index, der_index, xpub);
574 if (!pubkey.IsValid()) {
575 strErr =
"Error reading wallet database: CPubKey corrupt";
587 std::vector<uint8_t> to_hash;
588 to_hash.reserve(pubkey.size() + pkey.size());
589 to_hash.insert(to_hash.end(), pubkey.begin(), pubkey.end());
590 to_hash.insert(to_hash.end(), pkey.begin(), pkey.end());
592 if (
Hash(to_hash.begin(), to_hash.end()) != hash) {
594 "Error reading wallet database: CPubKey/CPrivKey corrupt";
598 if (!key.
Load(pkey, pubkey,
true)) {
599 strErr =
"Error reading wallet database: CPrivKey corrupt";
602 wss.m_descriptor_keys.insert(
603 std::make_pair(std::make_pair(desc_id, pubkey.GetID()), key));
609 if (!pubkey.IsValid()) {
610 strErr =
"Error reading wallet database: CPubKey corrupt";
613 std::vector<uint8_t> privkey;
617 wss.m_descriptor_crypt_keys.insert(
618 std::make_pair(std::make_pair(desc_id, pubkey.GetID()),
619 std::make_pair(pubkey, privkey)));
620 wss.fIsEncrypted =
true;
626 wss.m_unknown_records++;
628 }
catch (
const std::exception &e) {
629 if (strErr.empty()) {
634 if (strErr.empty()) {
635 strErr =
"Caught unknown exception in ReadKeyValue";
643 std::string &strType, std::string &strErr) {
646 return ReadKeyValue(pwallet, ssKey, ssValue, dummy_wss, strType, strErr);
656 bool fNoncriticalErrors =
false;
670 Dbc *pcursor = m_batch.GetCursor();
680 int ret = m_batch.ReadAtCursor(pcursor, ssKey, ssValue);
681 if (ret == DB_NOTFOUND) {
687 "Error reading next record from wallet database\n");
692 std::string strType, strErr;
693 if (!
ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr)) {
706 fNoncriticalErrors =
true;
713 if (!strErr.empty()) {
725 spk_man_pair.second, spk_man_pair.first,
false,
730 spk_man_pair.second, spk_man_pair.first,
true,
739 ->SetCache(desc_cache_pair.second);
746 ->AddKey(desc_key_pair.first.second, desc_key_pair.second);
751 ->AddCryptedKey(desc_key_pair.first.second,
752 desc_key_pair.second.first,
753 desc_key_pair.second.second);
773 wallet_version > 0 ? wallet_version : last_client);
776 "metadata, %u total. Unknown wallet records: %u\n",
785 LOCK(spk_man->cs_KeyStore);
786 spk_man->UpdateTimeFirstKey(1);
791 WriteTx(pwallet->mapWallet.at(txid));
795 if (wss.
fIsEncrypted && (last_client == 40000 || last_client == 50000)) {
821 std::vector<CWalletTx> &vWtx) {
833 Dbc *pcursor = m_batch.GetCursor();
835 LogPrintf(
"Error getting wallet database cursor\n");
843 int ret = m_batch.ReadAtCursor(pcursor, ssKey, ssValue);
844 if (ret == DB_NOTFOUND) {
849 LogPrintf(
"Error reading next record from wallet database\n");
862 txIds.push_back(txid);
875 std::vector<TxId> &txIdsOut) {
877 std::vector<TxId> txIds;
878 std::vector<CWalletTx> vWtx;
879 DBErrors err = FindWalletTx(txIds, vWtx);
884 std::sort(txIds.begin(), txIds.end());
885 std::sort(txIdsIn.begin(), txIdsIn.end());
888 bool delerror =
false;
889 std::vector<TxId>::iterator it = txIdsIn.begin();
890 for (
const TxId &txid : txIds) {
891 while (it < txIdsIn.end() && (*it) < txid) {
894 if (it == txIdsIn.end()) {
899 if (!EraseTx(txid)) {
901 "Transaction was found for deletion but returned " 902 "database error: %s\n",
906 txIdsOut.push_back(txid);
918 std::vector<TxId> txIds;
919 DBErrors err = FindWalletTx(txIds, vWtx);
925 for (
const TxId &txid : txIds) {
926 if (!EraseTx(txid)) {
935 static std::atomic<bool> fOneThread;
936 if (fOneThread.exchange(
true)) {
940 for (
const std::shared_ptr<CWallet> &pwallet :
GetWallets()) {
962 const std::string &key,
963 const std::string &value) {
975 const std::string &key) {
979 return EraseIC(std::make_pair(
993 return m_batch.TxnBegin();
997 return m_batch.TxnCommit();
1001 return m_batch.TxnAbort();
bool TxnCommit()
Commit current transaction.
void SetActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal, bool memonly=false)
Sets the active ScriptPubKeyMan for the specified type and internal.
bool IsLegacy() const
Determine if we are a legacy wallet.
bool ReadBestBlock(CBlockLocator &locator)
std::map< OutputType, uint256 > m_active_internal_spks
#define LogPrint(category,...)
std::vector< std::shared_ptr< CWallet > > GetWallets()
Describes a place in the block chain to another node such that if the other node doesn't have the sam...
void UpgradeKeyMetadata() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo.
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
Set a boolean argument if it doesn't already have a value.
const std::string SETTINGS
const std::string WALLETDESCRIPTORCKEY
bool WriteDescriptorDerivedCache(const CExtPubKey &xpub, const uint256 &desc_id, uint32_t key_exp_index, uint32_t der_index)
std::map< OutputType, uint256 > m_active_external_spks
const std::string CRYPTED_KEY
const std::string DEFAULTKEY
bool WriteMinVersion(int nVersion)
static bool ReadKeyValue(CWallet *pwallet, CDataStream &ssKey, CDataStream &ssValue, CWalletScanState &wss, std::string &strType, std::string &strErr) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
bool WriteHDChain(const CHDChain &chain)
write the hdchain model (external chain child index counter)
bool WriteDescriptor(const uint256 &desc_id, const WalletDescriptor &descriptor)
Private key encryption is done based on a CMasterKey, which holds a salt and random encryption key...
bool EraseDestData(const CTxDestination &address, const std::string &key)
Erase destination data tuple from wallet database.
static CTransactionRef MakeTransactionRef()
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
bool WriteWatchOnly(const CScript &script, const CKeyMetadata &keymeta)
const std::string KEYMETA
std::vector< BlockHash > vHave
An instance of this class represents one database.
static void LogPrintf(const char *fmt, const Args &... args)
unsigned int m_unknown_records
std::map< std::pair< uint256, CKeyID >, std::pair< CPubKey, std::vector< uint8_t > > > m_descriptor_crypt_keys
bool TxnBegin()
Begin a new transaction.
Double ended buffer combining vector and stream-like interfaces.
DBErrors ZapWalletTx(std::vector< CWalletTx > &vWtx)
bool WriteTx(const CWalletTx &wtx)
bool WriteName(const CTxDestination &address, const std::string &strName)
DBErrors LoadWallet(CWallet *pwallet)
bool WriteDescriptorParentCache(const CExtPubKey &xpub, const uint256 &desc_id, uint32_t key_exp_index)
DBErrors
Error statuses for the wallet database.
DBErrors FindWalletTx(std::vector< TxId > &txIds, std::vector< CWalletTx > &vWtx)
const std::string ORDERPOSNEXT
bool WriteWalletFlags(const uint64_t flags)
const std::string VERSION
const uint8_t * begin() const
const std::string MASTER_KEY
std::vector< uint8_t, secure_allocator< uint8_t > > CPrivKey
secure_allocator is defined in allocators.h CPrivKey is a serialized private key, with all parameters...
bool EraseWatchOnly(const CScript &script)
void Decode(const uint8_t code[BIP32_EXTKEY_SIZE])
bool WriteBestBlock(const CBlockLocator &locator)
bool TxnAbort()
Abort current transaction.
const std::string OLD_KEY
DBErrors ReorderTransactions()
bool IsBDBWalletLoaded(const fs::path &wallet_path)
Return whether a BDB wallet database is currently loaded.
const std::string HDCHAIN
static bool IsKeyType(const std::string &strType)
const std::string WALLETDESCRIPTOR
bool WriteCScript(const uint160 &hash, const CScript &redeemScript)
void WalletLogPrintf(std::string fmt, Params... parameters) const
Prepends the wallet name in logging output to ease debugging in multi-wallet use cases.
const std::string ACTIVEINTERNALSPK
bool WritePurpose(const CTxDestination &address, const std::string &purpose)
An encapsulated public key.
const std::string WATCHMETA
bool WriteMasterKey(unsigned int nID, const CMasterKey &kMasterKey)
bool EraseName(const CTxDestination &address)
void MaybeCompactWalletDB()
Compacts BDB state so that wallet.dat is self-contained (if there are changes)
const std::string WALLETDESCRIPTORKEY
const std::string DESTDATA
LegacyScriptPubKeyMan * GetOrCreateLegacyScriptPubKeyMan()
uint256 Hash(const T1 pbegin, const T1 pend)
Compute the 256-bit hash of an object.
bool WriteOrderPosNext(int64_t nOrderPosNext)
ScriptPubKeyMan * GetScriptPubKeyMan(const OutputType &type, bool internal) const
Get the ScriptPubKeyMan for the given OutputType and internal/external chain.
unsigned int size() const
Simple read-only vector-like interface to the pubkey data.
CTxDestination DecodeDestination(const std::string &addr, const CChainParams ¶ms)
Descriptor with some wallet metadata.
bool WriteCryptedKey(const CPubKey &vchPubKey, const std::vector< uint8_t > &vchCryptedSecret, const CKeyMetadata &keyMeta)
A transaction with a bunch of additional info that only the owner cares about.
bool WriteKeyMetadata(const CKeyMetadata &meta, const CPubKey &pubkey, const bool overwrite)
std::map< uint256, DescriptorCache > m_descriptor_caches
const std::string WALLETDESCRIPTORCACHE
bool ErasePool(int64_t nPool)
bool WritePool(int64_t nPool, const CKeyPool &keypool)
bool ErasePurpose(const CTxDestination &address)
bool WriteDestData(const CTxDestination &address, const std::string &key, const std::string &value)
Write destination data key,value tuple to database.
bool WriteCryptedDescriptorKey(const uint256 &desc_id, const CPubKey &pubkey, const std::vector< uint8_t > &secret)
#define EXCLUSIVE_LOCKS_REQUIRED(...)
const std::string ACENTRY
int64_t nLastWalletUpdate
static constexpr int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
std::map< std::pair< uint256, CKeyID >, CKey > m_descriptor_keys
bool WriteActiveScriptPubKeyMan(uint8_t type, const uint256 &id, bool internal)
int GetVersion() const
get the current wallet format (the oldest client version guaranteed to understand this wallet) ...
const CChainParams & Params()
Return the currently selected parameters.
Cache for single descriptor's derived extended pubkeys.
Serialized script, used inside transaction inputs and outputs.
A TxId is the identifier of a transaction.
unsigned int nLastFlushed
const std::string MINVERSION
const unsigned int BIP32_EXTKEY_SIZE
const std::string ACTIVEEXTERNALSPK
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
std::atomic< unsigned int > nUpdateCounter
bool ReadPool(int64_t nPool, CKeyPool &keypool)
A reference to a CScript: the Hash160 of its serialization (see script.h)
bool LoadMinVersion(int nVersion) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool WriteKey(const CPubKey &vchPubKey, const CPrivKey &vchPrivKey, const CKeyMetadata &keyMeta)
An encapsulated secp256k1 private key.
const uint8_t * end() const
DBErrors ZapSelectTx(std::vector< TxId > &txIdsIn, std::vector< TxId > &txIdsOut)
const std::string BESTBLOCK
const std::string CSCRIPT
std::vector< TxId > vWalletUpgrade
bool EraseTx(uint256 hash)
int64_t GetTime()
Return system time (or mocked time, if set)
void Encode(uint8_t code[BIP32_EXTKEY_SIZE]) const
std::string EncodeLegacyAddr(const CTxDestination &dest, const CChainParams ¶ms)
const std::string BESTBLOCK_NOMERKLE
boost::variant< CNoDestination, PKHash, ScriptHash > CTxDestination
A txout script template with a specific destination.
bool IsWalletLoaded(const fs::path &wallet_path)
Return whether a wallet database is currently loaded.
bool Load(const CPrivKey &privkey, const CPubKey &vchPubKey, bool fSkipCheck)
Load private key and check that public key matches.
bool WriteDescriptorKey(const uint256 &desc_id, const CPubKey &pubkey, const CPrivKey &privkey)
A key from a CWallet's keypool.
const std::string PURPOSE