Skip to content

Commit b657e2b

Browse files
authored
BTC v36: hoist donation script to chain-agnostic core::donation SSOT (#139)
The donation script bytes are coin-invariant (no network version byte; uniform v36 redeem hash160) yet were duplicated in every per-coin PoolConfig. Per operator FLAG6 re-scope (2026-06-17), the v36 donation must be bitcoin-agnostic. Introduce src/core/donation.hpp as the single source of truth and delegate btc::PoolConfig::get_donation_script() to it, removing the per-coin DONATION_SCRIPT / COMBINED_DONATION_SCRIPT arrays. Pure refactor: identical bytes, all call sites unchanged (they route via get_donation_script). c2pool-btc builds green. Cross-coin follow-up will migrate ltc/doge/bch/dgb to the same delegate. Co-authored-by: frstrtr <frstrtr@users.noreply.github.com>
1 parent 8d700a8 commit b657e2b

2 files changed

Lines changed: 74 additions & 47 deletions

File tree

src/core/donation.hpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#pragma once
2+
//
3+
// donation.hpp — Chain-agnostic c2pool donation script (SINGLE SOURCE OF TRUTH).
4+
//
5+
// The donation output receives the rounding remainder from PPLNS payout
6+
// distribution. The script bytes are IDENTICAL across every coin c2pool mines
7+
// (btc/ltc/bch/dgb): they carry no network version byte, and the v36 redeem
8+
// hash160 is uniform. Only the base58 *rendering* of the address differs per
9+
// coin prefix — never the script the coinbase actually commits to.
10+
//
11+
// Because the bytes are coin-invariant, they live here in core/ and every
12+
// per-coin PoolConfig delegates to core::donation::get_donation_script(). The
13+
// previously-duplicated per-coin arrays are removed: the defect was ownership
14+
// living in a per-coin namespace, not the script content (operator FLAG6
15+
// re-scope 2026-06-17 — donation must be bitcoin-agnostic).
16+
//
17+
// Provenance:
18+
// Pre-V36 (P2PK): forrestv/jtoomim BTC p2pool data.py:68 uncompressed
19+
// pubkey. Bit-identical across coins (verified 2026-04-28).
20+
// V36+ (P2SH 1-of-2 multisig): forrestv + frstrtr/c2pool dev key. The 20-byte
21+
// redeem hash160 (8c627262..8e85) is the shared cross-coin v36 donation
22+
// target (operator FLAG6 ruling 2026-06-17, option-b).
23+
//
24+
25+
#include <array>
26+
#include <cstdint>
27+
#include <vector>
28+
29+
namespace core::donation
30+
{
31+
32+
// Pre-V36 donation script — P2PK: OP_PUSHBYTES_65 <uncompressed pubkey> OP_CHECKSIG.
33+
inline constexpr std::array<uint8_t, 67> DONATION_SCRIPT = {
34+
0x41, // OP_PUSHBYTES_65
35+
0x04, 0xff, 0xd0, 0x3d, 0xe4, 0x4a, 0x6e, 0x11,
36+
0xb9, 0x91, 0x7f, 0x3a, 0x29, 0xf9, 0x44, 0x32,
37+
0x83, 0xd9, 0x87, 0x1c, 0x9d, 0x74, 0x3e, 0xf3,
38+
0x0d, 0x5e, 0xdd, 0xcd, 0x37, 0x09, 0x4b, 0x64,
39+
0xd1, 0xb3, 0xd8, 0x09, 0x04, 0x96, 0xb5, 0x32,
40+
0x56, 0x78, 0x6b, 0xf5, 0xc8, 0x29, 0x32, 0xec,
41+
0x23, 0xc3, 0xb7, 0x4d, 0x9f, 0x05, 0xa6, 0xf9,
42+
0x5a, 0x8b, 0x55, 0x29, 0x35, 0x26, 0x56, 0x66,
43+
0x4b,
44+
0xac // OP_CHECKSIG
45+
};
46+
47+
// V36+ donation script — P2SH: OP_HASH160 <hash160(redeem)> OP_EQUAL.
48+
inline constexpr std::array<uint8_t, 23> COMBINED_DONATION_SCRIPT = {
49+
0xa9, // OP_HASH160
50+
0x14, // PUSH 20 bytes
51+
0x8c, 0x62, 0x72, 0x62, 0x1d, 0x89, 0xe8, 0xfa,
52+
0x52, 0x6d, 0xd8, 0x6a, 0xcf, 0xf6, 0x0c, 0x71,
53+
0x36, 0xbe, 0x8e, 0x85,
54+
0x87 // OP_EQUAL
55+
};
56+
57+
// Returns the donation script for a given share version.
58+
// Pre-V36 shares use the P2PK script; V36+ shares use the combined P2SH script.
59+
inline std::vector<unsigned char> get_donation_script(int64_t share_version)
60+
{
61+
if (share_version >= 36)
62+
return {COMBINED_DONATION_SCRIPT.begin(), COMBINED_DONATION_SCRIPT.end()};
63+
return {DONATION_SCRIPT.begin(), DONATION_SCRIPT.end()};
64+
}
65+
66+
} // namespace core::donation

src/impl/btc/config_pool.hpp

Lines changed: 8 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <btclibs/util/strencodings.h>
77
#include <btclibs/crypto/sha256.h>
88
#include <core/uint256.hpp>
9+
#include <core/donation.hpp>
910

1011
#include <array>
1112
#include <cstdint>
@@ -99,55 +100,15 @@ class PoolConfig : protected core::Fileconfig
99100
// Must match frstrtr/p2pool-merged-v36 p2pool/data.py exactly.
100101
// -----------------------------------------------------------------------
101102

102-
// V35 DONATION_SCRIPT (P2PK: OP_PUSHBYTES_65 <uncompressed pubkey> OP_CHECKSIG).
103-
// Same script bytes as forrestv/jtoomim BTC p2pool data.py:68 — the
104-
// uncompressed pubkey is forrestv's; encoded address differs by network
105-
// (1... on BTC mainnet, L... on LTC). Verified bit-identical 2026-04-28.
106-
static constexpr std::array<uint8_t, 67> DONATION_SCRIPT = {
107-
0x41, // OP_PUSHBYTES_65
108-
0x04, 0xff, 0xd0, 0x3d, 0xe4, 0x4a, 0x6e, 0x11,
109-
0xb9, 0x91, 0x7f, 0x3a, 0x29, 0xf9, 0x44, 0x32,
110-
0x83, 0xd9, 0x87, 0x1c, 0x9d, 0x74, 0x3e, 0xf3,
111-
0x0d, 0x5e, 0xdd, 0xcd, 0x37, 0x09, 0x4b, 0x64,
112-
0xd1, 0xb3, 0xd8, 0x09, 0x04, 0x96, 0xb5, 0x32,
113-
0x56, 0x78, 0x6b, 0xf5, 0xc8, 0x29, 0x32, 0xec,
114-
0x23, 0xc3, 0xb7, 0x4d, 0x9f, 0x05, 0xa6, 0xf9,
115-
0x5a, 0x8b, 0x55, 0x29, 0x35, 0x26, 0x56, 0x66,
116-
0x4b,
117-
0xac // OP_CHECKSIG
118-
};
119-
120-
// V36+ COMBINED_DONATION_SCRIPT (P2SH: OP_HASH160 <hash160(redeem)> OP_EQUAL)
121-
// 1-of-2 multisig redeem: forrestv + frstrtr/c2pool dev key.
122-
//
123-
// INTENTIONAL unified cross-coin v36 donation target. This is NOT inert and
124-
// NOT LTC-only: BTC v36 coinbases deliberately pay this combined P2SH. The
125-
// identical 20-byte hash160 (8c627262..8e85) is emitted by EVERY coin's v36
126-
// gentx (btc/ltc/bch/dgb) via PoolConfig::get_donation_script(>=36). Per-coin
127-
// baseline conformance (vs each coin's own p2pool source) still governs every
128-
// OTHER consensus aspect; the v36 donation target is the one deliberate
129-
// cross-coin exception (operator FLAG6 ruling 2026-06-17, option-b).
130-
//
131-
// The hash160 renders as MLhSmVQxMusLE3pjGFvp4unFckgjeD8LUA under the LTC
132-
// mainnet P2SH prefix; the same hash160 is the shared target on all coins
133-
// (only the base58 rendering differs per coin prefix, the redeem does not).
134-
static constexpr std::array<uint8_t, 23> COMBINED_DONATION_SCRIPT = {
135-
0xa9, // OP_HASH160
136-
0x14, // PUSH 20 bytes
137-
0x8c, 0x62, 0x72, 0x62, 0x1d, 0x89, 0xe8, 0xfa,
138-
0x52, 0x6d, 0xd8, 0x6a, 0xcf, 0xf6, 0x0c, 0x71,
139-
0x36, 0xbe, 0x8e, 0x85,
140-
0x87 // OP_EQUAL
141-
};
142-
143-
// Returns the correct donation script based on share version.
144-
// Pre-V36 shares use the original P2PK donation script.
145-
// V36+ shares use the combined P2SH 1-of-2 multisig script.
103+
// Donation script — delegated to the chain-agnostic single source of
104+
// truth in core::donation. The bytes are coin-invariant (no network
105+
// version byte; uniform v36 redeem hash160), so they are no longer
106+
// duplicated per-coin. See core/donation.hpp for provenance (forrestv
107+
// P2PK pre-v36; combined P2SH 1-of-2 v36+, operator FLAG6 ruling
108+
// 2026-06-17 option-b; bitcoin-agnostic re-scope 2026-06-17).
146109
static std::vector<unsigned char> get_donation_script(int64_t share_version)
147110
{
148-
if (share_version >= 36)
149-
return {COMBINED_DONATION_SCRIPT.begin(), COMBINED_DONATION_SCRIPT.end()};
150-
return {DONATION_SCRIPT.begin(), DONATION_SCRIPT.end()};
111+
return core::donation::get_donation_script(share_version);
151112
}
152113

153114
// Message framing prefix — BTC mainnet (jtoomim bitcoin.py:14):

0 commit comments

Comments
 (0)