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
3 changes: 2 additions & 1 deletion src/c2pool/main_dgb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,8 @@ int run_node(const core::CoinParams& params, bool testnet,
// (declared just above, same scope). The StratumServer co-owns the work
// source via shared_ptr.
auto work_source = std::make_shared<dgb::stratum::DGBWorkSource>(
header_chain, mempool, testnet, std::move(stratum_submit_fn));
header_chain, mempool, testnet, std::move(stratum_submit_fn),
params.subsidy_func);

if (stratum_port != 0) {
stratum_server = std::make_unique<core::StratumServer>(
Expand Down
22 changes: 21 additions & 1 deletion src/impl/dgb/stratum/work_source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include <impl/dgb/coin/header_chain.hpp>
#include <impl/dgb/coin/mempool.hpp>
#include <impl/dgb/coin/embedded_coinbase_value.hpp>

#include <core/log.hpp>

Expand All @@ -26,23 +27,42 @@ DGBWorkSource::DGBWorkSource(c2pool::dgb::HeaderChain& chain,
dgb::coin::Mempool& mempool,
bool is_testnet,
SubmitBlockFn submit_fn,
core::SubsidyFunc subsidy_func,
core::stratum::StratumConfig config)
: chain_(chain)
, mempool_(mempool)
, is_testnet_(is_testnet)
, submit_block_fn_(std::move(submit_fn))
, subsidy_func_(std::move(subsidy_func))
, config_(std::move(config))
{
LOG_INFO << "[DGB-STRATUM] DGBWorkSource constructed"
<< " (testnet=" << is_testnet_
<< " min_diff=" << config_.min_difficulty
<< " max_diff=" << config_.max_difficulty
<< " target_time=" << config_.target_time
<< "s vardiff=" << (config_.vardiff_enabled ? "on" : "off") << ")";
<< "s vardiff=" << (config_.vardiff_enabled ? "on" : "off")
<< " subsidy_func=" << (subsidy_func_ ? "wired" : "UNSET") << ")";
}

DGBWorkSource::~DGBWorkSource() = default;

// ──────────────────────────────────────────────────────────────────
// Embedded coinbasevalue — first PRODUCTION caller of CoinParams::subsidy_func.
// Delegates to the dgb::coin SSOT (embedded_coinbase_value.hpp) so the embedded
// TemplateBuilder coinbasevalue and the external-daemon GBT coinbasevalue are
// computed from ONE definition and can never silently diverge. The GBT value,
// when present, is authoritative and returned verbatim (external-daemon
// fallback MUST PERSIST); otherwise subsidy_func(height)+fees is derived from
// the DGB oracle decay schedule.
// ──────────────────────────────────────────────────────────────────
uint64_t DGBWorkSource::coinbase_value(uint32_t height, uint64_t total_fees,
std::optional<uint64_t> gbt_coinbasevalue) const
{
return dgb::coin::resolve_coinbase_value(subsidy_func_, height, total_fees,
gbt_coinbasevalue);
}

// ─────────────────────────────────────────────────────────────────────────────
// IWorkSource: config + read-only state — Stage 4b will fill these in.
// ─────────────────────────────────────────────────────────────────────────────
Expand Down
17 changes: 17 additions & 0 deletions src/impl/dgb/stratum/work_source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@

#include <core/stratum_work_source.hpp>
#include <core/uint256.hpp>
#include <core/pow.hpp> // core::SubsidyFunc — embedded coinbasevalue SSOT feed

#include <atomic>
#include <cstdint>
#include <functional>
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -83,6 +85,7 @@ class DGBWorkSource : public core::stratum::IWorkSource
dgb::coin::Mempool& mempool,
bool is_testnet,
SubmitBlockFn submit_fn,
core::SubsidyFunc subsidy_func,
core::stratum::StratumConfig config = {});
~DGBWorkSource() override;

Expand Down Expand Up @@ -160,6 +163,16 @@ class DGBWorkSource : public core::stratum::IWorkSource
/// is constructed.
void set_best_share_hash_fn(std::function<uint256()> fn);

/// Embedded-path coinbasevalue for the template builder (Stage 4c).
/// Routes through dgb::coin::resolve_coinbase_value: when the external
/// digibyted GBT supplied a coinbasevalue it is returned verbatim (the
/// external-daemon fallback that MUST PERSIST); otherwise the value is
/// derived locally as subsidy_func(height) + total_fees from the DGB
/// oracle decay schedule. First PRODUCTION invocation site of
/// CoinParams::subsidy_func (SSOT guarded by test_dgb_coinbase_value).
uint64_t coinbase_value(uint32_t height, uint64_t total_fees,
std::optional<uint64_t> gbt_coinbasevalue) const;

private:
// External dependencies (non-owning references)
c2pool::dgb::HeaderChain& chain_;
Expand All @@ -169,6 +182,10 @@ class DGBWorkSource : public core::stratum::IWorkSource
// Submission dispatch
SubmitBlockFn submit_block_fn_;

// Embedded coinbasevalue SSOT feed (CoinParams::subsidy_func). Drives the
// template builder's coinbasevalue when no external-daemon GBT value.
core::SubsidyFunc subsidy_func_;

// Config (held by value; const after construction in MVP)
core::stratum::StratumConfig config_;

Expand Down
61 changes: 60 additions & 1 deletion src/impl/dgb/test/work_source_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,23 @@
#include <impl/dgb/stratum/work_source.hpp>
#include <impl/dgb/coin/header_chain.hpp>
#include <impl/dgb/coin/mempool.hpp>
#include <impl/dgb/config_coin.hpp> // dgb::CoinParams::subsidy (oracle SSOT)

#include <core/pow.hpp> // core::SubsidyFunc

#include <core/stratum_work_source.hpp>

#include <gtest/gtest.h>

#include <memory>
#include <optional>

namespace {

// IDENTICAL to params.hpp `p.subsidy_func` — the live CoinParams indirection.
const core::SubsidyFunc kSubsidyFunc =
[](uint32_t height) -> uint64_t { return dgb::CoinParams::subsidy(height); };

// Construct a DGBWorkSource over default-constructed coin deps. The submit
// callback records whether it was invoked (it must NOT be in the 4a skeleton).
struct Fixture {
Expand All @@ -39,7 +47,7 @@ struct Fixture {
return false;
};
return std::make_unique<dgb::stratum::DGBWorkSource>(
chain, mempool, /*is_testnet=*/false, fn);
chain, mempool, /*is_testnet=*/false, fn, kSubsidyFunc);
}
};

Expand Down Expand Up @@ -166,4 +174,55 @@ TEST(DgbWorkSource, ComputeShareDifficultyReturnsNotYetSentinel)
EXPECT_DOUBLE_EQ(diff, 0.0);
}

// ── Embedded coinbasevalue: first production caller of subsidy_func ──────────
// One pin on each side of every DGB reward-era boundary (p2pool-dgb-scrypt
// oracle vectors, test_dgb_subsidy.cpp).
namespace {
struct EraVec { uint32_t height; uint64_t subsidy; const char* era; };
constexpr EraVec kEraBoundaries[] = {
{67199, 8000000000ULL, "phase1-fixed last"},
{67200, 7960000000ULL, "phase2 -0.5%/wk first"},
{399999, 6746441103ULL, "phase2 last"},
{400000, 2434410000ULL, "phase3 -1%/wk first"},
{1429999, 2157824200ULL, "phase3 last"},
{1430000, 1078500000ULL, "phase4 monthly-decay first"},
};
} // namespace

// No external GBT (embedded path): coinbasevalue is derived THROUGH the work
// source's subsidy_func at every era boundary, zero fees -> oracle subsidy.
TEST(DgbWorkSource, CoinbaseValueDerivesViaSubsidyFuncWhenNoGbt)
{
Fixture fx;
auto ws = fx.make();
for (const auto& v : kEraBoundaries) {
EXPECT_EQ(ws->coinbase_value(v.height, /*fees=*/0, std::nullopt), v.subsidy)
<< "embedded coinbasevalue diverged from oracle subsidy at " << v.era;
}
}

// Fees compose additively on the embedded path: subsidy + total_fees.
TEST(DgbWorkSource, CoinbaseValueAddsFeesOnEmbeddedPath)
{
Fixture fx;
auto ws = fx.make();
constexpr uint64_t kFees = 1234567ULL;
for (const auto& v : kEraBoundaries) {
EXPECT_EQ(ws->coinbase_value(v.height, kFees, std::nullopt), v.subsidy + kFees)
<< "fee addition wrong at " << v.era;
}
}

// External-daemon fallback PERSISTS: a present GBT coinbasevalue is authoritative
// and returned verbatim through the work source, bypassing local derivation.
TEST(DgbWorkSource, CoinbaseValueHonorsGbtVerbatim)
{
Fixture fx;
auto ws = fx.make();
constexpr uint64_t kGbt = 99999999999ULL; // deliberately != subsidy+fees
EXPECT_EQ(ws->coinbase_value(/*height=*/400000, /*fees=*/500,
std::optional<uint64_t>{kGbt}),
kGbt);
}

} // namespace
Loading