summaryrefslogtreecommitdiff
path: root/patches/monero/0001-store-crash-fix.patch
diff options
context:
space:
mode:
authorCzarek Nakamoto <cyjan@mrcyjanek.net>2026-07-23 09:51:20 +0200
committerCzarek Nakamoto <cyjan@mrcyjanek.net>2026-08-03 14:53:50 +0200
commitc765eca1fbbfde6165d5ed5e56276878b3496c77 (patch)
tree5b9ef6e90361595b70fb6076d92bc41b7c6b7abc /patches/monero/0001-store-crash-fix.patch
parent5952bef2ec01b0b7e57c11613cbdc081dcd727c5 (diff)
use FCMP branch, bump simplybs, rebase patchescyjan-fcmp-v2
Diffstat (limited to 'patches/monero/0001-store-crash-fix.patch')
-rw-r--r--patches/monero/0001-store-crash-fix.patch335
1 files changed, 335 insertions, 0 deletions
diff --git a/patches/monero/0001-store-crash-fix.patch b/patches/monero/0001-store-crash-fix.patch
new file mode 100644
index 0000000..430dd36
--- /dev/null
+++ b/patches/monero/0001-store-crash-fix.patch
@@ -0,0 +1,335 @@
+From e502b3a2a2c88e9518c96123d44d91e6b6218f29 Mon Sep 17 00:00:00 2001
+From: Czarek Nakamoto <cyjan@mrcyjanek.net>
+Date: Sat, 11 May 2024 16:25:10 +0200
+Subject: [PATCH 01/22] store crash fix
+
+Monero wallet crashes (sometimes) when it is syncing,
+while the proper solution (that can be seen in feather)
+is to not store wallet while it is being synced, this is not
+acceptable for mobile wallets where OS can just come
+and kill the wallet because it felt like it.
+
+This patch depends on the background-sync patch, but
+to use it as a standalone fix grabbing the definition for the
+LOCK_REFRESH macro should be enough.
+
+tobtoht suggested:
+_say you want to store every 15 minutes during background sync. you stop the refresh every 15 minutes. then do something like this in the callback:_
+
+```
+// Make sure this doesn't run in the refresh thread
+onRefreshed() {
+ if (hasItBeen15MinutesSinceWeStored()) {
+ store();
+ }
+
+ if (shouldWeContinueRefreshing()) {
+ startRefresh();
+ }
+}
+```
+
+which works for crashes after the wallet is initially synced
+but doesn't solve the issue for wallet that are syncing (it
+would just wait for it to finish before actually storing).
+
+Also imo store() functin should store the wallet, no matter
+the current state.
+---
+ src/wallet/api/wallet.cpp | 53 +++++++++++++++++++--------------------
+ src/wallet/api/wallet.h | 1 -
+ src/wallet/wallet2.cpp | 11 +++++++-
+ src/wallet/wallet2.h | 3 +++
+ 4 files changed, 39 insertions(+), 29 deletions(-)
+
+diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
+index 2a3919577..1da515120 100644
+--- a/src/wallet/api/wallet.cpp
++++ b/src/wallet/api/wallet.cpp
+@@ -59,8 +59,8 @@ using namespace cryptonote;
+ #define MONERO_DEFAULT_LOG_CATEGORY "WalletAPI"
+
+ #define LOCK_REFRESH() \
+- bool refresh_enabled = m_refreshEnabled; \
+- m_refreshEnabled = false; \
++ bool refresh_enabled = m_wallet->get_refresh_enabled(); \
++ m_wallet->set_refresh_enabled(false); \
+ m_wallet->stop(); \
+ m_refreshCV.notify_one(); \
+ boost::mutex::scoped_lock lock(m_refreshMutex); \
+@@ -184,7 +184,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
+ virtual void on_new_block(uint64_t height, const cryptonote::block& block)
+ {
+ // Don't flood the GUI with signals. On fast refresh - send signal every 1000th block
+- // get_refresh_from_block_height() returns the blockheight from when the wallet was
++ // get_refresh_from_block_height() returns the blockheight from when the wallet was
+ // created or the restore height specified when wallet was recovered
+ if(height >= m_wallet->m_wallet->get_refresh_from_block_height() || height % 1000 == 0) {
+ // LOG_PRINT_L3(__FUNCTION__ << ": new block. height: " << height);
+@@ -356,7 +356,7 @@ bool Wallet::keyValid(const std::string &secret_key_string, const std::string &a
+ error = tr("Failed to parse address");
+ return false;
+ }
+-
++
+ cryptonote::blobdata key_data;
+ if(!epee::string_tools::parse_hexstr_to_binbuff(secret_key_string, key_data) || key_data.size() != sizeof(crypto::secret_key))
+ {
+@@ -381,7 +381,7 @@ bool Wallet::keyValid(const std::string &secret_key_string, const std::string &a
+ error = tr("key does not match address");
+ return false;
+ }
+-
++
+ return true;
+ }
+
+@@ -443,7 +443,7 @@ WalletImpl::WalletImpl(NetworkType nettype, uint64_t kdf_rounds)
+ m_wallet2Callback.reset(new Wallet2CallbackImpl(this));
+ m_wallet->callback(m_wallet2Callback.get());
+ m_refreshThreadDone = false;
+- m_refreshEnabled = false;
++ m_wallet->set_refresh_enabled(false);
+ m_addressBook.reset(new AddressBookImpl(this));
+ m_subaddress.reset(new SubaddressImpl(this));
+ m_subaddressAccount.reset(new SubaddressAccountImpl(this));
+@@ -464,7 +464,7 @@ WalletImpl::~WalletImpl()
+ m_wallet->callback(NULL);
+ // Pause refresh thread - prevents refresh from starting again
+ WalletImpl::pauseRefresh(); // Call the method directly (not polymorphically) to protect against UB in destructor.
+- // Close wallet - stores cache and stops ongoing refresh operation
++ // Close wallet - stores cache and stops ongoing refresh operation
+ close(false); // do not store wallet as part of the closing activities
+ // Stop refresh thread
+ stopRefresh();
+@@ -675,7 +675,7 @@ bool WalletImpl::recoverFromKeysWithPassword(const std::string &path,
+ setSeedLanguage(language);
+ LOG_PRINT_L1("Generated deterministic wallet from spend key with seed language: " + language);
+ }
+-
++
+ }
+ catch (const std::exception& e) {
+ setStatusError(string(tr("failed to generate new wallet: ")) + e.what());
+@@ -939,6 +939,7 @@ void WalletImpl::stop()
+ bool WalletImpl::store(const std::string &path)
+ {
+ clearStatus();
++ LOCK_REFRESH();
+ try {
+ if (path.empty()) {
+ m_wallet->store();
+@@ -1047,14 +1048,14 @@ uint64_t WalletImpl::daemonBlockChainTargetHeight() const
+ } else {
+ clearStatus();
+ }
+- // Target height can be 0 when daemon is synced. Use blockchain height instead.
++ // Target height can be 0 when daemon is synced. Use blockchain height instead.
+ if(result == 0)
+ result = daemonBlockChainHeight();
+ return result;
+ }
+
+ bool WalletImpl::daemonSynced() const
+-{
++{
+ if(connected() == Wallet::ConnectionStatus_Disconnected)
+ return false;
+ uint64_t blockChainHeight = daemonBlockChainHeight();
+@@ -1126,14 +1127,14 @@ UnsignedTransaction *WalletImpl::loadUnsignedTx(const std::string &unsigned_file
+
+ return transaction;
+ }
+-
++
+ // Check tx data and construct confirmation message
+ std::string extra_message;
+ if (!std::get<2>(transaction->m_unsigned_tx_set.transfers).empty())
+ extra_message = (boost::format("%u outputs to import. ") % (unsigned)std::get<2>(transaction->m_unsigned_tx_set.transfers).size()).str();
+ transaction->checkLoadedTx([&transaction](){return transaction->m_unsigned_tx_set.txes.size();}, [&transaction](size_t n)->const tools::wallet2::tx_construction_data&{return transaction->m_unsigned_tx_set.txes[n];}, extra_message);
+ setStatus(transaction->status(), transaction->errorString());
+-
++
+ return transaction;
+ }
+
+@@ -1148,7 +1149,7 @@ bool WalletImpl::submitTransaction(const string &fileName) {
+ setStatus(Status_Ok, tr("Failed to load transaction from file"));
+ return false;
+ }
+-
++
+ if(!transaction->commit()) {
+ setStatusError(transaction->m_errorString);
+ return false;
+@@ -1157,7 +1158,7 @@ bool WalletImpl::submitTransaction(const string &fileName) {
+ return true;
+ }
+
+-bool WalletImpl::exportKeyImages(const string &filename, bool all)
++bool WalletImpl::exportKeyImages(const string &filename, bool all)
+ {
+ if (m_wallet->watch_only())
+ {
+@@ -1166,7 +1167,7 @@ bool WalletImpl::exportKeyImages(const string &filename, bool all)
+ }
+ if (checkBackgroundSync("cannot export key images"))
+ return false;
+-
++
+ try
+ {
+ if (!m_wallet->export_key_images(filename, all))
+@@ -1623,7 +1624,7 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<stri
+ clearStatus();
+ // Pause refresh thread while creating transaction
+ pauseRefresh();
+-
++
+ cryptonote::address_parse_info info;
+
+ const auto adjusted_priority = m_wallet->adjust_priority(static_cast<uint32_t>(priority));
+@@ -2407,10 +2408,10 @@ void WalletImpl::refreshThreadFunc()
+ }
+
+ LOG_PRINT_L3(__FUNCTION__ << ": refresh lock acquired...");
+- LOG_PRINT_L3(__FUNCTION__ << ": m_refreshEnabled: " << m_refreshEnabled);
++ LOG_PRINT_L3(__FUNCTION__ << ": m_refreshEnabled: " << m_wallet->get_refresh_enabled());
+ LOG_PRINT_L3(__FUNCTION__ << ": m_status: " << status());
+ LOG_PRINT_L3(__FUNCTION__ << ": m_refreshShouldRescan: " << m_refreshShouldRescan);
+- if (m_refreshEnabled) {
++ if (m_wallet->get_refresh_enabled()) {
+ LOG_PRINT_L3(__FUNCTION__ << ": refreshing...");
+ doRefresh();
+ }
+@@ -2444,7 +2445,7 @@ void WalletImpl::doRefresh()
+ } catch (const std::exception &e) {
+ setStatusError(e.what());
+ break;
+- }while(!rescan && (rescan=m_refreshShouldRescan.exchange(false))); // repeat if not rescanned and rescan was requested
++ }while(m_wallet->get_refresh_enabled() && !rescan && (rescan=m_refreshShouldRescan.exchange(false))); // repeat if not rescanned and rescan was requested
+
+ if (m_wallet2Callback->getListener()) {
+ m_wallet2Callback->getListener()->refreshed();
+@@ -2454,9 +2455,9 @@ void WalletImpl::doRefresh()
+
+ void WalletImpl::startRefresh()
+ {
+- if (!m_refreshEnabled) {
++ if (!m_wallet->get_refresh_enabled()) {
+ LOG_PRINT_L2(__FUNCTION__ << ": refresh started/resumed...");
+- m_refreshEnabled = true;
++ m_wallet->set_refresh_enabled(true);
+ m_refreshCV.notify_one();
+ }
+ }
+@@ -2466,7 +2467,7 @@ void WalletImpl::startRefresh()
+ void WalletImpl::stopRefresh()
+ {
+ if (!m_refreshThreadDone) {
+- m_refreshEnabled = false;
++ m_wallet->set_refresh_enabled(false);
+ m_refreshThreadDone = true;
+ m_refreshCV.notify_one();
+ m_refreshThread.join();
+@@ -2477,9 +2478,7 @@ void WalletImpl::pauseRefresh()
+ {
+ LOG_PRINT_L2(__FUNCTION__ << ": refresh paused...");
+ // TODO synchronize access
+- if (!m_refreshThreadDone) {
+- m_refreshEnabled = false;
+- }
++ m_wallet->set_refresh_enabled(false);
+ }
+
+
+@@ -2489,7 +2488,7 @@ bool WalletImpl::isNewWallet() const
+ // it's the same case as if it created from scratch, i.e. we need "fast sync"
+ // with the daemon (pull hashes instead of pull blocks).
+ // If wallet cache is rebuilt, creation height stored in .keys is used.
+- // Watch only wallet is a copy of an existing wallet.
++ // Watch only wallet is a copy of an existing wallet.
+ return !(blockChainHeight() > 1 || m_recoveringFromSeed || m_recoveringFromDevice || m_rebuildWalletCache) && !watchOnly();
+ }
+
+@@ -2601,7 +2600,7 @@ void WalletImpl::hardForkInfo(uint8_t &version, uint64_t &earliest_height) const
+ m_wallet->get_hard_fork_info(version, earliest_height);
+ }
+
+-bool WalletImpl::useForkRules(uint8_t version, int64_t early_blocks) const
++bool WalletImpl::useForkRules(uint8_t version, int64_t early_blocks) const
+ {
+ return m_wallet->use_fork_rules(version,early_blocks);
+ }
+diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
+index d48d7f130..365025c6e 100644
+--- a/src/wallet/api/wallet.h
++++ b/src/wallet/api/wallet.h
+@@ -274,7 +274,6 @@ private:
+ std::unique_ptr<SubaddressAccountImpl> m_subaddressAccount;
+
+ // multi-threaded refresh stuff
+- std::atomic<bool> m_refreshEnabled;
+ std::atomic<bool> m_refreshThreadDone;
+ std::atomic<int> m_refreshIntervalMillis;
+ std::atomic<bool> m_refreshShouldRescan;
+diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
+index e818afe53..2ca99f63a 100644
+--- a/src/wallet/wallet2.cpp
++++ b/src/wallet/wallet2.cpp
+@@ -1222,6 +1222,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended, std
+ m_upper_transaction_weight_limit(0),
+ m_run(true),
+ m_callback(0),
++ m_refreshEnabled(false),
+ m_trusted_daemon(false),
+ m_nettype(nettype),
+ m_multisig_rounds_passed(0),
+@@ -1432,6 +1433,14 @@ bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_u
+ return ret;
+ }
+ //----------------------------------------------------------------------------------------------------
++bool wallet2::get_refresh_enabled() {
++ return m_refreshEnabled;
++}
++//----------------------------------------------------------------------------------------------------
++void wallet2::set_refresh_enabled(bool val) {
++ m_refreshEnabled = val;
++}
++//----------------------------------------------------------------------------------------------------
+ bool wallet2::set_proxy(const std::string &address)
+ {
+ return m_http_client->set_proxy(address);
+@@ -4461,7 +4470,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
+
+
+ bool first = true, last = false;
+- while(m_run.load(std::memory_order_relaxed) && blocks_fetched < max_blocks)
++ while(m_run.load(std::memory_order_relaxed) && blocks_fetched < max_blocks && m_refreshEnabled)
+ {
+ uint64_t next_blocks_start_height;
+ std::vector<cryptonote::block_complete_entry> next_blocks;
+diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
+index c350f1da8..e78abda83 100644
+--- a/src/wallet/wallet2.h
++++ b/src/wallet/wallet2.h
+@@ -579,6 +579,8 @@ private:
+ epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect,
+ const std::string &proxy = "");
+ bool set_proxy(const std::string &address);
++ bool get_refresh_enabled();
++ void set_refresh_enabled(bool val);
+
+ void stop() { m_run.store(false, std::memory_order_relaxed); m_message_store.stop(); }
+
+@@ -1591,6 +1593,7 @@ private:
+
+ boost::recursive_mutex m_daemon_rpc_mutex;
+
++ bool m_refreshEnabled;
+ bool m_trusted_daemon;
+ i_wallet2_callback* m_callback;
+ hw::device::device_type m_key_device_type;
+--
+2.54.0 (Apple Git-157)
+