0xd79f3c51…e683sent to0xb7278a61…e575·#24,727,971·view on Etherscan
L# { "Depends": "py-genlayer:test" }
from genlayer import *
# Score stored as: [player, level, moves, time_sec]
# key = "address_level" e.g. "0xABC_3"
class BlockholeLeaderboard(gl.Contract):
"""
Blockhole x GenLayer — On-chain leaderboard with AI-validated scores.
Optimistic Democracy: 5 LLM validators vote on whether each score is
humanly plausible before it's accepted on-chain.
"""
scores: TreeMap[str, str] # key="addr_level" value="moves,time_sec"
week_number: u32
total_submissions: u32
def __init__(self):
self.week_number = 1
self.total_submissions = 0
# ─── Write: submit a score ────────────────────────────────────────────────
def submit_score(
self,
player: str,
level: u32,
moves: u32,
time_sec: u32,
) -> None:
"""
Submit a level completion score.
GenLayer validators (each using a different LLM) vote on whether
the score is humanly plausible — this IS the Optimistic Democracy showcase.
"""
def validate_score() -> bool:
result = gl.exec_prompt(
f"A player completed level {level} of a Bloxorz-style puzzle game "
f"(roll a rectangular block into a hole) in {moves} moves and "
f"{time_sec} seconds. "
f"Level 1 is easy (~10 moves), level 10 is expert (~60+ moves). "
f"Is this score plausible for a human player? "
f"Answer only 'yes' or 'no'."
)
return "yes" in result.lower()
is_valid = gl.eq_principle_strict_eq(validate_score)
if not is_valid:
raise Exception("Score rejected by AI validators — not humanly plausible")
key = f"{player}_{level}"
existing = self.scores.get(key)
# Keep personal best (lowest moves, tie-break by time)
if existing is not None:
parts = existing.split(",")
best_moves = int(parts[0])
best_time = int(parts[1])
if moves > best_moves or (moves == best_moves and time_sec >= best_time):
return # Not a new personal best
self.scores[key] = f"{moves},{time_sec}"
self.total_submissions += 1
# ─── Read: leaderboard queries ───────────────────────────────────────────
def get_leaderboard(self, level: u32) -> list:
"""Return top 10 scores for a specific level, sorted by moves then time."""
level_scores = []
suffix = f"_{level}"
for key, val in self.scores.items():
if key.endswith(suffix):
player = key[: -len(suffix)]
parts = val.split(",")
level_scores.append({
"player": player,
"level": int(level),
"moves": int(parts[0]),
"time_sec": int(parts[1]),
})
level_scores.sort(key=lambda s: (s["moves"], s["time_sec"]))
return level_scores[:10]
def get_global_leaderboard(self) -> list:
"""Return top players by total moves across all levels (fewer = better)."""
player_totals: dict = {}
for key, val in self.scores.items():
# key format: "0xADDR_LEVEL"
last_underscore = key.rfind("_")
if last_underscore == -1:
continue
player = key[:last_underscore]
parts = val.split(",")
if player not in player_totals:
player_totals[player] = {"player": player, "total_moves": 0, "levels_done": 0}
player_totals[player]["total_moves"] += int(parts[0])
player_totals[player]["levels_done"] += 1
ranked = sorted(
player_totals.values(),
key=lambda x: (-(x["levels_done"]), x["total_moves"]),
)
return ranked[:10]
def get_player_scores(self, player: str) -> list:
"""Return all scores for a given player address."""
result = []
prefix = f"{player}_"
for key, val in self.scores.items():
if key.startswith(prefix):
level = int(key[len(prefix):])
parts = val.split(",")
result.append({
"level": level,
"moves": int(parts[0]),
"time_sec": int(parts[1]),
})
return sorted(result, key=lambda s: s["level"])
def get_week(self) -> u32:
return self.week_number
def get_total_submissions(self) -> u32:
return self.total_submissions
# ─── Admin: weekly reset ─────────────────────────────────────────────────
def weekly_reset(self) -> None:
"""Reset leaderboard for a new week."""
self.scores = gl.storage.inmem_allocate(TreeMap[str, str])
self.week_number += 1