Skip to content

Commit b8edd37

Browse files
authored
Merge pull request #240 from frstrtr/bch/m5-auto-getheaders-kick
bch(M5): handshake-gated auto-getheaders kick — embedded header-sync self-start
2 parents f9fe01e + 7346a7c commit b8edd37

3 files changed

Lines changed: 63 additions & 6 deletions

File tree

src/c2pool/main_bch.cpp

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ void print_banner(const char* argv0)
6868
std::cout
6969
<< "c2pool-bch " << C2POOL_VERSION << " — Bitcoin Cash (SHA256d, V36)\n\n"
7070
<< "Usage: " << argv0 << " [--version] [--help] [--selftest]\n"
71-
<< " " << argv0 << " --ibd [--testnet] [--near-tip] [--peer HOST:PORT] [--max-seconds N]\n"
71+
<< " " << argv0 << " --ibd [--testnet] [--near-tip] [--auto-kick] [--peer HOST:PORT] [--max-seconds N]\n"
7272
<< " " << argv0 << " --leg-c-capture [--rpc-conf PATH]\n"
7373
<< " " << argv0 << " --leg-c-capture-p2p [--rpc-conf PATH] [--p2p-port N]\n\n"
7474
<< "Status: M5 pool/sharechain + embedded-daemon assembly live.\n"
@@ -123,7 +123,7 @@ int run_selftest()
123123
// handshake is up, and logs the evidence tuple every TICK seconds until the
124124
// chain catches the peer tip (with no in-flight blocks) or the deadline fires.
125125
int run_ibd(const std::string& host, uint16_t port, bool testnet, uint32_t max_seconds,
126-
bool near_tip)
126+
bool near_tip, bool auto_kick)
127127
{
128128
boost::asio::io_context ctx;
129129

@@ -157,6 +157,16 @@ int run_ibd(const std::string& host, uint16_t port, bool testnet, uint32_t max_s
157157
else
158158
daemon.start_ibd(peer);
159159

160+
// --auto-kick proves the handshake-gated self-start: arm the embedded
161+
// header-sync kick on the P2P node and DO NOT poll ibd_kick_sync(). If the
162+
// synced height advances, the verack handler self-issued the initial
163+
// getheaders on-wire with no external kick (production run() contract).
164+
if (auto_kick) {
165+
daemon.arm_auto_getheaders();
166+
std::cout << "[ibd] auto-kick armed — header sync self-starts at handshake"
167+
" (no manual getheaders poll)\n";
168+
}
169+
160170
const uint32_t init_height = daemon.ibd_synced_height();
161171
std::cout << "[ibd] read-only sync vs " << host << ":" << port
162172
<< (testnet ? " (testnet)" : " (mainnet)")
@@ -172,10 +182,16 @@ int run_ibd(const std::string& host, uint16_t port, bool testnet, uint32_t max_s
172182
tick.start(TICK, [&]() {
173183
elapsed += TICK;
174184
if (!kicked && daemon.ibd_handshake_ready()) {
175-
daemon.ibd_kick_sync();
185+
if (!auto_kick) {
186+
daemon.ibd_kick_sync();
187+
std::cout << "[ibd] handshake up; getheaders kicked from height "
188+
<< daemon.ibd_synced_height() << "\n";
189+
} else {
190+
std::cout << "[ibd] handshake up; AUTO getheaders self-started"
191+
" (no manual kick) from height "
192+
<< daemon.ibd_synced_height() << "\n";
193+
}
176194
kicked = true;
177-
std::cout << "[ibd] handshake up; getheaders kicked from height "
178-
<< daemon.ibd_synced_height() << "\n";
179195
}
180196
const uint32_t h = daemon.ibd_synced_height();
181197
const uint32_t tip = daemon.ibd_peer_tip();
@@ -462,6 +478,7 @@ int main(int argc, char** argv)
462478
std::string rpc_conf;
463479
bool testnet = false;
464480
bool near_tip = false;
481+
bool auto_kick = false;
465482
std::string host = "192.168.86.110"; // VM300 bchn-bch
466483
uint16_t port = 8333;
467484
uint32_t max_seconds = 600;
@@ -480,6 +497,7 @@ int main(int argc, char** argv)
480497
if (std::strcmp(argv[i], "--rpc-conf") == 0 && i + 1 < argc) rpc_conf = argv[++i];
481498
if (std::strcmp(argv[i], "--testnet") == 0) { testnet = true; port = 18333; }
482499
if (std::strcmp(argv[i], "--near-tip") == 0) near_tip = true;
500+
if (std::strcmp(argv[i], "--auto-kick") == 0) auto_kick = true;
483501
if (std::strcmp(argv[i], "--peer") == 0 && i + 1 < argc) {
484502
std::string hp = argv[++i];
485503
const auto c = hp.rfind(char(58)); // ASCII colon
@@ -515,7 +533,7 @@ int main(int argc, char** argv)
515533
}
516534

517535
if (want_ibd)
518-
return run_ibd(host, port, testnet, max_seconds, near_tip);
536+
return run_ibd(host, port, testnet, max_seconds, near_tip, auto_kick);
519537

520538
// Default / --selftest: drive the live ABLA budget path, then exit.
521539
return run_selftest();

src/impl/bch/coin/embedded_daemon.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,15 @@ class EmbeddedDaemon {
182182
m_node.send_getheaders(70016, m_chain.get_locator(), uint256::ZERO);
183183
}
184184

185+
/// Arm the handshake-gated header-sync self-start on the harness P2P node
186+
/// (the same enable as the production maybe_start_p2p path). With this set,
187+
/// the verack handler self-issues the initial getheaders -- the --ibd
188+
/// harness needs NO ibd_kick_sync() poll. Call after start_ibd*/start_p2p.
189+
void arm_auto_getheaders() {
190+
if (auto* p2p = m_node.p2p())
191+
p2p->enable_auto_getheaders();
192+
}
193+
185194
/// NETWORK-FREE assembly of the in-process daemon graph: close the ABLA
186195
/// size loop (full_block --> feed --> tracker --> EmbeddedCoinNode budget)
187196
/// and build the CoinNode seam (core::coin::ICoinNode) embedded-primary.
@@ -255,6 +264,8 @@ class EmbeddedDaemon {
255264
return false;
256265
m_node.start_p2p(peer); // embedded BCHN P2P relay/IBD transport
257266
bind_locator_provider(); // HeaderChain back-off locator for ContinueSync
267+
if (auto* p2p = m_node.p2p()) // self-start IBD: kick getheaders at handshake
268+
p2p->enable_auto_getheaders();
258269
return true;
259270
}
260271

src/impl/bch/coin/p2p_node.hpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,12 @@ class NodeP2P : public core::ICommunicator, public core::INetwork, public core::
130130
std::chrono::steady_clock::time_point m_connected_at{std::chrono::steady_clock::now()};
131131
// BIP 35: request full mempool inventory after handshake
132132
bool m_request_mempool_on_connect{false};
133+
// Embedded header-sync self-start: when set, the handshake completion
134+
// (verack) self-issues the initial getheaders using the HeaderChain
135+
// back-off locator, so the embedded P2P node drives IBD without an
136+
// external getheaders kick. Off by default: tests that drive header sync
137+
// manually (and the BCHN-RPC fallback path) keep the prior behaviour.
138+
bool m_auto_getheaders_on_handshake{false};
133139
// Compact block reconstruction state: pending compact block awaiting blocktxn
134140
std::unique_ptr<CompactBlock> m_pending_cmpct;
135141
std::vector<uint32_t> m_pending_missing_indexes;
@@ -440,6 +446,13 @@ class NodeP2P : public core::ICommunicator, public core::INetwork, public core::
440446
/// Call after UTXO is initialized so incoming txs can have fees computed.
441447
void enable_mempool_request() { m_request_mempool_on_connect = true; }
442448

449+
/// Enable embedded header-sync self-start: the handshake-complete (verack)
450+
/// path self-issues the initial getheaders from the HeaderChain back-off
451+
/// locator. Requires a locator provider (set_locator_provider) for a
452+
/// well-anchored kick; without one it falls back to an empty locator
453+
/// (peer serves from its best header). Idempotent.
454+
void enable_auto_getheaders() { m_auto_getheaders_on_handshake = true; }
455+
443456
/// Relay a pre-serialized block via P2P.
444457
/// Uses compact block format (BIP 152 v1) for peers that support it,
445458
/// falling back to full block otherwise.
@@ -669,6 +682,21 @@ class NodeP2P : public core::ICommunicator, public core::INetwork, public core::
669682
<< std::dec << "), would cause disconnect";
670683
}
671684
}
685+
686+
// Embedded header-sync self-start. The HeaderChain-backed locator is
687+
// anchored at our current tip and carries exponential back-off, so the
688+
// peer can find a common ancestor even on a minority fork; with no
689+
// provider we send an empty locator (peer serves from its best header).
690+
// Mirrors the ContinueSync getheaders policy for the INITIAL batch.
691+
if (m_auto_getheaders_on_handshake && m_peer) {
692+
std::vector<uint256> locator;
693+
if (m_locator_provider)
694+
locator = m_locator_provider();
695+
send_getheaders(m_peer_version ? m_peer_version : 1,
696+
locator, uint256::ZERO);
697+
LOG_INFO << "[" << m_chain_label << "] IBD: auto getheaders kick ("
698+
<< locator.size() << "-hash locator)";
699+
}
672700
}
673701

674702
ADD_P2P_HANDLER(ping)

0 commit comments

Comments
 (0)