Skip to content

Commit 4f3cde6

Browse files
test: add comprehensive unit tests for LLMQ subsystem
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
1 parent f648039 commit 4f3cde6

File tree

9 files changed

+1349
-0
lines changed

9 files changed

+1349
-0
lines changed

src/Makefile.test.include

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ 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_test_utils.h \
137+
test/llmq_utils_tests.cpp \
131138
test/logging_tests.cpp \
132139
test/dbwrapper_tests.cpp \
133140
test/validation_tests.cpp \

src/test/llmq_chainlock_tests.cpp

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

0 commit comments

Comments
 (0)