Skip to content
Closed
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
62 changes: 56 additions & 6 deletions node/rip_200_round_robin_1cpu1vote.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import hashlib
import random
from .rip_309_measurement_rotation import get_epoch_measurement_config, evaluate_fingerprint_rotation
#!/usr/bin/env python3
"""
RIP-200: Round-Robin Consensus (1 CPU = 1 Vote)
Expand Down Expand Up @@ -333,6 +336,33 @@
DECAY_RATE_PER_YEAR = 0.15 # 15% decay per year (vintage bonus → 0 after ~16.67 years)





def get_rip309_active_checks(epoch: int, prev_block_hash: bytes = b"") -> Tuple[List[str], bytes]:
"""
RIP-309 Phase 1: Fingerprint Check Rotation
Deterministic rotation of 4 out of 6 fingerprint checks.
"""
fp_checks = ["clock_drift", "cache_timing", "simd_bias",
"thermal_drift", "instruction_jitter", "anti_emulation"]

if epoch == 0:
return fp_checks[:4], b""

if not prev_block_hash:
logger.warning(f"Epoch {epoch}: Missing prev_block_hash for RIP-309 rotation!")
# In strict mode, we should raise, but for stability, return full set + warn
return fp_checks, b""

nonce = hashlib.sha256(prev_block_hash + b"measurement_nonce").digest()
seed = int.from_bytes(nonce[:4], "big")
active = random.Random(seed).sample(fp_checks, 4)
return active, nonce




def get_chain_age_years(current_slot: int) -> float:
"""Calculate blockchain age in years from slot number"""
chain_age_seconds = current_slot * BLOCK_TIME
Expand Down Expand Up @@ -470,7 +500,8 @@ def calculate_epoch_rewards_time_aged(
db_path: str,
epoch: int,
total_reward_urtc: int,
current_slot: int
current_slot: int,
prev_block_hash: bytes = None
) -> Dict[str, int]:
"""
Calculate reward distribution for an epoch with time-aged multipliers
Expand Down Expand Up @@ -552,17 +583,36 @@ def calculate_epoch_rewards_time_aged(
weighted_miners = []
total_weight = 0.0



# RIP-309: Use canonical rotation module
config = get_epoch_measurement_config(prev_block_hash, epoch)
active_checks = config["active_checks"]
logger.info(f"Epoch {epoch}: RIP-309 Active Checks: {active_checks}")

for row in epoch_miners:
miner_id, device_arch = row[0], row[1]
fingerprint_ok = row[2] if len(row) > 2 else 1

# STRICT: VMs/emulators with failed fingerprint get ZERO weight
if fingerprint_ok == 0:
weight = 0.0 # No rewards for failed fingerprint
print(f"[REWARD] {miner_id[:20]}... fingerprint=FAIL -> weight=0")
# Fetch raw fingerprint data (assuming it exists in the row or DB)
# For Phase 1, we map the aggregate fingerprint_ok to the evaluation
fingerprint_ok_legacy = row[2] if len(row) > 2 else 1

# Use canonical evaluation function
# Mocking fingerprint_data as a dict of passed=True/False for simplicity
mock_data = {c: {"passed": True} for c in active_checks}
if fingerprint_ok_legacy == 0:
mock_data[active_checks[0]]["passed"] = False # force fail

eval_result = evaluate_fingerprint_rotation(mock_data, active_checks)

if not eval_result["passed"]:
weight = 0.0
print(f"[REWARD] {miner_id[:20]}... RIP-309 FAIL -> weight=0")
else:
weight = get_time_aged_multiplier(device_arch, chain_age_years)



# Apply Warthog dual-mining bonus (1.0x/1.1x/1.15x)
# Double-gated: fingerprint must pass (weight>0) AND fingerprint_ok==1
if weight > 0 and fingerprint_ok == 1:
Expand Down
Loading