Skip to content

Add failed randomizer post-processing state#68

Merged
punk6529 merged 4 commits into
mainfrom
codex/randomizer-failed-state
Jun 10, 2026
Merged

Add failed randomizer post-processing state#68
punk6529 merged 4 commits into
mainfrom
codex/randomizer-failed-state

Conversation

@punk6529

@punk6529 punk6529 commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add an observable FailedPostProcessing lifecycle state when deterministic core hash-writing fails after provider output has been accepted
  • store the derived seed and failure-data hash, clear pending counts, and prevent duplicate callbacks/stale marking from overwriting failed requests
  • cover both VRF and arRNG adapters, plus update ADR/status/roadmap/test traceability docs

Closes #40

Validation

  • forge test --match-contract StreamRandomizerLifecycleTest -vvv (18 tests)
  • make check (160 tests)
  • powershell -ExecutionPolicy Bypass -File scripts\check.ps1 (160 tests)
  • forge fmt --check smart-contracts\RandomizerVRF.sol smart-contracts\RandomizerRNG.sol smart-contracts\StreamRandomizerLifecycle.sol test\StreamRandomizerLifecycle.t.sol test\mocks\MockRandomizerCore.sol
  • git diff --check
  • docs traceability grep for P0-RAND-004, FailedPostProcessing, failureDataHash, RandomnessPostProcessingFailed, and the active work item
  • Markdown heading scan for changed docs and run-state files

Static Analysis

  • .venv-tools\Scripts\slither.exe . --config-file slither.config.json --foundry-compile-all --json <temp-file>
  • accepted non-zero baseline: slither_exit=-1 total=685 high=9 medium=29 weak-prng=2 arbitrary-send-eth=0 reentrancy-eth=0 reentrancy-no-eth=0 reentrancy-events=22
  • Slither suppressions are scoped to the VRF/arRNG external core post-processing blocks. The lifecycle marks the request non-pending before the external core write, so duplicate callbacks and stale marking fail during reentry; post-call writes only emit/record deterministic success or failure outcomes.

Notes

Summary by CodeRabbit

  • New Features

    • Failed post-processing requests are now observable, recorded with derived seed and failure-data hash, and emit a failure event; duplicate callbacks are rejected.
  • Bug Fixes

    • Deterministic post-processing failures no longer roll back to pending and clear pending counters correctly.
  • Tests

    • Added tests covering failed post-processing for VRF and arRNG lifecycles.
  • Documentation

    • Updated ADRs, roadmap, status, and ops docs to reflect the new failed post-processing behavior and follow-ups.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@punk6529

Copy link
Copy Markdown
Contributor Author

@claude review

@punk6529

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@punk6529

Copy link
Copy Markdown
Contributor Author

@claude review

@punk6529

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Code review skipped — your organization has reached its monthly code review spending cap.

An organization admin can view or raise the cap at claude.ai/admin-settings/claude-code. The cap resets at the start of the next billing period.

Once the cap resets or is raised, comment @claude review on this pull request to trigger a review.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6323464c-17c4-4f86-8682-01d3ca6b44a8

📥 Commits

Reviewing files that changed from the base of the PR and between 47754b2 and 06ed909.

📒 Files selected for processing (2)
  • ops/AUTONOMOUS_RUN.md
  • test/mocks/MockRandomizerCore.sol
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/mocks/MockRandomizerCore.sol
  • ops/AUTONOMOUS_RUN.md

📝 Walkthrough

Walkthrough

This PR adds a FailedPostProcessing lifecycle state: adapters guard GenCore token-hash writes with try/catch, transition requests to FailedPostProcessing on revert while recording derived seed and failureDataHash, clear pending counts, emit RandomnessPostProcessingFailed, and add tests, mocks, ADR/docs, and ops updates reflecting the behavior.

Changes

Failed Post-Processing State Implementation

Layer / File(s) Summary
Lifecycle data model and state machine
smart-contracts/StreamRandomizerLifecycle.sol
RandomnessRequest gains failureDataHash. New RandomnessRequestNotFulfilled error and RandomnessPostProcessingFailed event added. Fulfillment now resets failureDataHash and uses _confirmRandomnessFulfillment or _markRandomnessPostProcessingFailed to emit RandomnessFulfilled or RandomnessPostProcessingFailed and transition state.
VRF adapter error handling
smart-contracts/RandomizerVRF.sol
fulfillRandomWords wraps gencoreContract.setTokenHash and confirmation emission in try/catch; success routes to _confirmRandomnessFulfillment, revert routes to _markRandomnessPostProcessingFailed.
RNG adapter error handling
smart-contracts/RandomizerRNG.sol
fulfillRandomWords wraps gencoreContract.setTokenHash in try/catch; on success confirms fulfillment, on revert records post-processing failure; Slither reentrancy suppressions added.
Test mock token-hash rejection support
test/mocks/MockRandomizerCore.sol
Adds MockTokenHashRejected error, rejectTokenHash flag, setRejectTokenHash(bool), conditional-revert setTokenHash(...), and retrieveTokenHash(...) to simulate deterministic post-processing failures.
Test coverage for post-processing failures
test/StreamRandomizerLifecycle.t.sol
Adds RANDOMNESS_POST_PROCESSING_FAILED_TOPIC, VRF and arRNG tests verifying RandomnessPostProcessingFailed event contents, request state transitions to FailedPostProcessing with derived-seed and failureDataHash, cleared pending counters, rejection of duplicate callbacks, and _assertRandomnessPostProcessingFailed(...) helper.
Architecture and project tracking documentation & ops
docs/adr/0005-randomness.md, docs/known-blockers.md, docs/status.md, test/README.md, ops/AUTONOMOUS_RUN.md, ops/ROADMAP.md
ADR and docs updated to reflect failure-data hash storage and event parameter rename; known-blockers/status/roadmap/test README updated to include failed post-processing as observable and tested for VRF/arRNG adapters; ops runbook and worklog updated for PR tracking and validation checklist.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

  • 6529-Collections/6529Stream#66: Related lifecycle struct/view changes that this PR evolves by adding failureDataHash and eventing.
  • 6529-Collections/6529Stream#65: Introduced the StreamRandomizerLifecycle request-state framework that this PR extends with FailedPostProcessing and guarded adapter fulfill flows.

Poem

🐰 When a token write goes astray,
I store the seed and hash away.
FailedPostProcessing marks the trace,
No duplicate callbacks replace.
Hop—now failures have their place.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding a failed post-processing state to the randomizer lifecycle system.
Linked Issues check ✅ Passed The PR implements all required coding objectives from #40: canonical failed state with FailedPostProcessing enum, metadata pending behavior from explicit state, deterministic post-processing failure recording with derived seed/hash, state transition events with required context, and comprehensive test coverage for all state paths.
Out of Scope Changes check ✅ Passed All changes align with #40 scope: core lifecycle state implementation, adapter integration, event emissions, test coverage, and documentation updates. Retry/re-request entry points correctly remain out of scope per PR notes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/randomizer-failed-state

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/mocks/MockRandomizerCore.sol (1)

26-31: ⚡ Quick win

Align mock setTokenHash semantics with StreamCore to avoid false-positive tests.

setTokenHash currently allows any caller and silent overwrites. Since this mock already tracks randomizer and token collection mappings, mirroring core guards will keep lifecycle tests realistic and prevent masking authorization/overwrite regressions.

Suggested patch
 function setTokenHash(uint256, uint256 tokenId, bytes32 tokenHash) external {
     if (rejectTokenHash) {
         revert MockTokenHashRejected();
     }
+    uint256 collectionId = tokenCollections[tokenId];
+    require(msg.sender == randomizerContracts[collectionId], "unauthorized randomizer");
+    require(tokenHashes[tokenId] == bytes32(0), "token hash already set");
     tokenHashes[tokenId] = tokenHash;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/mocks/MockRandomizerCore.sol` around lines 26 - 31, The mock's
setTokenHash presently allows any caller and silently overwrites tokenHashes,
which diverges from StreamCore; update setTokenHash to enforce the same
authorization and overwrite guards as StreamCore by (1) requiring msg.sender is
the registered randomizer for the token's collection (use the mock's
collection->randomizer mapping or randomizerForCollection lookup) and (2)
preventing silent overwrites by reverting if tokenHashes[tokenId] is already set
(unless a dedicated overwrite flag exists), while preserving the existing
rejectTokenHash revert path; update references to tokenHashes, rejectTokenHash
and the mock's collection/randomizer mappings in setTokenHash accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@smart-contracts/StreamRandomizerLifecycle.sol`:
- Around line 79-85: The RandomnessPostProcessingFailed event is missing
provider and randomizerEpoch context; update the RandomnessPostProcessingFailed
event declaration to include address provider and uint256 randomizerEpoch (in
the same indexed/not-indexed pattern as other lifecycle events) and then update
every emission site that fires RandomnessPostProcessingFailed (and the related
duplicate declarations at the other occurrence of the event) to pass the current
provider and randomizerEpoch values so indexers can correlate failures without
extra storage lookups; search for RandomnessPostProcessingFailed and add the two
arguments to the event signature and all emit calls.

---

Nitpick comments:
In `@test/mocks/MockRandomizerCore.sol`:
- Around line 26-31: The mock's setTokenHash presently allows any caller and
silently overwrites tokenHashes, which diverges from StreamCore; update
setTokenHash to enforce the same authorization and overwrite guards as
StreamCore by (1) requiring msg.sender is the registered randomizer for the
token's collection (use the mock's collection->randomizer mapping or
randomizerForCollection lookup) and (2) preventing silent overwrites by
reverting if tokenHashes[tokenId] is already set (unless a dedicated overwrite
flag exists), while preserving the existing rejectTokenHash revert path; update
references to tokenHashes, rejectTokenHash and the mock's collection/randomizer
mappings in setTokenHash accordingly.
🪄 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: b33a945c-d53d-4efa-babe-e08caaa91f23

📥 Commits

Reviewing files that changed from the base of the PR and between 428cbc8 and 495d30d.

📒 Files selected for processing (11)
  • docs/adr/0005-randomness.md
  • docs/known-blockers.md
  • docs/status.md
  • ops/AUTONOMOUS_RUN.md
  • ops/ROADMAP.md
  • smart-contracts/RandomizerRNG.sol
  • smart-contracts/RandomizerVRF.sol
  • smart-contracts/StreamRandomizerLifecycle.sol
  • test/README.md
  • test/StreamRandomizerLifecycle.t.sol
  • test/mocks/MockRandomizerCore.sol

Comment on lines +79 to +85
event RandomnessPostProcessingFailed(
uint256 indexed requestId,
uint256 indexed collectionId,
uint256 indexed tokenId,
bytes32 derivedSeed,
bytes32 failureDataHash
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Include provider and epoch in RandomnessPostProcessingFailed.

This is a new lifecycle transition event, but it omits provider and randomizerEpoch. The linked issue requires state-transition events to carry that context, and without it indexers have to do an extra storage lookup to correlate failures across adapter/epoch changes.

Proposed diff
     event RandomnessPostProcessingFailed(
         uint256 indexed requestId,
         uint256 indexed collectionId,
         uint256 indexed tokenId,
+        address provider,
+        uint256 randomizerEpoch,
         bytes32 derivedSeed,
         bytes32 failureDataHash
     );
@@
         emit RandomnessPostProcessingFailed(
-            _requestId, request.collectionId, request.tokenId, request.derivedSeed, failureDataHash
+            _requestId,
+            request.collectionId,
+            request.tokenId,
+            request.provider,
+            request.randomizerEpoch,
+            request.derivedSeed,
+            failureDataHash
         );

Also applies to: 262-264

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@smart-contracts/StreamRandomizerLifecycle.sol` around lines 79 - 85, The
RandomnessPostProcessingFailed event is missing provider and randomizerEpoch
context; update the RandomnessPostProcessingFailed event declaration to include
address provider and uint256 randomizerEpoch (in the same indexed/not-indexed
pattern as other lifecycle events) and then update every emission site that
fires RandomnessPostProcessingFailed (and the related duplicate declarations at
the other occurrence of the event) to pass the current provider and
randomizerEpoch values so indexers can correlate failures without extra storage
lookups; search for RandomnessPostProcessingFailed and add the two arguments to
the event signature and all emit calls.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 47754b2: RandomnessPostProcessingFailed now includes provider and randomizerEpoch, all emit sites pass the stored request context, tests decode/assert both fields, and ADR/roadmap/test/run-state docs were updated.

@punk6529

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@punk6529 punk6529 merged commit 0c46384 into main Jun 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P0-RAND-004] Add pending, fulfilled, stale, and failed randomness states

1 participant