Skip to content

Conversation

aureleoules
Copy link
Contributor

@aureleoules aureleoules commented Apr 8, 2022

Re-opening #17232. I have rebased the PR and addressed jonatack's nit suggestions.

Add sanity asserts for return value of CBlockIndex::GetAncestor() where appropriate.

In validation.cpp CheckSequenceLocks, check the return value of tip->GetAncestor(maxInputHeight) stored into lp->maxInputBlock. If it ever returns nullptr because the ancestor isn't found, it's going to be a bad bug to keep going, since a LockPoints object with the maxInputBlock member set to nullptr signifies no relative lock time.

In the other places, the added asserts would prevent accidental dereferencing of a null pointer which is undefined behavior.

Co-Authored-By: Adam Jonas jonas@chaincode.com
Co-Authored-By: danra danra@users.noreply.github.com

Copy link
Member

@jonatack jonatack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of initial comments. Minor detail, please don't use @-usernames in the PR description.

@jonatack
Copy link
Member

jonatack commented Apr 8, 2022

Concept ACK with some suggestions for the lines touched here

suggested diff for your perusal

diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp
index 4f00d6e094..eb731ba205 100644
--- a/src/consensus/tx_verify.cpp
+++ b/src/consensus/tx_verify.cpp
@@ -76,7 +80,7 @@ std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags
             assert(ancestor != nullptr);
-            int64_t nCoinTime = ancestor->GetMedianTimePast();
+            const int64_t nCoinTime = ancestor->GetMedianTimePast();
             // NOTE: Subtract 1 to maintain nLockTime semantics
diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h
index 1209c0faa5..1386b029f5 100644
--- a/src/consensus/tx_verify.h
+++ b/src/consensus/tx_verify.h
@@ -446,17 +446,16 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
     BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail
 
-    const int SEQUENCE_LOCK_TIME = 512; // Sequence locks pass 512 seconds later
-    for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i)
-        m_node.chainman->ActiveChain().Tip()->GetAncestor(m_node.chainman->ActiveChain().Tip()->nHeight - i)->nTime += SEQUENCE_LOCK_TIME; //Trick the MedianTimePast
-        
-    {
+    const int SEQUENCE_LOCK_TIME{512}; // Sequence locks pass 512 seconds later
+    for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i) {
+        m_node.chainman->ActiveChain().Tip()->GetAncestor(m_node.chainman->ActiveChain().Tip()->nHeight - i)->nTime += SEQUENCE_LOCK_TIME; // Trick the MedianTimePast
         CBlockIndex* active_chain_tip = m_node.chainman->ActiveChain().Tip();
-        BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, CreateBlockIndex(active_chain_tip->nHeight + 1, active_chain_tip))); // Sequence locks pass 512 seconds later
+        BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, CreateBlockIndex(active_chain_tip->nHeight + 1, active_chain_tip)));
     }
 
-    for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i)
-        m_node.chainman->ActiveChain().Tip()->GetAncestor(m_node.chainman->ActiveChain().Tip()->nHeight - i)->nTime -= SEQUENCE_LOCK_TIME; //undo tricked MTP
+    for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i) {
+        m_node.chainman->ActiveChain().Tip()->GetAncestor(m_node.chainman->ActiveChain().Tip()->nHeight - i)->nTime -= SEQUENCE_LOCK_TIME; // undo tricked MTP
+    }
 
     // absolute height locked
@@ -501,9 +500,9 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
     BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3U);
-    // However if we advance height by 1 and time by 512, all of them should be mined
-    for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i)
-    {
+    // However, if we advance height by 1 and time by SEQUENCE_LOCK_TIME, all of
+    // them should be mined.
+    for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i) {
         CBlockIndex* ancestor = m_node.chainman->ActiveChain().Tip()->GetAncestor(m_node.chainman->ActiveChain().Tip()->nHeight - i);
         assert(ancestor != nullptr);
         ancestor->nTime += SEQUENCE_LOCK_TIME; // Trick the MedianTimePast
diff --git a/src/versionbits.cpp b/src/versionbits.cpp
index 9218c6bf26..934bfb015f 100644
--- a/src/versionbits.cpp
+++ b/src/versionbits.cpp
@@ -109,10 +109,6 @@ BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockI
 
     // Find how many blocks are in the current period
     int blocks_in_period = 1 + (pindex->nHeight % stats.period);
-    // Find beginning of period
-    const CBlockIndex* pindexEndOfPrevPeriod = pindex->GetAncestor(pindex->nHeight - ((pindex->nHeight + 1) % stats.period));
-    assert(pindexEndOfPrevPeriod != nullptr);
-    stats.elapsed = pindex->nHeight - pindexEndOfPrevPeriod->nHeight;
 
     // Reset signalling_blocks

@aureleoules aureleoules force-pushed the assert_get_ancestor_rebase branch from d297649 to dcaae44 Compare April 8, 2022 12:26
@aureleoules
Copy link
Contributor Author

Thank you for your review @jonatack, I have addressed your comments.

@aureleoules aureleoules force-pushed the assert_get_ancestor_rebase branch 2 times, most recently from 44f4141 to e3250c5 Compare April 8, 2022 13:03
@bitcoin bitcoin deleted a comment from joshuadbryant1985 Apr 12, 2022
Copy link
Member

@jonatack jonatack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few suggestions

index a8701cc9aa..c03e975c03 100644
--- a/src/consensus/tx_verify.cpp
+++ b/src/consensus/tx_verify.cpp
@@ -75,7 +75,7 @@ std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags
         int nCoinHeight = prevHeights[txinIndex];
 
         if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) {
-            const int64_t nCoinTime = Assert(block.GetAncestor(std::max(nCoinHeight - 1, 0)))->GetMedianTimePast();
+            const int64_t nCoinTime{Assert(block.GetAncestor(std::max(nCoinHeight - 1, 0)))->GetMedianTimePast()};
             // NOTE: Subtract 1 to maintain nLockTime semantics
             // BIP 68 relative lock times have the semantics of calculating
             // the first block or time at which the transaction would be
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 78bc93c3d4..1d7eb80d78 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -448,14 +448,17 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
 
     const int SEQUENCE_LOCK_TIME = 512; // Sequence locks pass 512 seconds later
     for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i)
-        m_node.chainman->ActiveChain().Tip()->GetAncestor(m_node.chainman->ActiveChain().Tip()->nHeight - i)->nTime += SEQUENCE_LOCK_TIME; //Trick the MedianTimePast
+        m_node.chainman->ActiveChain().Tip()->GetAncestor(m_node.chainman->ActiveChain().Tip()->nHeight - i)->nTime += SEQUENCE_LOCK_TIME; // Trick the MedianTimePast
     {
         CBlockIndex* active_chain_tip = m_node.chainman->ActiveChain().Tip();
-        BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, CreateBlockIndex(active_chain_tip->nHeight + 1, active_chain_tip))); // Sequence locks pass 512 seconds later
+        BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, CreateBlockIndex(active_chain_tip->nHeight + 1, active_chain_tip)));
     }
 
-    for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i)
-        m_node.chainman->ActiveChain().Tip()->GetAncestor(m_node.chainman->ActiveChain().Tip()->nHeight - i)->nTime -= SEQUENCE_LOCK_TIME; //undo tricked MTP
+    for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i) {
+        CBlockIndex* ancestor = m_node.chainman->ActiveChain().Tip()->GetAncestor(m_node.chainman->ActiveChain().Tip()->nHeight - i);
+        assert(ancestor != nullptr);
+        ancestor->nTime -= SEQUENCE_LOCK_TIME; // undo tricked MTP
+    }
 
     // absolute height locked
     tx.vin[0].prevout.hash = txFirst[2]->GetHash();

@aureleoules aureleoules force-pushed the assert_get_ancestor_rebase branch 2 times, most recently from 9f9361f to 977b6b1 Compare April 12, 2022 12:19
@aureleoules
Copy link
Contributor Author

Seems like there is a bug in the CI? I ran the tests on my fork and passed all tests

@jonatack
Copy link
Member

Yes, it's unrelated, see issue #24151 (and review #24454).

@DrahtBot
Copy link
Contributor

DrahtBot commented Apr 12, 2022

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #24912 (refactor: update CBlockIndex::nChainTx to be uint64_t by mruddy)
  • #24833 (refactor: consensus/tx_verify.{h,cpp} tidy-ups by jonatack)
  • #24567 (Enforce BIP 68 from genesis by MarcoFalke)
  • #23897 (refactor: Move calculation logic out from CheckSequenceLocksAtTip() by hebasto)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@jonatack
Copy link
Member

ACK 977b6b1

maflcko pushed a commit to bitcoin-core/gui that referenced this pull request Apr 24, 2022
…function and NONFATAL_UNREACHABLE macro

ee02c8b util/check: Add CHECK_NONFATAL identity function, NONFATAL_UNREACHABLE AND UNREACHABLE macros (Aurèle Oulès)

Pull request description:

  This PR replaces the macro `CHECK_NONFATAL` with an identity function.
  I simplified the usage of `CHECK_NONFATAL` where applicable in `src/rpc`.
  This function is useful in sanity checks for RPC and command-line interfaces.

  Context: bitcoin/bitcoin#24804 (comment).

  Also adds `UNREACHABLE_NONFATAL` macro.

ACKs for top commit:
  jonatack:
    ACK ee02c8b
  MarcoFalke:
    ACK ee02c8b 🍨

Tree-SHA512: 3cba09223cd7b22e62fe5d0b46c4a024c1d9957d4268ba6d3fb07fcc0a5854fc0886bb3266184e6a7df5df91373b3e84edd6adf6999c4e934aeef8c043b01aa2
@aureleoules aureleoules force-pushed the assert_get_ancestor_rebase branch from 977b6b1 to 54070a5 Compare April 25, 2022 00:17
Copy link
Member

@maflcko maflcko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some nits

@aureleoules aureleoules force-pushed the assert_get_ancestor_rebase branch 2 times, most recently from 9075d79 to a06141f Compare April 25, 2022 23:59
Copy link
Member

@jonatack jonatack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, modulo since the commit is authored by @adamjonas, you could change the first "Co-Authored-By:" in the commit message to yourself.

@jonatack
Copy link
Member

ACK c0fcbb7

If you have to retouch, maybe consider

--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1619,8 +1619,8 @@ static RPCHelpMan getchaintxstats()
     const CBlockIndex& past_block{*CHECK_NONFATAL(pindex->GetAncestor(pindex->nHeight - blockcount))};
-    int nTimeDiff = pindex->GetMedianTimePast() - past_block.GetMedianTimePast();
-    int nTxDiff = pindex->nChainTx - past_block.nChainTx;
+    const int64_t nTimeDiff{pindex->GetMedianTimePast() - past_block.GetMedianTimePast()};
+    const int nTxDiff = pindex->nChainTx - past_block.nChainTx;
 
@@ -1772,8 +1772,8 @@ static RPCHelpMan getblockstats() 
-    const CBlock block = GetBlockChecked(chainman.m_blockman, &pindex);
-    const CBlockUndo blockUndo = GetUndoChecked(chainman.m_blockman, &pindex);
+    const CBlock& block = GetBlockChecked(chainman.m_blockman, &pindex);
+    const CBlockUndo& blockUndo = GetUndoChecked(chainman.m_blockman, &pindex);

@aureleoules aureleoules force-pushed the assert_get_ancestor_rebase branch 2 times, most recently from b0c9d04 to 260a05d Compare May 5, 2022 01:15
Copy link
Member

@jonatack jonatack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 260a05d with a couple more suggestions

Add sanity asserts for return value of `CBlockIndex::GetAncestor()` where appropriate.

In validation.cpp `CheckSequenceLocks`, check the return value of `tip->GetAncestor(maxInputHeight)` stored into `lp->maxInputBlock`. If it ever returns `nullptr` because the ancestor isn't found, it's going to be a bad bug to keep going, since a `LockPoints` object with the `maxInputBlock` member set to `nullptr` signifies no relative lock time.

In the other places, the added asserts would prevent accidental dereferencing of a null pointer which is undefined behavior.

Co-Authored-By: Aurèle Oulès <aurele@oules.com>
Co-Authored-By: danra <danra@users.noreply.github.com>
@aureleoules aureleoules force-pushed the assert_get_ancestor_rebase branch from 260a05d to 308dd2e Compare May 5, 2022 13:59
@jonatack
Copy link
Member

jonatack commented May 5, 2022

ACK 308dd2e

@maflcko maflcko merged commit 59ac8ba into bitcoin:master May 6, 2022
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request May 9, 2022
@aureleoules aureleoules deleted the assert_get_ancestor_rebase branch May 20, 2022 22:14
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Mar 6, 2023
Summary:
Add sanity asserts for return value of `CBlockIndex::GetAncestor()` where appropriate.

In validation.cpp `CheckSequenceLocks`, check the return value of `tip->GetAncestor(maxInputHeight)` stored into `lp->maxInputBlock`. If it ever returns `nullptr` because the ancestor isn't found, it's going to be a bad bug to keep going, since a `LockPoints` object with the `maxInputBlock` member set to `nullptr` signifies no relative lock time.

In the other places, the added asserts would prevent accidental dereferencing of a null pointer which is undefined behavior.

Co-Authored-By: Aurèle Oulès <aurele@oules.com>
Co-Authored-By: danra <danra@users.noreply.github.com>

This is a backport of [[bitcoin/bitcoin#24804 | core#24804]]

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Subscribers: Fabien

Differential Revision: https://reviews.bitcoinabc.org/D13242
@bitcoin bitcoin locked and limited conversation to collaborators May 20, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants