Port smessage to RocksDB, make RocksDB a hard dep

The secure-messaging store (smsgDB) used the LevelDB API directly. Mass-
mapped to the equivalent RocksDB types: leveldb::DB/Status/WriteBatch/
Iterator/Slice/ReadOptions/WriteOptions/WriteBatch::Handler -> rocksdb::*.
The RocksDB API surface for our usage is binary-compatible — pure namespace
substitution, no semantic changes. Consumers in rpcsmessage.cpp and
qt/messagemodel.cpp updated to match.

RocksDB now becomes a hard build dependency (was optional behind
BUILD_ROCKSDB). The chain-DB rocksdb backend is consequently always
available; -chaindb=leveldb remains the default until the Phase-4
LevelDB retirement. Removed the BUILD_ROCKSDB cmake option, the
#ifdef BUILD_ROCKSDB guards in txdb*, and the runtime error path
that triggered when the flag was off.

CI updated: librocksdb-dev (Ubuntu), mingw-w64-x86_64-rocksdb (MSYS2),
and rocksdb (Homebrew) added to all build jobs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-26 18:11:00 -07:00
parent 03073bd597
commit 59ee532bf6
14 changed files with 74 additions and 107 deletions
+7 -5
View File
@@ -20,7 +20,7 @@ jobs:
sudo apt-get update
sudo apt-get install -y build-essential cmake ninja-build \
libboost-all-dev libssl-dev libdb++-dev libleveldb-dev \
libevent-dev libminiupnpc-dev zlib1g-dev
librocksdb-dev libevent-dev libminiupnpc-dev zlib1g-dev
- name: Configure
run: |
@@ -60,7 +60,7 @@ jobs:
sudo apt-get update
sudo apt-get install -y build-essential cmake ninja-build \
libboost-all-dev libssl-dev libdb++-dev libleveldb-dev \
libevent-dev libminiupnpc-dev zlib1g-dev
librocksdb-dev libevent-dev libminiupnpc-dev zlib1g-dev
- name: Configure with sanitizers
run: |
@@ -105,6 +105,7 @@ jobs:
mingw-w64-x86_64-libevent
mingw-w64-x86_64-miniupnpc
mingw-w64-x86_64-zlib
mingw-w64-x86_64-rocksdb
- name: Set VERSION
run: |
@@ -253,6 +254,7 @@ jobs:
mingw-w64-x86_64-libevent
mingw-w64-x86_64-miniupnpc
mingw-w64-x86_64-zlib
mingw-w64-x86_64-rocksdb
- name: Configure
run: |
@@ -318,7 +320,7 @@ jobs:
sudo apt-get install -y build-essential cmake ninja-build \
qtbase5-dev qttools5-dev-tools \
libboost-all-dev libssl-dev libdb++-dev \
libleveldb-dev libevent-dev libminiupnpc-dev zlib1g-dev
libleveldb-dev librocksdb-dev libevent-dev libminiupnpc-dev zlib1g-dev
- name: Configure
run: |
@@ -434,7 +436,7 @@ jobs:
sudo apt-get update
sudo apt-get install -y build-essential cmake ninja-build \
libboost-all-dev libssl-dev libdb++-dev libleveldb-dev \
libevent-dev libminiupnpc-dev zlib1g-dev
librocksdb-dev libevent-dev libminiupnpc-dev zlib1g-dev
- name: Configure
run: |
@@ -561,7 +563,7 @@ jobs:
- name: Install dependencies
run: |
brew install cmake ninja qt@5 openssl@3 boost berkeley-db@5 leveldb libevent miniupnpc
brew install cmake ninja qt@5 openssl@3 boost berkeley-db@5 leveldb rocksdb libevent miniupnpc
- name: Configure
run: |
+1 -1
View File
@@ -55,7 +55,7 @@ jobs:
sudo apt-get update
sudo apt-get install -y build-essential cmake ninja-build clang-tidy-15 \
libboost-all-dev libssl-dev libdb++-dev libleveldb-dev \
libevent-dev libminiupnpc-dev zlib1g-dev
librocksdb-dev libevent-dev libminiupnpc-dev zlib1g-dev
sudo ln -sf /usr/bin/clang-tidy-15 /usr/local/bin/clang-tidy
- name: Configure (export compile_commands.json)
+7 -12
View File
@@ -52,7 +52,6 @@ option(USE_QRCODE "Enable QR code generation via libqrencode" OFF
option(USE_DBUS "Enable D-Bus notifications (Linux only)" ON)
option(USE_ZMQ "Enable ZMQ publisher support" OFF)
option(USE_TOR_EMBEDDED "Enable embedded Tor library linking" OFF)
option(BUILD_ROCKSDB "Build with RocksDB chain database backend" OFF)
option(USE_O3 "Use -O3 optimization instead of -O2" OFF)
option(ENABLE_PIE "Build position-independent executables" OFF)
option(ENABLE_STATIC "Prefer static linking (Linux release builds)" OFF)
@@ -96,16 +95,13 @@ if(USE_ZMQ)
pkg_check_modules(ZMQ REQUIRED IMPORTED_TARGET libzmq)
endif()
if(BUILD_ROCKSDB)
# RocksDB ships a CMake config package on most distros (rocksdbConfig.cmake).
# On MSYS2/Homebrew/vcpkg the imported target is RocksDB::rocksdb.
find_package(RocksDB CONFIG)
if(NOT RocksDB_FOUND)
# Fall back to pkg-config for systems without the CMake config (older
# Linux distros). Builds an IMPORTED target named PkgConfig::RocksDB.
find_package(PkgConfig REQUIRED)
pkg_check_modules(RocksDB REQUIRED IMPORTED_TARGET rocksdb)
endif()
# RocksDB is now a hard dependency: backs both the chain database and the
# secure-messaging store (smessage). On MSYS2/Homebrew/vcpkg the imported
# target is RocksDB::rocksdb; on older Linux distros we fall back to pkg-config.
find_package(RocksDB CONFIG)
if(NOT RocksDB_FOUND)
find_package(PkgConfig REQUIRED)
pkg_check_modules(RocksDB REQUIRED IMPORTED_TARGET rocksdb)
endif()
if(BUILD_QT)
@@ -143,7 +139,6 @@ message(STATUS " QR code: ${USE_QRCODE}")
message(STATUS " D-Bus: ${USE_DBUS}")
message(STATUS " ZMQ: ${USE_ZMQ}")
message(STATUS " Embedded Tor: ${USE_TOR_EMBEDDED}")
message(STATUS " RocksDB backend: ${BUILD_ROCKSDB}")
message(STATUS " Static linking: ${ENABLE_STATIC}")
message(STATUS " ccache: ${CCACHE_PROGRAM}")
message(STATUS " Unity build: ${ENABLE_UNITY_BUILD}")
+3 -3
View File
@@ -5,13 +5,13 @@ Measures `FastImportBlockFile()` speed under each chain-DB backend
## Prerequisites
- A `trianglesd` binary built with both backends:
- A `trianglesd` binary (RocksDB is now a hard build dep, both backends are
always available):
```
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_QT=OFF \
-DBUILD_DAEMON=ON \
-DBUILD_ROCKSDB=ON
-DBUILD_DAEMON=ON
cmake --build build
```
- An `blk0001.dat` file (old-style block stream). If you have a synced
+1 -1
View File
@@ -17,7 +17,7 @@
# [--rpc-port=BASE] default 19112; each run uses BASE+offset
#
# Notes:
# - The binary must be built with BUILD_ROCKSDB=ON when --backends includes rocksdb.
# - RocksDB is a hard build dep, so any current trianglesd has both backends.
# - This script does not assume Tor is configured. It launches with -nolisten
# and -connect=0 to keep the run network-isolated.
# - Wall time comes from the daemon's own perf log line:
+8 -12
View File
@@ -97,10 +97,9 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|ARM")
list(APPEND CORE_SOURCES scrypt-arm.S)
endif()
# Optional: RocksDB chain database backend
if(BUILD_ROCKSDB)
list(APPEND CORE_SOURCES txdb-rocksdb.cpp)
endif()
# RocksDB chain database backend (always built; see top-level CMakeLists.txt
# for the rationale — RocksDB also backs the smessage store).
list(APPEND CORE_SOURCES txdb-rocksdb.cpp)
add_library(triangles_common OBJECT ${CORE_SOURCES})
@@ -148,14 +147,11 @@ if(USE_ZMQ)
target_link_libraries(triangles_common PUBLIC PkgConfig::ZMQ)
endif()
# Optional: RocksDB
if(BUILD_ROCKSDB)
target_compile_definitions(triangles_common PUBLIC BUILD_ROCKSDB)
if(TARGET RocksDB::rocksdb)
target_link_libraries(triangles_common PUBLIC RocksDB::rocksdb)
elseif(TARGET PkgConfig::RocksDB)
target_link_libraries(triangles_common PUBLIC PkgConfig::RocksDB)
endif()
# RocksDB (mandatory)
if(TARGET RocksDB::rocksdb)
target_link_libraries(triangles_common PUBLIC RocksDB::rocksdb)
elseif(TARGET PkgConfig::RocksDB)
target_link_libraries(triangles_common PUBLIC PkgConfig::RocksDB)
endif()
# Optional: Embedded Tor
+2 -2
View File
@@ -93,7 +93,7 @@ public:
QDateTime received_datetime;
std::string sPrefix("im");
leveldb::Iterator* it = dbSmsg.pdb->NewIterator(leveldb::ReadOptions());
rocksdb::Iterator* it = dbSmsg.pdb->NewIterator(rocksdb::ReadOptions());
while (dbSmsg.NextSmesg(it, sPrefix, chKey, smsgStored))
{
uint32_t nPayload = smsgStored.vchMessage.size() - SMSG_HDR_LEN;
@@ -121,7 +121,7 @@ public:
delete it;
sPrefix = "sm";
it = dbSmsg.pdb->NewIterator(leveldb::ReadOptions());
it = dbSmsg.pdb->NewIterator(rocksdb::ReadOptions());
while (dbSmsg.NextSmesg(it, sPrefix, chKey, smsgStored))
{
uint32_t nPayload = smsgStored.vchMessage.size() - SMSG_HDR_LEN;
+5 -5
View File
@@ -609,7 +609,7 @@ Value smsginbox(const Array& params, bool fHelp)
{
dbInbox.TxnBegin();
leveldb::Iterator* it = dbInbox.pdb->NewIterator(leveldb::ReadOptions());
rocksdb::Iterator* it = dbInbox.pdb->NewIterator(rocksdb::ReadOptions());
while (dbInbox.NextSmesgKey(it, sPrefix, chKey))
{
dbInbox.EraseSmesg(chKey);
@@ -631,7 +631,7 @@ Value smsginbox(const Array& params, bool fHelp)
dbInbox.TxnBegin();
leveldb::Iterator* it = dbInbox.pdb->NewIterator(leveldb::ReadOptions());
rocksdb::Iterator* it = dbInbox.pdb->NewIterator(rocksdb::ReadOptions());
while (dbInbox.NextSmesg(it, sPrefix, chKey, smsgStored))
{
if (fCheckReadStatus
@@ -719,7 +719,7 @@ Value smsgoutbox(const Array& params, bool fHelp)
{
dbOutbox.TxnBegin();
leveldb::Iterator* it = dbOutbox.pdb->NewIterator(leveldb::ReadOptions());
rocksdb::Iterator* it = dbOutbox.pdb->NewIterator(rocksdb::ReadOptions());
while (dbOutbox.NextSmesgKey(it, sPrefix, chKey))
{
dbOutbox.EraseSmesg(chKey);
@@ -736,7 +736,7 @@ Value smsgoutbox(const Array& params, bool fHelp)
{
SecMsgStored smsgStored;
MessageData msg;
leveldb::Iterator* it = dbOutbox.pdb->NewIterator(leveldb::ReadOptions());
rocksdb::Iterator* it = dbOutbox.pdb->NewIterator(rocksdb::ReadOptions());
while (dbOutbox.NextSmesg(it, sPrefix, chKey, smsgStored))
{
uint32_t nPayload = smsgStored.vchMessage.size() - SMSG_HDR_LEN;
@@ -932,7 +932,7 @@ Value smsgbroadcast(const Array& params, bool fHelp)
// Iterate all "pk" entries
std::string sPrefix("pk");
leveldb::Iterator* it = dbPub.pdb->NewIterator(leveldb::ReadOptions());
rocksdb::Iterator* it = dbPub.pdb->NewIterator(rocksdb::ReadOptions());
for (it->Seek(sPrefix); it->Valid(); it->Next())
{
std::string key = it->key().ToString();
+30 -30
View File
@@ -94,7 +94,7 @@ uint32_t nPeerIdCounter = 1;
CCriticalSection cs_smsg;
CCriticalSection cs_smsgDB;
leveldb::DB *smsgDB = NULL;
rocksdb::DB *smsgDB = NULL;
namespace fs = std::filesystem;
@@ -401,9 +401,9 @@ bool SecMsgDB::Open(const char* pszMode)
return false;
};
leveldb::Options options;
rocksdb::Options options;
options.create_if_missing = fCreate;
leveldb::Status s = leveldb::DB::Open(options, fullpath.string(), &smsgDB);
rocksdb::Status s = rocksdb::DB::Open(options, fullpath.string(), &smsgDB);
if (!s.ok())
{
@@ -417,17 +417,17 @@ bool SecMsgDB::Open(const char* pszMode)
};
class SecMsgBatchScanner : public leveldb::WriteBatch::Handler
class SecMsgBatchScanner : public rocksdb::WriteBatch::Handler
{
public:
std::string needle;
bool* deleted;
std::string* foundValue;
bool foundEntry;
SecMsgBatchScanner() : foundEntry(false) {}
virtual void Put(const leveldb::Slice& key, const leveldb::Slice& value)
virtual void Put(const rocksdb::Slice& key, const rocksdb::Slice& value) override
{
if (key.ToString() == needle)
{
@@ -436,8 +436,8 @@ public:
*foundValue = value.ToString();
};
};
virtual void Delete(const leveldb::Slice& key)
virtual void Delete(const rocksdb::Slice& key) override
{
if (key.ToString() == needle)
{
@@ -462,7 +462,7 @@ bool SecMsgDB::ScanBatch(const CDataStream& key, std::string* value, bool* delet
scanner.needle = key.str();
scanner.deleted = deleted;
scanner.foundValue = value;
leveldb::Status s = activeBatch->Iterate(&scanner);
rocksdb::Status s = activeBatch->Iterate(&scanner);
if (!s.ok())
{
printf("SecMsgDB ScanBatch error: %s\n", s.ToString().c_str());
@@ -476,7 +476,7 @@ bool SecMsgDB::TxnBegin()
{
if (activeBatch)
return true;
activeBatch = new leveldb::WriteBatch();
activeBatch = new rocksdb::WriteBatch();
return true;
};
@@ -484,10 +484,10 @@ bool SecMsgDB::TxnCommit()
{
if (!activeBatch)
return false;
leveldb::WriteOptions writeOptions;
rocksdb::WriteOptions writeOptions;
writeOptions.sync = true;
leveldb::Status status = pdb->Write(writeOptions, activeBatch);
rocksdb::Status status = pdb->Write(writeOptions, activeBatch);
delete activeBatch;
activeBatch = NULL;
@@ -531,12 +531,12 @@ bool SecMsgDB::ReadPK(CKeyID& addr, CPubKey& pubkey)
if (readFromDb)
{
leveldb::Status s = pdb->Get(leveldb::ReadOptions(), ssKey.str(), &strValue);
rocksdb::Status s = pdb->Get(rocksdb::ReadOptions(), ssKey.str(), &strValue);
if (!s.ok())
{
if (s.IsNotFound())
return false;
printf("LevelDB read failure: %s\n", s.ToString().c_str());
printf("RocksDB read failure: %s\n", s.ToString().c_str());
return false;
};
};
@@ -572,9 +572,9 @@ bool SecMsgDB::WritePK(CKeyID& addr, CPubKey& pubkey)
return true;
};
leveldb::WriteOptions writeOptions;
rocksdb::WriteOptions writeOptions;
writeOptions.sync = true;
leveldb::Status s = pdb->Put(writeOptions, ssKey.str(), ssValue.str());
rocksdb::Status s = pdb->Put(writeOptions, ssKey.str(), ssValue.str());
if (!s.ok())
{
printf("SecMsgDB write failure: %s\n", s.ToString().c_str());
@@ -605,12 +605,12 @@ bool SecMsgDB::ExistsPK(CKeyID& addr)
};
};
leveldb::Status s = pdb->Get(leveldb::ReadOptions(), ssKey.str(), &unused);
rocksdb::Status s = pdb->Get(rocksdb::ReadOptions(), ssKey.str(), &unused);
return s.IsNotFound() == false;
};
bool SecMsgDB::NextSmesg(leveldb::Iterator* it, std::string& prefix, unsigned char* chKey, SecMsgStored& smsgStored)
bool SecMsgDB::NextSmesg(rocksdb::Iterator* it, std::string& prefix, unsigned char* chKey, SecMsgStored& smsgStored)
{
if (!pdb)
return false;
@@ -638,7 +638,7 @@ bool SecMsgDB::NextSmesg(leveldb::Iterator* it, std::string& prefix, unsigned ch
return true;
};
bool SecMsgDB::NextSmesgKey(leveldb::Iterator* it, std::string& prefix, unsigned char* chKey)
bool SecMsgDB::NextSmesgKey(rocksdb::Iterator* it, std::string& prefix, unsigned char* chKey)
{
if (!pdb)
return false;
@@ -679,12 +679,12 @@ bool SecMsgDB::ReadSmesg(unsigned char* chKey, SecMsgStored& smsgStored)
if (readFromDb)
{
leveldb::Status s = pdb->Get(leveldb::ReadOptions(), ssKey.str(), &strValue);
rocksdb::Status s = pdb->Get(rocksdb::ReadOptions(), ssKey.str(), &strValue);
if (!s.ok())
{
if (s.IsNotFound())
return false;
printf("LevelDB read failure: %s\n", s.ToString().c_str());
printf("RocksDB read failure: %s\n", s.ToString().c_str());
return false;
};
};
@@ -716,9 +716,9 @@ bool SecMsgDB::WriteSmesg(unsigned char* chKey, SecMsgStored& smsgStored)
return true;
};
leveldb::WriteOptions writeOptions;
rocksdb::WriteOptions writeOptions;
writeOptions.sync = true;
leveldb::Status s = pdb->Put(writeOptions, ssKey.str(), ssValue.str());
rocksdb::Status s = pdb->Put(writeOptions, ssKey.str(), ssValue.str());
if (!s.ok())
{
printf("SecMsgDB write failed: %s\n", s.ToString().c_str());
@@ -746,7 +746,7 @@ bool SecMsgDB::ExistsSmesg(unsigned char* chKey)
};
};
leveldb::Status s = pdb->Get(leveldb::ReadOptions(), ssKey.str(), &unused);
rocksdb::Status s = pdb->Get(rocksdb::ReadOptions(), ssKey.str(), &unused);
return s.IsNotFound() == false;
return true;
};
@@ -762,9 +762,9 @@ bool SecMsgDB::EraseSmesg(unsigned char* chKey)
return true;
};
leveldb::WriteOptions writeOptions;
rocksdb::WriteOptions writeOptions;
writeOptions.sync = true;
leveldb::Status s = pdb->Delete(writeOptions, ssKey.str());
rocksdb::Status s = pdb->Delete(writeOptions, ssKey.str());
if (s.ok() || s.IsNotFound())
return true;
@@ -881,7 +881,7 @@ void ThreadSecureMsgPow(void* parg)
// -- sleep at end, then fSecMsgEnabled is tested on wake
SecMsgDB dbOutbox;
leveldb::Iterator* it;
rocksdb::Iterator* it;
{
LOCK(cs_smsgDB);
@@ -889,7 +889,7 @@ void ThreadSecureMsgPow(void* parg)
continue;
// -- fifo (smallest key first)
it = dbOutbox.pdb->NewIterator(leveldb::ReadOptions());
it = dbOutbox.pdb->NewIterator(rocksdb::ReadOptions());
}
// -- break up lock, SecureMsgSetHash will take long
+6 -6
View File
@@ -4,8 +4,8 @@
#ifndef SEC_MESSAGE_H
#define SEC_MESSAGE_H
#include <leveldb/db.h>
#include <leveldb/write_batch.h>
#include <rocksdb/db.h>
#include <rocksdb/write_batch.h>
#include "net.h"
#include "db.h"
@@ -314,15 +314,15 @@ public:
bool WritePK(CKeyID& addr, CPubKey& pubkey);
bool ExistsPK(CKeyID& addr);
bool NextSmesg(leveldb::Iterator* it, std::string& prefix, unsigned char* vchKey, SecMsgStored& smsgStored);
bool NextSmesgKey(leveldb::Iterator* it, std::string& prefix, unsigned char* vchKey);
bool NextSmesg(rocksdb::Iterator* it, std::string& prefix, unsigned char* vchKey, SecMsgStored& smsgStored);
bool NextSmesgKey(rocksdb::Iterator* it, std::string& prefix, unsigned char* vchKey);
bool ReadSmesg(unsigned char* chKey, SecMsgStored& smsgStored);
bool WriteSmesg(unsigned char* chKey, SecMsgStored& smsgStored);
bool ExistsSmesg(unsigned char* chKey);
bool EraseSmesg(unsigned char* chKey);
leveldb::DB *pdb; // points to the global instance
leveldb::WriteBatch *activeBatch;
rocksdb::DB *pdb; // points to the global instance
rocksdb::WriteBatch *activeBatch;
};
+2 -17
View File
@@ -24,25 +24,12 @@ ChainDbKind ResolveChainDbKind()
if (s == "leveldb")
return ChainDbKind::LevelDB;
if (s == "rocksdb") {
#ifdef BUILD_ROCKSDB
if (s == "rocksdb")
return ChainDbKind::RocksDB;
#else
throw std::runtime_error(
"-chaindb=rocksdb requested but this binary was built without "
"BUILD_ROCKSDB. Rebuild with -DBUILD_ROCKSDB=ON, or use "
"-chaindb=leveldb.");
#endif
}
throw std::runtime_error(
"-chaindb=" + s + " is not a recognized backend. "
"Valid values: leveldb"
#ifdef BUILD_ROCKSDB
", rocksdb"
#endif
".");
"Valid values: leveldb, rocksdb.");
}();
return kKind;
}
@@ -54,10 +41,8 @@ std::unique_ptr<CTxDBBase> MakeChainDB(const char* pszMode)
switch (ResolveChainDbKind()) {
case ChainDbKind::LevelDB:
return std::unique_ptr<CTxDBBase>(new CTxDB(pszMode));
#ifdef BUILD_ROCKSDB
case ChainDbKind::RocksDB:
return std::unique_ptr<CTxDBBase>(new CRocksTxDB(pszMode));
#endif
}
// Unreachable — ResolveChainDbKind throws on bad input.
return nullptr;
-4
View File
@@ -2,8 +2,6 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifdef BUILD_ROCKSDB
#include "txdb-rocksdb.h"
#include <map>
@@ -698,5 +696,3 @@ bool CRocksTxDB::LoadBlockIndex()
return true;
}
#endif // BUILD_ROCKSDB
-4
View File
@@ -5,8 +5,6 @@
#ifndef TRIANGLES_TXDB_ROCKSDB_H
#define TRIANGLES_TXDB_ROCKSDB_H
#ifdef BUILD_ROCKSDB
#include "txdb-base.h"
#include <rocksdb/db.h>
@@ -52,6 +50,4 @@ private:
bool ScanBatch(const std::string& key, std::string* value, bool* deleted) const;
};
#endif // BUILD_ROCKSDB
#endif // TRIANGLES_TXDB_ROCKSDB_H
+2 -5
View File
@@ -9,18 +9,15 @@
#include "txdb-base.h"
#include "txdb-leveldb.h"
#ifdef BUILD_ROCKSDB
#include "txdb-rocksdb.h"
#endif
#include <memory>
// Factory: returns a chain-database handle whose concrete backend is chosen
// by the -chaindb command-line argument:
//
// -chaindb=leveldb (default)
// -chaindb=rocksdb (only when built with -DBUILD_ROCKSDB=ON)
// -chaindb=leveldb (default — pending Phase-4 retirement)
// -chaindb=rocksdb
//
// Callers receive a CTxDBBase*, so the rest of the codebase stays
// backend-agnostic. Mode strings ("r", "r+", "cr+") match the pre-existing