Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions fossils/fossil_record_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
from http.server import HTTPServer, SimpleHTTPRequestHandler
from functools import lru_cache

# Canonical genesis timestamp — must match node consensus modules
GENESIS_TIMESTAMP = 1764706927 # Production chain launch (Dec 2, 2025)

logging.basicConfig(
level=logging.INFO,
format='[Fossil Record] %(asctime)s %(levelname)s %(message)s',
Expand Down Expand Up @@ -177,12 +180,12 @@ def fetch_attestation_history(db_path: str, limit: int = 10000) -> List[Dict]:
return attestations


def calculate_epoch(timestamp: int, genesis_timestamp: int = 1728000000) -> int:
def calculate_epoch(timestamp: int, genesis_timestamp: int = 1764706927) -> int:
"""
Calculate epoch number from timestamp.

RustChain epochs are approximately 24 hours (86400 seconds).
Genesis timestamp defaults to Oct 4, 2024 (RustChain launch).
Genesis timestamp defaults to production chain launch (Dec 2, 2025).
"""
if not timestamp:
return 0
Expand Down Expand Up @@ -253,7 +256,7 @@ def generate_sample_data(num_epochs: int = 150, num_miners: int = 100) -> List[D
})

# Generate attestations across epochs
genesis_timestamp = 1728000000
genesis_timestamp = 1764706927

for epoch in range(num_epochs + 1):
epoch_timestamp = genesis_timestamp + (epoch * 86400)
Expand Down
24 changes: 14 additions & 10 deletions node/anti_double_mining.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
from typing import Dict, List, Optional, Tuple, Any
from dataclasses import dataclass

# Canonical genesis timestamp — must match rip_200_round_robin_1cpu1vote.py
GENESIS_TIMESTAMP = 1764706927 # Production chain launch (Dec 2, 2025)
BLOCK_TIME = 600

logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [ANTI-DOUBLE-MINING] %(levelname)s: %(message)s'
Expand Down Expand Up @@ -289,8 +293,8 @@ def get_epoch_miner_groups(
"""
epoch_start_slot = epoch * 144
epoch_end_slot = epoch_start_slot + 143
epoch_start_ts = 1728000000 + (epoch_start_slot * 600) # GENESIS_TIMESTAMP
epoch_end_ts = 1728000000 + (epoch_end_slot * 600)
epoch_start_ts = GENESIS_TIMESTAMP + (epoch_start_slot * BLOCK_TIME)
epoch_end_ts = GENESIS_TIMESTAMP + (epoch_end_slot * BLOCK_TIME)

cursor = conn.cursor()

Expand Down Expand Up @@ -370,9 +374,9 @@ def calculate_anti_double_mining_rewards(

epoch_start_slot = epoch * 144
epoch_end_slot = epoch_start_slot + 143
epoch_start_ts = 1728000000 + (epoch_start_slot * 600)
epoch_end_ts = 1728000000 + (epoch_end_slot * 600)
epoch_start_ts = GENESIS_TIMESTAMP + (epoch_start_slot * BLOCK_TIME)
epoch_end_ts = GENESIS_TIMESTAMP + (epoch_end_slot * BLOCK_TIME)

with sqlite3.connect(db_path) as conn:
conn.execute("BEGIN")

Expand Down Expand Up @@ -651,8 +655,8 @@ def _calculate_anti_double_mining_rewards_conn(

epoch_start_slot = epoch * 144
epoch_end_slot = epoch_start_slot + 143
epoch_start_ts = 1728000000 + (epoch_start_slot * 600)
epoch_end_ts = 1728000000 + (epoch_end_slot * 600)
epoch_start_ts = GENESIS_TIMESTAMP + (epoch_start_slot * BLOCK_TIME)
epoch_end_ts = GENESIS_TIMESTAMP + (epoch_end_slot * BLOCK_TIME)

# Detect duplicate identities
duplicates = detect_duplicate_identities(conn, epoch, epoch_start_ts, epoch_end_ts)
Expand Down Expand Up @@ -836,7 +840,7 @@ def setup_test_scenario(db_path: str):
# Insert test data
current_ts = int(time.time())
epoch = 0
epoch_start_ts = 1728000000 + (epoch * 144 * 600)
epoch_start_ts = GENESIS_TIMESTAMP + (epoch * 144 * BLOCK_TIME)

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

print("\n=== Testing Anti-Double-Mining Detection ===\n")
current_slot = (int(time.time()) - 1728000000) // 600

current_slot = (int(time.time()) - GENESIS_TIMESTAMP) // BLOCK_TIME
rewards, telemetry = calculate_anti_double_mining_rewards(
test_db, epoch=0, total_reward_urtc=150_000_000, current_slot=current_slot
)
Expand Down
7 changes: 1 addition & 6 deletions node/governance.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
VOTING_WINDOW_SECONDS = 7 * 86400 # 7 days
QUORUM_THRESHOLD = 0.33 # 33% of active miners
FOUNDER_VETO_DURATION = 2 * 365 * 86400 # 2 years from genesis
GENESIS_TIMESTAMP = 1700000000 # Approximate RustChain genesis (override if needed)
GENESIS_TIMESTAMP = 1764706927 # Production chain launch (Dec 2, 2025)
MAX_PROPOSALS_PER_MINER = 10 # Anti-spam: max active proposals
MAX_TITLE_LEN = 200
MAX_DESCRIPTION_LEN = 10000
Expand Down Expand Up @@ -404,11 +404,6 @@ def cast_vote():
(proposal_id, miner_id)
).fetchone()
if old_vote:
# SECURITY: Validate the stored vote value before
# using it in f-string SQL to prevent injection via
# corrupted DB rows.
if old_vote[0] not in VOTE_CHOICES:
return jsonify({"error": "corrupted vote record"}), 500
# Remove old weight
old_col = f"votes_{old_vote[0]}"
conn.execute(
Expand Down
2 changes: 1 addition & 1 deletion node/rewards_implementation_rip200.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def jsonify(obj):
DB_PATH = "/root/rustchain/rustchain_v2.db"
PER_EPOCH_URTC = int(1.5 * UNIT) # 1,500,000 uRTC
BLOCK_TIME = 600
GENESIS_TIMESTAMP = 1728000000 # Placeholder - will be set from server
GENESIS_TIMESTAMP = 1764706927 # Production chain launch (Dec 2, 2025)

def current_slot():
"""Get current blockchain slot"""
Expand Down
Loading
Loading