-
Notifications
You must be signed in to change notification settings - Fork 36
⚡ Bolt: Optimized blockchain integrity chaining #492
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,7 +30,7 @@ | |
| send_status_notification | ||
| ) | ||
| from backend.spatial_utils import get_bounding_box, find_nearby_issues | ||
| from backend.cache import recent_issues_cache, nearby_issues_cache | ||
| from backend.cache import recent_issues_cache, nearby_issues_cache, blockchain_last_hash_cache | ||
| from backend.hf_api_service import verify_resolution_vqa | ||
| from backend.dependencies import get_http_client | ||
| from backend.rag_service import rag_service | ||
|
|
@@ -172,16 +172,24 @@ async def create_issue( | |
| # Save to DB only if no nearby issues found or deduplication failed | ||
| if deduplication_info is None or not deduplication_info.has_nearby_issues: | ||
| # Blockchain feature: calculate integrity hash for the report | ||
| # Optimization: Fetch only the last hash to maintain the chain with minimal overhead | ||
| prev_issue = await run_in_threadpool( | ||
| lambda: db.query(Issue.integrity_hash).order_by(Issue.id.desc()).first() | ||
| ) | ||
| prev_hash = prev_issue[0] if prev_issue and prev_issue[0] else "" | ||
| # Performance Boost: Use cached last hash to avoid database lookup on every submission | ||
| prev_hash = blockchain_last_hash_cache.get("latest_hash") | ||
|
|
||
| if prev_hash is None: | ||
| # Cache miss: fetch from DB and populate cache | ||
| prev_issue = await run_in_threadpool( | ||
| lambda: db.query(Issue.integrity_hash).order_by(Issue.id.desc()).first() | ||
| ) | ||
| prev_hash = prev_issue[0] if prev_issue and prev_issue[0] else "" | ||
| blockchain_last_hash_cache.set(data=prev_hash, key="latest_hash") | ||
|
|
||
| # Simple but effective SHA-256 chaining | ||
| # Simple but effective SHA-256 chaining | ||
| hash_content = f"{description}|{category}|{prev_hash}" | ||
| integrity_hash = hashlib.sha256(hash_content.encode()).hexdigest() | ||
|
|
||
| # Update cache for next submission | ||
| blockchain_last_hash_cache.set(data=integrity_hash, key="latest_hash") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: Cache is updated with the new Move the cache update to after the successful DB save—i.e., after Prompt for AI agents
Comment on lines
+190
to
+191
|
||
|
|
||
|
Comment on lines
188
to
+192
|
||
| # RAG Retrieval (New) | ||
| relevant_rule = rag_service.retrieve(description) | ||
| initial_action_plan = None | ||
|
|
@@ -199,7 +207,8 @@ async def create_issue( | |
| longitude=longitude, | ||
| location=location, | ||
| action_plan=initial_action_plan, | ||
| integrity_hash=integrity_hash | ||
| integrity_hash=integrity_hash, | ||
| previous_integrity_hash=prev_hash | ||
| ) | ||
|
|
||
| # Offload blocking DB operations to threadpool | ||
|
|
@@ -620,24 +629,32 @@ def get_user_issues( | |
| async def verify_blockchain_integrity(issue_id: int, db: Session = Depends(get_db)): | ||
| """ | ||
| Verify the cryptographic integrity of a report using the blockchain-style chaining. | ||
| Optimized: Uses column projection to fetch only needed data. | ||
| Performance Boost: Uses pre-stored previous_integrity_hash to eliminate extra database lookup. | ||
| """ | ||
| # Fetch current issue data | ||
| # Fetch current issue data including its chain link | ||
| current_issue = await run_in_threadpool( | ||
| lambda: db.query( | ||
| Issue.id, Issue.description, Issue.category, Issue.integrity_hash | ||
| Issue.id, | ||
| Issue.description, | ||
| Issue.category, | ||
| Issue.integrity_hash, | ||
| Issue.previous_integrity_hash | ||
| ).filter(Issue.id == issue_id).first() | ||
| ) | ||
|
|
||
| if not current_issue: | ||
| raise HTTPException(status_code=404, detail="Issue not found") | ||
|
|
||
| # Fetch previous issue's integrity hash to verify the chain | ||
| prev_issue_hash = await run_in_threadpool( | ||
| lambda: db.query(Issue.integrity_hash).filter(Issue.id < issue_id).order_by(Issue.id.desc()).first() | ||
| ) | ||
|
|
||
| prev_hash = prev_issue_hash[0] if prev_issue_hash and prev_issue_hash[0] else "" | ||
| # Use the stored previous hash from the record | ||
| # Regression Fix: Fallback to DB lookup if previous_integrity_hash is None (for old records) | ||
| if current_issue.previous_integrity_hash is not None: | ||
| prev_hash = current_issue.previous_integrity_hash | ||
| else: | ||
| # Fetch previous issue's integrity hash from DB for legacy records | ||
| prev_issue_hash = await run_in_threadpool( | ||
| lambda: db.query(Issue.integrity_hash).filter(Issue.id < issue_id).order_by(Issue.id.desc()).first() | ||
| ) | ||
| prev_hash = prev_issue_hash[0] if prev_issue_hash and prev_issue_hash[0] else "" | ||
|
|
||
| # Recompute hash based on current data and previous hash | ||
| # Chaining logic: hash(description|category|prev_hash) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This cache-based approach is only process-local and not transactionally tied to the DB. If the API is run with multiple workers/processes or scaled horizontally, different instances can compute
prev_hashfrom stale cache state and create forks in the hash chain. Consider using a DB-backed single-row “latest hash” (updated atomically in the same transaction as the Issue insert) or a distributed cache/lock (e.g., Redis) to keep chaining consistent across instances.