Skip to content

pool: hoist ban/whitelist subsystem into pool::SharechainNode (node.cpp reuse, slice 1)#758

Merged
frstrtr merged 1 commit into
masterfrom
feat/pool-sharechain-node-hoist
Jul 19, 2026
Merged

pool: hoist ban/whitelist subsystem into pool::SharechainNode (node.cpp reuse, slice 1)#758
frstrtr merged 1 commit into
masterfrom
feat/pool-sharechain-node-hoist

Conversation

@frstrtr

@frstrtr frstrtr commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Summary

node.cpp is copy-pasted across the five coins. This PR lands the first, safe slice of the reuse hoist: a new intermediate layer pool::SharechainNode<Config,ShareChain,Peer> between pool::BaseNode and each coin's NodeImpl, holding the byte-identical, coin-agnostic, non-consensus peer ban-list + whitelist subsystem. All four complete coins now inherit it instead of carrying their own copy.

Net: −688 lines across the four coins, +243-line shared header (one source of truth for four copies; −176 lines per coin).

What hoisted (verified byte-identical across ltc/btc/bch/dgb, coin namespace aside)

is_banned, is_whitelisted, set_ban_duration, set_whitelist_path, load_whitelist_from_disk, save_whitelist_to_disk, admin_list_bans, admin_ban_ip, admin_unban_ip, admin_list_whitelist, admin_whitelist_remove, the build_bans_json/build_whitelist_json helpers, and the members m_ban_list, m_ip_ban_list, m_ban_duration, m_whitelist_ips, m_whitelist_hosts, m_whitelist_path.

Every hoisted method touches only members that move with it — no dependent-base qualification, no consensus/sharechain-timing state. Bodies relocated unchanged: pure de-duplication, behaviour identical.

The connection-coupled endpoints (admin_whitelist_add, admin_list_peers, admin_drop_peer, admin_dial_peer) stay in NodeImpl for now — they reach into BaseNode's connection maps and the outbound-dial members, so they belong to the next slice that also hoists the outbound-connection manager.

Per-coin no-regression evidence (system Boost 1.83 / leveldb, -j4)

Check Result
c2pool-ltc / -btc / -bch / -dgb / -dash build all green
test_ltc_node PASS (exit 0)
core_test 56/56 PASS (incl. VersionGateTransition suite)
sharechain_test green (0 cases)
ltc_pool_test harness constructs node through the new base + enters run loop, no crash

ltc_coin_test aborts on CoindRPC connection refused — it requires a live litecoind daemon (environmental, not present in this sandbox); unrelated to this non-consensus change.

⚠️ Important finding — the audit premise does NOT hold for the consensus core

The directive assumed the five node.cpp copies are "~90% byte-identical" so a hoist is "same code relocated, behaviour UNCHANGED." A function-by-function identity check across the four complete coins (coin-name-normalized, brace-matched) shows that is true only for 26 of 43 functions. The other 17 — precisely the consensus-adjacent core — have drifted into 2–4 distinct implementations:

  • BTC + BCH are a tight pair (13 lines apart). LTC and DGB each diverge from them and from each other (242 / 313 / 499 / 510-line normalized diffs).
  • run_think, clean_tracker, processing_shares, processing_shares_phase2, handle_version, send_version, heartbeat_log (all four differ), download_shares, handle_get_share, load_persisted_shares, advertised_best_share, notify_local_share, prune_shares — all drifted.
  • readvertise_best (BTC/BCH: broadcast_share) vs readvertise_best_share (LTC/DGB: full tip-walk re-push) — different name and different body.
  • arm_think_watchdog / disarm_think_watchdog differ between LTC and BTC/BCH and are entirely missing in DGB; DGB additionally carries a unique apply_min_protocol_ratchet.
  • The async-defer lock discipline (kr1z1s SIGSEGV region) differs: LTC releases the tracker lock early; BTC/BCH hold it across the mutation and add a MAX_PENDING_ADDS backpressure cap.
  • The "config-constant accessor" drift is not cosmetic: LTC reads minimum_protocol_version = 3301 from coin_params, BTC reads MINIMUM_PROTOCOL_VERSION = 3500 from a PoolConfig constant — different values from different sources, entangled with the per-coin protocol-version map.

Consequence: a single shared implementation of any of those 17 functions cannot be produced by mechanical relocation — it forces one coin's behaviour onto the others in exactly the node/sharechain-timing + protocol-version areas with prior prod-incident history. Those are therefore NOT hoisted here; they require a reconciliation-first path (pick the canonical impl per function, back-port to all coins, soak-validate per coin) before any shared layer can absorb them.

DASH coordination

DASH is still the 668-line skeleton with no ban/whitelist block, so it is untouched and keeps deriving from pool::BaseNode directly. Once the DASH node quick-wire lands and gives it the same block, DASH switches its base to pool::SharechainNode and inherits this layer for free — same as the other four.

Follow-up (separate PRs, not this one)

  1. Slice 2 — hoist the outbound-connection manager + the connection-coupled admin endpoints + connected/error/close_connection (also byte-identical all-4) with the small this->/Base:: qualification they need.
  2. Reconciliation track (prerequisite for any consensus hoist) — converge the 17 drifted functions to one canonical implementation per function, back-port + soak per coin, THEN hoist. This is the risky, per-coin-validated work; it is intentionally deferred, not half-done here.

…ode.cpp drift, slice 1)

node.cpp is copy-pasted across ltc/btc/bch/dgb. This introduces the
intermediate layer pool::SharechainNode<Config,ShareChain,Peer> between
pool::BaseNode and each coin's NodeImpl, and hoists the FIRST byte-identical,
coin-agnostic, non-consensus block into it: the peer ban-list + whitelist
subsystem.

Hoisted (verified byte-identical across all four coins, coin namespace aside):
  is_banned, is_whitelisted, set_ban_duration, set_whitelist_path,
  load_whitelist_from_disk, save_whitelist_to_disk,
  admin_list_bans, admin_ban_ip, admin_unban_ip, admin_list_whitelist,
  admin_whitelist_remove, and the build_bans_json/build_whitelist_json helpers,
  plus the members m_ban_list, m_ip_ban_list, m_ban_duration,
  m_whitelist_ips, m_whitelist_hosts, m_whitelist_path.

This slice is deliberately limited to the self-contained ban/whitelist surface:
every hoisted method touches ONLY members that move with it, so no dependent-base
qualification is needed and no consensus/sharechain-timing state is involved. The
bodies are relocated unchanged — pure de-duplication, behaviour identical.

The connection-coupled admin endpoints (admin_whitelist_add, admin_list_peers,
admin_drop_peer, admin_dial_peer) stay in NodeImpl for now: they reach into
BaseNode's connection maps and the outbound-dial members, so they belong to a
later slice that also hoists the outbound-connection manager.

DASH (still the 668-line skeleton, no ban/whitelist block yet) is untouched and
continues to derive from pool::BaseNode directly; it inherits this layer for free
once its node quick-wire lands and gives it the same block.

Net: -688 lines across the four coins, +243-line shared header (one source of
truth for four copies).

Regression evidence (this environment, system Boost/leveldb):
  - c2pool-{ltc,btc,bch,dgb,dash} all build green.
  - test_ltc_node: PASS.
  - core_test: 56/56 PASS (incl. version-gate transition suite).
  - ltc_pool_test harness constructs the node through the new base and enters the
    run loop with no crash.
void load_whitelist_from_disk()
{
if (m_whitelist_path.empty()) return;
std::ifstream f(m_whitelist_path);
@frstrtr
frstrtr merged commit 47ea351 into master Jul 19, 2026
35 of 37 checks passed
@frstrtr
frstrtr deleted the feat/pool-sharechain-node-hoist branch July 19, 2026 15:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants