Skip to content

Conversation

@UdjinM6
Copy link

@UdjinM6 UdjinM6 commented Oct 28, 2025

Issue being fixed or feature implemented

What was done?

How Has This Been Tested?

Breaking Changes

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation
  • I have assigned this pull request to a milestone (for repository code-owners and collaborators only)

@UdjinM6 UdjinM6 added this to the 23.1 milestone Oct 28, 2025
@github-actions
Copy link

github-actions bot commented Oct 28, 2025

✅ No Merge Conflicts Detected

This PR currently has no conflicts with other open PRs.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Overview

Greptile Summary

This PR refactors the governance cleanup verification in feature_governance_cl.py by replacing a brittle 1-second sleep with explicit log assertions. The test now uses assert_debug_log to deterministically confirm that UpdateCachesAndClean scheduler events execute, then verifies cleanup completion via RPC calls. This approach eliminates race conditions where cleanup might not complete within the fixed sleep window. The change aligns with Dash Core's governance subsystem architecture where scheduled cleanup occurs in two phases: marking objects for deletion, then removing them after GOVERNANCE_DELETION_DELAY. The test exercises this flow by advancing mock time and triggering the scheduler explicitly.

PR Description Notes:

  • The PR description is completely empty - all fields (issue being fixed, what was done, how tested, breaking changes) are blank.

Important Files Changed

Filename Score Overview
test/functional/feature_governance_cl.py 2/5 Replaced time.sleep with deterministic log assertions but iterates over all nodes including isolated node 5, causing potential RPC failures; contains redundant mocktime assignments

Confidence score: 2/5

  • This PR has significant issues that could cause test failures and requires careful review before merging.
  • Score lowered because: (1) the code iterates over self.nodes including node 5 which remains isolated from the network, likely causing RPC failures when mockscheduler() is called on the disconnected node; (2) redundant node.mocktime assignments on lines145 and 153 have no effect since setmocktime() already updates internal time state; (3) the empty PR description provides no context for reviewers to understand the motivation or validate correctness.
  • Pay close attention to lines 143-155 where the node iteration occurs - verify that node 5's isolation doesn't break the mockscheduler() calls or consider excluding it from the loop.

Sequence Diagram

sequenceDiagram
    participant User
    participant Node0
    participant Nodes1_4 as "Nodes 1-4"
    participant Node5
    participant Blockchain
    participant GovernanceSystem as "Governance System"
    participant ChainLock as "ChainLock System"

    User->>Node0: "Enable DKG Spork"
    Node0->>Nodes1_4: "Sync spork update"
    User->>Node0: "Mine cycle quorum"
    Node0->>Blockchain: "Generate blocks"
    Blockchain->>ChainLock: "Activate ChainLocks"
    
    User->>Node0: "Enable Superblocks Spork"
    Node0->>Nodes1_4: "Sync spork update"
    
    User->>Node0: "Move to superblock cycle start"
    Node0->>Blockchain: "Generate blocks to cycle boundary"
    
    User->>Node0: "Prepare Proposal_0 and Proposal_1"
    Node0->>GovernanceSystem: "gobject prepare (P0 & P1)"
    GovernanceSystem-->>Node0: "Return collateral hashes"
    
    User->>Node0: "Wait 10 minutes (bump mocktime)"
    User->>Node0: "Generate 6 confirmation blocks"
    Node0->>Blockchain: "Mine 6 blocks"
    
    User->>Node0: "Submit proposals"
    Node0->>GovernanceSystem: "gobject submit (P0 & P1)"
    GovernanceSystem-->>Node0: "Store proposals"
    
    User->>Node5: "Isolate node 5"
    Node5--xNodes1_4: "Disconnect from network"
    
    User->>Node0: "Vote for proposals"
    Node0->>GovernanceSystem: "gobject vote-many (P0 & P1)"
    GovernanceSystem->>Nodes1_4: "Sync votes"
    Note over Node5: Node5 misses votes
    
    User->>Node0: "Move into superblock maturity window"
    Node0->>Blockchain: "Generate blocks"
    
    GovernanceSystem->>Nodes1_4: "Create trigger for superblock"
    Note over Node5: Node5 misses trigger
    
    User->>Node0: "Mine to superblock height"
    Node0->>Blockchain: "Generate remaining blocks"
    Node0->>Blockchain: "Mine superblock with payouts"
    Blockchain->>ChainLock: "Request ChainLock"
    ChainLock-->>Blockchain: "ChainLock superblock"
    
    User->>Node0: "Mine superblock_cycle + 1 blocks"
    loop sb_cycle + 1 times
        Node0->>Blockchain: "Generate block"
    end
    
    User->>Nodes1_4: "Bump time and trigger scheduler cleanup"
    Nodes1_4->>GovernanceSystem: "mockscheduler (5 min delta)"
    GovernanceSystem-->>Nodes1_4: "Mark old triggers for deletion"
    User->>Nodes1_4: "Bump time again and trigger cleanup"
    Nodes1_4->>GovernanceSystem: "mockscheduler (10 min delta)"
    GovernanceSystem->>GovernanceSystem: "Delete old triggers (UpdateCachesAndClean)"
    GovernanceSystem-->>Nodes1_4: "Triggers removed"
    
    User->>Node5: "Reconnect isolated node"
    Node5->>Node0: "Reconnect to network"
    Note over Node5: mnsync status: not synced
    
    User->>Node0: "Generate 1 block"
    Node0->>Blockchain: "Mine block"
    ChainLock->>Blockchain: "Create ChainLock"
    Blockchain->>Node5: "Sync via ChainLock"
    Note over Node5: Skips governance checks<br/>due to ChainLock coverage
Loading

Context used:

  • Context from dashboard - CLAUDE.md (source)

1 file reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@coderabbitai
Copy link

coderabbitai bot commented Oct 28, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

The functional test test/functional/feature_governance_cl.py was refactored to remove real-time sleep calls and drive governance cleanup using per-node mocked time and explicit mock-scheduler invocations. The test advances simulated time in two deltas (≈5 minutes then ≈10 minutes), calls setmocktime per node, runs the mock scheduler per node, and checks debug logs for "UpdateCachesAndClean" then verifies via RPC that the triggers list is emptied. It also adds handling for an isolated-node trigger-creation scenario and replaces sleeps with deterministic mocktime progression.

Sequence Diagram(s)

sequenceDiagram
    participant Test
    participant NodeA as Node A (daemon)
    participant NodeB as Node B (daemon)
    participant MockScheduler
    participant RPC as Governance RPC

    Note over Test,NodeA: Setup governance objects and nodes
    Test->>NodeA: create trigger/object
    Test->>NodeB: create trigger/object

    Note over Test,MockScheduler: Advance ~5 minutes to trigger cache cleaning
    Test->>NodeA: setmocktime(+5m)
    Test->>NodeB: setmocktime(+5m)
    Test->>MockScheduler: run scheduler on NodeA and NodeB
    MockScheduler->>NodeA: execute scheduled cleanup
    MockScheduler->>NodeB: execute scheduled cleanup
    NodeA-->>Test: debug-log "UpdateCachesAndClean" (assert)
    NodeB-->>Test: debug-log "UpdateCachesAndClean" (assert)

    Note over Test,MockScheduler: Advance additional ~10 minutes for deletion
    Test->>NodeA: setmocktime(+10m)
    Test->>NodeB: setmocktime(+10m)
    Test->>MockScheduler: run scheduler again on NodeA and NodeB
    MockScheduler->>NodeA: execute deletion tasks
    MockScheduler->>NodeB: execute deletion tasks

    Test->>RPC: getgovernanceinfo / list triggers
    RPC-->>Test: returns empty triggers list (assert)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

  • Files to focus on:
    • test/functional/feature_governance_cl.py: verify correct use of setmocktime, per-node advancement, and mockscheduler invocations.
    • Log assertions: ensure expected debug strings (e.g., "UpdateCachesAndClean") match emitted logs.
    • RPC/state checks: confirm trigger-listing RPC calls and empty-state assertions are correct.
    • Isolated-node logic: review conditional extra block generation and height-based trigger creation handling.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description Check ❓ Inconclusive The PR description consists entirely of an empty template with placeholder headings (Issue being fixed, What was done, How Has This Been Tested, Breaking Changes, and Checklist) but no actual content is provided in any section. This template structure conveys no meaningful information about the changeset whatsoever, making it impossible to understand what changes were made, why they were made, or how they were tested. The description provides no substance that can be related to the changeset content. The author should fill in the PR description template with actual content describing the changes made. At minimum, the "What was done?" section should explain that the test was refactored to replace sleep-based waiting with mocktime-driven scheduling and verification, and other template sections should be addressed appropriately (or marked as not applicable if certain sections don't apply).
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "test: improve trigger checks in feature_governance_cl.py" is directly related to the changeset, which focuses on refactoring the governance test file. The title is concise, specific to the file being modified, and clearly indicates that improvements are being made to the test. While the title doesn't mention the technical implementation detail (replacing sleep-based waiting with mocktime-driven scheduling), it adequately summarizes the main change at an appropriate level of abstraction for a PR history scan.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between da330e0 and 562bb5a.

📒 Files selected for processing (1)
  • test/functional/feature_governance_cl.py (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
test/functional/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Functional tests should be written in Python and placed in test/functional/

Files:

  • test/functional/feature_governance_cl.py
🧠 Learnings (2)
📓 Common learnings
Learnt from: UdjinM6
PR: dashpay/dash#6926
File: test/functional/feature_governance_cl.py:0-0
Timestamp: 2025-10-28T08:54:00.392Z
Learning: In Dash tests, the scheduler (mockscheduler) operates independently of network state. Isolated nodes should still run scheduler-based cleanup processes like governance cleanup, even if they have different state due to network isolation.
📚 Learning: 2025-10-28T08:54:00.392Z
Learnt from: UdjinM6
PR: dashpay/dash#6926
File: test/functional/feature_governance_cl.py:0-0
Timestamp: 2025-10-28T08:54:00.392Z
Learning: In Dash tests, the scheduler (mockscheduler) operates independently of network state. Isolated nodes should still run scheduler-based cleanup processes like governance cleanup, even if they have different state due to network isolation.

Applied to files:

  • test/functional/feature_governance_cl.py
🧬 Code graph analysis (1)
test/functional/feature_governance_cl.py (3)
test/functional/test_framework/test_framework.py (2)
  • bump_mocktime (880-897)
  • sync_blocks (826-846)
test/functional/test_framework/util.py (1)
  • assert_equal (69-74)
test/functional/test_framework/test_node.py (1)
  • assert_debug_log (444-472)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: linux64_multiprocess-build / Build source
  • GitHub Check: mac-build / Build source
  • GitHub Check: linux64_tsan-build / Build source
  • GitHub Check: linux64_fuzz-build / Build source
  • GitHub Check: linux64_ubsan-build / Build source
  • GitHub Check: linux64-build / Build source
  • GitHub Check: linux64_sqlite-build / Build source
  • GitHub Check: win64-build / Build source
  • GitHub Check: linux64_nowallet-build / Build source
  • GitHub Check: arm-linux-build / Build source
🔇 Additional comments (2)
test/functional/feature_governance_cl.py (2)

112-118: Good defensive logic for isolated node trigger creation.

The code correctly handles the edge case where the isolated node would be the trigger creator. The assertion at line 112 verifies the test's structural assumptions about which node is isolated.

One minor observation: the hard assertion assert_equal(self.mninfo[4].nodeIdx, 5) could fail if the test framework's node-to-masternode assignment logic changes in the future. While this is unlikely and the assertion serves as useful documentation of the test's assumptions, you might consider adding a brief comment explaining why this specific masternode index must map to node 5.


147-160: Excellent improvement to test determinism.

Replacing sleep-based waiting with explicit mocktime advancement and scheduler invocations is a significant improvement. The two-stage verification approach is well-structured:

  1. First delta (5 minutes) triggers marking of old governance objects for deletion
  2. Second delta (10 minutes) performs the actual deletion
  3. Debug log assertions verify each stage
  4. Final RPC check confirms the cleanup succeeded

The manual loop over nodes with setmocktime and mockscheduler calls is necessary here (rather than using the framework's bump_mocktime helper) because each node's operations need to be wrapped in the assert_debug_log context manager for verification.

Including all nodes in the cleanup verification is correct, as the scheduler operates independently of network state. Based on learnings.


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.

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b82450a and 35cf71a.

📒 Files selected for processing (1)
  • test/functional/feature_governance_cl.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
test/functional/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Functional tests should be written in Python and placed in test/functional/

Files:

  • test/functional/feature_governance_cl.py
🧬 Code graph analysis (1)
test/functional/feature_governance_cl.py (2)
test/functional/test_framework/test_node.py (1)
  • assert_debug_log (444-472)
test/functional/test_framework/util.py (1)
  • assert_equal (69-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build container / Build container

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
test/functional/feature_governance_cl.py (2)

141-147: DRY the two scheduler phases with a small parametrized loop.

Removes duplication while preserving behavior and assertions.

Apply this diff:

-        delta = 5 * 60
-        self.mocktime += delta
-        for node in self.nodes:
-            with node.assert_debug_log(expected_msgs=['UpdateCachesAndClean']):
-                node.setmocktime(self.mocktime)
-                node.mockscheduler(delta)
-        # Move forward to satisfy GOVERNANCE_DELETION_DELAY, should actually remove old triggers now
-        delta = 10 * 60
-        self.mocktime += delta
-        for node in self.nodes:
-            with node.assert_debug_log(expected_msgs=['UpdateCachesAndClean -- Governance Objects: 0']):
-                node.setmocktime(self.mocktime)
-                node.mockscheduler(delta)
+        for delta, expected in (
+            (5 * 60, ['UpdateCachesAndClean']),  # mark old triggers for deletion
+            (10 * 60, ['UpdateCachesAndClean -- Governance Objects: 0']),  # deletion after delay
+        ):
+            self.mocktime += delta
+            for node in self.nodes:
+                with node.assert_debug_log(expected_msgs=expected):
+                    node.setmocktime(self.mocktime)
+                    node.mockscheduler(delta)

148-153: Log match may be brittle; RPC already asserts 0.

Optional: relax the second log check to reduce coupling to exact formatting.

Apply this minimal change:

-            with node.assert_debug_log(expected_msgs=['UpdateCachesAndClean -- Governance Objects: 0']):
+            with node.assert_debug_log(expected_msgs=['UpdateCachesAndClean -- Governance Objects:']):

Rationale: RPC below enforces zero objects; the log assertion then only checks that the cleanup path ran, avoiding failures on minor message-format changes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 35cf71a and b116fc6.

📒 Files selected for processing (1)
  • test/functional/feature_governance_cl.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
test/functional/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Functional tests should be written in Python and placed in test/functional/

Files:

  • test/functional/feature_governance_cl.py
🧠 Learnings (1)
📚 Learning: 2025-10-28T08:54:00.383Z
Learnt from: UdjinM6
PR: dashpay/dash#6926
File: test/functional/feature_governance_cl.py:0-0
Timestamp: 2025-10-28T08:54:00.383Z
Learning: In Dash tests, the scheduler (mockscheduler) operates independently of network state. Isolated nodes should still run scheduler-based cleanup processes like governance cleanup, even if they have different state due to network isolation.

Applied to files:

  • test/functional/feature_governance_cl.py
🧬 Code graph analysis (1)
test/functional/feature_governance_cl.py (2)
test/functional/test_framework/test_node.py (1)
  • assert_debug_log (444-472)
test/functional/test_framework/util.py (1)
  • assert_equal (69-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: win64-build / Build source
  • GitHub Check: mac-build / Build source
  • GitHub Check: linux64_nowallet-build / Build source
  • GitHub Check: arm-linux-build / Build source
  • GitHub Check: linux64_tsan-build / Build source
  • GitHub Check: linux64_sqlite-build / Build source
  • GitHub Check: linux64_ubsan-build / Build source
  • GitHub Check: linux64-build / Build source
  • GitHub Check: linux64_fuzz-build / Build source
  • GitHub Check: Lint / Run linters
🔇 Additional comments (1)
test/functional/feature_governance_cl.py (1)

155-156: Including the isolated node here is correct.

Running cleanup and verifying RPC state on all nodes (including the isolated one) matches the scheduler’s node-local behavior and the intent captured in this PR. Looks good.

Based on learnings

@UdjinM6 UdjinM6 force-pushed the fix_gov_cl_test_sleep branch from da330e0 to a7fe1eb Compare October 28, 2025 13:18
@UdjinM6 UdjinM6 force-pushed the fix_gov_cl_test_sleep branch from a7fe1eb to 562bb5a Compare October 28, 2025 13:19
@UdjinM6 UdjinM6 changed the title test: improve trigger cleanup check in feature_governance_cl.py test: improve trigger checks in feature_governance_cl.py Oct 28, 2025
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.

1 participant