From 57249ff669748d60895c275255dfb9bffaecbb67 Mon Sep 17 00:00:00 2001 From: furszy Date: Tue, 26 Mar 2024 10:48:30 -0300 Subject: [PATCH] wallet: introduce active db txn listeners Useful to ensure that the in-memory state is updated only after successfully committing the data to disk. --- src/wallet/bdb.h | 1 + src/wallet/db.h | 1 + src/wallet/migrate.h | 1 + src/wallet/salvage.cpp | 1 + src/wallet/sqlite.h | 1 + src/wallet/test/util.h | 1 + src/wallet/walletdb.cpp | 26 ++++++++++++++++++++++++-- src/wallet/walletdb.h | 14 ++++++++++++++ 8 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h index af0c78f0d9e..f3fe8a19c19 100644 --- a/src/wallet/bdb.h +++ b/src/wallet/bdb.h @@ -208,6 +208,7 @@ public: bool TxnBegin() override; bool TxnCommit() override; bool TxnAbort() override; + bool HasActiveTxn() override { return activeTxn != nullptr; } DbTxn* txn() const { return activeTxn; } }; diff --git a/src/wallet/db.h b/src/wallet/db.h index 049af8dd19e..e8790006a4d 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -122,6 +122,7 @@ public: virtual bool TxnBegin() = 0; virtual bool TxnCommit() = 0; virtual bool TxnAbort() = 0; + virtual bool HasActiveTxn() = 0; }; /** An instance of this class represents one database. diff --git a/src/wallet/migrate.h b/src/wallet/migrate.h index 58c8c0adf4e..16eadeb019d 100644 --- a/src/wallet/migrate.h +++ b/src/wallet/migrate.h @@ -115,6 +115,7 @@ public: bool TxnBegin() override { return false; } bool TxnCommit() override { return false; } bool TxnAbort() override { return false; } + bool HasActiveTxn() override { return false; } }; //! Return object giving access to Berkeley Read Only database at specified path. diff --git a/src/wallet/salvage.cpp b/src/wallet/salvage.cpp index 04c02b0dcc6..0ac1b66897e 100644 --- a/src/wallet/salvage.cpp +++ b/src/wallet/salvage.cpp @@ -44,6 +44,7 @@ public: bool TxnBegin() override { return true; } bool TxnCommit() override { return true; } bool TxnAbort() override { return true; } + bool HasActiveTxn() override { return false; } }; /** A dummy WalletDatabase that does nothing and never fails. Only used by salvage. diff --git a/src/wallet/sqlite.h b/src/wallet/sqlite.h index 6b84f34366f..78a3accf890 100644 --- a/src/wallet/sqlite.h +++ b/src/wallet/sqlite.h @@ -95,6 +95,7 @@ public: bool TxnBegin() override; bool TxnCommit() override; bool TxnAbort() override; + bool HasActiveTxn() override { return m_txn; } }; /** An instance of this class represents one SQLite3 database. diff --git a/src/wallet/test/util.h b/src/wallet/test/util.h index ba12f5f6bf1..c8a89c0e642 100644 --- a/src/wallet/test/util.h +++ b/src/wallet/test/util.h @@ -95,6 +95,7 @@ public: bool TxnBegin() override { return m_pass; } bool TxnCommit() override { return m_pass; } bool TxnAbort() override { return m_pass; } + bool HasActiveTxn() override { return false; } }; /** A WalletDatabase whose contents and return values can be modified as needed for testing diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 7f092b44b16..b09a0e40eb4 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1347,12 +1347,34 @@ bool WalletBatch::TxnBegin() bool WalletBatch::TxnCommit() { - return m_batch->TxnCommit(); + bool res = m_batch->TxnCommit(); + if (res) { + for (const auto& listener : m_txn_listeners) { + listener.on_commit(); + } + // txn finished, clear listeners + m_txn_listeners.clear(); + } + return res; } bool WalletBatch::TxnAbort() { - return m_batch->TxnAbort(); + bool res = m_batch->TxnAbort(); + if (res) { + for (const auto& listener : m_txn_listeners) { + listener.on_abort(); + } + // txn finished, clear listeners + m_txn_listeners.clear(); + } + return res; +} + +void WalletBatch::RegisterTxnListener(const DbTxnListener& l) +{ + assert(m_batch->HasActiveTxn()); + m_txn_listeners.emplace_back(l); } std::unique_ptr MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error) diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index bffcc87202a..32c3c29b5e3 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -180,6 +180,11 @@ public: } }; +struct DbTxnListener +{ + std::function on_commit, on_abort; +}; + /** Access to the wallet database. * Opens the database and provides read and write access to it. Each read and write is its own transaction. * Multiple operation transactions can be started using TxnBegin() and committed using TxnCommit() @@ -292,9 +297,18 @@ public: bool TxnCommit(); //! Abort current transaction bool TxnAbort(); + bool HasActiveTxn() { return m_batch->HasActiveTxn(); } + + //! Registers db txn callback functions + void RegisterTxnListener(const DbTxnListener& l); + private: std::unique_ptr m_batch; WalletDatabase& m_database; + + // External functions listening to the current db txn outcome. + // Listeners are cleared at the end of the transaction. + std::vector m_txn_listeners; }; /**