test: Make duplicating MockableDatabases use cursor and batch
What changed, and why it matters
This is a test-only code change. It refactors how a fake in-memory wallet database is copied during unit tests so that the copy uses the same cursor-and-batch interface a real database would use. There is no change to production wallet code, no user-facing behavior change, and no security fix or vulnerability.
No security action needed. Review as normal test refactoring if desired.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit modifies src/wallet/test/util.cpp and src/wallet/test/util.h. DuplicateMockDatabase now creates a fresh MockableDatabase and copies records by iterating with a DatabaseCursor and writing via a DatabaseBatch, rather than directly copying the underlying std::map. CreateMockableWalletDatabase loses its optional initial-records parameter, and MockableBatch’s interface methods are moved from private to public so the test helper can call WriteKey directly. These changes are preparation for a future SQLite-backed MockableDatabase and affect only test utilities.
Changed components
src/wallet/test/util.cppsrc/wallet/test/util.hMockableDatabase test helperMockableBatch test helperInspect captured patch +27 / −11
diff --git a/src/wallet/test/util.cpp b/src/wallet/test/util.cpp
index 9ee63f6e..9c101d7e 100644
--- a/src/wallet/test/util.cpp
+++ b/src/wallet/test/util.cpp
@@ -105,7 +105,23 @@ void TestUnloadWallet(std::shared_ptr<CWallet>&& wallet)
std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database)
{
- return std::make_unique<MockableDatabase>(dynamic_cast<MockableDatabase&>(database).m_records);
+ std::unique_ptr<DatabaseBatch> batch_orig = database.MakeBatch();
+ std::unique_ptr<DatabaseCursor> cursor_orig = batch_orig->GetNewCursor();
+
+ std::unique_ptr<WalletDatabase> new_db = std::make_unique<MockableDatabase>();
+ std::unique_ptr<DatabaseBatch> new_db_batch = new_db->MakeBatch();
+ MockableBatch* batch_new = dynamic_cast<MockableBatch*>(new_db_batch.get());
+ Assert(batch_new);
+
+ while (true) {
+ DataStream key, value;
+ DatabaseCursor::Status status = cursor_orig->Next(key, value);
+ Assert(status != DatabaseCursor::Status::FAIL);
+ if (status != DatabaseCursor::Status::MORE) break;
+ batch_new->WriteKey(std::move(key), std::move(value));
+ }
+
+ return new_db;
}
std::string getnewaddress(CWallet& w)
@@ -208,9 +224,9 @@ bool MockableBatch::ErasePrefix(std::span<const std::byte> prefix)
return true;
}
-std::unique_ptr<WalletDatabase> CreateMockableWalletDatabase(MockableData records)
+std::unique_ptr<WalletDatabase> CreateMockableWalletDatabase()
{
- return std::make_unique<MockableDatabase>(records);
+ return std::make_unique<MockableDatabase>();
}
MockableDatabase& GetMockableDatabase(CWallet& wallet)
diff --git a/src/wallet/test/util.h b/src/wallet/test/util.h
index d5deba29..f812b0cc 100644
--- a/src/wallet/test/util.h
+++ b/src/wallet/test/util.h
@@ -68,18 +68,18 @@ private:
MockableData& m_records;
bool m_pass;
- bool ReadKey(DataStream&& key, DataStream& value) override;
- bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite=true) override;
- bool EraseKey(DataStream&& key) override;
- bool HasKey(DataStream&& key) override;
- bool ErasePrefix(std::span<const std::byte> prefix) override;
-
public:
explicit MockableBatch(MockableData& records, bool pass) : m_records(records), m_pass(pass) {}
~MockableBatch() = default;
void Close() override {}
+ bool ReadKey(DataStream&& key, DataStream& value) override;
+ bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite=true) override;
+ bool EraseKey(DataStream&& key) override;
+ bool HasKey(DataStream&& key) override;
+ bool ErasePrefix(std::span<const std::byte> prefix) override;
+
std::unique_ptr<DatabaseCursor> GetNewCursor() override
{
return std::make_unique<MockableCursor>(m_records, m_pass);
@@ -101,7 +101,7 @@ public:
MockableData m_records;
bool m_pass{true};
- MockableDatabase(MockableData records = {}) : WalletDatabase(), m_records(records) {}
+ MockableDatabase() : WalletDatabase() {}
~MockableDatabase() = default;
void Open() override {}
@@ -116,7 +116,7 @@ public:
std::unique_ptr<DatabaseBatch> MakeBatch() override { return std::make_unique<MockableBatch>(m_records, m_pass); }
};
-std::unique_ptr<WalletDatabase> CreateMockableWalletDatabase(MockableData records = {});
+std::unique_ptr<WalletDatabase> CreateMockableWalletDatabase();
MockableDatabase& GetMockableDatabase(CWallet& wallet);
DescriptorScriptPubKeyMan* CreateDescriptor(CWallet& keystore, const std::string& desc_str, bool success);
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.