mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-25 18:53:23 -03:00
CDiskBlockIndex: rename GetBlockHash() to ConstructBlockHash()
and mark the inherited CBlockIndex#GetBlockHash public interface member as deleted, to disallow calling it in the derived CDiskBlockIndex class. Here is a failing test on master demonstrating the inconsistent behavior of the current design: calling the same inherited public interface functions on the same CDiskBlockIndex object should yield identical behavior. ```diff diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp index 6dc522b421..dac3840f32 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -240,6 +240,15 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup) const CBlockIndex* tip = chainman.ActiveTip(); BOOST_CHECK_EQUAL(tip->nChainTx, au_data.nChainTx); + // CDiskBlockIndex "is a" CBlockIndex, as it publicly inherits from it. + // Test that calling the same inherited interface functions on the same + // object yields identical behavior. + CDiskBlockIndex index{tip}; + CBlockIndex *pB = &index; + CDiskBlockIndex *pD = &index; + BOOST_CHECK_EQUAL(pB->GetBlockHash(), pD->GetBlockHash()); + BOOST_CHECK_EQUAL(pB->ToString(), pD->ToString()); + ``` The GetBlockHash() test assertion only passes on master because the different methods invoked by the current design happen to return the same result. If one of the two is changed, it fails like the ToString() assertion does. Redefining inherited non-virtual functions is well-documented as incorrect design to avoid inconsistent behavior (see Scott Meyers, "Effective C++", Item 36). Class usage is confusing when the behavior depends on the pointer definition instead of the object definition (static binding happening where dynamic binding was expected). This can lead to unsuspected or hard-to-track bugs. Outside of critical hot spots, correctness usually comes before optimisation, but the current design dates back to main.cpp and it may possibly have been chosen to avoid the overhead of dynamic dispatch. This solution does the same: the class sizes are unchanged and no vptr or vtbl is added. There are better designs for doing this that use composition instead of inheritance or that separate the public interface from the private implementations. One example of the latter would be a non-virtual public interface that calls private virtual implementation methods, i.e. the Template pattern via the Non-Virtual Interface (NVI) idiom.
This commit is contained in:
parent
99e8ec8721
commit
57865eb512
3 changed files with 4 additions and 3 deletions
|
@ -403,7 +403,7 @@ public:
|
|||
READWRITE(obj.nNonce);
|
||||
}
|
||||
|
||||
uint256 GetBlockHash() const
|
||||
uint256 ConstructBlockHash() const
|
||||
{
|
||||
CBlockHeader block;
|
||||
block.nVersion = nVersion;
|
||||
|
@ -415,6 +415,7 @@ public:
|
|||
return block.GetHash();
|
||||
}
|
||||
|
||||
uint256 GetBlockHash() = delete;
|
||||
std::string ToString() = delete;
|
||||
};
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ FUZZ_TARGET(chain)
|
|||
disk_block_index->phashBlock = &zero;
|
||||
{
|
||||
LOCK(::cs_main);
|
||||
(void)disk_block_index->GetBlockHash();
|
||||
(void)disk_block_index->ConstructBlockHash();
|
||||
(void)disk_block_index->GetBlockPos();
|
||||
(void)disk_block_index->GetBlockTime();
|
||||
(void)disk_block_index->GetBlockTimeMax();
|
||||
|
|
|
@ -310,7 +310,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams,
|
|||
CDiskBlockIndex diskindex;
|
||||
if (pcursor->GetValue(diskindex)) {
|
||||
// Construct block index object
|
||||
CBlockIndex* pindexNew = insertBlockIndex(diskindex.GetBlockHash());
|
||||
CBlockIndex* pindexNew = insertBlockIndex(diskindex.ConstructBlockHash());
|
||||
pindexNew->pprev = insertBlockIndex(diskindex.hashPrev);
|
||||
pindexNew->nHeight = diskindex.nHeight;
|
||||
pindexNew->nFile = diskindex.nFile;
|
||||
|
|
Loading…
Add table
Reference in a new issue