From c630899926e824b1eff8a847e77a9f84b9828424 Mon Sep 17 00:00:00 2001 From: Bushstar Date: Fri, 4 Oct 2024 10:36:24 +0100 Subject: [PATCH] Dump CCustomCSView DB to files --- src/dbwrapper.h | 8 +++ src/dfi/rpc_accounts.cpp | 117 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 1d54891ae7..184cf57249 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -189,6 +189,14 @@ class CDBIterator return true; } + leveldb::Slice GetKey() { + return piter->key(); + } + + leveldb::Slice GetValue() { + return piter->value(); + } + unsigned int GetValueSize() { return piter->value().size(); } diff --git a/src/dfi/rpc_accounts.cpp b/src/dfi/rpc_accounts.cpp index b4a064e63e..e766248ffc 100644 --- a/src/dfi/rpc_accounts.cpp +++ b/src/dfi/rpc_accounts.cpp @@ -8,6 +8,8 @@ #include #include +#include + static bool DEFAULT_DVM_OWNERSHIP_CHECK = true; std::string tokenAmountString(const CCustomCSView &view, @@ -3537,6 +3539,120 @@ UniValue getpendingdusdswaps(const JSONRPCRequest &request) { return GetRPCResultCache().Set(request, obj); } +static std::string BytesToHex(const std::vector &data) { + std::ostringstream oss; + for (auto byte : data) { + oss << std::hex << std::setw(2) << std::setfill('0') << static_cast(byte); + } + return oss.str(); +} + +UniValue logdvmstate(const JSONRPCRequest &request) { + RPCHelpMan{ + "logdvmstate", + "Log the full DVM state for debugging.\n", + {}, + RPCResult{"Generates logdvmstate-xxx.log files\n"}, + RPCExamples{HelpExampleCli("logdvmstate", "")}, + } + .Check(request); + + LOCK(cs_main); + + // Flush any pending changes to the DB. Not always written to disk. + pcustomcsview->Flush(); + + // Get the CDBWrapper instance from CCustomCSView + auto db = pcustomcsview->GetStorage().GetStorageLevelDB()->GetDB(); + + // Create a CDBIterator + auto pcursor = db->NewIterator(leveldb::ReadOptions()); + + // File handling variables + const size_t MAX_FILE_SIZE = 1ULL << 30; // 1 GB + size_t fileCounter = 0; + size_t bytesWritten = 0; + std::ofstream outFile; + + // Function to open a new file + auto openNewFile = [&]() -> bool { + if (outFile.is_open()) { + outFile.close(); + } + std::ostringstream fileName; + fileName << "logdvmstate-" << std::setw(3) << std::setfill('0') << fileCounter << ".log"; + outFile.open(fileName.str(), std::ios::out | std::ios::binary); + if (!outFile) { + std::cerr << "Failed to open file: " << fileName.str() << std::endl; + return false; + } + bytesWritten = 0; + fileCounter++; + return true; + }; + + // Open the first file + if (!openNewFile()) { + return {}; + } + + // Seek to the beginning of the database + pcursor->SeekToFirst(); + + // Iterate over all key-value pairs + while (pcursor->Valid()) { + // Get the key and value slices + auto keySlice = pcursor->GetKey(); + auto valueSlice = pcursor->GetValue(); + + // Convert key and value to byte vectors + std::vector vKey(keySlice.data(), keySlice.data() + keySlice.size()); + std::vector vValue(valueSlice.data(), valueSlice.data() + valueSlice.size()); + + if (!vKey.empty()) { + auto &prefix = vKey[0]; + std::string keyPrefixName = BytesToHex({prefix}); + + // Convert the rest of the key + std::string keyRestHex; + if (vKey.size() > 1) { + keyRestHex = BytesToHex(std::vector(vKey.begin() + 1, vKey.end())); + } + + // Convert value + std::string valueHex = BytesToHex(vValue); + + // Prepare output + std::ostringstream oss; + oss << keyPrefixName << " "; + if (!keyRestHex.empty()) { + oss << keyRestHex << " "; + } + oss << valueHex << "\n"; + std::string outputStr = oss.str(); + + // Write to file + outFile << outputStr; + bytesWritten += outputStr.size(); + + // Check file size limit + if (bytesWritten >= MAX_FILE_SIZE) { + if (!openNewFile()) { + return {}; + } + } + } + + pcursor->Next(); + } + + if (outFile.is_open()) { + outFile.close(); + } + + return {}; +} + static const CRPCCommand commands[] = { // category name actor (function) params // ------------- ------------------------ ---------------------- ---------- @@ -3568,6 +3684,7 @@ static const CRPCCommand commands[] = { {"accounts", "listlockedtokens", &listlockedtokens, {} }, {"accounts", "getlockedtokens", &getlockedtokens, {"address"} }, {"accounts", "releaselockedtokens", &releaselockedtokens, {"releasePart"} }, + {"hidden", "logdvmstate", &logdvmstate, {""} }, }; void RegisterAccountsRPCCommands(CRPCTable &tableRPC) {