Skip to content

Commit 6eb33bd

Browse files
kernel: Add fatalError method to notifications
FatalError replaces what previously was the AbortNode function in shutdown.cpp. This commit is part of the libbitcoinkernel project and further removes the shutdown's and, more generally, the kernel library's dependency on interface_ui with a kernel notification method. By removing interface_ui from the kernel library, its dependency on boost is reduced to just boost::multi_index. At the same time it also takes a step towards de-globalising the interrupt infrastructure. Co-authored-by: Russell Yanofsky <[email protected]> Co-authored-by: TheCharlatan <[email protected]>
1 parent 7320db9 commit 6eb33bd

19 files changed

+128
-90
lines changed

src/Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ BITCOIN_CORE_H = \
205205
netbase.h \
206206
netgroup.h \
207207
netmessagemaker.h \
208+
node/abort.h \
208209
node/blockmanager_args.h \
209210
node/blockstorage.h \
210211
node/caches.h \
@@ -400,6 +401,7 @@ libbitcoin_node_a_SOURCES = \
400401
net.cpp \
401402
net_processing.cpp \
402403
netgroup.cpp \
404+
node/abort.cpp \
403405
node/blockmanager_args.cpp \
404406
node/blockstorage.cpp \
405407
node/caches.cpp \
@@ -935,7 +937,6 @@ libbitcoinkernel_la_SOURCES = \
935937
logging.cpp \
936938
node/blockstorage.cpp \
937939
node/chainstate.cpp \
938-
node/interface_ui.cpp \
939940
node/utxo_snapshot.cpp \
940941
policy/feerate.cpp \
941942
policy/fees.cpp \

src/bitcoin-chainstate.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,11 @@ int main(int argc, char* argv[])
101101
{
102102
std::cerr << "Error flushing block data to disk: " << debug_message << std::endl;
103103
}
104-
104+
void fatalError(const std::string& debug_message, const bilingual_str& user_message) override
105+
{
106+
std::cerr << "Error: " << debug_message << std::endl;
107+
std::cerr << (user_message.empty() ? "A fatal internal error occurred." : user_message.original) << std::endl;
108+
}
105109
};
106110
auto notifications = std::make_unique<KernelNotifications>();
107111

src/index/base.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <interfaces/chain.h>
99
#include <kernel/chain.h>
1010
#include <logging.h>
11+
#include <node/abort.h>
1112
#include <node/blockstorage.h>
1213
#include <node/context.h>
1314
#include <node/database_args.h>
@@ -30,9 +31,10 @@ constexpr auto SYNC_LOG_INTERVAL{30s};
3031
constexpr auto SYNC_LOCATOR_WRITE_INTERVAL{30s};
3132

3233
template <typename... Args>
33-
static void FatalErrorf(const char* fmt, const Args&... args)
34+
void BaseIndex::FatalErrorf(const char* fmt, const Args&... args)
3435
{
35-
AbortNode(tfm::format(fmt, args...));
36+
auto message = tfm::format(fmt, args...);
37+
node::AbortNode(m_chain->context()->exit_status, message);
3638
}
3739

3840
CBlockLocator GetLocator(interfaces::Chain& chain, const uint256& block_hash)

src/index/base.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ class BaseIndex : public CValidationInterface
9494

9595
virtual bool AllowPrune() const = 0;
9696

97+
template <typename... Args>
98+
void FatalErrorf(const char* fmt, const Args&... args);
99+
97100
protected:
98101
std::unique_ptr<interfaces::Chain> m_chain;
99102
Chainstate* m_chainstate{nullptr};

src/init.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -812,8 +812,6 @@ bool AppInitBasicSetup(const ArgsManager& args, std::atomic<int>& exit_status)
812812
// Enable heap terminate-on-corruption
813813
HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption, nullptr, 0);
814814
#endif
815-
InitShutdownState(exit_status);
816-
817815
if (!SetupNetworking()) {
818816
return InitError(Untranslated("Initializing networking failed."));
819817
}
@@ -986,7 +984,7 @@ bool AppInitParameterInteraction(const ArgsManager& args)
986984

987985
// Also report errors from parsing before daemonization
988986
{
989-
KernelNotifications notifications{};
987+
kernel::Notifications notifications{};
990988
ChainstateManager::Options chainman_opts_dummy{
991989
.chainparams = chainparams,
992990
.datadir = args.GetDataDirNet(),
@@ -1410,7 +1408,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
14101408

14111409
// ********************************************************* Step 7: load block chain
14121410

1413-
node.notifications = std::make_unique<KernelNotifications>();
1411+
node.notifications = std::make_unique<KernelNotifications>(node.exit_status);
14141412
fReindex = args.GetBoolArg("-reindex", false);
14151413
bool fReindexChainState = args.GetBoolArg("-reindex-chainstate", false);
14161414
ChainstateManager::Options chainman_opts{

src/kernel/notifications_interface.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
#ifndef BITCOIN_KERNEL_NOTIFICATIONS_INTERFACE_H
66
#define BITCOIN_KERNEL_NOTIFICATIONS_INTERFACE_H
77

8+
#include <util/translation.h>
9+
810
#include <cstdint>
911
#include <string>
1012

1113
class CBlockIndex;
1214
enum class SynchronizationState;
13-
struct bilingual_str;
1415

1516
namespace kernel {
1617

@@ -35,6 +36,15 @@ class Notifications
3536
//! by logging the error, or notifying the user, or triggering an early
3637
//! shutdown as a precaution against causing more errors.
3738
virtual void flushError(const std::string& debug_message) {}
39+
40+
//! The fatal error notification is sent to notify the user when an error
41+
//! occurs in kernel code that can't be recovered from. After this
42+
//! notification is sent, whatever function triggered the error should also
43+
//! return an error code or raise an exception. Applications can choose to
44+
//! handle the fatal error notification by logging the error, or notifying
45+
//! the user, or triggering an early shutdown as a precaution against
46+
//! causing more errors.
47+
virtual void fatalError(const std::string& debug_message, const bilingual_str& user_message = {}) {}
3848
};
3949
} // namespace kernel
4050

src/node/abort.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) 2023 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <node/abort.h>
6+
7+
#include <logging.h>
8+
#include <node/interface_ui.h>
9+
#include <shutdown.h>
10+
#include <util/translation.h>
11+
#include <warnings.h>
12+
13+
#include <atomic>
14+
#include <cstdlib>
15+
#include <string>
16+
17+
namespace node {
18+
19+
void AbortNode(std::atomic<int>& exit_status, const std::string& debug_message, const bilingual_str& user_message, bool shutdown)
20+
{
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+
exit_status.store(EXIT_FAILURE);
25+
if (shutdown) StartShutdown();
26+
}
27+
} // namespace node

src/node/abort.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (c) 2023 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_NODE_ABORT_H
6+
#define BITCOIN_NODE_ABORT_H
7+
8+
#include <util/translation.h>
9+
10+
#include <atomic>
11+
#include <string>
12+
13+
namespace node {
14+
void AbortNode(std::atomic<int>& exit_status, const std::string& debug_message, const bilingual_str& user_message = {}, bool shutdown = true);
15+
} // namespace node
16+
17+
#endif // BITCOIN_NODE_ABORT_H

src/node/blockstorage.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,8 @@ bool BlockManager::FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigne
659659
bool out_of_space;
660660
size_t bytes_allocated = BlockFileSeq().Allocate(pos, nAddSize, out_of_space);
661661
if (out_of_space) {
662-
return AbortNode("Disk space is too low!", _("Disk space is too low!"));
662+
m_opts.notifications.fatalError("Disk space is too low!", _("Disk space is too low!"));
663+
return false;
663664
}
664665
if (bytes_allocated != 0 && IsPruneMode()) {
665666
m_check_for_pruning = true;
@@ -683,7 +684,7 @@ bool BlockManager::FindUndoPos(BlockValidationState& state, int nFile, FlatFileP
683684
bool out_of_space;
684685
size_t bytes_allocated = UndoFileSeq().Allocate(pos, nAddSize, out_of_space);
685686
if (out_of_space) {
686-
return AbortNode(state, "Disk space is too low!", _("Disk space is too low!"));
687+
return FatalError(m_opts.notifications, state, "Disk space is too low!", _("Disk space is too low!"));
687688
}
688689
if (bytes_allocated != 0 && IsPruneMode()) {
689690
m_check_for_pruning = true;
@@ -725,7 +726,7 @@ bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValid
725726
return error("ConnectBlock(): FindUndoPos failed");
726727
}
727728
if (!UndoWriteToDisk(blockundo, _pos, block.pprev->GetBlockHash(), GetParams().MessageStart())) {
728-
return AbortNode(state, "Failed to write undo data");
729+
return FatalError(m_opts.notifications, state, "Failed to write undo data");
729730
}
730731
// rev files are written in block height order, whereas blk files are written as blocks come in (often out of order)
731732
// we want to flush the rev (undo) file once we've written the last block, which is indicated by the last height
@@ -843,7 +844,7 @@ FlatFilePos BlockManager::SaveBlockToDisk(const CBlock& block, int nHeight, CCha
843844
}
844845
if (!position_known) {
845846
if (!WriteBlockToDisk(block, blockPos, GetParams().MessageStart())) {
846-
AbortNode("Failed to write block");
847+
m_opts.notifications.fatalError("Failed to write block");
847848
return FlatFilePos();
848849
}
849850
}
@@ -927,7 +928,7 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
927928
for (Chainstate* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
928929
BlockValidationState state;
929930
if (!chainstate->ActivateBestChain(state, nullptr)) {
930-
AbortNode(strprintf("Failed to connect best block (%s)", state.ToString()));
931+
chainman.GetNotifications().fatalError(strprintf("Failed to connect best block (%s)", state.ToString()));
931932
return;
932933
}
933934
}

src/node/kernel_notifications.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@
1010

1111
#include <common/args.h>
1212
#include <common/system.h>
13+
#include <kernel/context.h>
14+
#include <logging.h>
15+
#include <node/abort.h>
1316
#include <node/interface_ui.h>
1417
#include <shutdown.h>
18+
#include <util/check.h>
1519
#include <util/strencodings.h>
1620
#include <util/string.h>
1721
#include <util/translation.h>
@@ -75,7 +79,12 @@ void KernelNotifications::warning(const bilingual_str& warning)
7579

7680
void KernelNotifications::flushError(const std::string& debug_message)
7781
{
78-
AbortNode(debug_message);
82+
AbortNode(m_exit_status, debug_message);
83+
}
84+
85+
void KernelNotifications::fatalError(const std::string& debug_message, const bilingual_str& user_message)
86+
{
87+
node::AbortNode(m_exit_status, debug_message, user_message, m_shutdown_on_fatal_error);
7988
}
8089

8190
} // namespace node

0 commit comments

Comments
 (0)