Skip to content

Commit 7b76e7a

Browse files
authored
Implement BIP9 style deployment for DIP8/ChainLocks and fix a bug with late headers (#2793)
* Also update bestChainLockWithKnownBlock in AcceptedBlockHeader * Implement BIP9 style DIP8 deployment * Fix ChainLocks tests * Apply suggestions from code review Co-Authored-By: codablock <ablock84@gmail.com>
1 parent 3ead8cd commit 7b76e7a

File tree

7 files changed

+84
-16
lines changed

7 files changed

+84
-16
lines changed

qa/rpc-tests/llmq-chainlocks.py

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ def __init__(self):
2121

2222
def run_test(self):
2323

24+
while self.nodes[0].getblockchaininfo()["bip9_softforks"]["dip0008"]["status"] != "active":
25+
self.nodes[0].generate(10)
26+
sync_blocks(self.nodes, timeout=60*5)
27+
2428
self.nodes[0].spork("SPORK_17_QUORUM_DKG_ENABLED", 0)
2529
self.nodes[0].spork("SPORK_19_CHAINLOCKS_ENABLED", 0)
2630
self.wait_for_sporks_same()

src/chainparams.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,13 @@ class CTestNetParams : public CChainParams {
435435
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nWindowSize = 100;
436436
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nThreshold = 50; // 50% of 100
437437

438+
// Deployment of DIP0008
439+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].bit = 4;
440+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nStartTime = 1553126400; // Mar 21st, 2019
441+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nTimeout = 1584748800; // Mar 21st, 2020
442+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nWindowSize = 100;
443+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nThreshold = 50; // 80% of 100
444+
438445
// The best chain should have at least this much work.
439446
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000000003cd72a542"); // 4000
440447

@@ -586,6 +593,13 @@ class CDevNetParams : public CChainParams {
586593
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nWindowSize = 100;
587594
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nThreshold = 50; // 50% of 100
588595

596+
// Deployment of DIP0008
597+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].bit = 4;
598+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nStartTime = 1553126400; // Mar 21st, 2019
599+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nTimeout = 1584748800; // Mar 21st, 2020
600+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nWindowSize = 100;
601+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nThreshold = 50; // 80% of 100
602+
589603
// The best chain should have at least this much work.
590604
consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000000000000000");
591605

@@ -731,6 +745,9 @@ class CRegTestParams : public CChainParams {
731745
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].bit = 3;
732746
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nStartTime = 0;
733747
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nTimeout = 999999999999ULL;
748+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].bit = 4;
749+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nStartTime = 0;
750+
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nTimeout = 999999999999ULL;
734751

735752
// The best chain should have at least this much work.
736753
consensus.nMinimumChainWork = uint256S("0x00");

src/consensus/params.h

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ enum DeploymentPos
1919
DEPLOYMENT_DIP0001, // Deployment of DIP0001 and lower transaction fees.
2020
DEPLOYMENT_BIP147, // Deployment of BIP147 (NULLDUMMY)
2121
DEPLOYMENT_DIP0003, // Deployment of DIP0002 and DIP0003 (txv3 and deterministic MN lists)
22+
DEPLOYMENT_DIP0008, // Deployment of ChainLock enforcement
2223
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp
2324
MAX_VERSION_BITS_DEPLOYMENTS
2425
};

src/llmq/quorums_chainlocks.cpp

+53-16
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ void CChainLocksHandler::Start()
4040
{
4141
quorumSigningManager->RegisterRecoveredSigsListener(this);
4242
scheduler->scheduleEvery([&]() {
43+
CheckActiveState();
4344
EnforceBestChainLock();
4445
// regularly retry signing the current chaintip as it might have failed before due to missing ixlocks
4546
TrySignChainTip();
@@ -153,6 +154,7 @@ void CChainLocksHandler::ProcessNewChainLock(NodeId from, const llmq::CChainLock
153154
}
154155

155156
scheduler->scheduleFromNow([&]() {
157+
CheckActiveState();
156158
EnforceBestChainLock();
157159
}, 0);
158160

@@ -177,6 +179,7 @@ void CChainLocksHandler::AcceptedBlockHeader(const CBlockIndex* pindexNew)
177179
// when EnforceBestChainLock is called later, it might end up invalidating other chains but not activating the
178180
// CLSIG locked chain. This happens when only the header is known but the block is still missing yet. The usual
179181
// block processing logic will handle this when the block arrives
182+
bestChainLockWithKnownBlock = bestChainLock;
180183
bestChainLockBlockIndex = pindexNew;
181184
}
182185
}
@@ -192,13 +195,38 @@ void CChainLocksHandler::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBl
192195
}
193196
tryLockChainTipScheduled = true;
194197
scheduler->scheduleFromNow([&]() {
198+
CheckActiveState();
195199
EnforceBestChainLock();
196200
TrySignChainTip();
197201
LOCK(cs);
198202
tryLockChainTipScheduled = false;
199203
}, 0);
200204
}
201205

206+
void CChainLocksHandler::CheckActiveState()
207+
{
208+
bool fDIP0008Active;
209+
{
210+
LOCK(cs_main);
211+
fDIP0008Active = VersionBitsState(chainActive.Tip()->pprev, Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0008, versionbitscache) == THRESHOLD_ACTIVE;
212+
}
213+
214+
LOCK(cs);
215+
bool oldIsEnforced = isEnforced;
216+
isSporkActive = sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED);
217+
isEnforced = fDIP0008Active && isSporkActive;
218+
219+
220+
if (!oldIsEnforced && isEnforced) {
221+
// ChainLocks got activated just recently, but it's possible that it was already running before, leaving
222+
// us with some stale values which we should not try to enforce anymore (there probably was a good reason to
223+
// to disable spork19)
224+
bestChainLockHash = uint256();
225+
bestChainLock = bestChainLockWithKnownBlock = CChainLockSig();
226+
bestChainLockBlockIndex = lastNotifyChainLockBlockIndex = nullptr;
227+
}
228+
}
229+
202230
void CChainLocksHandler::TrySignChainTip()
203231
{
204232
Cleanup();
@@ -215,9 +243,6 @@ void CChainLocksHandler::TrySignChainTip()
215243
if (!pindex->pprev) {
216244
return;
217245
}
218-
if (!sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED)) {
219-
return;
220-
}
221246

222247
// DIP8 defines a process called "Signing attempts" which should run before the CLSIG is finalized
223248
// To simplify the initial implementation, we skip this process and directly try to create a CLSIG
@@ -227,6 +252,10 @@ void CChainLocksHandler::TrySignChainTip()
227252
{
228253
LOCK(cs);
229254

255+
if (!isSporkActive) {
256+
return;
257+
}
258+
230259
if (pindex->nHeight == lastSignedHeight) {
231260
// already signed this one
232261
return;
@@ -348,7 +377,7 @@ void CChainLocksHandler::SyncTransaction(const CTransaction& tx, const CBlockInd
348377

349378
bool CChainLocksHandler::IsTxSafeForMining(const uint256& txid)
350379
{
351-
if (!sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED) || !sporkManager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) {
380+
if (!sporkManager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) {
352381
return true;
353382
}
354383
if (!IsNewInstantSendEnabled()) {
@@ -358,6 +387,9 @@ bool CChainLocksHandler::IsTxSafeForMining(const uint256& txid)
358387
int64_t txAge = 0;
359388
{
360389
LOCK(cs);
390+
if (!isEnforced) {
391+
return true;
392+
}
361393
auto it = txFirstSeenTime.find(txid);
362394
if (it != txFirstSeenTime.end()) {
363395
txAge = GetAdjustedTime() - it->second;
@@ -379,6 +411,11 @@ void CChainLocksHandler::EnforceBestChainLock()
379411
const CBlockIndex* currentBestChainLockBlockIndex;
380412
{
381413
LOCK(cs);
414+
415+
if (!isEnforced) {
416+
return;
417+
}
418+
382419
clsig = bestChainLockWithKnownBlock;
383420
pindex = currentBestChainLockBlockIndex = this->bestChainLockBlockIndex;
384421

@@ -442,14 +479,14 @@ void CChainLocksHandler::EnforceBestChainLock()
442479

443480
void CChainLocksHandler::HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig)
444481
{
445-
if (!sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED)) {
446-
return;
447-
}
448-
449482
CChainLockSig clsig;
450483
{
451484
LOCK(cs);
452485

486+
if (!isSporkActive) {
487+
return;
488+
}
489+
453490
if (recoveredSig.id != lastSignedRequestId || recoveredSig.msgHash != lastSignedMsgHash) {
454491
// this is not what we signed, so lets not create a CLSIG for it
455492
return;
@@ -495,10 +532,6 @@ void CChainLocksHandler::DoInvalidateBlock(const CBlockIndex* pindex, bool activ
495532

496533
bool CChainLocksHandler::HasChainLock(int nHeight, const uint256& blockHash)
497534
{
498-
if (!sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED)) {
499-
return false;
500-
}
501-
502535
LOCK(cs);
503536
return InternalHasChainLock(nHeight, blockHash);
504537
}
@@ -507,6 +540,10 @@ bool CChainLocksHandler::InternalHasChainLock(int nHeight, const uint256& blockH
507540
{
508541
AssertLockHeld(cs);
509542

543+
if (!isEnforced) {
544+
return false;
545+
}
546+
510547
if (!bestChainLockBlockIndex) {
511548
return false;
512549
}
@@ -525,10 +562,6 @@ bool CChainLocksHandler::InternalHasChainLock(int nHeight, const uint256& blockH
525562

526563
bool CChainLocksHandler::HasConflictingChainLock(int nHeight, const uint256& blockHash)
527564
{
528-
if (!sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED)) {
529-
return false;
530-
}
531-
532565
LOCK(cs);
533566
return InternalHasConflictingChainLock(nHeight, blockHash);
534567
}
@@ -537,6 +570,10 @@ bool CChainLocksHandler::InternalHasConflictingChainLock(int nHeight, const uint
537570
{
538571
AssertLockHeld(cs);
539572

573+
if (!isEnforced) {
574+
return false;
575+
}
576+
540577
if (!bestChainLockBlockIndex) {
541578
return false;
542579
}

src/llmq/quorums_chainlocks.h

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ class CChainLocksHandler : public CRecoveredSigsListener
5353
CScheduler* scheduler;
5454
CCriticalSection cs;
5555
bool tryLockChainTipScheduled{false};
56+
bool isSporkActive{false};
57+
bool isEnforced{false};
5658

5759
uint256 bestChainLockHash;
5860
CChainLockSig bestChainLock;
@@ -88,6 +90,7 @@ class CChainLocksHandler : public CRecoveredSigsListener
8890
void AcceptedBlockHeader(const CBlockIndex* pindexNew);
8991
void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork);
9092
void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock);
93+
void CheckActiveState();
9194
void TrySignChainTip();
9295
void EnforceBestChainLock();
9396
virtual void HandleNewRecoveredSig(const CRecoveredSig& recoveredSig);

src/rpc/blockchain.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1330,6 +1330,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
13301330
BIP9SoftForkDescPushBack(bip9_softforks, "csv", consensusParams, Consensus::DEPLOYMENT_CSV);
13311331
BIP9SoftForkDescPushBack(bip9_softforks, "dip0001", consensusParams, Consensus::DEPLOYMENT_DIP0001);
13321332
BIP9SoftForkDescPushBack(bip9_softforks, "dip0003", consensusParams, Consensus::DEPLOYMENT_DIP0003);
1333+
BIP9SoftForkDescPushBack(bip9_softforks, "dip0008", consensusParams, Consensus::DEPLOYMENT_DIP0008);
13331334
BIP9SoftForkDescPushBack(bip9_softforks, "bip147", consensusParams, Consensus::DEPLOYMENT_BIP147);
13341335
obj.push_back(Pair("softforks", softforks));
13351336
obj.push_back(Pair("bip9_softforks", bip9_softforks));

src/versionbits.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION
3131
/*.name =*/ "dip0003",
3232
/*.gbt_force =*/ true,
3333
/*.check_mn_protocol =*/ false,
34+
},
35+
{
36+
/*.name =*/ "dip0008",
37+
/*.gbt_force =*/ true,
38+
/*.check_mn_protocol =*/ false,
3439
}
3540
};
3641

0 commit comments

Comments
 (0)