Skip to content

Commit

Permalink
Implement BIP9 style deployment for DIP8/ChainLocks and fix a bug wit…
Browse files Browse the repository at this point in the history
…h 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>
  • Loading branch information
codablock committed Mar 22, 2019
1 parent 3ead8cd commit 7b76e7a
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 16 deletions.
4 changes: 4 additions & 0 deletions qa/rpc-tests/llmq-chainlocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ def __init__(self):

def run_test(self):

while self.nodes[0].getblockchaininfo()["bip9_softforks"]["dip0008"]["status"] != "active":
self.nodes[0].generate(10)
sync_blocks(self.nodes, timeout=60*5)

self.nodes[0].spork("SPORK_17_QUORUM_DKG_ENABLED", 0)
self.nodes[0].spork("SPORK_19_CHAINLOCKS_ENABLED", 0)
self.wait_for_sporks_same()
Expand Down
17 changes: 17 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,13 @@ class CTestNetParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nWindowSize = 100;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nThreshold = 50; // 50% of 100

// Deployment of DIP0008
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].bit = 4;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nStartTime = 1553126400; // Mar 21st, 2019
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nTimeout = 1584748800; // Mar 21st, 2020
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nWindowSize = 100;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nThreshold = 50; // 80% of 100

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

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

// Deployment of DIP0008
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].bit = 4;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nStartTime = 1553126400; // Mar 21st, 2019
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nTimeout = 1584748800; // Mar 21st, 2020
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nWindowSize = 100;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nThreshold = 50; // 80% of 100

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

Expand Down Expand Up @@ -731,6 +745,9 @@ class CRegTestParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].bit = 3;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0003].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].bit = 4;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0008].nTimeout = 999999999999ULL;

// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00");
Expand Down
1 change: 1 addition & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ enum DeploymentPos
DEPLOYMENT_DIP0001, // Deployment of DIP0001 and lower transaction fees.
DEPLOYMENT_BIP147, // Deployment of BIP147 (NULLDUMMY)
DEPLOYMENT_DIP0003, // Deployment of DIP0002 and DIP0003 (txv3 and deterministic MN lists)
DEPLOYMENT_DIP0008, // Deployment of ChainLock enforcement
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp
MAX_VERSION_BITS_DEPLOYMENTS
};
Expand Down
69 changes: 53 additions & 16 deletions src/llmq/quorums_chainlocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ void CChainLocksHandler::Start()
{
quorumSigningManager->RegisterRecoveredSigsListener(this);
scheduler->scheduleEvery([&]() {
CheckActiveState();
EnforceBestChainLock();
// regularly retry signing the current chaintip as it might have failed before due to missing ixlocks
TrySignChainTip();
Expand Down Expand Up @@ -153,6 +154,7 @@ void CChainLocksHandler::ProcessNewChainLock(NodeId from, const llmq::CChainLock
}

scheduler->scheduleFromNow([&]() {
CheckActiveState();
EnforceBestChainLock();
}, 0);

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

void CChainLocksHandler::CheckActiveState()
{
bool fDIP0008Active;
{
LOCK(cs_main);
fDIP0008Active = VersionBitsState(chainActive.Tip()->pprev, Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0008, versionbitscache) == THRESHOLD_ACTIVE;
}

LOCK(cs);
bool oldIsEnforced = isEnforced;
isSporkActive = sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED);
isEnforced = fDIP0008Active && isSporkActive;


if (!oldIsEnforced && isEnforced) {
// ChainLocks got activated just recently, but it's possible that it was already running before, leaving
// us with some stale values which we should not try to enforce anymore (there probably was a good reason to
// to disable spork19)
bestChainLockHash = uint256();
bestChainLock = bestChainLockWithKnownBlock = CChainLockSig();
bestChainLockBlockIndex = lastNotifyChainLockBlockIndex = nullptr;
}
}

void CChainLocksHandler::TrySignChainTip()
{
Cleanup();
Expand All @@ -215,9 +243,6 @@ void CChainLocksHandler::TrySignChainTip()
if (!pindex->pprev) {
return;
}
if (!sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED)) {
return;
}

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

if (!isSporkActive) {
return;
}

if (pindex->nHeight == lastSignedHeight) {
// already signed this one
return;
Expand Down Expand Up @@ -348,7 +377,7 @@ void CChainLocksHandler::SyncTransaction(const CTransaction& tx, const CBlockInd

bool CChainLocksHandler::IsTxSafeForMining(const uint256& txid)
{
if (!sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED) || !sporkManager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) {
if (!sporkManager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) {
return true;
}
if (!IsNewInstantSendEnabled()) {
Expand All @@ -358,6 +387,9 @@ bool CChainLocksHandler::IsTxSafeForMining(const uint256& txid)
int64_t txAge = 0;
{
LOCK(cs);
if (!isEnforced) {
return true;
}
auto it = txFirstSeenTime.find(txid);
if (it != txFirstSeenTime.end()) {
txAge = GetAdjustedTime() - it->second;
Expand All @@ -379,6 +411,11 @@ void CChainLocksHandler::EnforceBestChainLock()
const CBlockIndex* currentBestChainLockBlockIndex;
{
LOCK(cs);

if (!isEnforced) {
return;
}

clsig = bestChainLockWithKnownBlock;
pindex = currentBestChainLockBlockIndex = this->bestChainLockBlockIndex;

Expand Down Expand Up @@ -442,14 +479,14 @@ void CChainLocksHandler::EnforceBestChainLock()

void CChainLocksHandler::HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig)
{
if (!sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED)) {
return;
}

CChainLockSig clsig;
{
LOCK(cs);

if (!isSporkActive) {
return;
}

if (recoveredSig.id != lastSignedRequestId || recoveredSig.msgHash != lastSignedMsgHash) {
// this is not what we signed, so lets not create a CLSIG for it
return;
Expand Down Expand Up @@ -495,10 +532,6 @@ void CChainLocksHandler::DoInvalidateBlock(const CBlockIndex* pindex, bool activ

bool CChainLocksHandler::HasChainLock(int nHeight, const uint256& blockHash)
{
if (!sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED)) {
return false;
}

LOCK(cs);
return InternalHasChainLock(nHeight, blockHash);
}
Expand All @@ -507,6 +540,10 @@ bool CChainLocksHandler::InternalHasChainLock(int nHeight, const uint256& blockH
{
AssertLockHeld(cs);

if (!isEnforced) {
return false;
}

if (!bestChainLockBlockIndex) {
return false;
}
Expand All @@ -525,10 +562,6 @@ bool CChainLocksHandler::InternalHasChainLock(int nHeight, const uint256& blockH

bool CChainLocksHandler::HasConflictingChainLock(int nHeight, const uint256& blockHash)
{
if (!sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED)) {
return false;
}

LOCK(cs);
return InternalHasConflictingChainLock(nHeight, blockHash);
}
Expand All @@ -537,6 +570,10 @@ bool CChainLocksHandler::InternalHasConflictingChainLock(int nHeight, const uint
{
AssertLockHeld(cs);

if (!isEnforced) {
return false;
}

if (!bestChainLockBlockIndex) {
return false;
}
Expand Down
3 changes: 3 additions & 0 deletions src/llmq/quorums_chainlocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class CChainLocksHandler : public CRecoveredSigsListener
CScheduler* scheduler;
CCriticalSection cs;
bool tryLockChainTipScheduled{false};
bool isSporkActive{false};
bool isEnforced{false};

uint256 bestChainLockHash;
CChainLockSig bestChainLock;
Expand Down Expand Up @@ -88,6 +90,7 @@ class CChainLocksHandler : public CRecoveredSigsListener
void AcceptedBlockHeader(const CBlockIndex* pindexNew);
void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork);
void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock);
void CheckActiveState();
void TrySignChainTip();
void EnforceBestChainLock();
virtual void HandleNewRecoveredSig(const CRecoveredSig& recoveredSig);
Expand Down
1 change: 1 addition & 0 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
BIP9SoftForkDescPushBack(bip9_softforks, "csv", consensusParams, Consensus::DEPLOYMENT_CSV);
BIP9SoftForkDescPushBack(bip9_softforks, "dip0001", consensusParams, Consensus::DEPLOYMENT_DIP0001);
BIP9SoftForkDescPushBack(bip9_softforks, "dip0003", consensusParams, Consensus::DEPLOYMENT_DIP0003);
BIP9SoftForkDescPushBack(bip9_softforks, "dip0008", consensusParams, Consensus::DEPLOYMENT_DIP0008);
BIP9SoftForkDescPushBack(bip9_softforks, "bip147", consensusParams, Consensus::DEPLOYMENT_BIP147);
obj.push_back(Pair("softforks", softforks));
obj.push_back(Pair("bip9_softforks", bip9_softforks));
Expand Down
5 changes: 5 additions & 0 deletions src/versionbits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION
/*.name =*/ "dip0003",
/*.gbt_force =*/ true,
/*.check_mn_protocol =*/ false,
},
{
/*.name =*/ "dip0008",
/*.gbt_force =*/ true,
/*.check_mn_protocol =*/ false,
}
};

Expand Down

0 comments on commit 7b76e7a

Please sign in to comment.