Skip to content

Commit b15ed7e

Browse files
feat: add comprehensive tests for automatic chainlock detection
- Add 13 unit tests covering chainlock construction, serialization, edge cases - Add functional test for automatic coinbase chainlock processing - Add test utilities for LLMQ testing infrastructure - Fix compilation errors and add proper error handling - Add edge case validation for height overflow and invalid data All tests pass successfully, resolving WIP status.
1 parent 897ae86 commit b15ed7e

File tree

7 files changed

+704
-5
lines changed

7 files changed

+704
-5
lines changed

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ BITCOIN_TESTS =\
128128
test/lcg.h \
129129
test/limitedmap_tests.cpp \
130130
test/llmq_dkg_tests.cpp \
131+
test/llmq_chainlock_tests.cpp \
131132
test/logging_tests.cpp \
132133
test/dbwrapper_tests.cpp \
133134
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/llmq/chainlocks.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -387,12 +387,36 @@ void CChainLocksHandler::BlockConnected(const std::shared_ptr<const CBlock>& pbl
387387
txFirstSeenTime.emplace(tx->GetHash(), curTime);
388388
}
389389
}
390-
auto cbtx = GetCoinbaseTx(pindex);
391-
auto clsig_height = pindex->nHeight - cbtx->bestCLHeightDiff;
392390

393-
if (clsig_height > uint32_t(WITH_LOCK(cs, return bestChainLock.getHeight()))) {
394-
auto clsig = CChainLockSig(clsig_height, pindex->GetAncestor(clsig_height)->GetBlockHash(), cbtx->bestCLSignature);
395-
ProcessNewChainLock(-1, clsig, ::SerializeHash(clsig));
391+
// Check if coinbase transaction contains a chainlock signature
392+
auto opt_chainlock = GetNonNullCoinbaseChainlock(pindex);
393+
if (opt_chainlock.has_value()) {
394+
auto [clsig_sig, clsig_height_diff] = *opt_chainlock;
395+
auto clsig_height = pindex->nHeight - clsig_height_diff;
396+
397+
// Validate chainlock height is reasonable
398+
if (clsig_height < 0 || static_cast<uint32_t>(clsig_height) > static_cast<uint32_t>(pindex->nHeight)) {
399+
LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- Invalid chainlock height %d from coinbase (block height %d, height diff %d)\n",
400+
__func__, clsig_height, pindex->nHeight, clsig_height_diff);
401+
return;
402+
}
403+
404+
if (clsig_height > uint32_t(WITH_LOCK(cs, return bestChainLock.getHeight()))) {
405+
// Get the ancestor block for the chainlock
406+
const CBlockIndex* pindexAncestor = pindex->GetAncestor(clsig_height);
407+
if (!pindexAncestor) {
408+
LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- Cannot find ancestor block at height %d for chainlock\n",
409+
__func__, clsig_height);
410+
return;
411+
}
412+
413+
auto clsig = CChainLockSig(clsig_height, pindexAncestor->GetBlockHash(), clsig_sig);
414+
auto result = ProcessNewChainLock(-1, clsig, ::SerializeHash(clsig));
415+
if (result.m_error.has_value()) {
416+
LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- Failed to process chainlock from coinbase: %s\n",
417+
__func__, result.m_error->message);
418+
}
419+
}
396420
}
397421
}
398422

0 commit comments

Comments
 (0)