-
Couldn't load subscription status.
- Fork 1.2k
refactor: optimize BLS serialization with stack-allocated arrays #6917
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
base: develop
Are you sure you want to change the base?
Conversation
Replace heap-allocated std::vector with stack-allocated std::array
for BLS cryptographic element serialization to improve cache efficiency
and eliminate unnecessary allocations.
Key changes:
- Add std::array serialization support to serialize.h with optimized
byte array handling (direct write without size prefix)
- Update CoinJoin signature storage (vchSig) to use std::array
- Optimize BLS IES encryption to use ToBytes() for stack allocation
- Simplify CoinJoin signing code to use SignBasic() helper
- Add Span-based SetSignature() overload for unified interface
- Replace hardcoded sizes with BLS constants (BLS_CURVE_SIG_SIZE,
BLS_CURVE_PUBKEY_SIZE, BLS_CURVE_ID_SIZE)
- Simplify CBLSWrapper::Serialize() to use MakeByteSpan()
Performance improvements (Apple M4 Pro, 500ms benchmark):
- Signature ToBytes: 201.90 ns/op vs ToByteVector: 216.54 ns/op (6.8% faster)
- PubKey ToBytes: 129.13 ns/op vs ToByteVector: 145.75 ns/op (11.4% faster)
- Direct serialization: 222.93 ns/op vs vector path: 291.00 ns/op (23.4% faster)
Testing:
- Split test cases for better organization (686 tests, all passing)
- Added array serialization tests (bytes, integers, bools, empty, BLS sizes)
- Added BLS ToBytes/ToByteVector comparison tests
- Added BLS signature array serialization test
Files modified:
- src/serialize.h: Add std::array serialization templates
- src/bls/bls.h: Use MakeByteSpan, maintain vector/array naming convention
- src/bls/bls_ies.cpp: Use ToBytes() for symmetric keys
- src/coinjoin/coinjoin.h: Change vchSig to std::array with zero-init
- src/coinjoin/server.cpp: Use SignBasic() for cleaner signing
- src/masternode/node.{h,cpp}: SignBasic() returns std::array
- src/governance/vote.h: Add Span overload for SetSignature
- src/governance/object.h: Update SetSignature to accept Span
- src/governance/signing.cpp: Use SignBasic() with ToBytes()
- src/wallet/wallet.cpp: Simplify SetSignature call
- src/test/serialize_tests.cpp: Add array serialization tests
- src/test/bls_tests.cpp: Add ToBytes comparison tests
- src/test/coinjoin_queue_tests.cpp: Use SignBasic()
- src/bench/bls.cpp: Add ToBytes vs ToByteVector benchmarks
✅ No Merge Conflicts DetectedThis PR currently has no conflicts with other open PRs. |
|
Note Other AI code review bot(s) detectedCodeRabbit 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. WalkthroughReplaces dynamic BLS byte vectors with fixed-size std::array buffers and adds std::array<T,N> serialization support. Signature-related storage and APIs were changed to fixed-size arrays (coinjoin signature fields, CActiveMasternodeManager::SignBasic return type). CBLS serialization now writes a single MakeByteSpan(ToBytes(...)); bls_ies switched ToByteVector(...)+resize to ToBytes(...). CGovernanceVote::SetSignature now accepts Span. Wallet sign path now forwards decoded signature directly. New unit tests and benchmarks for ToBytes/ToByteVector and array serialization were added; the benchmark block is duplicated in src/bench/bls.cpp. Sequence Diagram(s)sequenceDiagram
autonumber
participant Caller
participant BLSObj as BLS object (Sig/Pub/Sec)
participant ToBytes as ToBytes()
participant Stream as Serializer (Stream / MakeByteSpan)
Note over BLSObj,ToBytes: New flow returns fixed-size std::array
Caller->>BLSObj: request serialization
BLSObj->>ToBytes: ToBytes(false)
ToBytes-->>Caller: std::array<uint8_t, N>
Caller->>Stream: Serialize(MakeByteSpan(array))
Stream-->>Caller: bytes written
Note right of Stream: Deserialization reads into std::array and reconstructs via Span
sequenceDiagram
autonumber
participant Caller
participant Old as Old flow (ToByteVector)
participant New as New flow (ToBytes + array)
Note over Old,New: Comparison of old dynamic vs new fixed-size flow
Caller->>Old: ToByteVector() -> std::vector -> optional resize/assign
Caller->>New: ToBytes() -> std::array -> direct Serialize/assign via Span
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (2)
src/serialize.h (1)
1081-1121: std::array (de)serialization looks correct; consider fast-paths and clearer failure for char-arrays
- OK as-is. Two optional improvements:
- Add a raw-byte fast-path for std::array<std::byte, N> to avoid element-wise loops.
- Add a static_assert to reject std::array<char, N> with a clearer message than template substitution failure.
Example additions:
+template<typename Stream, size_t N> +inline void Serialize(Stream& s, const std::array<std::byte, N>& a) { + if constexpr (N > 0) s.write(AsBytes(Span{a})); +} +template<typename Stream, size_t N> +inline void Unserialize(Stream& s, std::array<std::byte, N>& a) { + if constexpr (N > 0) s.read(AsWritableBytes(Span{a})); +} + +template<typename T, size_t N> +struct _RejectCharArray : std::bool_constant<std::is_same_v<T, char>> {}; + +template<typename Stream, typename T, size_t N> +inline void Serialize(Stream& s, const std::array<T, N>& a) +{ + static_assert(!_RejectCharArray<T, N>::value, "std::array<char,N> serialization is forbidden; use uint8_t/std::byte"); + /* … existing body … */ +}src/bls/bls_ies.cpp (1)
47-51: Make AES key length intent explicitAES256 uses 32 bytes; ToBytes(false) for a public key returns 48 bytes. We currently pass symKey.data(), which works (first 32 bytes are read), but it’s non‑obvious. Add a guard and optionally slice for clarity.
For example:
+#include <array> +static_assert(BLS_CURVE_PUBKEY_SIZE >= 32, "BLS pubkey must be >= 32 bytes for AES-256 key derivation"); @@ - auto symKey = pk.ToBytes(false); + auto symKey = pk.ToBytes(false); // 48 bytes + // AES256 uses the first 32 bytes + const unsigned char* key32 = symKey.data(); @@ - return DecryptBlob(data.data(), data.size(), decryptedDataRet, symKey.data(), iv.begin()); + return DecryptBlob(data.data(), data.size(), decryptedDataRet, key32, iv.begin());Apply similarly in Encrypt() and multi‑recipient Decrypt().
Also applies to: 82-85, 103-106
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
src/bench/bls.cpp(2 hunks)src/bls/bls.h(2 hunks)src/bls/bls_ies.cpp(3 hunks)src/coinjoin/coinjoin.h(3 hunks)src/governance/vote.h(1 hunks)src/masternode/node.cpp(1 hunks)src/masternode/node.h(1 hunks)src/serialize.h(2 hunks)src/test/bls_tests.cpp(1 hunks)src/test/serialize_tests.cpp(2 hunks)src/wallet/wallet.cpp(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
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/masternode/node.cppsrc/bls/bls.hsrc/bls/bls_ies.cppsrc/governance/vote.hsrc/masternode/node.hsrc/serialize.hsrc/coinjoin/coinjoin.hsrc/test/serialize_tests.cppsrc/test/bls_tests.cppsrc/wallet/wallet.cppsrc/bench/bls.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/masternode/node.cppsrc/masternode/node.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/serialize_tests.cppsrc/test/bls_tests.cpp
src/bench/**/*.{cpp,h,cc,cxx,hpp}
📄 CodeRabbit inference engine (CLAUDE.md)
Performance benchmarks should be placed in src/bench/ and use nanobench
Files:
src/bench/bls.cpp
🧬 Code graph analysis (8)
src/masternode/node.cpp (2)
src/bls/bls.h (1)
nodiscard(291-332)src/masternode/node.h (2)
nodiscard(73-74)cs(46-81)
src/governance/vote.h (1)
src/governance/object.cpp (2)
SetSignature(247-250)SetSignature(247-247)
src/masternode/node.h (2)
src/bls/bls.h (2)
nodiscard(291-332)BLS_CURVE_SIG_SIZE(39-170)src/masternode/node.cpp (5)
nodiscard(262-267)nodiscard(273-277)nodiscard(279-285)nodiscard(289-293)SignBasic(279-279)
src/serialize.h (1)
src/bls/bls.h (5)
Serialize(161-164)Serialize(435-438)bool(395-476)bool(398-470)bool(399-459)
src/coinjoin/coinjoin.h (1)
src/bls/bls.h (1)
BLS_CURVE_SIG_SIZE(39-170)
src/test/serialize_tests.cpp (1)
src/bls/bls.h (2)
BLS_CURVE_SIG_SIZE(39-170)BLS_CURVE_PUBKEY_SIZE(38-176)
src/test/bls_tests.cpp (2)
src/evo/mnhftx.h (1)
sig(40-40)src/bls/bls.h (3)
BLS_CURVE_SIG_SIZE(39-170)BLS_CURVE_PUBKEY_SIZE(38-176)BLS_CURVE_SECKEY_SIZE(37-204)
src/bench/bls.cpp (1)
src/test/bls_tests.cpp (5)
bytes(496-496)bytes(496-496)bytes(499-499)bytes(499-499)ss(656-656)
🪛 GitHub Actions: Clang Diff Format Check
src/masternode/node.h
[error] 1-1: Clang format differences found in src/masternode/node.h. Run the formatting script to fix differences. Command failed with exit code 1.
src/test/bls_tests.cpp
[error] 1-1: Clang format differences found in src/test/bls_tests.cpp. Run the formatting script to fix differences. Command failed with exit code 1.
src/bench/bls.cpp
[error] 1-1: Clang format differences found in src/bench/bls.cpp. Run the formatting script to fix differences. Command failed with exit code 1.
🔇 Additional comments (12)
src/bls/bls.h (1)
169-170: LGTM: direct write from ToBytesWriting s.write(MakeByteSpan(ToBytes(...))) avoids extra allocations and is safe wrt temporary lifetime.
src/wallet/wallet.cpp (1)
2115-2116: LGTMPassing the decoded bytes directly to SetSignature(Span) removes an unnecessary copy.
src/masternode/node.cpp (1)
279-285: LGTMReturning sig.ToBytes(false) matches the new std::array<uint8_t, BLS_CURVE_SIG_SIZE> API and avoids heap allocation.
src/masternode/node.h (1)
70-71: API return type change verified as type-compatible with all call sitesGood change toward fixed-size signatures. All six call sites are confirmed compatible: coinjoin structures now have matching
std::array<uint8_t, BLS_CURVE_SIG_SIZE>fields, and governance structures properly useSetSignature(Span<const uint8_t>)which acceptsstd::arrayimplicitly.Address the clang-format issues flagged by CI for
src/masternode/node.h.src/bench/bls.cpp (1)
8-8: Cannot verify formatting compliance in sandbox; recommend local verificationThe code at line 8 and surrounding sections (362-443) appear visually well-formatted with consistent indentation and spacing. However, clang-format is unavailable in the sandbox environment, preventing conclusive verification of compliance with Dash project standards.
To resolve the original CI formatting failure, run clang-format locally using your repository's configuration:
clang-format -i src/bench/bls.cppThen verify the changes before committing.
src/test/serialize_tests.cpp (2)
5-5: LGTM!The BLS header inclusion is necessary for the BLS size constants used in the new test cases.
310-400: Excellent test coverage for array serialization!The six new test cases comprehensively validate
std::arrayserialization across different element types (uint8_t, int32_t, bool), sizes (empty, small, BLS-sized), and scenarios (single vs. multiple arrays). The verification that byte arrays serialize without a size prefix (line 318) and that BLS signature arrays serialize to exactlyBLS_CURVE_SIG_SIZE(line 371) are particularly important correctness checks.src/coinjoin/coinjoin.h (3)
10-10: LGTM!The BLS header inclusion is necessary for the BLS constants and types used in this file.
186-186: Excellent refactor to fixed-size array!The change from
std::vector<unsigned char>tostd::array<uint8_t, BLS_CURVE_SIG_SIZE>is semantically correct since BLS signatures are always 96 bytes. This eliminates unnecessary heap allocations and improves cache locality, aligning with the PR's performance optimization goals.
239-239: Consistent with CCoinJoinQueue changes!This change mirrors the
vchSigrefactor inCCoinJoinQueue, providing the same performance and semantic correctness benefits for BLS signatures in broadcast transactions.src/test/bls_tests.cpp (2)
596-644: Comprehensive validation of ToBytes vs ToByteVector equivalence!These three test cases effectively verify that the new array-based
ToBytes()method produces identical results to the existingToByteVector()method across all BLS types (signatures, public keys, secret keys). This is crucial for ensuring correctness of the optimization.
646-676: Remove this review comment - the CBLSSignature constructor exists and is correctly used.The constructor
CBLSSignature(Span<const unsigned char>, bool)is explicitly defined at line 345 ofsrc/bls/bls.h. The test code at line 674 correctly uses this constructor signature. No changes are needed.Likely an incorrect or invalid review comment.
There was a problem hiding this 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 optimizes BLS cryptographic serialization throughout Dash Core by replacing heap-allocated std::vector<uint8_t> with stack-allocated std::array<uint8_t, N> for fixed-size BLS elements (signatures, public keys, IDs). The changes add std::array serialization support to serialize.h with optimized byte array handling that omits the CompactSize prefix used by vectors, enabling direct writes for known-size cryptographic data. Key affected subsystems include CoinJoin signature storage, masternode signing operations (SignBasic() now returns std::array), governance vote signatures, and BLS IES encryption. The refactoring leverages compile-time size constants (BLS_CURVE_SIG_SIZE=96, BLS_CURVE_PUBKEY_SIZE=48) to eliminate dynamic allocations in cryptographic hot paths while maintaining wire format compatibility. Benchmarks demonstrate 6.8-23.4% performance improvements across different BLS operations, with better cache locality and reduced allocation overhead.
Important Files Changed
| Filename | Score | Overview |
|---|---|---|
| src/serialize.h | 5/5 | Adds std::array<T, N> serialization with optimized byte array handling (no size prefix) |
| src/masternode/node.h | 5/5 | Changes SignBasic() return type from std::vector to std::array<uint8_t, BLS_CURVE_SIG_SIZE> |
| src/masternode/node.cpp | 5/5 | Updates SignBasic() implementation to call ToBytes() instead of ToByteVector() |
| src/coinjoin/coinjoin.h | 5/5 | Converts signature fields (vchSig) from std::vector to std::array with zero-init |
| src/bls/bls.h | 5/5 | Simplifies Serialize() using MakeByteSpan() and replaces hardcoded sizes with BLS constants |
| src/bls/bls_ies.cpp | 5/5 | Switches BLS IES encryption to use ToBytes() for stack-allocated symmetric keys |
| src/governance/vote.h | 2/5 | Adds Span-based SetSignature() overload but internal storage remains std::vector |
| src/wallet/wallet.cpp | 5/5 | Simplifies SetSignature() call by passing decoded value directly using new Span overload |
| src/test/bls_tests.cpp | 5/5 | Adds comprehensive tests comparing ToBytes() vs ToByteVector() and array serialization |
| src/bench/bls.cpp | 5/5 | Adds benchmarks validating 6.8-23.4% performance improvements claimed in PR |
Confidence score: 4/5
- This PR is safe to merge with minimal risk, as it maintains wire format compatibility and includes comprehensive test coverage.
- Score lowered by one point because governance/vote.h adds a Span-based interface but retains
std::vectorinternal storage (inconsistent with the stack-allocation optimization goal), and the PR description lists files (src/governance/object.h, src/governance/signing.cpp, src/coinjoin/server.cpp, src/test/coinjoin_queue_tests.cpp) that are not present in the changed files, suggesting potential documentation/implementation mismatch. - Pay close attention to src/governance/vote.h, which may need follow-up work to convert internal storage to
std::arrayfor consistency with the rest of the refactoring.
Sequence Diagram
sequenceDiagram
participant User
Context used:
- Context from
dashboard- CLAUDE.md (source)
11 files reviewed, 4 comments
|
|
||
| std::vector<unsigned char> symKey = pk.ToByteVector(false); | ||
| symKey.resize(32); | ||
| auto symKey = pk.ToBytes(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think better to write directly type of symKey; it's not something super complicated but make code easier to read.
also consider {} initialization instead =
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it being std::array<uint8_t, BLS_PUBLIC_KEY_SIZE> really more readable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, because it's easy to see, that there's no allocation, and it's raw bytes, no any wrappers or overhead. I guess it's still subjective and anyway it's an opinion
| if constexpr (N > 0) { | ||
| os.write(MakeByteSpan(a)); | ||
| } | ||
| } else if constexpr (std::is_same_v<T, bool>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need a case of std::array<bool, N> ? I don't see any usage in code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think to just keep compatibility with the vector api.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM overall;
though I would suggest to remove bool-specialization that is not used at the moment - it is dead code that increase scope and it could be re-introduced when it's really needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
linter fails; whitespaces:
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
@@ -308,0 +310,92 @@ BOOST_AUTO_TEST_CASE(class_methods)
+
+
+
+
+
+
+
+
+
+
+
+
Also strange one:
In file included from /usr/include/x86_64-linux-gnu/c++/11/bits/os_defines.h:39,
from /usr/include/x86_64-linux-gnu/c++/11/bits/c++config.h:586,
from /usr/include/c++/11/cstdint:38,
from ./compat/byteswap.h:8,
from ./compat/endian.h:8,
from ./crypto/common.h:8,
from ./hash.h:11,
from ./bls/bls.h:8,
from test/bls_tests.cpp:5:
/usr/include/features.h:425:5: warning: #warning _FORTIFY_SOURCE > 2 is treated like 2 on this platform [-Wcpp]
425 | # warning _FORTIFY_SOURCE > 2 is treated like 2 on this platform
| ^~~~~~~
test/bls_tests.cpp: In member function ‘void bls_tests::bls_signature_array_serialization::test_method()’:
test/bls_tests.cpp:674:24: error: class template placeholder ‘Span’ not permitted in this context
674 | CBLSSignature sig3(Span{sig_array}, false);
| ^~~~
test/bls_tests.cpp:674:24: note: use ‘auto’ for an abbreviated function template
83d8f0a to
990e239
Compare
|
@knst latest should resolve that |
There was a problem hiding this 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
🧹 Nitpick comments (2)
src/bench/bls.cpp (1)
362-442: Stabilize microbench loops for lower variance.Optional: set minEpochIterations on these new benches (like elsewhere in this file) to reduce noise in CI and local runs.
Example:
- bench.run([&] { + bench.minEpochIterations(bench.output() ? 10000 : 100).run([&] { auto bytes = sig.ToBytes(false); ankerl::nanobench::doNotOptimizeAway(bytes); });(Apply similarly to the 5 other new benches.)
src/serialize.h (1)
1079-1123: Unify byte-span helpers and add std::byte fast-path; improve char diagnostics.
- Prefer AsBytes(Span{a})/AsWritableBytes(Span{a}) for std::array to avoid relying on MakeByteSpan overloads.
- Add a fast-path for std::array<std::byte, N> to write/read in a single call (parity with uint8_t).
- Optionally, add a static_assert for std::array<char, N> to produce a clear error (current path hits deleted char Serialize and is less obvious).
template<typename Stream, typename T, size_t N> void Serialize(Stream& os, const std::array<T, N>& a) { + static_assert(!std::is_same_v<T, char>, "std::array<char,N> not supported; use std::array<uint8_t,N> or std::array<std::byte,N>"); if constexpr (std::is_same_v<T, unsigned char>) { - // Directly write the byte data without writing the size - if constexpr (N > 0) { - os.write(MakeByteSpan(a)); - } + if constexpr (N > 0) os.write(AsBytes(Span{a})); + } else if constexpr (std::is_same_v<T, std::byte>) { + if constexpr (N > 0) os.write(AsBytes(Span{a})); } else if constexpr (std::is_same_v<T, bool>) { // Serialize each bool individually for (const bool& elem : a) { ::Serialize(os, elem); } } else { // Serialize each element using the default Serialize function for (const T& elem : a) { ::Serialize(os, elem); } } } template<typename Stream, typename T, size_t N> void Unserialize(Stream& is, std::array<T, N>& a) { + static_assert(!std::is_same_v<T, char>, "std::array<char,N> not supported; use std::array<uint8_t,N> or std::array<std::byte,N>"); if constexpr (std::is_same_v<T, unsigned char>) { - // Directly read the byte data without reading the size - if constexpr (N > 0) { - is.read(AsWritableBytes(Span{a})); - } + if constexpr (N > 0) is.read(AsWritableBytes(Span{a})); + } else if constexpr (std::is_same_v<T, std::byte>) { + if constexpr (N > 0) is.read(AsWritableBytes(Span{a})); } else if constexpr (std::is_same_v<T, bool>) { // Unserialize each bool individually for (bool& elem : a) { ::Unserialize(is, elem); } } else { // Unserialize each element using the default Unserialize function for (T& elem : a) { ::Unserialize(is, elem); } } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/bench/bls.cpp(2 hunks)src/governance/vote.h(2 hunks)src/masternode/node.h(1 hunks)src/serialize.h(3 hunks)src/test/bls_tests.cpp(2 hunks)src/test/serialize_tests.cpp(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/test/bls_tests.cpp
- src/test/serialize_tests.cpp
🧰 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/governance/vote.hsrc/masternode/node.hsrc/serialize.hsrc/bench/bls.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/masternode/node.h
src/bench/**/*.{cpp,h,cc,cxx,hpp}
📄 CodeRabbit inference engine (CLAUDE.md)
Performance benchmarks should be placed in src/bench/ and use nanobench
Files:
src/bench/bls.cpp
🧬 Code graph analysis (3)
src/governance/vote.h (2)
src/governance/object.cpp (2)
SetSignature(247-250)SetSignature(247-247)src/script/interpreter.cpp (1)
vchSig(1550-1550)
src/masternode/node.h (2)
src/masternode/node.cpp (5)
nodiscard(262-267)nodiscard(273-277)nodiscard(279-285)nodiscard(289-293)SignBasic(279-279)src/bls/bls.h (2)
nodiscard(291-332)BLS_CURVE_SIG_SIZE(39-170)
src/bench/bls.cpp (1)
src/test/bls_tests.cpp (5)
bytes(497-497)bytes(497-497)bytes(500-500)bytes(500-500)ss(657-657)
⏰ 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
🔇 Additional comments (5)
src/governance/vote.h (2)
10-10: LGTM: Span header included.The
#include <span.h>is now present and correctly resolves the dependency forSpan<const uint8_t>used inSetSignature.
95-95: LGTM: Span-based API is correct and consistent.The
SetSignatureimplementation correctly usesvchSig.assign(vchSigIn.begin(), vchSigIn.end())to copy the span into the vector storage. This API modernization improves flexibility (accepts arrays, vectors, spans) while maintaining the intentional vector storage for variable-size support. The implementation is consistent withCGovernanceObject::SetSignatureinsrc/governance/object.cpp.src/serialize.h (2)
13-13: Include for std::array — OK.Header now explicitly includes . LGTM.
842-847: Forward declarations for std::array — OK.Placement mirrors vector/prevector decls; keeps API surface consistent.
src/masternode/node.h (1)
71-72: No ripple effects detected; review comment is incorrect.Verification shows
vchSigmembers inCCoinJoinQueueandCCoinJoinBroadcastTxare already typed asstd::array<uint8_t, BLS_CURVE_SIG_SIZE>, matching theSignBasic()return type exactly. All call sites perform direct array-to-array assignments, andSetSignature()acceptsSpan<const uint8_t>, which implicitly converts from arrays. No code changes required at call sites.Likely an incorrect or invalid review comment.
| CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | ||
| ss << sig; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing include for PROTOCOL_VERSION (bench build may fail).
CDataStream uses PROTOCOL_VERSION here, but protocol.h isn’t included in this TU.
Apply near the other headers:
#include <streams.h>
+#include <protocol.h>Also applies to: 430-431
🤖 Prompt for AI Agents
In src/bench/bls.cpp around lines 417-418 (and similarly at 430-431), the code
uses PROTOCOL_VERSION via CDataStream but does not include protocol.h; add
#include "protocol.h" among the other header includes at the top of this TU so
PROTOCOL_VERSION is defined and the bench build will compile.
src/test/bls_tests.cpp
Outdated
| // Distributed under the MIT software license, see the accompanying | ||
| // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
|
||
| #include "span.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/"span.h"/<span.h>
| #include "span.h" | |
| #include <span.h> |
There was a problem hiding this 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)
src/test/bls_tests.cpp (2)
597-645: Consider testing both legacy schemes for consistency.These three test cases verify that
ToBytes()andToByteVector()produce identical results for signatures, public keys, and secret keys. The logic is correct and the tests are well-structured.However, all three tests hardcode
legacy_scheme = false, while other test cases in this file (e.g.,FuncSign,FuncSerialize,FuncKeyAgg) consistently test bothlegacy_scheme = trueandfalse. For consistency and comprehensive coverage, consider testing both schemes here as well.Example pattern used elsewhere in the file:
void FuncTestToBytes(const bool legacy_scheme) { bls::bls_legacy_scheme.store(legacy_scheme); // ... test logic ... } BOOST_AUTO_TEST_CASE(bls_tobytes_tests) { FuncTestToBytes(true); FuncTestToBytes(false); }
647-677: Constructor is correctly implemented; consider expanding to test both legacy schemes.The Span-accepting constructor does exist in
src/bls/bls.h(line 345) and is correctly used in the test. The pattern internally callsSetBytes(), so line 675 is valid.For improved test coverage, optionally expand the test to verify both
legacy_scheme = trueandlegacy_scheme = falsecases, ensuring consistent behavior across scheme modes.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/test/bls_tests.cpp(2 hunks)
🧰 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/test/bls_tests.cpp
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/bls_tests.cpp
🧬 Code graph analysis (1)
src/test/bls_tests.cpp (1)
src/bls/bls.h (3)
BLS_CURVE_SIG_SIZE(39-170)BLS_CURVE_PUBKEY_SIZE(38-176)BLS_CURVE_SECKEY_SIZE(37-204)
🔇 Additional comments (1)
src/test/bls_tests.cpp (1)
5-5: LGTM! Include style fixed.The change from
"span.h"to<span.h>correctly addresses the past review feedback and follows the proper convention for system headers.
| int64_t nTime{0}; | ||
| bool fReady{false}; //ready for submit | ||
| std::vector<unsigned char> vchSig; | ||
| std::array<uint8_t, BLS_CURVE_SIG_SIZE> vchSig{}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mixing fails with CCoinJoinQueue::CheckSignature -- VerifyInsecure() failed - should change serialization accordingly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does it fail?
| COutPoint masternodeOutpoint; | ||
| uint256 m_protxHash; | ||
| std::vector<unsigned char> vchSig; | ||
| std::array<uint8_t, BLS_CURVE_SIG_SIZE> vchSig{}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same
| } | ||
|
|
||
| void SetSignature(const std::vector<unsigned char>& vchSigIn) { vchSig = vchSigIn; } | ||
| void SetSignature(Span<const uint8_t> vchSigIn) { vchSig.assign(vchSigIn.begin(), vchSigIn.end()); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so basically back to ToByteVector results
Issue being fixed or feature implemented
Replace heap-allocated std::vector with stack-allocated std::array for BLS cryptographic element serialization to improve cache efficiency and eliminate unnecessary allocations.
Key changes:
What was done?
Performance improvements (Apple M4 Pro, 500ms benchmark):
Files modified:
How Has This Been Tested?
Breaking Changes
None
Checklist:
Go over all the following points, and put an
xin all the boxes that apply.