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
12 changes: 10 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## [0.14.0-v36] - 2026-07-10

### Licensing
- **Relicensed MIT → AGPL-3.0-or-later** — the c2pool daemon (RPC/Stratum, merged-mining coordination, node management) is now AGPL-3.0-or-later. The extracted primitive layer ships separately as **c2pool-core-engine** under Apache-2.0. Bundled `src/btclibs/` and third-party crypto retain their original MIT notices. (#658)

### Release
- **c2pool v36 — LTC + DOGE** — first v36 release: LTC parent with DOGE merged-mining (AuxPoW) in one unified binary; AutoRatchet v35→v36 crossing (95% / 60-block / 2× work), work-weighted PPLNS accept gate, and trustless merged-payout coinbase commitment. Multiplatform packages (Linux / macOS / Windows).

## [0.1.1-alpha] - 2026-04-13

### Stability (Critical)
Expand Down Expand Up @@ -287,8 +295,8 @@
eliminates silent payout truncation on busy pools
- `MINIMUM_PAYOUT_SATOSHIS` fixed from 100 000 to 1 — coinbase outputs are
exempt from the dust limit
- P2P default ports corrected: mainnet 9326 → 9338
- YAML testnet ports corrected: p2p 9333 → 19338, stratum 8084 → 19327
- P2P default port: mainnet 9326 (matches p2pool-merged-v36 sharechain)
- YAML testnet ports corrected: p2p 9333 → 19326, stratum 8084 → 19327
- Ghost share tracker silenced via `vardiff_enabled_` flag
- Stale sharechain view crash on missing shares

Expand Down
26 changes: 19 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ C++ reimplementation of [forrestv/p2pool](https://github.com/p2pool/p2pool) targ
Bitcoin wiki: <https://en.bitcoin.it/wiki/P2Pool>
Original forum thread: <https://bitcointalk.org/index.php?topic=18313>

## Credits

c2pool is an independent C++ implementation of the P2Pool sharechain concept originally created by Forrest Voight (forrestv, <https://github.com/forrestv/p2pool>).

> **First merged-mined DOGE block:** [#6135703](https://blockchair.com/dogecoin/block/f84500c25a4cce2a08887f29763726bd5ecec7b66fed65a88b181fb0b0ab2383) (2026-03-23) — decentralized LTC+DOGE merged mining via P2Pool V36, cross-validated with c2pool on shared share chain
>
> **First daemonless DOGE block:** (2026-03-27) — DOGE block accepted on testnet4alpha via embedded SPV P2P, no dogecoind RPC needed
Expand Down Expand Up @@ -60,7 +64,7 @@ Get-FileHash c2pool-*-setup.exe -Algorithm SHA256

All release binaries are built from the tagged git commit. To verify a binary matches the source:

1. Check the git tag: `git log v0.1.1-alpha --oneline -1`
1. Check the git tag: `git log v0.14.0-v36-ltc-doge --oneline -1`
2. Build from that tag following the platform-specific guide
3. Compare the SHA256 of your binary with the release `SHA256SUMS`

Expand Down Expand Up @@ -334,16 +338,16 @@ complete examples with all options documented.
| `--rpcuser` | `ltc_rpc_user` | -- | RPC username |
| `--rpcpassword` | `ltc_rpc_password` | -- | RPC password |
| `--max-conns` | -- | 8 | Target outbound P2P peers |
| `--stratum-min-diff` | `min_difficulty` | 0.001 | Vardiff floor |
| `--stratum-min-diff` | `min_difficulty` | 0.0005 | Vardiff floor |
| `--stratum-max-diff` | `max_difficulty` | 65536 | Vardiff ceiling |
| `--stratum-target-time` | `target_time` | 10 | Seconds between pseudoshares |
| `--stratum-target-time` | `target_time` | 3.0 | Seconds between pseudoshares |
| `--no-vardiff` | `vardiff_enabled` | true | Disable auto-difficulty |
| `--max-coinbase-outputs` | `max_coinbase_outputs` | 4000 | Max coinbase outputs |
| `--network-id` | `network_id` | 0 | Private chain identifier (hex) |
| `--log-level` | `log_level` | INFO | trace/debug/info/warning/error |
| `--log-file` | `log_file` | debug.log | Log filename |
| `--log-rotation-mb` | `log_rotation_size_mb` | 100 | Log rotation threshold (MB) |
| `--log-max-mb` | `log_max_total_mb` | 50 | Max rotated log space (MB) |
| `--log-max-mb` | `log_max_total_mb` | 1000 | Total size cap across all rotated log files (MB) |
| `--p2p-max-peers` | `p2p_max_peers` | 30 | Max total P2P peers |
| `--ban-duration` | `ban_duration` | 300 | P2P ban duration (seconds) |
| `--rss-limit-mb` | `rss_limit_mb` | 4000 | RSS memory abort limit (MB) |
Expand Down Expand Up @@ -375,7 +379,7 @@ complete examples with all options documented.
| `/recent_blocks` | Recently found blocks |
| `/connected_miners` | Connected stratum workers |
| `/stratum_stats` | Per-worker stratum statistics (hashrate, difficulty, accepted/rejected) |
| `/sharechain_stats` | Share chain state |
| `/sharechain/stats` | Share chain state |
| `/miner_thresholds` | Minimum viable hashrate, dust range |
| `/merged_stats` | Merged mining block statistics |
| `/current_merged_payouts` | Current merged mining payouts |
Expand Down Expand Up @@ -520,11 +524,19 @@ cd build && ctest --output-on-failure -j$(nproc)

## V37 development

- Github pages: <[https://t.me/c2pooldev](https://frstrtr.github.io/c2pool/)>
- V37 dev branch primitives: <[https://github.com/frstrtr/c2pool/compare/master...v37-dev](https://github.com/frstrtr/c2pool/compare/master...v37-dev)>
- **V37 Purple Paper** (Work Receipts design): https://frstrtr.github.io/c2pool/purple-paper.html
- Dev chat (Telegram): https://t.me/c2pooldev
- V37 dev-branch primitives (diff): https://github.com/frstrtr/c2pool/compare/master...v37-dev

---

## License

- **c2pool daemon** (this repository): [AGPL-3.0-or-later](LICENSE). Network use triggers the AGPL source-provision obligation.
- **c2pool-core-engine** (extracted primitive layer): Apache-2.0, in the separate [c2pool-core-engine](https://github.com/frstrtr/c2pool-core-engine) repository.
- **Bundled `src/btclibs/` and third-party crypto**: retain their original MIT licenses (notices preserved in-file).
- **V37 Purple Paper** (frstrtr.github.io/c2pool): MIT License (as with the Bitcoin whitepaper). The remaining site articles are © technocore.one, all rights reserved.

### Install guides
- [Ubuntu / Debian / Linux](doc/build-unix.md)
- [macOS (Intel & Apple Silicon)](doc/build-macos.md)
Expand Down
27 changes: 22 additions & 5 deletions src/c2pool/c2pool_refactored.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,8 @@
std::cout << " --cors-origin ORIGIN CORS Access-Control-Allow-Origin (default: disabled)\n";
std::cout << " --payout-window N PPLNS payout window in seconds (default: 86400)\n";
std::cout << " --storage-save-interval N Periodic sharechain save interval in seconds (default: 300)\n";
std::cout << " --dashboard-dir PATH Dashboard static files directory (default: web-static)\n\n";
std::cout << " --dashboard-dir PATH Dashboard static files directory (default: web-static)\n";
std::cout << " --analytics-id ID Google Analytics measurement ID (e.g. G-XXXXXXXXXX)\n\n";

std::cout << "BLOCKCHAIN SUPPORT:\n";
std::cout << "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
Expand Down Expand Up @@ -613,7 +614,7 @@
std::string redistribute_mode_str = "pplns";

// Stratum tuning (configurable via CLI or YAML)
core::StratumConfig stratum_config; // defaults: min=0.001, max=65536, target=10s, vardiff=true
core::StratumConfig stratum_config; // defaults: min=0.0005, max=65536, target=3.0s, vardiff=true

// Operational tuning (configurable via CLI or YAML)
std::string log_file; // empty = default "debug.log"
Expand Down Expand Up @@ -1086,6 +1087,10 @@
dashboard_dir = argv[++i];
cli_explicit.insert("dashboard_dir");
}
else if (arg == "--analytics-id" && i + 1 < argc) {
analytics_id = argv[++i];

Check notice

Code scanning / CodeQL

For loop variable changed in body Note

Loop counters should not be modified in the body of the
loop
.
cli_explicit.insert("analytics_id");
}
// Seed node: -n HOST:PORT (p2pool compat)
else if (arg == "-n" && i + 1 < argc) {
seed_nodes.push_back(argv[++i]);
Expand Down Expand Up @@ -1228,6 +1233,14 @@
if (!cli_explicit.count("message_blob_hex") && cfg["message_blob_hex"])
operator_message_blob_hex = cfg["message_blob_hex"].as<std::string>();

// Custom coinbase scriptSig text (CLI --coinbase-text takes precedence)
if (!cli_explicit.count("coinbase_text") && cfg["coinbase_text"])
coinbase_text = cfg["coinbase_text"].as<std::string>();

// Private sharechain identifier, hex (CLI --network-id/--chain-id takes precedence)
if (!cli_explicit.count("network_id") && cfg["network_id"])
network_id = std::stoull(cfg["network_id"].as<std::string>(), nullptr, 16);

// Stratum tuning
if (!cli_explicit.count("stratum_min_diff") && cfg["min_difficulty"])
stratum_config.min_difficulty = cfg["min_difficulty"].as<double>();
Expand Down Expand Up @@ -1263,7 +1276,7 @@
storage_save_interval = cfg["storage_save_interval"].as<int>();
if (!cli_explicit.count("dashboard_dir") && cfg["dashboard_dir"])
dashboard_dir = cfg["dashboard_dir"].as<std::string>();
if (cfg["analytics_id"])
if (!cli_explicit.count("analytics_id") && cfg["analytics_id"])
analytics_id = cfg["analytics_id"].as<std::string>();
if (cfg["explorer"])
explorer_enabled = cfg["explorer"].as<bool>();
Expand Down Expand Up @@ -1360,8 +1373,12 @@
"THIS IS EXPERIMENTAL SOFTWARE -- USE AT YOUR OWN RISK",
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY",
"OF ANY KIND, EXPRESS OR IMPLIED.",
"Distributed under the MIT/X11 software license",
"See http://www.opensource.org/licenses/mit-license.php",
"Distributed under the GNU AGPL-3.0-or-later license.",
"This is free software; see the source for copying terms.",
"AGPL section 13: if you run a modified version and let",
"users interact with it over a network, you must offer",
"them the corresponding source code.",
"Source: https://github.com/frstrtr/c2pool",
}, rows);
for (const auto& r : rows) LOG_WARNING << r;
}
Expand Down
2 changes: 1 addition & 1 deletion src/c2pool/hashrate/tracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ void HashrateTracker::set_difficulty_hint(double hint) {
// Matches p2pool's stratum vardiff algorithm (stratum.py:546-573).
// Adjusts difficulty to target ~target_time_per_mining_share_ seconds per pseudoshare.
//
// Two triggers (matching p2pool exactly):
// Two triggers (as in p2pool's vardiff):
// 1) Normal: after VARDIFF_TRIGGER shares accumulated.
// 2) Timeout: elapsed time exceeds TIMEOUT_MULT * N * target_time.
//
Expand Down
10 changes: 5 additions & 5 deletions src/impl/bch/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ void NodeImpl::broadcast_share(const uint256& share_hash)
void NodeImpl::notify_local_share(const uint256& share_hash)
{
// p2pool: set_best_share() → think() synchronously on the reactor thread.
// Use think() for ALL best_share decisions, matching p2pool exactly.
// Use think() for ALL best_share decisions, as p2pool does.
if (share_hash.IsNull())
return;

Expand Down Expand Up @@ -965,7 +965,7 @@ void NodeImpl::readvertise_best()

void NodeImpl::download_shares(peer_ptr /*unused_peer*/, const uint256& target_hash)
{
// p2pool node.py:108-141 download_shares() — exact translation.
// download_shares(): C++ implementation of the p2pool share-download loop.
//
// Key differences from old c2pool implementation:
// 1. RANDOM peer selection (not the reporting peer)
Expand Down Expand Up @@ -1326,7 +1326,7 @@ void NodeImpl::start_outbound_connections()

void NodeImpl::prune_shares(const uint256& /*best_share*/)
{
// Matches p2pool node.py:381-398 tail-dropping exactly:
// Tail-dropping (as in p2pool's clean_tracker):
// - Check each tail: if min(height(head) for heads) < 2*CL+10 → skip
// - Remove ONE child of qualifying tail per iteration
// - Loop up to 1000 times (gradual, not bulk)
Expand Down Expand Up @@ -1873,7 +1873,7 @@ void NodeImpl::heartbeat_log()
}

// Periodic maintenance: eat stale heads, drop tails.
// Direct translation of p2pool node.py:355-402 clean_tracker().
// C++ implementation of the p2pool clean_tracker() design (stale-head eating + tail dropping).
//
// Runs on the compute thread under exclusive lock — matching p2pool where
// clean_tracker + think() execute on the same reactor thread. Chain
Expand Down Expand Up @@ -2007,7 +2007,7 @@ void NodeImpl::clean_tracker()
}

// Step 3: Drop tails — remove ALL children of qualifying tails.
// Exact translation of p2pool node.py:382-398.
// C++ implementation of the p2pool tail-dropping step.
// p2pool has NO best-chain protection — the 2*CHAIN_LENGTH+10 threshold
// ensures only shares far beyond the PPLNS window are removed.
{
Expand Down
2 changes: 1 addition & 1 deletion src/impl/bch/pool_monitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// [MONITOR-DIFF] — difficulty anomaly detection
// [MONITOR-SUMMARY] — one-line health summary
//
// Port of p2pool-v36 p2pool/monitor.py (commit d831a045).
// C++ implementation of the p2pool-v36 monitor.py design (ref commit d831a045).
//
// BCH note: BCH is a SHA256d standalone-parent chain (no merged-mining,
// no AuxPoW, no SegWit/witness). This monitor is coin-independent — it only
Expand Down
2 changes: 1 addition & 1 deletion src/impl/bch/share_check.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -950,7 +950,7 @@ inline std::vector<unsigned char> get_share_script(const auto* obj)
// the PPLNS weights computed from the share chain. Returns the expected
// gentx txid (double-SHA256 of the non-witness serialised transaction).
//
// This is the C++ port of p2pool v36's generate_transaction() / check().
// C++ implementation of the p2pool v36 generate_transaction() / check() design.
//
// The coinbase structure is:
// tx_ins: [ { prev_output: 0...0:ffffffff, script: coinbase } ]
Expand Down
2 changes: 1 addition & 1 deletion src/impl/bch/share_messages.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
// share_messages.hpp — V36 share-embedded messaging: decryption + validation
//
// Port of p2pool/share_messages.py (consensus-critical portions).
// C++ implementation of the p2pool share_messages design (consensus-critical portions).
// Messages are embedded in V36 shares' message_data field, included
// in the ref_hash computation (PoW-protected).
//
Expand Down
10 changes: 4 additions & 6 deletions src/impl/bch/share_tracker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -792,11 +792,9 @@ class ShareTracker

auto [last_height, last_last_hash] = chain.get_height_and_last(last_hash);

// oracle data.py:774-776 EXACTLY:
// want = max(CHAIN_LENGTH - head_height, 0)
// can = max(last_height - 1 - CHAIN_LENGTH, 0) if last_last_hash
// is not None else last_height
// get = min(want, can)
// Bounded backfill window: request as many shares as the chain is
// short of CHAIN_LENGTH (want), capped by how many the rooted peer
// can actually supply (can); to_get = min(want, can).
auto CL = static_cast<int32_t>(PoolConfig::chain_length());
auto want = std::max(CL - head_height, 0);
auto can = last_last_hash.IsNull()
Expand Down Expand Up @@ -1928,7 +1926,7 @@ class ShareTracker
if (prev_share_hash.IsNull())
return uint256{};

// RAW chain, matching p2pool compute_merged_payout_hash (data.py:2807).
// RAW chain, matching p2pool's compute_merged_payout_hash.
if (!chain.contains(prev_share_hash))
return uint256{};

Expand Down
2 changes: 1 addition & 1 deletion src/impl/bch/test/coinbase_kat_bytevector_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//
// >>> ORACLE GROUND-TRUTH PROVENANCE <<<
// The expected hex below was emitted by p2pool/util/pack.py`s tx_id_type --
// reconstructed VERBATIM from p2pool/bitcoin/data.py:133-138 (version IntType(32)
// reconstructed to match the p2pool/bitcoin data.py serialization (version IntType(32)
// | ListType(tx_in) | ListType(tx_out) | lock_time IntType(32)) -- run over this
// fixed coinbase:
// version = 1
Expand Down
2 changes: 1 addition & 1 deletion src/impl/btc/auto_ratchet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
// (permanent on restart) |
// CONFIRMED <--------------------------+
//
// Port of p2pool-v36 data.py AutoRatchet (lines 2109-2344).
// C++ implementation of the p2pool-v36 AutoRatchet design.

#include "config_pool.hpp"
#include "share_tracker.hpp"
Expand Down
10 changes: 5 additions & 5 deletions src/impl/btc/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ void NodeImpl::broadcast_share(const uint256& share_hash)
void NodeImpl::notify_local_share(const uint256& share_hash)
{
// p2pool: set_best_share() → think() synchronously on the reactor thread.
// Use think() for ALL best_share decisions, matching p2pool exactly.
// Use think() for ALL best_share decisions, as p2pool does.
if (share_hash.IsNull())
return;

Expand Down Expand Up @@ -962,7 +962,7 @@ void NodeImpl::readvertise_best()

void NodeImpl::download_shares(peer_ptr /*unused_peer*/, const uint256& target_hash)
{
// p2pool node.py:108-141 download_shares() — exact translation.
// download_shares(): C++ implementation of the p2pool share-download loop.
//
// Key differences from old c2pool implementation:
// 1. RANDOM peer selection (not the reporting peer)
Expand Down Expand Up @@ -1323,7 +1323,7 @@ void NodeImpl::start_outbound_connections()

void NodeImpl::prune_shares(const uint256& /*best_share*/)
{
// Matches p2pool node.py:381-398 tail-dropping exactly:
// Tail-dropping (as in p2pool's clean_tracker):
// - Check each tail: if min(height(head) for heads) < 2*CL+10 → skip
// - Remove ONE child of qualifying tail per iteration
// - Loop up to 1000 times (gradual, not bulk)
Expand Down Expand Up @@ -1870,7 +1870,7 @@ void NodeImpl::heartbeat_log()
}

// Periodic maintenance: eat stale heads, drop tails.
// Direct translation of p2pool node.py:355-402 clean_tracker().
// C++ implementation of the p2pool clean_tracker() design (stale-head eating + tail dropping).
//
// Runs on the compute thread under exclusive lock — matching p2pool where
// clean_tracker + think() execute on the same reactor thread. Chain
Expand Down Expand Up @@ -2004,7 +2004,7 @@ void NodeImpl::clean_tracker()
}

// Step 3: Drop tails — remove ALL children of qualifying tails.
// Exact translation of p2pool node.py:382-398.
// C++ implementation of the p2pool tail-dropping step.
// p2pool has NO best-chain protection — the 2*CHAIN_LENGTH+10 threshold
// ensures only shares far beyond the PPLNS window are removed.
{
Expand Down
2 changes: 1 addition & 1 deletion src/impl/btc/pool_monitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// [MONITOR-DIFF] — difficulty anomaly detection
// [MONITOR-SUMMARY] — one-line health summary
//
// Port of p2pool-v36 p2pool/monitor.py (commit d831a045).
// C++ implementation of the p2pool-v36 monitor.py design (ref commit d831a045).

#include "config_pool.hpp"
#include "share_tracker.hpp"
Expand Down
2 changes: 1 addition & 1 deletion src/impl/btc/redistribute.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
//
// Consensus-safe: only affects pubkey_hash stamped into shares on this node.
//
// Port of p2pool-v36 work.py --redistribute (commit de76224a) + FUTURE.md V2 spec.
// C++ implementation of the p2pool-v36 work.py --redistribute design (ref commit de76224a) + FUTURE.md V2 spec.

#include "config_pool.hpp"
#include "share_tracker.hpp"
Expand Down
2 changes: 1 addition & 1 deletion src/impl/btc/share_check.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -917,7 +917,7 @@ inline std::vector<unsigned char> get_share_script(const auto* obj)
// the PPLNS weights computed from the share chain. Returns the expected
// gentx txid (double-SHA256 of the non-witness serialised transaction).
//
// This is the C++ port of p2pool v36's generate_transaction() / check().
// C++ implementation of the p2pool v36 generate_transaction() / check() design.
//
// The coinbase structure is:
// tx_ins: [ { prev_output: 0...0:ffffffff, script: coinbase } ]
Expand Down
2 changes: 1 addition & 1 deletion src/impl/btc/share_messages.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
// share_messages.hpp — V36 share-embedded messaging: decryption + validation
//
// Port of p2pool/share_messages.py (consensus-critical portions).
// C++ implementation of the p2pool share_messages design (consensus-critical portions).
// Messages are embedded in V36 shares' message_data field, included
// in the ref_hash computation (PoW-protected).
//
Expand Down
Loading
Loading