@@ -1016,11 +1016,13 @@ TEST(DashConformanceVersionNeg, SwitchClassifier5CaseKat) {
10161016 successor_switch_allowed (clears, 36u )));
10171017}
10181018
1019- // === verify_version_transition: the WIRED accept-path gate (not the isolated
1020- // primitives above). Proves dash::verify_version_transition composes the
1021- // version_negotiation primitives into admit/reject enforcement at a version
1022- // boundary -- the mint<->accept coupling that was previously ZERO-consumer on
1023- // dash. CHAIN_LENGTH (CL) is small (20) so the [9/10..10/10] tail window is
1019+ // === dash::verify_share: the WIRED accept-path entry (not the isolated
1020+ // primitives above, and not the orphan verify_version_transition the S8-prep
1021+ // KAT used). Proves the version-boundary gate fires through the SAME combined
1022+ // entry a node calls -- closing the enforcement hole where the gate had ZERO
1023+ // accept-path consumers. verify_init=false because Phase 1 (X11 PoW/hash_link)
1024+ // runs in the node thread pool; these cases lock the Phase-2 chain-context
1025+ // WIRING. The init-composition case below proves Phase 1 is wired too. CHAIN_LENGTH (CL) is small (20) so the [9/10..10/10] tail window is
10241026// reachable in a synthetic chain; the exact 60%/95% floors are pinned by the
10251027// isolation KATs above, so these lock the WIRING, not the thresholds.
10261028namespace {
@@ -1034,6 +1036,7 @@ uint256 build_uniform(SyntheticChain& sc, int count, uint64_t version,
10341036 return prev;
10351037}
10361038constexpr uint64_t CL = 20 ; // synthetic CHAIN_LENGTH for the gate window
1039+ core::CoinParams kVgParams ; // accept-entry param (unused when verify_init=false)
10371040} // namespace
10381041
10391042// Same-version share is never a boundary -> always admitted (data.py:382).
@@ -1042,7 +1045,7 @@ TEST(DashConformanceVersionWiring, SameVersionAdmitted) {
10421045 const uint160 A = miner_h160 (0x10 );
10431046 uint256 tip = build_uniform (sc, 22 , 36 , BITS_DIFF1 , A);
10441047 add_versioned (sc, 0x80 , tip, 36 , BITS_DIFF1 , A);
1045- EXPECT_NO_THROW (dash::verify_version_transition (*sc.pool .back (), sc.chain , CL ));
1048+ EXPECT_NO_THROW (dash::verify_share (*sc.pool .back (), sc.chain , CL , kVgParams , /* verify_init= */ false ));
10461049}
10471050
10481051// Upgrade boundary with fewer than CHAIN_LENGTH ancestors -> rejected
@@ -1053,7 +1056,7 @@ TEST(DashConformanceVersionWiring, UpgradeWithoutHistoryRejected) {
10531056 uint256 tip = build_uniform (sc, 5 , 16 , BITS_DIFF1 , A); // < CL ancestors
10541057 add_versioned (sc, 0x81 , tip, 36 , BITS_DIFF1 , A); // v16 -> v36 upgrade
10551058 try {
1056- dash::verify_version_transition (*sc.pool .back (), sc.chain , CL );
1059+ dash::verify_share (*sc.pool .back (), sc.chain , CL , kVgParams , /* verify_init= */ false );
10571060 FAIL () << " expected throw on upgrade without enough history" ;
10581061 } catch (const std::invalid_argument& e) {
10591062 EXPECT_NE (std::string (e.what ()).find (" enough history" ), std::string::npos);
@@ -1068,7 +1071,7 @@ TEST(DashConformanceVersionWiring, UpgradeWithSuccessorMajorityAdmitted) {
10681071 uint256 tip = build_uniform (sc, 22 , 36 , BITS_DIFF1 , A); // tail window = v36
10691072 uint256 prev = add_versioned (sc, 0x82 , tip, 16 , BITS_DIFF1 , A); // a lone v16 prev
10701073 add_versioned (sc, 0x83 , prev, 36 , BITS_DIFF1 , A); // v16 -> v36 upgrade
1071- EXPECT_NO_THROW (dash::verify_version_transition (*sc.pool .back (), sc.chain , CL ));
1074+ EXPECT_NO_THROW (dash::verify_share (*sc.pool .back (), sc.chain , CL , kVgParams , /* verify_init= */ false ));
10721075}
10731076
10741077// Upgrade boundary, history present, but the tail window has NO successor votes
@@ -1079,7 +1082,7 @@ TEST(DashConformanceVersionWiring, UpgradeWithoutSuccessorVotesRejected) {
10791082 uint256 tip = build_uniform (sc, 22 , 16 , BITS_DIFF1 , A); // tail window = all v16
10801083 add_versioned (sc, 0x84 , tip, 36 , BITS_DIFF1 , A); // v16 -> v36 upgrade
10811084 try {
1082- dash::verify_version_transition (*sc.pool .back (), sc.chain , CL );
1085+ dash::verify_share (*sc.pool .back (), sc.chain , CL , kVgParams , /* verify_init= */ false );
10831086 FAIL () << " expected throw on upgrade without successor votes" ;
10841087 } catch (const std::invalid_argument& e) {
10851088 EXPECT_NE (std::string (e.what ()).find (" hash power upgraded" ),
@@ -1096,7 +1099,7 @@ TEST(DashConformanceVersionWiring, StalePreV36ShareRejected) {
10961099 uint256 tip = build_uniform (sc, 22 , 36 , BITS_DIFF1 , A); // lookbehind = all v36
10971100 add_versioned (sc, 0x85 , tip, 16 , BITS_DIFF1 , A); // stale v16 on v36 tip
10981101 try {
1099- dash::verify_version_transition (*sc.pool .back (), sc.chain , CL );
1102+ dash::verify_share (*sc.pool .back (), sc.chain , CL , kVgParams , /* verify_init= */ false );
11001103 FAIL () << " expected throw on stale pre-v36 share" ;
11011104 } catch (const std::invalid_argument& e) {
11021105 EXPECT_NE (std::string (e.what ()).find (" too old" ), std::string::npos);
@@ -1108,7 +1111,25 @@ TEST(DashConformanceVersionWiring, GenesisShareAdmitted) {
11081111 SyntheticChain sc;
11091112 const uint160 A = miner_h160 (0x15 );
11101113 add_versioned (sc, 0x86 , uint256 (), 36 , BITS_DIFF1 , A); // null prev_hash
1111- EXPECT_NO_THROW (dash::verify_version_transition (*sc.pool .back (), sc.chain , CL ));
1114+ EXPECT_NO_THROW (dash::verify_share (*sc.pool .back (), sc.chain , CL , kVgParams , /* verify_init=*/ false ));
1115+ }
1116+
1117+ // Phase-1 composition: with verify_init=true the combined entry runs
1118+ // share_init_verify FIRST, so a structurally invalid share (empty coinbase) is
1119+ // rejected by verify_share BEFORE the version gate is ever consulted. Proves
1120+ // Phase 1 is wired into the accept entry, not bypassed.
1121+ TEST (DashConformanceVersionWiring, InitPhaseComposedAndRejectsBeforeGate) {
1122+ SyntheticChain sc;
1123+ const uint160 A = miner_h160 (0x16 );
1124+ add_versioned (sc, 0x87 , uint256 (), 36 , BITS_DIFF1 , A); // genesis: gate is a no-op
1125+ // Synthetic shares carry an empty coinbase -> share_init_verify rejects on
1126+ // the size guard. verify_init=true must surface that, proving init runs.
1127+ try {
1128+ dash::verify_share (*sc.pool .back (), sc.chain , CL , kVgParams , /* verify_init=*/ true );
1129+ FAIL () << " expected Phase-1 init to reject the empty-coinbase share" ;
1130+ } catch (const std::invalid_argument& e) {
1131+ EXPECT_NE (std::string (e.what ()).find (" coinbase" ), std::string::npos);
1132+ }
11121133}
11131134
11141135// ── DIP4 special-tx coinbase payload (CCbTx) wire-encoding conformance ──────
0 commit comments