|
| 1 | +From 0746cc67eb84402b26fb381e5c9c9e1605c7f2ab Mon Sep 17 00:00:00 2001 |
| 2 | +From: D33r-Gee < [email protected]> |
| 3 | +Date: Tue, 29 Jul 2025 11:11:16 -0700 |
| 4 | +Subject: [PATCH] cpp: Implement snapshot loading progress notifications |
| 5 | + |
| 6 | +- Added a new method `snapshotLoadProgress(double progress)` to the notifications interface to report the progress of loading UTXO snapshots. |
| 7 | +- Updated the `ChainstateManager::PopulateAndValidateSnapshot` function to calculate and send progress updates during the snapshot loading process. |
| 8 | +- Introduced a new signal `SnapshotLoadProgress` in the UI interface to handle progress notifications. |
| 9 | +- Implemented the necessary handlers in the node interface to connect the new progress signal. |
| 10 | + |
| 11 | +This enhancement improves user feedback during lengthy snapshot loading operations. |
| 12 | +--- |
| 13 | + src/interfaces/node.h | 9 +++++++++ |
| 14 | + src/kernel/notifications_interface.h | 1 + |
| 15 | + src/node/interface_ui.cpp | 3 +++ |
| 16 | + src/node/interface_ui.h | 3 +++ |
| 17 | + src/node/interfaces.cpp | 10 ++++++++++ |
| 18 | + src/node/kernel_notifications.cpp | 5 +++++ |
| 19 | + src/node/kernel_notifications.h | 2 ++ |
| 20 | + src/validation.cpp | 4 ++++ |
| 21 | + 8 files changed, 37 insertions(+) |
| 22 | + |
| 23 | +diff --git a/src/interfaces/node.h b/src/interfaces/node.h |
| 24 | +index 78a186c5d9..0ff267e484 100644 |
| 25 | +--- a/src/interfaces/node.h |
| 26 | ++++ b/src/interfaces/node.h |
| 27 | +@@ -12,6 +12,7 @@ |
| 28 | + #include <net_types.h> |
| 29 | + #include <netaddress.h> |
| 30 | + #include <netbase.h> |
| 31 | ++#include <node/utxo_snapshot.h> |
| 32 | + #include <support/allocators/secure.h> |
| 33 | + #include <util/translation.h> |
| 34 | + |
| 35 | +@@ -204,6 +205,10 @@ public: |
| 36 | + //! List rpc commands. |
| 37 | + virtual std::vector<std::string> listRpcCommands() = 0; |
| 38 | + |
| 39 | ++ |
| 40 | ++ //! Load UTXO Snapshot. |
| 41 | ++ virtual bool loadSnapshot(AutoFile& afile, const node::SnapshotMetadata& metadata, bool in_memory) = 0; |
| 42 | ++ |
| 43 | + //! Get unspent output associated with a transaction. |
| 44 | + virtual std::optional<Coin> getUnspentOutput(const COutPoint& output) = 0; |
| 45 | + |
| 46 | +@@ -233,6 +238,10 @@ public: |
| 47 | + using ShowProgressFn = std::function<void(const std::string& title, int progress, bool resume_possible)>; |
| 48 | + virtual std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) = 0; |
| 49 | + |
| 50 | ++ //! Register handler for snapshot load progress. |
| 51 | ++ using SnapshotLoadProgressFn = std::function<void(double progress)>; |
| 52 | ++ virtual std::unique_ptr<Handler> handleSnapshotLoadProgress(SnapshotLoadProgressFn fn) = 0; |
| 53 | ++ |
| 54 | + //! Register handler for wallet loader constructed messages. |
| 55 | + using InitWalletFn = std::function<void()>; |
| 56 | + virtual std::unique_ptr<Handler> handleInitWallet(InitWalletFn fn) = 0; |
| 57 | +diff --git a/src/kernel/notifications_interface.h b/src/kernel/notifications_interface.h |
| 58 | +index 3e97e3b45e..e6a5a1dd3f 100644 |
| 59 | +--- a/src/kernel/notifications_interface.h |
| 60 | ++++ b/src/kernel/notifications_interface.h |
| 61 | +@@ -40,6 +40,7 @@ public: |
| 62 | + [[nodiscard]] virtual InterruptResult blockTip(SynchronizationState state, CBlockIndex& index, double verification_progress) { return {}; } |
| 63 | + virtual void headerTip(SynchronizationState state, int64_t height, int64_t timestamp, bool presync) {} |
| 64 | + virtual void progress(const bilingual_str& title, int progress_percent, bool resume_possible) {} |
| 65 | ++ virtual void snapshotLoadProgress(double progress) {} |
| 66 | + virtual void warningSet(Warning id, const bilingual_str& message) {} |
| 67 | + virtual void warningUnset(Warning id) {} |
| 68 | + |
| 69 | +diff --git a/src/node/interface_ui.cpp b/src/node/interface_ui.cpp |
| 70 | +index 273e51974e..3d6a705db7 100644 |
| 71 | +--- a/src/node/interface_ui.cpp |
| 72 | ++++ b/src/node/interface_ui.cpp |
| 73 | +@@ -23,6 +23,7 @@ struct UISignals { |
| 74 | + boost::signals2::signal<CClientUIInterface::NotifyNetworkActiveChangedSig> NotifyNetworkActiveChanged; |
| 75 | + boost::signals2::signal<CClientUIInterface::NotifyAlertChangedSig> NotifyAlertChanged; |
| 76 | + boost::signals2::signal<CClientUIInterface::ShowProgressSig> ShowProgress; |
| 77 | ++ boost::signals2::signal<CClientUIInterface::SnapshotLoadProgressSig> SnapshotLoadProgress; |
| 78 | + boost::signals2::signal<CClientUIInterface::NotifyBlockTipSig> NotifyBlockTip; |
| 79 | + boost::signals2::signal<CClientUIInterface::NotifyHeaderTipSig> NotifyHeaderTip; |
| 80 | + boost::signals2::signal<CClientUIInterface::BannedListChangedSig> BannedListChanged; |
| 81 | +@@ -46,6 +47,7 @@ ADD_SIGNALS_IMPL_WRAPPER(ShowProgress); |
| 82 | + ADD_SIGNALS_IMPL_WRAPPER(NotifyBlockTip); |
| 83 | + ADD_SIGNALS_IMPL_WRAPPER(NotifyHeaderTip); |
| 84 | + ADD_SIGNALS_IMPL_WRAPPER(BannedListChanged); |
| 85 | ++ADD_SIGNALS_IMPL_WRAPPER(SnapshotLoadProgress); |
| 86 | + |
| 87 | + bool CClientUIInterface::ThreadSafeMessageBox(const bilingual_str& message, const std::string& caption, unsigned int style) { return g_ui_signals.ThreadSafeMessageBox(message, caption, style).value_or(false);} |
| 88 | + bool CClientUIInterface::ThreadSafeQuestion(const bilingual_str& message, const std::string& non_interactive_message, const std::string& caption, unsigned int style) { return g_ui_signals.ThreadSafeQuestion(message, non_interactive_message, caption, style).value_or(false);} |
| 89 | +@@ -55,6 +57,7 @@ void CClientUIInterface::NotifyNumConnectionsChanged(int newNumConnections) { re |
| 90 | + void CClientUIInterface::NotifyNetworkActiveChanged(bool networkActive) { return g_ui_signals.NotifyNetworkActiveChanged(networkActive); } |
| 91 | + void CClientUIInterface::NotifyAlertChanged() { return g_ui_signals.NotifyAlertChanged(); } |
| 92 | + void CClientUIInterface::ShowProgress(const std::string& title, int nProgress, bool resume_possible) { return g_ui_signals.ShowProgress(title, nProgress, resume_possible); } |
| 93 | ++void CClientUIInterface::SnapshotLoadProgress(double progress) { return g_ui_signals.SnapshotLoadProgress(progress); } |
| 94 | + void CClientUIInterface::NotifyBlockTip(SynchronizationState s, const CBlockIndex& block, double verification_progress) { return g_ui_signals.NotifyBlockTip(s, block, verification_progress); } |
| 95 | + void CClientUIInterface::NotifyHeaderTip(SynchronizationState s, int64_t height, int64_t timestamp, bool presync) { return g_ui_signals.NotifyHeaderTip(s, height, timestamp, presync); } |
| 96 | + void CClientUIInterface::BannedListChanged() { return g_ui_signals.BannedListChanged(); } |
| 97 | +diff --git a/src/node/interface_ui.h b/src/node/interface_ui.h |
| 98 | +index 7732cf4797..6f25870c49 100644 |
| 99 | +--- a/src/node/interface_ui.h |
| 100 | ++++ b/src/node/interface_ui.h |
| 101 | +@@ -102,6 +102,9 @@ public: |
| 102 | + */ |
| 103 | + ADD_SIGNALS_DECL_WRAPPER(ShowProgress, void, const std::string& title, int nProgress, bool resume_possible); |
| 104 | + |
| 105 | ++ /** Snapshot load progress. */ |
| 106 | ++ ADD_SIGNALS_DECL_WRAPPER(SnapshotLoadProgress, void, double progress); |
| 107 | ++ |
| 108 | + /** New block has been accepted */ |
| 109 | + ADD_SIGNALS_DECL_WRAPPER(NotifyBlockTip, void, SynchronizationState, const CBlockIndex& block, double verification_progress); |
| 110 | + |
| 111 | +diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp |
| 112 | +index 0485ff48bd..f02e1d28cd 100644 |
| 113 | +--- a/src/node/interfaces.cpp |
| 114 | ++++ b/src/node/interfaces.cpp |
| 115 | +@@ -38,6 +38,7 @@ |
| 116 | + #include <node/kernel_notifications.h> |
| 117 | + #include <node/transaction.h> |
| 118 | + #include <node/types.h> |
| 119 | ++#include <node/utxo_snapshot.h> |
| 120 | + #include <node/warnings.h> |
| 121 | + #include <policy/feerate.h> |
| 122 | + #include <policy/fees.h> |
| 123 | +@@ -361,6 +362,11 @@ public: |
| 124 | + LOCK(::cs_main); |
| 125 | + return chainman().ActiveChainstate().CoinsTip().GetCoin(output); |
| 126 | + } |
| 127 | ++ bool loadSnapshot(AutoFile& coins_file, const SnapshotMetadata& metadata, bool in_memory) override |
| 128 | ++ { |
| 129 | ++ auto activation_result{chainman().ActivateSnapshot(coins_file, metadata, in_memory)}; |
| 130 | ++ return activation_result.has_value(); |
| 131 | ++ } |
| 132 | + TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) override |
| 133 | + { |
| 134 | + return BroadcastTransaction(*m_context, std::move(tx), err_string, max_tx_fee, /*relay=*/ true, /*wait_callback=*/ false); |
| 135 | +@@ -385,6 +391,10 @@ public: |
| 136 | + { |
| 137 | + return MakeSignalHandler(::uiInterface.ShowProgress_connect(fn)); |
| 138 | + } |
| 139 | ++ std::unique_ptr<Handler> handleSnapshotLoadProgress(SnapshotLoadProgressFn fn) override |
| 140 | ++ { |
| 141 | ++ return MakeSignalHandler(::uiInterface.SnapshotLoadProgress_connect(fn)); |
| 142 | ++ } |
| 143 | + std::unique_ptr<Handler> handleInitWallet(InitWalletFn fn) override |
| 144 | + { |
| 145 | + return MakeSignalHandler(::uiInterface.InitWallet_connect(fn)); |
| 146 | +diff --git a/src/node/kernel_notifications.cpp b/src/node/kernel_notifications.cpp |
| 147 | +index 4a6f8444da..a1ae75ecc4 100644 |
| 148 | +--- a/src/node/kernel_notifications.cpp |
| 149 | ++++ b/src/node/kernel_notifications.cpp |
| 150 | +@@ -77,6 +77,11 @@ void KernelNotifications::progress(const bilingual_str& title, int progress_perc |
| 151 | + uiInterface.ShowProgress(title.translated, progress_percent, resume_possible); |
| 152 | + } |
| 153 | + |
| 154 | ++void KernelNotifications::snapshotLoadProgress(double progress) |
| 155 | ++{ |
| 156 | ++ uiInterface.SnapshotLoadProgress(progress); |
| 157 | ++} |
| 158 | ++ |
| 159 | + void KernelNotifications::warningSet(kernel::Warning id, const bilingual_str& message) |
| 160 | + { |
| 161 | + if (m_warnings.Set(id, message)) { |
| 162 | +diff --git a/src/node/kernel_notifications.h b/src/node/kernel_notifications.h |
| 163 | +index 10ee3e18d7..d873d34feb 100644 |
| 164 | +--- a/src/node/kernel_notifications.h |
| 165 | ++++ b/src/node/kernel_notifications.h |
| 166 | +@@ -41,6 +41,8 @@ public: |
| 167 | + |
| 168 | + void progress(const bilingual_str& title, int progress_percent, bool resume_possible) override; |
| 169 | + |
| 170 | ++ void snapshotLoadProgress(double progress) override; |
| 171 | ++ |
| 172 | + void warningSet(kernel::Warning id, const bilingual_str& message) override; |
| 173 | + |
| 174 | + void warningUnset(kernel::Warning id) override; |
| 175 | +diff --git a/src/validation.cpp b/src/validation.cpp |
| 176 | +index 3cfcd2728c..aa7cdf1c69 100644 |
| 177 | +--- a/src/validation.cpp |
| 178 | ++++ b/src/validation.cpp |
| 179 | +@@ -5959,6 +5959,10 @@ util::Result<void> ChainstateManager::PopulateAndValidateSnapshot( |
| 180 | + --coins_left; |
| 181 | + ++coins_processed; |
| 182 | + |
| 183 | ++ // Show Snapshot Loading progress |
| 184 | ++ double progress = static_cast<double>(coins_processed) / static_cast<double>(coins_count); |
| 185 | ++ GetNotifications().snapshotLoadProgress(progress); |
| 186 | ++ |
| 187 | + if (coins_processed % 1000000 == 0) { |
| 188 | + LogPrintf("[snapshot] %d coins loaded (%.2f%%, %.2f MB)\n", |
| 189 | + coins_processed, |
| 190 | +-- |
| 191 | +2.34.1 |
| 192 | + |
0 commit comments