wallet: Add GetPrefixCursor to DatabaseBatch

In order to get records beginning with a prefix, we will need a cursor
specifically for that prefix. So add a GetPrefixCursor function and
DatabaseCursor classes for dealing with those prefixes.

Tested on each supported db engine.

1) Write two different key->value elements to db.
2) Create a new prefix cursor and walk-through every returned element,
   verifying that it gets parsed properly.
3) Try to move the cursor outside the filtered range: expect failure
   and flag complete=true.

Co-Authored-By: Ryan Ofsky <ryan@ofsky.org>
Co-Authored-By: furszy <matiasfurszyfer@protonmail.com>
This commit is contained in:
Andrew Chow
2022-04-11 17:11:37 -04:00
committed by Andrew Chow
parent 1d858b055d
commit ba616b932c
10 changed files with 239 additions and 15 deletions

View File

@@ -48,14 +48,17 @@ std::string getnewaddress(CWallet& w);
/** Returns a new destination, of an specific type, from the wallet */
CTxDestination getNewDestination(CWallet& w, OutputType output_type);
using MockableData = std::map<SerializeData, SerializeData, std::less<>>;
class MockableCursor: public DatabaseCursor
{
public:
std::map<SerializeData, SerializeData>::const_iterator m_cursor;
std::map<SerializeData, SerializeData>::const_iterator m_cursor_end;
MockableData::const_iterator m_cursor;
MockableData::const_iterator m_cursor_end;
bool m_pass;
explicit MockableCursor(const std::map<SerializeData, SerializeData>& records, bool pass) : m_cursor(records.begin()), m_cursor_end(records.end()), m_pass(pass) {}
explicit MockableCursor(const MockableData& records, bool pass) : m_cursor(records.begin()), m_cursor_end(records.end()), m_pass(pass) {}
MockableCursor(const MockableData& records, bool pass, Span<const std::byte> prefix);
~MockableCursor() {}
Status Next(DataStream& key, DataStream& value) override;
@@ -64,7 +67,7 @@ public:
class MockableBatch : public DatabaseBatch
{
private:
std::map<SerializeData, SerializeData>& m_records;
MockableData& m_records;
bool m_pass;
bool ReadKey(DataStream&& key, DataStream& value) override;
@@ -74,7 +77,7 @@ private:
bool ErasePrefix(Span<const std::byte> prefix) override;
public:
explicit MockableBatch(std::map<SerializeData, SerializeData>& records, bool pass) : m_records(records), m_pass(pass) {}
explicit MockableBatch(MockableData& records, bool pass) : m_records(records), m_pass(pass) {}
~MockableBatch() {}
void Flush() override {}
@@ -84,6 +87,9 @@ public:
{
return std::make_unique<MockableCursor>(m_records, m_pass);
}
std::unique_ptr<DatabaseCursor> GetNewPrefixCursor(Span<const std::byte> prefix) override {
return std::make_unique<MockableCursor>(m_records, m_pass, prefix);
}
bool TxnBegin() override { return m_pass; }
bool TxnCommit() override { return m_pass; }
bool TxnAbort() override { return m_pass; }
@@ -94,10 +100,10 @@ public:
class MockableDatabase : public WalletDatabase
{
public:
std::map<SerializeData, SerializeData> m_records;
MockableData m_records;
bool m_pass{true};
MockableDatabase(std::map<SerializeData, SerializeData> records = {}) : WalletDatabase(), m_records(records) {}
MockableDatabase(MockableData records = {}) : WalletDatabase(), m_records(records) {}
~MockableDatabase() {};
void Open() override {}
@@ -117,7 +123,7 @@ public:
std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override { return std::make_unique<MockableBatch>(m_records, m_pass); }
};
std::unique_ptr<WalletDatabase> CreateMockableWalletDatabase(std::map<SerializeData, SerializeData> records = {});
std::unique_ptr<WalletDatabase> CreateMockableWalletDatabase(MockableData records = {});
MockableDatabase& GetMockableDatabase(CWallet& wallet);
} // namespace wallet