#!/usr/bin/env python3 """Build the signed Kompromis-120b emission artifact (planned schedule for the new chain). Recomputes the integer schedule from the consensus constants, cross-checks it against eddycoin_mainnet_design/k120b_tables.json, writes canonical JSON + .sha256, signs with the offline Ed25519 key (openssl; env EDDY_SIGNING_KEY_DIR; the private key is never published). Output: eddycoin_site/emission_artifact/{kompromis-120b.json,.json.sha256,.json.sig,emission-signing.pub}""" import json, hashlib, os, subprocess, sys HERE = os.path.dirname(os.path.abspath(__file__)); OUT = os.path.join(HERE, "..", "emission_artifact") KEYDIR = os.environ.get("EDDY_SIGNING_KEY_DIR", "signing-key"); DESIGN = os.environ.get("EDDY_K120B_TABLES", "k120b_tables.json") COIN = 10**8; CAP = 900_000_000 * COIN; CPY = 1_051_920 EPOCH, N, F0, C, Q, SHIFT, D = 9_740, 12_960, 15_233_476_953, 712_119_615, 1_096_969_405_493, 40, 2_696_440 END = N * EPOCH def schedule(): F, s = F0, [] for k in range(N): m = 2 * N - 2 * k - 1; x = (F + C) * m * m // (4 * N * N); x -= x & 1; s.append(x); F = F * Q >> SHIFT return s def cum(s, h): if h <= 0: return 0 if h >= END: return CAP k = (h - 1) // EPOCH; return sum(s[:k]) * EPOCH + (h - k * EPOCH) * s[k] if __name__ == "__main__": s = schedule(); assert CAP - sum(s) * EPOCH == D and D % 2 == 0 and s[0] == 15_944_366_220 annual = [cum(s, y * CPY) - cum(s, (y - 1) * CPY) for y in range(1, 121)] assert sum(annual) == CAP and all(annual[i] > annual[i + 1] for i in range(119)) and annual[-1] > 0 ref = json.load(open(DESIGN)); assert [str(a) for a in annual] == [str(a) for a in ref["annual"]], "annual mismatch vs design" years = [1, 5, 10, 15, 20, 25, 30, 40, 50, 60, 70, 75, 80, 90, 100, 110, 120] for r in ref["rows"]: assert cum(s, r["year"] * CPY) == r["cum_units"], r["year"] ms = [{"year": y, "checkpoint": y * CPY, "cumulative_units": str(cum(s, y * CPY)), "share_of_cap_ppm": cum(s, y * CPY) * 1_000_000 // CAP} for y in years] spec = { "schema": "eddycoin-emission-spec/1", "id": "kompromis-120b", "name": "Kompromis-120b", "status": "planned schedule for the new Eddycoin chain - not live; the current testnet uses an earlier test schedule", "decimals": 8, "unit_per_coin": str(COIN), "cap_units": str(CAP), "premine_units": "0", "faucet": False, "issuance": "only via finalized Y checkpoints (one E-Chain CPU block + one D-Chain GPU block)", "split": {"cpu_e_chain": "1/2", "gpu_d_chain": "1/2", "rule": "every reward is an even number of units; E and D finder each get exactly half"}, "checkpoint_target_seconds": 30, "checkpoints_per_year": CPY, "years": 120, "end_checkpoint": END, "consensus": {"epoch_length": EPOCH, "epochs": N, "F0": str(F0), "C": str(C), "Q": str(Q), "shift": SHIFT, "F_rule": "F_0 = F0; F_(k+1) = floor(F_k * Q / 2^shift)", "s_rule": "m = 2N - 2k - 1; s_k = floor((F_k + C) * m^2 / (4 N^2)); s_k = s_k - (s_k mod 2)", "reward_rule": "checkpoint h in 1..end_checkpoint is in epoch k = floor((h-1)/epoch_length) and gets s_k; the final checkpoint h = end_checkpoint gets s_(N-1) + final_remainder_units; h > end_checkpoint gets 0 (fees only)", "final_remainder_units": str(D), "final_reward_units": str(s[-1] + D), "initial_reward_units": str(s[0]), "initial_reward_per_side_units": str(s[0] // 2), "invariant": "sum over all checkpoints = cap_units exactly; never exceeded"}, "annual_issuance_units": [str(a) for a in annual], "milestones": ms, "difficulty": "independent of issuance (per-chain retarget toward 30 s blocks)", } blob = json.dumps(spec, sort_keys=True, separators=(",", ":"), ensure_ascii=True).encode() + b"\n" os.makedirs(OUT, exist_ok=True); p = os.path.join(OUT, "kompromis-120b.json") open(p, "wb").write(blob); h = hashlib.sha256(blob).hexdigest() open(p + ".sha256", "w").write("%s kompromis-120b.json\n" % h) sig = subprocess.run(["openssl", "pkeyutl", "-sign", "-rawin", "-inkey", KEYDIR + "/emission-signing.key", "-in", p], check=True, capture_output=True).stdout assert len(sig) == 64; open(p + ".sig", "w").write(sig.hex() + "\n") pub = open(KEYDIR + "/emission-signing.pub.raw", "rb").read(); assert len(pub) == 32 open(os.path.join(OUT, "emission-signing.pub"), "w").write(pub.hex() + "\n") # self-check signature with openssl open("/tmp/_emsig.bin", "wb").write(sig) subprocess.run(["openssl", "pkeyutl", "-verify", "-rawin", "-pubin", "-inkey", KEYDIR + "/emission-signing.pub.pem", "-in", p, "-sigfile", "/tmp/_emsig.bin"], check=True, capture_output=True) os.remove("/tmp/_emsig.bin") print("sha256", h); print("pubkey_fingerprint_sha256", hashlib.sha256(pub).hexdigest()); print("bytes", len(blob)) for m in ms: print(m["year"], int(m["cumulative_units"]) / COIN / 1e6, m["share_of_cap_ppm"] / 1e4)