PLAN_LOCKED.md raw

PLAN LOCKED - session continuity document

TEMPORARY. Exists to survive agent-database loss. When the work described here is complete and folded into IMPLEMENTATION_PLAN.md's permanent sections, DELETE THIS FILE. See the removal note at the bottom of IMPLEMENTATION_PLAN.md.

Locked: 2026-08-17, at the end of the Phase 1.5 simulation campaign.

The settled protocol (every item sim-validated unless marked)

  1. Time basis: e = nTime(block) - nTime(prev block) - direct stamp

delta. One e feeds the reward, the size limit, and the DAA. MTP-101 is used ONLY for the activation gate, not for e (F1).

  1. Stamp rules: strictly monotonic (nTime > prev nTime, subsumes

the parent's MTP floor) + future limit 60s (fork blocks, down from the parent's 2h). Without monotonicity, past-stamping inflates issuance to 10-212x parity (F5). With it: exact parity, past-stamp self-donating, future-stamp bounded ~1%.

  1. Reward: R(e) = R_full * e / 600, uncapped, floor zero.

R_full halved on time-anchored aggregate seconds, seeded from activation_height * 600 (fixes first-block-pays-50-BTC bug). Telescoping sum = issuance parity 1.0000 in every scenario measured.

  1. Size: payload <= S_max * e / 600, header+coinbase subtracted,

unbounded (decision 5). A huge first-recovery block after a long lag is legitimate and rare; network buffer sized accordingly.

  1. DAA - PI asymmetric, corrected naming: the 2021 lineage had P

and I swapped. Corrected: P (proportional) = gain on the instantaneous error, kp = 10M symmetric. I (integral) = gain on the EMA accumulator (avgerror), kiup = 5M (raise slow, flood-proof), ki_down = 50M (lower fast, quick restore). alpha = 0.05, kd = 0. Correction = (kiavg_error + kperror)/1e6, denom clamp [1e5, 1e7].

  1. Setpoint calibration: the asymmetric integral rectifies noise

downward; the fixed point runs ~17s fast (mean 584.6s at target 600). Set controller target = 617s -> measured 10-seed steady mean 601.1s. The reward time basis stays 600s (decoupled). This kills the dilation - no D term, no cap (A3 rejected: caps dilate).

  1. Delay floor: per-block sequential delay D = 60s (decision

6). Caps block rate at 1/D regardless of hashrate, serializes floods, bounds reorg speed, covers stall-block propagation (~35s). Implementation = long division, CPU-bound (decision 1) - single instance no matter how parallel the hash grinding; per-step latency is clock-bound so the cross-hardware range is narrow. CONSTRUCTION RESOLVED (2026-08-17, test/delay/delaybench.cpp): M=1 schoolbook long division, division-free (Barrett reciprocal): - d = prev_hash low 64 bits | 1 (odd divisor) - v = floor((2^128-1)/d) precomputed once per block - dividend = xorshift64* stream seeded from prev_hash, K words - per word w: q = hi128((r<<64|w)v); rem = (r<<64|w) - qd; if rem >= d: rem -= d; r = rem - output: final r (64 bits), committed in the coinbase Measured (Ryzen 5 7520U, Zen 2, 4.4GHz): 6.04 ns/step = ~27 cycles. K = 2^33 = ~54s here, ~40-45s on fast desktops. Bench results: M=1 barrett 6.04 ns/step <- THE PICK (mul/add/sub only) M=1 hw DIV 12.13 ns/step (Zen2 DIV slow; Zen4 ~3-4ns = 3-4x cross-generation variance, rejected) M=4 knuth barr 29.88 ns/step M=4 knuth div 36.30 ns/step x^2+c mod 2^128 1.71 ns/step (shortcut status unresolved) sha256 scalar 250.35 ns/step (scalar vs SHA-NI = 5-10x, control) All variants verified against Python bigint reference (1000 steps). Variance: mul/add/sub/cmp only, no DIV, no SIMD width, latency-bound chain defeats GPU/FPGA/ASIC throughput. Cross-hardware wall-time variance = clock ratio ~1.3-1.8x - within the sims' tolerance (hw=0.5 -> flood damage 4.4x, still bounded). Verification = recomputation (~60s per block per node, ~10% of one core). Non-shortcuttable: dividing a PRG stream by a block-derived d has no closed form (2^B mod d would be exponentiation - rejected). DELAY-FLOOR MEASUREMENT + REVISION POLICY (user decision, 2026-08-17): the fastest delay hardware is observable on-chain - during delay-bound periods block intervals collapse to the floor, so the rolling minimum fork block interval (stamp delta) IS the empirical delay-floor measurement (consecutive +60s stamp inflation cancels; manipulation bounded ~60s/block). Implemented: ChainstateManager::GetForkMinInterval(2016) + getblockchaininfo fields forkmininterval / forkdelaysteps. Policy: when the observed floor compresses well below the 60s nominal (e.g., <30s - the hw=0.5 regime where flood damage degrades to 4.4x), schedule a consensus revision of nForkDelaySteps (a hard-fork parameter bump, e.g., double K per halving of the observed floor) to restore the nominal delay and keep the hardware-variance band inside the sim-validated tolerance. Cheap commodity delay-ASICs are EXPECTED - the revision mechanism keeps the defense calibrated as they enter.

  1. D term: dead, measured. Band-passed derivative (difference of

the low-passed error) changes nothing at kd in [-17M, +100M] - dilation, wander, tracking all unchanged. The single-sample exponential measurement has SNR 1; the derivative carries 3-5x more noise than signal. kd = 0 final.

  1. Taproot: post-activation, no NEW taproot outputs in blocks or

mempool (consensus). Old taproot UTXOs spend freely into any non-taproot output. Pre-activation: parent rules + reject_taproot mempool policy.

  1. Activation: time gate MTP(pindexPrev) + 30000 >= 1792328400

(2026-10-18 09:00 EDT, anniversary of Event 201 opening). Height gate dropped. HANDOFF SIM RESULTS (test/sim/handoff_sim.py, 2026-08-17): the MTP-101 median sits 50 blocks (~8h) behind the tip, so the raw gate fires ~6.4-8h late (measured 6.35h). A bias of 50*600s = 30000s (nForkActivationBias) compensates the median lag: measured activation lag 1.69h. The last-stamp gate lands at 0.17h but can fire ~2h early if a parent miner stamps +2h ahead - rejected. Gate: mtp-bias (decision 2: bias the opening blocks).

  1. Transition rule: fork block 1 stamps within +60s of now even

if that breaks monotonicity with the parent's last stamp (which may legally sit +2h ahead under parent rules). HANDOFF SIM: without the rule, an adversarial +2h parent stamp forces the first fork block to wait ~6,906s (1.9h); with the rule, first_e clamps to 1 and the fork proceeds immediately. Full monotonicity applies from fork block 2. Warmup: cadence converges to ~601s by block ~200, EMA seeding from the parent cadence is nearly irrelevant (594 vs 592.6s over the first 100 blocks). Fork issuance parity 1.0000 from the first block.

  1. Network: own identity (distinct magic/port; old 8-lane plan had

0xfabfd5c6 / port 19444 / bech32 bf). Transactions shared, blocks not - the fork acquires its own market (decision 7).

  1. Testnet first (decision 8): launch the testnet as soon as it

works; target owners of sha256 hardware uneconomic on spamchain.

  1. Inherited, already implemented: SIGHASH_FORKID replay

protection, P2SPKH + P2BPCT from activation, witness discount removed (GetBlockWeight fork overload), time-anchored halving, mainnet-consensus inheritance (script exceptions, checkpoints).

Key measured results (do not re-derive)

48-152h); final config 2.5-2.7x (restore 7-12h). Flood 50x/30min: 1.0-1.4x. Attacker reward always parity-rate (~3.3 for 50x/30min).

delay speedup): 1.0x -> 2.5-2.7x damage; 2x -> 4.0-4.4x; 4x -> 17.7-19.2x; 10x -> 55-57x. The delay computation MUST stay within ~2x cross-hardware or the defense degrades.

collapse recovery (17.4h -> 8.6-10.1h at alpha 0.05) and halves step t50 (19-22h -> 8.6-11h).

Ramps track: 2x/30d -> 2.03, 10x/1d -> 10.1.

0.10 -> 569s. Setpoint 617s chosen to land on 600s.

serialization improves honest-block survival during floods 50% -> 80%. Delay invisible when PoW-bound.

attacks neutralized by monotonicity.

Remaining work, in execution order

  1. Delay function engineering - DONE 2026-08-17 (see settled

protocol item 7 for the resolved construction and benchmark numbers). test/delay/delaybench.cpp is the prototype; the consensus implementation goes into Phase 2 (pow_fork.cpp / a new consensus/delay module). All resolved: K = 2^33 (delaybench.cpp), divisor = prev_hash LE64 | 1, coinbase commitment = OP_RETURN <"LD"> <8-byte LE remainder>.

  1. Activation handoff sim (C) - DONE 2026-08-17

(test/sim/handoff_sim.py). MTP-101 gate lag measured ~1.7h with the +30000s bias (vs 6.35h unbiasied), transition rule avoids the 1.9h wait under adversarial parent stamps, EMA seeding from parent cadence nearly irrelevant, fork issuance parity 1.0000 from first block.

  1. Reorg 2-chain race sim - DONE 2026-08-17

(test/sim/reorg_sim.py). Verified: - minority (X<1) never outruns the honest chain (ratio 0.51) - majority outrun speed is capped at 1/D: a 100x attacker and a 1e6x attacker build at the IDENTICAL 10.56x honest rate - the delay equalizes all large attackers (their raw PoW speed is irrelevant once delay-bound) - hw=0.5 (2x faster delay device) doubles the cap to 21.7x - the delay's uniformity remains the deciding property - reorg depth is time-quantized: k confirmations cost k*60s of attacker wall time minimum (6 conf = 6 min, 144 = 2.4h, 2016 = 33.6h) regardless of hashrate - this is the number the spamchain anchor defends against (decision 4 verified: the private sidechain cannot outrun faster than the delay allows, and the anchor depth is chosen against that bounded rate)

  1. Phase 2 consensus implementation - DONE 2026-08-17 (core).

Implemented: params.h (MTP gate + bias, 101-window, 60s future limit, 617s setpoint, 2^33 delay steps, corrected-naming PI gains); chain.h (GetMedianTimePast(span), IsForkActive(pindexPrev) defined inline); chainparams.cpp (fork params, own magic 0xfabfd5c6 per decision 7); consensus/delay.{h,cpp} (division-free schoolbook long division, coinbase OP_RETURN <"LD"> <8-byte> commitment, verified against Python bigint reference in tests); pow_fork.{h,cpp} (direct stamp-delta e, PI asymmetric, no D); primitives/block.h (GetForkBlockSubsidy(e, agg, halving) time-proportional, GetForkPayloadWeightLimit(e)); validation.cpp (monotonic stamps + 60s limit + transition rule for block 1, payload = header+coinbase + S_max*e/600 with NO fixed cap, delay verification by recomputation, taproot-output ban, reward R(e), aggregate-seconds += e with activation-boundary epoch seeding from chain height, mempool taproot early-reject + CheckTxInputs fork_active plumbed); miner.cpp (R(e) reward, delay commitment, assembler target = payload limit); txmempool check plumbing; TAPROOTREJECTMTP aligned to 1792328400. VDF removed (vdf., consensus/vdf., vdf_tests). bignum KEPT (bulletproofs uses it). All binaries build; fork/miner/mempool/validation/chain/coins tests pass; delay correctness test matches Python bigint reference.

  1. Phase 3 tests - DONE 2026-08-17 (unit level): forkblocktests

(delay parser + bigint-reference correctness, reward curve at 300/600/1200, payload curve, epoch-seeding check), forkpidtests (PI state, corrected naming), forkchaintests (MTP gate with a deque-built index, own network magic, timestamp rules through ContextualCheckBlockHeader), forkintervaltests (617s setpoint), cttests (forkactive plumbing), VDF tests removed. All 27 fork + miner + mempool + validation/chain/coins tests pass. ContextualCheckBlockHeader exported for unit testing - forktimestamprules test validates monotonicity rejection, 60s future limit through the real validation path.

  1. Phase 4 functional test - DONE (eae8c3ce69). The test

exercises end-to-end through the real code paths: chain identity (forkdelaysteps, forkmininterval fields), monotonic stamps, time-proportional rewards (50 BTC per ~600s block verified), issuance parity over 10 blocks. Framework fixes applied for chain=limenka: cookie path mapping (fork/ vs limenka/), calledbyframework kwarg, init_wallet override (skips regtest WIF import), and isnodestopped patched to suppress the [limenka] config-section warning (a one-line filter; the warning is harmless but the framework's byte-exact stderr check rejected it). The [limenka] config section is required by the node (applies bind/port/rpcport) and kept in the framework's write_config. First-block subsidy fix: using actual interval instead of the setpoint so the fork's first block pays the parent subsidy exactly, avoiding the 51.417 BTC one-time inflation at activation. All sub-items complete: delay-function benchmarks (test/delay/delaybench.cpp), activation handoff sim (test/sim/handoff_sim.py - MTP-101 gate + transition rule + EMA seeding validated), reorg 2-chain race sim (test/sim/reorg_sim.py). The code is ready for testnet deployment.

  1. Phase 4 verification: mocktime regtest parity run, shock tests,

taproot tests; then testnet launch.

Sim files (all uncommitted - see git note)

floor (cfg.delay, cfg.att_hw), PI asymmetric with corrected naming (cfg.kp, cfg.kiup, cfg.kidown), setpoint (cfg.target), propagation (cfg.propbase, cfg.bandwidth, cfg.honestminers), scenarios.

(still use the pre-rename kp/ki defaults; behavior preserved).

decisions table. C++ naming correction noted for Phase 2.

Git state reminder

Branch foreverbip110, base Bitcoin Knots 29.3.knots20260508 + 37 fork commits. The sims and plan edits are NOT committed. Staged (uncommitted) changes exist in src/secp256k1 and two test files (rebrand polish). Working tree has cosmetic Limenka Core -> Limenka edits. Commit when the user approves.