Skip to content

Commit 2e03201

Browse files
committed
Wire THE checkpoint creation into node layer
TheCheckpointStore now created from same LevelDB as found blocks. On every block found (parent or merged), checkpoint_create_fn: - Captures current the_state_root from cached work - Records sharechain_height, miner_count, hashrate_class - Persists to LevelDB with "thecp:" key prefix REST endpoints wired with actual callbacks: GET /checkpoint — scans tLTC/LTC/DOGE chains for latest verified GET /checkpoints — returns all stored checkpoints with status MiningInterface caches sharechain_height and miner_count alongside the_state_root during refresh_work() for checkpoint metadata. Startup log: "[THE] Checkpoint store enabled (N existing checkpoints)" Block-found log: "[THE] Checkpoint created: chain=X height=Y miners=Z"
1 parent 87169d0 commit 2e03201

3 files changed

Lines changed: 122 additions & 0 deletions

File tree

src/c2pool/c2pool_refactored.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <core/settings.hpp>
1515
#include <core/fileconfig.hpp>
1616
#include <core/coinbase_builder.hpp>
17+
#include <c2pool/storage/the_checkpoint.hpp>
1718
#include <core/pack.hpp>
1819
#include <core/filesystem.hpp>
1920
#include <core/log.hpp>
@@ -1221,6 +1222,104 @@ int main(int argc, char* argv[]) {
12211222
);
12221223
mi->load_persisted_found_blocks();
12231224
LOG_INFO << "[Pool] Found block persistence enabled at " << fblk_db_path;
1225+
1226+
// --- THE checkpoint store (shares same LevelDB) ---
1227+
auto the_store = std::make_shared<c2pool::storage::TheCheckpointStore>(*fblk_leveldb);
1228+
1229+
// Checkpoint creation: called on every found block
1230+
mi->set_checkpoint_fns(
1231+
// latest verified checkpoint
1232+
[the_store]() -> nlohmann::json {
1233+
// Try all chains
1234+
for (const auto& chain : {"tLTC", "LTC", "DOGE", "tDOGE"}) {
1235+
auto cp = the_store->get_latest_verified(chain);
1236+
if (cp.has_value()) {
1237+
return nlohmann::json{
1238+
{"chain", cp->chain},
1239+
{"block_height", cp->block_height},
1240+
{"block_hash", cp->block_hash},
1241+
{"the_state_root", cp->the_state_root.GetHex()},
1242+
{"sharechain_height", cp->sharechain_height},
1243+
{"miner_count", cp->miner_count},
1244+
{"hashrate_class", cp->hashrate_class},
1245+
{"timestamp", cp->timestamp},
1246+
{"status", cp->status == 1 ? "verified" : "pending"}
1247+
};
1248+
}
1249+
}
1250+
// Fall back to latest any-status
1251+
for (const auto& chain : {"tLTC", "LTC", "DOGE", "tDOGE"}) {
1252+
auto cp = the_store->get_latest(chain);
1253+
if (cp.has_value()) {
1254+
return nlohmann::json{
1255+
{"chain", cp->chain},
1256+
{"block_height", cp->block_height},
1257+
{"block_hash", cp->block_hash},
1258+
{"the_state_root", cp->the_state_root.GetHex()},
1259+
{"sharechain_height", cp->sharechain_height},
1260+
{"miner_count", cp->miner_count},
1261+
{"hashrate_class", cp->hashrate_class},
1262+
{"timestamp", cp->timestamp},
1263+
{"status", "pending"}
1264+
};
1265+
}
1266+
}
1267+
return nlohmann::json{{"error", "no checkpoints found"}};
1268+
},
1269+
// all checkpoints
1270+
[the_store]() -> nlohmann::json {
1271+
auto all = the_store->load_all();
1272+
nlohmann::json arr = nlohmann::json::array();
1273+
for (const auto& cp : all) {
1274+
arr.push_back({
1275+
{"chain", cp.chain},
1276+
{"block_height", cp.block_height},
1277+
{"block_hash", cp.block_hash},
1278+
{"the_state_root", cp.the_state_root.GetHex()},
1279+
{"sharechain_height", cp.sharechain_height},
1280+
{"miner_count", cp.miner_count},
1281+
{"hashrate_class", cp.hashrate_class},
1282+
{"timestamp", cp.timestamp},
1283+
{"status", cp.status == 1 ? "verified" : (cp.status == 2 ? "mismatch" : "pending")}
1284+
});
1285+
}
1286+
return arr;
1287+
},
1288+
// verify callback (recompute state_root)
1289+
[](const uint256& /*state_root*/, uint32_t /*height*/) -> bool {
1290+
// TODO: recompute from sharechain and compare
1291+
return true; // optimistic until V37
1292+
},
1293+
// create checkpoint on block found
1294+
[the_store, mi](const std::string& chain, uint64_t height,
1295+
const std::string& hash, uint64_t ts) {
1296+
c2pool::storage::TheCheckpoint cp;
1297+
cp.chain = chain;
1298+
cp.block_height = height;
1299+
cp.block_hash = hash;
1300+
cp.timestamp = ts;
1301+
cp.status = 0; // pending
1302+
1303+
// Capture current sharechain state from THE metadata
1304+
// The state_root was already computed in refresh_work()
1305+
// and embedded in the block. We store the same data here.
1306+
auto work = mi->get_current_work();
1307+
if (!work.the_state_root.IsNull())
1308+
cp.the_state_root = work.the_state_root;
1309+
1310+
cp.sharechain_height = work.sharechain_height;
1311+
cp.miner_count = work.miner_count;
1312+
cp.hashrate_class = c2pool::TheMetadata::encode_hashrate(work.pool_hashrate);
1313+
1314+
the_store->store(cp);
1315+
LOG_INFO << "[THE] Checkpoint created: chain=" << chain
1316+
<< " height=" << height
1317+
<< " miners=" << cp.miner_count
1318+
<< " hashrate_class=" << (int)cp.hashrate_class
1319+
<< " state_root=" << cp.the_state_root.GetHex().substr(0, 16) << "...";
1320+
}
1321+
);
1322+
LOG_INFO << "[THE] Checkpoint store enabled (" << the_store->count() << " existing checkpoints)";
12241323
}
12251324
mi->set_block_verify_fn(
12261325
[chain = embedded_chain.get()](const std::string& hash_hex) -> int {

src/core/web_server.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,8 @@ void MiningInterface::refresh_work()
15111511
m_cached_witness_root = witness_root;
15121512
m_cached_mm_commitment = std::move(mm_commitment);
15131513
m_cached_the_state_root = the_root;
1514+
m_cached_sharechain_height = tmpl_h;
1515+
m_cached_miner_count = static_cast<uint16_t>(m_cached_pplns_outputs.size());
15141516
m_cached_mweb = wd.m_data.contains("mweb")
15151517
? wd.m_data["mweb"].get<std::string>() : "";
15161518
m_work_valid = true;

src/core/web_server.hpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,22 @@ class MiningInterface : public jsonrpccxx::JsonRpc2Server
133133
nlohmann::json rest_checkpoint(); // latest verified checkpoint
134134
nlohmann::json rest_checkpoints(); // all checkpoints
135135

136+
// Current work state for THE checkpoint creation
137+
struct CurrentTheState {
138+
uint256 the_state_root;
139+
uint32_t sharechain_height{0};
140+
uint16_t miner_count{0};
141+
double pool_hashrate{0};
142+
};
143+
CurrentTheState get_current_work() const {
144+
CurrentTheState s;
145+
s.the_state_root = m_cached_the_state_root;
146+
s.sharechain_height = m_cached_sharechain_height;
147+
s.miner_count = m_cached_miner_count;
148+
s.pool_hashrate = m_cached_pool_hashrate;
149+
return s;
150+
}
151+
136152
// THE checkpoint management
137153
using checkpoint_store_fn_t = std::function<nlohmann::json()>; // get latest
138154
using checkpoints_all_fn_t = std::function<nlohmann::json()>; // get all
@@ -636,6 +652,11 @@ class MiningInterface : public jsonrpccxx::JsonRpc2Server
636652
// Coinbase scriptSig customization
637653
std::string m_coinbase_text; // empty = "/c2pool/" default tag
638654

655+
// Cached THE state for checkpoint creation (state_root already at line 639)
656+
uint32_t m_cached_sharechain_height{0};
657+
uint16_t m_cached_miner_count{0};
658+
double m_cached_pool_hashrate{0};
659+
639660
// THE checkpoint callbacks (set by node layer)
640661
checkpoint_store_fn_t m_checkpoint_latest_fn;
641662
checkpoints_all_fn_t m_checkpoints_all_fn;

0 commit comments

Comments
 (0)