@@ -301,11 +301,8 @@ bool WalletBatch::EraseLockedUTXO(const COutPoint& output)
301301class CWalletScanState {
302302public:
303303 unsigned int m_unknown_records{0 };
304- bool fAnyUnordered {false };
305- std::vector<uint256> vWalletUpgrade;
306304 std::map<OutputType, uint256> m_active_external_spks;
307305 std::map<OutputType, uint256> m_active_internal_spks;
308- bool tx_corrupt{false };
309306
310307 CWalletScanState () = default ;
311308};
@@ -473,51 +470,6 @@ ReadKeyValue(CWallet* pwallet, DataStream& ssKey, CDataStream& ssValue,
473470 if (strType == DBKeys::NAME) {
474471 } else if (strType == DBKeys::PURPOSE) {
475472 } else if (strType == DBKeys::TX) {
476- uint256 hash;
477- ssKey >> hash;
478- // LoadToWallet call below creates a new CWalletTx that fill_wtx
479- // callback fills with transaction metadata.
480- auto fill_wtx = [&](CWalletTx& wtx, bool new_tx) {
481- if (!new_tx) {
482- // There's some corruption here since the tx we just tried to load was already in the wallet.
483- // We don't consider this type of corruption critical, and can fix it by removing tx data and
484- // rescanning.
485- wss.tx_corrupt = true ;
486- return false ;
487- }
488- ssValue >> wtx;
489- if (wtx.GetHash () != hash)
490- return false ;
491-
492- // Undo serialize changes in 31600
493- if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703 )
494- {
495- if (!ssValue.empty ())
496- {
497- uint8_t fTmp ;
498- uint8_t fUnused ;
499- std::string unused_string;
500- ssValue >> fTmp >> fUnused >> unused_string;
501- strErr = strprintf (" LoadWallet() upgrading tx ver=%d %d %s" ,
502- wtx.fTimeReceivedIsTxTime , fTmp , hash.ToString ());
503- wtx.fTimeReceivedIsTxTime = fTmp ;
504- }
505- else
506- {
507- strErr = strprintf (" LoadWallet() repairing tx ver=%d %s" , wtx.fTimeReceivedIsTxTime , hash.ToString ());
508- wtx.fTimeReceivedIsTxTime = 0 ;
509- }
510- wss.vWalletUpgrade .push_back (hash);
511- }
512-
513- if (wtx.nOrderPos == -1 )
514- wss.fAnyUnordered = true ;
515-
516- return true ;
517- };
518- if (!pwallet->LoadToWallet (hash, fill_wtx)) {
519- return false ;
520- }
521473 } else if (strType == DBKeys::WATCHS) {
522474 } else if (strType == DBKeys::KEY) {
523475 } else if (strType == DBKeys::MASTER_KEY) {
@@ -537,7 +489,6 @@ ReadKeyValue(CWallet* pwallet, DataStream& ssKey, CDataStream& ssValue,
537489 } else if (strType == DBKeys::POOL) {
538490 } else if (strType == DBKeys::CSCRIPT) {
539491 } else if (strType == DBKeys::ORDERPOSNEXT) {
540- ssValue >> pwallet->nOrderPosNext ;
541492 } else if (strType == DBKeys::DESTDATA) {
542493 } else if (strType == DBKeys::HDCHAIN) {
543494 } else if (strType == DBKeys::OLD_KEY) {
@@ -562,11 +513,6 @@ ReadKeyValue(CWallet* pwallet, DataStream& ssKey, CDataStream& ssValue,
562513 } else if (strType == DBKeys::WALLETDESCRIPTORKEY) {
563514 } else if (strType == DBKeys::WALLETDESCRIPTORCKEY) {
564515 } else if (strType == DBKeys::LOCKED_UTXO) {
565- uint256 hash;
566- uint32_t n;
567- ssKey >> hash;
568- ssKey >> n;
569- pwallet->LockCoin (COutPoint (hash, n));
570516 } else if (strType != DBKeys::BESTBLOCK && strType != DBKeys::BESTBLOCK_NOMERKLE &&
571517 strType != DBKeys::MINVERSION && strType != DBKeys::ACENTRY &&
572518 strType != DBKeys::VERSION && strType != DBKeys::SETTINGS &&
@@ -1112,12 +1058,101 @@ static DBErrors LoadAddressBookRecords(CWallet* pwallet, DatabaseBatch& batch) E
11121058 return result;
11131059}
11141060
1061+ static DBErrors LoadTxRecords (CWallet* pwallet, DatabaseBatch& batch, std::vector<uint256>& upgraded_txs, bool & any_unordered) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
1062+ {
1063+ AssertLockHeld (pwallet->cs_wallet );
1064+ DBErrors result = DBErrors::LOAD_OK;
1065+
1066+ // Load tx record
1067+ any_unordered = false ;
1068+ LoadResult tx_res = LoadRecords (pwallet, batch, DBKeys::TX,
1069+ [&any_unordered, &upgraded_txs] (CWallet* pwallet, DataStream& key, CDataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED (pwallet->cs_wallet ) {
1070+ DBErrors result = DBErrors::LOAD_OK;
1071+ uint256 hash;
1072+ key >> hash;
1073+ // LoadToWallet call below creates a new CWalletTx that fill_wtx
1074+ // callback fills with transaction metadata.
1075+ auto fill_wtx = [&](CWalletTx& wtx, bool new_tx) {
1076+ if (!new_tx) {
1077+ // There's some corruption here since the tx we just tried to load was already in the wallet.
1078+ err = " Error: Corrupt transaction found. This can be fixed by removing transactions from wallet and rescanning." ;
1079+ result = DBErrors::CORRUPT;
1080+ return false ;
1081+ }
1082+ value >> wtx;
1083+ if (wtx.GetHash () != hash)
1084+ return false ;
1085+
1086+ // Undo serialize changes in 31600
1087+ if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703 )
1088+ {
1089+ if (!value.empty ())
1090+ {
1091+ uint8_t fTmp ;
1092+ uint8_t fUnused ;
1093+ std::string unused_string;
1094+ value >> fTmp >> fUnused >> unused_string;
1095+ pwallet->WalletLogPrintf (" LoadWallet() upgrading tx ver=%d %d %s\n " ,
1096+ wtx.fTimeReceivedIsTxTime , fTmp , hash.ToString ());
1097+ wtx.fTimeReceivedIsTxTime = fTmp ;
1098+ }
1099+ else
1100+ {
1101+ pwallet->WalletLogPrintf (" LoadWallet() repairing tx ver=%d %s\n " , wtx.fTimeReceivedIsTxTime , hash.ToString ());
1102+ wtx.fTimeReceivedIsTxTime = 0 ;
1103+ }
1104+ upgraded_txs.push_back (hash);
1105+ }
1106+
1107+ if (wtx.nOrderPos == -1 )
1108+ any_unordered = true ;
1109+
1110+ return true ;
1111+ };
1112+ if (!pwallet->LoadToWallet (hash, fill_wtx)) {
1113+ // Use std::max as fill_wtx may have already set result to CORRUPT
1114+ result = std::max (result, DBErrors::NEED_RESCAN);
1115+ }
1116+ return result;
1117+ });
1118+ result = std::max (result, tx_res.m_result );
1119+
1120+ // Load locked utxo record
1121+ LoadResult locked_utxo_res = LoadRecords (pwallet, batch, DBKeys::LOCKED_UTXO,
1122+ [] (CWallet* pwallet, DataStream& key, CDataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED (pwallet->cs_wallet ) {
1123+ uint256 hash;
1124+ uint32_t n;
1125+ key >> hash;
1126+ key >> n;
1127+ pwallet->LockCoin (COutPoint (hash, n));
1128+ return DBErrors::LOAD_OK;
1129+ });
1130+ result = std::max (result, locked_utxo_res.m_result );
1131+
1132+ // Load orderposnext record
1133+ // Note: There should only be one ORDERPOSNEXT record with nothing trailing the type
1134+ LoadResult order_pos_res = LoadRecords (pwallet, batch, DBKeys::ORDERPOSNEXT,
1135+ [] (CWallet* pwallet, DataStream& key, CDataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED (pwallet->cs_wallet ) {
1136+ try {
1137+ value >> pwallet->nOrderPosNext ;
1138+ } catch (const std::exception& e) {
1139+ err = e.what ();
1140+ return DBErrors::NONCRITICAL_ERROR;
1141+ }
1142+ return DBErrors::LOAD_OK;
1143+ });
1144+ result = std::max (result, order_pos_res.m_result );
1145+
1146+ return result;
1147+ }
1148+
11151149DBErrors WalletBatch::LoadWallet (CWallet* pwallet)
11161150{
11171151 CWalletScanState wss;
11181152 bool fNoncriticalErrors = false ;
1119- bool rescan_required = false ;
11201153 DBErrors result = DBErrors::LOAD_OK;
1154+ bool any_unordered = false ;
1155+ std::vector<uint256> upgraded_txs;
11211156
11221157 LOCK (pwallet->cs_wallet );
11231158
@@ -1153,6 +1188,9 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
11531188 // Load address book
11541189 result = std::max (LoadAddressBookRecords (pwallet, *m_batch), result);
11551190
1191+ // Load tx records
1192+ result = std::max (LoadTxRecords (pwallet, *m_batch, upgraded_txs, any_unordered), result);
1193+
11561194 // Get cursor
11571195 std::unique_ptr<DatabaseCursor> cursor = m_batch->GetNewCursor ();
11581196 if (!cursor)
@@ -1184,17 +1222,9 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
11841222 if (strType == DBKeys::MASTER_KEY ||
11851223 strType == DBKeys::DEFAULTKEY) {
11861224 result = DBErrors::CORRUPT;
1187- } else if (wss.tx_corrupt ) {
1188- pwallet->WalletLogPrintf (" Error: Corrupt transaction found. This can be fixed by removing transactions from wallet and rescanning.\n " );
1189- // Set tx_corrupt back to false so that the error is only printed once (per corrupt tx)
1190- wss.tx_corrupt = false ;
1191- result = DBErrors::CORRUPT;
11921225 } else {
11931226 // Leave other errors alone, if we try to fix them we might make things worse.
11941227 fNoncriticalErrors = true ; // ... but do warn the user there is something wrong.
1195- if (strType == DBKeys::TX)
1196- // Rescan if there is a bad transaction record:
1197- rescan_required = true ;
11981228 }
11991229 }
12001230 if (!strErr.empty ())
@@ -1214,9 +1244,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
12141244 pwallet->LoadActiveScriptPubKeyMan (spk_man_pair.second , spk_man_pair.first , /* internal=*/ true );
12151245 }
12161246
1217- if (rescan_required && result == DBErrors::LOAD_OK) {
1218- result = DBErrors::NEED_RESCAN;
1219- } else if (fNoncriticalErrors && result == DBErrors::LOAD_OK) {
1247+ if (fNoncriticalErrors && result == DBErrors::LOAD_OK) {
12201248 result = DBErrors::NONCRITICAL_ERROR;
12211249 }
12221250
@@ -1225,13 +1253,13 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
12251253 if (result != DBErrors::LOAD_OK)
12261254 return result;
12271255
1228- for (const uint256& hash : wss. vWalletUpgrade )
1256+ for (const uint256& hash : upgraded_txs )
12291257 WriteTx (pwallet->mapWallet .at (hash));
12301258
12311259 if (!has_last_client || last_client != CLIENT_VERSION) // Update
12321260 m_batch->Write (DBKeys::VERSION, CLIENT_VERSION);
12331261
1234- if (wss. fAnyUnordered )
1262+ if (any_unordered )
12351263 result = pwallet->ReorderTransactions ();
12361264
12371265 // Upgrade all of the wallet keymetadata to have the hd master key id
0 commit comments