2626// [1-4] sharechain height at block-find (4 bytes LE)
2727// [5-6] miner count in PPLNS window (2 bytes LE)
2828// [7] pool hashrate class (log2 of H/s)
29- // [8-9 ] share_period (current value, 2 bytes LE)
30- // [10-11] verified chain length (2 bytes LE)
31- // [12-15] pool_aps compressed (4 bytes)
32- // [16 -19] reserved (future THE temporal layer flags )
29+ // [8-15 ] chain fingerprint: SHA256d(PREFIX||IDENTIFIER)[0:8]
30+ // 0 = public p2pool network, nonzero = private chain
31+ // [16-17] share_period (current value, 2 bytes LE )
32+ // [18 -19] verified chain length (2 bytes LE )
3333// If fewer than 20 bytes available, metadata is truncated from the end.
3434
3535#include < cstdint>
@@ -71,23 +71,18 @@ struct TheMetadata {
7171 uint32_t sharechain_height = 0 ; // share chain height at block-find
7272 uint16_t miner_count = 0 ; // unique miners in PPLNS window
7373 uint8_t hashrate_class = 0 ; // log2(pool_hashrate_in_h_per_s)
74- uint32_t chain_fingerprint = 0 ; // SHA256("c2pool-chain-id:" || IDENTIFIER)[0:4 ]
75- // Discoverable chain identity on the blockchain:
74+ uint64_t chain_fingerprint = 0 ; // SHA256d(PREFIX || IDENTIFIER)[0:8 ]
75+ // 8-byte discoverable chain identity on the blockchain:
7676 // 0 = public p2pool network
7777 // nonzero = private chain fingerprint
7878 //
79- // This is a TRUNCATED CRYPTOGRAPHIC HASH of the IDENTIFIER, not the
80- // raw value. The full IDENTIFIER (8 bytes, 2^64 space) cannot be
81- // recovered from 4 bytes of SHA256 output — preimage resistance holds.
82- //
83- // Properties:
84- // Discoverable: same IDENTIFIER → same fingerprint (chain grouping)
85- // Secure: SHA256 preimage resistance protects the consensus secret
86- // Distinguishable: birthday collision at ~65K chains (sufficient)
79+ // SHA256d over PREFIX(8) || IDENTIFIER(8) = 16-byte preimage.
80+ // 8-byte output → collision-free for all practical chain counts.
81+ // IDENTIFIER cannot be recovered (SHA256d preimage resistance).
8782 uint16_t share_period = 0 ; // current share period (seconds)
8883 uint16_t verified_length = 0 ; // verified chain length
8984 uint32_t pool_aps_compressed = 0 ; // compressed pool attempts/s
90- uint32_t reserved = 0 ; // future: THE temporal layer flags
85+ // No reserved bytes — chain_fingerprint uses [8-15], share_period [16-17], verified_length [18-19]
9186
9287 // / Pack into bytes (up to max_bytes, truncated from end)
9388 std::vector<uint8_t > pack (size_t max_bytes = 20 ) const {
@@ -109,8 +104,11 @@ struct TheMetadata {
109104 push32 (sharechain_height); // [1-4]
110105 push16 (miner_count); // [5-6]
111106 push8 (hashrate_class); // [7]
112- push32 (chain_fingerprint); // [8-11] 0 = public, SHA256(IDENTIFIER)[0:4] = private
113- push32 (reserved); // [12-15] future: pool_aps, THE temporal flags
107+ // chain_fingerprint: 8 bytes LE
108+ for (int i = 0 ; i < 8 ; ++i) {
109+ if (out.size () < max_bytes)
110+ out.push_back ((chain_fingerprint >> (8 *i)) & 0xff );
111+ } // [8-15] SHA256d(PREFIX||IDENTIFIER)[0:8]
114112 push16 (share_period); // [16-17]
115113 push16 (verified_length); // [18-19]
116114 return out;
@@ -123,8 +121,11 @@ struct TheMetadata {
123121 if (len >= 5 ) m.sharechain_height = data[1 ] | (data[2 ]<<8 ) | (data[3 ]<<16 ) | (data[4 ]<<24 );
124122 if (len >= 7 ) m.miner_count = data[5 ] | (data[6 ]<<8 );
125123 if (len >= 8 ) m.hashrate_class = data[7 ];
126- if (len >= 12 ) m.chain_fingerprint = data[8 ] | (data[9 ]<<8 ) | (data[10 ]<<16 ) | (data[11 ]<<24 );
127- if (len >= 16 ) m.reserved = data[12 ] | (data[13 ]<<8 ) | (data[14 ]<<16 ) | (data[15 ]<<24 );
124+ if (len >= 16 ) {
125+ m.chain_fingerprint = 0 ;
126+ for (int i = 0 ; i < 8 ; ++i)
127+ m.chain_fingerprint |= uint64_t (data[8 +i]) << (8 *i);
128+ }
128129 if (len >= 18 ) m.share_period = data[16 ] | (data[17 ]<<8 );
129130 if (len >= 20 ) m.verified_length = data[18 ] | (data[19 ]<<8 );
130131 return m;
0 commit comments