1111#include < sharechain/share.hpp>
1212#include < sharechain/sharechain.hpp>
1313#include < core/target_utils.hpp>
14+ #include < core/version_gate.hpp> // SSOT: core::version_gate::is_v36_active
1415
1516#include < chrono>
1617
@@ -57,6 +58,17 @@ struct DashFormatter
5758 template <typename StreamType, typename ShareT>
5859 static void Read (StreamType& is, ShareT* share)
5960 {
61+ // V36 shares (wire-type 36, dash::DashV36Share) use the standardized
62+ // cross-coin v36 layout. Compile-time dispatch: the v16 body below is
63+ // instantiated ONLY for DashShare (version 16), so it stays byte-
64+ // unchanged; the v36 body is instantiated ONLY for DashV36Share.
65+ if constexpr (core::version_gate::is_v36_active (ShareT::version))
66+ {
67+ ReadV36 (is, share);
68+ return ;
69+ }
70+ else
71+ {
6072 // ── min_header ──
6173 is >> share->m_min_header ;
6274
@@ -136,11 +148,19 @@ struct DashFormatter
136148
137149 // ── coinbase_payload (outer) ──
138150 is >> share->m_coinbase_payload_outer ; // PossiblyNone('', VarStr)
151+ } // else (v16)
139152 }
140153
141154 template <typename StreamType, typename ShareT>
142155 static void Write (StreamType& os, const ShareT* share)
143156 {
157+ if constexpr (core::version_gate::is_v36_active (ShareT::version))
158+ {
159+ WriteV36 (os, share);
160+ return ;
161+ }
162+ else
163+ {
144164 os << share->m_min_header ;
145165 os << share->m_prev_hash ;
146166 os << share->m_coinbase ;
@@ -180,6 +200,124 @@ struct DashFormatter
180200 os << share->m_hash_link ;
181201 os << share->m_merkle_link .m_branch ;
182202 os << share->m_coinbase_payload_outer ;
203+ } // else (v16)
204+ }
205+
206+ // ═══════════════════════════════════════════════════════════════════════
207+ // V36 (wire-type 36) read/write — STANDARDIZED cross-coin non-segwit v36
208+ // layout (the bch/ltc/dgb MergedMiningShare shape MINUS segwit_data) plus
209+ // the DASH-specific suffix. Field ORDER and ENCODINGS mirror the BCH v36
210+ // Formatter (src/impl/bch/share.hpp) byte-for-byte for the standardized
211+ // prefix; the suffix (coinbase_payload / payment_amount / packed_payments /
212+ // coinbase_payload_outer) rides AFTER message_data. Pinned by the byte-
213+ // parity + round-trip KATs in test/test_dash_v36_share.cpp.
214+ // ═══════════════════════════════════════════════════════════════════════
215+ template <typename StreamType, typename ShareT>
216+ static void ReadV36 (StreamType& is, ShareT* share)
217+ {
218+ // ── min_header ──
219+ is >> share->m_min_header ;
220+
221+ // ── share_data (standardized v36) ──
222+ is >> share->m_prev_hash ; // PossiblyNone(0, IntType(256))
223+ is >> share->m_coinbase ; // VarStr
224+ is >> share->m_nonce ; // uint32
225+ is >> share->m_pubkey_hash ; // v36 address: IntType(160)
226+ is >> share->m_pubkey_type ; // v36: IntType(8)
227+ { uint64_t sub; ::Unserialize (is, VarInt (sub)); share->m_subsidy = sub; } // v36: VarInt
228+ is >> share->m_donation ; // uint16
229+ { uint8_t si; is >> si; share->m_stale_info = static_cast <dash::StaleInfo>(si); }
230+ { uint64_t dv; ::Unserialize (is, VarInt (dv)); share->m_desired_version = dv; } // version-vote
231+
232+ // NO segwit_data (non-segwit coin — BCH convention).
233+
234+ // v36 merged_addresses (empty/inert on DASH).
235+ is >> share->m_merged_addresses ;
236+
237+ // NO tx_info (only serialized for version < 34).
238+
239+ is >> share->m_far_share_hash ; // PossiblyNone(0, IntType(256))
240+ is >> share->m_max_bits ; // uint32
241+ is >> share->m_bits ; // uint32
242+ is >> share->m_timestamp ; // uint32
243+ is >> share->m_absheight ; // uint32
244+ ::Unserialize (is, Using<v36::AbsworkV36Format>(share->m_abswork)); // v36: VarInt low64
245+
246+ // v36 merged_coinbase_info + merged_payout_hash (empty/zero-inert on DASH).
247+ is >> share->m_merged_coinbase_info ;
248+ is >> share->m_merged_payout_hash ;
249+
250+ // ref_merkle_link (MERKLE_LINK_SMALL — index omitted).
251+ { ParamPackStream ps{v36::MERKLE_LINK_SMALL , is}; ::Unserialize (ps, share->m_ref_merkle_link ); }
252+
253+ is >> share->m_last_txout_nonce ; // uint64
254+ is >> share->m_hash_link ; // V36HashLinkType
255+
256+ { ParamPackStream ps{v36::MERKLE_LINK_SMALL , is}; ::Unserialize (ps, share->m_merkle_link ); }
257+
258+ is >> share->m_message_data ; // v36 messaging hook (empty on DASH Phase A)
259+
260+ // ── DASH-specific suffix (FLAGGED divergence) ──
261+ is >> share->m_coinbase_payload ; // PossiblyNone('', VarStr)
262+ is >> share->m_payment_amount ; // uint64
263+ {
264+ uint64_t count;
265+ ::Unserialize (is, VarInt(count));
266+ if (count > MAX_PAYMENTS_PER_SHARE )
267+ throw std::ios_base::failure (" packed_payments count exceeds cap" );
268+ share->m_packed_payments .resize (count);
269+ for (uint64_t i = 0 ; i < count; ++i) {
270+ BaseScript payee_bs;
271+ is >> payee_bs;
272+ share->m_packed_payments [i].m_payee .assign (
273+ payee_bs.m_data .begin (), payee_bs.m_data .end ());
274+ is >> share->m_packed_payments [i].m_amount ;
275+ }
276+ }
277+ is >> share->m_coinbase_payload_outer ; // PossiblyNone('', VarStr)
278+ }
279+
280+ template <typename StreamType, typename ShareT>
281+ static void WriteV36 (StreamType& os, const ShareT* share)
282+ {
283+ os << share->m_min_header ;
284+ os << share->m_prev_hash ;
285+ os << share->m_coinbase ;
286+ os << share->m_nonce ;
287+ os << share->m_pubkey_hash ;
288+ os << share->m_pubkey_type ;
289+ ::Serialize (os, VarInt(share->m_subsidy));
290+ os << share->m_donation ;
291+ { uint8_t si = static_cast <uint8_t >(share->m_stale_info ); os << si; }
292+ ::Serialize (os, VarInt(share->m_desired_version));
293+ os << share->m_merged_addresses ;
294+ os << share->m_far_share_hash ;
295+ os << share->m_max_bits ;
296+ os << share->m_bits ;
297+ os << share->m_timestamp ;
298+ os << share->m_absheight ;
299+ ::Serialize (os, Using<v36::AbsworkV36Format>(share->m_abswork));
300+ os << share->m_merged_coinbase_info ;
301+ os << share->m_merged_payout_hash ;
302+ { ParamPackStream ps{v36::MERKLE_LINK_SMALL , os}; ::Serialize (ps, share->m_ref_merkle_link ); }
303+ os << share->m_last_txout_nonce ;
304+ os << share->m_hash_link ;
305+ { ParamPackStream ps{v36::MERKLE_LINK_SMALL , os}; ::Serialize (ps, share->m_merkle_link ); }
306+ os << share->m_message_data ;
307+ // ── DASH-specific suffix (FLAGGED divergence) ──
308+ os << share->m_coinbase_payload ;
309+ os << share->m_payment_amount ;
310+ {
311+ uint64_t count = share->m_packed_payments .size ();
312+ ::Serialize (os, VarInt(count));
313+ for (auto & pay : share->m_packed_payments ) {
314+ BaseScript bs;
315+ bs.m_data .assign (pay.m_payee .begin (), pay.m_payee .end ());
316+ os << bs;
317+ os << pay.m_amount ;
318+ }
319+ }
320+ os << share->m_coinbase_payload_outer ;
183321 }
184322};
185323
@@ -188,6 +326,22 @@ struct DashFormatter
188326
189327using ShareType = chain::ShareVariants<DashFormatter, DashShare>;
190328
329+ // ── PHASE A: v36 share-type dispatch (DORMANT) ───────────────────────────────
330+ // The live `ShareType` above is DELIBERATELY left as {DashShare} only, so the
331+ // live accept / mint / store / send paths (node.cpp) stay byte-unchanged and
332+ // keep compiling — several consume the share via generic-invoke lambdas that
333+ // call DashShare-concrete helpers (e.g. share_init_verify(const DashShare&) at
334+ // node.cpp:64). Promoting DashV36Share into the live variant requires guarding
335+ // those call sites with `if constexpr (std::is_same_v<share_t, DashShare>)`, and
336+ // is the FIRST wiring step of Phase B/C — NOT Phase A.
337+ //
338+ // This SEPARATE variant proves the v36 wire type round-trips through the REAL
339+ // chain::ShareVariants dispatch machinery (load map keyed by version 36 ->
340+ // DashV36Share, DashFormatter::ReadV36/WriteV36). It is what the round-trip KAT
341+ // exercises. Nothing mints a v36 share (current_share_version stays 16), so the
342+ // type is parseable/mintable-in-principle yet dormant until Phase-C activation.
343+ using V36ShareType = chain::ShareVariants<DashFormatter, DashV36Share>;
344+
191345// ── Load share from wire format ──────────────────────────────────────────────
192346
193347inline ShareType load_share (chain::RawShare& rshare, NetService peer_addr)
@@ -200,6 +354,16 @@ inline ShareType load_share(chain::RawShare& rshare, NetService peer_addr)
200354 return share;
201355}
202356
357+ // PHASE A v36 load helper (dispatch-by-version-36). Mirrors load_share but over
358+ // the dormant V36ShareType variant; used by the round-trip KAT.
359+ inline V36ShareType load_v36_share (chain::RawShare& rshare, NetService peer_addr)
360+ {
361+ auto stream = rshare.contents .as_stream ();
362+ auto share = V36ShareType::load (rshare.type , stream);
363+ share.ACTION ({ obj->peer_addr = peer_addr; });
364+ return share;
365+ }
366+
203367// ── ShareHasher ──────────────────────────────────────────────────────────────
204368
205369struct ShareHasher
0 commit comments