33RustChain v2 - Integrated Server
44Includes RIP-0005 (Epoch Rewards), RIP-0008 (Withdrawals), RIP-0009 (Finality)
55"""
6- import os , time , json , secrets , hashlib , hmac , sqlite3 , base64 , struct , uuid , glob , logging , sys , binascii , math , re
6+ import os , time , json , secrets , hashlib , hmac , sqlite3 , base64 , struct , uuid , glob , logging , sys , binascii , math , re , statistics
77import ipaddress
88from urllib .parse import urlparse
99from flask import Flask , request , jsonify , g , send_from_directory , send_file , abort
@@ -807,6 +807,7 @@ def init_db():
807807 c .execute ("CREATE TABLE IF NOT EXISTS epoch_state (epoch INTEGER PRIMARY KEY, accepted_blocks INTEGER DEFAULT 0, finalized INTEGER DEFAULT 0)" )
808808 c .execute ("CREATE TABLE IF NOT EXISTS epoch_enroll (epoch INTEGER, miner_pk TEXT, weight REAL, PRIMARY KEY (epoch, miner_pk))" )
809809 c .execute ("CREATE TABLE IF NOT EXISTS balances (miner_pk TEXT PRIMARY KEY, balance_rtc REAL DEFAULT 0)" )
810+ ensure_fingerprint_history_table (c )
810811
811812 # Pending transfers (2-phase commit)
812813 # NOTE: Production DBs may already have a different balances schema; this table is additive.
@@ -1116,6 +1117,7 @@ def record_attestation_success(miner: str, device: dict, fingerprint_passed: boo
11161117 INSERT OR REPLACE INTO miner_attest_recent (miner, ts_ok, device_family, device_arch, entropy_score, fingerprint_passed, source_ip)
11171118 VALUES (?, ?, ?, ?, ?, ?, ?)
11181119 """ , (miner , now , device .get ("device_family" , device .get ("family" , "unknown" )), device .get ("device_arch" , device .get ("arch" , "unknown" )), 0.0 , 1 if fingerprint_passed else 0 , source_ip ))
1120+ _ = append_fingerprint_snapshot (conn , miner , fingerprint if isinstance (fingerprint , dict ) else {}, now )
11191121 conn .commit ()
11201122
11211123 # RIP-201: Record fleet immune system signals
@@ -1127,6 +1129,155 @@ def record_attestation_success(miner: str, device: dict, fingerprint_passed: boo
11271129 print (f"[RIP-201] Fleet signal recording warning: { _fe } " )
11281130 # Auto-induct to Hall of Rust
11291131 auto_induct_to_hall (miner , device )
1132+
1133+
1134+ TEMPORAL_HISTORY_LIMIT = 10
1135+ TEMPORAL_DRIFT_BANDS = {
1136+ "clock_drift_cv" : (0.0005 , 0.35 ),
1137+ "thermal_variance" : (0.05 , 25.0 ),
1138+ "jitter_cv" : (0.0001 , 0.50 ),
1139+ "cache_hierarchy_ratio" : (1.10 , 20.0 ),
1140+ }
1141+
1142+
1143+ def ensure_fingerprint_history_table (conn ):
1144+ conn .execute (
1145+ """
1146+ CREATE TABLE IF NOT EXISTS miner_fingerprint_history (
1147+ id INTEGER PRIMARY KEY AUTOINCREMENT,
1148+ miner TEXT NOT NULL,
1149+ ts INTEGER NOT NULL,
1150+ profile_json TEXT NOT NULL
1151+ )
1152+ """
1153+ )
1154+ conn .execute ("CREATE INDEX IF NOT EXISTS idx_mfh_miner_ts ON miner_fingerprint_history(miner, ts DESC)" )
1155+
1156+
1157+ def extract_temporal_profile (fingerprint : dict ) -> dict :
1158+ checks = (fingerprint or {}).get ("checks" , {}) if isinstance (fingerprint , dict ) else {}
1159+
1160+ def _check_data (name ):
1161+ item = checks .get (name , {})
1162+ if isinstance (item , dict ):
1163+ data = item .get ("data" , {})
1164+ return data if isinstance (data , dict ) else {}
1165+ return {}
1166+
1167+ clock = _check_data ("clock_drift" )
1168+ thermal = _check_data ("thermal_entropy" ) or _check_data ("thermal_drift" )
1169+ jitter = _check_data ("instruction_jitter" )
1170+ cache = _check_data ("cache_timing" )
1171+
1172+ return {
1173+ "clock_drift_cv" : float (clock .get ("cv" , 0.0 ) or 0.0 ),
1174+ "thermal_variance" : float (thermal .get ("variance" , 0.0 ) or 0.0 ),
1175+ "jitter_cv" : float (jitter .get ("cv" , 0.0 ) or jitter .get ("stddev_ns" , 0.0 ) or 0.0 ),
1176+ "cache_hierarchy_ratio" : float (cache .get ("hierarchy_ratio" , 0.0 ) or 0.0 ),
1177+ }
1178+
1179+
1180+ def append_fingerprint_snapshot (conn , miner : str , fingerprint : dict , now : int ) -> list :
1181+ ensure_fingerprint_history_table (conn )
1182+ profile = extract_temporal_profile (fingerprint )
1183+ conn .execute (
1184+ "INSERT INTO miner_fingerprint_history (miner, ts, profile_json) VALUES (?, ?, ?)" ,
1185+ (miner , now , json .dumps (profile , separators = ("," , ":" ))),
1186+ )
1187+ conn .execute (
1188+ """
1189+ DELETE FROM miner_fingerprint_history
1190+ WHERE miner = ? AND id NOT IN (
1191+ SELECT id FROM miner_fingerprint_history
1192+ WHERE miner = ?
1193+ ORDER BY ts DESC, id DESC
1194+ LIMIT ?
1195+ )
1196+ """ ,
1197+ (miner , miner , TEMPORAL_HISTORY_LIMIT ),
1198+ )
1199+ rows = conn .execute (
1200+ "SELECT ts, profile_json FROM miner_fingerprint_history WHERE miner = ? ORDER BY ts ASC, id ASC" ,
1201+ (miner ,),
1202+ ).fetchall ()
1203+ seq = []
1204+ for ts , profile_json in rows :
1205+ try :
1206+ seq .append ({"ts" : int (ts ), "profile" : json .loads (profile_json or "{}" )})
1207+ except Exception :
1208+ continue
1209+ return seq
1210+
1211+
1212+ def fetch_miner_fingerprint_sequence (conn , miner : str ) -> list :
1213+ ensure_fingerprint_history_table (conn )
1214+ rows = conn .execute (
1215+ "SELECT ts, profile_json FROM miner_fingerprint_history WHERE miner = ? ORDER BY ts ASC, id ASC" ,
1216+ (miner ,),
1217+ ).fetchall ()
1218+ out = []
1219+ for ts , profile_json in rows :
1220+ try :
1221+ out .append ({"ts" : int (ts ), "profile" : json .loads (profile_json or "{}" )})
1222+ except Exception :
1223+ continue
1224+ return out
1225+
1226+
1227+ def validate_temporal_consistency (sequence : list , current_profile : dict = None ) -> dict :
1228+ samples = list (sequence or [])
1229+ if current_profile is not None :
1230+ samples .append ({"ts" : int (time .time ()), "profile" : current_profile })
1231+ if len (samples ) < 3 :
1232+ return {
1233+ "score" : 1.0 ,
1234+ "review_flag" : False ,
1235+ "reason" : "insufficient_history" ,
1236+ "flags" : [],
1237+ "check_scores" : {},
1238+ }
1239+
1240+ flags = []
1241+ check_scores = {}
1242+ for metric , (low , high ) in TEMPORAL_DRIFT_BANDS .items ():
1243+ values = []
1244+ for s in samples :
1245+ p = s .get ("profile" , {}) if isinstance (s , dict ) else {}
1246+ if isinstance (p , dict ):
1247+ v = float (p .get (metric , 0.0 ) or 0.0 )
1248+ if v > 0 :
1249+ values .append (v )
1250+
1251+ if len (values ) < 3 :
1252+ check_scores [metric ] = 1.0
1253+ continue
1254+
1255+ avg = sum (values ) / len (values )
1256+ spread = statistics .pstdev (values )
1257+ rel_var = spread / max (abs (avg ), 1e-9 )
1258+
1259+ score = 1.0
1260+ if rel_var < 0.01 :
1261+ flags .append (f"frozen_profile:{ metric } " )
1262+ score = min (score , 0.2 )
1263+ if rel_var > 0.8 :
1264+ flags .append (f"noisy_profile:{ metric } " )
1265+ score = min (score , 0.3 )
1266+ if avg < low or avg > high :
1267+ flags .append (f"drift_out_of_band:{ metric } " )
1268+ score = min (score , 0.4 )
1269+
1270+ check_scores [metric ] = score
1271+
1272+ score = sum (check_scores .values ()) / max (len (check_scores ), 1 )
1273+ review_flag = any (f .startswith ("frozen_profile" ) or f .startswith ("noisy_profile" ) or f .startswith ("drift_out_of_band" ) for f in flags )
1274+ return {
1275+ "score" : round (score , 4 ),
1276+ "review_flag" : review_flag ,
1277+ "reason" : "temporal_review_required" if review_flag else "temporal_consistent" ,
1278+ "flags" : flags ,
1279+ "check_scores" : check_scores ,
1280+ }
11301281# =============================================================================
11311282# FINGERPRINT VALIDATION (RIP-PoA Anti-Emulation)
11321283# =============================================================================
@@ -2130,6 +2281,13 @@ def submit_attestation():
21302281 # Record successful attestation (with fingerprint status)
21312282 record_attestation_success (miner , device , fingerprint_passed , client_ip , signals = signals , fingerprint = fingerprint )
21322283
2284+ temporal_review = {"score" : 1.0 , "review_flag" : False , "reason" : "insufficient_history" , "flags" : [], "check_scores" : {}}
2285+ try :
2286+ with sqlite3 .connect (DB_PATH ) as tconn :
2287+ temporal_review = validate_temporal_consistency (fetch_miner_fingerprint_sequence (tconn , miner ))
2288+ except Exception as _te :
2289+ print (f"[TEMPORAL] Warning: { _te } " )
2290+
21332291 # Update warthog_bonus in attestation record
21342292 if warthog_bonus > 1.0 :
21352293 try :
@@ -2159,6 +2317,10 @@ def submit_attestation():
21592317 enroll_weight = 0.000000001
21602318 else :
21612319 enroll_weight = hw_weight
2320+
2321+ # Issue #19 temporal consistency only sets a review flag (no hard-fail).
2322+ if temporal_review .get ("review_flag" ):
2323+ app .logger .warning (f"[TEMPORAL-REVIEW] { miner [:20 ]} ... flags={ temporal_review .get ('flags' , [])} " )
21622324
21632325 miner_id = data .get ("miner_id" , miner )
21642326
@@ -2210,6 +2372,7 @@ def submit_attestation():
22102372 "status" : "accepted" ,
22112373 "device" : device ,
22122374 "fingerprint_passed" : fingerprint_passed ,
2375+ "temporal_review_flag" : bool (temporal_review .get ("review_flag" )),
22132376 "macs_recorded" : len (macs ) if macs else 0 ,
22142377 "warthog_bonus" : warthog_bonus
22152378 })
0 commit comments