Added redis backend support for storage alternative to empower nextgen observer
This commit is contained in:
+114
-18
@@ -34,6 +34,9 @@
|
||||
#include "json_parsers.h"
|
||||
#include "crypto.h"
|
||||
#include "hardforks/hardforks.h"
|
||||
#ifdef WITH_REDIS
|
||||
#include "redis_storage.h"
|
||||
#endif
|
||||
#include <fstream>
|
||||
|
||||
#if !defined(_MSC_VER) || !defined(__cppcheck__)
|
||||
@@ -3298,51 +3301,143 @@ void SideChain::clear_checkpoints()
|
||||
|
||||
void SideChain::save_checkpoints() const
|
||||
{
|
||||
const std::string path = DATA_DIR + "p2pool_checkpoints.dat";
|
||||
|
||||
#ifdef WITH_REDIS
|
||||
ReadLock lock(m_checkpointsLock);
|
||||
|
||||
|
||||
if (m_checkpoints.empty()) {
|
||||
get_redis_storage().del("checkpoints");
|
||||
return;
|
||||
}
|
||||
|
||||
// Build binary buffer matching file format
|
||||
std::vector<uint8_t> buf;
|
||||
const uint32_t version = 1;
|
||||
const uint32_t count = static_cast<uint32_t>(m_checkpoints.size());
|
||||
|
||||
buf.insert(buf.end(), reinterpret_cast<const uint8_t*>(&version),
|
||||
reinterpret_cast<const uint8_t*>(&version) + sizeof(version));
|
||||
buf.insert(buf.end(), reinterpret_cast<const uint8_t*>(&count),
|
||||
reinterpret_cast<const uint8_t*>(&count) + sizeof(count));
|
||||
|
||||
for (const Checkpoint& cp : m_checkpoints) {
|
||||
buf.insert(buf.end(), reinterpret_cast<const uint8_t*>(&cp.height),
|
||||
reinterpret_cast<const uint8_t*>(&cp.height) + sizeof(cp.height));
|
||||
buf.insert(buf.end(), cp.id.h, cp.id.h + HASH_SIZE);
|
||||
buf.insert(buf.end(), reinterpret_cast<const uint8_t*>(&cp.cumulative_difficulty),
|
||||
reinterpret_cast<const uint8_t*>(&cp.cumulative_difficulty) + sizeof(cp.cumulative_difficulty));
|
||||
}
|
||||
|
||||
if (!get_redis_storage().set("checkpoints", buf.data(), buf.size())) {
|
||||
LOGWARN(1, "Failed to save checkpoints to Redis");
|
||||
return;
|
||||
}
|
||||
LOGINFO(3, "Saved " << count << " checkpoints to Redis");
|
||||
#else
|
||||
const std::string path = DATA_DIR + "p2pool_checkpoints.dat";
|
||||
|
||||
ReadLock lock(m_checkpointsLock);
|
||||
|
||||
if (m_checkpoints.empty()) {
|
||||
// No checkpoints to save, remove old file if exists
|
||||
remove(path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
std::ofstream f(path, std::ios::binary);
|
||||
if (!f.is_open()) {
|
||||
LOGWARN(1, "Failed to save checkpoints to " << path);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Write version marker for future compatibility
|
||||
const uint32_t version = 1;
|
||||
f.write(reinterpret_cast<const char*>(&version), sizeof(version));
|
||||
|
||||
|
||||
// Write checkpoint count
|
||||
const uint32_t count = static_cast<uint32_t>(m_checkpoints.size());
|
||||
f.write(reinterpret_cast<const char*>(&count), sizeof(count));
|
||||
|
||||
|
||||
// Write each checkpoint
|
||||
for (const Checkpoint& cp : m_checkpoints) {
|
||||
f.write(reinterpret_cast<const char*>(&cp.height), sizeof(cp.height));
|
||||
f.write(reinterpret_cast<const char*>(cp.id.h), HASH_SIZE);
|
||||
f.write(reinterpret_cast<const char*>(&cp.cumulative_difficulty), sizeof(cp.cumulative_difficulty));
|
||||
}
|
||||
|
||||
|
||||
f.close();
|
||||
LOGINFO(3, "Saved " << count << " checkpoints to " << path);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SideChain::load_checkpoints()
|
||||
{
|
||||
#ifdef WITH_REDIS
|
||||
std::vector<uint8_t> buf;
|
||||
if (!get_redis_storage().get("checkpoints", buf)) {
|
||||
LOGINFO(3, "No checkpoints found in Redis (normal for first run)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (buf.size() < 8) {
|
||||
LOGWARN(1, "Checkpoint data too small, ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t offset = 0;
|
||||
|
||||
// Read version
|
||||
uint32_t version = *reinterpret_cast<const uint32_t*>(buf.data() + offset);
|
||||
offset += sizeof(version);
|
||||
if (version != 1) {
|
||||
LOGWARN(1, "Unknown checkpoint version " << version << ", ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
// Read count
|
||||
uint32_t count = *reinterpret_cast<const uint32_t*>(buf.data() + offset);
|
||||
offset += sizeof(count);
|
||||
if (count > 100) {
|
||||
LOGWARN(1, "Suspicious checkpoint count " << count << ", ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
WriteLock lock(m_checkpointsLock);
|
||||
m_checkpoints.clear();
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (offset + sizeof(uint64_t) + HASH_SIZE + sizeof(difficulty_type) > buf.size()) {
|
||||
LOGWARN(1, "Checkpoint data corrupted at entry " << i << ", discarding");
|
||||
m_checkpoints.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
Checkpoint cp;
|
||||
memcpy(&cp.height, buf.data() + offset, sizeof(cp.height));
|
||||
offset += sizeof(cp.height);
|
||||
memcpy(cp.id.h, buf.data() + offset, HASH_SIZE);
|
||||
offset += HASH_SIZE;
|
||||
memcpy(&cp.cumulative_difficulty, buf.data() + offset, sizeof(cp.cumulative_difficulty));
|
||||
offset += sizeof(cp.cumulative_difficulty);
|
||||
|
||||
m_checkpoints.push_back(cp);
|
||||
}
|
||||
|
||||
LOGINFO(1, "Loaded " << count << " checkpoints from Redis");
|
||||
|
||||
if (!m_checkpoints.empty()) {
|
||||
LOGINFO(1, "Latest anchor point: height " << m_checkpoints.back().height <<
|
||||
", id " << m_checkpoints.back().id);
|
||||
m_checkpointsNeedValidation = true;
|
||||
}
|
||||
#else
|
||||
const std::string path = DATA_DIR + "p2pool_checkpoints.dat";
|
||||
|
||||
|
||||
std::ifstream f(path, std::ios::binary);
|
||||
if (!f.is_open()) {
|
||||
LOGINFO(3, "No checkpoint file found at " << path << " (normal for first run)");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Read version
|
||||
uint32_t version = 0;
|
||||
f.read(reinterpret_cast<char*>(&version), sizeof(version));
|
||||
@@ -3350,42 +3445,43 @@ void SideChain::load_checkpoints()
|
||||
LOGWARN(1, "Unknown checkpoint file version " << version << ", ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Read checkpoint count
|
||||
uint32_t count = 0;
|
||||
f.read(reinterpret_cast<char*>(&count), sizeof(count));
|
||||
|
||||
|
||||
if (count > 100) {
|
||||
LOGWARN(1, "Checkpoint file has suspicious count " << count << ", ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
WriteLock lock(m_checkpointsLock);
|
||||
m_checkpoints.clear();
|
||||
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
Checkpoint cp;
|
||||
f.read(reinterpret_cast<char*>(&cp.height), sizeof(cp.height));
|
||||
f.read(reinterpret_cast<char*>(cp.id.h), HASH_SIZE);
|
||||
f.read(reinterpret_cast<char*>(&cp.cumulative_difficulty), sizeof(cp.cumulative_difficulty));
|
||||
|
||||
|
||||
if (f.fail()) {
|
||||
LOGWARN(1, "Checkpoint file corrupted at entry " << i << ", discarding");
|
||||
m_checkpoints.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_checkpoints.push_back(cp);
|
||||
}
|
||||
|
||||
|
||||
f.close();
|
||||
LOGINFO(1, "Loaded " << count << " checkpoints from " << path);
|
||||
|
||||
if (!m_checkpoints.empty()) {
|
||||
LOGINFO(1, "Latest anchor point: height " << m_checkpoints.back().height <<
|
||||
LOGINFO(1, "Latest anchor point: height " << m_checkpoints.back().height <<
|
||||
", id " << m_checkpoints.back().id);
|
||||
m_checkpointsNeedValidation = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SideChain::validate_loaded_checkpoints()
|
||||
|
||||
Reference in New Issue
Block a user