Skip to content

test: consolidate masternode info tracking (MasternodeInfo) in functional tests, implement helpers, add type annotations #6718

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

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from

Conversation

kwvg
Copy link
Collaborator

@kwvg kwvg commented Jun 9, 2025

Motivation

While working on functional tests for dash#6666 (which in turn, relies on the foundation built by dash#6674, see rpc_netinfo.py, source), the existing test infrastructure, while well optimized for testing interactions between masternodes, didn't offer enough flexibility for test creation of masternodes.

The tests that need to be implemented for extended addresses mimic feature_dip3_deterministicmns.py (source) in objective and while taking cues from it, it was found that instead of the MasternodeInfo used in most of the codebase (source), feature_dip3_deterministicmns.py implements its own object, Masternode (source).

In a similar vein, rpc_netinfo.py, as implemented in c788531, implemented its own variant, Node (source) to address the testing needs for extended addresses. It became clear that without additional intervention, the test suite would have three different ways of representing masternode information (MasternodeInfo, Masternode, Node) and that it would be more beneficial to consolidate all three approaches together.

So, taking cue from Node (from rpc_netinfo.py, not included in develop as of this writing, source), this pull request aims to clean up, consolidate and improve upon MasternodeInfo in an attempt to remove the need for Node.

Additional Information

  • PEP 526 ("Syntax for Variable Annotations") prohibit annotation of variables defined by a for or with statement (source), to get around that, the syntax for type comments (source) as defined in PEP 484 ("Type Hints") have been used instead.

  • The decision to remove node from MasternodeInfo despite its convenience was rooted in the observation that there are cases where nodeIdx and node are assigned separately (source, source), which highlighted the fact that MasternodeInfo has no control over the lifetime of the TestNode instance as it is ultimately controlled by BitcoinTestFramework.

    To avoid potential error and to make it syntactically clear that ownership is vests with BitcoinTestFramework, node has been removed and replaced with get_node(), which alongside some basic sanity checks, is just an alias for self.nodes[mn.nodeIdx] but is still less tedious to type or read.

  • The reason why functions like generate_addresses() accept a separate TestNode (source) is due to the practice of using a single node to instantiate all masternodes instead of keeping them as self-contained instances that mine their own blocks and fund their own collaterals (for instance, DashTestFramework uses nodes[0] to setup all the masternodes even if the masternodes themselves had a different index).

  • The decision to replace addr with nodePort has been inspired by the need to register masternodes with non-loopback addresses (like in feature_dip3_deterministicmns.py or rpc_netinfo.py). As a node that is intended to be used will always need the same standardized loopback address, we can safely resort to only storing the port number and save a few p2p_port() calls along the way.

Breaking Changes

None expected. Affects only functional tests.

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 (note: N/A)
  • I have assigned this pull request to a milestone (for repository code-owners and collaborators only)

@kwvg kwvg added this to the 23 milestone Jun 9, 2025
@kwvg kwvg marked this pull request as ready for review June 9, 2025 15:44
Copy link

coderabbitai bot commented Jun 9, 2025

Walkthrough

The changes refactor the functional test suite for Dash by standardizing how masternode node objects are accessed and enhancing type safety. The MasternodeInfo class is restructured with explicit type annotations, new attributes, and utility methods, encapsulating masternode data and operations. All direct accesses to masternode nodes via the .node attribute are replaced with the get_node(self) method, and node indices are accessed through the nodeIdx attribute. Type annotations are introduced throughout the tests for variables, method parameters, and return types involving MasternodeInfo. Method signatures are updated to reflect these changes, and imports are adjusted to explicitly include MasternodeInfo. No changes are made to test logic or control flow.


📜 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 c5444b3 and 0532baf.

📒 Files selected for processing (19)
  • test/functional/feature_asset_locks.py (2 hunks)
  • test/functional/feature_dip3_deterministicmns.py (7 hunks)
  • test/functional/feature_dip3_v19.py (4 hunks)
  • test/functional/feature_dip4_coinbasemerkleroots.py (3 hunks)
  • test/functional/feature_governance.py (2 hunks)
  • test/functional/feature_llmq_connections.py (6 hunks)
  • test/functional/feature_llmq_data_recovery.py (5 hunks)
  • test/functional/feature_llmq_dkgerrors.py (1 hunks)
  • test/functional/feature_llmq_evo.py (5 hunks)
  • test/functional/feature_llmq_rotation.py (3 hunks)
  • test/functional/feature_llmq_signing.py (6 hunks)
  • test/functional/feature_llmq_simplepose.py (6 hunks)
  • test/functional/feature_llmq_singlenode.py (4 hunks)
  • test/functional/feature_mnehf.py (4 hunks)
  • test/functional/interface_zmq_dash.py (4 hunks)
  • test/functional/p2p_quorum_data.py (10 hunks)
  • test/functional/rpc_mnauth.py (2 hunks)
  • test/functional/rpc_quorum.py (2 hunks)
  • test/functional/test_framework/test_framework.py (21 hunks)
🚧 Files skipped from review as they are similar to previous changes (12)
  • test/functional/feature_dip4_coinbasemerkleroots.py
  • test/functional/feature_asset_locks.py
  • test/functional/feature_llmq_dkgerrors.py
  • test/functional/rpc_mnauth.py
  • test/functional/rpc_quorum.py
  • test/functional/feature_llmq_rotation.py
  • test/functional/feature_llmq_signing.py
  • test/functional/feature_dip3_v19.py
  • test/functional/feature_llmq_evo.py
  • test/functional/p2p_quorum_data.py
  • test/functional/feature_llmq_data_recovery.py
  • test/functional/feature_dip3_deterministicmns.py
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: kwvg
PR: dashpay/dash#6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.983Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.
🧬 Code Graph Analysis (3)
test/functional/feature_governance.py (1)
test/functional/test_framework/test_framework.py (1)
  • MasternodeInfo (1138-1214)
test/functional/feature_llmq_singlenode.py (2)
test/functional/test_framework/test_framework.py (2)
  • MasternodeInfo (1138-1214)
  • get_node (1209-1214)
test/functional/feature_llmq_signing.py (1)
  • assert_sigs_nochange (61-62)
test/functional/feature_mnehf.py (2)
test/functional/test_framework/test_framework.py (2)
  • MasternodeInfo (1138-1214)
  • get_node (1209-1214)
test/functional/test_framework/util.py (1)
  • assert_equal (64-69)
🪛 Ruff (0.11.9)
test/functional/feature_governance.py

12-12: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)

test/functional/feature_llmq_connections.py

17-17: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)


59-59: Function definition does not bind loop variable mn

(B023)


64-64: Function definition does not bind loop variable mn

(B023)


69-69: Function definition does not bind loop variable mn

(B023)


89-90: Use a single with statement with multiple contexts instead of nested with statements

(SIM117)


119-119: Function definition does not bind loop variable mn

(B023)

test/functional/feature_llmq_simplepose.py

230-230: Function definition does not bind loop variable mn

(B023)

test/functional/feature_llmq_singlenode.py

19-19: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)

test/functional/feature_mnehf.py

21-21: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)

test/functional/interface_zmq_dash.py

17-17: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)

test/functional/test_framework/test_framework.py

2102-2102: Do not assert False (python -O removes these calls), raise AssertionError()

Replace assert False

(B011)

🪛 Pylint (3.3.7)
test/functional/interface_zmq_dash.py

[error] 224-224: Instance of 'DashZMQTest' has no 'quorum_hash' member

(E1101)


[error] 225-225: Instance of 'DashZMQTest' has no 'quorum_type' member

(E1101)

test/functional/test_framework/test_framework.py

[refactor] 1183-1186: Unnecessary "else" after "raise", remove the "else" and de-indent the code inside it

(R1720)


[refactor] 1192-1192: Too many arguments (6/5)

(R0913)


[refactor] 1192-1192: Too many positional arguments (6/5)

(R0917)


[refactor] 1379-1379: Too many local variables (16/15)

(R0914)


[refactor] 2117-2117: Too many arguments (6/5)

(R0913)


[refactor] 2117-2117: Too many positional arguments (6/5)

(R0917)

⏰ Context from checks skipped due to timeout of 90000ms (9)
  • GitHub Check: win64-build / Build source
  • GitHub Check: mac-build / Build source
  • GitHub Check: arm-linux-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: linux64_nowallet-build / Build source
  • GitHub Check: predict_conflicts
🔇 Additional comments (31)
test/functional/feature_governance.py (2)

10-13: LGTM! Import addition supports type annotations.

The explicit import of MasternodeInfo is correctly added to support the type annotation used later in the file.

🧰 Tools
🪛 Ruff (0.11.9)

12-12: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)


193-193: LGTM! Type annotation improves code clarity.

The type annotation for the loop variable enhances code readability and supports static analysis. The static analysis tool incorrectly flags the MasternodeInfo import as unused, but it's actually required for this type annotation.

test/functional/feature_llmq_singlenode.py (4)

17-20: LGTM! Import addition supports type annotations.

The explicit import of MasternodeInfo correctly supports the type annotation used later in the file.

🧰 Tools
🪛 Ruff (0.11.9)

19-19: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)


61-67: LGTM! Consistent refactoring to use get_node() method.

The changes correctly replace direct node attribute access with the get_node() method calls and add appropriate type annotation. This aligns with the PR's goal to consolidate masternode info tracking.


118-134: LGTM! Consistent application of the refactoring pattern.

All instances of direct node access have been correctly replaced with get_node(self) method calls, maintaining the same functionality while improving the encapsulation.


143-143: LGTM! Node access properly refactored.

The change from direct node attribute access to the get_node() method is correct and consistent with the refactoring pattern.

test/functional/feature_mnehf.py (4)

19-22: LGTM! Import addition supports type annotations.

The explicit import of MasternodeInfo is correctly added to support the type annotation used in the loop.

🧰 Tools
🪛 Ruff (0.11.9)

21-21: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)


44-45: LGTM! Correct refactoring to use nodeIdx attribute.

The changes properly replace direct node attribute access with the nodeIdx attribute from MasternodeInfo and add appropriate type annotation. This aligns with the consolidation of masternode info tracking.


57-57: LGTM! Node access properly refactored.

The change from mninfo[0].node.quorum(...) to mninfo[0].get_node(self).quorum(...) correctly uses the new method interface.


143-143: LGTM! Consistent application of get_node() method.

The quorum method call correctly uses the get_node(self) method instead of direct node attribute access.

test/functional/feature_llmq_connections.py (7)

15-18: LGTM! Import addition supports type annotations.

The explicit import of MasternodeInfo correctly supports the type annotations used throughout the file. The static analysis tool incorrectly flags this as unused.

🧰 Tools
🪛 Ruff (0.11.9)

17-17: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)


38-40: LGTM! Node access properly refactored.

The change from direct node attribute access to the get_node(self) method is correct and consistent with the refactoring pattern.


52-52: LGTM! Consistent refactoring pattern applied.

The wait_for_mnauth call correctly uses the get_node(self) method instead of direct node attribute access.


86-97: LGTM! Proper refactoring with type annotations.

The loop correctly uses type annotation and all node access has been properly refactored to use the get_node(self) method.

🧰 Tools
🪛 Ruff (0.11.9)

89-90: Use a single with statement with multiple contexts instead of nested with statements

(SIM117)


94-94: Do not use bare except

(E722)


102-112: LGTM! Consistent application of refactoring pattern.

The masternode node access and type annotation are correctly implemented following the established pattern.

🧰 Tools
🪛 Ruff (0.11.9)

108-108: Do not use bare except

(E722)


116-121: LGTM! Network control methods properly refactored.

All the setnetworkactive calls correctly use the get_node(self) method with appropriate type annotations.

🧰 Tools
🪛 Ruff (0.11.9)

119-119: Function definition does not bind loop variable mn

(B023)


127-127: LGTM! Method call properly refactored.

The wait_for_mnauth call correctly uses the get_node(self) method.

test/functional/interface_zmq_dash.py (3)

15-18: LGTM: Import updated to include MasternodeInfo.

The addition of MasternodeInfo to the import statement aligns with the refactoring to consolidate masternode info tracking.

🧰 Tools
🪛 Ruff (0.11.9)

17-17: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)


172-172: LGTM: Consistent use of get_node() method.

The change from direct mn.node access to mn.get_node(self) method call is consistent with the refactoring to encapsulate node access in MasternodeInfo.


195-195: LGTM: Consistent use of get_node() method.

The change from direct mn.node access to mn.get_node(self) method call maintains consistency with the refactoring pattern.

test/functional/feature_llmq_simplepose.py (8)

16-20: LGTM: Import updated to include MasternodeInfo.

The addition of MasternodeInfo to the import statement supports the refactoring to consolidate masternode info tracking with proper type annotations.


71-74: LGTM: Enhanced with type annotation and consistent node access.

The addition of the MasternodeInfo type annotation and the change from direct mn.node access to mn.get_node(self) method calls improve code clarity and maintain consistency with the refactoring pattern.


76-86: LGTM: Improved type safety and consistent attribute usage.

Good improvements:

  • Type annotation for the mn parameter
  • Consistent use of mn.nodeIdx instead of mn.node.index
  • Proper use of mn.get_node(self) method calls
  • Type annotation for the loop variable

The changes maintain the same functionality while improving type safety and consistency.


88-93: LGTM: Type annotation and consistent node access pattern.

The type annotation and consistent use of mn.nodeIdx and mn.get_node(self) align well with the refactoring objectives.


105-105: LGTM: Consistent use of get_node() method.

The change from direct mn.node access to mn.get_node(self) method call maintains consistency with the refactoring pattern.


171-171: LGTM: Enhanced type annotation for loop variable.

The explicit type annotation for the mn variable improves code clarity and type safety.


207-218: LGTM: Comprehensive refactoring with improved type safety.

Excellent improvements throughout this method:

  • Type annotation for the loop variable
  • Direct use of mn.nodePort instead of a utility function call
  • Consistent use of mn.nodeIdx and mn.get_node(self) method calls

The changes simplify the code while maintaining consistency with the refactoring pattern.


227-233: LGTM: Consistent refactoring with type annotations.

The addition of type annotations and consistent use of mn.get_node(self) method calls and mn.nodeIdx attribute maintain the refactoring pattern throughout the method.

🧰 Tools
🪛 Ruff (0.11.9)

230-230: Function definition does not bind loop variable mn

(B023)

test/functional/test_framework/test_framework.py (3)

1138-1214: Excellent refactoring of the MasternodeInfo class.

The restructuring with explicit type annotations, encapsulated methods, and proper error handling in get_node() significantly improves code clarity and maintainability. The separation of concerns between node lifecycle management and masternode data is well-implemented.

🧰 Tools
🪛 Pylint (3.3.7)

[refactor] 1138-1138: Too many instance attributes (16/7)

(R0902)


[refactor] 1183-1186: Unnecessary "else" after "raise", remove the "else" and de-indent the code inside it

(R1720)


[refactor] 1192-1192: Too many arguments (6/5)

(R0913)


[refactor] 1192-1192: Too many positional arguments (6/5)

(R0917)


1241-1248: Proper adaptation to the new MasternodeInfo interface.

The method correctly uses get_node(self) instead of direct node access and maintains proper masternode thread management during connections.


1366-1530: Comprehensive and consistent refactoring implementation.

The systematic replacement of direct node access with get_node(self) calls, addition of type annotations, and proper use of the new MasternodeInfo interface throughout the methods demonstrates excellent attention to detail. The refactoring successfully consolidates masternode state management while maintaining all existing functionality.

🧰 Tools
🪛 Ruff (0.11.9)

1433-1433: Do not use bare except

(E722)

🪛 Pylint (3.3.7)

[refactor] 1379-1379: Too many local variables (16/15)

(R0914)

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 5

🧹 Nitpick comments (2)
test/functional/feature_llmq_connections.py (1)

89-90: Consider simplifying nested with statements.

The nested with statements can be combined for better readability.

-                    with mn.get_node(self).assert_debug_log(['removing masternodes quorum connections']):
-                        with mn.get_node(self).assert_debug_log(['keeping mn quorum connections']):
+                    with (mn.get_node(self).assert_debug_log(['removing masternodes quorum connections']),
+                          mn.get_node(self).assert_debug_log(['keeping mn quorum connections'])):
🧰 Tools
🪛 Ruff (0.11.9)

89-90: Use a single with statement with multiple contexts instead of nested with statements

(SIM117)

test/functional/feature_llmq_simplepose.py (1)

230-230: Address potential loop variable binding issue.

The lambda function captures the loop variable mn, which could potentially cause issues if the lambda were executed after the loop completes. However, since wait_until calls the lambda immediately within the same iteration, this is likely not a practical problem in this context.

For better clarity and to avoid static analysis warnings, consider capturing the variable explicitly:

-            self.wait_until(lambda: mn.get_node(self).getconnectioncount() == 0)
+            self.wait_until(lambda mn=mn: mn.get_node(self).getconnectioncount() == 0)
🧰 Tools
🪛 Ruff (0.11.9)

230-230: Function definition does not bind loop variable mn

(B023)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 09aa42e and c5444b3.

📒 Files selected for processing (19)
  • test/functional/feature_asset_locks.py (2 hunks)
  • test/functional/feature_dip3_deterministicmns.py (7 hunks)
  • test/functional/feature_dip3_v19.py (4 hunks)
  • test/functional/feature_dip4_coinbasemerkleroots.py (3 hunks)
  • test/functional/feature_governance.py (2 hunks)
  • test/functional/feature_llmq_connections.py (6 hunks)
  • test/functional/feature_llmq_data_recovery.py (5 hunks)
  • test/functional/feature_llmq_dkgerrors.py (1 hunks)
  • test/functional/feature_llmq_evo.py (5 hunks)
  • test/functional/feature_llmq_rotation.py (3 hunks)
  • test/functional/feature_llmq_signing.py (6 hunks)
  • test/functional/feature_llmq_simplepose.py (6 hunks)
  • test/functional/feature_llmq_singlenode.py (4 hunks)
  • test/functional/feature_mnehf.py (4 hunks)
  • test/functional/interface_zmq_dash.py (4 hunks)
  • test/functional/p2p_quorum_data.py (10 hunks)
  • test/functional/rpc_mnauth.py (2 hunks)
  • test/functional/rpc_quorum.py (2 hunks)
  • test/functional/test_framework/test_framework.py (21 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (11)
test/functional/feature_dip3_v19.py (1)
test/functional/test_framework/test_framework.py (4)
  • DashTestFramework (1214-2155)
  • MasternodeInfo (1138-1212)
  • dynamically_add_masternode (1339-1375)
  • dynamically_evo_update_service (1410-1434)
test/functional/feature_llmq_connections.py (1)
test/functional/test_framework/test_framework.py (9)
  • DashTestFramework (1214-2155)
  • MasternodeInfo (1138-1212)
  • get_node (1209-1212)
  • wait_for_mnauth (2147-2155)
  • mine_quorum (1865-1951)
  • get_quorum_masternodes (2102-2107)
  • wait_until (900-901)
  • bump_mocktime (873-890)
  • mine_cycle_quorum (1953-2075)
test/functional/feature_llmq_rotation.py (1)
test/functional/test_framework/test_framework.py (1)
  • get_node (1209-1212)
test/functional/feature_governance.py (1)
test/functional/test_framework/test_framework.py (1)
  • MasternodeInfo (1138-1212)
test/functional/feature_dip4_coinbasemerkleroots.py (1)
test/functional/test_framework/test_framework.py (2)
  • DashTestFramework (1214-2155)
  • MasternodeInfo (1138-1212)
test/functional/feature_asset_locks.py (2)
test/functional/test_framework/test_framework.py (1)
  • get_node (1209-1212)
test/functional/test_framework/util.py (1)
  • assert_equal (64-69)
test/functional/feature_mnehf.py (2)
test/functional/test_framework/test_framework.py (2)
  • MasternodeInfo (1138-1212)
  • get_node (1209-1212)
test/functional/test_framework/util.py (1)
  • assert_equal (64-69)
test/functional/feature_llmq_evo.py (1)
test/functional/test_framework/test_framework.py (2)
  • MasternodeInfo (1138-1212)
  • dynamically_add_masternode (1339-1375)
test/functional/feature_llmq_simplepose.py (3)
test/functional/test_framework/test_framework.py (8)
  • DashTestFramework (1214-2155)
  • MasternodeInfo (1138-1212)
  • get_node (1209-1212)
  • wait_until (900-901)
  • stop_node (673-675)
  • start_masternode (1522-1527)
  • connect_nodes (695-735)
  • connect_nodes (1239-1246)
test/functional/test_framework/util.py (2)
  • assert_equal (64-69)
  • force_finish_mnsync (525-531)
test/functional/test_framework/masternodes.py (2)
  • check_banned (11-13)
  • check_punished (7-9)
test/functional/rpc_quorum.py (2)
test/functional/test_framework/test_framework.py (1)
  • MasternodeInfo (1138-1212)
test/functional/test_framework/util.py (1)
  • assert_equal (64-69)
test/functional/feature_llmq_data_recovery.py (3)
test/functional/test_framework/test_framework.py (6)
  • MasternodeInfo (1138-1212)
  • get_node (1209-1212)
  • restart_node (687-690)
  • wait_until (900-901)
  • connect_nodes (695-735)
  • connect_nodes (1239-1246)
test/functional/p2p_quorum_data.py (1)
  • restart_mn (126-133)
test/functional/test_framework/util.py (1)
  • force_finish_mnsync (525-531)
🪛 Ruff (0.11.9)
test/functional/feature_llmq_connections.py

17-17: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)


59-59: Function definition does not bind loop variable mn

(B023)


64-64: Function definition does not bind loop variable mn

(B023)


69-69: Function definition does not bind loop variable mn

(B023)


89-90: Use a single with statement with multiple contexts instead of nested with statements

(SIM117)


119-119: Function definition does not bind loop variable mn

(B023)

test/functional/feature_governance.py

12-12: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)

test/functional/feature_mnehf.py

21-21: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)

test/functional/interface_zmq_dash.py

17-17: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)

test/functional/feature_llmq_singlenode.py

19-19: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)

test/functional/feature_llmq_simplepose.py

230-230: Function definition does not bind loop variable mn

(B023)

test/functional/test_framework/test_framework.py

1184-1184: Do not assert False (python -O removes these calls), raise AssertionError()

Replace assert False

(B011)


2100-2100: Do not assert False (python -O removes these calls), raise AssertionError()

Replace assert False

(B011)

🪛 Pylint (3.3.7)
test/functional/interface_zmq_dash.py

[error] 224-224: Instance of 'DashZMQTest' has no 'quorum_hash' member

(E1101)


[error] 225-225: Instance of 'DashZMQTest' has no 'quorum_type' member

(E1101)

test/functional/test_framework/test_framework.py

[refactor] 1192-1192: Too many arguments (6/5)

(R0913)


[refactor] 1192-1192: Too many positional arguments (6/5)

(R0917)


[refactor] 1377-1377: Too many local variables (16/15)

(R0914)


[refactor] 2115-2115: Too many arguments (6/5)

(R0913)


[refactor] 2115-2115: Too many positional arguments (6/5)

(R0917)

⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: linux64_tsan-test / Test source
  • GitHub Check: linux64_ubsan-test / Test source
  • GitHub Check: linux64_sqlite-test / Test source
  • GitHub Check: linux64_nowallet-test / Test source
  • GitHub Check: linux64-test / Test source
  • GitHub Check: linux64_multiprocess-build / Build source
  • GitHub Check: linux64_fuzz-build / Build source
🔇 Additional comments (54)
test/functional/feature_governance.py (2)

10-13: LGTM! Import consolidation for better type safety.

Adding MasternodeInfo to the import statement supports the type annotation added later in the file.

🧰 Tools
🪛 Ruff (0.11.9)

12-12: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)


193-193: Good addition of type annotation for clarity.

The type annotation comment helps with code readability and IDE support. Note that the static analysis tool incorrectly flags MasternodeInfo as unused - this is a false positive since type annotation comments are valid usage.

test/functional/feature_llmq_dkgerrors.py (1)

30-30: Excellent refactoring to improve encapsulation.

Replacing direct .node attribute access with .get_node(self) method calls improves encapsulation and consistency across the codebase. The logic remains unchanged while providing better abstraction for node access.

Also applies to: 35-36, 41-41, 49-50, 55-57, 62-63, 68-69

test/functional/feature_dip4_coinbasemerkleroots.py (2)

17-20: LGTM! Added MasternodeInfo import for type annotations.

The explicit import supports the type annotations added in the method signatures below.


56-56: Good addition of type annotations for better code clarity.

Adding explicit type annotations for MasternodeInfo variables improves code readability and enables better static type checking.

Also applies to: 86-86

test/functional/feature_llmq_singlenode.py (2)

17-20: LGTM! Import consolidation for type safety.

Adding MasternodeInfo to the import statement supports the type annotation used later in the file.

🧰 Tools
🪛 Ruff (0.11.9)

19-19: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)


61-67: Excellent encapsulation improvement with get_node() method.

Replacing direct .node attribute access with .get_node(self) method calls improves encapsulation and follows the established pattern across the codebase. The type annotation comment on line 61 also enhances code clarity. Note that the static analysis tool incorrectly flags MasternodeInfo as unused - this is a false positive since it's used for the type annotation comment.

Also applies to: 118-118, 121-121, 123-123, 128-128, 133-134, 143-143

test/functional/rpc_quorum.py (3)

5-9: LGTM: Import statement properly updated for type annotations.

The explicit import of MasternodeInfo enables proper type annotations and aligns with the refactoring effort.


28-28: Good addition of type annotation.

Adding MasternodeInfo type annotation improves code clarity and enables better static analysis support.


31-31: Excellent improvement: Direct attribute access over dynamic calculation.

Replacing p2p_port(mn.node.index) with mn.nodePort eliminates the need for dynamic port calculation and directly uses the encapsulated port information from the MasternodeInfo object. This is cleaner and more efficient.

test/functional/feature_llmq_rotation.py (3)

143-143: LGTM: Consistent node access pattern.

The change from mn.node to mn.get_node(self) follows the standardized node access pattern established in this refactoring effort.


196-196: LGTM: Proper node access method usage.

Consistent application of the get_node(self) method for accessing masternode nodes.


401-401: LGTM: Standardized node retrieval.

The node access pattern is correctly updated to use the encapsulated get_node(self) method.

test/functional/feature_asset_locks.py (2)

106-106: LGTM: Consistent node access refactoring.

The change from mninfo[0].node.quorum(...) to mninfo[0].get_node(self).quorum(...) properly follows the new standardized node access pattern while maintaining identical functionality.


371-371: LGTM: Proper node method access.

Correctly updated to use the get_node(self) method for accessing the quorum RPC, consistent with the refactoring approach.

test/functional/rpc_mnauth.py (3)

8-11: LGTM: Proper import for type annotations.

Explicitly importing MasternodeInfo enables type annotations and maintains consistency with the refactoring effort.


26-27: Excellent approach: Extract node once and reuse.

Adding the type annotation and extracting the node using get_node(self) once is more efficient than calling it multiple times throughout the method. This is a clean implementation of the new access pattern.


28-55: LGTM: Consistent use of extracted node variable.

All node method calls correctly use the extracted node variable instead of accessing through masternode.node. This maintains the same functionality while following the standardized access pattern.

test/functional/feature_dip3_v19.py (2)

17-20: LGTM! Import statement properly updated.

The addition of MasternodeInfo to the import statement is consistent with its usage in type annotations throughout the file.


84-94: LGTM! Type annotations improve code clarity.

The explicit type annotations for MasternodeInfo variables enhance code readability and provide better static analysis support. All annotations are consistent with the return types of dynamically_add_masternode.

Also applies to: 107-107, 135-135

test/functional/feature_llmq_signing.py (3)

15-18: LGTM! Import statement properly updated.

The addition of MasternodeInfo to the import statement supports the type annotations used throughout the file.


42-42: LGTM! Consistent refactoring to use get_node() method.

The replacement of direct .node attribute access with .get_node(self) method calls is consistent with the MasternodeInfo class design and improves encapsulation. This change standardizes how test nodes are accessed from masternode info objects.

Also applies to: 50-50, 52-52, 54-54, 68-68, 72-72, 75-76, 82-82, 84-85, 98-98, 103-103, 108-108, 113-113, 116-116, 149-149, 173-175, 184-198


49-49: LGTM! Type annotations enhance code clarity.

The explicit type annotations for MasternodeInfo variables improve code readability and static analysis support.

Also applies to: 97-97, 101-101, 148-148, 183-183

test/functional/interface_zmq_dash.py (3)

15-18: LGTM! Import statement properly updated.

The addition of MasternodeInfo to the import statement supports the type annotations used throughout the file.

🧰 Tools
🪛 Ruff (0.11.9)

17-17: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)


172-172: LGTM! Consistent refactoring to use get_node() method.

The replacement of direct .node attribute access with .get_node(self) method calls follows the same pattern as other files in this PR and improves encapsulation.

Also applies to: 195-195, 225-225


224-224: Fix type annotation consistency.

The type annotation is correct for the loop variable.

🧰 Tools
🪛 Pylint (3.3.7)

[error] 224-224: Instance of 'DashZMQTest' has no 'quorum_hash' member

(E1101)

test/functional/feature_llmq_connections.py (3)

15-18: LGTM! Import statement properly updated.

The addition of MasternodeInfo to the import statement supports the type annotations used throughout the file.

🧰 Tools
🪛 Ruff (0.11.9)

17-17: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)


38-38: LGTM! Consistent refactoring to use get_node() method.

The replacement of direct .node attribute access with .get_node(self) method calls is consistent with the broader refactoring and improves encapsulation.

Also applies to: 52-52, 87-87, 89-92, 103-105, 117-117, 121-121, 127-127


86-86: LGTM! Type annotations enhance code clarity.

The explicit type annotations for MasternodeInfo variables improve code readability and static analysis support.

Also applies to: 102-102, 116-118, 120-120

test/functional/feature_mnehf.py (4)

19-22: LGTM! Import statement properly updated for MasternodeInfo.

The import has been correctly updated to include MasternodeInfo alongside DashTestFramework, aligning with the refactoring to use the enhanced MasternodeInfo class.

🧰 Tools
🪛 Ruff (0.11.9)

21-21: test_framework.test_framework.MasternodeInfo imported but unused

Remove unused import: test_framework.test_framework.MasternodeInfo

(F401)


44-45: LGTM! Proper migration to new MasternodeInfo API.

The code correctly:

  • Adds type annotation for the loop variable
  • Replaces mn.node.index with mn.nodeIdx for node indexing

This aligns with the enhanced MasternodeInfo class design.


57-57: LGTM! Node access properly updated.

The direct node access self.mninfo[0].node.quorum(...) has been correctly replaced with self.mninfo[0].get_node(self).quorum(...), following the new encapsulated approach.


143-143: LGTM! Consistent node access pattern.

This line correctly follows the same pattern as line 57, ensuring consistent usage of the get_node(self) method throughout the file.

test/functional/feature_llmq_evo.py (5)

13-13: LGTM! Optional import added for type annotations.

The Optional import is properly added to support the return type annotation in the get_mn_payee_for_block method.


18-21: LGTM! Import statement correctly updated.

The import has been properly updated to include MasternodeInfo for use in type annotations throughout the file.


79-79: LGTM! Excellent type annotation additions.

The type annotations for evo_info, current_evo, and payee variables significantly improve code clarity and enable better static analysis. All annotations correctly use MasternodeInfo.

Also applies to: 118-118, 122-122


161-161: LGTM! Method return type properly annotated.

The get_mn_payee_for_block method now correctly declares its return type as Optional[MasternodeInfo], which matches the implementation that can return either a MasternodeInfo instance or None.


166-166: LGTM! Loop variable type annotations improve clarity.

The inline type comments for loop variables help clarify that the iterations are over MasternodeInfo instances, enhancing code readability and static analysis support.

Also applies to: 177-177

test/functional/p2p_quorum_data.py (4)

13-16: LGTM! Import statement properly updated.

The import has been correctly updated to include MasternodeInfo, supporting the comprehensive refactoring throughout this file.


126-133: LGTM! Method signature and implementation properly updated.

The restart_mn method correctly:

  • Adds type annotation for the mn parameter as MasternodeInfo
  • Replaces mn.node.index with mn.nodeIdx for node indexing
  • Uses mn.get_node(self) for node access
  • Maintains the same functionality with improved encapsulation

147-188: LGTM! Consistent node access pattern throughout test_basics.

All direct node accesses have been properly replaced with the get_node(self) method, maintaining consistency with the new MasternodeInfo API. The changes preserve the original test logic while improving encapsulation.


414-416: LGTM! Local variable type annotations improve clarity.

The type annotations for mn1, mn2, and mn3 variables clearly indicate they are MasternodeInfo instances, enhancing code readability and enabling better static analysis.

test/functional/feature_llmq_simplepose.py (3)

16-20: LGTM! Import statement properly updated.

The import has been correctly updated to include MasternodeInfo, supporting the type annotations and method calls throughout the file.


71-74: LGTM! Method signatures and implementations properly updated.

All three methods (isolate_mn, close_mn_port, force_old_mn_proto) correctly:

  • Add type annotations for the mn parameter as MasternodeInfo
  • Replace direct node access with mn.get_node(self) method calls
  • Use mn.nodeIdx for node indexing
  • Maintain the same functionality with improved encapsulation

Also applies to: 76-86, 88-93


211-211: LGTM! Direct port access improves consistency.

Using mn.nodePort directly instead of a utility function with mn.nodeIdx is more consistent with the encapsulated MasternodeInfo design and eliminates unnecessary indirection.

test/functional/feature_llmq_data_recovery.py (3)

7-12: Good addition of type annotations and explicit imports.

The explicit import of MasternodeInfo and addition of type annotations improves code clarity and enables better IDE support.


35-50: Consistent refactoring to use MasternodeInfo methods.

The changes properly utilize the new MasternodeInfo structure by:

  • Using mn.nodeIdx instead of mn.node.index
  • Calling mn.get_node(self) instead of direct mn.node access

This improves encapsulation and maintains consistency with the framework refactoring.


80-94: Well-structured return type annotations.

The addition of return type annotations (Optional[MasternodeInfo], List[Optional[MasternodeInfo]], List[MasternodeInfo]) enhances code documentation and type safety.

test/functional/feature_dip3_deterministicmns.py (3)

11-20: Good use of constants and explicit imports.

Importing MASTERNODE_COLLATERAL eliminates magic numbers and improves maintainability. The explicit import of MasternodeInfo clarifies dependencies.


224-229: Well-structured masternode preparation with MasternodeInfo.

The prepare_mn method now properly creates and initializes a MasternodeInfo instance with:

  • Correct evo/legacy flags based on softfork status
  • Generated addresses
  • Proper parameters including operator reward and node port

This encapsulation makes the code more maintainable and type-safe.


231-262: Excellent refactoring of masternode lifecycle methods.

The refactoring of create_mn_collateral, register_fund_mn, register_mn, start_mn, and spend_mn_collateral to use MasternodeInfo methods and attributes:

  • Improves code organization
  • Ensures consistent collateral value calculation
  • Properly encapsulates masternode state

The assertion in start_mn (line 252) is a good defensive programming practice.

test/functional/test_framework/test_framework.py (3)

1138-1187: Excellent refactoring of MasternodeInfo class.

The new MasternodeInfo class is well-structured with:

  • Comprehensive type annotations for all attributes
  • Clear separation between evo and regular masternodes
  • Useful helper methods for address generation and collateral management
  • Proper encapsulation of masternode state

This significantly improves code maintainability and type safety.

🧰 Tools
🪛 Ruff (0.11.9)

1184-1184: Do not assert False (python -O removes these calls), raise AssertionError()

Replace assert False

(B011)

🪛 Pylint (3.3.7)

[refactor] 1138-1138: Too many instance attributes (16/7)

(R0902)


1209-1212: Well-designed node access method.

The get_node method with proper assertions ensures:

  • nodeIdx is set before accessing the node
  • The node exists in the test framework
  • Clear error messages for debugging

This defensive programming approach prevents common errors.


1239-1246: Good encapsulation in connect_nodes method.

The refactoring to use mn.get_node(self) instead of direct mn.node access maintains consistency with the new MasternodeInfo encapsulation pattern throughout the codebase.

Comment on lines +224 to +225
for mn in self.get_quorum_masternodes(self.quorum_hash): # type: MasternodeInfo
mn.get_node(self).quorum("sign", self.quorum_type, sign_id, sign_msg_hash)
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify missing attributes: quorum_hash and quorum_type.

The code references self.quorum_hash and self.quorum_type but these attributes don't appear to be defined in the DashZMQTest class.


🏁 Script executed:

#!/bin/bash
# Description: Search for quorum_hash and quorum_type attribute definitions in DashZMQTest class
# Expected: Find where these attributes should be defined or initialized

# Search for quorum_hash and quorum_type in the test file
rg -A 3 -B 3 "quorum_hash|quorum_type" test/functional/interface_zmq_dash.py

# Search for these attributes in other test files to understand the pattern
rg -A 2 -B 2 "self\.quorum_hash|self\.quorum_type" test/functional/

# Check the DashTestFramework base class for these attributes
rg -A 3 -B 3 "quorum_hash|quorum_type" test/functional/test_framework/test_framework.py

Length of output: 11281


🏁 Script executed:

#!/bin/bash
# Inspect the DashZMQTest class definition and its initial attributes
rg -n "^class " test/functional/interface_zmq_dash.py
sed -n '1,200p' test/functional/interface_zmq_dash.py

Length of output: 7384


🏁 Script executed:

#!/bin/bash
# Locate set_dash_llmq_test_params definition
rg -n "def set_dash_llmq_test_params" test/functional/test_framework/test_framework.py

# Locate mine_cycle_quorum definition
rg -n "def mine_cycle_quorum" -n test/functional/test_framework/test_framework.py
rg -A 20 -B 0 "def mine_cycle_quorum" test/functional/test_framework/test_framework.py

# Search for assignments to self.quorum_hash and self.quorum_type in the framework
rg -n "self\.quorum_hash" test/functional/test_framework/test_framework.py
rg -n "self\.quorum_type" test/functional/test_framework/test_framework.py

Length of output: 1597


Initialize missing quorum attributes before use

The test_recovered_signature_publishers method references self.quorum_hash and self.quorum_type (lines 224–225) but neither is ever initialized in DashZMQTest, leading to an AttributeError when this code runs. You should set these attributes before invoking get_quorum_masternodes and the quorum("sign", …) call. For example:

• After generating the quorum in run_test, capture its hash and type:

# in run_test, instead of:
self.mine_cycle_quorum()
# do:
self.quorum_hash, self.quorum_type = self.mine_cycle_quorum()

• Or explicitly initialize them in set_test_params (or right before the loop):

self.quorum_type = 103  # llmq_test_dip0024
self.quorum_hash = self.nodes[0].quorum("list")[“llmq_test_dip0024”][-1]

Then update the loop to use the initialized values:

- for mn in self.get_quorum_masternodes(self.quorum_hash):
+ for mn in self.get_quorum_masternodes(self.quorum_hash):
    mn.get_node(self).quorum("sign", self.quorum_type, sign_id, sign_msg_hash)

• File: test/functional/interface_zmq_dash.py
Lines: 224–225

🧰 Tools
🪛 Pylint (3.3.7)

[error] 224-224: Instance of 'DashZMQTest' has no 'quorum_hash' member

(E1101)


[error] 225-225: Instance of 'DashZMQTest' has no 'quorum_type' member

(E1101)

🤖 Prompt for AI Agents
In test/functional/interface_zmq_dash.py around lines 224 to 225, the attributes
self.quorum_hash and self.quorum_type are used but never initialized, causing an
AttributeError. To fix this, initialize these attributes before the loop in
test_recovered_signature_publishers or in run_test by assigning self.quorum_hash
and self.quorum_type from the result of self.mine_cycle_quorum() or by setting
them explicitly in set_test_params or just before the loop. This ensures the
quorum hash and type are defined before calling get_quorum_masternodes and
quorum("sign", ...).


self.log.info("mine a new quorum and verify that all members connect to each other")
q = self.mine_quorum()

self.log.info("checking that all MNs got probed")
for mn in self.get_quorum_masternodes(q):
self.wait_until(lambda: self.get_mn_probe_count(mn.node, q, False) == 4)
self.wait_until(lambda: self.get_mn_probe_count(mn.get_node(self), q, False) == 4)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix lambda function variable capture issue.

The lambda functions are capturing the loop variable mn by reference, which could lead to incorrect behavior when the lambda is executed after the loop iteration completes.

Apply this fix to properly capture the loop variable:

-        for mn in self.get_quorum_masternodes(q):
-            self.wait_until(lambda: self.get_mn_probe_count(mn.get_node(self), q, False) == 4)
+        for mn in self.get_quorum_masternodes(q):
+            self.wait_until(lambda mn=mn: self.get_mn_probe_count(mn.get_node(self), q, False) == 4)

Apply the same pattern to lines 64 and 69.

Also applies to: 64-64, 69-69

🧰 Tools
🪛 Ruff (0.11.9)

59-59: Function definition does not bind loop variable mn

(B023)

🤖 Prompt for AI Agents
In test/functional/feature_llmq_connections.py at lines 59, 64, and 69, the
lambda functions capture the loop variable mn by reference, causing potential
incorrect behavior after the loop ends. To fix this, modify each lambda to
capture the current value of mn as a default argument in the lambda definition,
ensuring the correct mn is used when the lambda executes.

for mn in self.mninfo: # type: MasternodeInfo
mn.get_node(self).setnetworkactive(False)
for mn in self.mninfo: # type: MasternodeInfo
self.wait_until(lambda: len(mn.get_node(self).getpeerinfo()) == 0)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix lambda function variable capture issue.

Similar issue with lambda function capturing loop variable by reference.

Apply this fix:

-        for mn in self.mninfo: # type: MasternodeInfo
-            self.wait_until(lambda: len(mn.get_node(self).getpeerinfo()) == 0)
+        for mn in self.mninfo: # type: MasternodeInfo
+            self.wait_until(lambda mn=mn: len(mn.get_node(self).getpeerinfo()) == 0)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
self.wait_until(lambda: len(mn.get_node(self).getpeerinfo()) == 0)
for mn in self.mninfo: # type: MasternodeInfo
self.wait_until(lambda mn=mn: len(mn.get_node(self).getpeerinfo()) == 0)
🧰 Tools
🪛 Ruff (0.11.9)

119-119: Function definition does not bind loop variable mn

(B023)

🤖 Prompt for AI Agents
In test/functional/feature_llmq_connections.py at line 119, the lambda function
captures the loop variable by reference, causing incorrect behavior. Fix this by
binding the current value of the loop variable as a default argument in the
lambda function to ensure it captures the intended value at each iteration.

@kwvg kwvg marked this pull request as draft June 9, 2025 15:59
@kwvg kwvg changed the title test: consolidate masternode state tracking (MasternodeInfo) in functional tests, add type annotations, implement helpers test: consolidate masternode info tracking (MasternodeInfo) in functional tests, implement helpers, add type annotations Jun 9, 2025
kwvg added 10 commits June 9, 2025 16:40
MasternodeInfo is used a lot in multiple tests and without annotations,
the linter is running blind. Let's try to do something about that. Note,
PEP 526 prohibits annotating types in loops, we are using PEP 484
comments there instead.
Relevant when we migrate feature_dip3_deterministicmns away from their
own bespoke Masternode class
This makes crafting invalid addresses as part of testing easier, a valid
entry will always use the loopback address (127.0.0.1), it's the port
that differentiates. So let's only store what we need.

Relevant when we migrate feature_dip3_deterministicmns away from their
own bespoke Masternode class
node is self.nodes[nodeIdx], so node.index will always be nodeIdx, just
fetch nodeIdx directly instead.
We don't register nodeIdx and node at the same time. This creates a
problem that we aren't entirely sure if the node is online when we
access node since we don't really own the TestNode instance, it is
always in the control of BitcoinTestFramework.

So let's try to be more explicit about that and add some
belt-and-suspenders assertions.
In order to generate BLS keypairs properly, we need to also record if
we are running a legacy node, so we store that now too. set_params() is
meant to be as flexible as possible, to allow ensuring that details are
registered across different steps or all at once.
@kwvg kwvg marked this pull request as ready for review June 9, 2025 16:42
@kwvg kwvg requested review from knst, UdjinM6 and PastaPastaPasta June 9, 2025 17:29
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