diff --git a/docs/zh-CN/README.md b/docs/zh-CN/README.md index 2ec809341..3ace6810f 100644 --- a/docs/zh-CN/README.md +++ b/docs/zh-CN/README.md @@ -50,6 +50,8 @@ | [wRTC 教程](../WRTC_ONBOARDING_TUTORIAL.md) | 跨链桥接指南 | | [贡献指南](../../CONTRIBUTING.md) | 参与开发 | +BoTTube 高级接口运行在 BoTTube 域名上:`https://bottube.ai/api/premium/videos` 和 `https://bottube.ai/api/premium/analytics/`。 + --- ## 🔥 Crypto 迷失了方向。我们回到原点。 diff --git a/miners/checksums.sha256 b/miners/checksums.sha256 index 0412ea8be..69cf98f36 100644 --- a/miners/checksums.sha256 +++ b/miners/checksums.sha256 @@ -1,4 +1,4 @@ -4afd5aea552cc5b68364b39fa37cdc93d1d406ec295670969e1a9c4164babb15 linux/rustchain_linux_miner.py +c7af612bb2630d5fe6576bb132bdeb7a00ba0be042ec168887ab767a1f16c9f9 linux/rustchain_linux_miner.py cdfca6e63ecd24f53b30140dd44df42415a3254c68aad95b1fca3c1557e15f7b linux/fingerprint_checks.py 603d9a3b3ebfe1a0ca56a60988db4b5d4a80ab57cb5feb1c0b563a1d4020fcd7 macos/rustchain_mac_miner_v2.4.py 163fafcf751d8fbd41bf936facaeb366c042f467fa34b79f2c4c0a45472ef70f macos/rustchain_mac_miner_v2.5.py diff --git a/node/airdrop_v2.py b/node/airdrop_v2.py index 83e4dae52..ac74ea05c 100644 --- a/node/airdrop_v2.py +++ b/node/airdrop_v2.py @@ -1139,7 +1139,7 @@ def get_claims_by_github( "SELECT * FROM airdrop_claims WHERE github_username = ?", (github_username,), ) - rows = cursor.fetchall() + rows = cursor.fetchall() # fetchall-ok: bounded-by-schema self._close_conn(conn) return [ @@ -1190,7 +1190,7 @@ def get_allocation_status(self) -> Dict[str, Dict[str, Any]]: conn = self._get_conn() cursor = conn.cursor() cursor.execute("SELECT * FROM airdrop_allocation") - rows = cursor.fetchall() + rows = cursor.fetchall() # fetchall-ok: bounded-by-schema self._close_conn(conn) return { @@ -1223,7 +1223,7 @@ def get_stats(self) -> Dict[str, Any]: ) by_tier = { row["tier"]: {"count": row["count"], "total_wrtc": row["total"] / 1_000_000} - for row in cursor.fetchall() + for row in cursor.fetchall() # fetchall-ok: bounded-by-schema } # Claims by chain @@ -1235,7 +1235,7 @@ def get_stats(self) -> Dict[str, Any]: ) by_chain = { row["chain"]: {"count": row["count"], "total_wrtc": row["total"] / 1_000_000} - for row in cursor.fetchall() + for row in cursor.fetchall() # fetchall-ok: bounded-by-schema } # Bridge locks diff --git a/node/anti_double_mining.py b/node/anti_double_mining.py index 7a119860d..c543f070d 100644 --- a/node/anti_double_mining.py +++ b/node/anti_double_mining.py @@ -157,7 +157,7 @@ def detect_duplicate_identities( "SELECT miner_pk FROM epoch_enroll WHERE epoch = ?", (epoch,) ) - enrolled = cursor.fetchall() + enrolled = cursor.fetchall() # fetchall-ok: bounded-by-schema if enrolled: rows = [] @@ -207,7 +207,7 @@ def detect_duplicate_identities( WHERE ts_ok >= ? AND ts_ok <= ? ORDER BY device_arch, entropy_score DESC """, (epoch_start_ts, epoch_end_ts)) - rows = cursor.fetchall() + rows = cursor.fetchall() # fetchall-ok: bounded-by-schema # Group miners by machine identity identity_map: Dict[str, List[Tuple[str, Dict]]] = {} # identity_hash -> [(miner_id, attestation_data)] @@ -330,7 +330,7 @@ def select_representative_miner( ORDER BY entropy_score DESC, ts_ok DESC, miner ASC """, miner_ids) - rows = cursor.fetchall() + rows = cursor.fetchall() # fetchall-ok: bounded-by-schema if not rows: # Fallback: return first miner ID @@ -364,7 +364,7 @@ def get_epoch_miner_groups( "SELECT miner_pk FROM epoch_enroll WHERE epoch = ?", (epoch,) ) - enrolled = cursor.fetchall() + enrolled = cursor.fetchall() # fetchall-ok: bounded-by-schema if enrolled: # Build miner list from epoch_enroll; look up arch + fingerprint history. @@ -404,7 +404,7 @@ def get_epoch_miner_groups( FROM miner_attest_recent WHERE ts_ok >= ? AND ts_ok <= ? """, (epoch_start_ts, epoch_end_ts)) - rows = cursor.fetchall() + rows = cursor.fetchall() # fetchall-ok: bounded-by-schema # Group by machine identity groups: Dict[str, List[str]] = {} @@ -436,7 +436,7 @@ def _get_epoch_enrolled_weights(conn: sqlite3.Connection, epoch: int) -> Dict[st multiplier path. """ try: - cols = conn.execute("PRAGMA table_info(epoch_enroll)").fetchall() + cols = conn.execute("PRAGMA table_info(epoch_enroll)").fetchall() # fetchall-ok: pragma-result except sqlite3.Error: return {} @@ -447,7 +447,7 @@ def _get_epoch_enrolled_weights(conn: sqlite3.Connection, epoch: int) -> Dict[st rows = conn.execute( "SELECT miner_pk, weight FROM epoch_enroll WHERE epoch = ?", (epoch,), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema except sqlite3.Error: return {} diff --git a/node/bcos_routes.py b/node/bcos_routes.py index a8e7f09ec..542321424 100644 --- a/node/bcos_routes.py +++ b/node/bcos_routes.py @@ -541,7 +541,7 @@ def bcos_directory(): query += " ORDER BY created_at DESC LIMIT ? OFFSET ?" params.extend([limit, offset]) - rows = conn.execute(query, params).fetchall() + rows = conn.execute(query, params).fetchall() # fetchall-ok: bounded-by-schema total = conn.execute( "SELECT COUNT(*) FROM bcos_attestations" ).fetchone()[0] diff --git a/node/beacon_anchor.py b/node/beacon_anchor.py index 47327f437..784bfd9a8 100644 --- a/node/beacon_anchor.py +++ b/node/beacon_anchor.py @@ -76,7 +76,7 @@ def _ensure_payload_hash_version_column(conn: sqlite3.Connection): """ columns = { row[1] - for row in conn.execute("PRAGMA table_info(beacon_envelopes)").fetchall() + for row in conn.execute("PRAGMA table_info(beacon_envelopes)").fetchall() # fetchall-ok: pragma-result } if "payload_hash_version" not in columns: conn.execute( @@ -233,7 +233,7 @@ def compute_beacon_digest(db_path=DB_PATH) -> dict: rows = conn.execute( "SELECT id, payload_hash, payload_hash_version, created_at FROM beacon_envelopes " "WHERE anchored = 0 ORDER BY id ASC" - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema if not rows: return { @@ -302,7 +302,7 @@ def get_recent_envelopes(limit=50, offset=0, db_path=DB_PATH) -> list: "SELECT id, agent_id, kind, nonce, payload_hash, payload_hash_version, anchored, created_at " "FROM beacon_envelopes ORDER BY created_at DESC LIMIT ? OFFSET ?", (limit, offset) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema return [dict(r) for r in rows] diff --git a/node/beacon_api.py b/node/beacon_api.py index 6bbd12dc9..8f60c9271 100644 --- a/node/beacon_api.py +++ b/node/beacon_api.py @@ -309,7 +309,7 @@ def get_agents(): db = get_db() rows = db.execute( "SELECT agent_id, pubkey_hex, name, status, created_at, updated_at FROM relay_agents ORDER BY created_at DESC" - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema agents = [] for row in rows: @@ -544,13 +544,13 @@ def beacon_atlas(): WHERE status = ? ORDER BY created_at DESC""", (status_filter,) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema else: rows = db.execute( """SELECT agent_id, pubkey_hex, name, status, coinbase_address, created_at, updated_at FROM relay_agents ORDER BY created_at DESC""" - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema agents = [] for row in rows: @@ -592,7 +592,7 @@ def get_contracts(): db = get_db() rows = db.execute( "SELECT * FROM beacon_contracts ORDER BY created_at DESC" - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema contracts = [] for row in rows: @@ -821,7 +821,7 @@ def get_bounties(): db = get_db() rows = db.execute( "SELECT * FROM beacon_bounties WHERE state = 'open' ORDER BY reward_rtc DESC" - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema bounties = [] for row in rows: @@ -1078,7 +1078,7 @@ def get_reputation(): return jsonify({'error': 'Unauthorized'}), 401 try: db = get_db() - rows = db.execute("SELECT * FROM beacon_reputation ORDER BY score DESC").fetchall() + rows = db.execute("SELECT * FROM beacon_reputation ORDER BY score DESC").fetchall() # fetchall-ok: bounded-by-schema reputations = [] for row in rows: diff --git a/node/beacon_identity.py b/node/beacon_identity.py index 997433041..5e06af78f 100644 --- a/node/beacon_identity.py +++ b/node/beacon_identity.py @@ -122,7 +122,7 @@ def load_all_keys(db_path: str = DB_PATH) -> List[Dict[str, Any]]: conn.row_factory = sqlite3.Row rows = conn.execute( "SELECT * FROM beacon_known_keys ORDER BY first_seen ASC" - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema return [dict(r) for r in rows] @@ -256,7 +256,7 @@ def expire_old_keys( rows = conn.execute( "SELECT agent_id FROM beacon_known_keys WHERE last_seen < ? AND revoked = 0", (cutoff,), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema expired_ids = [r[0] for r in rows] if not dry_run and expired_ids: placeholders = ",".join("?" for _ in expired_ids) diff --git a/node/beacon_x402.py b/node/beacon_x402.py index 4f8f570f7..04ce7500c 100644 --- a/node/beacon_x402.py +++ b/node/beacon_x402.py @@ -69,7 +69,7 @@ def _run_migrations(db_path): # Add coinbase_address to relay_agents if missing cursor = conn.execute("PRAGMA table_info(relay_agents)") existing_cols = {row[1] if isinstance(row, tuple) else row["name"] - for row in cursor.fetchall()} + for row in cursor.fetchall()} # fetchall-ok: pragma-result for sql in RELAY_MIGRATION_SQL: col_name = sql.split("ADD COLUMN ")[1].split()[0] @@ -338,7 +338,7 @@ def premium_reputation(): try: rows = db.execute( "SELECT * FROM reputation ORDER BY score DESC" - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema reputation = [dict(r) for r in rows] except sqlite3.OperationalError: reputation = [] @@ -366,7 +366,7 @@ def premium_contracts_export(): try: rows = db.execute( "SELECT * FROM contracts ORDER BY created_at DESC" - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema except sqlite3.OperationalError: rows = [] @@ -407,7 +407,7 @@ def x402_beacon_payments(): try: rows = db.execute( "SELECT * FROM x402_beacon_payments ORDER BY created_at DESC LIMIT 50" - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema except sqlite3.OperationalError: rows = [] diff --git a/node/bottube_feed_routes.py b/node/bottube_feed_routes.py index 21c43f103..77f406386 100644 --- a/node/bottube_feed_routes.py +++ b/node/bottube_feed_routes.py @@ -125,7 +125,7 @@ def _fetch_videos( params.append(limit) cursor_obj.execute(query, params) - rows = cursor_obj.fetchall() + rows = cursor_obj.fetchall() # fetchall-ok: bounded-by-schema conn.close() videos = [] diff --git a/node/bridge_api.py b/node/bridge_api.py index 2df704c9a..3323db496 100644 --- a/node/bridge_api.py +++ b/node/bridge_api.py @@ -544,7 +544,7 @@ def list_bridge_transfers( query += " ORDER BY id DESC LIMIT ?" params.append(min(limit, 500)) - rows = cursor.execute(query, params).fetchall() + rows = cursor.execute(query, params).fetchall() # fetchall-ok: bounded-by-schema return [ { diff --git a/node/claims_eligibility.py b/node/claims_eligibility.py index ffef1a13d..8ac062084 100644 --- a/node/claims_eligibility.py +++ b/node/claims_eligibility.py @@ -672,7 +672,7 @@ def get_eligible_epochs( limit )) - epochs = [row[0] for row in cursor.fetchall() if row[0] >= 0] + epochs = [row[0] for row in cursor.fetchall() if row[0] >= 0] # fetchall-ok: bounded-by-schema except sqlite3.Error as e: print(f"[CLAIMS] Error getting eligible epochs: {e}") return { diff --git a/node/claims_settlement.py b/node/claims_settlement.py index dd72bfd0e..49243cab0 100644 --- a/node/claims_settlement.py +++ b/node/claims_settlement.py @@ -83,7 +83,7 @@ def get_pending_claims( """, (max_claims,)) claims = [] - for row in cursor.fetchall(): + for row in cursor.fetchall(): # fetchall-ok: bounded-by-schema claims.append({ "claim_id": row["claim_id"], "miner_id": row["miner_id"], @@ -128,7 +128,7 @@ def get_verifying_claims( """, (threshold, _VERIFYING_CLAIMS_LIMIT)) claims = [] - for row in cursor.fetchall(): + for row in cursor.fetchall(): # fetchall-ok: bounded-by-schema claims.append({ "claim_id": row["claim_id"], "miner_id": row["miner_id"], @@ -413,7 +413,7 @@ def reserve_claims_for_settlement( WHERE status = 'approved' ORDER BY submitted_at ASC LIMIT ? - """, (max_claims,)).fetchall() + """, (max_claims,)).fetchall() # fetchall-ok: bounded-by-schema claim_ids = [row["claim_id"] for row in rows] if not claim_ids: @@ -440,7 +440,7 @@ def reserve_claims_for_settlement( AND settlement_batch = ? ORDER BY submitted_at ASC LIMIT ? - """, (batch_id, max_claims)).fetchall() + """, (batch_id, max_claims)).fetchall() # fetchall-ok: bounded-by-schema conn.commit() except Exception: diff --git a/node/claims_submission.py b/node/claims_submission.py index ff84e1173..721e9914d 100644 --- a/node/claims_submission.py +++ b/node/claims_submission.py @@ -113,7 +113,7 @@ def get_registered_claim_public_key(db_path: str, miner_id: str) -> Optional[str for table, miner_column in candidate_tables: try: cursor.execute(f"PRAGMA table_info({table})") - columns = {row[1] for row in cursor.fetchall()} + columns = {row[1] for row in cursor.fetchall()} # fetchall-ok: pragma-result except sqlite3.Error: continue @@ -637,7 +637,7 @@ def get_claim_history( claims = [] total_claimed = 0 - for row in cursor.fetchall(): + for row in cursor.fetchall(): # fetchall-ok: bounded-by-schema claims.append({ "claim_id": row["claim_id"], "epoch": row["epoch"], diff --git a/node/coalition.py b/node/coalition.py index f972f72ec..6c8f259f2 100644 --- a/node/coalition.py +++ b/node/coalition.py @@ -319,7 +319,7 @@ def _settle_expired_proposals(db_path: str): "JOIN coalitions c ON p.coalition_id = c.id " "WHERE p.status = ? AND p.expires_at <= ? AND c.status = ?", (PROPOSAL_STATUS_ACTIVE, now, COALITION_STATUS_ACTIVE) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema for (pid, v_for, v_against, cid) in active: total_votes = v_for + v_against @@ -871,12 +871,12 @@ def list_coalitions(): "SELECT * FROM coalitions WHERE status = ? " "ORDER BY created_at DESC LIMIT ? OFFSET ?", (status_filter, limit, offset) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema else: rows = conn.execute( "SELECT * FROM coalitions ORDER BY created_at DESC LIMIT ? OFFSET ?", (limit, offset) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema coalitions = [dict(r) for r in rows] # Enrich with member count @@ -912,7 +912,7 @@ def get_coalition(coalition_id: int): "SELECT miner_id, joined_at, status FROM coalition_members " "WHERE coalition_id = ? ORDER BY joined_at", (coalition_id,) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema active_proposals = conn.execute( "SELECT COUNT(*) FROM coalition_proposals WHERE coalition_id = ? AND status = ?", @@ -957,13 +957,13 @@ def get_coalition_proposals(coalition_id: int): "SELECT * FROM coalition_proposals WHERE coalition_id = ? AND status = ? " "ORDER BY created_at DESC LIMIT ? OFFSET ?", (coalition_id, status_filter, limit, offset) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema else: rows = conn.execute( "SELECT * FROM coalition_proposals WHERE coalition_id = ? " "ORDER BY created_at DESC LIMIT ? OFFSET ?", (coalition_id, limit, offset) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema proposals = [dict(r) for r in rows] # Enrich active proposals with quorum info diff --git a/node/ergo_miner_anchor.py b/node/ergo_miner_anchor.py index bddfef6f0..945fc2364 100644 --- a/node/ergo_miner_anchor.py +++ b/node/ergo_miner_anchor.py @@ -35,7 +35,7 @@ def get_recent_miners(self, limit=10): conn.row_factory = sqlite3.Row cur = conn.cursor() cur.execute("SELECT miner, device_arch, ts_ok FROM miner_attest_recent ORDER BY ts_ok DESC LIMIT ?", (limit,)) - miners = [dict(row) for row in cur.fetchall()] + miners = [dict(row) for row in cur.fetchall()] # fetchall-ok: bounded-by-schema conn.close() return miners diff --git a/node/ergo_raw_tx.py b/node/ergo_raw_tx.py index f4821c6e5..5b4b55dd8 100644 --- a/node/ergo_raw_tx.py +++ b/node/ergo_raw_tx.py @@ -74,7 +74,7 @@ def get_recent_miners(self, limit=10): conn.row_factory = sqlite3.Row cur = conn.cursor() cur.execute("SELECT miner, device_arch, ts_ok FROM miner_attest_recent ORDER BY ts_ok DESC LIMIT ?", (limit,)) - miners = [dict(row) for row in cur.fetchall()] + miners = [dict(row) for row in cur.fetchall()] # fetchall-ok: bounded-by-schema conn.close() return miners diff --git a/node/governance.py b/node/governance.py index 0de1b8209..1ca1f7834 100644 --- a/node/governance.py +++ b/node/governance.py @@ -231,7 +231,7 @@ def _settle_expired_proposals(db_path: str): "SELECT id, votes_for, votes_against, votes_abstain FROM governance_proposals " "WHERE status = ? AND expires_at <= ?", (STATUS_ACTIVE, now) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema for (pid, v_for, v_against, v_abstain) in active: total_votes = v_for + v_against + v_abstain @@ -469,12 +469,12 @@ def list_proposals(): "SELECT * FROM governance_proposals WHERE status = ? " "ORDER BY created_at DESC LIMIT ? OFFSET ?", (status_filter, limit, offset) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema else: rows = conn.execute( "SELECT * FROM governance_proposals ORDER BY created_at DESC LIMIT ? OFFSET ?", (limit, offset) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema proposals = [dict(r) for r in rows] except Exception as e: @@ -504,7 +504,7 @@ def get_proposal(proposal_id: int): "SELECT miner_id, vote, weight, voted_at FROM governance_votes " "WHERE proposal_id = ? ORDER BY voted_at DESC", (proposal_id,) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema except Exception as e: log.error("Get proposal error: %s", e) diff --git a/node/gpu_render_endpoints.py b/node/gpu_render_endpoints.py index 348c90b0c..e2cd40a07 100644 --- a/node/gpu_render_endpoints.py +++ b/node/gpu_render_endpoints.py @@ -61,7 +61,7 @@ def _database_error_response(): def _ensure_escrow_secret_column(db): """Best-effort migration for older DBs.""" try: - cols = {row[1] for row in db.execute("PRAGMA table_info(render_escrow)").fetchall()} + cols = {row[1] for row in db.execute("PRAGMA table_info(render_escrow)").fetchall()} # fetchall-ok: pragma-result if "escrow_secret_hash" not in cols: db.execute("ALTER TABLE render_escrow ADD COLUMN escrow_secret_hash TEXT") db.commit() diff --git a/node/gpu_render_protocol.py b/node/gpu_render_protocol.py index 57532a9ae..fb554754a 100644 --- a/node/gpu_render_protocol.py +++ b/node/gpu_render_protocol.py @@ -149,7 +149,7 @@ def _init_db(self): def _ensure_escrow_secret_column(self, conn): """Add escrow secret storage for databases created before this guard.""" - cols = {row[1] for row in conn.execute("PRAGMA table_info(render_escrow)").fetchall()} + cols = {row[1] for row in conn.execute("PRAGMA table_info(render_escrow)").fetchall()} # fetchall-ok: pragma-result if "escrow_secret_hash" not in cols: conn.execute("ALTER TABLE render_escrow ADD COLUMN escrow_secret_hash TEXT") @@ -269,7 +269,7 @@ def list_gpu_nodes(self, job_type=None, device_arch=None) -> list: query += " AND device_arch=?" params.append(device_arch) query += " ORDER BY benchmark_score DESC" - rows = conn.execute(query, params).fetchall() + rows = conn.execute(query, params).fetchall() # fetchall-ok: bounded-by-schema return [dict(r) for r in rows] finally: conn.close() @@ -415,7 +415,7 @@ def get_fair_market_rates(self, job_type=None) -> dict: try: nodes = conn.execute( "SELECT * FROM gpu_attestations WHERE status='active'" - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema if not nodes: return {"error": "No active GPU nodes", "rates": {}} diff --git a/node/hall_of_rust.py b/node/hall_of_rust.py index ea149ecf3..21bf1f31a 100644 --- a/node/hall_of_rust.py +++ b/node/hall_of_rust.py @@ -323,7 +323,7 @@ def rust_leaderboard(): LIMIT ? """, (limit,)) - rows = c.fetchall() + rows = c.fetchall() # fetchall-ok: bounded-by-schema conn.close() leaderboard = [] @@ -573,7 +573,7 @@ def api_hall_of_fame_leaderboard(): """, params + [limit], ) - rows = c.fetchall() + rows = c.fetchall() # fetchall-ok: bounded-by-schema conn.close() leaderboard = [] @@ -653,7 +653,7 @@ def api_hall_of_fame_machine(): 'rust_score': machine.get('rust_score'), 'samples': int(r['attestations'] or 0), } - for r in c.fetchall() + for r in c.fetchall() # fetchall-ok: bounded-by-schema ] elif _table_exists(c, 'rust_score_history'): c.execute( @@ -675,7 +675,7 @@ def api_hall_of_fame_machine(): 'samples': int(r['samples'] or 0), 'attestations': int(r['samples'] or 0), } - for r in c.fetchall() + for r in c.fetchall() # fetchall-ok: bounded-by-schema ] # Reward participation (best-effort) from enrollments + pending ledger credits. @@ -824,7 +824,7 @@ def fleet_breakdown(): """) breakdown = [] - for row in c.fetchall(): + for row in c.fetchall(): # fetchall-ok: bounded-by-schema breakdown.append({ 'architecture': row[0], 'count': row[1], @@ -867,7 +867,7 @@ def hall_timeline(): """) timeline = [] - for row in c.fetchall(): + for row in c.fetchall(): # fetchall-ok: bounded-by-schema timeline.append({ 'date': row[0], 'machines_joined': row[1], diff --git a/node/hardware_binding_v2.py b/node/hardware_binding_v2.py index e03e891e1..894807320 100755 --- a/node/hardware_binding_v2.py +++ b/node/hardware_binding_v2.py @@ -190,7 +190,7 @@ def check_entropy_collision(entropy_profile: Dict, exclude_serial: str = None) - c = conn.cursor() c.execute('SELECT serial_hash, entropy_profile FROM hardware_bindings_v2') - for row in c.fetchall(): + for row in c.fetchall(): # fetchall-ok: bounded-by-schema serial_hash, stored_json = row if serial_hash == exclude_serial: continue diff --git a/node/hardware_fingerprint_replay.py b/node/hardware_fingerprint_replay.py index 8d756a3ec..2776a605a 100644 --- a/node/hardware_fingerprint_replay.py +++ b/node/hardware_fingerprint_replay.py @@ -263,7 +263,7 @@ def check_fingerprint_replay( LIMIT 10 ''', (fingerprint_hash, window_start)) - recent_submissions = c.fetchall() + recent_submissions = c.fetchall() # fetchall-ok: bounded-by-schema if recent_submissions: for prev_wallet, prev_miner, prev_time, prev_nonce in recent_submissions: @@ -344,7 +344,7 @@ def check_entropy_collision( LIMIT 5 ''', (entropy_profile_hash, window_start, wallet_address)) - collisions = c.fetchall() + collisions = c.fetchall() # fetchall-ok: bounded-by-schema if collisions: collision_wallets = [ @@ -551,7 +551,7 @@ def detect_fingerprint_anomalies( LIMIT 20 ''', (miner_id,)) - history = c.fetchall() + history = c.fetchall() # fetchall-ok: bounded-by-schema if len(history) < 2: return False, [] # Not enough history diff --git a/node/lock_ledger.py b/node/lock_ledger.py index 25b210fc9..eab99186b 100644 --- a/node/lock_ledger.py +++ b/node/lock_ledger.py @@ -477,7 +477,7 @@ def get_locks_by_miner( query += " ORDER BY id DESC LIMIT ?" params.append(min(limit, 500)) - rows = cursor.execute(query, params).fetchall() + rows = cursor.execute(query, params).fetchall() # fetchall-ok: bounded-by-schema return [ LockEntry( @@ -535,7 +535,7 @@ def get_pending_unlocks( query += " ORDER BY unlock_at ASC LIMIT ?" params.append(min(limit, 500)) - rows = cursor.execute(query, params).fetchall() + rows = cursor.execute(query, params).fetchall() # fetchall-ok: bounded-by-schema return [ LockEntry( @@ -584,7 +584,7 @@ def get_miner_locked_balance( FROM lock_ledger WHERE miner_id = ? AND status = 'locked' GROUP BY lock_type - """, (miner_id,)).fetchall() + """, (miner_id,)).fetchall() # fetchall-ok: bounded-by-schema breakdown = { r[0]: {"amount_rtc": r[1] / LOCK_UNIT, "count": r[2]} diff --git a/node/machine_passport.py b/node/machine_passport.py index 67c37aa63..c6bb60110 100644 --- a/node/machine_passport.py +++ b/node/machine_passport.py @@ -447,7 +447,7 @@ def list_passports(self, owner_miner_id: Optional[str] = None, WHERE {where_clause} ORDER BY created_at DESC LIMIT ? OFFSET ? - """, params).fetchall() + """, params).fetchall() # fetchall-ok: bounded-by-schema return [MachinePassport( machine_id=row['machine_id'], @@ -492,7 +492,7 @@ def get_repair_log(self, machine_id: str) -> List[Dict]: SELECT * FROM passport_repair_log WHERE machine_id = ? ORDER BY repair_date DESC - """, (machine_id,)).fetchall() + """, (machine_id,)).fetchall() # fetchall-ok: bounded-by-schema return [dict(row) for row in rows] @@ -526,7 +526,7 @@ def get_attestation_history(self, machine_id: str) -> List[Dict]: SELECT * FROM passport_attestation_history WHERE machine_id = ? ORDER BY attestation_ts DESC - """, (machine_id,)).fetchall() + """, (machine_id,)).fetchall() # fetchall-ok: bounded-by-schema return [dict(row) for row in rows] @@ -564,7 +564,7 @@ def get_benchmark_signatures(self, machine_id: str) -> List[Dict]: SELECT * FROM passport_benchmark_signatures WHERE machine_id = ? ORDER BY benchmark_ts DESC - """, (machine_id,)).fetchall() + """, (machine_id,)).fetchall() # fetchall-ok: bounded-by-schema return [dict(row) for row in rows] @@ -598,7 +598,7 @@ def get_lineage_notes(self, machine_id: str) -> List[Dict]: SELECT * FROM passport_lineage_notes WHERE machine_id = ? ORDER BY lineage_ts DESC - """, (machine_id,)).fetchall() + """, (machine_id,)).fetchall() # fetchall-ok: bounded-by-schema return [dict(row) for row in rows] diff --git a/node/migrate_machine_passport.py b/node/migrate_machine_passport.py index af8251fef..c32d0361e 100644 --- a/node/migrate_machine_passport.py +++ b/node/migrate_machine_passport.py @@ -46,7 +46,7 @@ def check_existing_schema(db_path: str) -> dict: cursor = conn.execute( "SELECT name FROM sqlite_master WHERE type='table'" ) - result['tables'] = [row[0] for row in cursor.fetchall()] + result['tables'] = [row[0] for row in cursor.fetchall()] # fetchall-ok: bounded-by-schema result['machine_passports'] = 'machine_passports' in result['tables'] result['passport_repair_log'] = 'passport_repair_log' in result['tables'] diff --git a/node/payout_worker.py b/node/payout_worker.py index 4d7808294..e4c06074d 100755 --- a/node/payout_worker.py +++ b/node/payout_worker.py @@ -44,7 +44,7 @@ def get_pending_withdrawals(self, limit: int = BATCH_SIZE) -> List[Dict]: WHERE status = 'pending' ORDER BY created_at ASC LIMIT ? - """, (limit,)).fetchall() + """, (limit,)).fetchall() # fetchall-ok: bounded-by-schema withdrawals = [] for row in rows: @@ -106,7 +106,7 @@ def reconcile_broadcast_withdrawals(self): WHERE status = 'processing' AND tx_hash IS NOT NULL AND tx_hash != '' - """).fetchall() + """).fetchall() # fetchall-ok: bounded-by-schema for withdrawal_id, tx_hash in rows: chain_status = self.lookup_withdrawal_status(tx_hash) @@ -299,7 +299,7 @@ def recover_orphans(self): FROM withdrawals WHERE status = 'processing' AND (tx_hash IS NULL OR tx_hash = '') - """).fetchall() + """).fetchall() # fetchall-ok: bounded-by-schema for (withdrawal_id,) in rows: logger.warning( @@ -397,7 +397,7 @@ def cleanup_old_withdrawals(self): SELECT withdrawal_id, miner_pk, amount, destination, tx_hash, processed_at FROM withdrawals WHERE status = 'completed' AND processed_at < ? - """, (cutoff,)).fetchall() + """, (cutoff,)).fetchall() # fetchall-ok: bounded-by-schema archive_dir = os.path.join(os.path.dirname(self.db_path), "archives") os.makedirs(archive_dir, exist_ok=True) diff --git a/node/proposer_duty_calendar.py b/node/proposer_duty_calendar.py index 194f03e86..5d0b349e3 100644 --- a/node/proposer_duty_calendar.py +++ b/node/proposer_duty_calendar.py @@ -92,7 +92,7 @@ def load_vote_history( ORDER BY epoch DESC, ts DESC """, (lower_bound, int(current_epoch)), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema except sqlite3.Error: return [] diff --git a/node/rewards_implementation_rip200.py b/node/rewards_implementation_rip200.py index f43c6aef6..bbf551cac 100644 --- a/node/rewards_implementation_rip200.py +++ b/node/rewards_implementation_rip200.py @@ -359,7 +359,7 @@ def get_all_balances(): with sqlite3.connect(DB_PATH) as db: rows = db.execute( "SELECT miner_id, amount_i64 FROM balances WHERE amount_i64 > 0 ORDER BY amount_i64 DESC" - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema balances = [ { diff --git a/node/rip_200_round_robin_1cpu1vote.py b/node/rip_200_round_robin_1cpu1vote.py index 082f0d538..5483ccee5 100644 --- a/node/rip_200_round_robin_1cpu1vote.py +++ b/node/rip_200_round_robin_1cpu1vote.py @@ -496,7 +496,7 @@ def get_attested_miners(db_path: str, current_ts: int) -> List[Tuple[str, str]]: ORDER BY miner ASC """, (current_ts - ATTESTATION_TTL,)) - return cursor.fetchall() + return cursor.fetchall() # fetchall-ok: bounded-by-schema def get_round_robin_producer(slot: int, attested_miners: List[Tuple[str, str]]) -> str: @@ -633,7 +633,7 @@ def calculate_epoch_rewards_time_aged( cursor = conn.cursor() # Schema compatibility: detect whether fingerprint_checks_json column exists - cols = cursor.execute("PRAGMA table_info(miner_attest_recent)").fetchall() + cols = cursor.execute("PRAGMA table_info(miner_attest_recent)").fetchall() # fetchall-ok: pragma-result has_checks_col = any(col[1] == 'fingerprint_checks_json' for col in cols) has_warthog_col = any(col[1] == 'warthog_bonus' for col in cols) wart_sql = ", COALESCE(warthog_bonus, 1.0) " if has_warthog_col else ", 1.0 " @@ -644,7 +644,7 @@ def calculate_epoch_rewards_time_aged( "SELECT miner_pk, weight FROM epoch_enroll WHERE epoch = ?", (epoch,) ) - enrolled = cursor.fetchall() + enrolled = cursor.fetchall() # fetchall-ok: bounded-by-schema except sqlite3.Error: enrolled = [] @@ -705,7 +705,7 @@ def calculate_epoch_rewards_time_aged( FROM miner_attest_recent WHERE ts_ok >= ? AND ts_ok <= ? """, (epoch_start_ts - ATTESTATION_TTL, epoch_end_ts)) - epoch_miners = cursor.fetchall() + epoch_miners = cursor.fetchall() # fetchall-ok: bounded-by-schema if not epoch_miners: return {} diff --git a/node/rip_200_round_robin_1cpu1vote_v2.py b/node/rip_200_round_robin_1cpu1vote_v2.py index 656a8c623..7b4189d8f 100644 --- a/node/rip_200_round_robin_1cpu1vote_v2.py +++ b/node/rip_200_round_robin_1cpu1vote_v2.py @@ -272,7 +272,7 @@ def get_attested_miners(db_path: str, current_ts: int) -> List[Tuple[str, str, D """, (current_ts - ATTESTATION_TTL,)) results = [] - for row in cursor.fetchall(): + for row in cursor.fetchall(): # fetchall-ok: bounded-by-schema miner_id, arch, family, model, year = row device_info = { "arch": arch or "modern_x86", @@ -318,7 +318,7 @@ def calculate_epoch_rewards_v2( WHERE ts_ok >= ? AND ts_ok <= ? """, (epoch_start_ts - ATTESTATION_TTL, epoch_end_ts)) - epoch_miners = cursor.fetchall() + epoch_miners = cursor.fetchall() # fetchall-ok: bounded-by-schema if not epoch_miners: return {} diff --git a/node/rip_node_sync.py b/node/rip_node_sync.py index 22bdef8e3..c9d6b2684 100644 --- a/node/rip_node_sync.py +++ b/node/rip_node_sync.py @@ -60,7 +60,7 @@ def get_local_attestations() -> Set[str]: with sqlite3.connect(DB_PATH) as conn: cursor = conn.cursor() cursor.execute("SELECT miner FROM miner_attest_recent") - return set(row[0] for row in cursor.fetchall()) + return set(row[0] for row in cursor.fetchall()) # fetchall-ok: bounded-by-schema except Exception as e: logger.error(f"Failed to read local DB: {e}") return set() diff --git a/node/rom_clustering_server.py b/node/rom_clustering_server.py index 8b67347e4..8581548b5 100644 --- a/node/rom_clustering_server.py +++ b/node/rom_clustering_server.py @@ -82,7 +82,7 @@ def _ensure_rom_cluster_unique_index(conn: sqlite3.Connection): GROUP BY rom_hash, hash_type HAVING COUNT(*) > 1 """) - duplicate_keys = [(row[0], row[1]) for row in cur.fetchall()] + duplicate_keys = [(row[0], row[1]) for row in cur.fetchall()] # fetchall-ok: bounded-by-schema for rom_hash, hash_type in duplicate_keys: cur.execute(""" @@ -92,7 +92,7 @@ def _ensure_rom_cluster_unique_index(conn: sqlite3.Connection): WHERE rom_hash = ? AND hash_type = ? ORDER BY last_updated DESC, cluster_size DESC, cluster_id DESC """, (rom_hash, hash_type)) - rows = cur.fetchall() + rows = cur.fetchall() # fetchall-ok: bounded-by-schema keep = rows[0] keep_id = keep[0] duplicate_ids = [row[0] for row in rows if row[0] != keep_id] @@ -232,7 +232,7 @@ def process_rom_report( WHERE rom_hash = ? AND miner_id != ? """, (rom_hash_lower, miner_id)) - other_miners = [row[0] for row in cur.fetchall()] + other_miners = [row[0] for row in cur.fetchall()] # fetchall-ok: bounded-by-schema all_miners = [miner_id] + other_miners if len(all_miners) >= self._effective_cluster_threshold(): @@ -314,7 +314,7 @@ def get_clusters(self) -> List[Dict]: import json clusters = [] - for row in cur.fetchall(): + for row in cur.fetchall(): # fetchall-ok: bounded-by-schema clusters.append({ "rom_hash": row[0], "hash_type": row[1], @@ -342,7 +342,7 @@ def get_flagged_miners(self) -> List[Dict]: """) flagged = [] - for row in cur.fetchall(): + for row in cur.fetchall(): # fetchall-ok: bounded-by-schema flagged.append({ "miner_id": row[0], "reason": row[1], diff --git a/node/rustchain_bft_consensus.py b/node/rustchain_bft_consensus.py index 7f4b91c92..d3c927a6e 100644 --- a/node/rustchain_bft_consensus.py +++ b/node/rustchain_bft_consensus.py @@ -231,7 +231,7 @@ def _restore_committed_state(self): with sqlite3.connect(self.db_path) as conn: rows = conn.execute( "SELECT epoch, view FROM bft_committed_epochs" - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema for epoch, view in rows: self.committed_epochs.add(epoch) if view > self.current_view: diff --git a/node/rustchain_block_producer.py b/node/rustchain_block_producer.py index d208f87af..0b3d537a8 100644 --- a/node/rustchain_block_producer.py +++ b/node/rustchain_block_producer.py @@ -264,7 +264,7 @@ def get_attested_miners(self, current_ts: int) -> List[Tuple[str, str, Dict]]: """, (current_ts - ATTESTATION_TTL,)) results = [] - for row in cursor.fetchall(): + for row in cursor.fetchall(): # fetchall-ok: bounded-by-schema device_info = { "arch": row["device_arch"] or "modern_x86", "family": row["device_family"] or "", @@ -435,7 +435,7 @@ def get_state_root(self) -> str: """) state = [] - for row in cursor.fetchall(): + for row in cursor.fetchall(): # fetchall-ok: bounded-by-schema state.append({ "wallet": row["wallet"], "balance": row["balance_urtc"], @@ -466,7 +466,7 @@ def get_attestations_for_block(self) -> List[Dict]: "family": row["device_family"], "timestamp": row["ts_ok"] } - for row in cursor.fetchall() + for row in cursor.fetchall() # fetchall-ok: bounded-by-schema ] def produce_block(self, slot: int = None) -> Optional[Block]: @@ -834,7 +834,7 @@ def _blocks_table_missing(exc: sqlite3.Error) -> bool: def _sqlite_table_columns(conn: sqlite3.Connection, table: str) -> set: - return {row[1] for row in conn.execute(f"PRAGMA table_info({table})").fetchall()} + return {row[1] for row in conn.execute(f"PRAGMA table_info({table})").fetchall()} # fetchall-ok: pragma-result def _ensure_block_randomness_columns(conn: sqlite3.Connection): @@ -1018,7 +1018,7 @@ def get_blocks_batch(): rows = cursor.execute( f"SELECT * FROM blocks WHERE height IN ({placeholders})", height_misses, - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema except sqlite3.Error as exc: if _blocks_table_missing(exc): logger.debug("Block batch height lookup skipped: %s", exc) @@ -1038,7 +1038,7 @@ def get_blocks_batch(): rows = cursor.execute( f"SELECT * FROM blocks WHERE block_hash IN ({placeholders})", hash_misses, - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema except sqlite3.Error as exc: if _blocks_table_missing(exc): logger.debug("Block batch hash lookup skipped: %s", exc) diff --git a/node/rustchain_dashboard.py b/node/rustchain_dashboard.py index 4c54ac550..668741572 100644 --- a/node/rustchain_dashboard.py +++ b/node/rustchain_dashboard.py @@ -501,7 +501,7 @@ def api_stats(): GROUP BY e.miner_pk ORDER BY e.weight DESC, b.balance_rtc DESC LIMIT 50 - """, (epoch_data['epoch'],)).fetchall() + """, (epoch_data['epoch'],)).fetchall() # fetchall-ok: bounded-by-schema active_miners = [] for miner in miners: @@ -554,7 +554,7 @@ def api_stats(): GROUP BY epoch ORDER BY epoch DESC LIMIT 10 - """).fetchall() + """).fetchall() # fetchall-ok: bounded-by-schema recent_blocks = [] for idx, activity in enumerate(recent_activity): diff --git a/node/rustchain_ergo_anchor.py b/node/rustchain_ergo_anchor.py index 3179625c0..e8e593917 100644 --- a/node/rustchain_ergo_anchor.py +++ b/node/rustchain_ergo_anchor.py @@ -465,7 +465,7 @@ def _monitor_loop(self, interval: int): WHERE status IN ('pending', 'confirming') """) - for row in cursor.fetchall(): + for row in cursor.fetchall(): # fetchall-ok: bounded-by-schema tx_id = row["ergo_tx_id"] confs, status = self.update_anchor_status(tx_id) logger.debug(f"Anchor {tx_id[:16]}... = {confs} confirmations ({status})") @@ -553,7 +553,7 @@ def list_anchors(): LIMIT ? OFFSET ? """, (limit, offset)) - anchors = [dict(row) for row in cursor.fetchall()] + anchors = [dict(row) for row in cursor.fetchall()] # fetchall-ok: bounded-by-schema finally: conn.close() diff --git a/node/rustchain_migration.py b/node/rustchain_migration.py index a7512b665..c00b9ed37 100644 --- a/node/rustchain_migration.py +++ b/node/rustchain_migration.py @@ -120,7 +120,7 @@ def pre_flight_checks(self) -> bool: # Check tables exist cursor.execute("SELECT name FROM sqlite_master WHERE type='table'") - tables = [row[0] for row in cursor.fetchall()] + tables = [row[0] for row in cursor.fetchall()] # fetchall-ok: bounded-by-schema self.log(f"Testnet tables: {tables}") # Check miner attestations @@ -357,7 +357,7 @@ def migrate_attestation_history(self): SELECT miner, device_arch, device_family, ts_ok FROM miner_attest_recent """) - attestations = cursor.fetchall() + attestations = cursor.fetchall() # fetchall-ok: bounded-by-schema with sqlite3.connect(self.mainnet_db) as mainnet_conn: cursor = mainnet_conn.cursor() @@ -490,7 +490,7 @@ def verify_migration(self) -> bool: # Check chain metadata cursor.execute("SELECT key, value FROM chain_metadata") - metadata = dict(cursor.fetchall()) + metadata = dict(cursor.fetchall()) # fetchall-ok: bounded-by-schema self.log(f"Chain version: {metadata.get('version', 'unknown')}") self.log(f"Network: {metadata.get('network', 'unknown')}") diff --git a/node/rustchain_p2p_gossip.py b/node/rustchain_p2p_gossip.py index 757babe51..bc737f59d 100644 --- a/node/rustchain_p2p_gossip.py +++ b/node/rustchain_p2p_gossip.py @@ -672,7 +672,7 @@ def _load_state_from_db(self): rows = conn.execute(""" SELECT miner, ts_ok, device_family, device_arch, entropy_score FROM miner_attest_recent - """).fetchall() + """).fetchall() # fetchall-ok: bounded-by-schema for miner, ts_ok, family, arch, entropy in rows: self.attestation_crdt.set(miner, { "miner": miner, @@ -684,14 +684,14 @@ def _load_state_from_db(self): # Load settled epochs rows = conn.execute(""" SELECT epoch FROM epoch_state WHERE settled = 1 - """).fetchall() + """).fetchall() # fetchall-ok: bounded-by-schema for (epoch,) in rows: self.epoch_crdt.add(epoch) rows = conn.execute(""" SELECT epoch, proposal_hash, voter, vote FROM p2p_epoch_votes - """).fetchall() + """).fetchall() # fetchall-ok: bounded-by-schema for epoch, proposal_hash, voter, vote in rows: key = (epoch, proposal_hash) self._epoch_votes.setdefault(key, {})[voter] = vote @@ -1169,7 +1169,7 @@ def _handle_epoch_propose(self, msg: GossipMessage) -> Dict: cursor = conn.execute( "SELECT miner FROM miner_attest_recent" ) - attested_miners = {row[0] for row in cursor.fetchall()} + attested_miners = {row[0] for row in cursor.fetchall()} # fetchall-ok: bounded-by-schema except Exception as e: logger.error(f"Epoch {epoch}: Failed to query attested miners: {e}") return self._reject_epoch_vote(epoch, proposal, "attested_miners_query_error") diff --git a/node/rustchain_p2p_sync.py b/node/rustchain_p2p_sync.py index 68831dfd7..b9dd0df5d 100644 --- a/node/rustchain_p2p_sync.py +++ b/node/rustchain_p2p_sync.py @@ -153,7 +153,7 @@ def get_active_peers(self) -> List[str]: SELECT peer_url FROM peers WHERE is_active = 1 AND last_seen > ? - """, (int(time.time()) - 300,)).fetchall() # 5 minute timeout + """, (int(time.time()) - 300,)).fetchall() # 5 minute timeout # fetchall-ok: bounded-by-schema return [row[0] for row in rows] @@ -529,7 +529,7 @@ def get_blocks(): WHERE height >= ? ORDER BY height ASC LIMIT ? - """, (start, limit)).fetchall() + """, (start, limit)).fetchall() # fetchall-ok: bounded-by-schema blocks = [ {"height": row[0], "hash": row[1], "data": json.loads(row[2])} diff --git a/node/rustchain_p2p_sync_secure.py b/node/rustchain_p2p_sync_secure.py index bac80b3e4..74f6a3f27 100644 --- a/node/rustchain_p2p_sync_secure.py +++ b/node/rustchain_p2p_sync_secure.py @@ -411,7 +411,7 @@ def get_active_peers(self) -> List[str]: SELECT peer_url FROM peers WHERE is_active = 1 AND is_banned = 0 """) - return [row[0] for row in cursor.fetchall()] + return [row[0] for row in cursor.fetchall()] # fetchall-ok: bounded-by-schema def get_network_stats(self): """Get P2P network statistics""" @@ -540,7 +540,7 @@ def get_blocks_for_sync(self, start_height, limit=100): ORDER BY slot ASC LIMIT ? """, (start_height, limit)) - rows = cursor.fetchall() + rows = cursor.fetchall() # fetchall-ok: bounded-by-schema blocks = [] previous_hash = "0" * 64 diff --git a/node/rustchain_sync.py b/node/rustchain_sync.py index 265f8cfd0..d8d9f7541 100644 --- a/node/rustchain_sync.py +++ b/node/rustchain_sync.py @@ -64,7 +64,7 @@ def _load_table_schema(self, table_name: str) -> Optional[Dict[str, Any]]: if not self._table_exists(conn, table_name): return None - rows = conn.execute(f"PRAGMA table_info({table_name})").fetchall() + rows = conn.execute(f"PRAGMA table_info({table_name})").fetchall() # fetchall-ok: pragma-result if not rows: return None @@ -110,7 +110,7 @@ def calculate_table_hash(self, table_name: str) -> str: try: cursor = conn.cursor() cursor.execute(f"SELECT * FROM {table_name} ORDER BY {pk} ASC") - rows = cursor.fetchall() + rows = cursor.fetchall() # fetchall-ok: bounded-by-schema hasher = hashlib.sha256() for row in rows: @@ -150,7 +150,7 @@ def get_table_data(self, table_name: str, limit: int = 200, offset: int = 0) -> f"SELECT * FROM {table_name} ORDER BY {pk} ASC LIMIT ? OFFSET ?", (int(limit), int(offset)), ) - data = [dict(row) for row in cursor.fetchall()] + data = [dict(row) for row in cursor.fetchall()] # fetchall-ok: bounded-by-schema conn.close() return data diff --git a/node/rustchain_tx_handler.py b/node/rustchain_tx_handler.py index 98affd0e9..39e6b6029 100644 --- a/node/rustchain_tx_handler.py +++ b/node/rustchain_tx_handler.py @@ -129,7 +129,7 @@ def _ensure_schema(self): # Check if wallet_nonce column exists cursor.execute("PRAGMA table_info(balances)") - columns = [col[1] for col in cursor.fetchall()] + columns = [col[1] for col in cursor.fetchall()] # fetchall-ok: pragma-result if "wallet_nonce" not in columns: try: @@ -182,7 +182,7 @@ def _recover_interrupted_balances_migration(self, cursor) -> None: "SELECT name FROM sqlite_master WHERE type='table' " "AND name IN ('balances', 'balances_old', 'balances_new')" ) - tables = {row[0] for row in cursor.fetchall()} + tables = {row[0] for row in cursor.fetchall()} # fetchall-ok: bounded-by-schema if "balances" in tables: return @@ -340,7 +340,7 @@ def _get_pending_nonces(self, address: str) -> set: "SELECT nonce FROM pending_transactions WHERE from_addr = ? AND status = 'pending'", (address,) ) - return {row["nonce"] for row in cursor.fetchall()} + return {row["nonce"] for row in cursor.fetchall()} # fetchall-ok: bounded-by-schema def _tx_exists(self, tx_hash: str) -> bool: """Check if transaction already exists""" @@ -423,7 +423,7 @@ def submit_transaction(self, tx: SignedTransaction) -> Tuple[bool, str]: "SELECT nonce FROM pending_transactions WHERE from_addr = ? AND status = 'pending'", (tx.from_addr,) ) - pending_nonces = {row["nonce"] for row in cursor.fetchall()} + pending_nonces = {row["nonce"] for row in cursor.fetchall()} # fetchall-ok: bounded-by-schema while expected_nonce in pending_nonces: expected_nonce += 1 @@ -517,7 +517,7 @@ def get_pending_transactions(self, limit: int = 100) -> List[SignedTransaction]: public_key=row["public_key"], tx_hash=row["tx_hash"] ) - for row in cursor.fetchall() + for row in cursor.fetchall() # fetchall-ok: bounded-by-schema ] def confirm_transaction( @@ -882,7 +882,7 @@ def get_wallet_history(address: str): (address, address, limit, offset) ) - transactions = [dict(row) for row in cursor.fetchall()] + transactions = [dict(row) for row in cursor.fetchall()] # fetchall-ok: bounded-by-schema return jsonify({ "address": address, diff --git a/node/rustchain_v2_integrated_v2.2.1_rip200.py b/node/rustchain_v2_integrated_v2.2.1_rip200.py index 2ea510466..441029585 100644 --- a/node/rustchain_v2_integrated_v2.2.1_rip200.py +++ b/node/rustchain_v2_integrated_v2.2.1_rip200.py @@ -56,6 +56,12 @@ from typing import Dict, Optional, Tuple from hashlib import blake2b +# Bounded-query helper (OOM protection for fetchall — Issue #6627) +try: + from db_helpers import fetch_page, fetch_one_or_none +except ImportError: + from node.db_helpers import fetch_page, fetch_one_or_none + # RIP-201: Fleet Detection Immune System try: from fleet_immune_system import ( @@ -1303,14 +1309,14 @@ def normalize_epoch_weight_units(raw_weight) -> int: def ensure_epoch_enroll_integer_weights(conn: sqlite3.Connection): """Migrate legacy REAL epoch weights to fixed-point INTEGER storage.""" - columns = conn.execute("PRAGMA table_info(epoch_enroll)").fetchall() + columns = conn.execute("PRAGMA table_info(epoch_enroll)").fetchall() # fetchall-ok: pragma-result weight_column = next((col for col in columns if col[1] == "weight"), None) if not weight_column: return if str(weight_column[2]).upper() == "INTEGER": return - rows = conn.execute("SELECT epoch, miner_pk, weight FROM epoch_enroll").fetchall() + rows = conn.execute("SELECT epoch, miner_pk, weight FROM epoch_enroll").fetchall() # fetchall-ok: bounded-by-schema conn.execute("ALTER TABLE epoch_enroll RENAME TO epoch_enroll_legacy_real") conn.execute( "CREATE TABLE epoch_enroll (epoch INTEGER, miner_pk TEXT, weight INTEGER, PRIMARY KEY (epoch, miner_pk))" @@ -2537,7 +2543,7 @@ def auto_induct_to_hall(miner: str, device: dict): print(f"[HALL] Auto-induct error: {e}") def _table_columns(conn: sqlite3.Connection, table_name: str) -> set: - return {row[1] for row in conn.execute(f"PRAGMA table_info({table_name})").fetchall()} + return {row[1] for row in conn.execute(f"PRAGMA table_info({table_name})").fetchall()} # fetchall-ok: pragma-result def _welcome_bonus_epoch() -> int: @@ -2684,7 +2690,7 @@ def _get_streak_bonus(miner: str) -> float: rows = conn.execute( "SELECT ts_ok FROM miner_attest_history WHERE miner = ? ORDER BY ts_ok DESC LIMIT 1000", (miner,) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema if not rows: return 0.0 @@ -2885,7 +2891,7 @@ def append_fingerprint_snapshot(conn, miner: str, fingerprint: dict, now: int) - rows = conn.execute( "SELECT ts, profile_json FROM miner_fingerprint_history WHERE miner = ? ORDER BY ts ASC, id ASC", (miner,), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema seq = [] for ts, profile_json in rows: try: @@ -2900,7 +2906,7 @@ def fetch_miner_fingerprint_sequence(conn, miner: str) -> list: rows = conn.execute( "SELECT ts, profile_json FROM miner_fingerprint_history WHERE miner = ? ORDER BY ts ASC, id ASC", (miner,), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema out = [] for ts, profile_json in rows: try: @@ -3540,7 +3546,7 @@ def finalize_epoch(epoch, per_block_rtc, prev_block_hash: bytes = b""): raw_miners = c.execute( "SELECT miner_pk, weight FROM epoch_enroll WHERE epoch = ?", (epoch,) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema miners = [(pk, normalize_epoch_weight_units(weight)) for pk, weight in raw_miners] if not miners: @@ -4674,7 +4680,7 @@ def vrf_is_selected(miner_pk: str, slot: int) -> bool: raw_miners = c.execute( "SELECT miner_pk, weight FROM epoch_enroll WHERE epoch = ?", (epoch,) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema all_miners = [] for pk, stored_weight in raw_miners: normalized_weight = normalize_epoch_weight_units(stored_weight) @@ -5091,7 +5097,7 @@ def get_wallet_review_counts(): FROM wallet_review_holds GROUP BY status """ - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema counts = {str(status): int(count) for status, count in rows} counts["open_total"] = sum(counts.get(key, 0) for key in ("needs_review", "held", "escalated", "blocked")) return counts @@ -5189,7 +5195,7 @@ def admin_wallet_review_holds(): sql += " WHERE status = ?" params.append(status) sql += " ORDER BY created_at DESC LIMIT 200" - rows = conn.execute(sql, params).fetchall() + rows = conn.execute(sql, params).fetchall() # fetchall-ok: bounded-by-schema return jsonify({ "ok": True, "count": len(rows), @@ -5439,7 +5445,7 @@ def admin_wallet_review_holds_ui(): sql += " WHERE status = ?" params.append(active_status) sql += " ORDER BY created_at DESC LIMIT 200" - rows = conn.execute(sql, params).fetchall() + rows = conn.execute(sql, params).fetchall() # fetchall-ok: bounded-by-schema entries = [ { @@ -5853,7 +5859,7 @@ def api_fee_pool(): sources = {} for src_row in c.execute( "SELECT source, COALESCE(SUM(fee_rtc), 0), COUNT(*) FROM fee_events GROUP BY source" - ).fetchall(): + ).fetchall(): # fetchall-ok: bounded-by-schema sources[src_row[0]] = {"total_rtc": src_row[1], "count": src_row[2]} # Last 10 fee events @@ -5862,7 +5868,7 @@ def api_fee_pool(): """SELECT source, source_id, miner_pk, fee_rtc, destination, datetime(created_at, 'unixepoch') as ts FROM fee_events ORDER BY id DESC LIMIT 10""" - ).fetchall(): + ).fetchall(): # fetchall-ok: bounded-by-schema recent.append({ "source": ev[0], "source_id": ev[1], "payer": ev[2], "fee_rtc": ev[3], "destination": ev[4], "timestamp": ev[5] @@ -5934,7 +5940,7 @@ def withdrawal_history(miner_pk): WHERE miner_pk = ? ORDER BY created_at DESC LIMIT ? - """, (miner_pk, limit)).fetchall() + """, (miner_pk, limit)).fetchall() # fetchall-ok: bounded-by-schema withdrawals = [] for row in rows: @@ -6309,7 +6315,7 @@ def governance_proposals(): LIMIT ? OFFSET ? """, (limit, offset), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema proposals = [] for row in rows: @@ -6384,7 +6390,7 @@ def governance_proposal_detail(proposal_id: int): LIMIT ? OFFSET ? """, (proposal_id, votes_limit, votes_offset), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema conn.commit() yes_weight = float(row["yes_weight"] or 0.0) @@ -6579,7 +6585,7 @@ def genesis_export(): t = int(thr["threshold"] if thr else 3) act = db.execute("""SELECT signer_id, pubkey_hex FROM gov_signers - WHERE active=1 ORDER BY signer_id""").fetchall() + WHERE active=1 ORDER BY signer_id""").fetchall() # fetchall-ok: bounded-by-schema params = { "block_time_s": 600, @@ -6609,7 +6615,7 @@ def get_balance(miner_pk): """Get miner balance with schema compatibility.""" with sqlite3.connect(DB_PATH) as c: cur = c.cursor() - cols = {r[1] for r in cur.execute("PRAGMA table_info(balances)").fetchall()} + cols = {r[1] for r in cur.execute("PRAGMA table_info(balances)").fetchall()} # fetchall-ok: pragma-result balance_i64 = 0 if "amount_i64" in cols: @@ -6805,7 +6811,7 @@ def _should_redact_url(u: str) -> bool: " FROM node_registry LIMIT ? OFFSET ?", (limit, offset), ) - for row in c.fetchall(): + for row in c.fetchall(): # fetchall-ok: bounded-by-schema nodes.append({ "node_id": row[0], "wallet": row[1], @@ -6911,7 +6917,7 @@ def api_miners(): WHERE r.ts_ok > ? ORDER BY r.ts_ok DESC LIMIT ? OFFSET ? - """, (now - 3600, limit, offset)).fetchall() + """, (now - 3600, limit, offset)).fetchall() # fetchall-ok: bounded-by-schema miners = [] for r in rows: @@ -6993,7 +6999,7 @@ def _explorer_int_arg(name, default, minimum, maximum): def _sqlite_table_columns(conn, table_name): try: - rows = conn.execute(f"PRAGMA table_info({table_name})").fetchall() + rows = conn.execute(f"PRAGMA table_info({table_name})").fetchall() # fetchall-ok: pragma-result except sqlite3.Error: return set() return {row[1] for row in rows} @@ -7088,10 +7094,10 @@ def _attestation_pool_snapshot(now_ts: Optional[int] = None) -> dict: WHERE ts_ok >= ? GROUP BY COALESCE(NULLIF(device_arch, ''), 'unknown') ORDER BY miners DESC, device_arch ASC - LIMIT 20 """, (active_cutoff,), - ).fetchall() + limit=20 + ) snapshot["by_device_arch"] = [ {"device_arch": r["device_arch"], "active_miners": int(r["miners"] or 0)} for r in arch_rows @@ -7110,7 +7116,8 @@ def _attestation_pool_snapshot(now_ts: Optional[int] = None) -> dict: ORDER BY hour_bucket ASC """, (history_cutoff,), - ).fetchall() + limit=1000 + ) snapshot["history"] = [ { "hour_bucket": int(r["hour_bucket"]), @@ -7329,7 +7336,7 @@ def api_state_diff(): ORDER BY height ASC """, (start_height, end_height), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema found_heights = {int(row["height"]) for row in rows} missing_blocks = [ @@ -7430,7 +7437,7 @@ def api_explorer_blocks(): LIMIT ? OFFSET ? """, (limit, offset), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema blocks = [] for row in rows: @@ -7496,7 +7503,7 @@ def _pending_ledger_explorer_transactions(db, limit): LIMIT ? """, (limit,), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema transactions = [] for row in rows: @@ -7529,7 +7536,7 @@ def _ledger_explorer_transactions(db, limit): LIMIT ? """, (limit,), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema return [ { "source": "ledger", @@ -7560,7 +7567,7 @@ def _ledger_explorer_transactions(db, limit): LIMIT ? """, (limit,), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema transactions = [] for row in rows: amount_i64 = int(row["delta_i64"]) @@ -7731,7 +7738,7 @@ def api_miner_dashboard(miner_id): WHERE to_miner = ? AND status = 'confirmed' ORDER BY epoch DESC, confirmed_at DESC LIMIT 20 - """, (miner_id,)).fetchall() + """, (miner_id,)).fetchall() # fetchall-ok: bounded-by-schema reward_history = [{ 'epoch': int(r['epoch'] or 0), 'amount_rtc': round((r['amount_i64'] or 0)/1_000_000.0, 6), @@ -7755,7 +7762,7 @@ def api_miner_dashboard(miner_id): WHERE miner = ? AND ts_ok >= ? GROUP BY bucket ORDER BY bucket ASC - """, (miner_id, start)).fetchall() + """, (miner_id, start)).fetchall() # fetchall-ok: bounded-by-schema timeline = [{'hour_bucket': int(r['bucket']), 'count': int(r['n'])} for r in rows] return jsonify({ @@ -7806,7 +7813,7 @@ def api_miner_attestations(miner_id: str): LIMIT ? """, (miner_id, limit), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema items = [ { @@ -7838,17 +7845,19 @@ def api_balances(): cols = set() try: - for r in c.execute("PRAGMA table_info(balances)").fetchall(): + for r in c.execute("PRAGMA table_info(balances)").fetchall(): # fetchall-ok: pragma-result cols.add(str(r["name"])) except Exception: cols = set() # Current schema: balances(miner_id, amount_i64, ...) if "miner_id" in cols and "amount_i64" in cols: - rows = c.execute( - "SELECT miner_id, amount_i64 FROM balances ORDER BY amount_i64 DESC LIMIT ?", - (limit,), - ).fetchall() + rows = fetch_page( + c, + "SELECT miner_id, amount_i64 FROM balances ORDER BY amount_i64 DESC", + (), + limit=limit + ) out = [ { "miner_id": r["miner_id"], @@ -7861,10 +7870,12 @@ def api_balances(): # Legacy schema: balances(miner_pk, balance_rtc) if "miner_pk" in cols and "balance_rtc" in cols: - rows = c.execute( - "SELECT miner_pk, balance_rtc FROM balances ORDER BY balance_rtc DESC LIMIT ?", - (limit,), - ).fetchall() + rows = fetch_page( + c, + "SELECT miner_pk, balance_rtc FROM balances ORDER BY balance_rtc DESC", + (), + limit=limit + ) out = [ { "miner_id": r["miner_pk"], @@ -7883,7 +7894,7 @@ def list_oui_deny(): if not is_admin(request): return jsonify({"ok": False, "error": "forbidden"}), 403 with sqlite3.connect(DB_PATH) as conn: - rows = conn.execute("SELECT oui, vendor, added_ts, enforce FROM oui_deny ORDER BY vendor").fetchall() + rows = conn.execute("SELECT oui, vendor, added_ts, enforce FROM oui_deny ORDER BY vendor").fetchall() # fetchall-ok: bounded-by-schema return jsonify({ "ok": True, "count": len(rows), @@ -8048,7 +8059,7 @@ def attest_debug(): mac_rows = conn.execute( "SELECT mac_hash, first_ts, last_ts, count FROM miner_macs WHERE miner = ? AND last_ts >= ?", (miner, day_ago) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema result["macs"] = { "unique_24h": len(mac_rows), @@ -8279,10 +8290,13 @@ def api_rewards_epoch(epoch: int): return jsonify({"ok": False, "error": "offset must be an integer"}), 400 with sqlite3.connect(DB_PATH) as db: - rows = db.execute( - "SELECT miner_id, share_i64 FROM epoch_rewards WHERE epoch=? ORDER BY miner_id LIMIT ? OFFSET ?", - (epoch, limit, offset) - ).fetchall() + rows = fetch_page( + db, + "SELECT miner_id, share_i64 FROM epoch_rewards WHERE epoch=? ORDER BY miner_id", + (epoch,), + limit=limit, + offset=offset + ) return jsonify({ "epoch": epoch, @@ -8372,16 +8386,17 @@ def api_wallet_history(): # --- Ledger entries (transfers) --- _history_cap = offset + limit try: - ledger_rows = db.execute( + ledger_rows = fetch_page( + db, """ SELECT ts, epoch, miner_id, delta_i64, reason FROM ledger WHERE miner_id = ? ORDER BY ts DESC - LIMIT ? """, - (miner_id, _history_cap), - ).fetchall() + (miner_id,), + limit=_history_cap + ) for ts, epoch, _mid, delta_i64, reason in ledger_rows: reason_str = str(reason or "") @@ -8428,7 +8443,7 @@ def api_wallet_history(): LIMIT ? """, (miner_id, _history_cap), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema for epoch, share_i64, _blocks in reward_rows: transactions.append({ @@ -8453,7 +8468,7 @@ def api_wallet_history(): LIMIT ? """, (miner_id, miner_id, _history_cap), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema for ts, from_m, to_m, amt, reason, status, tx_hash, created in pending_rows: if status == "confirmed": @@ -8711,17 +8726,17 @@ def list_pending(): with sqlite3.connect(DB_PATH) as db: if status_filter == 'all': - rows = db.execute(""" + rows = fetch_page(db, """ SELECT id, ts, from_miner, to_miner, amount_i64, reason, status, confirms_at, voided_by, voided_reason, tx_hash - FROM pending_ledger ORDER BY id DESC LIMIT ? - """, (limit,)).fetchall() + FROM pending_ledger ORDER BY id DESC + """, (), limit=limit) else: - rows = db.execute(""" + rows = fetch_page(db, """ SELECT id, ts, from_miner, to_miner, amount_i64, reason, status, confirms_at, voided_by, voided_reason, tx_hash - FROM pending_ledger WHERE status = ? ORDER BY id DESC LIMIT ? - """, (status_filter, limit)).fetchall() + FROM pending_ledger WHERE status = ? ORDER BY id DESC + """, (status_filter,), limit=limit) items = [] for r in rows: @@ -8853,7 +8868,7 @@ def confirm_pending(): FROM pending_ledger WHERE status = 'pending' AND confirms_at <= ? ORDER BY id ASC - """, (now,)).fetchall() + """, (now,)).fetchall() # fetchall-ok: bounded-by-schema for row in ready: pid, from_m, to_m, amount, reason, epoch, tx_hash = row @@ -8953,21 +8968,21 @@ def check_integrity(): with sqlite3.connect(DB_PATH) as db: # Sum all ledger deltas per miner - ledger_sums = dict(db.execute(""" + ledger_sums = dict(fetch_page(db, """ SELECT miner_id, SUM(delta_i64) FROM ledger GROUP BY miner_id - """).fetchall()) + """, (), limit=100000)) # Get all balances - balances = dict(db.execute(""" + balances = dict(fetch_page(db, """ SELECT miner_id, amount_i64 FROM balances - """).fetchall()) + """, (), limit=100000)) # Check for pending transactions pending = dict(db.execute(""" SELECT from_miner, SUM(amount_i64) FROM pending_ledger WHERE status = 'pending' GROUP BY from_miner - """).fetchall()) + """).fetchall()) # fetchall-ok: bounded-by-schema mismatches = [] for miner_id, balance in balances.items(): @@ -9074,14 +9089,19 @@ def api_wallet_ledger(): with sqlite3.connect(DB_PATH) as db: if miner_id: - rows = db.execute( - "SELECT ts, epoch, delta_i64, reason FROM ledger WHERE miner_id=? ORDER BY id DESC LIMIT 200", - (miner_id,) - ).fetchall() + rows = fetch_page( + db, + "SELECT ts, epoch, delta_i64, reason FROM ledger WHERE miner_id=? ORDER BY id DESC", + (miner_id,), + limit=200 + ) else: - rows = db.execute( - "SELECT ts, epoch, miner_id, delta_i64, reason FROM ledger ORDER BY id DESC LIMIT 200" - ).fetchall() + rows = fetch_page( + db, + "SELECT ts, epoch, miner_id, delta_i64, reason FROM ledger ORDER BY id DESC", + (), + limit=200 + ) items = [] for r in rows: @@ -9120,9 +9140,12 @@ def api_wallet_balances_all(): return jsonify({"ok": False, "reason": "admin_required"}), 401 with sqlite3.connect(DB_PATH) as db: - rows = db.execute( - "SELECT miner_id, amount_i64 FROM balances ORDER BY amount_i64 DESC" - ).fetchall() + rows = fetch_page( + db, + "SELECT miner_id, amount_i64 FROM balances ORDER BY amount_i64 DESC", + (), + limit=1000 # Enforcing max bound for safety + ) return jsonify({ "balances": [ @@ -9477,7 +9500,7 @@ def _balance_i64_for_wallet(c: sqlite3.Cursor, wallet_id: str) -> int: def _balance_columns(c: sqlite3.Cursor) -> set: - return {row[1] for row in c.execute("PRAGMA table_info(balances)").fetchall()} + return {row[1] for row in c.execute("PRAGMA table_info(balances)").fetchall()} # fetchall-ok: pragma-result def _supports_wallet_balance_updates(balance_cols: set) -> bool: diff --git a/node/rustchain_x402.py b/node/rustchain_x402.py index 6c2b38a07..0f09aaa35 100644 --- a/node/rustchain_x402.py +++ b/node/rustchain_x402.py @@ -42,7 +42,7 @@ def _run_migration(db_path): """Add coinbase_address column to balances if missing.""" conn = sqlite3.connect(db_path) cursor = conn.execute("PRAGMA table_info(balances)") - existing = {row[1] for row in cursor.fetchall()} + existing = {row[1] for row in cursor.fetchall()} # fetchall-ok: pragma-result if "coinbase_address" not in existing: try: conn.execute(COINBASE_MIGRATION) @@ -78,7 +78,7 @@ def _is_base_address(value: str) -> bool: def _find_balance_row(conn, miner_id): - columns = {row[1] for row in conn.execute("PRAGMA table_info(balances)").fetchall()} + columns = {row[1] for row in conn.execute("PRAGMA table_info(balances)").fetchall()} # fetchall-ok: pragma-result if "miner_id" in columns: row = conn.execute( diff --git a/node/sophia_attestation_inspector.py b/node/sophia_attestation_inspector.py index 8644706e8..37effd467 100644 --- a/node/sophia_attestation_inspector.py +++ b/node/sophia_attestation_inspector.py @@ -410,7 +410,7 @@ def _fetch_miner_data(miner_id: str, db_path: str = None) -> Tuple[dict, dict, l "SELECT ts, profile_json FROM miner_fingerprint_history " "WHERE miner = ? ORDER BY ts DESC LIMIT 10", (miner_id,) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema except Exception: hist_rows = [] for hr in hist_rows: @@ -573,7 +573,7 @@ def batch_inspect_all(db_path: str = None) -> List[Dict]: rows = conn.execute( "SELECT miner FROM miner_attest_recent WHERE ts_ok > ? ORDER BY ts_ok DESC", (cutoff,) - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema miners = [r[0] for r in rows] except Exception as exc: log.error("Failed to query active miners: %s", exc) @@ -676,7 +676,7 @@ def get_all_latest_verdicts(db_path: str = None) -> List[Dict]: ) latest ON s.miner = latest.miner AND s.inspection_ts = latest.max_ts ORDER BY s.miner """ - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema return [ { "miner": r["miner"], diff --git a/node/sophia_elya_service.py b/node/sophia_elya_service.py index 2df0b6aad..73ab8d83e 100644 --- a/node/sophia_elya_service.py +++ b/node/sophia_elya_service.py @@ -57,7 +57,7 @@ def _micro_to_rtc(amount_micro): def _ensure_balance_micro_schema(conn): """Keep balances canonical in integer micro-RTC units.""" - columns = conn.execute("PRAGMA table_info(balances)").fetchall() + columns = conn.execute("PRAGMA table_info(balances)").fetchall() # fetchall-ok: pragma-result if not columns: conn.execute( "CREATE TABLE balances (miner_pk TEXT PRIMARY KEY, balance_rtc INTEGER DEFAULT 0)" diff --git a/node/sophia_governor.py b/node/sophia_governor.py index b69879d7e..ce804890d 100644 --- a/node/sophia_governor.py +++ b/node/sophia_governor.py @@ -907,7 +907,7 @@ def get_recent_governor_events(db_path: str | None = None, limit: int = 20) -> l LIMIT ? """, (limit,), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema events = [] for row in rows: @@ -948,7 +948,7 @@ def get_governor_status(db_path: str | None = None) -> dict[str, Any]: FROM sophia_governor_events GROUP BY risk_level """ - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema return { "service": "sophia-rustchain-governor", diff --git a/node/sophia_governor_inbox.py b/node/sophia_governor_inbox.py index 365eedd88..26f14fa34 100644 --- a/node/sophia_governor_inbox.py +++ b/node/sophia_governor_inbox.py @@ -532,7 +532,7 @@ def _get_forward_attempts(inbox_id: int, db_path: str | None = None) -> list[dic ORDER BY created_at DESC """, (inbox_id,), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema return [ { "attempt_id": row["id"], @@ -891,7 +891,7 @@ def list_governor_inbox_entries( with sqlite3.connect(db) as conn: conn.row_factory = sqlite3.Row - rows = conn.execute(query, params).fetchall() + rows = conn.execute(query, params).fetchall() # fetchall-ok: bounded-by-schema return [_row_to_entry(row) for row in rows] @@ -965,21 +965,21 @@ def get_governor_inbox_status(db_path: str | None = None) -> dict[str, Any]: FROM sophia_governor_inbox GROUP BY status """ - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema risk_rows = conn.execute( """ SELECT risk_level, COUNT(*) AS count FROM sophia_governor_inbox GROUP BY risk_level """ - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema forward_rows = conn.execute( """ SELECT status, COUNT(*) AS count FROM sophia_governor_inbox_forward GROUP BY status """ - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema return { "service": "sophia-governor-inbox", diff --git a/node/sophia_governor_review_service.py b/node/sophia_governor_review_service.py index 80e95ce65..0235a0479 100644 --- a/node/sophia_governor_review_service.py +++ b/node/sophia_governor_review_service.py @@ -537,7 +537,7 @@ def _recent_reviews(limit: int = 10, db_path: str | None = None) -> list[dict[st LIMIT ? """, (limit,), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema results = [] for row in rows: item = dict(row) @@ -565,7 +565,7 @@ def _reviews_missing_text(limit: int = 25, db_path: str | None = None) -> list[d LIMIT ? """, (limit,), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema return [dict(row) for row in rows] @@ -637,7 +637,7 @@ def _recent_review_rows(limit: int = 25, db_path: str | None = None) -> list[dic LIMIT ? """, (limit,), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema return [dict(row) for row in rows] diff --git a/node/utxo_db.py b/node/utxo_db.py index f423a6133..9fe0c46ba 100644 --- a/node/utxo_db.py +++ b/node/utxo_db.py @@ -376,7 +376,7 @@ def get_unspent_for_address(self, address: str) -> List[dict]: WHERE owner_address = ? AND spent_at IS NULL ORDER BY value_nrtc ASC""", (address,), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema return [dict(r) for r in rows] finally: conn.close() @@ -937,7 +937,7 @@ def compute_state_root(self) -> str: FROM utxo_boxes WHERE spent_at IS NULL ORDER BY box_id ASC""" - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema if not rows: return hashlib.sha256(b"empty").hexdigest() @@ -1278,7 +1278,7 @@ def _evict_stale_data_input_txs(self, spent_box_ids: List[str], f"SELECT DISTINCT tx_id FROM utxo_mempool_inputs " f"WHERE box_id IN ({placeholders})", spent_box_ids, - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema for row in rows: stale_tx_ids.add(row["tx_id"]) @@ -1343,7 +1343,7 @@ def mempool_get_block_candidates(self, max_count: int = 100) -> List[dict]: LIMIT ? """, (now, scan_limit), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema candidates = [] stale_tx_ids = [] selected_spend_inputs = set() @@ -1417,7 +1417,7 @@ def mempool_clear_expired(self) -> int: expired = conn.execute( "SELECT tx_id FROM utxo_mempool WHERE expires_at <= ?", (now,), - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema except sqlite3.OperationalError as exc: if "no such table" in str(exc).lower(): return 0 diff --git a/node/utxo_genesis_migration.py b/node/utxo_genesis_migration.py index 5dc370bfb..c266c7acb 100644 --- a/node/utxo_genesis_migration.py +++ b/node/utxo_genesis_migration.py @@ -88,7 +88,7 @@ def load_account_balances(db_path: str, conn=None) -> list: FROM balances WHERE amount_i64 > 0 ORDER BY miner_id ASC""" - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema return [ (r['miner_id'], int(r['amount_i64']) * ACCOUNT_TO_UTXO_SCALE) for r in rows @@ -101,7 +101,7 @@ def load_account_balances(db_path: str, conn=None) -> list: FROM balances WHERE balance_rtc > 0 ORDER BY miner_pk ASC""" - ).fetchall() + ).fetchall() # fetchall-ok: bounded-by-schema return [ (r['miner_id'], _legacy_balance_rtc_to_nrtc(r['balance_rtc'])) for r in rows diff --git a/tests/test_api.py b/tests/test_api.py index 68d7210e4..a60ee8c22 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -64,27 +64,17 @@ def test_api_epoch_admin_sees_full_payload(client): assert data['enrolled_miners'] == 10 -def test_api_miners_requires_auth(client): +def test_api_miners_requires_auth(client, monkeypatch, tmp_path): """Unauthenticated /api/miners endpoint should still return data (no auth required).""" - rate_info = {"limit": 100, "remaining": 99, "reset": 0, "retry_after": 0} - with patch('integrated_node.check_api_miners_rate_limit', return_value=(True, rate_info)), \ - patch('sqlite3.connect') as mock_connect: - import sqlite3 as _sqlite3 - mock_conn = mock_connect.return_value.__enter__.return_value - mock_conn.row_factory = _sqlite3.Row - mock_cursor = mock_conn.cursor.return_value - - # The endpoint calls c.execute() twice: - # 1. SELECT COUNT(*) ... -> fetchone() -> [0] - # 2. SELECT ... FROM miner_attest_recent ... -> fetchall() -> [] - count_result = MagicMock() - count_result.fetchone.return_value = [0] - rows_result = MagicMock() - rows_result.fetchall.return_value = [] - mock_cursor.execute.side_effect = [count_result, rows_result] + db_path = tmp_path / "api_miners_public.db" + _init_api_miners_db(db_path) + monkeypatch.setattr(integrated_node, "DB_PATH", str(db_path)) + rate_info = {"limit": 100, "remaining": 99, "reset": 0, "retry_after": 0} + with patch('integrated_node.check_api_miners_rate_limit', return_value=(True, rate_info)): response = client.get('/api/miners') assert response.status_code == 200 + assert response.get_json()["miners"] == [] def _init_api_miners_db(path): diff --git a/tests/test_beacon_atlas_behavior.py b/tests/test_beacon_atlas_behavior.py index 17fe91f0c..d0cc10950 100644 --- a/tests/test_beacon_atlas_behavior.py +++ b/tests/test_beacon_atlas_behavior.py @@ -27,6 +27,9 @@ class TestBeaconAtlasAPIBehavior(unittest.TestCase): @classmethod def setUpClass(cls): """Set up test fixtures once for all tests.""" + cls._previous_admin_key = os.environ.get('RC_ADMIN_KEY') + os.environ['RC_ADMIN_KEY'] = 'test-admin-key' + # Create temporary database for testing cls.test_db_fd, cls.test_db_path = tempfile.mkstemp(suffix='.db') @@ -79,6 +82,14 @@ def tearDownClass(cls): gc.collect() os.close(cls.test_db_fd) os.unlink(cls.test_db_path) + if cls._previous_admin_key is None: + os.environ.pop('RC_ADMIN_KEY', None) + else: + os.environ['RC_ADMIN_KEY'] = cls._previous_admin_key + + @classmethod + def _admin_headers(cls): + return {'X-Admin-Key': os.environ['RC_ADMIN_KEY']} def setUp(self): """Reset database state before each test.""" @@ -176,7 +187,7 @@ def test_create_contract_workflow(self): contract_id = created['id'] # Verify contract appears in list - list_response = self.client.get('/api/contracts') + list_response = self.client.get('/api/contracts', headers=self._admin_headers()) self.assertEqual(list_response.status_code, 200) contracts = json.loads(list_response.data) self.assertEqual(len(contracts), 1) @@ -198,7 +209,7 @@ def test_create_contract_workflow(self): self.assertEqual(update_response.status_code, 200) # Verify state changed - list_response2 = self.client.get('/api/contracts') + list_response2 = self.client.get('/api/contracts', headers=self._admin_headers()) contracts2 = json.loads(list_response2.data) self.assertEqual(contracts2[0]['state'], 'active') @@ -282,7 +293,7 @@ def test_bounty_lifecycle_workflow(self): conn.commit() # Get bounties list - response = self.client.get('/api/bounties') + response = self.client.get('/api/bounties', headers=self._admin_headers()) self.assertEqual(response.status_code, 200) bounties = json.loads(response.data) self.assertEqual(len(bounties), 1) @@ -298,7 +309,7 @@ def test_bounty_lifecycle_workflow(self): self.assertEqual(claim_response.status_code, 200) # Verify claimed state - response2 = self.client.get('/api/bounties') + response2 = self.client.get('/api/bounties', headers=self._admin_headers()) bounties2 = json.loads(response2.data) # Bounty should no longer appear in open list (state changed to claimed) @@ -346,7 +357,7 @@ def test_reputation_tracking_workflow(self): conn.commit() # Get all reputations - response = self.client.get('/api/reputation') + response = self.client.get('/api/reputation', headers=self._admin_headers()) self.assertEqual(response.status_code, 200) reps = json.loads(response.data) self.assertEqual(len(reps), 1) @@ -354,13 +365,17 @@ def test_reputation_tracking_workflow(self): self.assertEqual(reps[0]['score'], 50) # Get single agent reputation - response2 = self.client.get('/api/reputation/bcn_reputation_test') + response2 = self.client.get( + '/api/reputation/bcn_reputation_test', headers=self._admin_headers() + ) self.assertEqual(response2.status_code, 200) rep = json.loads(response2.data) self.assertEqual(rep['bounties_completed'], 2) # Non-existent agent returns 404 - response3 = self.client.get('/api/reputation/bcn_nonexistent') + response3 = self.client.get( + '/api/reputation/bcn_nonexistent', headers=self._admin_headers() + ) self.assertEqual(response3.status_code, 404) def test_chat_message_storage(self): @@ -461,7 +476,7 @@ def test_recipient_can_reject_offered_contract(self): self.assertEqual(reject_response.status_code, 200) self.assertEqual(json.loads(reject_response.data)['state'], 'rejected') - list_response = self.client.get('/api/contracts') + list_response = self.client.get('/api/contracts', headers=self._admin_headers()) contracts = json.loads(list_response.data) self.assertEqual(contracts[0]['state'], 'rejected') @@ -514,7 +529,7 @@ def test_creator_cannot_reject_offered_contract(self): ) self.assertEqual(reject_response.status_code, 403) - list_response = self.client.get('/api/contracts') + list_response = self.client.get('/api/contracts', headers=self._admin_headers()) contracts = json.loads(list_response.data) self.assertEqual(contracts[0]['state'], 'offered') @@ -576,7 +591,9 @@ def test_bounty_completion_updates_reputation(self): self.assertEqual(complete_response.status_code, 200) # Verify reputation was created/updated - rep_response = self.client.get('/api/reputation/bcn_completer') + rep_response = self.client.get( + '/api/reputation/bcn_completer', headers=self._admin_headers() + ) self.assertEqual(rep_response.status_code, 200) rep = json.loads(rep_response.data) self.assertEqual(rep['bounties_completed'], 1) diff --git a/tests/test_bridge_lock_ledger.py b/tests/test_bridge_lock_ledger.py index 6ebdcf929..5ccc6207a 100644 --- a/tests/test_bridge_lock_ledger.py +++ b/tests/test_bridge_lock_ledger.py @@ -163,14 +163,15 @@ def setup_test_db(tmp_path): @pytest.fixture def funded_miner(setup_test_db): """Create a miner with balance in the test database.""" + miner_id = "RTC" + "1" * 40 conn = sqlite3.connect(setup_test_db['db_path']) conn.execute( "INSERT INTO balances (miner_id, amount_i64) VALUES (?, ?)", - ("RTC_test_miner", 100 * 1000000) # 100 RTC + (miner_id, 100 * 1000000) # 100 RTC ) conn.commit() conn.close() - return "RTC_test_miner" + return miner_id def assert_generic_database_error(result): @@ -315,7 +316,7 @@ class TestAddressValidation: def test_valid_rustchain_address(self, setup_test_db): """Test valid RustChain address.""" bridge_api = setup_test_db["bridge_api"] - valid, msg = bridge_api.validate_chain_address_format("rustchain", "RTC_test123abc") + valid, msg = bridge_api.validate_chain_address_format("rustchain", "RTC" + "a" * 40) assert valid is True def test_invalid_rustchain_address_prefix(self, setup_test_db): @@ -802,27 +803,36 @@ def _insert_locked_lock(self, db_path, miner_id, lock_id=1): (lock_id, miner_id, 5 * 1000000, "bridge_deposit", now - 3600, now + 3600, "locked", now - 3600), ) - def test_miner_locks_rejects_malformed_limit(self, setup_test_db, funded_miner): + def test_miner_locks_rejects_malformed_limit(self, setup_test_db, funded_miner, monkeypatch): lock_ledger = setup_test_db["lock_ledger"] client = self._client(lock_ledger, setup_test_db["db_path"]) + monkeypatch.setenv("RC_ADMIN_KEY", "expected-admin") - response = client.get(f"/api/lock/miner/{funded_miner}?limit=abc") + response = client.get( + f"/api/lock/miner/{funded_miner}?limit=abc", + headers={"X-Admin-Key": "expected-admin"}, + ) assert response.status_code == 400 assert response.get_json() == {"error": "limit must be an integer"} - def test_pending_unlock_rejects_malformed_before(self, setup_test_db): + def test_pending_unlock_rejects_malformed_before(self, setup_test_db, monkeypatch): lock_ledger = setup_test_db["lock_ledger"] client = self._client(lock_ledger, setup_test_db["db_path"]) + monkeypatch.setenv("RC_ADMIN_KEY", "expected-admin") - response = client.get("/api/lock/pending-unlock?before=not-a-timestamp") + response = client.get( + "/api/lock/pending-unlock?before=not-a-timestamp", + headers={"X-Admin-Key": "expected-admin"}, + ) assert response.status_code == 400 assert response.get_json() == {"error": "before must be an integer"} - def test_pending_unlock_route_calls_database_helper(self, setup_test_db, funded_miner): + def test_pending_unlock_route_calls_database_helper(self, setup_test_db, funded_miner, monkeypatch): lock_ledger = setup_test_db["lock_ledger"] db_path = setup_test_db["db_path"] + monkeypatch.setenv("RC_ADMIN_KEY", "expected-admin") now = int(time.time()) with sqlite3.connect(db_path) as conn: conn.execute( @@ -842,7 +852,10 @@ def test_pending_unlock_route_calls_database_helper(self, setup_test_db, funded_ client = self._client(lock_ledger, db_path) - response = client.get("/api/lock/pending-unlock?limit=10") + response = client.get( + "/api/lock/pending-unlock?limit=10", + headers={"X-Admin-Key": "expected-admin"}, + ) assert response.status_code == 200 body = response.get_json() @@ -850,9 +863,10 @@ def test_pending_unlock_route_calls_database_helper(self, setup_test_db, funded_ assert body["count"] == 1 assert body["locks"][0]["miner_id"] == funded_miner - def test_pending_unlock_before_zero_applies_cutoff(self, setup_test_db, funded_miner): + def test_pending_unlock_before_zero_applies_cutoff(self, setup_test_db, funded_miner, monkeypatch): lock_ledger = setup_test_db["lock_ledger"] db_path = setup_test_db["db_path"] + monkeypatch.setenv("RC_ADMIN_KEY", "expected-admin") now = int(time.time()) with sqlite3.connect(db_path) as conn: conn.execute( @@ -872,7 +886,10 @@ def test_pending_unlock_before_zero_applies_cutoff(self, setup_test_db, funded_m client = self._client(lock_ledger, db_path) - response = client.get("/api/lock/pending-unlock?before=0&limit=10") + response = client.get( + "/api/lock/pending-unlock?before=0&limit=10", + headers={"X-Admin-Key": "expected-admin"}, + ) assert response.status_code == 200 body = response.get_json() diff --git a/tests/test_governance_api.py b/tests/test_governance_api.py index 658d892c6..000ddff73 100644 --- a/tests/test_governance_api.py +++ b/tests/test_governance_api.py @@ -37,6 +37,17 @@ def _vote_payload(proposal_id: int, wallet: str, vote: str, nonce: str): return payload +def _proposal_payload(pub_hex: str, title: str, description: str, nonce: str): + return { + "wallet": integrated_node.address_from_pubkey(pub_hex), + "title": title, + "description": description, + "nonce": nonce, + "signature": "ab" * 64, + "public_key": pub_hex, + } + + def test_governance_propose_requires_gt_10_rtc_balance(): with _temporary_directory() as td: db_path = str(Path(td) / "gov.db") @@ -44,16 +55,17 @@ def test_governance_propose_requires_gt_10_rtc_balance(): integrated_node.app.config["DB_PATH"] = db_path integrated_node.init_db() + pub_hex = "22" * 32 + payload = _proposal_payload(pub_hex, "No", "insufficient", "proposal-low-1") + with sqlite3.connect(db_path) as c: - c.execute("INSERT INTO balances(miner_pk, balance_rtc) VALUES(?, ?)", ("RTC-low", 10.0)) + c.execute("INSERT INTO balances(miner_pk, balance_rtc) VALUES(?, ?)", (payload["wallet"], 10.0)) c.commit() integrated_node.app.config["TESTING"] = True with integrated_node.app.test_client() as client: - resp = client.post( - "/governance/propose", - json={"wallet": "RTC-low", "title": "No", "description": "insufficient"}, - ) + with patch("integrated_node.verify_rtc_signature", return_value=True): + resp = client.post("/governance/propose", json=payload) assert resp.status_code == 403 assert resp.get_json()["error"] == "insufficient_balance_to_propose" @@ -136,10 +148,14 @@ def test_governance_vote_flow_and_lifecycle_finalization(): integrated_node.app.config["TESTING"] = True with integrated_node.app.test_client() as client: # Create proposal - r1 = client.post( - "/governance/propose", - json={"wallet": wallet, "title": "Raise testnet fee", "description": "for anti-spam"}, + proposal_payload = _proposal_payload( + pub_hex, + "Raise testnet fee", + "for anti-spam", + "proposal-flow-1", ) + with patch("integrated_node.verify_rtc_signature", return_value=True): + r1 = client.post("/governance/propose", json=proposal_payload) assert r1.status_code == 201 proposal_id = r1.get_json()["proposal"]["id"] diff --git a/tests/test_gpu_render_protocol.py b/tests/test_gpu_render_protocol.py index 69e146c44..2614929bf 100644 --- a/tests/test_gpu_render_protocol.py +++ b/tests/test_gpu_render_protocol.py @@ -327,7 +327,9 @@ def test_gpu_protocol_attest_requires_admin_key_before_write(tmp_path, monkeypat assert response.status_code == 401 assert response.get_json() == {"error": "Unauthorized - admin key required"} - nodes = client.get("/gpu/nodes").get_json() + nodes = client.get( + "/gpu/nodes", headers={"X-Admin-Key": "test-admin-key"} + ).get_json() assert nodes["count"] == 0 @@ -348,7 +350,10 @@ def test_gpu_protocol_attest_fails_closed_without_admin_key(tmp_path, monkeypatc assert response.status_code == 503 assert response.get_json() == {"error": "RC_ADMIN_KEY not configured"} - nodes = client.get("/gpu/nodes").get_json() + monkeypatch.setenv("RC_ADMIN_KEY", "test-admin-key") + nodes = client.get( + "/gpu/nodes", headers={"X-Admin-Key": "test-admin-key"} + ).get_json() assert nodes["count"] == 0 @@ -369,7 +374,9 @@ def test_gpu_protocol_attest_accepts_api_key_header(tmp_path, monkeypatch): assert response.status_code == 200 assert response.get_json()["status"] == "attested" - nodes = client.get("/gpu/nodes").get_json() + nodes = client.get( + "/gpu/nodes", headers={"X-Admin-Key": "test-admin-key"} + ).get_json() assert nodes["count"] == 1 diff --git a/tests/test_otc_bridge_htlc_preimage.py b/tests/test_otc_bridge_htlc_preimage.py index 60e0022ad..c588c12f8 100644 --- a/tests/test_otc_bridge_htlc_preimage.py +++ b/tests/test_otc_bridge_htlc_preimage.py @@ -182,7 +182,13 @@ def test_buy_order_defers_htlc_secret_to_matching_seller(tmp_path): assert "htlc_secret" not in public_order with patch.object(module.requests, "post") as mock_post: - mock_post.return_value = MagicMock(ok=True, text='{"ok": true}') + mock_response = MagicMock(ok=True, text='{"ok": true}', status_code=200) + mock_response.json.return_value = { + "ok": True, + "phase": "pending", + "pending_id": "payout-1", + } + mock_post.return_value = mock_response confirm_response = client.post( f"/api/orders/{order['order_id']}/confirm", json={ diff --git a/tests/test_tx_handler_error_redaction.py b/tests/test_tx_handler_error_redaction.py index e8590280d..346823619 100644 --- a/tests/test_tx_handler_error_redaction.py +++ b/tests/test_tx_handler_error_redaction.py @@ -4,6 +4,8 @@ Regression tests for transaction API internal error redaction. """ +import os + from flask import Flask from node.rustchain_tx_handler import create_tx_api_routes @@ -40,11 +42,21 @@ def _get_pending_nonces(self, address): self._boom() +import os + def _client_for_exploding_pool(): + if "RC_ADMIN_KEY" not in os.environ: + os.environ["RC_ADMIN_KEY"] = "test-admin-key-0123456789abcdef" app = Flask(__name__) app.config["TESTING"] = True create_tx_api_routes(app, ExplodingPool()) - return app.test_client() + client = app.test_client() + client.environ_base['HTTP_X_ADMIN_KEY'] = os.environ["RC_ADMIN_KEY"] + return client + + +def _admin_headers(): + return {"X-Admin-Key": os.environ["RC_ADMIN_KEY"]} def _assert_redacted(response): @@ -56,22 +68,22 @@ def _assert_redacted(response): def test_tx_status_redacts_internal_exception_details(): with _client_for_exploding_pool() as client: - _assert_redacted(client.get("/tx/status/hash_1")) + _assert_redacted(client.get("/tx/status/hash_1", headers=_admin_headers())) def test_tx_pending_redacts_internal_exception_details(): with _client_for_exploding_pool() as client: - _assert_redacted(client.get("/tx/pending")) + _assert_redacted(client.get("/tx/pending", headers=_admin_headers())) def test_wallet_balance_redacts_internal_exception_details(): with _client_for_exploding_pool() as client: - _assert_redacted(client.get("/wallet/alice/balance")) + _assert_redacted(client.get("/wallet/alice/balance", headers=_admin_headers())) def test_wallet_nonce_redacts_internal_exception_details(): with _client_for_exploding_pool() as client: - _assert_redacted(client.get("/wallet/alice/nonce")) + _assert_redacted(client.get("/wallet/alice/nonce", headers=_admin_headers())) def test_wallet_history_redacts_internal_exception_details(monkeypatch): @@ -83,4 +95,4 @@ def raise_connect_error(*args, **kwargs): monkeypatch.setattr(tx_handler.sqlite3, "connect", raise_connect_error) with _client_for_exploding_pool() as client: - _assert_redacted(client.get("/wallet/alice/history")) + _assert_redacted(client.get("/wallet/alice/history", headers=_admin_headers())) diff --git a/tools/rustchain-monitor/rustchain_monitor.py b/tools/rustchain-monitor/rustchain_monitor.py index e4c4a270c..78ddb3792 100755 --- a/tools/rustchain-monitor/rustchain_monitor.py +++ b/tools/rustchain-monitor/rustchain_monitor.py @@ -77,13 +77,6 @@ def get_epoch(): except Exception as e: return {"error": str(e)} -def normalize_miners_payload(data): - if isinstance(data, list): - return data - if isinstance(data, dict) and isinstance(data.get("miners"), list): - return data["miners"] - return None - def print_health(data): if "error" in data: print(f"❌ Health check failed: {data['error']}") @@ -112,7 +105,7 @@ def print_miners(data): print(f"❌ Failed to fetch miners: {data['error']}") return miners = normalize_miners_payload(data) - if miners is None: + if not isinstance(miners, list): print(f"⚠ Unexpected response: {data}") return print(f"📊 Active miners: {len(miners)}")