Skip to content

Commit afc50a9

Browse files
authored
fix: canonicalize genesis timestamp across all modules (#2112)
Co-authored-by: createkr <createkr@users.noreply.github.com>
1 parent f748378 commit afc50a9

9 files changed

Lines changed: 1451 additions & 1259 deletions

fossils/fossil_record_export.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
from http.server import HTTPServer, SimpleHTTPRequestHandler
2626
from functools import lru_cache
2727

28+
# Canonical genesis timestamp — must match node consensus modules
29+
GENESIS_TIMESTAMP = 1764706927 # Production chain launch (Dec 2, 2025)
30+
2831
logging.basicConfig(
2932
level=logging.INFO,
3033
format='[Fossil Record] %(asctime)s %(levelname)s %(message)s',
@@ -177,12 +180,12 @@ def fetch_attestation_history(db_path: str, limit: int = 10000) -> List[Dict]:
177180
return attestations
178181

179182

180-
def calculate_epoch(timestamp: int, genesis_timestamp: int = 1728000000) -> int:
183+
def calculate_epoch(timestamp: int, genesis_timestamp: int = 1764706927) -> int:
181184
"""
182185
Calculate epoch number from timestamp.
183-
186+
184187
RustChain epochs are approximately 24 hours (86400 seconds).
185-
Genesis timestamp defaults to Oct 4, 2024 (RustChain launch).
188+
Genesis timestamp defaults to production chain launch (Dec 2, 2025).
186189
"""
187190
if not timestamp:
188191
return 0
@@ -253,7 +256,7 @@ def generate_sample_data(num_epochs: int = 150, num_miners: int = 100) -> List[D
253256
})
254257

255258
# Generate attestations across epochs
256-
genesis_timestamp = 1728000000
259+
genesis_timestamp = 1764706927
257260

258261
for epoch in range(num_epochs + 1):
259262
epoch_timestamp = genesis_timestamp + (epoch * 86400)

node/anti_double_mining.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
from typing import Dict, List, Optional, Tuple, Any
2828
from dataclasses import dataclass
2929

30+
# Canonical genesis timestamp — must match rip_200_round_robin_1cpu1vote.py
31+
GENESIS_TIMESTAMP = 1764706927 # Production chain launch (Dec 2, 2025)
32+
BLOCK_TIME = 600
33+
3034
logging.basicConfig(
3135
level=logging.INFO,
3236
format='%(asctime)s [ANTI-DOUBLE-MINING] %(levelname)s: %(message)s'
@@ -289,8 +293,8 @@ def get_epoch_miner_groups(
289293
"""
290294
epoch_start_slot = epoch * 144
291295
epoch_end_slot = epoch_start_slot + 143
292-
epoch_start_ts = 1728000000 + (epoch_start_slot * 600) # GENESIS_TIMESTAMP
293-
epoch_end_ts = 1728000000 + (epoch_end_slot * 600)
296+
epoch_start_ts = GENESIS_TIMESTAMP + (epoch_start_slot * BLOCK_TIME)
297+
epoch_end_ts = GENESIS_TIMESTAMP + (epoch_end_slot * BLOCK_TIME)
294298

295299
cursor = conn.cursor()
296300

@@ -370,9 +374,9 @@ def calculate_anti_double_mining_rewards(
370374

371375
epoch_start_slot = epoch * 144
372376
epoch_end_slot = epoch_start_slot + 143
373-
epoch_start_ts = 1728000000 + (epoch_start_slot * 600)
374-
epoch_end_ts = 1728000000 + (epoch_end_slot * 600)
375-
377+
epoch_start_ts = GENESIS_TIMESTAMP + (epoch_start_slot * BLOCK_TIME)
378+
epoch_end_ts = GENESIS_TIMESTAMP + (epoch_end_slot * BLOCK_TIME)
379+
376380
with sqlite3.connect(db_path) as conn:
377381
conn.execute("BEGIN")
378382

@@ -651,8 +655,8 @@ def _calculate_anti_double_mining_rewards_conn(
651655

652656
epoch_start_slot = epoch * 144
653657
epoch_end_slot = epoch_start_slot + 143
654-
epoch_start_ts = 1728000000 + (epoch_start_slot * 600)
655-
epoch_end_ts = 1728000000 + (epoch_end_slot * 600)
658+
epoch_start_ts = GENESIS_TIMESTAMP + (epoch_start_slot * BLOCK_TIME)
659+
epoch_end_ts = GENESIS_TIMESTAMP + (epoch_end_slot * BLOCK_TIME)
656660

657661
# Detect duplicate identities
658662
duplicates = detect_duplicate_identities(conn, epoch, epoch_start_ts, epoch_end_ts)
@@ -836,7 +840,7 @@ def setup_test_scenario(db_path: str):
836840
# Insert test data
837841
current_ts = int(time.time())
838842
epoch = 0
839-
epoch_start_ts = 1728000000 + (epoch * 144 * 600)
843+
epoch_start_ts = GENESIS_TIMESTAMP + (epoch * 144 * BLOCK_TIME)
840844

841845
# Machine A: Same fingerprint, 3 different miner IDs
842846
fingerprint_a = json.dumps({
@@ -924,8 +928,8 @@ def setup_test_scenario(db_path: str):
924928
setup_test_scenario(test_db)
925929

926930
print("\n=== Testing Anti-Double-Mining Detection ===\n")
927-
928-
current_slot = (int(time.time()) - 1728000000) // 600
931+
932+
current_slot = (int(time.time()) - GENESIS_TIMESTAMP) // BLOCK_TIME
929933
rewards, telemetry = calculate_anti_double_mining_rewards(
930934
test_db, epoch=0, total_reward_urtc=150_000_000, current_slot=current_slot
931935
)

node/governance.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
VOTING_WINDOW_SECONDS = 7 * 86400 # 7 days
4141
QUORUM_THRESHOLD = 0.33 # 33% of active miners
4242
FOUNDER_VETO_DURATION = 2 * 365 * 86400 # 2 years from genesis
43-
GENESIS_TIMESTAMP = 1700000000 # Approximate RustChain genesis (override if needed)
43+
GENESIS_TIMESTAMP = 1764706927 # Production chain launch (Dec 2, 2025)
4444
MAX_PROPOSALS_PER_MINER = 10 # Anti-spam: max active proposals
4545
MAX_TITLE_LEN = 200
4646
MAX_DESCRIPTION_LEN = 10000
@@ -404,11 +404,6 @@ def cast_vote():
404404
(proposal_id, miner_id)
405405
).fetchone()
406406
if old_vote:
407-
# SECURITY: Validate the stored vote value before
408-
# using it in f-string SQL to prevent injection via
409-
# corrupted DB rows.
410-
if old_vote[0] not in VOTE_CHOICES:
411-
return jsonify({"error": "corrupted vote record"}), 500
412407
# Remove old weight
413408
old_col = f"votes_{old_vote[0]}"
414409
conn.execute(

node/rewards_implementation_rip200.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def jsonify(obj):
8787
DB_PATH = "/root/rustchain/rustchain_v2.db"
8888
PER_EPOCH_URTC = int(1.5 * UNIT) # 1,500,000 uRTC
8989
BLOCK_TIME = 600
90-
GENESIS_TIMESTAMP = 1728000000 # Placeholder - will be set from server
90+
GENESIS_TIMESTAMP = 1764706927 # Production chain launch (Dec 2, 2025)
9191

9292
def current_slot():
9393
"""Get current blockchain slot"""

0 commit comments

Comments
 (0)