@@ -123,17 +123,19 @@ using node::ApplyArgsManOptions;
123
123
using node::BlockManager;
124
124
using node::CacheSizes;
125
125
using node::CalculateCacheSizes;
126
+ using node::ChainstateLoadResult;
127
+ using node::ChainstateLoadStatus;
126
128
using node::DEFAULT_PERSIST_MEMPOOL;
127
129
using node::DEFAULT_PRINT_MODIFIED_FEE;
128
130
using node::DEFAULT_STOPATHEIGHT;
129
131
using node::DumpMempool;
130
- using node::LoadMempool ;
132
+ using node::ImportBlocks ;
131
133
using node::KernelNotifications;
132
134
using node::LoadChainstate;
135
+ using node::LoadMempool;
133
136
using node::MempoolPath;
134
137
using node::NodeContext;
135
138
using node::ShouldPersistMempool;
136
- using node::ImportBlocks;
137
139
using node::VerifyLoadedChainstate;
138
140
using util::Join;
139
141
using util::ReplaceAll;
@@ -1183,6 +1185,104 @@ bool CheckHostPortOptions(const ArgsManager& args) {
1183
1185
return true ;
1184
1186
}
1185
1187
1188
+ // A GUI user may opt to retry once if there is a failure during chainstate initialization.
1189
+ // The function therefore has to support re-entry.
1190
+ static ChainstateLoadResult InitAndLoadChainstate (
1191
+ NodeContext& node,
1192
+ bool do_reindex,
1193
+ const bool do_reindex_chainstate,
1194
+ CacheSizes& cache_sizes,
1195
+ const ArgsManager& args)
1196
+ {
1197
+ const CChainParams& chainparams = Params ();
1198
+ CTxMemPool::Options mempool_opts{
1199
+ .check_ratio = chainparams.DefaultConsistencyChecks () ? 1 : 0 ,
1200
+ .signals = node.validation_signals .get (),
1201
+ };
1202
+ Assert (ApplyArgsManOptions (args, chainparams, mempool_opts)); // no error can happen, already checked in AppInitParameterInteraction
1203
+ bilingual_str mempool_error;
1204
+ node.mempool = std::make_unique<CTxMemPool>(mempool_opts, mempool_error);
1205
+ if (!mempool_error.empty ()) {
1206
+ return {ChainstateLoadStatus::FAILURE_FATAL, mempool_error};
1207
+ }
1208
+ LogPrintf (" * Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n " , cache_sizes.coins * (1.0 / 1024 / 1024 ), mempool_opts.max_size_bytes * (1.0 / 1024 / 1024 ));
1209
+ ChainstateManager::Options chainman_opts{
1210
+ .chainparams = chainparams,
1211
+ .datadir = args.GetDataDirNet (),
1212
+ .notifications = *node.notifications ,
1213
+ .signals = node.validation_signals .get (),
1214
+ };
1215
+ Assert (ApplyArgsManOptions (args, chainman_opts)); // no error can happen, already checked in AppInitParameterInteraction
1216
+ BlockManager::Options blockman_opts{
1217
+ .chainparams = chainman_opts.chainparams ,
1218
+ .blocks_dir = args.GetBlocksDirPath (),
1219
+ .notifications = chainman_opts.notifications ,
1220
+ };
1221
+ Assert (ApplyArgsManOptions (args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction
1222
+ try {
1223
+ node.chainman = std::make_unique<ChainstateManager>(*Assert (node.shutdown ), chainman_opts, blockman_opts);
1224
+ } catch (std::exception & e) {
1225
+ return {ChainstateLoadStatus::FAILURE_FATAL, strprintf (Untranslated (" Failed to initialize ChainstateManager: %s" ), e.what ())};
1226
+ }
1227
+ ChainstateManager& chainman = *node.chainman ;
1228
+ // This is defined and set here instead of inline in validation.h to avoid a hard
1229
+ // dependency between validation and index/base, since the latter is not in
1230
+ // libbitcoinkernel.
1231
+ chainman.snapshot_download_completed = [&node]() {
1232
+ if (!node.chainman ->m_blockman .IsPruneMode ()) {
1233
+ LogPrintf (" [snapshot] re-enabling NODE_NETWORK services\n " );
1234
+ node.connman ->AddLocalServices (NODE_NETWORK);
1235
+ }
1236
+ LogPrintf (" [snapshot] restarting indexes\n " );
1237
+ // Drain the validation interface queue to ensure that the old indexes
1238
+ // don't have any pending work.
1239
+ Assert (node.validation_signals )->SyncWithValidationInterfaceQueue ();
1240
+ for (auto * index : node.indexes ) {
1241
+ index ->Interrupt ();
1242
+ index ->Stop ();
1243
+ if (!(index ->Init () && index ->StartBackgroundSync ())) {
1244
+ LogPrintf (" [snapshot] WARNING failed to restart index %s on snapshot chain\n " , index ->GetName ());
1245
+ }
1246
+ }
1247
+ };
1248
+ node::ChainstateLoadOptions options;
1249
+ options.mempool = Assert (node.mempool .get ());
1250
+ options.wipe_block_tree_db = do_reindex;
1251
+ options.wipe_chainstate_db = do_reindex || do_reindex_chainstate;
1252
+ options.prune = chainman.m_blockman .IsPruneMode ();
1253
+ options.check_blocks = args.GetIntArg (" -checkblocks" , DEFAULT_CHECKBLOCKS);
1254
+ options.check_level = args.GetIntArg (" -checklevel" , DEFAULT_CHECKLEVEL);
1255
+ options.require_full_verification = args.IsArgSet (" -checkblocks" ) || args.IsArgSet (" -checklevel" );
1256
+ options.coins_error_cb = [] {
1257
+ uiInterface.ThreadSafeMessageBox (
1258
+ _ (" Error reading from database, shutting down." ),
1259
+ " " , CClientUIInterface::MSG_ERROR);
1260
+ };
1261
+ uiInterface.InitMessage (_ (" Loading block index…" ).translated );
1262
+ const auto load_block_index_start_time{SteadyClock::now ()};
1263
+ auto catch_exceptions = [](auto && f) {
1264
+ try {
1265
+ return f ();
1266
+ } catch (const std::exception & e) {
1267
+ LogError (" %s\n " , e.what ());
1268
+ return std::make_tuple (node::ChainstateLoadStatus::FAILURE, _ (" Error opening block database" ));
1269
+ }
1270
+ };
1271
+ auto [status, error] = catch_exceptions ([&] { return LoadChainstate (chainman, cache_sizes, options); });
1272
+ if (status == node::ChainstateLoadStatus::SUCCESS) {
1273
+ uiInterface.InitMessage (_ (" Verifying blocks…" ).translated );
1274
+ if (chainman.m_blockman .m_have_pruned && options.check_blocks > MIN_BLOCKS_TO_KEEP) {
1275
+ LogWarning (" pruned datadir may not have more than %d blocks; only checking available blocks\n " ,
1276
+ MIN_BLOCKS_TO_KEEP);
1277
+ }
1278
+ std::tie (status, error) = catch_exceptions ([&] { return VerifyLoadedChainstate (chainman, options); });
1279
+ if (status == node::ChainstateLoadStatus::SUCCESS) {
1280
+ LogPrintf (" block index %15dms\n " , Ticks<std::chrono::milliseconds>(SteadyClock::now () - load_block_index_start_time));
1281
+ }
1282
+ }
1283
+ return {status, error};
1284
+ };
1285
+
1186
1286
bool AppInitMain (NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1187
1287
{
1188
1288
const ArgsManager& args = *Assert (node.args );
@@ -1514,20 +1614,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1514
1614
1515
1615
node.notifications = std::make_unique<KernelNotifications>(*Assert (node.shutdown ), node.exit_status , *Assert (node.warnings ));
1516
1616
ReadNotificationArgs (args, *node.notifications );
1517
- ChainstateManager::Options chainman_opts{
1518
- .chainparams = chainparams,
1519
- .datadir = args.GetDataDirNet (),
1520
- .notifications = *node.notifications ,
1521
- .signals = &validation_signals,
1522
- };
1523
- Assert (ApplyArgsManOptions (args, chainman_opts)); // no error can happen, already checked in AppInitParameterInteraction
1524
-
1525
- BlockManager::Options blockman_opts{
1526
- .chainparams = chainman_opts.chainparams ,
1527
- .blocks_dir = args.GetBlocksDirPath (),
1528
- .notifications = chainman_opts.notifications ,
1529
- };
1530
- Assert (ApplyArgsManOptions (args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction
1531
1617
1532
1618
// cache size calculations
1533
1619
CacheSizes cache_sizes = CalculateCacheSizes (args, g_enabled_filter_types.size ());
@@ -1546,96 +1632,25 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1546
1632
assert (!node.mempool );
1547
1633
assert (!node.chainman );
1548
1634
1549
- CTxMemPool::Options mempool_opts{
1550
- .check_ratio = chainparams.DefaultConsistencyChecks () ? 1 : 0 ,
1551
- .signals = &validation_signals,
1552
- };
1553
- Assert (ApplyArgsManOptions (args, chainparams, mempool_opts)); // no error can happen, already checked in AppInitParameterInteraction
1554
-
1555
1635
bool do_reindex{args.GetBoolArg (" -reindex" , false )};
1556
1636
const bool do_reindex_chainstate{args.GetBoolArg (" -reindex-chainstate" , false )};
1557
1637
1558
1638
for (bool fLoaded = false ; !fLoaded && !ShutdownRequested (node);) {
1559
- bilingual_str mempool_error;
1560
- node.mempool = std::make_unique<CTxMemPool>(mempool_opts, mempool_error);
1561
- if (!mempool_error.empty ()) {
1562
- return InitError (mempool_error);
1563
- }
1564
- LogPrintf (" * Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n " , cache_sizes.coins * (1.0 / 1024 / 1024 ), mempool_opts.max_size_bytes * (1.0 / 1024 / 1024 ));
1565
-
1566
- try {
1567
- node.chainman = std::make_unique<ChainstateManager>(*Assert (node.shutdown ), chainman_opts, blockman_opts);
1568
- } catch (std::exception & e) {
1569
- return InitError (strprintf (Untranslated (" Failed to initialize ChainstateManager: %s" ), e.what ()));
1570
- }
1571
- ChainstateManager& chainman = *node.chainman ;
1572
-
1573
- // This is defined and set here instead of inline in validation.h to avoid a hard
1574
- // dependency between validation and index/base, since the latter is not in
1575
- // libbitcoinkernel.
1576
- chainman.snapshot_download_completed = [&node]() {
1577
- if (!node.chainman ->m_blockman .IsPruneMode ()) {
1578
- LogPrintf (" [snapshot] re-enabling NODE_NETWORK services\n " );
1579
- node.connman ->AddLocalServices (NODE_NETWORK);
1580
- }
1581
-
1582
- LogPrintf (" [snapshot] restarting indexes\n " );
1583
-
1584
- // Drain the validation interface queue to ensure that the old indexes
1585
- // don't have any pending work.
1586
- Assert (node.validation_signals )->SyncWithValidationInterfaceQueue ();
1587
-
1588
- for (auto * index : node.indexes ) {
1589
- index ->Interrupt ();
1590
- index ->Stop ();
1591
- if (!(index ->Init () && index ->StartBackgroundSync ())) {
1592
- LogPrintf (" [snapshot] WARNING failed to restart index %s on snapshot chain\n " , index ->GetName ());
1593
- }
1594
- }
1595
- };
1596
-
1597
- node::ChainstateLoadOptions options;
1598
- options.mempool = Assert (node.mempool .get ());
1599
- options.wipe_block_tree_db = do_reindex;
1600
- options.wipe_chainstate_db = do_reindex || do_reindex_chainstate;
1601
- options.prune = chainman.m_blockman .IsPruneMode ();
1602
- options.check_blocks = args.GetIntArg (" -checkblocks" , DEFAULT_CHECKBLOCKS);
1603
- options.check_level = args.GetIntArg (" -checklevel" , DEFAULT_CHECKLEVEL);
1604
- options.require_full_verification = args.IsArgSet (" -checkblocks" ) || args.IsArgSet (" -checklevel" );
1605
- options.coins_error_cb = [] {
1606
- uiInterface.ThreadSafeMessageBox (
1607
- _ (" Error reading from database, shutting down." ),
1608
- " " , CClientUIInterface::MSG_ERROR);
1609
- };
1610
-
1611
- uiInterface.InitMessage (_ (" Loading block index…" ).translated );
1612
- const auto load_block_index_start_time{SteadyClock::now ()};
1613
- auto catch_exceptions = [](auto && f) {
1614
- try {
1615
- return f ();
1616
- } catch (const std::exception & e) {
1617
- LogError (" %s\n " , e.what ());
1618
- return std::make_tuple (node::ChainstateLoadStatus::FAILURE, _ (" Error opening block database" ));
1619
- }
1620
- };
1621
- auto [status, error] = catch_exceptions ([&]{ return LoadChainstate (chainman, cache_sizes, options); });
1622
- if (status == node::ChainstateLoadStatus::SUCCESS) {
1623
- uiInterface.InitMessage (_ (" Verifying blocks…" ).translated );
1624
- if (chainman.m_blockman .m_have_pruned && options.check_blocks > MIN_BLOCKS_TO_KEEP) {
1625
- LogWarning (" pruned datadir may not have more than %d blocks; only checking available blocks\n " ,
1626
- MIN_BLOCKS_TO_KEEP);
1627
- }
1628
- std::tie (status, error) = catch_exceptions ([&]{ return VerifyLoadedChainstate (chainman, options);});
1629
- if (status == node::ChainstateLoadStatus::SUCCESS) {
1630
- fLoaded = true ;
1631
- LogPrintf (" block index %15dms\n " , Ticks<std::chrono::milliseconds>(SteadyClock::now () - load_block_index_start_time));
1632
- }
1633
- }
1639
+ auto [status, error] = InitAndLoadChainstate (
1640
+ node,
1641
+ do_reindex,
1642
+ do_reindex_chainstate,
1643
+ cache_sizes,
1644
+ args);
1634
1645
1635
1646
if (status == node::ChainstateLoadStatus::FAILURE_FATAL || status == node::ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB || status == node::ChainstateLoadStatus::FAILURE_INSUFFICIENT_DBCACHE) {
1636
1647
return InitError (error);
1637
1648
}
1638
1649
1650
+ if (status == ChainstateLoadStatus::SUCCESS) {
1651
+ fLoaded = true ;
1652
+ }
1653
+
1639
1654
if (!fLoaded && !ShutdownRequested (node)) {
1640
1655
// first suggest a reindex
1641
1656
if (!do_reindex) {
0 commit comments