diff --git a/src/blockstatus.h b/src/blockstatus.h index cde83d926..2ebe5ffd5 100644 --- a/src/blockstatus.h +++ b/src/blockstatus.h @@ -1,117 +1,124 @@ // Copyright (c) 2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_BLOCKSTATUS_H #define BITCOIN_BLOCKSTATUS_H #include "blockvalidity.h" #include "serialize.h" #include struct BlockStatus { private: uint32_t status; explicit BlockStatus(uint32_t nStatusIn) : status(nStatusIn) {} static const uint32_t VALIDITY_MASK = 0x07; // Full block available in blk*.dat static const uint32_t HAS_DATA_FLAG = 0x08; // Undo data available in rev*.dat static const uint32_t HAS_UNDO_FLAG = 0x10; // The block is invalid. static const uint32_t FAILED_FLAG = 0x20; // The block has an invalid parent. static const uint32_t FAILED_PARENT_FLAG = 0x40; // Mask used to check if the block failed. static const uint32_t INVALID_MASK = FAILED_FLAG | FAILED_PARENT_FLAG; // The block is being parked for some reason. It will be reconsidered if its // chains grows. static const uint32_t PARKED_FLAG = 0x80; // One of the block's parent is parked. static const uint32_t PARKED_PARENT_FLAG = 0x100; // Mask used to check for parked blocks. static const uint32_t PARKED_MASK = PARKED_FLAG | PARKED_PARENT_FLAG; public: explicit BlockStatus() : status(0) {} BlockValidity getValidity() const { return BlockValidity(status & VALIDITY_MASK); } BlockStatus withValidity(BlockValidity validity) const { return BlockStatus((status & ~VALIDITY_MASK) | uint32_t(validity)); } bool hasData() const { return status & HAS_DATA_FLAG; } BlockStatus withData(bool hasData = true) const { return BlockStatus((status & ~HAS_DATA_FLAG) | (hasData ? HAS_DATA_FLAG : 0)); } bool hasUndo() const { return status & HAS_UNDO_FLAG; } BlockStatus withUndo(bool hasUndo = true) const { return BlockStatus((status & ~HAS_UNDO_FLAG) | (hasUndo ? HAS_UNDO_FLAG : 0)); } bool hasFailed() const { return status & FAILED_FLAG; } BlockStatus withFailed(bool hasFailed = true) const { return BlockStatus((status & ~FAILED_FLAG) | (hasFailed ? FAILED_FLAG : 0)); } bool hasFailedParent() const { return status & FAILED_PARENT_FLAG; } BlockStatus withFailedParent(bool hasFailedParent = true) const { return BlockStatus((status & ~FAILED_PARENT_FLAG) | (hasFailedParent ? FAILED_PARENT_FLAG : 0)); } bool isParked() const { return status & PARKED_FLAG; } BlockStatus withParked(bool parked = true) const { return BlockStatus((status & ~PARKED_FLAG) | (parked ? PARKED_FLAG : 0)); } bool hasParkedParent() const { return status & PARKED_PARENT_FLAG; } BlockStatus withParkedParent(bool parkedParent = true) const { return BlockStatus((status & ~PARKED_PARENT_FLAG) | (parkedParent ? PARKED_PARENT_FLAG : 0)); } /** * Check whether this block index entry is valid up to the passed validity * level. */ bool isValid(enum BlockValidity nUpTo = BlockValidity::TRANSACTIONS) const { if (isInvalid()) { return false; } return getValidity() >= nUpTo; } bool isInvalid() const { return status & INVALID_MASK; } BlockStatus withClearedFailureFlags() const { return BlockStatus(status & ~INVALID_MASK); } bool isOnParkedChain() const { return status & PARKED_MASK; } + BlockStatus withClearedParkedFlags() const { + return BlockStatus(status & ~PARKED_MASK); + } + + BlockStatus withReconsideredFlags() const { + return withClearedFailureFlags().withClearedParkedFlags(); + } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream &s, Operation ser_action) { READWRITE(VARINT(status)); } }; #endif // BITCOIN_BLOCKSTATUS_H diff --git a/src/test/blockstatus_tests.cpp b/src/test/blockstatus_tests.cpp index 2f42b6bc8..44d529466 100644 --- a/src/test/blockstatus_tests.cpp +++ b/src/test/blockstatus_tests.cpp @@ -1,132 +1,136 @@ // Copyright (c) 2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "blockstatus.h" #include "blockvalidity.h" #include "test/test_bitcoin.h" #include #include BOOST_FIXTURE_TEST_SUITE(blockstatus_tests, BasicTestingSetup) static void CheckBlockStatus(const BlockStatus s, BlockValidity validity, bool hasData, bool hasUndo, bool hasFailed, bool hasFailedParent, bool isParked, bool hasParkedParent) { BOOST_CHECK(s.getValidity() == validity); BOOST_CHECK_EQUAL(s.hasData(), hasData); BOOST_CHECK_EQUAL(s.hasUndo(), hasUndo); BOOST_CHECK_EQUAL(s.hasFailed(), hasFailed); BOOST_CHECK_EQUAL(s.hasFailedParent(), hasFailedParent); BOOST_CHECK_EQUAL(s.isInvalid(), hasFailed || hasFailedParent); BOOST_CHECK_EQUAL(s.isParked(), isParked); BOOST_CHECK_EQUAL(s.hasParkedParent(), hasParkedParent); BOOST_CHECK_EQUAL(s.isOnParkedChain(), isParked || hasParkedParent); } static void CheckAllPermutations(const BlockStatus base, bool hasData, bool hasUndo, bool hasFailed, bool hasFailedParent, bool isParked, bool hasParkedParent) { // Check all possible permutations. std::set baseValidities{ BlockValidity::UNKNOWN, BlockValidity::HEADER, BlockValidity::TREE, BlockValidity::TRANSACTIONS, BlockValidity::CHAIN, BlockValidity::SCRIPTS}; for (BlockValidity validity : baseValidities) { const BlockStatus s = base.withValidity(validity); CheckBlockStatus(s, validity, hasData, hasUndo, hasFailed, hasFailedParent, isParked, hasParkedParent); - // Clears failure flags. + // Clear various flags. CheckBlockStatus(s.withClearedFailureFlags(), validity, hasData, hasUndo, false, false, isParked, hasParkedParent); + CheckBlockStatus(s.withClearedParkedFlags(), validity, hasData, hasUndo, + hasFailed, hasFailedParent, false, false); + CheckBlockStatus(s.withReconsideredFlags(), validity, hasData, hasUndo, + false, false, false, false); // Also check all possible alterations. CheckBlockStatus(s.withData(true), validity, true, hasUndo, hasFailed, hasFailedParent, isParked, hasParkedParent); CheckBlockStatus(s.withData(false), validity, false, hasUndo, hasFailed, hasFailedParent, isParked, hasParkedParent); CheckBlockStatus(s.withUndo(true), validity, hasData, true, hasFailed, hasFailedParent, isParked, hasParkedParent); CheckBlockStatus(s.withUndo(false), validity, hasData, false, hasFailed, hasFailedParent, isParked, hasParkedParent); CheckBlockStatus(s.withFailed(true), validity, hasData, hasUndo, true, hasFailedParent, isParked, hasParkedParent); CheckBlockStatus(s.withFailed(false), validity, hasData, hasUndo, false, hasFailedParent, isParked, hasParkedParent); CheckBlockStatus(s.withFailedParent(true), validity, hasData, hasUndo, hasFailed, true, isParked, hasParkedParent); CheckBlockStatus(s.withFailedParent(false), validity, hasData, hasUndo, hasFailed, false, isParked, hasParkedParent); CheckBlockStatus(s.withParked(true), validity, hasData, hasUndo, hasFailed, hasFailedParent, true, hasParkedParent); CheckBlockStatus(s.withParked(false), validity, hasData, hasUndo, hasFailed, hasFailedParent, false, hasParkedParent); CheckBlockStatus(s.withParkedParent(true), validity, hasData, hasUndo, hasFailed, hasFailedParent, isParked, true); CheckBlockStatus(s.withParkedParent(false), validity, hasData, hasUndo, hasFailed, hasFailedParent, isParked, false); for (BlockValidity newValidity : baseValidities) { CheckBlockStatus(s.withValidity(newValidity), newValidity, hasData, hasUndo, hasFailed, hasFailedParent, isParked, hasParkedParent); } } } static void CheckParked(const BlockStatus s, bool hasData, bool hasUndo, bool hasFailed, bool hasFailedParent) { std::set isParkedValues{false, true}; std::set hasParkedParentValues{false, true}; for (bool isParked : isParkedValues) { for (bool hasParkedParent : hasParkedParentValues) { CheckAllPermutations( s.withParked(isParked).withParkedParent(hasParkedParent), hasData, hasUndo, hasFailed, hasFailedParent, isParked, hasParkedParent); } } } static void CheckFailures(const BlockStatus s, bool hasData, bool hasUndo) { std::set hasFailedValues{false, true}; std::set hasFailedParentValues{false, true}; for (bool hasFailed : hasFailedValues) { for (bool hasFailedParent : hasFailedParentValues) { CheckParked( s.withFailed(hasFailed).withFailedParent(hasFailedParent), hasData, hasUndo, hasFailed, hasFailedParent); } } } static void CheckHaveDataAndUndo(const BlockStatus s) { std::set hasDataValues{false, true}; std::set hasUndoValues{false, true}; for (bool hasData : hasDataValues) { for (bool hasUndo : hasUndoValues) { CheckFailures(s.withData(hasData).withUndo(hasUndo), hasData, hasUndo); } } } BOOST_AUTO_TEST_CASE(sighash_construction_test) { // Check default values. CheckBlockStatus(BlockStatus(), BlockValidity::UNKNOWN, false, false, false, false, false, false); CheckHaveDataAndUndo(BlockStatus()); } BOOST_AUTO_TEST_SUITE_END()