Skip to content

Conversation

@UdjinM6
Copy link

@UdjinM6 UdjinM6 commented Nov 11, 2025

Issue being fixed or feature implemented

Current implementation is too limited for proper testing.

What was done?

Split CDeterministicMNStateDiffLegacy ser/deser. Improve tests to confirm we can indeed deser pubKeyOperator as legacy BLS and set correct scheme later via SetLegacy(). Also check a few additional things while at it.

How Has This Been Tested?

Run tests

Breaking Changes

n/a

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 Nov 11, 2025
@github-actions
Copy link

github-actions bot commented Nov 11, 2025

✅ No Merge Conflicts Detected

This PR currently has no conflicts with other open PRs.

@coderabbitai
Copy link

coderabbitai bot commented Nov 11, 2025

Walkthrough

This change adds explicit Serialize(Stream&) and Unserialize(Stream&) template methods to CDeterministicMNStateDiffLegacy to support testing-time round-trip of legacy-format fields, replacing a previous macro-based deserialize path. Legacy field handling uses specific wrappers for operator pubkey and NetInfo, writes/reads a VARINT field mask, and conditionally processes each legacy member. A ToNewFormat() helper was added to map legacy field bits and values into the new CDeterministicMNStateDiff format. Tests were updated to include PoSe ban height in legacy round-trip and to assert correct mapping to the new Field_nPoSeBanHeight bit and related data (including operator key conversion and ban height).

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Test as Tests
participant Legacy as CDeterministicMNStateDiffLegacy
participant Stream as Stream
participant Wrappers as LegacyWrappers
participant New as CDeterministicMNStateDiff

rect rgba(200,230,255,0.4)
Note over Test,Legacy: Serialization (testing-time)
Test->>Legacy: call Serialize(Stream&)
Legacy->>Stream: write VARINT(fields)
Legacy->>Wrappers: prepare pubKeyOperator/NetInfo wrappers
alt field present
    Legacy->>Stream: write field data (using wrappers where needed)
end
Stream-->>Test: serialized bytes
end

rect rgba(230,255,220,0.4)
Note over Test,Legacy: Deserialization (legacy path)
Test->>Legacy: call Unserialize(Stream&)
Legacy->>Stream: read VARINT(fields)
loop for each legacy_member
    alt pubKeyOperator
        Legacy->>Wrappers: use CBLSLazyPublicKeyVersionWrapper (legacy)
        Wrappers->>Legacy: provide pubKeyOperator
    else netInfo
        Legacy->>Wrappers: use NetInfoSerWrapper (non-extended)
        Wrappers->>Legacy: provide netInfo
    else other fields
        Stream-->>Legacy: read field into member.get(state)
    end
end
Stream-->>Test: deserialized legacy object
end

rect rgba(255,240,220,0.4)
Note over Legacy,New: Migration to new format
Test->>Legacy: call ToNewFormat()
Legacy->>New: copy state
Legacy->>New: map legacy field bits -> new Field_* bits (including Field_nPoSeBanHeight)
New-->>Test: CDeterministicMNStateDiff with mapped fields
end

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas to focus:
    • Correctness of legacy-to-new field bit mapping in ToNewFormat(), especially nPoSeBanHeightField_nPoSeBanHeight.
    • Conditional serialization/deserialization logic: VARINT field mask handling and per-field wrapper usage (pubKeyOperator via CBLSLazyPublicKeyVersionWrapper, NetInfoSerWrapper).
    • Tests in src/test/evo_deterministicmns_tests.cpp: ensure assertions accurately validate legacy round-trip, banned-state setup, and equality of operator key representations.
    • Update to legacy deserializer path (replacement of macro-based deserialization) for potential edge cases and backward compatibility.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
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.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main changes: splitting serialization/deserialization of CDeterministicMNStateDiffLegacy and improving tests.
Description check ✅ Passed The description is directly related to the changeset, explaining the issue, what was split/improved, and testing approach.
✨ 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 bd8bbcf and 4c8ae8e.

📒 Files selected for processing (2)
  • src/evo/dmnstate.h (1 hunks)
  • src/test/evo_deterministicmns_tests.cpp (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/test/evo_deterministicmns_tests.cpp
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.{cpp,h,cc,cxx,hpp}: Dash Core C++ codebase must be written in C++20 and require at least Clang 16 or GCC 11.1
Dash uses unordered_lru_cache for efficient caching with LRU eviction

Files:

  • src/evo/dmnstate.h
src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

Masternode lists must use immutable data structures (Immer library) for thread safety

Files:

  • src/evo/dmnstate.h
🧠 Learnings (3)
📓 Common learnings
Learnt from: kwvg
Repo: dashpay/dash PR: 6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: kwvg
Repo: dashpay/dash PR: 6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
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.
Learnt from: UdjinM6
Repo: dashpay/dash PR: 6786
File: ci/test/04_install.sh:99-101
Timestamp: 2025-08-01T07:46:37.840Z
Learning: In backport PRs like #6786, UdjinM6 prefers to defer non-critical fixes (such as shell command expansion issues) to separate commits/PRs to maintain focus on the primary backport objectives, consistent with the project's pattern of avoiding scope creep.
Learnt from: kwvg
Repo: dashpay/dash PR: 6665
File: src/evo/providertx.h:82-82
Timestamp: 2025-06-06T11:53:09.094Z
Learning: In ProTx serialization code (SERIALIZE_METHODS), version checks should use hardcoded maximum flags (/*is_basic_scheme_active=*/true, /*is_extended_addr=*/true) rather than deployment-based flags. This is because serialization code should be able to deserialize any structurally valid ProTx up to the maximum version the code knows how to handle, regardless of current consensus validity. Validation code, not serialization code, is responsible for checking whether a ProTx version is consensus-valid based on deployment status.
Learnt from: knst
Repo: dashpay/dash PR: 6805
File: src/wallet/rpc/wallet.cpp:357-357
Timestamp: 2025-08-08T07:01:47.332Z
Learning: In src/wallet/rpc/wallet.cpp, the upgradetohd RPC now returns a UniValue string message (RPCResult::Type::STR) instead of a boolean, including guidance about mnemonic backup and null-character passphrase handling; functional tests have been updated to assert returned strings in several cases.
📚 Learning: 2025-06-06T11:53:09.094Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6665
File: src/evo/providertx.h:82-82
Timestamp: 2025-06-06T11:53:09.094Z
Learning: In ProTx serialization code (SERIALIZE_METHODS), version checks should use hardcoded maximum flags (/*is_basic_scheme_active=*/true, /*is_extended_addr=*/true) rather than deployment-based flags. This is because serialization code should be able to deserialize any structurally valid ProTx up to the maximum version the code knows how to handle, regardless of current consensus validity. Validation code, not serialization code, is responsible for checking whether a ProTx version is consensus-valid based on deployment status.

Applied to files:

  • src/evo/dmnstate.h
📚 Learning: 2025-02-06T14:34:30.466Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.

Applied to files:

  • src/evo/dmnstate.h
🧬 Code graph analysis (1)
src/evo/dmnstate.h (1)
src/bls/bls.h (1)
  • CBLSLazyPublicKeyVersionWrapper (575-587)
🪛 GitHub Actions: Clang Diff Format Check
src/evo/dmnstate.h

[error] 357-384: Clang format differences detected. Run 'clang-format-diff.py -p1' or 'clang-format' to fix formatting in this file.

⏰ 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: mac-build / Build source
  • GitHub Check: linux64_sqlite-build / Build source
  • GitHub Check: linux64_ubsan-build / Build source
  • GitHub Check: linux64_fuzz-build / Build source
  • GitHub Check: linux64-build / Build source
  • GitHub Check: linux64_tsan-build / Build source
  • GitHub Check: linux64_nowallet-build / Build source
  • GitHub Check: win64-build / Build source
  • GitHub Check: arm-linux-build / Build source
  • GitHub Check: Lint / Run linters
🔇 Additional comments (1)
src/evo/dmnstate.h (1)

413-443: LGTM! ToNewFormat() correctly maps all legacy fields to new format.

The implementation properly:

  • Copies the state from legacy to new format
  • Maps all 19 legacy field bits to their corresponding new format positions
  • Returns a complete CDeterministicMNStateDiff with correct field masks

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 368eebb and bd8bbcf.

📒 Files selected for processing (2)
  • src/evo/dmnstate.h (1 hunks)
  • src/test/evo_deterministicmns_tests.cpp (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.{cpp,h,cc,cxx,hpp}: Dash Core C++ codebase must be written in C++20 and require at least Clang 16 or GCC 11.1
Dash uses unordered_lru_cache for efficient caching with LRU eviction

Files:

  • src/evo/dmnstate.h
  • src/test/evo_deterministicmns_tests.cpp
src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

Masternode lists must use immutable data structures (Immer library) for thread safety

Files:

  • src/evo/dmnstate.h
src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Files:

  • src/test/evo_deterministicmns_tests.cpp
🧠 Learnings (3)
📓 Common learnings
Learnt from: kwvg
Repo: dashpay/dash PR: 6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: kwvg
Repo: dashpay/dash PR: 6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
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.
Learnt from: UdjinM6
Repo: dashpay/dash PR: 6786
File: ci/test/04_install.sh:99-101
Timestamp: 2025-08-01T07:46:37.840Z
Learning: In backport PRs like #6786, UdjinM6 prefers to defer non-critical fixes (such as shell command expansion issues) to separate commits/PRs to maintain focus on the primary backport objectives, consistent with the project's pattern of avoiding scope creep.
📚 Learning: 2025-01-07T18:50:44.838Z
Learnt from: knst
Repo: dashpay/dash PR: 6511
File: src/evo/deterministicmns.cpp:1369-1373
Timestamp: 2025-01-07T18:50:44.838Z
Learning: The functions `MigrateDBIfNeeded` and `MigrateDBIfNeeded2` in `src/evo/deterministicmns.cpp` are temporary and will be removed in a future version. Refactoring suggestions for these functions should be avoided.

Applied to files:

  • src/test/evo_deterministicmns_tests.cpp
📚 Learning: 2025-06-06T11:53:09.094Z
Learnt from: kwvg
Repo: dashpay/dash PR: 6665
File: src/evo/providertx.h:82-82
Timestamp: 2025-06-06T11:53:09.094Z
Learning: In ProTx serialization code (SERIALIZE_METHODS), version checks should use hardcoded maximum flags (/*is_basic_scheme_active=*/true, /*is_extended_addr=*/true) rather than deployment-based flags. This is because serialization code should be able to deserialize any structurally valid ProTx up to the maximum version the code knows how to handle, regardless of current consensus validity. Validation code, not serialization code, is responsible for checking whether a ProTx version is consensus-valid based on deployment status.

Applied to files:

  • src/test/evo_deterministicmns_tests.cpp
🧬 Code graph analysis (2)
src/evo/dmnstate.h (1)
src/bls/bls.h (1)
  • CBLSLazyPublicKeyVersionWrapper (575-587)
src/test/evo_deterministicmns_tests.cpp (1)
src/evo/netinfo.cpp (2)
  • MakeNetInfo (273-280)
  • MakeNetInfo (273-273)
🪛 GitHub Actions: Clang Diff Format Check
src/evo/dmnstate.h

[error] 357-383: Clang-format differences found. Command failed: git diff -U0 origin/develop -- $(git ls-files -- $(cat test/util/data/non-backported.txt)) | ./contrib/devtools/clang-format-diff.py -p1 > diff_output.txt. Please run clang-format-diff.py to fix formatting issues in this file.

⏰ 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: mac-build / Build source
  • GitHub Check: linux64_tsan-build / Build source
  • GitHub Check: linux64_nowallet-build / Build source
  • GitHub Check: arm-linux-build / Build source
  • GitHub Check: win64-build / Build source
  • GitHub Check: linux64_ubsan-build / Build source
  • GitHub Check: linux64_sqlite-build / Build source
  • GitHub Check: linux64_fuzz-build / Build source
  • GitHub Check: linux64-build / Build source
  • GitHub Check: Lint / Run linters
🔇 Additional comments (4)
src/test/evo_deterministicmns_tests.cpp (2)

1131-1142: LGTM: Comprehensive legacy diff setup for migration testing.

The test correctly initializes a legacy diff with real BLS keys, ban state, and multiple fields to validate the serialization roundtrip and format conversion. The explicit checks ensure pubKeyOperator starts as non-legacy and ban state is properly initialized.


1150-1166: LGTM: Thorough validation of legacy-to-new format conversion.

The assertions correctly verify:

  • Original pubKeyOperator scheme is preserved before deserialization
  • Deserialized legacy format forces pubKeyOperator to legacy scheme as expected
  • All fields (nVersion, ban height, pubKeyOperator) are correctly mapped and preserved during conversion
  • pubKeyOperator scheme can be toggled post-conversion

This comprehensively validates the migration path.

src/evo/dmnstate.h (2)

386-409: LGTM: Correct legacy format deserialization.

The Unserialize method correctly handles legacy format:

  • Forces pubKeyOperator to legacy BLS scheme (line 396), as documented in the comment "We'll set proper scheme later in MigrateLegacyDiffs()"
  • Uses non-extended addresses for netInfo (line 401), consistent with legacy format constraints
  • Appropriately omits nVersion validation that exists in the new format, since legacy format had nVersion as the last field (0x40000), not first

412-442: LGTM: Clean field bit mapping for legacy-to-new conversion.

The ToNewFormat method correctly:

  • Copies the state including pubKeyOperator with its legacy scheme flag
  • Maps all 19 field bits from legacy positions to new positions
  • Uses macros to avoid repetition while maintaining clarity

The conversion preserves all state data while translating field bitmasks to the new layout.

…ffLegacy, only deser

We don't use ser for anything (yet)
Improvements:
- Compares against original values instead of hardcoded constants
- Verifies ban height round-trips correctly
- Verifies BLS key value is identical after round-trip (using Get() to force initialization)
- Verifies string representation matches
@UdjinM6 UdjinM6 force-pushed the fix_CDeterministicMNStateDiffLegacy_deser branch from bd8bbcf to 4c8ae8e Compare November 12, 2025 15:03
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