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
50 changes: 50 additions & 0 deletions src/core/version_gate.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#pragma once
//
// version_gate.hpp — Cross-coin c2pool share-version activation gate (SINGLE SOURCE OF TRUTH).
//
// c2pool's sharechain format is versioned. The V36 format revision is a
// CONSENSUS boundary that is IDENTICAL across every coin c2pool mines
// (btc/ltc/bch/dgb): when a share's VERSION >= 36 the wire layout switches to
// the V36 encoding (VarInt subsidy, AbsworkV36Format, merged_addresses,
// merged_coinbase_info + merged_payout_hash, V36HashLinkType extra_data,
// message_data) and the V36 PPLNS / donation semantics engage. The activation
// number 36 carries no per-coin network state — every coin's params set
// current_share_version = 36 — so it belongs here in core/ rather than being
// re-spelled as a bare `>= 36` literal at each call site.
//
// SCOPE — what this gate does and does NOT own:
// OWNS: the V36 share-format / consensus-revision boundary (uniform 36).
// NOT: segwit activation. That version is coin-SPECIFIC
// (BTC 33, dgb 35, ltc/bch 17) and stays in each coin's PoolConfig
// as SEGWIT_ACTIVATION_VERSION, surfaced via the per-coin
// is_segwit_activated() helper. Do not fold segwit into this gate.
//
// Conformance shape (BTC-first, per v36-standardize goal):
// Every coin replaces its scattered `version >= 36` / `>= 36` literals with
// core::version_gate::is_v36_active(version). Both compile-time
// (`if constexpr (is_v36_active(Tmpl::version))`) and runtime
// (`if (is_v36_active(p.share_version))`) call sites are covered because the
// predicate is constexpr. BTC is the reference adoption; ltc/dgb/bch conform
// by mechanical site-rewrite — no value changes, byte-for-byte identical gate.
//
// Provenance: p2pool check() gates the V36 share rev on self.VERSION >= 36
// (jtoomim/forrestv). The number is shared across the c2pool multi-coin tree.
//

#include <cstdint>

namespace core::version_gate
{

// V36 share-format / consensus-revision activation version. Uniform cross-coin.
inline constexpr uint64_t V36_ACTIVATION_VERSION = 36;

// True iff a share of the given VERSION uses the V36 sharechain encoding and
// V36 consensus semantics. constexpr so it serves both `if constexpr` template
// gates and runtime checks.
constexpr bool is_v36_active(uint64_t version)
{
return version >= V36_ACTIVATION_VERSION;
}

} // namespace core::version_gate
13 changes: 7 additions & 6 deletions src/impl/btc/share.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "coin/block.hpp"
#include "share_types.hpp"
#include <core/version_gate.hpp> // SSOT: core::version_gate::is_v36_active

#include <sharechain/sharechain.hpp>
#include <sharechain/share.hpp>
Expand Down Expand Up @@ -159,7 +160,7 @@ struct Formatter
);

// Address handling — version-dependent
if constexpr (version >= 36)
if constexpr (core::version_gate::is_v36_active(version))
{
READWRITE(obj->m_pubkey_hash); // IntType(160)
READWRITE(obj->m_pubkey_type); // IntType(8)
Expand All @@ -174,7 +175,7 @@ struct Formatter
}

// Subsidy — V36 uses VarInt, others use fixed uint64
if constexpr (version >= 36)
if constexpr (core::version_gate::is_v36_active(version))
{
READWRITE(VarInt(obj->m_subsidy));
}
Expand All @@ -195,7 +196,7 @@ struct Formatter
}

// V36: merged_addresses (after segwit_data, before far_share_hash)
if constexpr (version >= 36)
if constexpr (core::version_gate::is_v36_active(version))
{
READWRITE(obj->m_merged_addresses);
}
Expand All @@ -214,7 +215,7 @@ struct Formatter
);

// Abswork — V36 uses VarInt-encoded uint64, others use fixed uint128
if constexpr (version >= 36)
if constexpr (core::version_gate::is_v36_active(version))
{
READWRITE(Using<AbsworkV36Format>(obj->m_abswork));
}
Expand All @@ -224,7 +225,7 @@ struct Formatter
}

// V36: merged_coinbase_info + merged_payout_hash (after abswork)
if constexpr (version >= 36)
if constexpr (core::version_gate::is_v36_active(version))
{
READWRITE(obj->m_merged_coinbase_info);
READWRITE(obj->m_merged_payout_hash);
Expand All @@ -244,7 +245,7 @@ struct Formatter
);

// V36: message_data (at the end)
if constexpr (version >= 36)
if constexpr (core::version_gate::is_v36_active(version))
{
READWRITE(obj->m_message_data);
}
Expand Down
53 changes: 27 additions & 26 deletions src/impl/btc/share_check.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "config_pool.hpp"
#include "share.hpp"
#include <core/version_gate.hpp> // SSOT: core::version_gate::is_v36_active
#include "share_messages.hpp"
#include "share_types.hpp"

Expand Down Expand Up @@ -374,7 +375,7 @@ inline std::pair<uint256, uint64_t> compute_ref_hash_for_work(const RefHashParam

ref_stream << p.share_nonce;

if (p.share_version >= 36) {
if (core::version_gate::is_v36_active(p.share_version)) {
// V36: pubkey_hash (uint160) + pubkey_type (uint8)
ref_stream << p.pubkey_hash;
ref_stream << p.pubkey_type;
Expand All @@ -399,7 +400,7 @@ inline std::pair<uint256, uint64_t> compute_ref_hash_for_work(const RefHashParam
ref_stream << p.segwit_data;

// V36: merged_addresses (after segwit_data, before far_share_hash)
if (p.share_version >= 36)
if (core::version_gate::is_v36_active(p.share_version))
ref_stream << p.merged_addresses;

ref_stream << p.far_share_hash;
Expand All @@ -408,7 +409,7 @@ inline std::pair<uint256, uint64_t> compute_ref_hash_for_work(const RefHashParam
ref_stream << p.timestamp;
ref_stream << p.absheight;

if (p.share_version >= 36) {
if (core::version_gate::is_v36_active(p.share_version)) {
::Serialize(ref_stream, Using<AbsworkV36Format>(p.abswork));
ref_stream << p.merged_coinbase_info;
ref_stream << p.merged_payout_hash;
Expand All @@ -426,10 +427,10 @@ inline std::pair<uint256, uint64_t> compute_ref_hash_for_work(const RefHashParam
{
static int rfn_log = 0;
static int rfn_v36_log = 0;
bool should_log = (rfn_log < 3) || (p.share_version >= 36 && rfn_v36_log < 5);
bool should_log = (rfn_log < 3) || (core::version_gate::is_v36_active(p.share_version) && rfn_v36_log < 5);
if (should_log) {
rfn_log++;
if (p.share_version >= 36) rfn_v36_log++;
if (core::version_gate::is_v36_active(p.share_version)) rfn_v36_log++;
static const char* HX = "0123456789abcdef";
std::string hex;
auto* rd = reinterpret_cast<const unsigned char*>(ref_stream.data());
Expand Down Expand Up @@ -543,7 +544,7 @@ uint256 share_init_verify(const ShareT& share, bool check_pow = true)
ref_stream << share.m_pubkey_hash;

// subsidy: VarInt for V36+, raw uint64_t LE for older
if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
::Serialize(ref_stream, VarInt(share.m_subsidy));
else
ref_stream << share.m_subsidy;
Expand Down Expand Up @@ -578,7 +579,7 @@ uint256 share_init_verify(const ShareT& share, bool check_pow = true)
}

// merged_addresses (V36+)
if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
{
if constexpr (requires { share.m_merged_addresses; })
ref_stream << share.m_merged_addresses;
Expand All @@ -599,7 +600,7 @@ uint256 share_init_verify(const ShareT& share, bool check_pow = true)
ref_stream << share.m_absheight;

// abswork: AbsworkV36Format for V36+, raw uint128 LE for older
if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
{
if constexpr (requires { share.m_abswork; })
::Serialize(ref_stream, Using<AbsworkV36Format>(share.m_abswork));
Expand All @@ -610,7 +611,7 @@ uint256 share_init_verify(const ShareT& share, bool check_pow = true)
}

// V36+ merged mining commitment fields
if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
{
if constexpr (requires { share.m_merged_coinbase_info; })
ref_stream << share.m_merged_coinbase_info;
Expand All @@ -621,7 +622,7 @@ uint256 share_init_verify(const ShareT& share, bool check_pow = true)

// V36 ref_type includes message_data as PossiblyNoneType(b'', VarStrType())
// When m_message_data is empty, BaseScript serialises as varint(0) = 0x00.
if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
{
if constexpr (requires { share.m_message_data; })
ref_stream << share.m_message_data;
Expand Down Expand Up @@ -935,7 +936,7 @@ uint256 generate_share_transaction(const ShareT& share, TrackerT& tracker, bool
// p2pool selects PPLNS formula by runtime AutoRatchet state, not compile-time
// share version. When v36_active is true (AutoRatchet ACTIVATED/CONFIRMED),
// use v36 PPLNS even for v35 shares. Ref: p2pool data.py:879, work.py:759.
const bool use_v36_pplns = v36_active || (ver >= 36);
const bool use_v36_pplns = v36_active || (core::version_gate::is_v36_active(ver));
const uint64_t subsidy = share.m_subsidy;
const uint16_t donation = share.m_donation;

Expand Down Expand Up @@ -1268,7 +1269,7 @@ uint256 generate_share_transaction(const ShareT& share, TrackerT& tracker, bool
else
ref_stream << share.m_pubkey_hash;

if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
::Serialize(ref_stream, VarInt(share.m_subsidy));
else
ref_stream << share.m_subsidy;
Expand Down Expand Up @@ -1297,7 +1298,7 @@ uint256 generate_share_transaction(const ShareT& share, TrackerT& tracker, bool
}
}

if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
{
if constexpr (requires { share.m_merged_addresses; })
ref_stream << share.m_merged_addresses;
Expand All @@ -1315,7 +1316,7 @@ uint256 generate_share_transaction(const ShareT& share, TrackerT& tracker, bool
ref_stream << share.m_timestamp;
ref_stream << share.m_absheight;

if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
{
if constexpr (requires { share.m_abswork; })
::Serialize(ref_stream, Using<AbsworkV36Format>(share.m_abswork));
Expand All @@ -1325,7 +1326,7 @@ uint256 generate_share_transaction(const ShareT& share, TrackerT& tracker, bool
ref_stream << share.m_abswork;
}

if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
{
if constexpr (requires { share.m_merged_coinbase_info; })
ref_stream << share.m_merged_coinbase_info;
Expand All @@ -1335,7 +1336,7 @@ uint256 generate_share_transaction(const ShareT& share, TrackerT& tracker, bool
}

// V36 ref_type includes message_data (must match verify_share)
if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
{
if constexpr (requires { share.m_message_data; })
ref_stream << share.m_message_data;
Expand Down Expand Up @@ -1737,7 +1738,7 @@ bool share_check(const ShareT& share,
// This ensures V35 shares always verify with V35 PPLNS formula, even after
// the AutoRatchet transitions to ACTIVATED.
constexpr int64_t share_ver = ShareT::version;
bool v36_active = (share_ver >= 36);
bool v36_active = (core::version_gate::is_v36_active(share_ver));
if (!share.m_prev_hash.IsNull() && tracker.chain.contains(share.m_prev_hash))
{
uint256 expected_gentx = generate_share_transaction(share, tracker, false, v36_active);
Expand Down Expand Up @@ -1861,7 +1862,7 @@ bool share_check(const ShareT& share,
// independently compute from the share chain. Without this, a malicious
// node could steal all merged chain (DOGE) rewards while appearing honest
// on the parent chain (LTC payouts are consensus-enforced via gentx above).
if constexpr (ShareT::version >= 36)
if constexpr (core::version_gate::is_v36_active(ShareT::version))
{
if constexpr (requires { share.m_merged_payout_hash; })
{
Expand Down Expand Up @@ -1889,7 +1890,7 @@ bool share_check(const ShareT& share,

// 5. V36+ merged coinbase commitment verification (7-step chain)
// Verifies the actual merged coinbase matches canonical PPLNS construction.
if constexpr (ShareT::version >= 36)
if constexpr (core::version_gate::is_v36_active(ShareT::version))
{
auto mcv_err = verify_merged_coinbase_commitment(share, tracker);
if (!mcv_err.empty())
Expand Down Expand Up @@ -1959,7 +1960,7 @@ uint256 verify_share(const ShareT& share, TrackerT& tracker)
else
ref_stream << share.m_pubkey_hash;

if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
::Serialize(ref_stream, VarInt(share.m_subsidy));
else
ref_stream << share.m_subsidy;
Expand Down Expand Up @@ -1987,7 +1988,7 @@ uint256 verify_share(const ShareT& share, TrackerT& tracker)
}
}

if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
{
if constexpr (requires { share.m_merged_addresses; })
ref_stream << share.m_merged_addresses;
Expand All @@ -2005,7 +2006,7 @@ uint256 verify_share(const ShareT& share, TrackerT& tracker)
ref_stream << share.m_timestamp;
ref_stream << share.m_absheight;

if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
{
if constexpr (requires { share.m_abswork; })
::Serialize(ref_stream, Using<AbsworkV36Format>(share.m_abswork));
Expand All @@ -2015,7 +2016,7 @@ uint256 verify_share(const ShareT& share, TrackerT& tracker)
ref_stream << share.m_abswork;
}

if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
{
if constexpr (requires { share.m_merged_coinbase_info; })
ref_stream << share.m_merged_coinbase_info;
Expand All @@ -2025,7 +2026,7 @@ uint256 verify_share(const ShareT& share, TrackerT& tracker)
}

// V36 ref_type includes message_data
if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
{
if constexpr (requires { share.m_message_data; })
ref_stream << share.m_message_data;
Expand All @@ -2050,7 +2051,7 @@ uint256 verify_share(const ShareT& share, TrackerT& tracker)
uint256 gentx_hash = check_hash_link(share.m_hash_link, hash_link_data, gentx_before_refhash);

// V36+: Validate message_data (reject shares with invalid encrypted messages)
if constexpr (ver >= 36)
if constexpr (core::version_gate::is_v36_active(ver))
{
if constexpr (requires { share.m_message_data; })
{
Expand Down Expand Up @@ -3252,7 +3253,7 @@ uint256 create_local_share(
{
static int xcheck_count = 0;
if (true) { // Always cross-check (was: xcheck_count < 5)
uint256 verify_hash = generate_share_transaction<MergedMiningShare>(*heap_share, tracker, true, (MergedMiningShare::version >= 36));
uint256 verify_hash = generate_share_transaction<MergedMiningShare>(*heap_share, tracker, true, (core::version_gate::is_v36_active(MergedMiningShare::version)));
bool xcheck_ok = (verify_hash == gentx_hash_for_header);
if (xcheck_ok) {
LOG_INFO << "[Pool] Cross-check PASSED";
Expand Down
3 changes: 2 additions & 1 deletion src/impl/btc/share_tracker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ inline uint64_t mul128_shift(uint64_t a, uint64_t b, unsigned shift) {
#endif

#include "share.hpp"
#include <core/version_gate.hpp> // SSOT: core::version_gate::is_v36_active
#include "share_check.hpp"
#include "config_pool.hpp"

Expand Down Expand Up @@ -975,7 +976,7 @@ class ShareTracker
prev_hash = obj->m_prev_hash;
share_ver = obj->version;
});
if (share_ver >= 36) {
if (core::version_gate::is_v36_active(share_ver)) {

if (!prev_hash.IsNull() && chain.contains(prev_hash)) {
if (!pplns_active) {
Expand Down
Loading