Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/c2pool/c2pool_refactored.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1570,8 +1570,8 @@ int main(int argc, char* argv[]) {
LOG_INFO << "╚══════════════════════════════════════════════════════════════╝";

auto ltc_params = settings->m_testnet
? ltc::coin::LTCChainParams::testnet()
: ltc::coin::LTCChainParams::mainnet();
? ltc::coin::make_ltc_chain_params_testnet()
: ltc::coin::make_ltc_chain_params_mainnet();

// LevelDB-backed header chain for persistence across restarts
// Use absolute path under ~/.c2pool/ (matches sharechain + found_blocks)
Expand Down
109 changes: 3 additions & 106 deletions src/c2pool/storage/sharechain_storage.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "sharechain_storage.hpp"
#include <functional>
#include <impl/ltc/share.hpp>

namespace c2pool {
namespace storage {
Expand Down Expand Up @@ -35,60 +34,7 @@ bool SharechainStorage::is_available() const {
return m_leveldb_store != nullptr;
}

template<typename ShareChainType>
void SharechainStorage::save_sharechain(const ShareChainType& chain)
{
if (!m_leveldb_store) {
LOG_ERROR << "LevelDB store not available";
return;
}

try {
// For now, log that we would save (full integration needs sharechain API)
LOG_INFO << "LevelDB sharechain storage is ready for persistent share storage";
LOG_INFO << " Network: " << m_network_name;
LOG_INFO << " Current stored shares: " << m_leveldb_store->get_share_count();
LOG_INFO << " Storage path: " << m_leveldb_store->get_base_path() << "/" << m_network_name << "/sharechain_leveldb";

} catch (const std::exception& e) {
LOG_ERROR << "Error with LevelDB sharechain storage: " << e.what();
}
}

template<typename ShareChainType>
bool SharechainStorage::load_sharechain(ShareChainType& chain)
{
if (!m_leveldb_store) {
LOG_WARNING << "LevelDB store not available, starting with empty sharechain";
return false;
}

try {
uint64_t stored_shares = m_leveldb_store->get_share_count();
if (stored_shares == 0) {
LOG_INFO << "No shares found in LevelDB storage, starting fresh";
return false;
}

uint256 best_hash = m_leveldb_store->get_best_hash();
uint64_t best_height = m_leveldb_store->get_best_height();

LOG_INFO << "LevelDB sharechain storage contains " << stored_shares << " shares";
LOG_INFO << " Best height: " << best_height;
LOG_INFO << " Best hash: " << best_hash.ToString().substr(0, 16) << "...";

// For now, just report availability - full integration needs sharechain API
LOG_INFO << "LevelDB storage is ready for share loading and recovery";

return stored_shares > 0;

} catch (const std::exception& e) {
LOG_ERROR << "Error loading from LevelDB sharechain storage: " << e.what();
return false;
}
}

bool SharechainStorage::store_share(const uint256& hash, const std::vector<uint8_t>& serialized_data,
bool SharechainStorage::store_share(const uint256& hash, const std::vector<uint8_t>& serialized_data,
const uint256& prev_hash, uint64_t height, uint64_t timestamp,
const uint256& work, const uint256& target, bool is_orphan)
{
Expand Down Expand Up @@ -268,57 +214,8 @@ std::vector<uint256> SharechainStorage::get_shares_by_height_range(uint64_t star
return m_leveldb_store->get_shares_by_height_range(start_height, end_height);
}

template<typename ShareChainType>
void SharechainStorage::schedule_periodic_save(ShareChainType& chain, boost::asio::io_context& ioc, int interval_seconds)
{
auto timer = std::make_shared<boost::asio::steady_timer>(ioc);

// Create a safe capture by copying what we need
auto leveldb_store_ptr = m_leveldb_store.get(); // Raw pointer for safety check

// Use a shared_ptr to hold the recursive callback
auto save_task = std::make_shared<std::function<void()>>();
*save_task = [leveldb_store_ptr, timer, interval_seconds, save_task]() {
if (leveldb_store_ptr) {
LOG_INFO << "Periodic LevelDB storage maintenance";

try {
uint64_t share_count = leveldb_store_ptr->get_share_count();
uint64_t best_height = leveldb_store_ptr->get_best_height();

LOG_INFO << "LevelDB Storage Stats:";
LOG_INFO << " Total shares: " << share_count;
LOG_INFO << " Best height: " << best_height;

// Periodic compaction (every hour)
static int compact_counter = 0;
if (++compact_counter >= (3600 / interval_seconds)) {
LOG_INFO << "Compacting LevelDB sharechain storage...";
leveldb_store_ptr->compact();
compact_counter = 0;
}
} catch (const std::exception& e) {
LOG_ERROR << "Error in periodic LevelDB maintenance: " << e.what();
}
}

timer->expires_after(std::chrono::seconds(interval_seconds));
timer->async_wait([save_task](const boost::system::error_code&) {
if (save_task) (*save_task)();
});
};

// Start after initial delay
timer->expires_after(std::chrono::seconds(30));
timer->async_wait([save_task](const boost::system::error_code&) {
if (save_task) (*save_task)();
});
}

// Explicit template instantiations for common types
template void SharechainStorage::save_sharechain<ltc::ShareChain>(const ltc::ShareChain& chain);
template bool SharechainStorage::load_sharechain<ltc::ShareChain>(ltc::ShareChain& chain);
template void SharechainStorage::schedule_periodic_save<ltc::ShareChain>(ltc::ShareChain& chain, boost::asio::io_context& ioc, int interval_seconds);
// Template method bodies (save_sharechain, load_sharechain, schedule_periodic_save)
// live in the header so any coin's ShareChain type gets implicit instantiation.

} // namespace storage
} // namespace c2pool
63 changes: 59 additions & 4 deletions src/c2pool/storage/sharechain_storage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,45 @@ class SharechainStorage {
* @param chain The sharechain to save
*/
template<typename ShareChainType>
void save_sharechain(const ShareChainType& chain);

void save_sharechain(const ShareChainType& /*chain*/)
{
if (!m_leveldb_store) {
LOG_ERROR << "LevelDB store not available";
return;
}
try {
LOG_INFO << "LevelDB sharechain storage is ready for persistent share storage";
LOG_INFO << " Network: " << m_network_name;
} catch (const std::exception& e) {
LOG_ERROR << "Error with LevelDB sharechain storage: " << e.what();
}
}

/**
* @brief Load sharechain from persistent storage
* @tparam ShareChainType Type of sharechain to load into
* @param chain The sharechain to load into
* @return True if shares were loaded
*/
template<typename ShareChainType>
bool load_sharechain(ShareChainType& chain);
bool load_sharechain(ShareChainType& /*chain*/)
{
if (!m_leveldb_store) {
LOG_WARNING << "LevelDB store not available, starting with empty sharechain";
return false;
}
try {
uint64_t stored_shares = m_leveldb_store->get_share_count();
if (stored_shares == 0) {
LOG_INFO << "No shares found in LevelDB storage, starting fresh";
return false;
}
return stored_shares > 0;
} catch (const std::exception& e) {
LOG_ERROR << "Error loading from LevelDB sharechain storage: " << e.what();
return false;
}
}

/**
* @brief Store a specific share in the database
Expand Down Expand Up @@ -169,7 +198,33 @@ class SharechainStorage {
* @param interval_seconds Maintenance interval
*/
template<typename ShareChainType>
void schedule_periodic_save(ShareChainType& chain, boost::asio::io_context& ioc, int interval_seconds = 300);
void schedule_periodic_save(ShareChainType& /*chain*/, boost::asio::io_context& ioc, int interval_seconds = 300)
{
auto timer = std::make_shared<boost::asio::steady_timer>(ioc);
auto leveldb_store_ptr = m_leveldb_store.get();
auto save_task = std::make_shared<std::function<void()>>();
*save_task = [leveldb_store_ptr, timer, interval_seconds, save_task]() {
if (leveldb_store_ptr) {
LOG_INFO << "Periodic LevelDB storage maintenance";
try {
uint64_t share_count = leveldb_store_ptr->get_share_count();
uint64_t best_height = leveldb_store_ptr->get_best_height();
LOG_INFO << " Share count: " << share_count;
LOG_INFO << " Best height: " << best_height;
} catch (const std::exception& e) {
LOG_ERROR << "Error in periodic maintenance: " << e.what();
}
}
timer->expires_after(std::chrono::seconds(interval_seconds));
timer->async_wait([save_task](const boost::system::error_code&) {
if (save_task) (*save_task)();
});
};
timer->expires_after(std::chrono::seconds(30));
timer->async_wait([save_task](const boost::system::error_code&) {
if (save_task) (*save_task)();
});
}
};

} // namespace storage
Expand Down
52 changes: 52 additions & 0 deletions src/core/pow.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#pragma once

// PoW function types and built-in algorithm implementations.
// Each coin binds its CoinParams::pow_func to one of these.

#include "uint256.hpp"
#include "hash.hpp"
#include <btclibs/crypto/scrypt.h>

#include <cstring>
#include <functional>
#include <span>

namespace core
{

// PoW function: takes an 80-byte block header, returns the PoW hash.
// For most coins, this differs from the block identity hash (SHA256d).
using PowFunc = std::function<uint256(std::span<const unsigned char>)>;

// Block hash function: computes the block's identity hash (used for prev_block references).
// For Bitcoin-family coins this is always SHA256d, but kept separate for generality.
using BlockHashFunc = std::function<uint256(std::span<const unsigned char>)>;

// Subsidy function: given a block height, returns the block reward in satoshis.
using SubsidyFunc = std::function<uint64_t(uint32_t height)>;

// Donation script function: given a share version, returns the donation script bytes.
using DonationScriptFunc = std::function<std::vector<unsigned char>(int64_t share_version)>;

namespace pow
{

// SHA256d (Bitcoin): double SHA-256 of 80-byte header.
inline uint256 sha256d(std::span<const unsigned char> header)
{
return Hash(header);
}

// Scrypt(1024,1,1,256) (Litecoin, Dogecoin): scrypt hash of 80-byte header.
inline uint256 scrypt(std::span<const unsigned char> header)
{
char pow_hash_bytes[32];
scrypt_1024_1_1_256(reinterpret_cast<const char*>(header.data()),
pow_hash_bytes);
uint256 result;
std::memcpy(result.begin(), pow_hash_bytes, 32);
return result;
}

} // namespace pow
} // namespace core
90 changes: 90 additions & 0 deletions src/impl/bitcoin_family/coin/base_block.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#pragma once

// Generic Bitcoin-family block header types.
// SmallBlockHeaderType: compact header for p2pool share serialization (VarInt version).
// BlockHeaderType: standard 80-byte block header (fixed uint32 version).
// BaseBlockType: block = header + transactions (no MWEB).
//
// LTC extends BaseBlockType with MWEB support (m_mweb_raw, HogEx).
// Dash, BTC, DOGE use BaseBlockType directly.

#include <core/uint256.hpp>
#include <core/pack_types.hpp>

#include <vector>

namespace bitcoin_family
{
namespace coin
{

struct SmallBlockHeaderType
{
uint64_t m_version {};
uint256 m_previous_block{};
uint32_t m_timestamp{};
uint32_t m_bits{};
uint32_t m_nonce{};

SERIALIZE_METHODS(SmallBlockHeaderType) { READWRITE(VarInt(obj.m_version), obj.m_previous_block, obj.m_timestamp, obj.m_bits, obj.m_nonce); }

SmallBlockHeaderType() {}

void SetNull()
{
m_version = 0;
m_previous_block.SetNull();
m_timestamp = 0;
m_bits = 0;
m_nonce = 0;
}

bool IsNull() const
{
return (m_bits == 0);
}
};

struct BlockHeaderType : SmallBlockHeaderType
{
uint256 m_merkle_root;

// Full block header uses fixed 4-byte int32 version (not VarInt like SmallBlockHeaderType)
template<typename Stream>
void Serialize(Stream& s) const {
uint32_t version32 = static_cast<uint32_t>(m_version);
::Serialize(s, version32);
::Serialize(s, m_previous_block);
::Serialize(s, m_merkle_root);
::Serialize(s, m_timestamp);
::Serialize(s, m_bits);
::Serialize(s, m_nonce);
}
template<typename Stream>
void Unserialize(Stream& s) {
uint32_t version32;
::Unserialize(s, version32);
m_version = version32;
::Unserialize(s, m_previous_block);
::Unserialize(s, m_merkle_root);
::Unserialize(s, m_timestamp);
::Unserialize(s, m_bits);
::Unserialize(s, m_nonce);
}

BlockHeaderType() : SmallBlockHeaderType() { }

void SetNull()
{
SmallBlockHeaderType::SetNull();
m_merkle_root.SetNull();
}

bool IsNull() const
{
return (m_bits == 0);
}
};

} // namespace coin
} // namespace bitcoin_family
Loading
Loading