Skip to content

Commit 0f8cf34

Browse files
authored
Fix staker crash on invalidateblock (#1741)
* Fix staker crash on rollback * Make GetTimelock return optional * Invert logic for require
1 parent d2eaa8a commit 0f8cf34

File tree

6 files changed

+34
-19
lines changed

6 files changed

+34
-19
lines changed

src/masternodes/masternodes.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,11 @@ Res CMasternodesView::ResignMasternode(CMasternode &node, const uint256 &nodeId,
325325
return Res::Err("node %s state is not 'PRE_ENABLED' or 'ENABLED'", nodeId.ToString());
326326
}
327327

328-
Require(!GetTimelock(nodeId, node, height), "Trying to resign masternode before timelock expiration.");
328+
const auto timelock = GetTimelock(nodeId, node, height);
329+
if (!timelock) {
330+
return Res::Err("Failed to get timelock for masternode");
331+
}
332+
Require(timelock.value() == CMasternode::ZEROYEAR, "Trying to resign masternode before timelock expiration.");
329333

330334
node.resignTx = txid;
331335
node.resignHeight = height;
@@ -522,9 +526,8 @@ void CMasternodesView::EraseSubNodesLastBlockTime(const uint256 &nodeId, const u
522526
}
523527
}
524528

525-
uint16_t CMasternodesView::GetTimelock(const uint256 &nodeId, const CMasternode &node, const uint64_t height) const {
526-
auto timelock = ReadBy<Timelock, uint16_t>(nodeId);
527-
if (timelock) {
529+
std::optional<uint16_t> CMasternodesView::GetTimelock(const uint256 &nodeId, const CMasternode &node, const uint64_t height) const {
530+
if (const auto timelock = ReadBy<Timelock, uint16_t>(nodeId); timelock) {
528531
LOCK(cs_main);
529532
// Get last height
530533
auto lastHeight = height - 1;
@@ -540,7 +543,12 @@ uint16_t CMasternodesView::GetTimelock(const uint256 &nodeId, const CMasternode
540543
// Get average time of the last two times the activation delay worth of blocks
541544
uint64_t totalTime{0};
542545
for (; lastHeight + Params().GetConsensus().mn.newResignDelay >= height; --lastHeight) {
543-
totalTime += ::ChainActive()[lastHeight]->nTime;
546+
const auto &blockIndex{::ChainActive()[lastHeight]};
547+
// Last height might not be available due to rollback or call to invalidateblock
548+
if (!blockIndex) {
549+
return {};
550+
}
551+
totalTime += blockIndex->nTime;
544552
}
545553
const uint32_t averageTime = totalTime / Params().GetConsensus().mn.newResignDelay;
546554

src/masternodes/masternodes.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ class CMasternodesView : public virtual CStorageView {
263263
uint8_t{},
264264
std::numeric_limits<uint32_t>::max()});
265265

266-
uint16_t GetTimelock(const uint256 &nodeId, const CMasternode &node, const uint64_t height) const;
266+
std::optional<uint16_t> GetTimelock(const uint256 &nodeId, const CMasternode &node, const uint64_t height) const;
267267

268268
// tags
269269
struct ID {

src/masternodes/rpc_masternodes.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,15 @@ UniValue mnToJSON(CCustomCSView& view, uint256 const & nodeId, CMasternode const
4545
}
4646
obj.pushKV("localMasternode", localMasternode);
4747

48-
uint16_t timelock = pcustomcsview->GetTimelock(nodeId, node, currentHeight);
48+
const auto timelock = pcustomcsview->GetTimelock(nodeId, node, currentHeight);
4949

5050
// Only get targetMultiplier for active masternodes
51-
if (node.IsActive(currentHeight, view)) {
51+
if (timelock && node.IsActive(currentHeight, view)) {
5252
// Get block times with next block as height
53-
const auto subNodesBlockTime = pcustomcsview->GetBlockTimes(node.operatorAuthAddress, currentHeight + 1, node.creationHeight, timelock);
53+
const auto subNodesBlockTime = pcustomcsview->GetBlockTimes(node.operatorAuthAddress, currentHeight + 1, node.creationHeight, *timelock);
5454

5555
if (currentHeight >= Params().GetConsensus().EunosPayaHeight) {
56-
const uint8_t loops = timelock == CMasternode::TENYEAR ? 4 : timelock == CMasternode::FIVEYEAR ? 3 : 2;
56+
const uint8_t loops = *timelock == CMasternode::TENYEAR ? 4 : *timelock == CMasternode::FIVEYEAR ? 3 : 2;
5757
UniValue multipliers(UniValue::VARR);
5858
for (uint8_t i{0}; i < loops; ++i) {
5959
multipliers.push_back(pos::CalcCoinDayWeight(Params().GetConsensus(), GetTime(), subNodesBlockTime[i]).getdouble());
@@ -64,8 +64,8 @@ UniValue mnToJSON(CCustomCSView& view, uint256 const & nodeId, CMasternode const
6464
}
6565
}
6666

67-
if (timelock) {
68-
obj.pushKV("timelock", strprintf("%d years", timelock / 52));
67+
if (timelock && *timelock) {
68+
obj.pushKV("timelock", strprintf("%d years", *timelock / 52));
6969
}
7070

7171
/// @todo add unlock height and|or real resign height

src/miner.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,11 @@ namespace pos {
777777
blockHeight = tip->nHeight + 1;
778778
creationHeight = int64_t(nodePtr->creationHeight);
779779
blockTime = std::max(tip->GetMedianTimePast() + 1, GetAdjustedTime());
780-
timelock = pcustomcsview->GetTimelock(masternodeID, *nodePtr, blockHeight);
780+
const auto optTimeLock = pcustomcsview->GetTimelock(masternodeID, *nodePtr, blockHeight);
781+
if (!optTimeLock)
782+
return Status::stakeWaiting;
783+
784+
timelock = *optTimeLock;
781785

782786
// Get block times
783787
subNodesBlockTime = pcustomcsview->GetBlockTimes(args.operatorID, blockHeight, creationHeight, timelock);

src/pos.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ bool ContextualCheckProofOfStake(const CBlockHeader& blockHeader, const Consensu
7575
creationHeight = int64_t(nodePtr->creationHeight);
7676

7777
if (height >= params.EunosPayaHeight) {
78-
timelock = mnView->GetTimelock(masternodeID, *nodePtr, height);
78+
const auto optTimeLock = mnView->GetTimelock(masternodeID, *nodePtr, height);
79+
if (!optTimeLock)
80+
return false;
81+
timelock = *optTimeLock;
7982
}
8083

8184
// Check against EunosPayaHeight here for regtest, does not hurt other networks.

src/rpc/mining.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -300,12 +300,12 @@ static UniValue getmininginfo(const JSONRPCRequest& request)
300300
const auto timelock = pcustomcsview->GetTimelock(mnId.second, *nodePtr, height);
301301

302302
// Get targetMultiplier if node is active
303-
if (nodePtr->IsActive(height, *pcustomcsview)) {
303+
if (timelock && nodePtr->IsActive(height, *pcustomcsview)) {
304304
// Get block times
305-
const auto subNodesBlockTime = pcustomcsview->GetBlockTimes(nodePtr->operatorAuthAddress, height, nodePtr->creationHeight, timelock);
305+
const auto subNodesBlockTime = pcustomcsview->GetBlockTimes(nodePtr->operatorAuthAddress, height, nodePtr->creationHeight, *timelock);
306306

307307
if (height >= Params().GetConsensus().EunosPayaHeight) {
308-
const uint8_t loops = timelock == CMasternode::TENYEAR ? 4 : timelock == CMasternode::FIVEYEAR ? 3 : 2;
308+
const uint8_t loops = *timelock == CMasternode::TENYEAR ? 4 : *timelock == CMasternode::FIVEYEAR ? 3 : 2;
309309
UniValue multipliers(UniValue::VARR);
310310
for (uint8_t i{0}; i < loops; ++i) {
311311
multipliers.push_back(pos::CalcCoinDayWeight(Params().GetConsensus(), GetTime(), subNodesBlockTime[i]).getdouble());
@@ -316,8 +316,8 @@ static UniValue getmininginfo(const JSONRPCRequest& request)
316316
}
317317
}
318318

319-
if (timelock) {
320-
obj.pushKV("timelock", strprintf("%d years", timelock / 52));
319+
if (timelock && *timelock) {
320+
obj.pushKV("timelock", strprintf("%d years", *timelock / 52));
321321
}
322322

323323
mnArr.push_back(subObj);

0 commit comments

Comments
 (0)