Skip to content

Commit 00fbd2c

Browse files
committed
Fix 3 critical consensus bugs: Scrypt diff, canonical coinbase, DOGE P2P port
1. DUMB_SCRYPT_DIFF (65536) missing from mining.set_difficulty. Scrypt miners received raw difficulty (0.005) instead of scaled (327). Miners showed Diff=0, submitted everything, 80% rejection, 0 real shares. 2. Canonical merged coinbase strings must match p2pool for consensus: scriptSig: "/c2pool/" -> "/P2Pool/" OP_RETURN: "c2pool merged mining" -> "P2Pool merged mining" Mismatch caused 426 merkle_root failures per session on every peer share. 3. DOGE testnet P2P port: 44556 (RPC) -> 44557 (P2P). CoinBroadcaster connected to RPC port, got non-P2P data, disconnected with "prefix doesn't match" on every attempt. Also: multiaddress PPLNS tests, embedded fallback wiring, FUTURE.md updates.
1 parent 8014f7c commit 00fbd2c

15 files changed

Lines changed: 2631 additions & 95 deletions

docs/FUTURE.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,131 @@ commitment chain is already established on the blockchain.
257257
258258
---
259259
260+
## Multi-Parent Chain Architecture (LTC + DGB Simultaneous Operation)
261+
262+
### Overview
263+
264+
c2pool can serve both Litecoin and DigiByte Scrypt as parent chains simultaneously.
265+
Each parent chain runs its own independent P2Pool sharechain network with separate
266+
ports and validation rules.
267+
268+
### Deployment Models
269+
270+
#### Model A: Two Processes (recommended for first release)
271+
272+
Two independent c2pool instances, each handling one parent chain. Zero code changes
273+
required — works today.
274+
275+
```
276+
# Instance 1: LTC parent + DOGE/PEP/BELLS merged mining
277+
c2pool --integrated --net litecoin \
278+
--p2pool-port 9326 --worker-port 9327 --web-port 8080 \
279+
--coind-address 127.0.0.1 --coind-rpc-port 9332 --coind-p2p-port 9333 \
280+
--merged DOGE:98:127.0.0.1:22555:user:pass \
281+
--merged PEP:63:127.0.0.1:33874:user:pass
282+
283+
# Instance 2: DGB parent + DOGE/PEP/BELLS merged mining
284+
c2pool --integrated --net digibyte \
285+
--p2pool-port 5024 --worker-port 5025 --web-port 8081 \
286+
--coind-address 127.0.0.1 --coind-rpc-port 14024 --coind-p2p-port 12024 \
287+
--merged DOGE:98:127.0.0.1:22555:user:pass \
288+
--merged PEP:63:127.0.0.1:33874:user:pass
289+
```
290+
291+
Miners connect to port 9327 for LTC mining, port 5025 for DGB mining.
292+
293+
**Port allocation:**
294+
295+
| Service | LTC Instance | DGB Instance |
296+
|---------|-------------|-------------|
297+
| P2Pool P2P | 9326 | 5024 |
298+
| Stratum (miners) | 9327 | 5025 |
299+
| Web dashboard | 8080 | 8081 |
300+
301+
**Pros:** Simple, crash-isolated, independent restarts, no code changes.
302+
**Cons:** Duplicate memory for shared state, separate dashboards, merged mining
303+
daemons contacted independently from each instance.
304+
305+
#### Model B: Single Process, Multiple Networks (future optimization)
306+
307+
One c2pool process hosting both parent chain networks. Shares a single `io_context`,
308+
`MergedMiningManager`, and web dashboard.
309+
310+
```
311+
c2pool --integrated \
312+
--net litecoin --worker-port 9327 --p2pool-port 9326 \
313+
--net digibyte --worker-port 5025 --p2pool-port 5024 \
314+
--merged DOGE:98:127.0.0.1:22555:user:pass \
315+
--web-port 8080
316+
```
317+
318+
**Architecture changes required:**
319+
320+
1. **CLI parser** — allow multiple `--net` flags, each followed by its own
321+
`--worker-port` and `--p2pool-port`. Current parser stores a single
322+
`blockchain` variable; needs a vector of network configs.
323+
324+
2. **EnhancedNode instantiation** — create one `EnhancedNode` per parent chain,
325+
each with its own `StratumServer`, `ShareChain`, and `P2PNode`. Currently
326+
`c2pool_refactored.cpp` creates exactly one.
327+
328+
3. **Shared MergedMiningManager** — both parent chains submit aux work to the
329+
same merged mining daemon. When either LTC or DGB finds a share meeting an
330+
aux chain's target, it submits the merged block. DOGE blocks get found from
331+
both LTC and DGB Scrypt work simultaneously, increasing aux chain hit rate.
332+
333+
4. **Unified web dashboard** — single HTTP server on one port, with per-network
334+
API prefix (`/api/ltc/stats`, `/api/dgb/stats`) and a combined overview page.
335+
336+
5. **Shared io_context** — both networks run on the same Boost.ASIO thread pool,
337+
reducing thread overhead.
338+
339+
**Pros:** Single dashboard, shared merged mining state (DOGE contacted once, not
340+
twice), lower memory footprint, simpler operations.
341+
**Cons:** More complex startup/shutdown, single process crash affects both chains.
342+
343+
### Merged Mining Overlap
344+
345+
Both LTC and DGB are Scrypt chains that can merge-mine the same aux coins.
346+
When running both parent chains simultaneously, the merged mining situation:
347+
348+
| Aux Coin | Merged via LTC | Merged via DGB | Notes |
349+
|----------|---------------|---------------|-------|
350+
| DOGE (chain_id=98) | Yes | Yes | Both parents submit DOGE blocks independently |
351+
| PEP (chain_id=63) | Yes | Yes | |
352+
| BELLS (chain_id=16) | Yes | Yes | |
353+
| LKY (chain_id=8211) | Yes | Yes | |
354+
| JKC (chain_id=8224) | Yes | Yes | |
355+
| SHIC (chain_id=74) | Yes | Yes | |
356+
| DINGO (chain_id=98) | Conflicts with DOGE | Conflicts with DOGE | Same chain_id, pick one |
357+
358+
**Important:** Running both parents effectively doubles the hashrate attacking
359+
aux chain targets, since both LTC and DGB share submissions are evaluated against
360+
each aux chain's difficulty. This is especially valuable for low-difficulty aux
361+
chains where even DGB's smaller hashrate regularly finds blocks.
362+
363+
### DGB Node Embedding Decision
364+
365+
**Not planned.** DGB does NOT need embedded SPV because:
366+
367+
- DGB is a parent chain, not an aux chain — miners need full `digibyte-core` for
368+
`getblocktemplate` anyway
369+
- DOGE embedding was justified by DOGE being 73% of combined LTC+DOGE revenue
370+
and requiring a 50GB+ blockchain sync
371+
- DGB miners are dedicated DGB miners who already run the full node
372+
- Embedding effort (header sync, fork handling, difficulty validation) is the same
373+
as DOGE but benefits 100x fewer users
374+
375+
### Implementation Phases
376+
377+
| Phase | Scope | Effort |
378+
|-------|-------|--------|
379+
| **Now** | Model A (two processes) | Zero — works today |
380+
| **Next** | Unified web dashboard proxy | Small — nginx/traefik reverse proxy config |
381+
| **Later** | Model B (single process) | Medium — CLI parser + multi-EnhancedNode |
382+
383+
---
384+
260385
## Stratum Protocol Enhancements (from p2pool-merged-v36)
261386
262387
### `mining.ping` — Not Started

src/c2pool/c2pool_refactored.cpp

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@
4141
#include <c2pool/storage/sharechain_storage.hpp>
4242
#include <c2pool/storage/found_block_store.hpp>
4343
#include <c2pool/payout/payout_manager.hpp>
44+
#include <execinfo.h> // for backtrace()
45+
46+
static void segfault_handler(int sig) {
47+
void* frames[64];
48+
int n = backtrace(frames, 64);
49+
fprintf(stderr, "\n=== SEGFAULT (signal %d) ===\n", sig);
50+
backtrace_symbols_fd(frames, n, STDERR_FILENO);
51+
fprintf(stderr, "=== END SEGFAULT ===\n");
52+
_exit(128 + sig);
53+
}
4454

4555
// Integrated merged mining
4656
#include <c2pool/merged/merged_mining.hpp>
@@ -267,6 +277,7 @@ int main(int argc, char* argv[]) {
267277
// Install signal handlers
268278
std::signal(SIGINT, signal_handler);
269279
std::signal(SIGTERM, signal_handler);
280+
std::signal(SIGSEGV, segfault_handler);
270281

271282
// Initialize logging
272283
core::log::Logger::init();
@@ -379,7 +390,7 @@ int main(int argc, char* argv[]) {
379390
// Well-known P2P ports for coin daemons (same machine as RPC by default)
380391
auto get_coin_p2p_port = [](const std::string& symbol, bool testnet) -> int {
381392
if (symbol == "LTC" || symbol == "ltc") return testnet ? 19335 : 9333;
382-
if (symbol == "DOGE" || symbol == "doge") return testnet ? 44556 : 22556;
393+
if (symbol == "DOGE" || symbol == "doge") return testnet ? 44557 : 22556;
383394
if (symbol == "BTC" || symbol == "btc") return testnet ? 18333 : 8333;
384395
if (symbol == "DGB" || symbol == "dgb") return testnet ? 12026 : 12024;
385396
if (symbol == "PEP" || symbol == "pep") return testnet ? 44874 : 33874;
@@ -1137,16 +1148,18 @@ int main(int argc, char* argv[]) {
11371148
<< " payout_window=" << payout_window_seconds << "s"
11381149
<< " save_interval=" << storage_save_interval << "s";
11391150

1151+
// io_context needed for block verification timers in all modes
1152+
web_server.get_mining_interface()->set_io_context(&ioc);
1153+
11401154
// Wire live coin-daemon RPC so getblocktemplate/submitblock use real data
11411155
if (!embedded_ltc) {
11421156
web_server.set_coin_rpc(node_rpc.get(), &coin_node);
11431157
} else if (embedded_broadcaster && embedded_chain) {
11441158
// Wire embedded node + header-sync callback (now that web_server is alive)
11451159
web_server.set_embedded_node(embedded_node.get());
11461160

1147-
// Wire block verification: check header chain for found blocks
1161+
// Wire block verification for embedded mode
11481162
auto* mi = web_server.get_mining_interface();
1149-
mi->set_io_context(&ioc);
11501163

11511164
// --- Layer +2: Persistent found block storage ---
11521165
// Uses a dedicated LevelDB in the network data dir.
@@ -1796,8 +1809,11 @@ int main(int argc, char* argv[]) {
17961809

17971810
// Wire the ref_hash computation hook for per-connection coinbase generation.
17981811
// This computes the p2pool ref_hash from share fields + tracker state.
1812+
// Also stores the computed share target so mining.notify and share
1813+
// creation use the share difficulty (not block difficulty).
1814+
auto* mi_for_share_bits = web_server.get_mining_interface();
17991815
web_server.get_mining_interface()->set_ref_hash_fn(
1800-
[&p2p_node, &whale_detector](
1816+
[&p2p_node, &whale_detector, mi_for_share_bits](
18011817
const uint256& frozen_prev_share,
18021818
const std::vector<unsigned char>& coinbase_scriptSig,
18031819
const std::vector<unsigned char>& payout_script,
@@ -1824,6 +1840,17 @@ int main(int argc, char* argv[]) {
18241840
params.bits = share_bits;
18251841
params.timestamp = timestamp;
18261842

1843+
// Store share target for mining.notify and share creation
1844+
mi_for_share_bits->m_share_bits.store(share_bits);
1845+
mi_for_share_bits->m_share_max_bits.store(share_max_bits);
1846+
{
1847+
auto st = chain::bits_to_target(share_bits);
1848+
double sd = chain::target_to_difficulty(st);
1849+
LOG_INFO << "[ShareTarget] share_bits=" << std::hex << share_bits
1850+
<< " max_bits=" << share_max_bits << std::dec
1851+
<< " share_diff=" << sd;
1852+
}
1853+
18271854
// Extract pubkey_hash and type from payout_script
18281855
if (payout_script.size() == 25 &&
18291856
payout_script[0] == 0x76 && payout_script[1] == 0xa9 &&
@@ -2272,12 +2299,21 @@ int main(int argc, char* argv[]) {
22722299
auto payouts_map = p2p_node->tracker().get_merged_expected_payouts(
22732300
best, block_target, coinbase_value, chain_id, donation_script);
22742301

2302+
LOG_INFO << "[MM-payout] chain_id=" << chain_id
2303+
<< " coinbase_value=" << coinbase_value
2304+
<< " payouts_map_size=" << payouts_map.size()
2305+
<< " chain_height=" << p2p_node->tracker().chain.get_height(best)
2306+
<< " block_target=" << block_target.GetHex().substr(0,16);
2307+
22752308
// Convert map → sorted vector for coinbase construction
22762309
std::vector<std::pair<std::vector<unsigned char>, uint64_t>> result;
22772310
result.reserve(payouts_map.size());
22782311
for (auto& [script, amount] : payouts_map) {
22792312
if (amount >= 1.0)
22802313
result.emplace_back(script, static_cast<uint64_t>(amount));
2314+
else
2315+
LOG_WARNING << "[MM-payout] Skipping script (len=" << script.size()
2316+
<< ") with amount=" << amount;
22812317
}
22822318
// Sort by script for deterministic coinbase ordering
22832319
std::sort(result.begin(), result.end());

0 commit comments

Comments
 (0)