Skip to content

Commit 68dec34

Browse files
Merge #6691: test: add comprehensive unit tests for LLMQ subsystem
e08d628 chore: run clang-format (pasta) e5431a4 fix: update copyright year to 2025 in LLMQ test files (pasta) 72cbe5f fix: address knst review feedback for LLMQ unit tests (pasta) f97c705 fix: remove trailing whitespace in llmq_tests.h (pasta) d9ddc3f build: add llmq_tests.h to TEST_UTIL_H list (pasta) 9a8eb89 test: address review comments for LLMQ unit tests (pasta) 4744cfc test: add TODO comments for disabled serialization tests (pasta) 3e5a532 build: remove header file from BITCOIN_TESTS list (pasta) 4f3cde6 test: add comprehensive unit tests for LLMQ subsystem (pasta) Pull request description: ## What was done? Adds unit test coverage for core LLMQ components that were previously only covered by functional tests. New test files: - llmq_commitment_tests.cpp: CFinalCommitment serialization, validation - llmq_chainlock_tests.cpp: CChainLockSig construction and serialization - llmq_hash_tests.cpp: BuildCommitmentHash deterministic behavior - llmq_params_tests.cpp: LLMQParams calculations for rotated/non-rotated quorums - llmq_snapshot_tests.cpp: CQuorumSnapshot and CQuorumRotationInfo structures - llmq_utils_tests.cpp: DeterministicOutboundConnection behavior - llmq_test_utils.h: Common test utilities and helpers ## How Has This Been Tested? Running unit tests ## Breaking Changes None ## Checklist: - [x] 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 - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_ ACKs for top commit: UdjinM6: utACK e08d628 Tree-SHA512: 20ab05d37bce0246d0e568d3be90f4621f1010875cc295169cc083f0a7b27077df6ee8425cdc7397de636b437a88d18200788d338d90858323e5728f6d1e3d86
2 parents 38ddeb3 + e08d628 commit 68dec34

File tree

10 files changed

+1366
-0
lines changed

10 files changed

+1366
-0
lines changed

src/Makefile.test.include

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ BITCOIN_TESTS =\
128128
test/lcg.h \
129129
test/limitedmap_tests.cpp \
130130
test/llmq_dkg_tests.cpp \
131+
test/llmq_chainlock_tests.cpp \
132+
test/llmq_commitment_tests.cpp \
133+
test/llmq_hash_tests.cpp \
134+
test/llmq_params_tests.cpp \
135+
test/llmq_snapshot_tests.cpp \
136+
test/llmq_utils_tests.cpp \
131137
test/logging_tests.cpp \
132138
test/dbwrapper_tests.cpp \
133139
test/validation_tests.cpp \

src/Makefile.test_util.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ TEST_UTIL_H = \
1212
test/util/chainstate.h \
1313
test/util/json.h \
1414
test/util/index.h \
15+
test/util/llmq_tests.h \
1516
test/util/logging.h \
1617
test/util/mining.h \
1718
test/util/net.h \

src/test/llmq_chainlock_tests.cpp

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
// Copyright (c) 2025 The Dash Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <test/util/llmq_tests.h>
6+
#include <test/util/setup_common.h>
7+
8+
#include <llmq/clsig.h>
9+
#include <streams.h>
10+
#include <util/strencodings.h>
11+
12+
#include <boost/test/unit_test.hpp>
13+
14+
using namespace llmq;
15+
using namespace llmq::testutils;
16+
17+
BOOST_FIXTURE_TEST_SUITE(llmq_chainlock_tests, BasicTestingSetup)
18+
19+
BOOST_AUTO_TEST_CASE(chainlock_construction_test)
20+
{
21+
// Test default constructor
22+
CChainLockSig clsig1;
23+
BOOST_CHECK(clsig1.IsNull());
24+
BOOST_CHECK_EQUAL(clsig1.getHeight(), -1);
25+
BOOST_CHECK(clsig1.getBlockHash().IsNull());
26+
BOOST_CHECK(!clsig1.getSig().IsValid());
27+
28+
// Test parameterized constructor
29+
int32_t height = 12345;
30+
uint256 blockHash = GetTestBlockHash(1);
31+
CBLSSignature sig = CreateRandomBLSSignature();
32+
33+
CChainLockSig clsig2(height, blockHash, sig);
34+
BOOST_CHECK(!clsig2.IsNull());
35+
BOOST_CHECK_EQUAL(clsig2.getHeight(), height);
36+
BOOST_CHECK(clsig2.getBlockHash() == blockHash);
37+
BOOST_CHECK(clsig2.getSig() == sig);
38+
}
39+
40+
BOOST_AUTO_TEST_CASE(chainlock_null_test)
41+
{
42+
CChainLockSig clsig;
43+
44+
// Default constructed should be null
45+
BOOST_CHECK(clsig.IsNull());
46+
47+
// With height set but null hash, should not be null
48+
clsig = CChainLockSig(100, uint256(), CBLSSignature());
49+
BOOST_CHECK(!clsig.IsNull());
50+
51+
// With valid data should not be null
52+
clsig = CreateChainLock(100, GetTestBlockHash(1));
53+
BOOST_CHECK(!clsig.IsNull());
54+
}
55+
56+
BOOST_AUTO_TEST_CASE(chainlock_serialization_test)
57+
{
58+
// Test with valid chainlock
59+
CChainLockSig clsig = CreateChainLock(67890, GetTestBlockHash(42));
60+
61+
// Test serialization preserves all fields
62+
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
63+
ss << clsig;
64+
65+
CChainLockSig deserialized;
66+
ss >> deserialized;
67+
68+
BOOST_CHECK_EQUAL(clsig.getHeight(), deserialized.getHeight());
69+
BOOST_CHECK(clsig.getBlockHash() == deserialized.getBlockHash());
70+
BOOST_CHECK(clsig.getSig() == deserialized.getSig());
71+
BOOST_CHECK_EQUAL(clsig.IsNull(), deserialized.IsNull());
72+
}
73+
74+
BOOST_AUTO_TEST_CASE(chainlock_tostring_test)
75+
{
76+
// Test null chainlock
77+
CChainLockSig nullClsig;
78+
std::string nullStr = nullClsig.ToString();
79+
BOOST_CHECK(!nullStr.empty());
80+
81+
// Test valid chainlock
82+
int32_t height = 123456;
83+
uint256 blockHash = GetTestBlockHash(789);
84+
CChainLockSig clsig = CreateChainLock(height, blockHash);
85+
86+
std::string str = clsig.ToString();
87+
BOOST_CHECK(!str.empty());
88+
89+
// ToString should contain height and hash info
90+
BOOST_CHECK(str.find(strprintf("%d", height)) != std::string::npos);
91+
BOOST_CHECK(str.find(blockHash.ToString().substr(0, 10)) != std::string::npos);
92+
}
93+
94+
BOOST_AUTO_TEST_CASE(chainlock_edge_cases_test)
95+
{
96+
// Test with edge case heights
97+
CChainLockSig clsig1 = CreateChainLock(0, GetTestBlockHash(1));
98+
BOOST_CHECK_EQUAL(clsig1.getHeight(), 0);
99+
BOOST_CHECK(!clsig1.IsNull());
100+
101+
CChainLockSig clsig2 = CreateChainLock(std::numeric_limits<int32_t>::max(), GetTestBlockHash(2));
102+
BOOST_CHECK_EQUAL(clsig2.getHeight(), std::numeric_limits<int32_t>::max());
103+
104+
// Test serialization with extreme values
105+
CDataStream ss1(SER_NETWORK, PROTOCOL_VERSION);
106+
ss1 << clsig1;
107+
CChainLockSig clsig1_deserialized;
108+
ss1 >> clsig1_deserialized;
109+
BOOST_CHECK_EQUAL(clsig1.getHeight(), clsig1_deserialized.getHeight());
110+
111+
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
112+
ss2 << clsig2;
113+
CChainLockSig clsig2_deserialized;
114+
ss2 >> clsig2_deserialized;
115+
BOOST_CHECK_EQUAL(clsig2.getHeight(), clsig2_deserialized.getHeight());
116+
}
117+
118+
BOOST_AUTO_TEST_CASE(chainlock_comparison_test)
119+
{
120+
// Create identical chainlocks
121+
int32_t height = 5000;
122+
uint256 blockHash = GetTestBlockHash(10);
123+
CBLSSignature sig = CreateRandomBLSSignature();
124+
125+
CChainLockSig clsig1(height, blockHash, sig);
126+
CChainLockSig clsig2(height, blockHash, sig);
127+
128+
// Verify getters return same values
129+
BOOST_CHECK_EQUAL(clsig1.getHeight(), clsig2.getHeight());
130+
BOOST_CHECK(clsig1.getBlockHash() == clsig2.getBlockHash());
131+
BOOST_CHECK(clsig1.getSig() == clsig2.getSig());
132+
133+
// Different chainlocks
134+
CChainLockSig clsig3(height + 1, blockHash, sig);
135+
BOOST_CHECK(clsig1.getHeight() != clsig3.getHeight());
136+
137+
CChainLockSig clsig4(height, GetTestBlockHash(11), sig);
138+
BOOST_CHECK(clsig1.getBlockHash() != clsig4.getBlockHash());
139+
}
140+
141+
BOOST_AUTO_TEST_CASE(chainlock_malformed_data_test)
142+
{
143+
// Test deserialization of truncated data
144+
CChainLockSig clsig = CreateChainLock(1000, GetTestBlockHash(5));
145+
146+
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
147+
ss << clsig;
148+
149+
// Truncate the stream
150+
std::string data = ss.str();
151+
for (size_t truncateAt = 1; truncateAt < data.size(); truncateAt += 10) {
152+
CDataStream truncated(std::vector<unsigned char>(data.begin(), data.begin() + truncateAt), SER_NETWORK,
153+
PROTOCOL_VERSION);
154+
155+
CChainLockSig deserialized;
156+
try {
157+
truncated >> deserialized;
158+
// If no exception, verify it's either complete or default
159+
if (truncateAt < sizeof(int32_t)) {
160+
BOOST_CHECK(deserialized.IsNull());
161+
}
162+
} catch (const std::exception&) {
163+
// Expected for most truncation points
164+
}
165+
}
166+
}
167+
168+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)