Skip to content

Commit 35ebb69

Browse files
committed
dgb(#82): DGBWorkSource IWorkSource Stage-4a skeleton — miner-facing path
Concrete dgb::stratum::DGBWorkSource bridges the coin-agnostic core::StratumServer to DGB-Scrypt work generation + share validation, mirroring btc::stratum::BTCWorkSource's 4a landing. Skeleton compiles, instantiates over the live coin deps, and pins the full IWorkSource contract so the StratumServer wiring in main_dgb.cpp can be validated end-to-end before the substantive logic lands. All work-generation getters return documented empty/default forms; mining_submit rejects every submission as low-difficulty WITHOUT reaching the won-block broadcaster; compute_share_difficulty returns the 0.0 not-yet sentinel (vardiff hard-reject — no garbage diff leaks). The real scrypt_1024_1_1_256 assembly + share-classification hot path land in 4b/4c/4d. dgb_work_source_test: 10/10 PASS (IWorkSource contract + atomics + worker registry + stub-safety + sentinel). Wired into dgb_dgb CMake + BOTH build.yml --target allowlists (#143 NOT_BUILT trap avoided). Single-coin, no shared-base/bitcoin_family touch, no -DAUX_DOGE.
1 parent 3cfd460 commit 35ebb69

7 files changed

Lines changed: 626 additions & 2 deletions

File tree

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ jobs:
6969
test_address_resolution test_compute_share_target \
7070
test_utxo test_dgb_subsidy dgb_share_test dgb_block_assembly_test \
7171
dgb_gentx_coinbase_test nmc_auxpow_merkle_test dgb_gentx_share_path_test dgb_other_tx_resolver_test \
72-
dgb_other_tx_assembler_test dgb_reconstruct_won_block_test dgb_gentx_unpack_test \
72+
dgb_other_tx_assembler_test dgb_reconstruct_won_block_test dgb_gentx_unpack_test dgb_work_source_test \
7373
rpc_request_test softfork_check_test genesis_check_test algo_select_test digishield_walk_test header_chain_test \
7474
v37_test \
7575
-j$(nproc)
@@ -201,7 +201,7 @@ jobs:
201201
test_address_resolution test_compute_share_target \
202202
test_utxo test_dgb_subsidy dgb_share_test dgb_block_assembly_test \
203203
dgb_gentx_coinbase_test nmc_auxpow_merkle_test dgb_gentx_share_path_test dgb_other_tx_resolver_test \
204-
dgb_other_tx_assembler_test dgb_reconstruct_won_block_test dgb_gentx_unpack_test \
204+
dgb_other_tx_assembler_test dgb_reconstruct_won_block_test dgb_gentx_unpack_test dgb_work_source_test \
205205
rpc_request_test softfork_check_test genesis_check_test algo_select_test digishield_walk_test header_chain_test \
206206
test_coin_broadcaster test_multiaddress_pplns test_pplns_stress \
207207
v37_test \

src/impl/dgb/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
if(COIN_DGB)
2020
message(STATUS "c2pool: DGB Scrypt-only coin module enabled")
2121
add_subdirectory(coin)
22+
add_subdirectory(stratum) # dgb_stratum: IWorkSource (#82 miner-facing path)
2223
# add_subdirectory(daemon)
2324
add_subdirectory(test)
2425

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# dgb::stratum module — concrete IWorkSource implementation for c2pool-dgb.
2+
# Bridges core::StratumServer (coin-agnostic protocol layer) to DGB's
3+
# Scrypt template builder + sharechain + the #82 dual-path won-block
4+
# broadcaster. Mirrors src/impl/btc/stratum/CMakeLists.txt. Stage 4a
5+
# skeleton (work-gen/submit stubbed; 4b/4c/4d fill them in).
6+
7+
add_library(dgb_stratum
8+
work_source.hpp work_source.cpp
9+
)
10+
11+
target_link_libraries(dgb_stratum
12+
core
13+
dgb_coin
14+
btclibs
15+
nlohmann_json::nlohmann_json
16+
${Boost_LIBRARIES}
17+
)
18+
19+
# Include parent so #include <impl/dgb/...> resolves
20+
target_include_directories(dgb_stratum PUBLIC
21+
${CMAKE_SOURCE_DIR}/src
22+
)
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
// dgb::stratum::DGBWorkSource — Stage 4a skeleton.
2+
//
3+
// All IWorkSource methods are stubbed to safe defaults. Subsequent
4+
// sub-stages flesh them out (mirroring btc::stratum::BTCWorkSource's own
5+
// 4b/4c/4d progression):
6+
// Stage 4b: read-only getters (config, prevhash, generation, workers)
7+
// Stage 4c: Scrypt work generation (template, merkle branches, coinbase)
8+
// Stage 4d: mining_submit hot path (Scrypt PoW classify + won-block dispatch)
9+
//
10+
// The skeleton is intentionally non-functional but compiles, instantiates,
11+
// and lets us validate the StratumServer wiring in main_dgb.cpp end-to-end
12+
// before implementing the substantive logic. DGB validates Scrypt blocks
13+
// only (V36 / project_v36_dgb_scrypt_only); the other four DGB algos are
14+
// accept-by-continuity / V37 and never reach this work source.
15+
16+
#include <impl/dgb/stratum/work_source.hpp>
17+
18+
#include <impl/dgb/coin/header_chain.hpp>
19+
#include <impl/dgb/coin/mempool.hpp>
20+
21+
#include <core/log.hpp>
22+
23+
namespace dgb::stratum {
24+
25+
DGBWorkSource::DGBWorkSource(c2pool::dgb::HeaderChain& chain,
26+
dgb::coin::Mempool& mempool,
27+
bool is_testnet,
28+
SubmitBlockFn submit_fn,
29+
core::stratum::StratumConfig config)
30+
: chain_(chain)
31+
, mempool_(mempool)
32+
, is_testnet_(is_testnet)
33+
, submit_block_fn_(std::move(submit_fn))
34+
, config_(std::move(config))
35+
{
36+
LOG_INFO << "[DGB-STRATUM] DGBWorkSource constructed"
37+
<< " (testnet=" << is_testnet_
38+
<< " min_diff=" << config_.min_difficulty
39+
<< " max_diff=" << config_.max_difficulty
40+
<< " target_time=" << config_.target_time
41+
<< "s vardiff=" << (config_.vardiff_enabled ? "on" : "off") << ")";
42+
}
43+
44+
DGBWorkSource::~DGBWorkSource() = default;
45+
46+
// ─────────────────────────────────────────────────────────────────────────────
47+
// IWorkSource: config + read-only state — Stage 4b will fill these in.
48+
// ─────────────────────────────────────────────────────────────────────────────
49+
50+
const core::stratum::StratumConfig& DGBWorkSource::get_stratum_config() const
51+
{
52+
return config_;
53+
}
54+
55+
std::function<uint256()> DGBWorkSource::get_best_share_hash_fn() const
56+
{
57+
std::lock_guard<std::mutex> lk(best_share_mutex_);
58+
return best_share_hash_fn_; // empty function until set_best_share_hash_fn() called
59+
}
60+
61+
std::string DGBWorkSource::get_current_gbt_prevhash() const
62+
{
63+
// Stage 4b: read chain_.tip() and return BE-display-hex form.
64+
return {};
65+
}
66+
67+
uint64_t DGBWorkSource::get_work_generation() const
68+
{
69+
return work_generation_.load(std::memory_order_relaxed);
70+
}
71+
72+
bool DGBWorkSource::has_merged_chain(uint32_t /*chain_id*/) const
73+
{
74+
// DGB V36 default build: standalone Scrypt parent, no merged mining.
75+
// The DGB-as-DOGE-parent dual-parent path (-DAUX_DOGE=ON) is a V36
76+
// STRETCH, parked behind the shared DOGE-aux settle — not wired here.
77+
return false;
78+
}
79+
80+
// ─────────────────────────────────────────────────────────────────────────────
81+
// IWorkSource: per-connection bookkeeping — minimal but real now.
82+
// ─────────────────────────────────────────────────────────────────────────────
83+
84+
void DGBWorkSource::register_stratum_worker(const std::string& session_id,
85+
const core::stratum::WorkerInfo& info)
86+
{
87+
std::lock_guard<std::mutex> lk(workers_mutex_);
88+
workers_[session_id] = info;
89+
LOG_INFO << "[DGB-STRATUM] worker registered: session=" << session_id
90+
<< " user=" << info.username
91+
<< " worker=" << info.worker_name
92+
<< " endpoint=" << info.remote_endpoint;
93+
}
94+
95+
void DGBWorkSource::unregister_stratum_worker(const std::string& session_id)
96+
{
97+
std::lock_guard<std::mutex> lk(workers_mutex_);
98+
auto it = workers_.find(session_id);
99+
if (it != workers_.end()) {
100+
LOG_INFO << "[DGB-STRATUM] worker unregistered: session=" << session_id
101+
<< " user=" << it->second.username
102+
<< " accepted=" << it->second.accepted
103+
<< " rejected=" << it->second.rejected
104+
<< " stale=" << it->second.stale;
105+
workers_.erase(it);
106+
}
107+
}
108+
109+
void DGBWorkSource::update_stratum_worker(const std::string& session_id,
110+
double hashrate, double dead_hashrate,
111+
double difficulty,
112+
uint64_t accepted, uint64_t rejected, uint64_t stale)
113+
{
114+
std::lock_guard<std::mutex> lk(workers_mutex_);
115+
auto it = workers_.find(session_id);
116+
if (it == workers_.end()) return;
117+
it->second.hashrate = hashrate;
118+
it->second.dead_hashrate = dead_hashrate;
119+
it->second.difficulty = difficulty;
120+
it->second.accepted = accepted;
121+
it->second.rejected = rejected;
122+
it->second.stale = stale;
123+
}
124+
125+
// ─────────────────────────────────────────────────────────────────────────────
126+
// IWorkSource: work generation — Stage 4c will fill these in.
127+
// ─────────────────────────────────────────────────────────────────────────────
128+
129+
nlohmann::json DGBWorkSource::get_current_work_template() const
130+
{
131+
// Stage 4c: drive dgb::coin::TemplateBuilder over chain_ + mempool_ and
132+
// shape its WorkData into the GBT-style JSON the stratum session expects
133+
// (previousblockhash, bits, version, curtime, mintime, height,
134+
// coinbasevalue, transactions[]). Scrypt nBits, not SHA256d.
135+
return nlohmann::json::object();
136+
}
137+
138+
std::vector<std::string> DGBWorkSource::get_stratum_merkle_branches() const
139+
{
140+
// Stage 4c: return cached branches from last template build.
141+
return {};
142+
}
143+
144+
std::pair<std::string, std::string> DGBWorkSource::get_coinbase_parts() const
145+
{
146+
// Stage 4c: return cached coinb1/coinb2 (extranonce slot between them).
147+
return { {}, {} };
148+
}
149+
150+
core::stratum::CoinbaseResult DGBWorkSource::build_connection_coinbase(
151+
const uint256& /*prev_share_hash*/,
152+
const std::string& /*extranonce1_hex*/,
153+
const std::vector<unsigned char>& /*payout_script*/,
154+
const std::vector<std::pair<uint32_t, std::vector<unsigned char>>>& /*merged_addrs*/) const
155+
{
156+
// Stage 4c: build per-connection coinbase using the SSOT gentx assembler
157+
// (coin/gentx_coinbase.hpp) + ShareTracker ref_hash + PPLNS payout map.
158+
// For now return an empty result; sessions calling this will get an empty
159+
// job and skip pushing work, which is safe but non-functional.
160+
return {};
161+
}
162+
163+
// ─────────────────────────────────────────────────────────────────────────────
164+
// IWorkSource: share submission — Stage 4d (the hot path).
165+
// ─────────────────────────────────────────────────────────────────────────────
166+
167+
nlohmann::json DGBWorkSource::mining_submit(
168+
const std::string& username, const std::string& job_id,
169+
const std::string& /*extranonce1*/, const std::string& /*extranonce2*/,
170+
const std::string& /*ntime*/, const std::string& /*nonce*/,
171+
const std::string& /*request_id*/,
172+
const std::map<uint32_t, std::vector<unsigned char>>& /*merged_addresses*/,
173+
const core::stratum::JobSnapshot* /*job*/)
174+
{
175+
// Stage 4d will:
176+
// 1. Reconstruct the 80-byte block header from JobSnapshot + miner inputs
177+
// 2. Scrypt(header) → pow_hash (scrypt_1024_1_1_256, the DGB-Scrypt algo)
178+
// 3. Decode share target from job->share_bits (compact)
179+
// 4. Decode block target from job->block_nbits (compact)
180+
// 5. Classify:
181+
// pow_hash <= block target → submit_block_fn_(full_block, height)
182+
// pow_hash <= share target → record share in tracker (sharechain accept)
183+
// otherwise → reject as low-difficulty
184+
// 6. Update worker stats accordingly
185+
//
186+
// For now: log + reject everything as low-difficulty. Miners will see
187+
// stratum errors but the binary won't crash.
188+
LOG_WARNING << "[DGB-STRATUM] mining_submit not implemented (stage 4d): "
189+
<< "user=" << username << " job=" << job_id
190+
<< " — submission rejected as low-difficulty";
191+
192+
return nlohmann::json::array({
193+
false,
194+
nlohmann::json::array({23, "Low difficulty share (stratum stub: stage 4d not implemented)", nullptr})
195+
});
196+
}
197+
198+
double DGBWorkSource::compute_share_difficulty(
199+
const std::string& /*coinb1*/, const std::string& /*coinb2*/,
200+
const std::string& /*extranonce1*/, const std::string& /*extranonce2*/,
201+
const std::string& /*ntime*/, const std::string& /*nonce*/,
202+
uint32_t /*version*/, const std::string& /*prevhash_hex*/,
203+
const std::string& /*nbits_hex*/,
204+
const std::vector<std::string>& /*merkle_branches*/) const
205+
{
206+
// Stage 4b/4c: reconstruct the 80-byte header from (coinb1+en1+en2+coinb2)
207+
// merkle-rooted with merkle_branches, then scrypt_1024_1_1_256(header) and
208+
// return diff1 / pow_hash. Until then the coin-agnostic StratumServer must
209+
// not credit pseudoshares it cannot score, so we return 0.0 — the documented
210+
// parse-error / not-yet sentinel that the vardiff gate already treats as a
211+
// hard reject (no garbage difficulty leaks into the rate monitor).
212+
return 0.0;
213+
}
214+
215+
// ─────────────────────────────────────────────────────────────────────────────
216+
// DGB-specific control surface
217+
// ─────────────────────────────────────────────────────────────────────────────
218+
219+
void DGBWorkSource::set_best_share_hash_fn(std::function<uint256()> fn)
220+
{
221+
std::lock_guard<std::mutex> lk(best_share_mutex_);
222+
best_share_hash_fn_ = std::move(fn);
223+
}
224+
225+
} // namespace dgb::stratum

0 commit comments

Comments
 (0)