@@ -256,7 +256,7 @@ void NodeImpl::send_version(peer_ptr peer)
256256 m_nonce,
257257 m_software_version,
258258 1 , // mode (always 1 for legacy compat)
259- best_share_hash () // advertise our tallest chain head
259+ advertised_best_share () // verified head, or raw head pre-sync (ROOT-2)
260260 );
261261 peer->write (std::move (rmsg));
262262}
@@ -901,6 +901,49 @@ uint256 NodeImpl::best_share_hash()
901901 return best;
902902}
903903
904+ // Head advertised to peers in the version handshake and re-advertisement ONLY.
905+ // Unlike best_share_hash() -- which is verified-only and collapses to ZERO once
906+ // peers exist so work/template never builds on a MAX_TARGET head -- this returns
907+ // our tallest RAW chain head. Root-2: on a fresh (--genesis) node the verified
908+ // set is empty at handshake, so best_share_hash() advertised ZERO and the peer
909+ // never issued download_shares() for our shares. Advertising the raw head makes
910+ // a connecting peer always learn we have a chain and pull it, while work/template
911+ // stays on the verified head via best_share_hash().
912+ uint256 NodeImpl::advertised_best_share ()
913+ {
914+ // Prefer think()s current best (verified or not) -- our canonical head.
915+ if (!m_best_share_hash.IsNull ())
916+ return m_best_share_hash;
917+
918+ // Otherwise the tallest raw chain head (mirrors the genesis fallback above).
919+ if (m_chain && m_chain->size () > 0 ) {
920+ uint256 best;
921+ int32_t best_height = -1 ;
922+ for (const auto & [head_hash, tail_hash] : m_chain->get_heads ()) {
923+ auto h = m_chain->get_height (head_hash);
924+ if (h > best_height) {
925+ best = head_hash;
926+ best_height = h;
927+ }
928+ }
929+ if (!best.IsNull ())
930+ return best;
931+ }
932+
933+ // True genesis: no shares at all yet -- advertise ZERO exactly as before.
934+ return uint256::ZERO ;
935+ }
936+
937+ void NodeImpl::readvertise_best ()
938+ {
939+ if (m_peers.empty ())
940+ return ;
941+ uint256 adv = advertised_best_share ();
942+ if (adv.IsNull () || adv == uint256::ZERO )
943+ return ;
944+ broadcast_share (adv);
945+ }
946+
904947void NodeImpl::download_shares (peer_ptr /* unused_peer*/ , const uint256& target_hash)
905948{
906949 // p2pool node.py:108-141 download_shares() — exact translation.
@@ -1571,6 +1614,10 @@ void NodeImpl::run_think()
15711614 auto wr_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
15721615 std::chrono::steady_clock::now () - wr_t0).count ();
15731616 LOG_INFO << " [ASYNC-THINK] IO-phase: work refresh done in " << wr_ms << " ms" ;
1617+ // Root-2: re-advertise our new head. A peer that handshook
1618+ // before we had a chain saw a ZERO advert and never issued
1619+ // download_shares -- re-announce so it pulls our shares now.
1620+ readvertise_best ();
15741621 } else if (result.best .IsNull ()) {
15751622 LOG_WARNING << " [ASYNC-THINK] IO-phase: result.best is NULL — verified_tails="
15761623 << m_tracker.verified .get_tails ().size ()
@@ -2080,6 +2127,7 @@ void NodeImpl::clean_tracker()
20802127 if (clean_best_changed && m_on_best_share_changed) {
20812128 LOG_INFO << " [CLEAN] IO-phase: work refresh (best changed)" ;
20822129 m_on_best_share_changed ();
2130+ readvertise_best (); // root-2: re-announce new head to peers
20832131 }
20842132 drain_pending_adds ();
20852133 m_think_running.store (false );
0 commit comments