From 8c6961ca716541126b6ff74eb351680b66e87f90 Mon Sep 17 00:00:00 2001 From: Matt Hess Date: Wed, 17 Dec 2025 01:54:52 +0000 Subject: [PATCH] Fixed race condition with mainchain prefetch on startup, Version-gated checkpoint exchange for backward compatibility, Version bump to v4.13 with protocol 1.5, Added CAP exchange protocol (CHECKPOINT_REQUEST/CHECKPOINT_RESPONSE) --- src/p2p_server.cpp | 8 +++++--- src/p2p_server.h | 3 ++- src/p2pool.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ src/p2pool.h | 1 + src/util.h | 2 +- 5 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/p2p_server.cpp b/src/p2p_server.cpp index e817673..f4aab6d 100644 --- a/src/p2p_server.cpp +++ b/src/p2p_server.cpp @@ -2661,9 +2661,11 @@ void P2PServer::P2PClient::on_after_handshake(uint8_t* &p) } // Request checkpoints from peer (CAP exchange) - // TODO: Only send to peers with compatible protocol version to avoid disconnects - // LOGINFO(5, "sending CHECKPOINT_REQUEST to " << static_cast(m_addrString)); - // *(p++) = static_cast(MessageId::CHECKPOINT_REQUEST); + // Only send to peers with protocol 1.5+ to avoid disconnects with older nodes + if (m_protocolVersion >= PROTOCOL_VERSION_1_5) { + LOGINFO(5, "sending CHECKPOINT_REQUEST to " << static_cast(m_addrString)); + *(p++) = static_cast(MessageId::CHECKPOINT_REQUEST); + } } bool P2PServer::P2PClient::on_listen_port(const uint8_t* buf) diff --git a/src/p2p_server.h b/src/p2p_server.h index 84dc39e..e8e8c5b 100644 --- a/src/p2p_server.h +++ b/src/p2p_server.h @@ -43,8 +43,9 @@ static constexpr uint32_t PROTOCOL_VERSION_1_1 = 0x00010001UL; static constexpr uint32_t PROTOCOL_VERSION_1_2 = 0x00010002UL; static constexpr uint32_t PROTOCOL_VERSION_1_3 = 0x00010003UL; static constexpr uint32_t PROTOCOL_VERSION_1_4 = 0x00010004UL; +static constexpr uint32_t PROTOCOL_VERSION_1_5 = 0x00010005UL; -static constexpr uint32_t SUPPORTED_PROTOCOL_VERSION = PROTOCOL_VERSION_1_4; +static constexpr uint32_t SUPPORTED_PROTOCOL_VERSION = PROTOCOL_VERSION_1_5; class P2PServer : public TCPServer { diff --git a/src/p2pool.cpp b/src/p2pool.cpp index db38125..ac18305 100644 --- a/src/p2pool.cpp +++ b/src/p2pool.cpp @@ -1461,6 +1461,9 @@ void p2pool::download_block_headers4(uint64_t start_height, uint64_t current_hei } #endif + // Pre-fetch recent mainchain blocks to populate cache before sidechain sync + prefetch_mainchain_blocks(current_height); + api_update_network_stats(); get_miner_data(); @@ -1949,6 +1952,46 @@ uint32_t p2pool::parse_block_headers_range(const char* data, size_t size) return num_headers_parsed; } +void p2pool::prefetch_mainchain_blocks(uint64_t current_height) +{ + // Pre-fetch recent mainchain blocks to populate cache before sidechain sync + // This prevents the race condition where cached sidechain blocks need mainchain data + // that hasn't arrived via ZMQ yet + constexpr uint64_t PREFETCH_DEPTH = 300; + + if (current_height < PREFETCH_DEPTH) { + return; + } + + const uint64_t start_height = current_height - PREFETCH_DEPTH; + + LOGINFO(1, "Pre-fetching mainchain blocks " << start_height << " - " << current_height << " to populate cache"); + + char buf[log::Stream::BUF_SIZE + 1] = {}; + log::Stream s(buf); + + const Params::Host& host = current_host(); + + s.m_pos = 0; + s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_headers_range\",\"params\":{\"start_height\":" << start_height << ",\"end_height\":" << current_height << "}}" << '\0'; + + JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params->m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint, + [this, start_height, current_height](const char* data, size_t size, double) { + const uint32_t parsed = parse_block_headers_range(data, size); + if (parsed > 0) { + LOGINFO(1, "Pre-fetched " << parsed << " mainchain blocks into cache"); + } else { + LOGWARN(1, "Failed to pre-fetch mainchain blocks, will rely on ZMQ"); + } + }, + [this](const char* data, size_t size, double) { + if (size > 0) { + LOGWARN(1, "Failed to pre-fetch mainchain blocks: " << log::const_buf(data, size)); + } + } + ); +} + void p2pool::api_update_network_stats() { if (!m_api || m_stopped) { diff --git a/src/p2pool.h b/src/p2pool.h index e69a615..8e17104 100644 --- a/src/p2pool.h +++ b/src/p2pool.h @@ -119,6 +119,7 @@ public: void download_block_headers2(uint64_t current_height); void download_block_headers3(uint64_t start_height, uint64_t current_height); void download_block_headers4(uint64_t start_height, uint64_t current_height); + void prefetch_mainchain_blocks(uint64_t current_height); bool chainmain_get_by_hash(const hash& id, ChainMain& data) const; diff --git a/src/util.h b/src/util.h index 5720fbd..6ba8f43 100644 --- a/src/util.h +++ b/src/util.h @@ -35,7 +35,7 @@ namespace p2pool { #define P2POOL_VERSION_MAJOR 4 -#define P2POOL_VERSION_MINOR 12 +#define P2POOL_VERSION_MINOR 13 #define P2POOL_VERSION_PATCH 0 constexpr uint32_t P2POOL_VERSION = (P2POOL_VERSION_MAJOR << 16) | (P2POOL_VERSION_MINOR << 8) | P2POOL_VERSION_PATCH;