"""RELEASE build of the eddycoin-mainnet-1 node. 1) runs node_net/build_mainnet_node.py logic against the REAL signed K120b artifact (eddycoin_site/emission_artifact) 2) applies release edits: version, port 8773, genesis bits, embedded artifact + genesis.json, genesis id = hash of genesis.json (hardcoded), artifact check for the real schema, /api/genesis, no admin/reset route, --genesis-bits only for private test networks. Output: launch/release/eddycoin_node.py (+ old_key_denylist.json copy). Every edit must match exactly once.""" import hashlib, json, os, re, shutil HERE = os.path.dirname(os.path.abspath(__file__)); NN = os.path.join(HERE, "..", "node_net") ART = os.environ.get("EDDY_EMISSION_DIR", "emission"); GEN = os.path.join(HERE, "genesis") OUTD = os.path.join(HERE, "release"); os.makedirs(OUTD, exist_ok=True) # --- step 1: prototype builder with the real artifact, output captured instead of written b = open(os.path.join(NN, "build_mainnet_node.py"), encoding="utf-8").read() b = b.replace('os.path.join(here, "emission", "kompromis-120b.json")', 'os.path.join(%r, "kompromis-120b.json")' % ART) b = b.replace('os.path.join(here, "emission", "emission-signing.pub")', 'os.path.join(%r, "emission-signing.pub")' % ART) b = b.replace('open(os.path.join(here, "eddycoin_node_mainnet.py"), "w", encoding="utf-8").write(src)', 'RESULT.append(src)') RESULT = [] g = {"__file__": os.path.join(NN, "build_mainnet_node.py"), "RESULT": RESULT, "__name__": "builder"} exec(compile(b, "build_mainnet_node.py", "exec"), g) src = RESULT[0] def rep(old, new, count=1): global src n = src.count(old); assert n == count, (n, old[:90]); src = src.replace(old, new) spec = open(os.path.join(ART, "kompromis-120b.json"), "rb").read(); sig = open(os.path.join(ART, "kompromis-120b.json.sig")).read().strip() SPEC_SHA = hashlib.sha256(spec).hexdigest(); assert SPEC_SHA == "0a70d671ca52094d7eaa82c7b43122bce4f9bba1281f79d0ca1211b99c27cfb7" gj = open(os.path.join(GEN, "genesis.json"), "rb").read(); gsig = open(os.path.join(GEN, "genesis.json.sig")).read().strip() G = json.loads(gj); GSHA = hashlib.sha256(gj).hexdigest() assert G["emission"]["spec_sha256"] == SPEC_SHA and G["allocations"] == [] and G["network"] == "eddycoin-mainnet-1" and G["chain_id"] == "EDDY1" # ---- release identity, port, genesis bits rep('NODE_VERSION = "eddycoin-node/2.0-mainnet-PROTOTYPE"', 'NODE_VERSION = "eddycoin-node/2.0"') rep('DEFAULT_PORT = 8771\n', 'DEFAULT_PORT = 8773 # 8770 = old testnet node, 8771 = pool, 8772 = explorer; mainnet P2P/API default = 8773\n') rep('BOOTSTRAP = ["https://129-159-188-73.sslip.io"] # Oracle seed (placeholder name) + community seeds appended here', 'BOOTSTRAP = ["https://129-159-188-73.sslip.io"] # Oracle seed (discovery only) + community seeds appended here') rep('# e.g. "seed.eddycoin.example": A/AAAA records -> http://:8771', '# e.g. "seed.eddycoin.example": A/AAAA records -> http://:8773', 0) if False else None src = src.replace('A/AAAA records -> http://:8771', 'A/AAAA records -> http://:8773') rep('GENESIS_BITS = {"E": 28, "D": 33}', 'GENESIS_BITS = {"E": %d, "D": %d} # == genesis.json genesis_bits' % (G["genesis_bits"]["E"], G["genesis_bits"]["D"])) rep('EMISSION_SPEC_SHA256 = "%s" # SHA-256 of the canonical kompromis-120b.json (PROTOTYPE: test artifact)' % SPEC_SHA, 'EMISSION_SPEC_SHA256 = "%s" # SHA-256 of the canonical, signed kompromis-120b.json (committed in genesis.json)' % SPEC_SHA) PUB = open(os.path.join(ART, "emission-signing.pub")).read().strip() rep('EMISSION_PUBKEY = "%s" # Ed25519 emission-signing public key (PROTOTYPE: test key)' % PUB, 'EMISSION_PUBKEY = "%s" # Ed25519 emission-signing public key (display/transparency only)\n' % PUB + 'EMISSION_ARTIFACT = %r\nEMISSION_ARTIFACT_SIG = %r\n' % (spec, sig) + '# ---- genesis (GENESIS_DESIGN.md): exact canonical bytes of genesis.json; the genesis checkpoint commits to their SHA-256\n' + 'GENESIS_JSON = %r\nGENESIS_JSON_SHA256 = "%s"\nGENESIS_SIG = %r\nGENESIS_TIME_MS = %d\n' % (gj, GSHA, gsig, G["timestamp_ms"])) # ---- genesis checkpoint: evidence = GENESIS|network|chain id|sha256(genesis.json); time = genesis timestamp (same on every node) rep('def genesis_checkpoint(t=0):', 'def genesis_checkpoint(t=None):\n t = GENESIS_TIME_MS if t is None else t') rep(' g = "GENESIS|%s|%s|emission=%s:%s" % (NETWORK, CHAIN_ID, EMISSION_NAME, EMISSION_SPEC_SHA256)\n cp = {', ' g = "GENESIS|%s|%s|%s" % (NETWORK, CHAIN_ID, GENESIS_JSON_SHA256)\n cp = {') rep(' def __init__(self, genesis_bits=None, genesis_time=0):', ' def __init__(self, genesis_bits=None, genesis_time=None):') rep('GENESIS_ID = genesis_checkpoint()["id"]\n', '''GENESIS_ID = genesis_checkpoint()["id"] GENESIS_ID_HARDCODED = "@@GID@@" _GJ = json.loads(GENESIS_JSON) assert hashlib.sha256(GENESIS_JSON).hexdigest() == GENESIS_JSON_SHA256, "genesis.json bytes changed" assert GENESIS_ID == GENESIS_ID_HARDCODED, "genesis id mismatch" assert _GJ["network"] == NETWORK and _GJ["chain_id"] == CHAIN_ID and _GJ["emission"]["spec_sha256"] == EMISSION_SPEC_SHA256 and _GJ["allocations"] == [] assert int(_GJ["max_supply"]) == MAX_SUPPLY and _GJ["genesis_bits"] == GENESIS_BITS and hashlib.sha256(EMISSION_ARTIFACT).hexdigest() == EMISSION_SPEC_SHA256 assert _GJ["emission_signing_pubkey_fingerprint"] == "sha256:" + hashlib.sha256(bytes.fromhex(EMISSION_PUBKEY)).hexdigest() assert (_GJ["domains"]["tx"], _GJ["domains"]["sig"], _GJ["domains"]["address"], _GJ["domains"]["checkpoint"]) == (D_TX, D_SIG, D_ADDR, D_CP) ''') # ---- artifact check understands the real (published) schema rep('def emission_vectors_ok(art):', '''def emission_vectors_ok(art): """published schema eddycoin-emission-spec/1: constants, milestones, annual issuance, cap, end, first reward vs the built-in formula""" if isinstance(art, dict) and art.get("schema") == "eddycoin-emission-spec/1": try: c = art["consensus"] if (int(c["F0"]), int(c["C"]), int(c["Q"]), int(c["epoch_length"]), int(c["epochs"]), int(c["shift"])) != (EM_F0, EM_C, EM_Q, EM_EPOCH, EM_N, EM_SHIFT): return False, "constants differ from the built-in formula" if int(art["cap_units"]) != MAX_SUPPLY or int(art["end_checkpoint"]) != EM_END or int(c["initial_reward_units"]) != emission_reward(1): return False, "cap / end / initial reward differ" bad = [m["checkpoint"] for m in art["milestones"] if int(m["cumulative_units"]) != emission_cum(int(m["checkpoint"]))] cpy = int(art["checkpoints_per_year"]) bad += ["year%d" % (i + 1) for i, v in enumerate(art["annual_issuance_units"]) if int(v) != emission_cum((i + 1) * cpy) - emission_cum(i * cpy)] n = len(art["milestones"]) + len(art["annual_issuance_units"]) return (not bad), ("%d milestones/annual values match the built-in formula" % n if not bad else "mismatch at %s" % bad[:5]) except Exception as ex: return False, "unreadable artifact (%s)" % ex return emission_vectors_ok_v0(art) def emission_vectors_ok_v0(art):''') # ---- bundled artifact = embedded copy first rep(''' def bundled_artifact(self): for d in''', ''' def bundled_artifact(self): if hashlib.sha256(EMISSION_ARTIFACT).hexdigest() == EMISSION_SPEC_SHA256 and ed25519_verify(EMISSION_PUBKEY, EMISSION_ARTIFACT_SIG, EMISSION_ARTIFACT): return EMISSION_ARTIFACT, EMISSION_ARTIFACT_SIG, "built-in (embedded in this program)" for d in''') # ---- GET /api/genesis rep(''' if p == "/api/emission": return self.send(*node.api_emission())''', ''' if p == "/api/emission": return self.send(*node.api_emission()) if p == "/api/genesis": return self.send(200, {"network": NETWORK, "chain_id": CHAIN_ID, "genesis_id": GENESIS_ID, "genesis_json_sha256": GENESIS_JSON_SHA256, "json": GENESIS_JSON.decode("ascii"), "sig": GENESIS_SIG, "pubkey": EMISSION_PUBKEY, "sig_verified": ed25519_verify(EMISSION_PUBKEY, GENESIS_SIG, GENESIS_JSON)})''') # ---- --genesis-bits only for private local test networks (env EDDY_TEST_PRIVATE_NET=1) rep(''' why = startup_key_check(build_cfg(a))''', ''' if a.genesis_bits and os.environ.get("EDDY_TEST_PRIVATE_NET") != "1": print("REFUSING TO START: --genesis-bits is only for private test networks (EDDY_TEST_PRIVATE_NET=1)", flush=True); sys.exit(2) why = startup_key_check(build_cfg(a))''') # a bootstrap entry that is this node's own public URL (the Oracle seed itself) is not a peer rep(""" for u in BOOTSTRAP: if norm_url(u) and norm_url(u) not in self.peers:""", """ for u in BOOTSTRAP: if norm_url(u) and norm_url(u) not in self.peers and not (cfg.public_url and norm_url(u) == norm_url(cfg.public_url)):""") # ---- --behind-proxy (ported from the deployed Oracle testnet node): real client IP from X-Forwarded-For for rate limits/bans rep(""" u = urllib.parse.urlsplit(self.path); p = u.path.rstrip("/"); q = urllib.parse.parse_qs(u.query); ip = self.client_address[0]""", """ u = urllib.parse.urlsplit(self.path); p = u.path.rstrip("/"); q = urllib.parse.parse_qs(u.query); ip = self.cip()""") rep(""" p = urllib.parse.urlsplit(self.path).path.rstrip("/"); ip = self.client_address[0]""", """ p = urllib.parse.urlsplit(self.path).path.rstrip("/"); ip = self.cip()""") i = src.index(" u = urllib.parse.urlsplit(self.path); p = u.path.rstrip(\"/\"); q = urllib.parse.parse_qs(u.query); ip = self.cip()") j = src.rindex(" def do_GET(self):", 0, i) src = src[:j] + """ def cip(self): \"\"\"client IP; behind the local HTTPS proxy (Caddy, --behind-proxy) the real client from X-Forwarded-For (rate limits, bans)\"\"\" ip = self.client_address[0] if node.cfg.behind_proxy and ip in ("127.0.0.1", "::1"): x = (self.headers.get("X-Forwarded-For") or "").split(",")[-1].strip() if x: return x return ip """ + src[j:] rep("self.seed_timeout = 60; self.seed_interval = 8; self.peer_interval = 5", "self.seed_timeout = 60; self.seed_interval = 8; self.peer_interval = 5; self.behind_proxy = False") rep(""" cfg.peers = a.peer or [] """, """ cfg.peers = a.peer or [] cfg.behind_proxy = bool(getattr(a, "behind_proxy", False)) """) rep(""" ap.add_argument("--denylist",""", """ ap.add_argument("--behind-proxy", action="store_true", help="server: requests from 127.0.0.1 come through the local HTTPS proxy (Caddy); use X-Forwarded-For as client IP") ap.add_argument("--denylist",""") assert "/api/admin" not in src and "admin_reset" not in src and "ADMIN_SECRET" not in src # fix genesis id: compute with a temporary module tmp = os.path.join(OUTD, "_tmp_gid.py"); open(tmp, "w").write(src.replace('assert GENESIS_ID == GENESIS_ID_HARDCODED, "genesis id mismatch"', 'pass')) import importlib.util as u s = u.spec_from_file_location("gid", tmp); m = u.module_from_spec(s); s.loader.exec_module(m); GID = m.GENESIS_ID; os.unlink(tmp) src = src.replace("@@GID@@", GID) out = os.path.join(OUTD, "eddycoin_node.py"); open(out, "w", encoding="utf-8").write(src) shutil.copy(os.environ.get("EDDY_DENYLIST", "old_key_denylist.json"), os.path.join(OUTD, "old_key_denylist.json")) for f in ("genesis.json", "genesis.json.sig", "genesis.json.sha256"): shutil.copy(os.path.join(GEN, f), os.path.join(OUTD, f)) print("built", out, "sha256", hashlib.sha256(src.encode()).hexdigest(), "\nGENESIS_ID", GID, "\nGENESIS_JSON_SHA256", GSHA)