In commit “kernel: Add fatalError method to notifications” (861582b4087f1602e7115ee4a70ef7a7263eb36b)
I think it would make sense to get rid of this callback now that there is a notifications object. Following seems to work:
0diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp
1index 41056272f549..3a055c8e0bc7 100644
2--- a/src/node/chainstate.cpp
3+++ b/src/node/chainstate.cpp
4@@ -200,10 +200,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
5 // snapshot is actually validated? Because this entails unusual
6 // filesystem operations to move leveldb data directories around, and that seems
7 // too risky to do in the middle of normal runtime.
8- auto snapshot_completion = chainman.MaybeCompleteSnapshotValidation(
9- [&chainman](bilingual_str msg) {
10- chainman.GetNotifications().fatalError(msg.original, msg);
11- });
12+ auto snapshot_completion = chainman.MaybeCompleteSnapshotValidation();
13
14 if (snapshot_completion == SnapshotCompletionResult::SKIPPED) {
15 // do nothing; expected case
16diff --git a/src/node/kernel_notifications.cpp b/src/node/kernel_notifications.cpp
17index 5fc116d87097..7f2e55ec6738 100644
18--- a/src/node/kernel_notifications.cpp
19+++ b/src/node/kernel_notifications.cpp
20@@ -79,7 +79,7 @@ void KernelNotifications::fatalError(const std::string& debug_message, const bil
21 SetMiscWarning(Untranslated(debug_message));
22 LogPrintf("*** %s\n", debug_message);
23 InitError(user_message.empty() ? _("A fatal internal error occurred, see debug.log for details") : user_message);
24- StartShutdown();
25+ if (m_do_shutdown) StartShutdown();
26 }
27
28 } // namespace node
29diff --git a/src/node/kernel_notifications.h b/src/node/kernel_notifications.h
30index 3db4de0a8c14..99cb04325ac9 100644
31--- a/src/node/kernel_notifications.h
32+++ b/src/node/kernel_notifications.h
33@@ -27,6 +27,9 @@ public:
34 void warning(const bilingual_str& warning) override;
35
36 void fatalError(const std::string& debug_message, const bilingual_str& user_message = {}) override;
37+
38+ //! Useful for tests, can be set to false to avoid shutdown on fatal error.
39+ bool m_do_shutdown{true};
40 };
41 } // namespace node
42
43diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp
44index 81a015513a5a..3c52d76a6ba5 100644
45--- a/src/test/validation_chainstatemanager_tests.cpp
46+++ b/src/test/validation_chainstatemanager_tests.cpp
47@@ -564,7 +564,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_completion, SnapshotTestSetup
48 auto db_cache_before_complete = active_cs.m_coinsdb_cache_size_bytes;
49
50 SnapshotCompletionResult res;
51- auto mock_shutdown = [](bilingual_str msg) {};
52+ m_node.notifications->m_do_shutdown = false;
53
54 fs::path snapshot_chainstate_dir = *node::FindSnapshotChainstateDir();
55 BOOST_CHECK(fs::exists(snapshot_chainstate_dir));
56@@ -574,8 +574,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_completion, SnapshotTestSetup
57 const uint256 snapshot_tip_hash = WITH_LOCK(chainman.GetMutex(),
58 return chainman.ActiveTip()->GetBlockHash());
59
60- res = WITH_LOCK(::cs_main,
61- return chainman.MaybeCompleteSnapshotValidation(mock_shutdown));
62+ res = WITH_LOCK(::cs_main, return chainman.MaybeCompleteSnapshotValidation());
63 BOOST_CHECK_EQUAL(res, SnapshotCompletionResult::SUCCESS);
64
65 WITH_LOCK(::cs_main, BOOST_CHECK(chainman.IsSnapshotValidated()));
66@@ -591,8 +590,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_completion, SnapshotTestSetup
67 BOOST_CHECK_EQUAL(all_chainstates[0], &active_cs);
68
69 // Trying completion again should return false.
70- res = WITH_LOCK(::cs_main,
71- return chainman.MaybeCompleteSnapshotValidation(mock_shutdown));
72+ res = WITH_LOCK(::cs_main, return chainman.MaybeCompleteSnapshotValidation());
73 BOOST_CHECK_EQUAL(res, SnapshotCompletionResult::SKIPPED);
74
75 // The invalid snapshot path should not have been used.
76@@ -645,7 +643,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_completion_hash_mismatch, Sna
77 Chainstate& validation_chainstate = *std::get<0>(chainstates);
78 ChainstateManager& chainman = *Assert(m_node.chainman);
79 SnapshotCompletionResult res;
80- auto mock_shutdown = [](bilingual_str msg) {};
81+ m_node.notifications->m_do_shutdown = false;
82
83 // Test tampering with the IBD UTXO set with an extra coin to ensure it causes
84 // snapshot completion to fail.
85@@ -661,8 +659,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_completion_hash_mismatch, Sna
86 fs::path snapshot_chainstate_dir = gArgs.GetDataDirNet() / "chainstate_snapshot";
87 BOOST_CHECK(fs::exists(snapshot_chainstate_dir));
88
89- res = WITH_LOCK(::cs_main,
90- return chainman.MaybeCompleteSnapshotValidation(mock_shutdown));
91+ res = WITH_LOCK(::cs_main, return chainman.MaybeCompleteSnapshotValidation());
92 BOOST_CHECK_EQUAL(res, SnapshotCompletionResult::HASH_MISMATCH);
93
94 auto all_chainstates = chainman.GetAll();
95diff --git a/src/validation.cpp b/src/validation.cpp
96index e753b75c88ae..491376f0e4f0 100644
97--- a/src/validation.cpp
98+++ b/src/validation.cpp
99@@ -2871,10 +2871,7 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew,
100 if (this != &m_chainman.ActiveChainstate()) {
101 // This call may set `m_disabled`, which is referenced immediately afterwards in
102 // ActivateBestChain, so that we stop connecting blocks past the snapshot base.
103- m_chainman.MaybeCompleteSnapshotValidation(
104- [¬ifications = m_chainman.GetNotifications()](bilingual_str msg) {
105- notifications.fatalError(msg.original, msg);
106- });
107+ m_chainman.MaybeCompleteSnapshotValidation();
108 }
109
110 connectTrace.BlockConnected(pindexNew, std::move(pthisBlock));
111@@ -5385,8 +5382,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
112 // through IsUsable() checks, or
113 //
114 // (ii) giving each chainstate its own lock instead of using cs_main for everything.
115-SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation(
116- std::function<void(bilingual_str)> shutdown_fnc)
117+SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation()
118 {
119 AssertLockHeld(cs_main);
120 if (m_ibd_chainstate.get() == &this->ActiveChainstate() ||
121@@ -5435,7 +5431,7 @@ SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation(
122
123 m_snapshot_chainstate->InvalidateCoinsDBOnDisk();
124
125- shutdown_fnc(user_error);
126+ GetNotifications().fatalError(user_error.original, user_error);
127 };
128
129 if (index_new.GetBlockHash() != snapshot_blockhash) {
130diff --git a/src/validation.h b/src/validation.h
131index 136992a9ac15..b03e3d4a5fe4 100644
132--- a/src/validation.h
133+++ b/src/validation.h
134@@ -1044,8 +1044,7 @@ public:
135 //! If the coins match (expected), then mark the validation chainstate for
136 //! deletion and continue using the snapshot chainstate as active.
137 //! Otherwise, revert to using the ibd chainstate and shutdown.
138- SnapshotCompletionResult MaybeCompleteSnapshotValidation(
139- std::function<void(bilingual_str)> shutdown_fnc) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
140+ SnapshotCompletionResult MaybeCompleteSnapshotValidation() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
141
142 //! The most-work chain.
143 Chainstate& ActiveChainstate() const;