box-prover.py: the export directory owns its disk (20 GB and 7-day caps, export deleted on record accepted or paid, no export under 10 percent free)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
a99617bd9f
commit
86c9854863
1 changed files with 27 additions and 3 deletions
|
|
@ -27,7 +27,29 @@ HOST = f"{FLOOR}/bin/igneum-prove-host"; EXPORT = f"{FLOOR}/bin/igneum-prove-exp
|
||||||
EVM = "http://127.0.0.1:26790"; GRPC = "grpc://127.0.0.1:26610"; CHAIN = os.environ.get("CHAIN_NAME", "igneum-devnet") # Devnet 2 signs for igneum-devnet-2
|
EVM = "http://127.0.0.1:26790"; GRPC = "grpc://127.0.0.1:26610"; CHAIN = os.environ.get("CHAIN_NAME", "igneum-devnet") # Devnet 2 signs for igneum-devnet-2
|
||||||
LABEL = os.environ.get("LABEL", "box"); WALLET = os.environ.get("WALLET", "0x" + "19" * 20)
|
LABEL = os.environ.get("LABEL", "box"); WALLET = os.environ.get("WALLET", "0x" + "19" * 20)
|
||||||
THRESHOLD = os.environ.get("THRESHOLD", ""); MINER = os.environ.get("MINER", "keep"); RUN_HOURS = float(os.environ.get("RUN_HOURS", "9"))
|
THRESHOLD = os.environ.get("THRESHOLD", ""); MINER = os.environ.get("MINER", "keep"); RUN_HOURS = float(os.environ.get("RUN_HOURS", "9"))
|
||||||
EXPORT_FROM = int(os.environ.get("EXPORT_FROM", "27276")) # the devnet's exec restart block (ov13.json exec_restart_number) when the node does not report one
|
EXPORT_FROM = int(os.environ.get("EXPORT_FROM", "27276"))
|
||||||
|
# the export directory's own rule (6 October 2026, 20:4xZ, after the hub's node died on a full disk): a size cap and an age cap
|
||||||
|
# on OUT/segs, each segment's export deleted the moment its record is accepted or paid, and a disk-free check before each
|
||||||
|
# export that skips with a logged line under 10 percent free. Defaults fit a 100 GB box for a week.
|
||||||
|
SEGS_CAP_GB = float(os.environ.get("SEGS_CAP_GB", "20")); SEGS_MAX_AGE_H = float(os.environ.get("SEGS_MAX_AGE_H", str(7 * 24))); DISK_MIN_FREE_PCT = float(os.environ.get("DISK_MIN_FREE_PCT", "10"))
|
||||||
|
import shutil
|
||||||
|
def seg_dir_size(d):
|
||||||
|
return sum(os.path.getsize(os.path.join(r, f)) for r, _, fs in os.walk(d) for f in fs if os.path.exists(os.path.join(r, f)))
|
||||||
|
def drop_export(first, why):
|
||||||
|
d = f"{OUT}/segs/seg-{first}"
|
||||||
|
if os.path.isdir(d): sz = seg_dir_size(d); shutil.rmtree(d, ignore_errors=True); say(f"RESULT export_dropped {stamp()} segment {first} ({sz/1e6:.0f} MB): {why}")
|
||||||
|
def prune_exports():
|
||||||
|
root = f"{OUT}/segs"
|
||||||
|
if not os.path.isdir(root): return
|
||||||
|
entries = sorted((os.path.join(root, n) for n in os.listdir(root)), key=lambda x: os.path.getmtime(x))
|
||||||
|
now_ = time.time(); total = sum(seg_dir_size(e) if os.path.isdir(e) else os.path.getsize(e) for e in entries)
|
||||||
|
for e in entries:
|
||||||
|
age_h = (now_ - os.path.getmtime(e)) / 3600
|
||||||
|
if age_h > SEGS_MAX_AGE_H or total > SEGS_CAP_GB * 1e9:
|
||||||
|
sz = seg_dir_size(e) if os.path.isdir(e) else os.path.getsize(e); shutil.rmtree(e, ignore_errors=True) if os.path.isdir(e) else os.remove(e); total -= sz
|
||||||
|
say(f"RESULT export_pruned {stamp()} {os.path.basename(e)} ({sz/1e6:.0f} MB, {age_h:.1f} h old): dir {total/1e9:.1f} GB against the {SEGS_CAP_GB:.0f} GB cap, {SEGS_MAX_AGE_H:.0f} h age cap")
|
||||||
|
def disk_free_pct(path="/"):
|
||||||
|
st = os.statvfs(path); return 100.0 * st.f_bavail / max(st.f_blocks, 1) # the devnet's exec restart block (ov13.json exec_restart_number) when the node does not report one
|
||||||
MINE = f"{F}/card{CARD}/mine" if CARD else f"{F}/mine"
|
MINE = f"{F}/card{CARD}/mine" if CARD else f"{F}/mine"
|
||||||
os.makedirs(f"{OUT}/segs", exist_ok=True); os.makedirs(f"{MINE}/packs", exist_ok=True)
|
os.makedirs(f"{OUT}/segs", exist_ok=True); os.makedirs(f"{MINE}/packs", exist_ok=True)
|
||||||
DEV = os.environ.get("IGNEUM_CUDA_DEVICE", "0")
|
DEV = os.environ.get("IGNEUM_CUDA_DEVICE", "0")
|
||||||
|
|
@ -131,7 +153,7 @@ while (time.time() - t_run0) / 3600 < RUN_HOURS:
|
||||||
for first in list(submitted):
|
for first in list(submitted):
|
||||||
rec = rpc("igneum_getSegmentRecords", [hex(first)])
|
rec = rpc("igneum_getSegmentRecords", [hex(first)])
|
||||||
if rec and rec.get("paid"):
|
if rec and rec.get("paid"):
|
||||||
wei = hexi(rec["paid"]["wei"]); state["paid"] += 1; state["paid_wei"] += wei
|
wei = hexi(rec["paid"]["wei"]); state["paid"] += 1; state["paid_wei"] += wei; drop_export(first, "record paid")
|
||||||
say(f"RESULT paid {stamp()} segment {first}..{submitted[first]['last']} wei={wei} ({wei/1e18:.4f} IGN) carrier={hexi(rec['paid'].get('carrierNumber'))} after {int(time.time()-submitted[first]['at'])} s")
|
say(f"RESULT paid {stamp()} segment {first}..{submitted[first]['last']} wei={wei} ({wei/1e18:.4f} IGN) carrier={hexi(rec['paid'].get('carrierNumber'))} after {int(time.time()-submitted[first]['at'])} s")
|
||||||
for s in state["segments"]:
|
for s in state["segments"]:
|
||||||
if s["first"] == first: s["paid_wei"] = wei; s["paid_at"] = stamp()
|
if s["first"] == first: s["paid_wei"] = wei; s["paid_at"] = stamp()
|
||||||
|
|
@ -144,7 +166,7 @@ while (time.time() - t_run0) / 3600 < RUN_HOURS:
|
||||||
if tip > h["deadline"]: say(f"RESULT held_expired {stamp()} segment {first} deadline passed"); del held[first]; continue
|
if tip > h["deadline"]: say(f"RESULT held_expired {stamp()} segment {first} deadline passed"); del held[first]; continue
|
||||||
rr = submit("igneum_submitSegmentRecord", h["record"], h["proof_file"])
|
rr = submit("igneum_submitSegmentRecord", h["record"], h["proof_file"])
|
||||||
if rr and rr.get("accepted"):
|
if rr and rr.get("accepted"):
|
||||||
state["submitted"] += 1; submitted[first] = {"last": h["last"], "at": time.time(), "deadline": h["deadline"]}; say(f"RESULT submitted {stamp()} segment {first}..{h['last']} record accepted on retry (held {int(time.time()-h['since'])} s)"); del held[first]
|
state["submitted"] += 1; submitted[first] = {"last": h["last"], "at": time.time(), "deadline": h["deadline"]}; drop_export(first, "record accepted"); say(f"RESULT submitted {stamp()} segment {first}..{h['last']} record accepted on retry (held {int(time.time()-h['since'])} s)"); del held[first]
|
||||||
state["held"] = len(held)
|
state["held"] = len(held)
|
||||||
cands, start, n, tip, entries = candidates(st)
|
cands, start, n, tip, entries = candidates(st)
|
||||||
save_state()
|
save_state()
|
||||||
|
|
@ -171,6 +193,8 @@ while (time.time() - t_run0) / 3600 < RUN_HOURS:
|
||||||
first, last = picked["first"], picked["last"]; attempted.add(first); state["claimed"] += 1
|
first, last = picked["first"], picked["last"]; attempted.add(first); state["claimed"] += 1
|
||||||
say(f"RESULT claim {stamp()} segment {first}..{last} ({len(picked['shards'])} shards, {'continuing' if prev_file else 'fresh'}) margin={picked['margin']} tip={tip} candidates={len(cands)} rank_by=fnv")
|
say(f"RESULT claim {stamp()} segment {first}..{last} ({len(picked['shards'])} shards, {'continuing' if prev_file else 'fresh'}) margin={picked['margin']} tip={tip} candidates={len(cands)} rank_by=fnv")
|
||||||
seg = {"first": first, "last": last, "claimed_at": stamp(), "shards": len(picked["shards"]), "fresh": prev_file is None}; state["segments"].append(seg)
|
seg = {"first": first, "last": last, "claimed_at": stamp(), "shards": len(picked["shards"]), "fresh": prev_file is None}; state["segments"].append(seg)
|
||||||
|
prune_exports(); free = disk_free_pct()
|
||||||
|
if free < DISK_MIN_FREE_PCT: say(f"RESULT skip {stamp()} segment {first}: disk {free:.1f}% free is under the {DISK_MIN_FREE_PCT:.0f}% floor, no export"); time.sleep(60); continue
|
||||||
d = f"{OUT}/segs/seg-{first}"; os.makedirs(d, exist_ok=True); t_seg0 = time.time()
|
d = f"{OUT}/segs/seg-{first}"; os.makedirs(d, exist_ok=True); t_seg0 = time.time()
|
||||||
# export
|
# export
|
||||||
# a node whose EVM restarted at a chain block (0.3.13's exec restart rule) exports from that block, not genesis: the
|
# a node whose EVM restarted at a chain block (0.3.13's exec restart rule) exports from that block, not genesis: the
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue