It’s not immediately obvious to me why we can’t stick to our usual pattern of using a const DataStream& ssKey, CDataStream& ssValue function signature, and instead resort to lambdas as is done here. I think the below code is much more straightforward, but perhaps I’m missing some nuance or drawbacks?
 0diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
 1index 1b2548f262..cb27b739fe 100644
 2--- a/src/dbwrapper.cpp
 3+++ b/src/dbwrapper.cpp
 4@@ -335,11 +335,8 @@ std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const
 5     return ret;
 6 }
 7 
 8-bool CDBWrapper::ReadImpl(std::function<void(DataStream&)> write_key_to_stream, std::function<void(CDataStream&)> read_value_from_stream) const
 9+bool CDBWrapper::ReadImpl(const DataStream& ssKey, CDataStream& ssValue) const
10 {
11-    DataStream ssKey{};
12-    ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
13-    write_key_to_stream(ssKey);
14     leveldb::Slice slKey(CharCast(ssKey.data()), ssKey.size());
15 
16     std::string strValue;
17@@ -351,9 +348,8 @@ bool CDBWrapper::ReadImpl(std::function<void(DataStream&)> write_key_to_stream,
18         HandleError(status);
19     }
20     try {
21-        CDataStream ssValue{MakeByteSpan(strValue), SER_DISK, CLIENT_VERSION};
22+        ssValue << MakeByteSpan(strValue);
23         ssValue.Xor(obfuscate_key);
24-        read_value_from_stream(ssValue);
25     } catch (const std::exception&) {
26         return false;
27     }
28diff --git a/src/dbwrapper.h b/src/dbwrapper.h
29index e48d077a80..e9536b8e7a 100644
30--- a/src/dbwrapper.h
31+++ b/src/dbwrapper.h
32@@ -205,7 +205,7 @@ private:
33     //! whether or not the database resides in memory
34     bool m_is_memory;
35 
36-    bool ReadImpl(std::function<void(DataStream&)> write_key_to_stream, std::function<void(CDataStream&)> read_value_from_stream) const;
37+    bool ReadImpl(const DataStream& ssKey, CDataStream& ssValue) const;
38     bool ExistsImpl(const Span<const std::byte>& key) const;
39     size_t EstimateSizeImpl(const Span<const std::byte>& key1, const Span<const std::byte>& key2) const;
40     auto& DBContext() const { return *Assert(m_db_context); }
41@@ -220,9 +220,16 @@ public:
42     template <typename K, typename V>
43     bool Read(const K& key, V& value) const
44     {
45-        auto write_key_to_stream{[&key](DataStream& ssKey) { ssKey << key; }};
46-        auto read_value_from_stream{[&value](CDataStream& ssValue) { ssValue >> value; }};
47-        return ReadImpl(write_key_to_stream, read_value_from_stream);
48+        DataStream ssKey{};
49+        ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
50+        ssKey << key;
51+
52+        CDataStream ssValue{SER_DISK, CLIENT_VERSION};
53+        if(ReadImpl(ssKey, ssValue)) {
54+            ssValue >> value;
55+            return true;
56+        }
57+        return false;
58     }
59 
60     template <typename K, typename V>