From 08318aa73c6e80d4300603a69c2834249579d2c6 Mon Sep 17 00:00:00 2001 From: RohanExploit <178623867+RohanExploit@users.noreply.github.com> Date: Tue, 12 May 2026 11:52:48 +0000 Subject: [PATCH] feat: add blockchain integrity fields to ResolutionProofToken Added `integrity_hash` and `previous_integrity_hash` to the `ResolutionProofToken` model to maintain standard blockchain-style integrity chaining across core entities. Implemented a `token_last_hash_cache` in `backend/cache.py` to prevent redundant database queries and securely generate hashes using HMAC-SHA256 in `backend/resolution_proof_service.py` without degrading performance. --- backend/cache.py | 1 + backend/models.py | 4 ++++ backend/resolution_proof_service.py | 22 +++++++++++++++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/backend/cache.py b/backend/cache.py index 260d5f88..2aa52e07 100644 --- a/backend/cache.py +++ b/backend/cache.py @@ -180,6 +180,7 @@ def invalidate(self): blockchain_last_hash_cache = ThreadSafeCache(ttl=3600, max_size=1) grievance_last_hash_cache = ThreadSafeCache(ttl=3600, max_size=1) resolution_last_hash_cache = ThreadSafeCache(ttl=3600, max_size=1) +token_last_hash_cache = ThreadSafeCache(ttl=3600, max_size=1) visit_last_hash_cache = ThreadSafeCache(ttl=3600, max_size=2) audit_last_hash_cache = ThreadSafeCache(ttl=3600, max_size=2) evidence_audit_last_hash_cache = ThreadSafeCache(ttl=3600, max_size=1) diff --git a/backend/models.py b/backend/models.py index 71c35605..dd93ddcd 100644 --- a/backend/models.py +++ b/backend/models.py @@ -323,6 +323,10 @@ class ResolutionProofToken(Base): valid_from = Column(DateTime, nullable=True) valid_until = Column(DateTime, nullable=True) + # Blockchain integrity fields + integrity_hash = Column(String, nullable=True) + previous_integrity_hash = Column(String, nullable=True, index=True) + # Relationship grievance = relationship("Grievance", back_populates="resolution_tokens") diff --git a/backend/resolution_proof_service.py b/backend/resolution_proof_service.py index ea142571..d5d71ef1 100644 --- a/backend/resolution_proof_service.py +++ b/backend/resolution_proof_service.py @@ -26,7 +26,7 @@ EvidenceAuditLog, VerificationStatus, GrievanceStatus ) from backend.config import get_config, get_auth_config -from backend.cache import resolution_last_hash_cache, evidence_audit_last_hash_cache +from backend.cache import resolution_last_hash_cache, evidence_audit_last_hash_cache, token_last_hash_cache logger = logging.getLogger(__name__) @@ -189,6 +189,22 @@ def generate_proof_token( signature = ResolutionProofService._sign_payload(payload) + # Generate Integrity Hash + prev_hash = token_last_hash_cache.get("last_hash") + if prev_hash is None: + # Cache miss: Fetch only the last hash from DB + last_record = db.query(ResolutionProofToken.integrity_hash).order_by(ResolutionProofToken.id.desc()).first() + prev_hash = last_record[0] if last_record and last_record[0] else "" + token_last_hash_cache.set(data=prev_hash, key="last_hash") + + hash_content = f"{token_uuid}|{grievance_id}|{authority_email}|{now.isoformat()}|{prev_hash}" + secret_key = get_auth_config().secret_key + integrity_hash = hmac.new( + secret_key.encode('utf-8'), + hash_content.encode('utf-8'), + hashlib.sha256 + ).hexdigest() + # Create token record token = ResolutionProofToken( token_id=token_uuid, @@ -203,12 +219,16 @@ def generate_proof_token( nonce=nonce, token_signature=signature, is_used=False, + integrity_hash=integrity_hash, + previous_integrity_hash=prev_hash, ) db.add(token) db.commit() db.refresh(token) + token_last_hash_cache.set(data=integrity_hash, key="last_hash") + logger.info( f"Generated RPT {token_uuid} for grievance {grievance_id} " f"by {authority_email}, expires {valid_until.isoformat()}"