|
| 1 | +#!/usr/bin/env bash |
| 2 | +# dgb_g2_ratchet_staged_migration_harness.sh |
| 3 | +# ----------------------------------------------------------------------------- |
| 4 | +# Greenlight gate G2 -- DGB RATCHET STAGED-MIGRATION test harness. |
| 5 | +# |
| 6 | +# Gate sequence (per integrator 2026-06-24, UID2208): G1 (oracle byte-parity |
| 7 | +# KAT) -> G2 (this: ratchet staged-migration) -> G3a/G3b (testnet block prod). |
| 8 | +# |
| 9 | +# WHAT G2 PROVES |
| 10 | +# -------------- |
| 11 | +# DGB conforms to its OWN oracle frstrtr/p2pool-dgb-scrypt (terminal share |
| 12 | +# VERSION=35, SUCCESSOR=None); c2pool-dgb drives the 35 -> 36 ratchet while |
| 13 | +# staying backward-compatible with the ver35 oracle during the migration |
| 14 | +# window. This is NOT the LTC v35 transition -- do not borrow LTC's script. |
| 15 | +# |
| 16 | +# DUAL-POOL TESTBED (self-provisioned on the VM115 isolated scrypt net, |
| 17 | +# 192.168.86.42 -- NOT vm-fleet, which is disabled). Both pools share the DGB |
| 18 | +# sharechain IDENTIFIER 4B62545B1A631AFE so they peer as ONE sharechain; the |
| 19 | +# axis under test is the share VERSION (35 vs 36), not the namespace. |
| 20 | +# |
| 21 | +# POOL O (oracle-base) : frstrtr/p2pool-dgb-scrypt (python reference), |
| 22 | +# mints share ver35 / SUCCESSOR=None, |
| 23 | +# donation 4104ffd0..., P2P 5024. |
| 24 | +# POOL V (v36 c2pool) : c2pool-dgb, AutoRatchet VOTING->ACTIVATED->CONFIRMED. |
| 25 | +# |
| 26 | +# Bucket-1 isolation (operator 2026-06-17 3-bucket rule): PREFIX / IDENTIFIER |
| 27 | +# are kept per-coin/per-instance -- this testbed is isolated from prod & other |
| 28 | +# coins by them. diff-1 both pools. Self-service RPC creds (no secret on any |
| 29 | +# coordination card). |
| 30 | +# |
| 31 | +# THE 5 CHECKS (see scripts/dgb_g2_evidence_template.md for the evidence form): |
| 32 | +# C1 BASELINE COHABIT : v36 c2pool-dgb peers the ver35 oracle on one |
| 33 | +# sharechain; accepts ver35 shares (backward compat). |
| 34 | +# C2 VOTING MINT : c2pool-dgb in VOTING mints base_version=35 (oracle- |
| 35 | +# faithful), advertises desired_version=36 (the vote); |
| 36 | +# NO premature v36-format mint. |
| 37 | +# C3 STAGED ACCEPT GATE : (#288) the 95%-by-FLAT-COUNT desired trigger is |
| 38 | +# GATED behind the 60%-BY-WORK accept |
| 39 | +# (get_desired_version_weights idx->work). Mint cannot |
| 40 | +# outrun accept -- flat 95% does NOT activate until |
| 41 | +# work>=60%. This is the "staged" property. |
| 42 | +# C4 RATCHET + PERSIST : on 60%-by-work + 95% sustained 2*CHAIN_LENGTH, |
| 43 | +# VOTING->ACTIVATED->CONFIRMED; v36-format mint begins; |
| 44 | +# ver35 oracle still accepts in-window; CONFIRMED |
| 45 | +# survives c2pool-dgb restart (JSON state). |
| 46 | +# C5 ALGO POSTURE : Scrypt is the ONLY validated/work-weighted algo; |
| 47 | +# SHA-256d / Skein / Qubit / Odocrypt legs are |
| 48 | +# N/A-by-continuity (V36 scope) -- recorded as N/A, |
| 49 | +# NOT as skipped checks. |
| 50 | +# |
| 51 | +# RIG DEPENDENCY (GATED): C2/C3/C4 work-weighted evidence needs real hashrate to |
| 52 | +# move desired_version_weights. The only valid scrypt set is the 3x R1-LTC rigs, |
| 53 | +# currently tied up in the LIVE LTC crossing-soak (owner ltc-doge-production- |
| 54 | +# steward). Per integrator: author first, then request the rig window -- do NOT |
| 55 | +# pull rigs off a live soak. Until rigs are brokered, this harness: |
| 56 | +# * provisions + validates the dual-pool substrate end-to-end (C1 reachable), |
| 57 | +# * drives C2/C3/C4 in SIMULATED-VOTE mode (--sim-votes) using the AutoRatchet |
| 58 | +# KAT seam so the staged-gate LOGIC is proven now, |
| 59 | +# * and emits the evidence template with the rig-bound rows marked |
| 60 | +# [GATED: rigs] until the live run. |
| 61 | +# |
| 62 | +# PER-COIN ISOLATION: DGB only. Touches no other coin tree. Localhost/VM115 net. |
| 63 | +set -euo pipefail |
| 64 | + |
| 65 | +# ---- binaries (self-provision; no operator install) ------------------------- |
| 66 | +DGB_DAEMON="${DGB_DAEMON:-digibyted}" # DigiByte Core (NOT vendored) |
| 67 | +DGB_CLI="${DGB_CLI:-digibyte-cli}" |
| 68 | +C2POOL_DGB="${C2POOL_DGB:-c2pool-dgb}" # v36 pool binary |
| 69 | +ORACLE_PY="${ORACLE_PY:-$HOME/Github/p2pool-dgb-scrypt/run_p2pool.py}" # ver35 oracle |
| 70 | + |
| 71 | +# ---- isolated net params (VM115 / 192.168.86.42) ---------------------------- |
| 72 | +NET="${DGB_NET:-testnet}" # isolated scrypt testnet, diff-1 |
| 73 | +BIND_ADDR="${DGB_BIND:-0.0.0.0}" |
| 74 | +SHARECHAIN_ID="4b62545b1a631afe" # bucket-1 IDENTIFIER (peer both) |
| 75 | +DONATION="${DGB_DONATION:-4104ffd0}" # oracle donation tag (prefix) |
| 76 | + |
| 77 | +# pool O (oracle ver35) |
| 78 | +O_P2P=${O_P2P:-5024} # oracle sharechain P2P |
| 79 | +O_STRATUM=${O_STRATUM:-9327} |
| 80 | +# pool V (v36 c2pool-dgb) |
| 81 | +V_P2P=${V_P2P:-5025} |
| 82 | +V_STRATUM=${V_STRATUM:-9328} |
| 83 | + |
| 84 | +# parent daemon (shared) |
| 85 | +RPCPORT=${DGB_RPCPORT:-14022} |
| 86 | +P2PPORT=${DGB_P2PPORT:-14023} |
| 87 | +DATADIR="${DGB_DATADIR:-$HOME/.digibyte-g2}" |
| 88 | +RATCHET_STATE="${DGB_RATCHET_STATE:-$HOME/.c2pool-dgb-g2/ratchet.json}" |
| 89 | + |
| 90 | +SIM_VOTES=0 |
| 91 | +for a in "$@"; do case "$a" in --sim-votes) SIM_VOTES=1;; esac; done |
| 92 | + |
| 93 | +log() { echo "[dgb-g2 $(printf "%(%H:%M:%S)T")] $*" >&2; } |
| 94 | +die() { echo "[dgb-g2 FAIL] $*" >&2; exit 1; } |
| 95 | +need() { command -v "$1" >/dev/null 2>&1 || die "missing binary: $1 (self-provision; sudo is operator-only)"; } |
| 96 | +gated(){ echo "[dgb-g2 GATED: rigs] $*" >&2; } |
| 97 | + |
| 98 | +cli() { "$DGB_CLI" -"$NET" -datadir="$DATADIR" -rpcport=$RPCPORT "$@"; } |
| 99 | + |
| 100 | +# ---- self-service RPC creds (never written to a coordination card) ---------- |
| 101 | +gen_creds() { |
| 102 | + mkdir -p "$DATADIR" |
| 103 | + if [ ! -f "$DATADIR/.rpccreds" ]; then |
| 104 | + local u p |
| 105 | + u="dgbg2_$(printf "%(%s)T" -1 | tail -c 6)" |
| 106 | + p="$(head -c18 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | head -c 24)" |
| 107 | + printf 'rpcuser=%s\nrpcpassword=%s\n' "$u" "$p" > "$DATADIR/.rpccreds" |
| 108 | + chmod 600 "$DATADIR/.rpccreds" |
| 109 | + log "generated isolated RPC creds at $DATADIR/.rpccreds (600)" |
| 110 | + fi |
| 111 | +} |
| 112 | + |
| 113 | +# ---- substrate: parent daemon on isolated diff-1 net ------------------------ |
| 114 | +start_daemon() { |
| 115 | + need "$DGB_DAEMON"; need "$DGB_CLI" |
| 116 | + gen_creds |
| 117 | + cat "$DATADIR/.rpccreds" > "$DATADIR/digibyte.conf" |
| 118 | + cat >> "$DATADIR/digibyte.conf" <<CONF |
| 119 | +$NET=1 |
| 120 | +server=1 |
| 121 | +listen=1 |
| 122 | +[${NET}] |
| 123 | +rpcbind=127.0.0.1 |
| 124 | +rpcport=$RPCPORT |
| 125 | +port=$P2PPORT |
| 126 | +CONF |
| 127 | + "$DGB_DAEMON" -datadir="$DATADIR" -daemon |
| 128 | + for i in $(seq 1 30); do cli getblockchaininfo >/dev/null 2>&1 && break; sleep 1; done |
| 129 | + cli getblockchaininfo >/dev/null 2>&1 || die "digibyted did not come up on $NET" |
| 130 | + log "parent digibyted up: $(cli getblockchaininfo | grep -E 'chain|blocks' | tr -d ' ,\"')" |
| 131 | +} |
| 132 | + |
| 133 | +# ---- pools ------------------------------------------------------------------- |
| 134 | +start_pool_oracle() { |
| 135 | + [ -f "$ORACLE_PY" ] || { gated "oracle pool $ORACLE_PY not staged -- C1 cohabit deferred"; return 0; } |
| 136 | + log "starting POOL O (oracle ver35) p2p=$O_P2P stratum=$O_STRATUM id=$SHARECHAIN_ID" |
| 137 | + # oracle is the conformance reference: mints ver35 / SUCCESSOR=None. |
| 138 | + nohup python3 "$ORACLE_PY" --net dgb-scrypt-testnet \ |
| 139 | + --p2pool-port $O_P2P --worker-port $O_STRATUM \ |
| 140 | + --bitcoind-rpc-port $RPCPORT --give-author 0 \ |
| 141 | + >"$HOME/.c2pool-dgb-g2/oracle.log" 2>&1 & |
| 142 | + echo $! > "$HOME/.c2pool-dgb-g2/oracle.pid" |
| 143 | +} |
| 144 | + |
| 145 | +start_pool_v36() { |
| 146 | + need "$C2POOL_DGB" |
| 147 | + mkdir -p "$(dirname "$RATCHET_STATE")" |
| 148 | + log "starting POOL V (v36 c2pool-dgb) p2p=$V_P2P stratum=$V_STRATUM ratchet-state=$RATCHET_STATE" |
| 149 | + # v36 c2pool-dgb peers POOL O on the shared sharechain identifier; AutoRatchet |
| 150 | + # base_version=35 (oracle-faithful VOTING mint), target=36. |
| 151 | + nohup "$C2POOL_DGB" --run --"$NET" \ |
| 152 | + --coin-rpc 127.0.0.1:$RPCPORT --coin-rpc-auth "$DATADIR/digibyte.conf" \ |
| 153 | + --sharechain-port $V_P2P --stratum "$BIND_ADDR:$V_STRATUM" \ |
| 154 | + --addnode 127.0.0.1:$O_P2P \ |
| 155 | + --ratchet-state "$RATCHET_STATE" \ |
| 156 | + >"$HOME/.c2pool-dgb-g2/v36.log" 2>&1 & |
| 157 | + echo $! > "$HOME/.c2pool-dgb-g2/v36.pid" |
| 158 | +} |
| 159 | + |
| 160 | +# ---- the 5 checks ------------------------------------------------------------ |
| 161 | +# SIM mode (--sim-votes) proves the staged-gate LOGIC now via existing AutoRatchet |
| 162 | +# KATs (rig-independent). LIVE rows (real work-weighted hashrate) stay GATED until |
| 163 | +# the R1-LTC scrypt window is brokered off the LTC soak. Exact ctest names below. |
| 164 | +check_c1_cohabit() { |
| 165 | + log "C1 BASELINE COHABIT: v36 peers ver35 oracle on id=$SHARECHAIN_ID, accepts ver35 shares" |
| 166 | + # v36 c2pool-dgb establishes a sharechain peer to POOL O and ingests a ver35 |
| 167 | + # share without rejecting it (backward-compat in-window). No sharechain split. |
| 168 | + # Live-peer assertion runs against the v36 stats endpoint once both pools are up |
| 169 | + # on the rig-fed net; substrate provisioning (provision subcmd) is reachable now. |
| 170 | + gated "C1 live-peer assertion needs both pools up on the rig-fed net" |
| 171 | +} |
| 172 | + |
| 173 | +check_c2_voting_mint() { |
| 174 | + log "C2 VOTING MINT: base_version=35 minted, desired_version=36 advertised, no premature v36-format" |
| 175 | + if [ "$SIM_VOTES" -eq 1 ]; then |
| 176 | + log " [sim] VOTING mints ver35 / votes 36 -- DGB_share_test.AutoRatchet* KATs" |
| 177 | + ctest --test-dir build_dgb -R 'AutoRatchetBootstrapMintsBaselineWhileVoting|AutoRatchetWireBootstrapMints35Votes36|AutoRatchetBaseVersionParameterized' \ |
| 178 | + --output-on-failure || die "C2 sim (VOTING base35/votes36 KAT) failed" |
| 179 | + else |
| 180 | + gated "C2 live work-weighted vote needs rigs" |
| 181 | + fi |
| 182 | +} |
| 183 | + |
| 184 | +check_c3_staged_accept_gate() { |
| 185 | + log "C3 STAGED ACCEPT GATE (#288): flat-95% desired is GATED behind 60%-by-WORK accept" |
| 186 | + if [ "$SIM_VOTES" -eq 1 ]; then |
| 187 | + log " [sim] tail-guard: flat 95% must NOT activate below 60%-by-work -- AutoRatchetTailGuard.* KATs" |
| 188 | + ctest --test-dir build_dgb -R 'AutoRatchetTailGuard' \ |
| 189 | + --output-on-failure || die "C3 sim (#288 tail-guard) failed -- mint outran accept" |
| 190 | + else |
| 191 | + gated "C3 live mint-cannot-outrun-accept needs rigs to move work weights" |
| 192 | + fi |
| 193 | +} |
| 194 | + |
| 195 | +check_c4_ratchet_persist() { |
| 196 | + log "C4 RATCHET + PERSIST: VOTING->ACTIVATED->CONFIRMED on 60%-work+95%/2*CL; CONFIRMED survives restart" |
| 197 | + if [ "$SIM_VOTES" -eq 1 ]; then |
| 198 | + log " [sim] state-machine + restart persistence -- DGB_share_test.AutoRatchet* KATs" |
| 199 | + ctest --test-dir build_dgb -R 'AutoRatchetStatePersistsAcrossRestart|AutoRatchetThresholdsMatchCanonical|AutoRatchetWireBaselineConstantsFromOracle' \ |
| 200 | + --output-on-failure || die "C4 sim (state-machine/restart KAT) failed" |
| 201 | + else |
| 202 | + gated "C4 live CONFIRMED requires sustained 2*CHAIN_LENGTH of rig-fed 95%/60% shares" |
| 203 | + fi |
| 204 | +} |
| 205 | + |
| 206 | +check_c5_algo_posture() { |
| 207 | + log "C5 ALGO POSTURE: Scrypt-only work-weighting; SHA256d/Skein/Qubit/Odocrypt = N/A-by-continuity" |
| 208 | + # NOT a skipped check: V36 scope validates Scrypt only; the other 4 algos are |
| 209 | + # asserted N/A-by-continuity (DgbAlgoSelect.AllKnownNonScryptAlgosAreContinuity). |
| 210 | + ctest --test-dir build_dgb -R 'DgbAlgoSelect|DgbScryptPowKAT' \ |
| 211 | + --output-on-failure || die "C5 (scrypt-only work-weighting) failed" |
| 212 | + log " Scrypt validated + work-weighted; other 4 algos N/A-by-continuity (V36 design, V37 defers)" |
| 213 | +} |
| 214 | + |
| 215 | +# ---- driver ------------------------------------------------------------------ |
| 216 | +main() { |
| 217 | + mkdir -p "$HOME/.c2pool-dgb-g2" |
| 218 | + case "${1:-run}" in |
| 219 | + provision) start_daemon; start_pool_oracle; start_pool_v36 ;; |
| 220 | + checks) |
| 221 | + check_c1_cohabit |
| 222 | + check_c2_voting_mint |
| 223 | + check_c3_staged_accept_gate |
| 224 | + check_c4_ratchet_persist |
| 225 | + check_c5_algo_posture |
| 226 | + log "G2 check pass complete (sim=$SIM_VOTES). Fill scripts/dgb_g2_evidence_template.md." |
| 227 | + ;; |
| 228 | + run|*) |
| 229 | + log "G2 harness: provision dual-pool substrate, then run 5 checks." |
| 230 | + log " rig-bound rows GATED until ltc-doge frees the R1-LTC scrypt window." |
| 231 | + start_daemon || true |
| 232 | + start_pool_oracle || true |
| 233 | + start_pool_v36 || true |
| 234 | + check_c1_cohabit |
| 235 | + check_c2_voting_mint |
| 236 | + check_c3_staged_accept_gate |
| 237 | + check_c4_ratchet_persist |
| 238 | + check_c5_algo_posture |
| 239 | + ;; |
| 240 | + esac |
| 241 | +} |
| 242 | +main "$@" |
0 commit comments