diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2729,17 +2729,17 @@ CBlockIndex *pindex, bool invalidate) { AssertLockHeld(cs_main); - // Mark the block itself as invalid. - pindex->nStatus = - pindex->nStatus.withFailed(invalidate).withParked(!invalidate); + // Mark the block as either invalid or parked. + pindex->nStatus = invalidate ? pindex->nStatus.withFailed() + : pindex->nStatus.withParked(); setDirtyBlockIndex.insert(pindex); DisconnectedBlockTransactions disconnectpool; while (chainActive.Contains(pindex)) { CBlockIndex *pindexWalk = chainActive.Tip(); - pindexWalk->nStatus = - pindexWalk->nStatus.withFailed(invalidate).withParked(!invalidate); - setDirtyBlockIndex.insert(pindexWalk); + pindexWalk->nStatus = invalidate ? pindex->nStatus.withFailedParent() + : pindex->nStatus.withParkedParent(); + setDirtyBlockIndex.insert(pindex); // ActivateBestChain considers blocks already in chainActive // unconditionally valid already, so force disconnect away from it. diff --git a/test/functional/abc-parkedchain.py b/test/functional/abc-parkedchain.py --- a/test/functional/abc-parkedchain.py +++ b/test/functional/abc-parkedchain.py @@ -16,7 +16,7 @@ def run_test(self): node = self.nodes[0] - self.log.info("test chain parking") + self.log.info("Test chain parking...") node.generate(10) tip = node.getbestblockhash() node.generate(1) @@ -33,6 +33,69 @@ node.unparkblock(parked_tip) assert_equal(node.getbestblockhash(), parked_tip) + # Parking and then unparking a block should not change its validity, + # and invaliding and reconsidering a block should not change its + # parked state. See the following test cases: + self.log.info("Test invalidate, park, unpark, reconsider...") + node.generate(1) + tip = node.getbestblockhash() + node.generate(1) + bad_tip = node.getbestblockhash() + + node.invalidateblock(bad_tip) + assert_equal(node.getbestblockhash(), tip) + node.parkblock(bad_tip) + assert_equal(node.getbestblockhash(), tip) + node.unparkblock(bad_tip) + assert_equal(node.getbestblockhash(), tip) + node.reconsiderblock(bad_tip) + assert_equal(node.getbestblockhash(), bad_tip) + + self.log.info("Test park, invalidate, reconsider, unpark") + node.generate(1) + tip = node.getbestblockhash() + node.generate(1) + bad_tip = node.getbestblockhash() + + node.parkblock(bad_tip) + assert_equal(node.getbestblockhash(), tip) + node.invalidateblock(bad_tip) + assert_equal(node.getbestblockhash(), tip) + node.reconsiderblock(bad_tip) + assert_equal(node.getbestblockhash(), tip) + node.unparkblock(bad_tip) + assert_equal(node.getbestblockhash(), bad_tip) + + self.log.info("Test invalidate, park, reconsider, unpark...") + node.generate(1) + tip = node.getbestblockhash() + node.generate(1) + bad_tip = node.getbestblockhash() + + node.invalidateblock(bad_tip) + assert_equal(node.getbestblockhash(), tip) + node.parkblock(bad_tip) + assert_equal(node.getbestblockhash(), tip) + node.reconsiderblock(bad_tip) + assert_equal(node.getbestblockhash(), tip) + node.unparkblock(bad_tip) + assert_equal(node.getbestblockhash(), bad_tip) + + self.log.info("Test park, invalidate, unpark, reconsider") + node.generate(1) + tip = node.getbestblockhash() + node.generate(1) + bad_tip = node.getbestblockhash() + + node.parkblock(bad_tip) + assert_equal(node.getbestblockhash(), tip) + node.invalidateblock(bad_tip) + assert_equal(node.getbestblockhash(), tip) + node.unparkblock(bad_tip) + assert_equal(node.getbestblockhash(), tip) + node.reconsiderblock(bad_tip) + assert_equal(node.getbestblockhash(), bad_tip) + if __name__ == '__main__': ParckedChainTest().main()