|
| 1 | +#!/usr/bin/env bash |
| 2 | +# G3a — DGB v36 greenlight gate: produce a POPULATED regtest block with a |
| 3 | +# diverse transaction mix and HARD-FAIL assertions that every output-script |
| 4 | +# type and the SegWit witness data survive a full serialize->node->deserialize |
| 5 | +# round-trip. Isolated digibyted regtest only (off-prod); self-provisions coins. |
| 6 | +# Additive/fenced: no consensus, shared-base, build.yml or CMake surface. |
| 7 | +set -euo pipefail |
| 8 | +D="${DGB_SRC:-$HOME/Github/digibyte/src}" |
| 9 | +CLI="$D/digibyte-cli" |
| 10 | +J() { python3 -c 'import sys,json;print(json.load(sys.stdin)["'"$1"'"])'; } |
| 11 | +fail() { echo "ASSERT-FAIL: $*" >&2; exit 1; } |
| 12 | + |
| 13 | +echo "=== G3a populated-block harness — chain=$($CLI getblockchaininfo | J chain) ===" |
| 14 | +[ "$($CLI getblockchaininfo | J chain)" = "regtest" ] || fail "refusing to run off regtest" |
| 15 | + |
| 16 | +# --- 1. self-provision mature coins ----------------------------------------- |
| 17 | +A_LEGACY=$($CLI getnewaddress "" legacy) |
| 18 | +$CLI generatetoaddress 130 "$A_LEGACY" >/dev/null |
| 19 | +echo "mined 130 -> spendable balance: $($CLI getbalance)" |
| 20 | + |
| 21 | +# --- 2. one address per output-script type ---------------------------------- |
| 22 | +A_P2PKH=$($CLI getnewaddress "" legacy) # pubkeyhash |
| 23 | +A_P2WPKH=$($CLI getnewaddress "" bech32) # witness_v0_keyhash (wallet-owned) |
| 24 | +A_P2SHWPKH=$($CLI getnewaddress "" p2sh-segwit) # scripthash, witness when spent (wallet-owned) |
| 25 | +K1=$($CLI getaddressinfo "$($CLI getnewaddress)" | J pubkey) |
| 26 | +K2=$($CLI getaddressinfo "$($CLI getnewaddress)" | J pubkey) |
| 27 | +A_MS_P2SH=$($CLI createmultisig 1 "[\"$K1\",\"$K2\"]" legacy | J address) # scripthash (1-of-2, donation shape) |
| 28 | +A_MS_P2WSH=$($CLI createmultisig 1 "[\"$K1\",\"$K2\"]" bech32 | J address) # witness_v0_scripthash |
| 29 | + |
| 30 | +# --- 3. pre-seed wallet-owned SEGWIT utxos (spent in the block => witnesses) - |
| 31 | +$CLI sendmany "" "{\"$A_P2WPKH\":25,\"$A_P2SHWPKH\":25}" >/dev/null |
| 32 | +$CLI generatetoaddress 1 "$A_LEGACY" >/dev/null |
| 33 | + |
| 34 | +pick_utxo() { # $1=address -> "txid vout" |
| 35 | + $CLI listunspent 1 9999999 "[\"$1\"]" | python3 -c 'import sys,json;u=json.load(sys.stdin)[0];print(u["txid"],u["vout"])' |
| 36 | +} |
| 37 | + |
| 38 | +# --- 4. assemble the POPULATED block's mempool ------------------------------ |
| 39 | +# T1: spend P2WPKH utxo -> native-segwit witness tx (txid != wtxid) |
| 40 | +read -r I1T I1V < <(pick_utxo "$A_P2WPKH") |
| 41 | +T1R=$($CLI createrawtransaction "[{\"txid\":\"$I1T\",\"vout\":$I1V}]" "{\"$A_P2PKH\":24.9}") |
| 42 | +T1=$($CLI sendrawtransaction "$($CLI signrawtransactionwithwallet "$T1R" | J hex)") |
| 43 | +# T5: spend P2SH-P2WPKH utxo -> wrapped-segwit witness tx (txid != wtxid) |
| 44 | +read -r I5T I5V < <(pick_utxo "$A_P2SHWPKH") |
| 45 | +T5R=$($CLI createrawtransaction "[{\"txid\":\"$I5T\",\"vout\":$I5V}]" "{\"$A_P2PKH\":24.9}") |
| 46 | +T5=$($CLI sendrawtransaction "$($CLI signrawtransactionwithwallet "$T5R" | J hex)") |
| 47 | +# T2: bare-funded raw tx -> P2SH 1-of-2 multisig output + OP_RETURN data carrier |
| 48 | +DATA=$(printf 'c2pool-dgb-g3a' | xxd -p) |
| 49 | +T2R=$($CLI createrawtransaction "[]" "{\"$A_MS_P2SH\":5,\"data\":\"$DATA\"}") |
| 50 | +T2F=$($CLI fundrawtransaction "$T2R" | J hex) |
| 51 | +T2=$($CLI sendrawtransaction "$($CLI signrawtransactionwithwallet "$T2F" | J hex)") |
| 52 | +# T3: native P2WSH output T4: native P2WPKH output |
| 53 | +T3=$($CLI sendtoaddress "$A_MS_P2WSH" 6) |
| 54 | +T4=$($CLI sendtoaddress "$A_P2WPKH" 7) |
| 55 | +echo "mempool: T1=$T1 T5=$T5 T2=$T2 T3=$T3 T4=$T4" |
| 56 | + |
| 57 | +# --- 5. mine ONE block capturing the whole mempool = the deliverable block --- |
| 58 | +BLK=$($CLI generatetoaddress 1 "$A_LEGACY" | python3 -c 'import sys,json;print(json.load(sys.stdin)[0])') |
| 59 | +echo "=== deliverable populated block: $BLK ===" |
| 60 | +$CLI getblock "$BLK" 2 > /tmp/g3a_block.json |
| 61 | + |
| 62 | +# --- 6. HARD-FAIL assertions ------------------------------------------------ |
| 63 | +python3 - "$T1" "$T5" <<'PY' |
| 64 | +import json,sys |
| 65 | +b=json.load(open("/tmp/g3a_block.json")); txs=b["tx"]; T1,T5=sys.argv[1],sys.argv[2] |
| 66 | +def fail(m): print("ASSERT-FAIL:",m,file=sys.stderr); sys.exit(1) |
| 67 | +n=len(txs); print(f" block tx count = {n}") |
| 68 | +if n<6: fail(f"under-populated ({n} txs, want >=6)") |
| 69 | +print(" [PASS] A1 populated (coinbase + >=5 payload tx)") |
| 70 | +cb=txs[0] |
| 71 | +if not any(o["scriptPubKey"]["hex"].startswith("6a24aa21a9ed") for o in cb["vout"]): |
| 72 | + fail("coinbase missing segwit witness commitment") |
| 73 | +print(" [PASS] A2 coinbase witness-commitment present") |
| 74 | +seg=sum(1 for t in txs[1:] if any("txinwitness" in v for v in t["vin"])) |
| 75 | +for nm,need in (("T1",T1),("T5",T5)): |
| 76 | + tt=[t for t in txs if t["txid"]==need] |
| 77 | + if not tt: fail(f"witness tx {nm}={need} absent") |
| 78 | + if tt[0]["txid"]==tt[0]["hash"]: fail(f"{nm} txid==wtxid (witness lost)") |
| 79 | +print(f" [PASS] A3 {seg} witness tx(s); txid!=wtxid holds for T1,T5") |
| 80 | +want={"pubkeyhash","scripthash","witness_v0_keyhash","witness_v0_scripthash","nulldata"} |
| 81 | +got=set(o["scriptPubKey"].get("type") for t in txs for o in t["vout"] if o["scriptPubKey"].get("type")) |
| 82 | +print(" output types survived round-trip:",sorted(got)) |
| 83 | +miss=want-got |
| 84 | +if miss: fail(f"types lost on round-trip: {miss}") |
| 85 | +print(" [PASS] A4 all 5 core script types survived node serialize->deserialize") |
| 86 | +print("\nG3A RESULT: PASS — block %s height=%d txs=%d witness=%d types=%s"%(b["hash"],b["height"],n,seg,sorted(got))) |
| 87 | +PY |
| 88 | +echo "=== G3a complete (height $($CLI getblockcount)) ===" |
0 commit comments