⚡ Bolt: Resolution Evidence Blockchain & Performance Optimization#629
⚡ Bolt: Resolution Evidence Blockchain & Performance Optimization#629RohanExploit wants to merge 1 commit into
Conversation
…cation
- Added `integrity_hash` and `previous_integrity_hash` columns to `ResolutionEvidence` model.
- Implemented cryptographic chaining (HMAC-SHA256) in `ResolutionProofService.submit_evidence`.
- Optimized `ResolutionProofService.verify_evidence` to use `.count()` and fetching only the latest record instead of materializing all records.
- Integrated `resolution_last_hash_cache` (ThreadSafeCache) for O(1) previous hash retrieval during submission.
- Added `/api/resolution-proof/{evidence_id}/blockchain-verify` endpoint for O(1) single-record integrity validation.
- Fixed `ResolutionProofToken` model to explicitly store `valid_from`, `valid_until`, and `nonce` for secure signing and satisfy `expires_at` NOT NULL constraint.
- Updated `backend/init_db.py` with required schema migrations.
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
❌ Deploy Preview for fixmybharat failed. Why did it fail? →
|
🙏 Thank you for your contribution, @RohanExploit!PR Details:
Quality Checklist:
Review Process:
Note: The maintainers will monitor code quality and ensure the overall project flow isn't broken. |
📝 WalkthroughWalkthroughThe changes implement blockchain-style integrity chaining for resolution evidence. A new thread-safe cache stores the last integrity hash, database migrations add chaining columns and token validity fields, cryptographic signing chains evidence submissions, and a new verification endpoint validates integrity chains against stored hashes. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Router as resolution_proof<br/>Router
participant Service as ResolutionProof<br/>Service
participant DB as Database
participant Cache as Cache
participant Crypto as Signing
Client->>Router: POST submit evidence<br/>(token_id, evidence)
Router->>Service: submit_evidence(token_id, evidence)
Service->>Cache: get(resolution_last_hash_cache)
alt Cache hit
Cache-->>Service: previous_hash
else Cache miss
Service->>DB: query ResolutionEvidence<br/>order_by desc limit 1
DB-->>Service: most recent record
Service->>Service: extract previous_hash<br/>from DB
end
Service->>Crypto: sign(evidence_hash|token_id|prev_hash)
Crypto-->>Service: integrity_hash
Service->>DB: create ResolutionEvidence<br/>(integrity_hash, previous_hash)
DB-->>Service: commit success
Service->>Cache: set(resolution_last_hash_cache,<br/>integrity_hash)
Cache-->>Service: cached
Service-->>Router: success response
Router-->>Client: 201 Created
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR extends the Resolution Proof system with blockchain-style integrity chaining for ResolutionEvidence and adds performance optimizations to reduce unnecessary DB materialization during verification and evidence submission.
Changes:
- Adds HMAC-SHA256 integrity chaining to resolution evidence creation (with cached “last hash” lookup) and persists
integrity_hash+previous_integrity_hash. - Optimizes resolution verification to use
.count()and fetch only the latest evidence record. - Introduces a new per-evidence blockchain verification endpoint and adds DB migrations/fields to align
ResolutionProofTokenpersistence with the service/schema expectations.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| backend/routers/resolution_proof.py | Adds an evidence-level blockchain verification endpoint. |
| backend/resolution_proof_service.py | Adds integrity chaining during submission + verification query optimizations. |
| backend/models.py | Adds integrity chain columns to ResolutionEvidence and new token fields to ResolutionProofToken. |
| backend/init_db.py | Adds migrations for the new evidence/token columns and index. |
| backend/cache.py | Adds a dedicated cache instance for resolution evidence last-hash. |
| .jules/bolt.md | Documents learnings around cache safety and verification optimizations. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Performance Boost: Use thread-safe cache for O(1) last hash retrieval | ||
| prev_hash = resolution_last_hash_cache.get("last_hash") | ||
| if prev_hash is None: | ||
| # Cache miss: fetch ONLY the last hash from DB | ||
| last_record = db.query(ResolutionEvidence.integrity_hash).order_by(ResolutionEvidence.id.desc()).first() | ||
| prev_hash = last_record[0] if last_record and last_record[0] else "" | ||
| resolution_last_hash_cache.set(data=prev_hash, key="last_hash") | ||
|
|
There was a problem hiding this comment.
submit_evidence() derives prev_hash from an in-memory cache without validating it against the current DB tail. In multi-worker deployments (or after another process writes newer evidence), this can cause previous_integrity_hash to point to a hash that is no longer the latest persisted record, weakening the intended append-only chain semantics.
Suggestion: treat the cache as a hint only—fetch (last_id, last_hash) from DB and compare against cached values (or store a single cached tuple) before computing the new integrity_hash; refresh the cache on mismatch. If strict linear chaining is required under concurrency, compute prev_hash inside a serialized/locked transaction rather than relying on the cache.
| # Performance Boost: Use thread-safe cache for O(1) last hash retrieval | |
| prev_hash = resolution_last_hash_cache.get("last_hash") | |
| if prev_hash is None: | |
| # Cache miss: fetch ONLY the last hash from DB | |
| last_record = db.query(ResolutionEvidence.integrity_hash).order_by(ResolutionEvidence.id.desc()).first() | |
| prev_hash = last_record[0] if last_record and last_record[0] else "" | |
| resolution_last_hash_cache.set(data=prev_hash, key="last_hash") | |
| # Treat the cache as a hint only: validate against the current DB tail | |
| cached_tail = resolution_last_hash_cache.get("last_evidence_tail") | |
| last_record = ( | |
| db.query(ResolutionEvidence.id, ResolutionEvidence.integrity_hash) | |
| .order_by(ResolutionEvidence.id.desc()) | |
| .first() | |
| ) | |
| db_tail = ( | |
| (last_record[0], last_record[1] or "") | |
| if last_record | |
| else (None, "") | |
| ) | |
| if cached_tail != db_tail: | |
| resolution_last_hash_cache.set(data=db_tail, key="last_evidence_tail") | |
| prev_hash = db_tail[1] |
| valid_from = Column(DateTime, default=lambda: datetime.datetime.now(datetime.timezone.utc)) | ||
| valid_until = Column(DateTime, nullable=True) | ||
| nonce = Column(String, nullable=True) | ||
| generated_at = Column(DateTime, default=lambda: datetime.datetime.now(datetime.timezone.utc)) | ||
| expires_at = Column(DateTime, nullable=False) |
There was a problem hiding this comment.
The new valid_from/valid_until/nonce columns are defined as nullable, but the service logic (validate_token() and timestamp window checks) assumes these fields are always present and will raise if they are NULL.
Suggestion: make these columns non-nullable (and ensure generate_proof_token() always sets them), or update service logic to fall back to legacy fields (generated_at/expires_at) when the new columns are missing so existing rows don’t break runtime validation.
| if not column_exists("resolution_proof_tokens", "valid_from"): | ||
| conn.execute(text("ALTER TABLE resolution_proof_tokens ADD COLUMN valid_from DATETIME")) | ||
| logger.info("Added valid_from column to resolution_proof_tokens") | ||
|
|
||
| if not column_exists("resolution_proof_tokens", "valid_until"): | ||
| conn.execute(text("ALTER TABLE resolution_proof_tokens ADD COLUMN valid_until DATETIME")) | ||
| logger.info("Added valid_until column to resolution_proof_tokens") | ||
|
|
||
| if not column_exists("resolution_proof_tokens", "nonce"): | ||
| conn.execute(text("ALTER TABLE resolution_proof_tokens ADD COLUMN nonce VARCHAR")) | ||
| logger.info("Added nonce column to resolution_proof_tokens") | ||
|
|
There was a problem hiding this comment.
Migration adds valid_from, valid_until, and nonce to resolution_proof_tokens but doesn’t backfill existing rows. Any still-valid pre-migration token rows will have NULL in these columns, which can break validate_token() (it reads token.valid_until / token.valid_from / token.nonce).
Suggestion: add a one-time backfill step after adding the columns (e.g., set valid_from=generated_at, valid_until=expires_at where null). If nonce is required for signature verification, either backfill from existing token payload data (if stored) or adjust signature verification to handle legacy tokens explicitly.
| if not column_exists("resolution_proof_tokens", "valid_from"): | |
| conn.execute(text("ALTER TABLE resolution_proof_tokens ADD COLUMN valid_from DATETIME")) | |
| logger.info("Added valid_from column to resolution_proof_tokens") | |
| if not column_exists("resolution_proof_tokens", "valid_until"): | |
| conn.execute(text("ALTER TABLE resolution_proof_tokens ADD COLUMN valid_until DATETIME")) | |
| logger.info("Added valid_until column to resolution_proof_tokens") | |
| if not column_exists("resolution_proof_tokens", "nonce"): | |
| conn.execute(text("ALTER TABLE resolution_proof_tokens ADD COLUMN nonce VARCHAR")) | |
| logger.info("Added nonce column to resolution_proof_tokens") | |
| has_valid_from = column_exists("resolution_proof_tokens", "valid_from") | |
| if not has_valid_from: | |
| conn.execute(text("ALTER TABLE resolution_proof_tokens ADD COLUMN valid_from DATETIME")) | |
| logger.info("Added valid_from column to resolution_proof_tokens") | |
| has_valid_from = True | |
| has_valid_until = column_exists("resolution_proof_tokens", "valid_until") | |
| if not has_valid_until: | |
| conn.execute(text("ALTER TABLE resolution_proof_tokens ADD COLUMN valid_until DATETIME")) | |
| logger.info("Added valid_until column to resolution_proof_tokens") | |
| has_valid_until = True | |
| has_nonce = column_exists("resolution_proof_tokens", "nonce") | |
| if not has_nonce: | |
| conn.execute(text("ALTER TABLE resolution_proof_tokens ADD COLUMN nonce VARCHAR")) | |
| logger.info("Added nonce column to resolution_proof_tokens") | |
| has_nonce = True | |
| has_generated_at = column_exists("resolution_proof_tokens", "generated_at") | |
| has_expires_at = column_exists("resolution_proof_tokens", "expires_at") | |
| if has_valid_from and has_generated_at: | |
| conn.execute(text( | |
| "UPDATE resolution_proof_tokens " | |
| "SET valid_from = generated_at " | |
| "WHERE valid_from IS NULL AND generated_at IS NOT NULL" | |
| )) | |
| logger.info("Backfilled valid_from from generated_at for legacy resolution_proof_tokens rows") | |
| if has_valid_until and has_expires_at: | |
| conn.execute(text( | |
| "UPDATE resolution_proof_tokens " | |
| "SET valid_until = expires_at " | |
| "WHERE valid_until IS NULL AND expires_at IS NOT NULL" | |
| )) | |
| logger.info("Backfilled valid_until from expires_at for legacy resolution_proof_tokens rows") | |
| if has_nonce: | |
| if column_exists("resolution_proof_tokens", "token"): | |
| conn.execute(text( | |
| "UPDATE resolution_proof_tokens " | |
| "SET nonce = token " | |
| "WHERE nonce IS NULL AND token IS NOT NULL" | |
| )) | |
| logger.info("Backfilled nonce from token for legacy resolution_proof_tokens rows") | |
| else: | |
| logger.warning( | |
| "resolution_proof_tokens.nonce exists but no legacy source column was found for backfill; " | |
| "legacy rows may require explicit compatibility handling during validation." | |
| ) |
| evidence = db.query( | ||
| ResolutionEvidence.evidence_hash, | ||
| ResolutionEvidence.token_id, | ||
| ResolutionEvidence.integrity_hash, | ||
| ResolutionEvidence.previous_integrity_hash | ||
| ).filter(ResolutionEvidence.id == evidence_id).first() | ||
|
|
||
| if not evidence: | ||
| raise HTTPException(status_code=404, detail="Evidence not found") | ||
|
|
||
| # Determine previous hash (O(1) from stored column) | ||
| prev_hash = evidence.previous_integrity_hash or "" | ||
|
|
||
| # Fetch token_id string for chaining logic consistency | ||
| from backend.models import ResolutionProofToken | ||
| token = db.query(ResolutionProofToken.token_id).filter(ResolutionProofToken.id == evidence.token_id).first() | ||
| token_id_str = token[0] if token else "" | ||
|
|
There was a problem hiding this comment.
/{evidence_id}/blockchain-verify currently does an extra query to fetch the token UUID (ResolutionProofToken.token_id) and silently falls back to "" when the token row is missing. That can both (a) undercut the stated O(1) optimization (2 DB round-trips) and (b) report a misleading “integrity check failed” when the real problem is a missing/invalid token reference.
Suggestion: fetch ResolutionProofToken.token_id via a join in the initial query (single round-trip), and if the token is missing, return an explicit error/invalid state indicating the evidence’s token reference can’t be resolved.
There was a problem hiding this comment.
1 issue found across 6 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="backend/resolution_proof_service.py">
<violation number="1" location="backend/resolution_proof_service.py:375">
P1: The cache-based `prev_hash` lookup is not atomic with the subsequent insert+commit, so concurrent `submit_evidence` calls will read the same `prev_hash` and produce two records chaining off the same predecessor — forking the integrity chain. A `SELECT ... FOR UPDATE` or database-level advisory lock is needed to serialize chain extension and ensure each new record links to the true latest hash.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
|
|
||
| # 5b. Implement cryptographic chaining (Issue #BLOCKCHAIN-003) | ||
| # Performance Boost: Use thread-safe cache for O(1) last hash retrieval | ||
| prev_hash = resolution_last_hash_cache.get("last_hash") |
There was a problem hiding this comment.
P1: The cache-based prev_hash lookup is not atomic with the subsequent insert+commit, so concurrent submit_evidence calls will read the same prev_hash and produce two records chaining off the same predecessor — forking the integrity chain. A SELECT ... FOR UPDATE or database-level advisory lock is needed to serialize chain extension and ensure each new record links to the true latest hash.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/resolution_proof_service.py, line 375:
<comment>The cache-based `prev_hash` lookup is not atomic with the subsequent insert+commit, so concurrent `submit_evidence` calls will read the same `prev_hash` and produce two records chaining off the same predecessor — forking the integrity chain. A `SELECT ... FOR UPDATE` or database-level advisory lock is needed to serialize chain extension and ensure each new record links to the true latest hash.</comment>
<file context>
@@ -368,6 +370,19 @@ def submit_evidence(
+ # 5b. Implement cryptographic chaining (Issue #BLOCKCHAIN-003)
+ # Performance Boost: Use thread-safe cache for O(1) last hash retrieval
+ prev_hash = resolution_last_hash_cache.get("last_hash")
+ if prev_hash is None:
+ # Cache miss: fetch ONLY the last hash from DB
</file context>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
backend/resolution_proof_service.py (1)
373-412:⚠️ Potential issue | 🔴 CriticalThe chain head still races under concurrent submissions.
A thread-safe cache does not make the append operation atomic. Two requests, or two workers with stale in-memory caches, can read the same
prev_hash, insert different rows with the sameprevious_integrity_hash, and both commit successfully. That forks the chain while/blockchain-verifystill reports each row as valid because it only recomputes the local seal. Serialize head selection in the database or enforce a uniqueness/retry guard there, then keep the cache as a post-commit optimization.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/resolution_proof_service.py` around lines 373 - 412, The current prepend is racy because reading resolution_last_hash_cache and inserting a new ResolutionEvidence is not atomic; serialize head selection in the DB and add a uniqueness/retry guard: enforce a DB-level uniqueness constraint on ResolutionEvidence.previous_integrity_hash (allowing empty/genesis), and change the create flow to (a) obtain the true current head with a serializing read (e.g., SELECT ... ORDER BY id DESC FOR UPDATE on the last row or use a single-row chain_head table and lock it), (b) compute integrity_hash (ResolutionProofService._sign_payload) and insert the new ResolutionEvidence, and (c) on unique-constraint violation (IntegrityError) retry the read-sign-insert loop a few times before failing; keep updating resolution_last_hash_cache only after a successful commit.
🧹 Nitpick comments (1)
backend/routers/resolution_proof.py (1)
233-249: Use the token UUID already sealed with the evidence.This re-queries
ResolutionProofToken.token_id, so historical verification now depends on that row still existing and remaining unchanged. The UUID is already captured inResolutionEvidence.metadata_bundleat submission time, which is the stable value that was actually sealed. Prefer that snapshot, or denormalize it into a dedicated column, so old evidence keeps verifying even if expired tokens are cleaned up later.♻️ Possible simplification
- evidence = db.query( - ResolutionEvidence.evidence_hash, - ResolutionEvidence.token_id, - ResolutionEvidence.integrity_hash, - ResolutionEvidence.previous_integrity_hash - ).filter(ResolutionEvidence.id == evidence_id).first() + evidence = db.query( + ResolutionEvidence.evidence_hash, + ResolutionEvidence.metadata_bundle, + ResolutionEvidence.integrity_hash, + ResolutionEvidence.previous_integrity_hash, + ).filter(ResolutionEvidence.id == evidence_id).first() ... - from backend.models import ResolutionProofToken - token = db.query(ResolutionProofToken.token_id).filter(ResolutionProofToken.id == evidence.token_id).first() - token_id_str = token[0] if token else "" + token_id_str = (evidence.metadata_bundle or {}).get("token_id", "")🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/routers/resolution_proof.py` around lines 233 - 249, The code re-queries ResolutionProofToken.token_id using evidence.token_id (in the block that assigns token_id_str), which makes verification depend on a separate token row that can be deleted or changed; instead read the sealed UUID from ResolutionEvidence.metadata_bundle (or add a dedicated column populated at submission) and use that value for token_id_str so historical evidence verification uses the immutable sealed snapshot; update the logic in the function interacting with ResolutionEvidence (referencing ResolutionEvidence.metadata_bundle and token_id_str) to parse/extract the UUID from metadata_bundle and fall back to the denormalized column if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@backend/init_db.py`:
- Around line 223-235: After adding the three nullable columns to
resolution_proof_tokens, add a data migration that (1) backfills
valid_from/valid_until from the table's existing legacy timestamp column(s)
(e.g., created_at or issued_at) so validate_token() has timezone-aware
datetimes, and (2) handles rows missing nonce by either setting valid_until to
now (explicitly expiring them) or generating a new nonce and rebuilding the HMAC
using ResolutionProofService (so future calls to
ResolutionProofService.validate_token() won't fail); implement this immediately
after the ALTER TABLEs using the same conn.execute/inspector flow (use
column_exists, conn.execute(text(...)) and ResolutionProofService methods to
recompute tokens as needed).
---
Outside diff comments:
In `@backend/resolution_proof_service.py`:
- Around line 373-412: The current prepend is racy because reading
resolution_last_hash_cache and inserting a new ResolutionEvidence is not atomic;
serialize head selection in the DB and add a uniqueness/retry guard: enforce a
DB-level uniqueness constraint on ResolutionEvidence.previous_integrity_hash
(allowing empty/genesis), and change the create flow to (a) obtain the true
current head with a serializing read (e.g., SELECT ... ORDER BY id DESC FOR
UPDATE on the last row or use a single-row chain_head table and lock it), (b)
compute integrity_hash (ResolutionProofService._sign_payload) and insert the new
ResolutionEvidence, and (c) on unique-constraint violation (IntegrityError)
retry the read-sign-insert loop a few times before failing; keep updating
resolution_last_hash_cache only after a successful commit.
---
Nitpick comments:
In `@backend/routers/resolution_proof.py`:
- Around line 233-249: The code re-queries ResolutionProofToken.token_id using
evidence.token_id (in the block that assigns token_id_str), which makes
verification depend on a separate token row that can be deleted or changed;
instead read the sealed UUID from ResolutionEvidence.metadata_bundle (or add a
dedicated column populated at submission) and use that value for token_id_str so
historical evidence verification uses the immutable sealed snapshot; update the
logic in the function interacting with ResolutionEvidence (referencing
ResolutionEvidence.metadata_bundle and token_id_str) to parse/extract the UUID
from metadata_bundle and fall back to the denormalized column if needed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ab7cbda5-b53a-465a-b007-96320290d537
📒 Files selected for processing (6)
.jules/bolt.mdbackend/cache.pybackend/init_db.pybackend/models.pybackend/resolution_proof_service.pybackend/routers/resolution_proof.py
| # Resolution Proof Tokens Table Migrations | ||
| if inspector.has_table("resolution_proof_tokens"): | ||
| if not column_exists("resolution_proof_tokens", "valid_from"): | ||
| conn.execute(text("ALTER TABLE resolution_proof_tokens ADD COLUMN valid_from DATETIME")) | ||
| logger.info("Added valid_from column to resolution_proof_tokens") | ||
|
|
||
| if not column_exists("resolution_proof_tokens", "valid_until"): | ||
| conn.execute(text("ALTER TABLE resolution_proof_tokens ADD COLUMN valid_until DATETIME")) | ||
| logger.info("Added valid_until column to resolution_proof_tokens") | ||
|
|
||
| if not column_exists("resolution_proof_tokens", "nonce"): | ||
| conn.execute(text("ALTER TABLE resolution_proof_tokens ADD COLUMN nonce VARCHAR")) | ||
| logger.info("Added nonce column to resolution_proof_tokens") |
There was a problem hiding this comment.
Handle legacy resolution_proof_tokens rows during this migration.
Lines 225-234 only add valid_from, valid_until, and nonce as nullable columns. ResolutionProofService.validate_token() now treats those fields as required when checking expiry and rebuilding the HMAC, so any still-live token created before this migration can start failing validation or blow up on valid_until.tzinfo. Add a data migration that backfills valid_from/valid_until from the legacy timestamps and explicitly expires or regenerates rows that have no nonce.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@backend/init_db.py` around lines 223 - 235, After adding the three nullable
columns to resolution_proof_tokens, add a data migration that (1) backfills
valid_from/valid_until from the table's existing legacy timestamp column(s)
(e.g., created_at or issued_at) so validate_token() has timezone-aware
datetimes, and (2) handles rows missing nonce by either setting valid_until to
now (explicitly expiring them) or generating a new nonce and rebuilding the HMAC
using ResolutionProofService (so future calls to
ResolutionProofService.validate_token() won't fail); implement this immediately
after the ALTER TABLEs using the same conn.execute/inspector flow (use
column_exists, conn.execute(text(...)) and ResolutionProofService methods to
recompute tokens as needed).
This optimization implements blockchain-style cryptographic integrity chaining for the Resolution Proof system while significantly improving performance through O(1) lookups and database query optimizations.
💡 What:
.count()) and limit-based fetching (.first()).ResolutionProofTokento support secure token signing and database constraints.🎯 Why:
📊 Impact:
🔬 Measurement:
pytest tests/test_resolution_proof.py(30 tests) and full blockchain test suite (42 tests total).sqlite3PRAGMA inspection.PR created automatically by Jules for task 14891178781287473821 started by @RohanExploit
Summary by cubic
Adds blockchain-style HMAC-SHA256 chaining to resolution evidence and an O(1) integrity verification endpoint, while cutting DB load during submission and verification. Improves latency by caching the last hash and avoiding full-record scans.
New Features
/api/resolution-proof/{evidence_id}/blockchain-verifyfor single-record integrity checks.expires_atset explicitly for compatibility.Performance
resolution_last_hash_cacheenables O(1) previous-hash lookup; cache updates only after successful commit..count()and fetches only the latest record (.first()), avoiding materializing all evidence.Written for commit 011f375. Summary will update on new commits.
Summary by CodeRabbit
New Features
Performance Improvements